Compare commits

...

13 Commits

Author SHA1 Message Date
Bram Moolenaar
a3571ebef5 patch 8.0.1346: crash when passing 50 char string to balloon_split()
Problem:    Crash when passing 50 char string to balloon_split().
Solution:   Fix off-by-one error.
2017-11-26 16:53:16 +01:00
Bram Moolenaar
c41838aa01 patch 8.0.1345: race condition between stat() and open() for viminfo
Problem:    Race condition between stat() and open() for the viminfo temp
            file. (Simon Ruderich)
Solution:   use open() with O_EXCL to atomically check if the file exists.
            Don't try using a temp file, renaming it will fail anyway.
2017-11-26 16:50:41 +01:00
Bram Moolenaar
2877d334ad patch 8.0.1344: using 'imactivatefunc' in the GUI does not work
Problem:    Using 'imactivatefunc' in the GUI does not work.
Solution:   Do not use 'imactivatefunc' and 'imstatusfunc' in the GUI.
2017-11-26 14:56:16 +01:00
Bram Moolenaar
d7ccc4d81d patch 8.0.1343: MS-Windows: does not show colored emojis
Problem:    MS-Windows: does not show colored emojis.
Solution:   Implement colored emojis. Improve drawing speed. Make 'taamode'
            work. (Taro Muraoka, Yasuhiro Matsumoto, Ken Takata, close #2375)
2017-11-26 14:29:32 +01:00
Bram Moolenaar
fb1db0e355 patch 8.0.1342: cannot build with Motif and multi-byte
Problem:    Cannot build with Motif and multi-byte. (Mohamed Boughaba)
Solution:   Use the right input method status flag. (closes #2374)
2017-11-25 21:07:46 +01:00
Bram Moolenaar
be5d998d0e patch 8.0.1341: 'imactivatefunc' test fails on MS-Windows
Problem:    'imactivatefunc' test fails on MS-Windows.
Solution:   Skip the text.
2017-11-25 17:58:28 +01:00
Bram Moolenaar
281c93e714 patch 8.0.1340: MS-Windows: cannot build GUI without IME
Problem:    MS-Windows: cannot build GUI without IME.
Solution:   Define im_get_status() and im_set_active() when IME is not used.
2017-11-25 17:48:33 +01:00
Bram Moolenaar
83799a7b74 patch 8.0.1339: no test for what 8.0.1335 fixes
Problem:    No test for what 8.0.1335 fixes.
Solution:   Add a test. (Yasuhiro Matsumoto, closes #2373)
2017-11-25 17:24:09 +01:00
Bram Moolenaar
819edbe078 patch 8.0.1338: USE_IM_CONTROL is confusing and incomplete
Problem:    USE_IM_CONTROL is confusing and incomplete.
Solution:   Just use FEAT_MBYTE.  Call 'imactivatefunc' also without GUI.
2017-11-25 17:14:33 +01:00
Bram Moolenaar
50d43153a7 patch 8.0.1337: typo in #ifdef
Problem:    Typo in #ifdef.
Solution:   Fix the #if line.
2017-11-25 15:24:56 +01:00
Bram Moolenaar
6315a9ae92 patch 8.0.1336: cannot use imactivatefunc() unless compiled with +xim
Problem:    Cannot use imactivatefunc() unless compiled with +xim.
Solution:   Allow using imactivatefunc() when not compiled with +xim.
            (Yasuhiro Matsumoto, closes #2349)
2017-11-25 15:20:02 +01:00
Bram Moolenaar
291a9d15ed patch 8.0.1335: writefile() using fsync() may give an error.
Problem:    Writefile() using fsync() may give an error for a device.
            (Yasuhiro Matsumoto)
Solution:   Ignore fsync() failing. (closes #2373)
2017-11-25 14:37:11 +01:00
Bram Moolenaar
3167c3e701 patch 8.0.1334: splitting a window with a WinBar damages window layout
Problem:    Splitting a window with a WinBar damages window layout.
            (Lifepillar)
Solution:   Take the winbar into account when computing the new window
            position.  Add WINBAR_HEIGHT().
2017-11-25 14:19:43 +01:00
30 changed files with 996 additions and 567 deletions

View File

@@ -16,6 +16,7 @@ matrix:
before_build:
- '"C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64 /release'
- 'set INCLUDE=%INCLUDE%C:\Program Files (x86)\Windows Kits\8.1\Include\um'
build_script:
- src/appveyor.bat

View File

@@ -26,8 +26,9 @@ For changing the language of messages and menus see |mlang.txt|.
7. Input on X11 |mbyte-XIM|
8. Input on MS-Windows |mbyte-IME|
9. Input with a keymap |mbyte-keymap|
10. Using UTF-8 |mbyte-utf8|
11. Overview of options |mbyte-options|
10. Input with imactivatefunc() |mbyte-func|
11. Using UTF-8 |mbyte-utf8|
12. Overview of options |mbyte-options|
NOTE: This file contains UTF-8 characters. These may show up as strange
characters or boxes when using another encoding.
@@ -1254,7 +1255,35 @@ Combining forms:
ﭏ 0xfb4f Xal alef-lamed
==============================================================================
10. Using UTF-8 *mbyte-utf8* *UTF-8* *utf-8* *utf8*
10. Input with imactivatefunc() *mbyte-func*
Vim has |imactivatefunc()| and |imstatusfunc()|. This is useful to
activate/deativate input method from Vim in any way, also with an external
command. For example, fcitx provide fcitx-remote command: >
set iminsert=2
set imsearch=2
set imcmdline
set imactivatefunc=ImActivate
function! ImActivate(active)
if a:active
call system('fcitx-remote -o')
else
call system('fcitx-remote -c')
endif
endfunction
set imstatusfunc=ImStatus
function! ImStatus()
return system('fcitx-remote')[0] is# '2'
endfunction
Using this script, you can activate/deactivate XIM via Vim even when it is not
compiled with |+xim|.
==============================================================================
11. Using UTF-8 *mbyte-utf8* *UTF-8* *utf-8* *utf8*
*Unicode* *unicode*
The Unicode character set was designed to include all characters from other
character sets. Therefore it is possible to write text in any language using
@@ -1402,7 +1431,7 @@ not everybody is able to type a composing character.
==============================================================================
11. Overview of options *mbyte-options*
12. Overview of options *mbyte-options*
These options are relevant for editing multi-byte files. Check the help in
options.txt for detailed information.

View File

@@ -4256,10 +4256,10 @@ A jump table for the options with a short description can be found at |Q_op|.
'imactivatefunc' 'imaf' string (default "")
global
{not in Vi}
{only available when compiled with |+xim| and
|+GUI_GTK|}
{only available when compiled with |+mbyte|}
This option specifies a function that will be called to
activate/inactivate Input Method.
activate or deactivate the Input Method.
It is not used in the GUI.
Example: >
function ImActivateFunc(active)
@@ -4308,8 +4308,7 @@ A jump table for the options with a short description can be found at |Q_op|.
'imcmdline' 'imc' boolean (default off)
global
{not in Vi}
{only available when compiled with the |+xim|,
|+multi_byte_ime| or |global-ime| features}
{only available when compiled with |+mbyte|}
When set the Input Method is always on when starting to edit a command
line, unless entering a search pattern (see 'imsearch' for that).
Setting this option is useful when your input method allows entering
@@ -4320,8 +4319,7 @@ A jump table for the options with a short description can be found at |Q_op|.
'imdisable' 'imd' boolean (default off, on for some systems (SGI))
global
{not in Vi}
{only available when compiled with the |+xim|,
|+multi_byte_ime| or |global-ime| features}
{only available when compiled with |+mbyte|}
When set the Input Method is never used. This is useful to disable
the IM when it doesn't work properly.
Currently this option is on by default for SGI/IRIX machines. This
@@ -4336,8 +4334,6 @@ A jump table for the options with a short description can be found at |Q_op|.
0 :lmap is off and IM is off
1 :lmap is ON and IM is off
2 :lmap is off and IM is ON
2 is available only when compiled with the |+multi_byte_ime|, |+xim|
or |global-ime|.
To always reset the option to zero when leaving Insert mode with <Esc>
this can be used: >
:inoremap <ESC> <ESC>:set iminsert=0<CR>
@@ -4350,6 +4346,10 @@ A jump table for the options with a short description can be found at |Q_op|.
The value 0 may not work correctly with Athena and Motif with some XIM
methods. Use 'imdisable' to disable XIM then.
You can set 'imactivatefunc' and 'imstatusfunc' to handle IME/XIM
via external command if vim is not compiled with the |+xim|,
|+multi_byte_ime| or |global-ime|.
*'imsearch'* *'ims'*
'imsearch' 'ims' number (default -1)
local to buffer
@@ -4372,10 +4372,10 @@ A jump table for the options with a short description can be found at |Q_op|.
'imstatusfunc' 'imsf' string (default "")
global
{not in Vi}
{only available when compiled with |+xim| and
|+GUI_GTK|}
{only available when compiled with |+mbyte|}
This option specifies a function that is called to obtain the status
of Input Method. It must return a positive number when IME is active.
It is not used in the GUI.
Example: >
function ImStatusFunc()
@@ -6154,11 +6154,34 @@ A jump table for the options with a short description can be found at |Q_op|.
Example: >
set encoding=utf-8
set gfn=Ricty_Diminished:h12:cSHIFTJIS
set gfn=Ricty_Diminished:h12
set rop=type:directx
<
If select a raster font (Courier, Terminal or FixedSys) to
'guifont', it fallbacks to be drawn by GDI automatically.
If select a raster font (Courier, Terminal or FixedSys which
have ".fon" extension in file name) to 'guifont', it will be
drawn by GDI as a fallback. This fallback will cause
significant slow down on drawing.
NOTE: It is known that some fonts and options combination
causes trouble on drawing glyphs.
- 'rendmode:5' and 'renmode:6' will not work with some
special made fonts (True-Type fonts which includes only
bitmap glyphs).
- 'taamode:3' will not work with some vector fonts.
NOTE: With this option, you can display colored emoji
(emoticon) in Windows 8.1 or later. To display colored emoji,
there are some conditions which you should notice.
- If your font includes non-colored emoji already, it will
be used.
- If your font doesn't have emoji, the system chooses an
alternative symbol font. On Windows 10, "Segoe UI Emoji"
will be used.
- When this alternative font didn't have fixed width glyph,
emoji might be rendered beyond the bounding box of drawing
cell.
Other render types are currently not supported.

View File

@@ -2190,6 +2190,7 @@ test_arglist \
test_highlight \
test_history \
test_hlsearch \
test_iminsert \
test_increment \
test_increment_dbcs \
test_ins_complete \

View File

@@ -516,7 +516,7 @@ edit(
*/
if (curbuf->b_p_iminsert == B_IMODE_LMAP)
State |= LANGMAP;
#ifdef USE_IM_CONTROL
#ifdef FEAT_MBYTE
im_set_active(curbuf->b_p_iminsert == B_IMODE_IM);
#endif
@@ -8372,7 +8372,7 @@ ins_reg(void)
++no_u_sync;
if (regname == '=')
{
# ifdef USE_IM_CONTROL
# ifdef FEAT_MBYTE
int im_on = im_get_status();
# endif
/* Sync undo when evaluating the expression calls setline() or
@@ -8380,7 +8380,7 @@ ins_reg(void)
u_sync_once = 2;
regname = get_expr_register();
# ifdef USE_IM_CONTROL
# ifdef FEAT_MBYTE
/* Restore the Input Method. */
if (im_on)
im_set_active(TRUE);
@@ -8509,12 +8509,12 @@ ins_ctrl_hat(void)
{
curbuf->b_p_iminsert = B_IMODE_LMAP;
State |= LANGMAP;
#ifdef USE_IM_CONTROL
#ifdef FEAT_MBYTE
im_set_active(FALSE);
#endif
}
}
#ifdef USE_IM_CONTROL
#ifdef FEAT_MBYTE
else
{
/* There are no ":lmap" mappings, toggle IM */
@@ -8661,7 +8661,7 @@ ins_esc(
}
}
#ifdef USE_IM_CONTROL
#ifdef FEAT_MBYTE
/* Disable IM to allow typing English directly for Normal mode commands.
* When ":lmap" is enabled don't change 'iminsert' (IM can be enabled as
* well). */

View File

@@ -13449,8 +13449,10 @@ f_writefile(typval_T *argvars, typval_T *rettv)
if (write_list(fd, list, binary) == FAIL)
ret = -1;
#ifdef HAVE_FSYNC
else if (do_fsync && fsync(fileno(fd)) != 0)
EMSG(_(e_fsync));
else if (do_fsync)
/* Ignore the error, the user wouldn't know what to do about it.
* May happen for a device. */
ignored = fsync(fileno(fd));
#endif
fclose(fd);
}

View File

@@ -1825,7 +1825,6 @@ write_viminfo(char_u *file, int forceit)
FILE *fp_out = NULL; /* output viminfo file */
char_u *tempname = NULL; /* name of temp viminfo file */
stat_T st_new; /* mch_stat() of potential new file */
char_u *wp;
#if defined(UNIX) || defined(VMS)
mode_t umask_save;
#endif
@@ -1847,27 +1846,29 @@ write_viminfo(char_u *file, int forceit)
fp_in = mch_fopen((char *)fname, READBIN);
if (fp_in == NULL)
{
int fd;
/* if it does exist, but we can't read it, don't try writing */
if (mch_stat((char *)fname, &st_new) == 0)
goto end;
#if defined(UNIX) || defined(VMS)
/*
* For Unix we create the .viminfo non-accessible for others,
* because it may contain text from non-accessible documents.
*/
umask_save = umask(077);
#endif
fp_out = mch_fopen((char *)fname, WRITEBIN);
#if defined(UNIX) || defined(VMS)
(void)umask(umask_save);
#endif
/* Create the new .viminfo non-accessible for others, because it may
* contain text from non-accessible documents. It is up to the user to
* widen access (e.g. to a group). This may also fail if there is a
* race condition, then just give up. */
fd = mch_open((char *)fname,
O_CREAT|O_EXTRA|O_EXCL|O_WRONLY|O_NOFOLLOW, 0600);
if (fd < 0)
goto end;
fp_out = fdopen(fd, WRITEBIN);
}
else
{
/*
* There is an existing viminfo file. Create a temporary file to
* write the new viminfo into, in the same directory as the
* existing viminfo file, which will be renamed later.
* existing viminfo file, which will be renamed once all writing is
* successful.
*/
#ifdef UNIX
/*
@@ -1901,12 +1902,18 @@ write_viminfo(char_u *file, int forceit)
#endif
/*
* Make tempname.
* Make tempname, find one that does not exist yet.
* Beware of a race condition: If someone logs out and all Vim
* instances exit at the same time a temp file might be created between
* stat() and open(). Use mch_open() with O_EXCL to avoid that.
* May try twice: Once normal and once with shortname set, just in
* case somebody puts his viminfo file in an 8.3 filesystem.
*/
for (;;)
{
int next_char = 'z';
char_u *wp;
tempname = buf_modname(
#ifdef UNIX
shortname,
@@ -1924,127 +1931,129 @@ write_viminfo(char_u *file, int forceit)
break;
/*
* Check if tempfile already exists. Never overwrite an
* existing file!
* Try a series of names. Change one character, just before
* the extension. This should also work for an 8.3
* file name, when after adding the extension it still is
* the same file as the original.
*/
if (mch_stat((char *)tempname, &st_new) == 0)
wp = tempname + STRLEN(tempname) - 5;
if (wp < gettail(tempname)) /* empty file name? */
wp = gettail(tempname);
for (;;)
{
/*
* Check if tempfile already exists. Never overwrite an
* existing file!
*/
if (mch_stat((char *)tempname, &st_new) == 0)
{
#ifdef UNIX
/*
* Check if tempfile is same as original file. May happen
* when modname() gave the same file back. E.g. silly
* link, or file name-length reached. Try again with
* shortname set.
*/
if (!shortname && st_new.st_dev == st_old.st_dev
&& st_new.st_ino == st_old.st_ino)
{
vim_free(tempname);
tempname = NULL;
shortname = TRUE;
continue;
}
#endif
/*
* Try another name. Change one character, just before
* the extension. This should also work for an 8.3
* file name, when after adding the extension it still is
* the same file as the original.
*/
wp = tempname + STRLEN(tempname) - 5;
if (wp < gettail(tempname)) /* empty file name? */
wp = gettail(tempname);
for (*wp = 'z'; mch_stat((char *)tempname, &st_new) == 0;
--*wp)
{
/*
* They all exist? Must be something wrong! Don't
* write the viminfo file then.
* Check if tempfile is same as original file. May happen
* when modname() gave the same file back. E.g. silly
* link, or file name-length reached. Try again with
* shortname set.
*/
if (*wp == 'a')
if (!shortname && st_new.st_dev == st_old.st_dev
&& st_new.st_ino == st_old.st_ino)
{
EMSG2(_("E929: Too many viminfo temp files, like %s!"),
tempname);
vim_free(tempname);
tempname = NULL;
shortname = TRUE;
break;
}
#endif
}
else
{
/* Try creating the file exclusively. This may fail if
* another Vim tries to do it at the same time. */
#ifdef VMS
/* fdopen() fails for some reason */
umask_save = umask(077);
fp_out = mch_fopen((char *)tempname, WRITEBIN);
(void)umask(umask_save);
#else
int fd;
/* Use mch_open() to be able to use O_NOFOLLOW and set file
* protection:
* Unix: same as original file, but strip s-bit. Reset
* umask to avoid it getting in the way.
* Others: r&w for user only. */
# ifdef UNIX
umask_save = umask(0);
fd = mch_open((char *)tempname,
O_CREAT|O_EXTRA|O_EXCL|O_WRONLY|O_NOFOLLOW,
(int)((st_old.st_mode & 0777) | 0600));
(void)umask(umask_save);
# else
fd = mch_open((char *)tempname,
O_CREAT|O_EXTRA|O_EXCL|O_WRONLY|O_NOFOLLOW, 0600);
# endif
if (fd < 0)
{
fp_out = NULL;
# ifdef EEXIST
/* Avoid trying lots of names while the problem is lack
* of premission, only retry if the file already
* exists. */
if (errno != EEXIST)
break;
# endif
}
else
fp_out = fdopen(fd, WRITEBIN);
#endif /* VMS */
if (fp_out != NULL)
break;
}
/* Assume file exists, try again with another name. */
if (next_char == 'a' - 1)
{
/* They all exist? Must be something wrong! Don't write
* the viminfo file then. */
EMSG2(_("E929: Too many viminfo temp files, like %s!"),
tempname);
break;
}
*wp = next_char;
--next_char;
}
break;
if (tempname != NULL)
break;
/* continue if shortname was set */
}
if (tempname != NULL)
{
#ifdef VMS
/* fdopen() fails for some reason */
umask_save = umask(077);
fp_out = mch_fopen((char *)tempname, WRITEBIN);
(void)umask(umask_save);
#else
int fd;
/* Use mch_open() to be able to use O_NOFOLLOW and set file
* protection:
* Unix: same as original file, but strip s-bit. Reset umask to
* avoid it getting in the way.
* Others: r&w for user only. */
# ifdef UNIX
umask_save = umask(0);
fd = mch_open((char *)tempname,
O_CREAT|O_EXTRA|O_EXCL|O_WRONLY|O_NOFOLLOW,
(int)((st_old.st_mode & 0777) | 0600));
(void)umask(umask_save);
# else
fd = mch_open((char *)tempname,
O_CREAT|O_EXTRA|O_EXCL|O_WRONLY|O_NOFOLLOW, 0600);
# endif
if (fd < 0)
fp_out = NULL;
else
fp_out = fdopen(fd, WRITEBIN);
#endif /* VMS */
/*
* If we can't create in the same directory, try creating a
* "normal" temp file. This is just an attempt, renaming the temp
* file might fail as well.
*/
if (fp_out == NULL)
{
vim_free(tempname);
if ((tempname = vim_tempname('o', TRUE)) != NULL)
fp_out = mch_fopen((char *)tempname, WRITEBIN);
}
#if defined(UNIX) && defined(HAVE_FCHOWN)
if (tempname != NULL && fp_out != NULL)
{
stat_T tmp_st;
/*
* Make sure the original owner can read/write the tempfile and
* otherwise preserve permissions, making sure the group matches.
*/
if (fp_out != NULL)
if (mch_stat((char *)tempname, &tmp_st) >= 0)
{
stat_T tmp_st;
if (mch_stat((char *)tempname, &tmp_st) >= 0)
{
if (st_old.st_uid != tmp_st.st_uid)
/* Changing the owner might fail, in which case the
* file will now owned by the current user, oh well. */
ignored = fchown(fileno(fp_out), st_old.st_uid, -1);
if (st_old.st_gid != tmp_st.st_gid
&& fchown(fileno(fp_out), -1, st_old.st_gid) == -1)
/* can't set the group to what it should be, remove
* group permissions */
(void)mch_setperm(tempname, 0600);
}
else
/* can't stat the file, set conservative permissions */
if (st_old.st_uid != tmp_st.st_uid)
/* Changing the owner might fail, in which case the
* file will now owned by the current user, oh well. */
ignored = fchown(fileno(fp_out), st_old.st_uid, -1);
if (st_old.st_gid != tmp_st.st_gid
&& fchown(fileno(fp_out), -1, st_old.st_gid) == -1)
/* can't set the group to what it should be, remove
* group permissions */
(void)mch_setperm(tempname, 0600);
}
#endif
else
/* can't stat the file, set conservative permissions */
(void)mch_setperm(tempname, 0600);
}
}
#endif
/*
* Check if the new viminfo file can be written to.

View File

@@ -359,11 +359,11 @@ getcmdline(
b_im_ptr = &curbuf->b_p_imsearch;
if (*b_im_ptr == B_IMODE_LMAP)
State |= LANGMAP;
#ifdef USE_IM_CONTROL
#ifdef FEAT_MBYTE
im_set_active(*b_im_ptr == B_IMODE_IM);
#endif
}
#ifdef USE_IM_CONTROL
#ifdef FEAT_MBYTE
else if (p_imcmdline)
im_set_active(TRUE);
#endif
@@ -1119,7 +1119,7 @@ getcmdline(
{
/* ":lmap" mappings exists, toggle use of mappings. */
State ^= LANGMAP;
#ifdef USE_IM_CONTROL
#ifdef FEAT_MBYTE
im_set_active(FALSE); /* Disable input method */
#endif
if (b_im_ptr != NULL)
@@ -1130,7 +1130,7 @@ getcmdline(
*b_im_ptr = B_IMODE_NONE;
}
}
#ifdef USE_IM_CONTROL
#ifdef FEAT_MBYTE
else
{
/* There are no ":lmap" mappings, toggle IM. When
@@ -2143,7 +2143,7 @@ returncmd:
#endif
State = save_State;
#ifdef USE_IM_CONTROL
#ifdef FEAT_MBYTE
if (b_im_ptr != NULL && *b_im_ptr != B_IMODE_LMAP)
im_save_status(b_im_ptr);
im_set_active(FALSE);

View File

@@ -2890,7 +2890,7 @@ vgetorpeek(int advance)
+ typebuf.tb_len] != NUL)
typebuf.tb_noremap[typebuf.tb_off
+ typebuf.tb_len++] = RM_YES;
#ifdef USE_IM_CONTROL
#ifdef FEAT_MBYTE
/* Get IM status right after getting keys, not after the
* timeout for a mapping (focus may be lost by then). */
vgetc_im_active = im_get_status();

View File

@@ -1022,7 +1022,7 @@ EXTERN int stop_insert_mode; /* for ":stopinsert" and 'insertmode' */
EXTERN int KeyTyped; /* TRUE if user typed current char */
EXTERN int KeyStuffed; /* TRUE if current char from stuffbuf */
#ifdef USE_IM_CONTROL
#ifdef FEAT_MBYTE
EXTERN int vgetc_im_active; /* Input Method was active for last
character obtained from vgetc() */
#endif

View File

@@ -1078,7 +1078,7 @@ gui_update_cursor(
gui_undraw_cursor();
if (gui.row < 0)
return;
#ifdef USE_IM_CONTROL
#ifdef FEAT_MBYTE
if (gui.row != gui.cursor_row || gui.col != gui.cursor_col)
im_set_position(gui.row, gui.col);
#endif
@@ -1136,7 +1136,7 @@ gui_update_cursor(
if (id > 0)
{
cattr = syn_id2colors(id, &cfg, &cbg);
#if defined(USE_IM_CONTROL) || defined(FEAT_HANGULIN)
#if defined(FEAT_MBYTE) || defined(FEAT_HANGULIN)
{
static int iid;
guicolor_T fg, bg;

View File

@@ -4,6 +4,7 @@
*
* Contributors:
* - Ken Takata
* - Yasuhiro Matsumoto
*
* Copyright (C) 2013 MURAOKA Taro <koron.kaoriya@gmail.com>
* THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE.
@@ -23,7 +24,21 @@
#include <math.h>
#include <d2d1.h>
#include <d2d1helper.h>
#include <dwrite.h>
// Disable these macros to compile with old VC and newer SDK (V8.1 or later).
#if defined(_MSC_VER) && (_MSC_VER < 1700)
# define _COM_Outptr_ __out
# define _In_reads_(s)
# define _In_reads_opt_(s)
# define _Maybenull_
# define _Out_writes_(s)
# define _Out_writes_opt_(s)
# define _Out_writes_to_(x, y)
# define _Out_writes_to_opt_(x, y)
# define _Outptr_
#endif
#include <dwrite_2.h>
#include "gui_dwrite.h"
@@ -79,16 +94,6 @@ template <class T> inline void SafeRelease(T **ppT)
}
}
struct GdiTextRendererContext
{
// const fields.
COLORREF color;
FLOAT cellWidth;
// working fields.
FLOAT offsetX;
};
static DWRITE_PIXEL_GEOMETRY
ToPixelGeometry(int value)
{
@@ -184,17 +189,151 @@ ToInt(DWRITE_RENDERING_MODE value)
}
}
class FontCache {
public:
struct Item {
HFONT hFont;
IDWriteTextFormat* pTextFormat;
DWRITE_FONT_WEIGHT fontWeight;
DWRITE_FONT_STYLE fontStyle;
Item() : hFont(NULL), pTextFormat(NULL) {}
};
private:
int mSize;
Item *mItems;
public:
FontCache(int size = 2) :
mSize(size),
mItems(new Item[size])
{
}
~FontCache()
{
for (int i = 0; i < mSize; ++i)
SafeRelease(&mItems[i].pTextFormat);
delete[] mItems;
}
bool get(HFONT hFont, Item &item)
{
int n = find(hFont);
if (n < 0)
return false;
item = mItems[n];
slide(n);
return true;
}
void put(const Item& item)
{
int n = find(item.hFont);
if (n < 0)
n = mSize - 1;
if (mItems[n].pTextFormat != item.pTextFormat)
{
SafeRelease(&mItems[n].pTextFormat);
item.pTextFormat->AddRef();
}
mItems[n] = item;
slide(n);
}
private:
int find(HFONT hFont)
{
for (int i = 0; i < mSize; ++i)
{
if (mItems[i].hFont == hFont)
return i;
}
return -1;
}
void slide(int nextTop)
{
if (nextTop == 0)
return;
Item tmp = mItems[nextTop];
for (int i = nextTop - 1; i >= 0; --i)
mItems[i + 1] = mItems[i];
mItems[0] = tmp;
}
};
struct DWriteContext {
HDC mHDC;
bool mDrawing;
bool mFallbackDC;
ID2D1Factory *mD2D1Factory;
ID2D1DCRenderTarget *mRT;
ID2D1SolidColorBrush *mBrush;
IDWriteFactory *mDWriteFactory;
IDWriteFactory2 *mDWriteFactory2;
IDWriteGdiInterop *mGdiInterop;
IDWriteRenderingParams *mRenderingParams;
FontCache mFontCache;
IDWriteTextFormat *mTextFormat;
DWRITE_FONT_WEIGHT mFontWeight;
DWRITE_FONT_STYLE mFontStyle;
D2D1_TEXT_ANTIALIAS_MODE mTextAntialiasMode;
// METHODS
DWriteContext();
virtual ~DWriteContext();
HRESULT CreateTextFormatFromLOGFONT(const LOGFONTW &logFont,
IDWriteTextFormat **ppTextFormat);
HRESULT SetFontByLOGFONT(const LOGFONTW &logFont);
void SetFont(HFONT hFont);
void BindDC(HDC hdc, RECT *rect);
void AssureDrawing();
ID2D1Brush* SolidBrush(COLORREF color);
void DrawText(const WCHAR* text, int len,
int x, int y, int w, int h, int cellWidth, COLORREF color,
UINT fuOptions, CONST RECT *lprc, CONST INT * lpDx);
void FillRect(RECT *rc, COLORREF color);
void Flush();
void SetRenderingParams(
const DWriteRenderingParams *params);
DWriteRenderingParams *GetRenderingParams(
DWriteRenderingParams *params);
};
class AdjustedGlyphRun : public DWRITE_GLYPH_RUN
{
private:
FLOAT &mAccum;
FLOAT mDelta;
FLOAT *mAdjustedAdvances;
public:
AdjustedGlyphRun(
const DWRITE_GLYPH_RUN *glyphRun,
FLOAT cellWidth) :
FLOAT cellWidth,
FLOAT &accum) :
DWRITE_GLYPH_RUN(*glyphRun),
mAccum(accum),
mDelta(0.0f),
mAdjustedAdvances(new FLOAT[glyphRun->glyphCount])
{
@@ -209,45 +348,44 @@ public:
glyphAdvances = mAdjustedAdvances;
}
~AdjustedGlyphRun(void)
~AdjustedGlyphRun()
{
mAccum += mDelta;
delete[] mAdjustedAdvances;
}
FLOAT getDelta(void) const
{
return mDelta;
}
static FLOAT adjustToCell(FLOAT value, FLOAT cellWidth)
{
int cellCount = (int)floor(value / cellWidth + 0.5f);
int cellCount = int(floor(value / cellWidth + 0.5f));
if (cellCount < 1)
cellCount = 1;
return cellCount * cellWidth;
}
};
class GdiTextRenderer FINAL : public IDWriteTextRenderer
struct TextRendererContext {
// const fields.
COLORREF color;
FLOAT cellWidth;
// working fields.
FLOAT offsetX;
};
class TextRenderer FINAL : public IDWriteTextRenderer
{
public:
GdiTextRenderer(
IDWriteBitmapRenderTarget* bitmapRenderTarget,
IDWriteRenderingParams* renderingParams) :
TextRenderer(
DWriteContext* pDWC) :
cRefCount_(0),
pRenderTarget_(bitmapRenderTarget),
pRenderingParams_(renderingParams)
pDWC_(pDWC)
{
pRenderTarget_->AddRef();
pRenderingParams_->AddRef();
AddRef();
}
// add "virtual" to avoid a compiler warning
virtual ~GdiTextRenderer()
virtual ~TextRenderer()
{
SafeRelease(&pRenderTarget_);
SafeRelease(&pRenderingParams_);
}
IFACEMETHOD(IsPixelSnappingDisabled)(
@@ -263,7 +401,8 @@ public:
__out DWRITE_MATRIX* transform)
{
// forward the render target's transform
pRenderTarget_->GetCurrentTransform(transform);
pDWC_->mRT->GetTransform(
reinterpret_cast<D2D1_MATRIX_3X2_F*>(transform));
return S_OK;
}
@@ -271,43 +410,12 @@ public:
__maybenull void* clientDrawingContext,
__out FLOAT* pixelsPerDip)
{
*pixelsPerDip = pRenderTarget_->GetPixelsPerDip();
float dpiX, unused;
pDWC_->mRT->GetDpi(&dpiX, &unused);
*pixelsPerDip = dpiX / 96.0f;
return S_OK;
}
IFACEMETHOD(DrawGlyphRun)(
__maybenull void* clientDrawingContext,
FLOAT baselineOriginX,
FLOAT baselineOriginY,
DWRITE_MEASURING_MODE measuringMode,
__in DWRITE_GLYPH_RUN const* glyphRun,
__in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
IUnknown* clientDrawingEffect)
{
HRESULT hr = S_OK;
GdiTextRendererContext *context =
reinterpret_cast<GdiTextRendererContext*>(clientDrawingContext);
AdjustedGlyphRun adjustedGlyphRun(glyphRun, context->cellWidth);
// Pass on the drawing call to the render target to do the real work.
RECT dirtyRect = {0};
hr = pRenderTarget_->DrawGlyphRun(
baselineOriginX + context->offsetX,
baselineOriginY,
measuringMode,
&adjustedGlyphRun,
pRenderingParams_,
context->color,
&dirtyRect);
context->offsetX += adjustedGlyphRun.getDelta();
return hr;
}
IFACEMETHOD(DrawUnderline)(
__maybenull void* clientDrawingContext,
FLOAT baselineOriginX,
@@ -340,6 +448,69 @@ public:
return E_NOTIMPL;
}
IFACEMETHOD(DrawGlyphRun)(
__maybenull void* clientDrawingContext,
FLOAT baselineOriginX,
FLOAT baselineOriginY,
DWRITE_MEASURING_MODE measuringMode,
__in DWRITE_GLYPH_RUN const* glyphRun,
__in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
IUnknown* clientDrawingEffect)
{
TextRendererContext *context =
reinterpret_cast<TextRendererContext*>(clientDrawingContext);
AdjustedGlyphRun adjustedGlyphRun(glyphRun, context->cellWidth,
context->offsetX);
if (pDWC_->mDWriteFactory2 != NULL)
{
IDWriteColorGlyphRunEnumerator *enumerator = NULL;
HRESULT hr = pDWC_->mDWriteFactory2->TranslateColorGlyphRun(
baselineOriginX + context->offsetX,
baselineOriginY,
&adjustedGlyphRun,
NULL,
DWRITE_MEASURING_MODE_GDI_NATURAL,
NULL,
0,
&enumerator);
if (SUCCEEDED(hr))
{
// Draw by IDWriteFactory2 for color emoji
BOOL hasRun = TRUE;
enumerator->MoveNext(&hasRun);
while (hasRun)
{
const DWRITE_COLOR_GLYPH_RUN* colorGlyphRun;
enumerator->GetCurrentRun(&colorGlyphRun);
pDWC_->mBrush->SetColor(colorGlyphRun->runColor);
pDWC_->mRT->DrawGlyphRun(
D2D1::Point2F(
colorGlyphRun->baselineOriginX,
colorGlyphRun->baselineOriginY),
&colorGlyphRun->glyphRun,
pDWC_->mBrush,
DWRITE_MEASURING_MODE_NATURAL);
enumerator->MoveNext(&hasRun);
}
SafeRelease(&enumerator);
return S_OK;
}
}
// Draw by IDWriteFactory (without color emoji)
pDWC_->mRT->DrawGlyphRun(
D2D1::Point2F(
baselineOriginX + context->offsetX,
baselineOriginY),
&adjustedGlyphRun,
pDWC_->SolidBrush(context->color),
DWRITE_MEASURING_MODE_NATURAL);
return S_OK;
}
public:
IFACEMETHOD_(unsigned long, AddRef) ()
{
@@ -385,80 +556,28 @@ public:
private:
long cRefCount_;
IDWriteBitmapRenderTarget* pRenderTarget_;
IDWriteRenderingParams* pRenderingParams_;
};
struct DWriteContext {
FLOAT mDpiScaleX;
FLOAT mDpiScaleY;
bool mDrawing;
ID2D1Factory *mD2D1Factory;
ID2D1DCRenderTarget *mRT;
ID2D1SolidColorBrush *mBrush;
IDWriteFactory *mDWriteFactory;
IDWriteGdiInterop *mGdiInterop;
IDWriteRenderingParams *mRenderingParams;
IDWriteTextFormat *mTextFormat;
HFONT mLastHFont;
DWRITE_FONT_WEIGHT mFontWeight;
DWRITE_FONT_STYLE mFontStyle;
D2D1_TEXT_ANTIALIAS_MODE mTextAntialiasMode;
// METHODS
DWriteContext();
virtual ~DWriteContext();
HRESULT SetLOGFONT(const LOGFONTW &logFont, float fontSize);
void SetFont(HFONT hFont);
void SetFont(const LOGFONTW &logFont);
void DrawText(HDC hdc, const WCHAR* text, int len,
int x, int y, int w, int h, int cellWidth, COLORREF color);
float PixelsToDipsX(int x);
float PixelsToDipsY(int y);
void SetRenderingParams(
const DWriteRenderingParams *params);
DWriteRenderingParams *GetRenderingParams(
DWriteRenderingParams *params);
DWriteContext* pDWC_;
};
DWriteContext::DWriteContext() :
mDpiScaleX(1.f),
mDpiScaleY(1.f),
mHDC(NULL),
mDrawing(false),
mFallbackDC(false),
mD2D1Factory(NULL),
mRT(NULL),
mBrush(NULL),
mDWriteFactory(NULL),
mDWriteFactory2(NULL),
mGdiInterop(NULL),
mRenderingParams(NULL),
mFontCache(8),
mTextFormat(NULL),
mLastHFont(NULL),
mFontWeight(DWRITE_FONT_WEIGHT_NORMAL),
mFontStyle(DWRITE_FONT_STYLE_NORMAL),
mTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_DEFAULT)
{
HRESULT hr;
HDC screen = ::GetDC(0);
mDpiScaleX = ::GetDeviceCaps(screen, LOGPIXELSX) / 96.0f;
mDpiScaleY = ::GetDeviceCaps(screen, LOGPIXELSY) / 96.0f;
::ReleaseDC(0, screen);
hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,
__uuidof(ID2D1Factory), NULL,
reinterpret_cast<void**>(&mD2D1Factory));
@@ -495,6 +614,15 @@ DWriteContext::DWriteContext() :
mDWriteFactory);
}
if (SUCCEEDED(hr))
{
DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory2),
reinterpret_cast<IUnknown**>(&mDWriteFactory2));
_RPT1(_CRT_WARN, "IDWriteFactory2: %s\n", SUCCEEDED(hr) ? "available" : "not available");
}
if (SUCCEEDED(hr))
{
hr = mDWriteFactory->GetGdiInterop(&mGdiInterop);
@@ -515,20 +643,24 @@ DWriteContext::~DWriteContext()
SafeRelease(&mRenderingParams);
SafeRelease(&mGdiInterop);
SafeRelease(&mDWriteFactory);
SafeRelease(&mDWriteFactory2);
SafeRelease(&mBrush);
SafeRelease(&mRT);
SafeRelease(&mD2D1Factory);
}
HRESULT
DWriteContext::SetLOGFONT(const LOGFONTW &logFont, float fontSize)
DWriteContext::CreateTextFormatFromLOGFONT(const LOGFONTW &logFont,
IDWriteTextFormat **ppTextFormat)
{
// Most of this function is copy from: http://msdn.microsoft.com/en-us/library/windows/desktop/dd941783(v=vs.85).aspx
// Most of this function is copied from: https://github.com/Microsoft/Windows-classic-samples/blob/master/Samples/Win7Samples/multimedia/DirectWrite/RenderTest/TextHelpers.cpp
HRESULT hr = S_OK;
IDWriteTextFormat *pTextFormat = NULL;
IDWriteFont *font = NULL;
IDWriteFontFamily *fontFamily = NULL;
IDWriteLocalizedStrings *localizedFamilyNames = NULL;
float fontSize = 0;
if (SUCCEEDED(hr))
{
@@ -561,33 +693,30 @@ DWriteContext::SetLOGFONT(const LOGFONTW &logFont, float fontSize)
if (SUCCEEDED(hr))
{
// If no font size was passed in use the lfHeight of the LOGFONT.
if (fontSize == 0)
// Use lfHeight of the LOGFONT as font size.
fontSize = float(logFont.lfHeight);
if (fontSize < 0)
{
// Convert from pixels to DIPs.
fontSize = PixelsToDipsY(logFont.lfHeight);
if (fontSize < 0)
{
// Negative lfHeight represents the size of the em unit.
fontSize = -fontSize;
}
else
{
// Positive lfHeight represents the cell height (ascent +
// descent).
DWRITE_FONT_METRICS fontMetrics;
font->GetMetrics(&fontMetrics);
// Negative lfHeight represents the size of the em unit.
fontSize = -fontSize;
}
else
{
// Positive lfHeight represents the cell height (ascent +
// descent).
DWRITE_FONT_METRICS fontMetrics;
font->GetMetrics(&fontMetrics);
// Convert the cell height (ascent + descent) from design units
// to ems.
float cellHeight = static_cast<float>(
fontMetrics.ascent + fontMetrics.descent)
/ fontMetrics.designUnitsPerEm;
// Convert the cell height (ascent + descent) from design units
// to ems.
float cellHeight = static_cast<float>(
fontMetrics.ascent + fontMetrics.descent)
/ fontMetrics.designUnitsPerEm;
// Divide the font size by the cell height to get the font em
// size.
fontSize /= cellHeight;
}
// Divide the font size by the cell height to get the font em
// size.
fontSize /= cellHeight;
}
}
@@ -612,123 +741,165 @@ DWriteContext::SetLOGFONT(const LOGFONTW &logFont, float fontSize)
font->GetStretch(),
fontSize,
localeName,
&mTextFormat);
&pTextFormat);
}
if (SUCCEEDED(hr))
{
mFontWeight = static_cast<DWRITE_FONT_WEIGHT>(logFont.lfWeight);
mFontStyle = logFont.lfItalic ? DWRITE_FONT_STYLE_ITALIC
: DWRITE_FONT_STYLE_NORMAL;
}
hr = pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
if (SUCCEEDED(hr))
hr = pTextFormat->SetParagraphAlignment(
DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
if (SUCCEEDED(hr))
hr = pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
SafeRelease(&localizedFamilyNames);
SafeRelease(&fontFamily);
SafeRelease(&font);
if (SUCCEEDED(hr))
*ppTextFormat = pTextFormat;
else
SafeRelease(&pTextFormat);
return hr;
}
HRESULT
DWriteContext::SetFontByLOGFONT(const LOGFONTW &logFont)
{
HRESULT hr = S_OK;
IDWriteTextFormat *pTextFormat = NULL;
hr = CreateTextFormatFromLOGFONT(logFont, &pTextFormat);
if (SUCCEEDED(hr))
{
SafeRelease(&mTextFormat);
mTextFormat = pTextFormat;
mFontWeight = static_cast<DWRITE_FONT_WEIGHT>(logFont.lfWeight);
mFontStyle = logFont.lfItalic ? DWRITE_FONT_STYLE_ITALIC
: DWRITE_FONT_STYLE_NORMAL;
}
return hr;
}
void
DWriteContext::SetFont(HFONT hFont)
{
if (mLastHFont != hFont)
FontCache::Item item;
if (mFontCache.get(hFont, item))
{
LOGFONTW lf;
if (GetObjectW(hFont, sizeof(lf), &lf))
if (item.pTextFormat != NULL)
{
SetFont(lf);
mLastHFont = hFont;
item.pTextFormat->AddRef();
SafeRelease(&mTextFormat);
mTextFormat = item.pTextFormat;
mFontWeight = item.fontWeight;
mFontStyle = item.fontStyle;
mFallbackDC = false;
}
else
mFallbackDC = true;
return;
}
HRESULT hr = E_FAIL;
LOGFONTW lf;
if (GetObjectW(hFont, sizeof(lf), &lf))
hr = SetFontByLOGFONT(lf);
item.hFont = hFont;
if (SUCCEEDED(hr))
{
item.pTextFormat = mTextFormat;
item.fontWeight = mFontWeight;
item.fontStyle = mFontStyle;
}
mFontCache.put(item);
}
void
DWriteContext::SetFont(const LOGFONTW &logFont)
DWriteContext::BindDC(HDC hdc, RECT *rect)
{
SafeRelease(&mTextFormat);
mLastHFont = NULL;
HRESULT hr = SetLOGFONT(logFont, 0.f);
if (SUCCEEDED(hr))
hr = mTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
if (SUCCEEDED(hr))
hr = mTextFormat->SetParagraphAlignment(
DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
if (SUCCEEDED(hr))
hr = mTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
Flush();
mRT->BindDC(hdc, rect);
mRT->SetTransform(D2D1::IdentityMatrix());
mHDC = hdc;
}
void
DWriteContext::DrawText(HDC hdc, const WCHAR* text, int len,
int x, int y, int w, int h, int cellWidth, COLORREF color)
DWriteContext::AssureDrawing()
{
HRESULT hr = S_OK;
IDWriteBitmapRenderTarget *bmpRT = NULL;
if (mDrawing == false)
{
mRT->BeginDraw();
mDrawing = true;
}
}
// Skip when any fonts are not set.
if (mTextFormat == NULL)
ID2D1Brush*
DWriteContext::SolidBrush(COLORREF color)
{
mBrush->SetColor(D2D1::ColorF(UINT32(GetRValue(color)) << 16 |
UINT32(GetGValue(color)) << 8 | UINT32(GetBValue(color))));
return mBrush;
}
void
DWriteContext::DrawText(const WCHAR* text, int len,
int x, int y, int w, int h, int cellWidth, COLORREF color,
UINT fuOptions, CONST RECT *lprc, CONST INT * lpDx)
{
if (mFallbackDC)
{
Flush();
ExtTextOutW(mHDC, x, y, fuOptions, lprc, text, len, lpDx);
return;
}
// Check possibility of zero divided error.
if (cellWidth == 0 || mDpiScaleX == 0.0f || mDpiScaleY == 0.0f)
return;
AssureDrawing();
if (SUCCEEDED(hr))
hr = mGdiInterop->CreateBitmapRenderTarget(hdc, w, h, &bmpRT);
HRESULT hr;
IDWriteTextLayout *textLayout = NULL;
hr = mDWriteFactory->CreateTextLayout(text, len, mTextFormat,
FLOAT(w), FLOAT(h), &textLayout);
if (SUCCEEDED(hr))
{
IDWriteTextLayout *textLayout = NULL;
DWRITE_TEXT_RANGE textRange = { 0, UINT32(len) };
textLayout->SetFontWeight(mFontWeight, textRange);
textLayout->SetFontStyle(mFontStyle, textRange);
HDC memdc = bmpRT->GetMemoryDC();
BitBlt(memdc, 0, 0, w, h, hdc, x, y, SRCCOPY);
hr = mDWriteFactory->CreateGdiCompatibleTextLayout(
text, len, mTextFormat, PixelsToDipsX(w),
PixelsToDipsY(h), mDpiScaleX, NULL, TRUE, &textLayout);
if (SUCCEEDED(hr))
{
DWRITE_TEXT_RANGE textRange = { 0, (UINT32)len };
textLayout->SetFontWeight(mFontWeight, textRange);
textLayout->SetFontStyle(mFontStyle, textRange);
}
if (SUCCEEDED(hr))
{
GdiTextRenderer *renderer = new GdiTextRenderer(bmpRT,
mRenderingParams);
GdiTextRendererContext data = {
color,
PixelsToDipsX(cellWidth),
0.0f
};
textLayout->Draw(&data, renderer, 0, 0);
SafeRelease(&renderer);
}
BitBlt(hdc, x, y, w, h, memdc, 0, 0, SRCCOPY);
SafeRelease(&textLayout);
TextRenderer renderer(this);
TextRendererContext context = { color, FLOAT(cellWidth), 0.0f };
textLayout->Draw(&context, &renderer, FLOAT(x), FLOAT(y));
}
SafeRelease(&bmpRT);
SafeRelease(&textLayout);
}
float
DWriteContext::PixelsToDipsX(int x)
void
DWriteContext::FillRect(RECT *rc, COLORREF color)
{
return x / mDpiScaleX;
AssureDrawing();
mRT->FillRectangle(
D2D1::RectF(FLOAT(rc->left), FLOAT(rc->top),
FLOAT(rc->right), FLOAT(rc->bottom)),
SolidBrush(color));
}
float
DWriteContext::PixelsToDipsY(int y)
void
DWriteContext::Flush()
{
return y / mDpiScaleY;
if (mDrawing)
{
mRT->EndDraw();
mDrawing = false;
}
}
void
@@ -757,6 +928,10 @@ DWriteContext::SetRenderingParams(
SafeRelease(&mRenderingParams);
mRenderingParams = renderingParams;
mTextAntialiasMode = textAntialiasMode;
Flush();
mRT->SetTextRenderingParams(mRenderingParams);
mRT->SetTextAntialiasMode(mTextAntialiasMode);
}
}
@@ -824,40 +999,23 @@ DWriteContext_Open(void)
return new DWriteContext();
}
void
DWriteContext_BeginDraw(DWriteContext *ctx)
{
if (ctx != NULL && ctx->mRT != NULL)
{
ctx->mRT->BeginDraw();
ctx->mRT->SetTransform(D2D1::IdentityMatrix());
ctx->mDrawing = true;
}
}
void
DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, RECT *rect)
{
if (ctx != NULL && ctx->mRT != NULL)
{
ctx->mRT->BindDC(hdc, rect);
ctx->mRT->SetTextAntialiasMode(ctx->mTextAntialiasMode);
}
if (ctx != NULL)
ctx->BindDC(hdc, rect);
}
void
DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont)
{
if (ctx != NULL)
{
ctx->SetFont(hFont);
}
}
void
DWriteContext_DrawText(
DWriteContext *ctx,
HDC hdc,
const WCHAR* text,
int len,
int x,
@@ -865,20 +1023,28 @@ DWriteContext_DrawText(
int w,
int h,
int cellWidth,
COLORREF color)
COLORREF color,
UINT fuOptions,
CONST RECT *lprc,
CONST INT * lpDx)
{
if (ctx != NULL)
ctx->DrawText(hdc, text, len, x, y, w, h, cellWidth, color);
ctx->DrawText(text, len, x, y, w, h, cellWidth, color,
fuOptions, lprc, lpDx);
}
void
DWriteContext_EndDraw(DWriteContext *ctx)
DWriteContext_FillRect(DWriteContext *ctx, RECT *rc, COLORREF color)
{
if (ctx != NULL && ctx->mRT != NULL)
{
ctx->mRT->EndDraw();
ctx->mDrawing = false;
}
if (ctx != NULL)
ctx->FillRect(rc, color);
}
void
DWriteContext_Flush(DWriteContext *ctx)
{
if (ctx != NULL)
ctx->Flush();
}
void

View File

@@ -4,6 +4,7 @@
*
* Contributors:
* - Ken Takata
* - Yasuhiro Matsumoto
*
* Copyright (C) 2013 MURAOKA Taro <koron.kaoriya@gmail.com>
* THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE.
@@ -54,12 +55,10 @@ void DWrite_Init(void);
void DWrite_Final(void);
DWriteContext *DWriteContext_Open(void);
void DWriteContext_BeginDraw(DWriteContext *ctx);
void DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, RECT *rect);
void DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont);
void DWriteContext_DrawText(
DWriteContext *ctx,
HDC hdc,
const WCHAR* text,
int len,
int x,
@@ -67,8 +66,12 @@ void DWriteContext_DrawText(
int w,
int h,
int cellWidth,
COLORREF color);
void DWriteContext_EndDraw(DWriteContext *ctx);
COLORREF color,
UINT fuOptions,
CONST RECT *lprc,
CONST INT * lpDx);
void DWriteContext_FillRect(DWriteContext *ctx, RECT *rc, COLORREF color);
void DWriteContext_Flush(DWriteContext *ctx);
void DWriteContext_Close(DWriteContext *ctx);
void DWriteContext_SetRenderingParams(

View File

@@ -2024,15 +2024,15 @@ gui_mac_handle_window_activate(
switch (eventKind)
{
case kEventWindowActivated:
#if defined(USE_IM_CONTROL)
# if defined(FEAT_MBYTE)
im_on_window_switch(TRUE);
#endif
# endif
return noErr;
case kEventWindowDeactivated:
#if defined(USE_IM_CONTROL)
# if defined(FEAT_MBYTE)
im_on_window_switch(FALSE);
#endif
# endif
return noErr;
}
}
@@ -6230,7 +6230,7 @@ char_u *FullPathFromFSSpec_save(FSSpec file)
#endif
}
#if (defined(USE_IM_CONTROL) || defined(PROTO)) && defined(USE_CARBONKEYHANDLER)
#if (defined(FEAT_MBYTE) || defined(PROTO)) && defined(USE_CARBONKEYHANDLER)
/*
* Input Method Control functions.
*/
@@ -6317,7 +6317,7 @@ im_set_active(int active)
ScriptLanguageRecord *slptr = NULL;
OSStatus err;
if (! gui.in_use)
if (!gui.in_use)
return;
if (im_initialized == 0)
@@ -6379,7 +6379,7 @@ im_get_status(void)
return im_is_active;
}
#endif /* defined(USE_IM_CONTROL) || defined(PROTO) */
#endif /* defined(FEAT_MBYTE) || defined(PROTO) */

View File

@@ -34,28 +34,14 @@ static DWriteContext *s_dwc = NULL;
static int s_directx_enabled = 0;
static int s_directx_load_attempted = 0;
# define IS_ENABLE_DIRECTX() (s_directx_enabled && s_dwc != NULL)
static int directx_enabled(void);
static void directx_binddc(void);
#endif
#ifdef FEAT_MENU
static int gui_mswin_get_menu_height(int fix_window);
#endif
#if defined(FEAT_DIRECTX) || defined(PROTO)
int
directx_enabled(void)
{
if (s_dwc != NULL)
return 1;
else if (s_directx_load_attempted)
return 0;
/* load DirectX */
DWrite_Init();
s_directx_load_attempted = 1;
s_dwc = DWriteContext_Open();
return s_dwc != NULL ? 1 : 0;
}
#endif
#if defined(FEAT_RENDER_OPTIONS) || defined(PROTO)
int
gui_mch_set_rendering_options(char_u *s)
@@ -369,6 +355,34 @@ static int allow_scrollbar = FALSE;
# define MyTranslateMessage(x) TranslateMessage(x)
#endif
#if defined(FEAT_DIRECTX)
static int
directx_enabled(void)
{
if (s_dwc != NULL)
return 1;
else if (s_directx_load_attempted)
return 0;
/* load DirectX */
DWrite_Init();
s_directx_load_attempted = 1;
s_dwc = DWriteContext_Open();
directx_binddc();
return s_dwc != NULL ? 1 : 0;
}
static void
directx_binddc(void)
{
if (s_textArea != NULL)
{
RECT rect;
GetClientRect(s_textArea, &rect);
DWriteContext_BindDC(s_dwc, s_hdc, &rect);
}
}
#endif
#if defined(FEAT_MBYTE) || defined(GLOBAL_IME)
/* use of WindowProc depends on wide_WindowProc */
# define MyWindowProc vim_WindowProc
@@ -485,12 +499,10 @@ static void TrackUserActivity(UINT uMsg);
* These LOGFONT used for IME.
*/
#ifdef FEAT_MBYTE
# ifdef USE_IM_CONTROL
/* holds LOGFONT for 'guifontwide' if available, otherwise 'guifont' */
static LOGFONT norm_logfont;
/* holds LOGFONT for 'guifont' always. */
static LOGFONT sub_logfont;
# endif
#endif
#ifdef FEAT_MBYTE_IME
@@ -591,6 +603,10 @@ _OnBlinkTimer(
blink_timer = (UINT) SetTimer(NULL, 0, (UINT)blink_ontime,
(TIMERPROC)_OnBlinkTimer);
}
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
}
static void
@@ -1002,6 +1018,19 @@ _OnMouseMoveOrRelease(
_OnMouseEvent(button, x, y, FALSE, keyFlags);
}
static void
_OnSizeTextArea(
HWND hwnd UNUSED,
UINT state UNUSED,
int cx UNUSED,
int cy UNUSED)
{
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
directx_binddc();
#endif
}
#ifdef FEAT_MENU
/*
* Find the vimmenu_T with the given id
@@ -1236,6 +1265,7 @@ _TextAreaWndProc(
HANDLE_MSG(hwnd, WM_XBUTTONDBLCLK,_OnMouseButtonDown);
HANDLE_MSG(hwnd, WM_XBUTTONDOWN,_OnMouseButtonDown);
HANDLE_MSG(hwnd, WM_XBUTTONUP, _OnMouseMoveOrRelease);
HANDLE_MSG(hwnd, WM_SIZE, _OnSizeTextArea);
#ifdef FEAT_BEVAL_GUI
case WM_NOTIFY: Handle_WM_Notify(hwnd, (LPNMHDR)lParam);
@@ -1635,6 +1665,11 @@ gui_mch_invert_rectangle(
{
RECT rc;
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
/*
* Note: InvertRect() excludes right and bottom of rectangle.
*/
@@ -1663,6 +1698,11 @@ gui_mch_draw_hollow_cursor(guicolor_T color)
HBRUSH hbr;
RECT rc;
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
/*
* Note: FrameRect() excludes right and bottom of rectangle.
*/
@@ -1703,6 +1743,12 @@ gui_mch_draw_part_cursor(
rc.top = FILL_Y(gui.row) + gui.char_height - h;
rc.right = rc.left + w;
rc.bottom = rc.top + h;
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
hbr = CreateSolidBrush(color);
FillRect(s_hdc, &rc, hbr);
DeleteBrush(hbr);
@@ -2858,10 +2904,6 @@ _OnPaint(
out_flush(); /* make sure all output has been processed */
(void)BeginPaint(hwnd, &ps);
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_BeginDraw(s_dwc);
#endif
#ifdef FEAT_MBYTE
/* prevent multi-byte characters from misprinting on an invalid
@@ -2878,19 +2920,11 @@ _OnPaint(
if (!IsRectEmpty(&ps.rcPaint))
{
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_BindDC(s_dwc, s_hdc, &ps.rcPaint);
#endif
gui_redraw(ps.rcPaint.left, ps.rcPaint.top,
ps.rcPaint.right - ps.rcPaint.left + 1,
ps.rcPaint.bottom - ps.rcPaint.top + 1);
}
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_EndDraw(s_dwc);
#endif
EndPaint(hwnd, &ps);
}
}
@@ -3012,6 +3046,11 @@ gui_mch_flash(int msec)
{
RECT rc;
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
/*
* Note: InvertRect() excludes right and bottom of rectangle.
*/
@@ -3084,6 +3123,12 @@ gui_mch_delete_lines(
intel_gpu_workaround();
#if defined(FEAT_DIRECTX)
// Commit drawing queue before ScrollWindowEx.
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
rc.left = FILL_X(gui.scroll_region_left);
rc.right = FILL_X(gui.scroll_region_right + 1);
rc.top = FILL_Y(row);
@@ -3117,6 +3162,12 @@ gui_mch_insert_lines(
intel_gpu_workaround();
#if defined(FEAT_DIRECTX)
// Commit drawing queue before ScrollWindowEx.
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
rc.left = FILL_X(gui.scroll_region_left);
rc.right = FILL_X(gui.scroll_region_right + 1);
rc.top = FILL_Y(row);
@@ -6147,9 +6198,6 @@ gui_mch_draw_string(
#endif
HPEN hpen, old_pen;
int y;
#ifdef FEAT_DIRECTX
int font_is_ttf_or_vector = 0;
#endif
/*
* Italic and bold text seems to have an extra row of pixels at the bottom
@@ -6210,6 +6258,11 @@ gui_mch_draw_string(
hbr = hbr_cache[brush_lru];
brush_lru = !brush_lru;
}
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_FillRect(s_dwc, &rc, gui.currBgColor);
#endif
FillRect(s_hdc, &rc, hbr);
SetBkMode(s_hdc, TRANSPARENT);
@@ -6229,16 +6282,7 @@ gui_mch_draw_string(
#ifdef FEAT_DIRECTX
if (IS_ENABLE_DIRECTX())
{
TEXTMETRIC tm;
GetTextMetrics(s_hdc, &tm);
if (tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR))
{
font_is_ttf_or_vector = 1;
DWriteContext_SetFont(s_dwc, (HFONT)gui.currFont);
}
}
DWriteContext_SetFont(s_dwc, (HFONT)gui.currFont);
#endif
if (pad_size != Columns || padding == NULL || padding[0] != gui.char_width)
@@ -6349,12 +6393,13 @@ gui_mch_draw_string(
++clen;
}
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX() && font_is_ttf_or_vector)
if (IS_ENABLE_DIRECTX())
{
/* Add one to "cells" for italics. */
DWriteContext_DrawText(s_dwc, s_hdc, unicodebuf, wlen,
DWriteContext_DrawText(s_dwc, unicodebuf, wlen,
TEXT_X(col), TEXT_Y(row), FILL_X(cells + 1), FILL_Y(1),
gui.char_width, gui.currFgColor);
gui.char_width, gui.currFgColor,
foptions, pcliprect, unicodepdy);
}
else
#endif
@@ -6413,6 +6458,12 @@ gui_mch_draw_string(
foptions, pcliprect, (char *)text, len, padding);
}
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX() &&
(flags & (DRAW_UNDERL | DRAW_STRIKE | DRAW_UNDERC | DRAW_CURSOR)))
DWriteContext_Flush(s_dwc);
#endif
/* Underline */
if (flags & DRAW_UNDERL)
{
@@ -6475,6 +6526,11 @@ gui_mch_flush(void)
BOOL __stdcall GdiFlush(void);
# endif
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
GdiFlush();
}
@@ -6483,6 +6539,14 @@ clear_rect(RECT *rcp)
{
HBRUSH hbr;
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
{
DWriteContext_FillRect(s_dwc, rcp, gui.back_pixel);
return;
}
#endif
hbr = CreateSolidBrush(gui.back_pixel);
FillRect(s_hdc, rcp, hbr);
DeleteBrush(hbr);
@@ -8388,6 +8452,11 @@ gui_mch_drawsign(int row, int col, int typenr)
if (!gui.in_use || (sign = (signicon_t *)sign_get_image(typenr)) == NULL)
return;
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
x = TEXT_X(col);
y = TEXT_Y(row);
w = gui.char_width * 2;
@@ -8867,6 +8936,11 @@ netbeans_draw_multisign_indicator(int row)
x = 0;
y = TEXT_Y(row);
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
for (i = 0; i < gui.char_height - 3; i++)
SetPixel(s_hdc, x+2, y++, gui.currFgColor);

View File

@@ -4782,6 +4782,48 @@ iconv_end(void)
#endif /* FEAT_MBYTE */
#ifdef FEAT_GUI
# define USE_IMACTIVATEFUNC (!gui.in_use && *p_imaf != NUL)
# define USE_IMSTATUSFUNC (!gui.in_use && *p_imsf != NUL)
#else
# define USE_IMACTIVATEFUNC (*p_imaf != NUL)
# define USE_IMSTATUSFUNC (*p_imsf != NUL)
#endif
#ifdef FEAT_EVAL
static void
call_imactivatefunc(int active)
{
char_u *argv[1];
if (active)
argv[0] = (char_u *)"1";
else
argv[0] = (char_u *)"0";
(void)call_func_retnr(p_imaf, 1, argv, FALSE);
}
static int
call_imstatusfunc(void)
{
int is_active;
/* FIXME: Don't execute user function in unsafe situation. */
if (exiting
# ifdef FEAT_AUTOCMD
|| is_autocmd_blocked()
# endif
)
return FALSE;
/* FIXME: :py print 'xxx' is shown duplicate result.
* Use silent to avoid it. */
++msg_silent;
is_active = call_func_retnr(p_imsf, 0, NULL, FALSE);
--msg_silent;
return (is_active > 0);
}
#endif
#if defined(FEAT_XIM) || defined(PROTO)
# if defined(FEAT_GUI_GTK) || defined(PROTO)
@@ -5654,6 +5696,11 @@ im_synthesize_keypress(unsigned int keyval, unsigned int state)
void
xim_reset(void)
{
#ifdef FEAT_EVAL
if (USE_IMACTIVATEFUNC)
call_imactivatefunc(im_is_active);
else
#endif
if (xic != NULL)
{
gtk_im_context_reset(xic);
@@ -5664,20 +5711,7 @@ xim_reset(void)
{
xim_set_focus(gui.in_focus);
# ifdef FEAT_EVAL
if (p_imaf[0] != NUL)
{
char_u *argv[1];
if (im_is_active)
argv[0] = (char_u *)"1";
else
argv[0] = (char_u *)"0";
(void)call_func_retnr(p_imaf, 1, argv, FALSE);
}
else
# endif
if (im_activatekey_keyval != GDK_VoidSymbol)
if (im_activatekey_keyval != GDK_VoidSymbol)
{
if (im_is_active)
{
@@ -5842,24 +5876,8 @@ xim_queue_key_press_event(GdkEventKey *event, int down)
im_get_status(void)
{
# ifdef FEAT_EVAL
if (p_imsf[0] != NUL)
{
int is_active;
/* FIXME: Don't execute user function in unsafe situation. */
if (exiting
# ifdef FEAT_AUTOCMD
|| is_autocmd_blocked()
# endif
)
return FALSE;
/* FIXME: :py print 'xxx' is shown duplicate result.
* Use silent to avoid it. */
++msg_silent;
is_active = call_func_retnr(p_imsf, 0, NULL, FALSE);
--msg_silent;
return (is_active > 0);
}
if (USE_IMSTATUSFUNC)
return call_imstatusfunc();
# endif
return im_is_active;
}
@@ -5881,30 +5899,43 @@ im_is_preediting(void)
static int xim_is_active = FALSE; /* XIM should be active in the current
mode */
static int xim_has_focus = FALSE; /* XIM is really being used for Vim */
#ifdef FEAT_GUI_X11
# ifdef FEAT_GUI_X11
static XIMStyle input_style;
static int status_area_enabled = TRUE;
#endif
# endif
/*
* Switch using XIM on/off. This is used by the code that changes "State".
* When 'imactivatefunc' is defined use that function instead.
*/
void
im_set_active(int active)
im_set_active(int active_arg)
{
if (xic == NULL)
return;
int active = active_arg;
/* If 'imdisable' is set, XIM is never active. */
if (p_imdisable)
active = FALSE;
#if !defined(FEAT_GUI_GTK)
else if (input_style & XIMPreeditPosition)
/* There is a problem in switching XIM off when preediting is used,
* and it is not clear how this can be solved. For now, keep XIM on
* all the time, like it was done in Vim 5.8. */
active = TRUE;
#endif
# if defined(FEAT_EVAL)
if (USE_IMACTIVATEFUNC)
{
if (active != im_get_status())
{
call_imactivatefunc(active);
xim_has_focus = active;
}
return;
}
# endif
if (xic == NULL)
return;
/* Remember the active state, it is needed when Vim gets keyboard focus. */
xim_is_active = active;
@@ -6006,19 +6037,19 @@ xim_set_preedit(void)
}
}
#if defined(FEAT_GUI_X11)
# if defined(FEAT_GUI_X11)
static char e_xim[] = N_("E285: Failed to create input context");
#endif
# endif
#if defined(FEAT_GUI_X11) || defined(PROTO)
# if defined(XtSpecificationRelease) && XtSpecificationRelease >= 6 && !defined(SUN_SYSTEM)
# define USE_X11R6_XIM
# endif
# if defined(FEAT_GUI_X11) || defined(PROTO)
# if defined(XtSpecificationRelease) && XtSpecificationRelease >= 6 && !defined(SUN_SYSTEM)
# define USE_X11R6_XIM
# endif
static int xim_real_init(Window x11_window, Display *x11_display);
#ifdef USE_X11R6_XIM
# ifdef USE_X11R6_XIM
static void xim_destroy_cb(XIM im, XPointer client_data, XPointer call_data);
static void
@@ -6030,9 +6061,9 @@ xim_instantiate_cb(
Window x11_window;
Display *x11_display;
#ifdef XIM_DEBUG
# ifdef XIM_DEBUG
xim_log("xim_instantiate_cb()\n");
#endif
# endif
gui_get_x11_windis(&x11_window, &x11_display);
if (display != x11_display)
@@ -6054,9 +6085,9 @@ xim_destroy_cb(
Window x11_window;
Display *x11_display;
#ifdef XIM_DEBUG
# ifdef XIM_DEBUG
xim_log("xim_destroy_cb()\n");
#endif
#endif
gui_get_x11_windis(&x11_window, &x11_display);
xic = NULL;
@@ -6067,7 +6098,7 @@ xim_destroy_cb(
XRegisterIMInstantiateCallback(x11_display, NULL, NULL, NULL,
xim_instantiate_cb, NULL);
}
#endif
# endif
void
xim_init(void)
@@ -6075,9 +6106,9 @@ xim_init(void)
Window x11_window;
Display *x11_display;
#ifdef XIM_DEBUG
# ifdef XIM_DEBUG
xim_log("xim_init()\n");
#endif
# endif
gui_get_x11_windis(&x11_window, &x11_display);
@@ -6088,10 +6119,10 @@ xim_init(void)
gui_set_shellsize(FALSE, FALSE, RESIZE_BOTH);
#ifdef USE_X11R6_XIM
# ifdef USE_X11R6_XIM
XRegisterIMInstantiateCallback(x11_display, NULL, NULL, NULL,
xim_instantiate_cb, NULL);
#endif
# endif
}
static int
@@ -6103,7 +6134,7 @@ xim_real_init(Window x11_window, Display *x11_display)
*ns,
*end,
tmp[1024];
#define IMLEN_MAX 40
# define IMLEN_MAX 40
char buf[IMLEN_MAX + 7];
XIM xim = NULL;
XIMStyles *xim_styles;
@@ -6168,7 +6199,7 @@ xim_real_init(Window x11_window, Display *x11_display)
return FALSE;
}
#ifdef USE_X11R6_XIM
# ifdef USE_X11R6_XIM
{
XIMCallback destroy_cb;
@@ -6177,7 +6208,7 @@ xim_real_init(Window x11_window, Display *x11_display)
if (XSetIMValues(xim, XNDestroyCallback, &destroy_cb, NULL))
EMSG(_("E287: Warning: Could not set destroy callback to IM"));
}
#endif
# endif
if (XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL) || !xim_styles)
{
@@ -6253,7 +6284,7 @@ xim_real_init(Window x11_window, Display *x11_display)
/* A crash was reported when trying to pass gui.norm_font as XNFontSet,
* thus that has been removed. Hopefully the default works... */
#ifdef FEAT_XFONTSET
# ifdef FEAT_XFONTSET
if (gui.fontset != NOFONTSET)
{
preedit_list = XVaCreateNestedList(0,
@@ -6269,7 +6300,7 @@ xim_real_init(Window x11_window, Display *x11_display)
NULL);
}
else
#endif
# endif
{
preedit_list = XVaCreateNestedList(0,
XNSpotLocation, &over_spot,
@@ -6303,7 +6334,8 @@ xim_real_init(Window x11_window, Display *x11_display)
}
else
{
EMSG(_(e_xim));
if (!is_not_a_term())
EMSG(_(e_xim));
XCloseIM(xim);
return FALSE;
}
@@ -6311,7 +6343,7 @@ xim_real_init(Window x11_window, Display *x11_display)
return TRUE;
}
#endif /* FEAT_GUI_X11 */
# endif /* FEAT_GUI_X11 */
/*
* Get IM status. When IM is on, return TRUE. Else return FALSE.
@@ -6322,6 +6354,10 @@ xim_real_init(Window x11_window, Display *x11_display)
int
im_get_status(void)
{
# ifdef FEAT_EVAL
if (USE_IMSTATUSFUNC)
return call_imstatusfunc();
# endif
return xim_has_focus;
}
@@ -6442,6 +6478,43 @@ xim_get_status_area_height(void)
}
# endif
#else /* !defined(FEAT_XIM) */
# if !defined(FEAT_GUI_W32) || !(defined(FEAT_MBYTE_IME) || defined(GLOBAL_IME))
static int im_was_set_active = FALSE;
int
im_get_status()
{
# ifdef FEAT_EVAL
if (USE_IMSTATUSFUNC)
return call_imstatusfunc();
# endif
return im_was_set_active;
}
void
im_set_active(int active_arg)
{
# if defined(FEAT_MBYTE) && defined(FEAT_EVAL)
int active = !p_imdisable && active_arg;
if (USE_IMACTIVATEFUNC && active != im_get_status())
{
call_imactivatefunc(active);
im_was_set_active = active;
}
# endif
}
# ifdef FEAT_GUI
void
im_set_position(int row, int col)
{
}
# endif
# endif
#endif /* FEAT_XIM */
#if defined(FEAT_MBYTE) || defined(PROTO)

View File

@@ -892,7 +892,7 @@ getcount:
int lit = FALSE; /* get extra character literally */
int langmap_active = FALSE; /* using :lmap mappings */
int lang; /* getting a text character */
#ifdef USE_IM_CONTROL
#ifdef FEAT_MBYTE
int save_smd; /* saved value of p_smd */
#endif
@@ -957,7 +957,7 @@ getcount:
State = LANGMAP;
langmap_active = TRUE;
}
#ifdef USE_IM_CONTROL
#ifdef FEAT_MBYTE
save_smd = p_smd;
p_smd = FALSE; /* Don't let the IM code show the mode here */
if (lang && curbuf->b_p_iminsert == B_IMODE_IM)
@@ -973,7 +973,7 @@ getcount:
++allow_keys;
State = NORMAL_BUSY;
}
#ifdef USE_IM_CONTROL
#ifdef FEAT_MBYTE
if (lang)
{
if (curbuf->b_p_iminsert != B_IMODE_LMAP)

View File

@@ -1539,7 +1539,7 @@ static struct vimoption options[] =
(char_u *)&p_ic, PV_NONE,
{(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
{"imactivatefunc","imaf",P_STRING|P_VI_DEF|P_SECURE,
# if defined(FEAT_EVAL) && defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
#if defined(FEAT_EVAL) && defined(FEAT_MBYTE)
(char_u *)&p_imaf, PV_NONE,
{(char_u *)"", (char_u *)NULL}
# else
@@ -1555,14 +1555,14 @@ static struct vimoption options[] =
#endif
{(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
{"imcmdline", "imc", P_BOOL|P_VI_DEF,
#ifdef USE_IM_CONTROL
#ifdef FEAT_MBYTE
(char_u *)&p_imcmdline, PV_NONE,
#else
(char_u *)NULL, PV_NONE,
#endif
{(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
{"imdisable", "imd", P_BOOL|P_VI_DEF,
#ifdef USE_IM_CONTROL
#ifdef FEAT_MBYTE
(char_u *)&p_imdisable, PV_NONE,
#else
(char_u *)NULL, PV_NONE,
@@ -1582,7 +1582,7 @@ static struct vimoption options[] =
{(char_u *)B_IMODE_USE_INSERT, (char_u *)0L}
SCRIPTID_INIT},
{"imstatusfunc","imsf",P_STRING|P_VI_DEF|P_SECURE,
#if defined(FEAT_EVAL) && defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
#if defined(FEAT_EVAL) && defined(FEAT_MBYTE)
(char_u *)&p_imsf, PV_NONE,
{(char_u *)"", (char_u *)NULL}
#else
@@ -8469,7 +8469,7 @@ set_bool_option(
}
#endif
#ifdef USE_IM_CONTROL
#ifdef FEAT_MBYTE
/* 'imdisable' */
else if ((int *)varp == &p_imdisable)
{

View File

@@ -581,13 +581,15 @@ EXTERN char_u *p_iconstring; /* 'iconstring' */
EXTERN int p_ic; /* 'ignorecase' */
#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
EXTERN char_u *p_imak; /* 'imactivatekey' */
#define IM_ON_THE_SPOT 0L
#define IM_OVER_THE_SPOT 1L
EXTERN long p_imst; /* 'imstyle' */
#endif
#if defined(FEAT_EVAL) && defined(FEAT_MBYTE)
EXTERN char_u *p_imaf; /* 'imactivatefunc' */
EXTERN char_u *p_imsf; /* 'imstatusfunc' */
EXTERN long p_imst; /* 'imstyle' */
# define IM_ON_THE_SPOT 0L
# define IM_OVER_THE_SPOT 1L
#endif
#ifdef USE_IM_CONTROL
#ifdef FEAT_MBYTE
EXTERN int p_imcmdline; /* 'imcmdline' */
EXTERN int p_imdisable; /* 'imdisable' */
#endif

View File

@@ -836,7 +836,7 @@ split_message(char_u *mesg, pumitem_T **array)
item->bytelen = p - item->start;
if (item->cells > max_cells)
max_cells = item->cells;
long_item_count += item->cells / BALLOON_MIN_WIDTH;
long_item_count += (item->cells - 1) / BALLOON_MIN_WIDTH;
}
height = 2 + ga.ga_len;

View File

@@ -1,5 +1,4 @@
/* gui_w32.c */
int directx_enabled(void);
int gui_mch_set_rendering_options(char_u *s);
int gui_mch_is_blinking(void);
int gui_mch_is_blink_off(void);

View File

@@ -2091,12 +2091,8 @@ struct file_buffer
#define B_IMODE_USE_INSERT -1 /* Use b_p_iminsert value for search */
#define B_IMODE_NONE 0 /* Input via none */
#define B_IMODE_LMAP 1 /* Input via langmap */
#ifndef USE_IM_CONTROL
# define B_IMODE_LAST 1
#else
# define B_IMODE_IM 2 /* Input via input method */
# define B_IMODE_LAST 2
#endif
#define B_IMODE_IM 2 /* Input via input method */
#define B_IMODE_LAST 2
#ifdef FEAT_KEYMAP
short b_kmap_state; /* using "lmap" mappings */

View File

@@ -115,6 +115,7 @@ NEW_TESTS = test_arabic.res \
test_highlight.res \
test_history.res \
test_hlsearch.res \
test_iminsert.res \
test_increment.res \
test_increment_dbcs.res \
test_ins_complete.res \

View File

@@ -0,0 +1,31 @@
if !has('multi_byte')
finish
endif
source view_util.vim
let s:imactivatefunc_called = 0
let s:imstatusfunc_called = 0
func IM_activatefunc(active)
let s:imactivatefunc_called = 1
endfunc
func IM_statusfunc()
let s:imstatusfunc_called = 1
return 0
endfunc
func Test_iminsert2()
set imactivatefunc=IM_activatefunc
set imstatusfunc=IM_statusfunc
set iminsert=2
normal! i
set iminsert=0
set imactivatefunc=
set imstatusfunc=
let expected = has('gui_running') ? 0 : 1
call assert_equal(expected, s:imactivatefunc_called)
call assert_equal(expected, s:imstatusfunc_called)
endfunc

View File

@@ -707,6 +707,10 @@ func Test_balloon_split()
if !exists('*balloon_split')
return
endif
call assert_equal([
\ 'tempname: 0x555555e380a0 "/home/mool/.viminfz.tmp"',
\ ], balloon_split(
\ 'tempname: 0x555555e380a0 "/home/mool/.viminfz.tmp"'))
call assert_equal([
\ 'one two three four one two three four one two thre',
\ 'e four',

View File

@@ -100,3 +100,11 @@ func Test_writefile_sync_arg()
call writefile(['two'], 'Xtest', 'S')
call delete('Xtest')
endfunc
func Test_writefile_sync_dev_stdout()
if !has('unix')
return
endif
" Just check that this doesn't cause an error.
call writefile(['one'], '/dev/stdout')
endfunc

View File

@@ -3307,7 +3307,7 @@ ui_focus_change(
}
#endif
#if defined(USE_IM_CONTROL) || defined(PROTO)
#if defined(FEAT_MBYTE) || defined(PROTO)
/*
* Save current Input Method status to specified place.
*/

View File

@@ -771,6 +771,32 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1346,
/**/
1345,
/**/
1344,
/**/
1343,
/**/
1342,
/**/
1341,
/**/
1340,
/**/
1339,
/**/
1338,
/**/
1337,
/**/
1336,
/**/
1335,
/**/
1334,
/**/
1333,
/**/

View File

@@ -533,15 +533,6 @@ typedef unsigned long u8char_T; /* long should be 32 bits or more */
# endif
#endif
/*
* Check input method control.
*/
#if defined(FEAT_XIM) \
|| (defined(FEAT_GUI) && (defined(FEAT_MBYTE_IME) || defined(GLOBAL_IME))) \
|| (defined(FEAT_GUI_MAC) && defined(FEAT_MBYTE))
# define USE_IM_CONTROL
#endif
/*
* For dynamically loaded gettext library. Currently, only for Win32.
*/
@@ -1485,6 +1476,11 @@ typedef UINT32_TYPEDEF UINT32_T;
#define MIN_COLUMNS 12 /* minimal columns for screen */
#define MIN_LINES 2 /* minimal lines for screen */
#define STATUS_HEIGHT 1 /* height of a status line under a window */
#ifdef FEAT_MENU /* height of a status line under a window */
# define WINBAR_HEIGHT(wp) (wp)->w_winbar_height
#else
# define WINBAR_HEIGHT(wp) 0
#endif
#define QF_WINHEIGHT 10 /* default height for quickfix window */
/*

View File

@@ -1098,21 +1098,14 @@ win_split_ins(
/* set height and row of new window to full height */
wp->w_winrow = tabline_height();
win_new_height(wp, curfrp->fr_height - (p_ls > 0)
#ifdef FEAT_MENU
- wp->w_winbar_height
#endif
);
- WINBAR_HEIGHT(wp));
wp->w_status_height = (p_ls > 0);
}
else
{
/* height and row of new window is same as current window */
wp->w_winrow = oldwin->w_winrow;
win_new_height(wp, oldwin->w_height
#ifdef FEAT_MENU
+ oldwin->w_winbar_height
#endif
);
win_new_height(wp, oldwin->w_height + WINBAR_HEIGHT(oldwin));
wp->w_status_height = oldwin->w_status_height;
}
frp->fr_height = curfrp->fr_height;
@@ -1171,10 +1164,7 @@ win_split_ins(
if (flags & (WSP_TOP | WSP_BOT))
{
int new_fr_height = curfrp->fr_height - new_size
#ifdef FEAT_MENU
+ wp->w_winbar_height
#endif
;
+ WINBAR_HEIGHT(wp) ;
if (!((flags & WSP_BOT) && p_ls == 0))
new_fr_height -= STATUS_HEIGHT;
@@ -1190,7 +1180,8 @@ win_split_ins(
}
else /* new window below current one */
{
wp->w_winrow = oldwin->w_winrow + oldwin->w_height + STATUS_HEIGHT;
wp->w_winrow = oldwin->w_winrow + oldwin->w_height
+ STATUS_HEIGHT + WINBAR_HEIGHT(oldwin);
wp->w_status_height = oldwin->w_status_height;
if (!(flags & WSP_BOT))
oldwin->w_status_height = STATUS_HEIGHT;
@@ -2867,10 +2858,7 @@ frame_new_height(
/* Simple case: just one window. */
win_new_height(topfrp->fr_win,
height - topfrp->fr_win->w_status_height
#ifdef FEAT_MENU
- topfrp->fr_win->w_winbar_height
#endif
);
- WINBAR_HEIGHT(topfrp->fr_win));
}
else if (topfrp->fr_layout == FR_ROW)
{
@@ -3217,10 +3205,7 @@ frame_fix_width(win_T *wp)
frame_fix_height(win_T *wp)
{
wp->w_frame->fr_height = wp->w_height + wp->w_status_height
#ifdef FEAT_MENU
+ wp->w_winbar_height
#endif
;
+ WINBAR_HEIGHT(wp) ;
}
/*