Compare commits

...

15 Commits

Author SHA1 Message Date
f38c86eb6b patch 8.0.1352: dead URLs in the help go unnoticed
Problem:    Dead URLs in the help go unnoticed.
Solution:   Add a script to check URLs in the help files. (Christian Brabandt)
2017-11-28 14:19:07 +01:00
bdb8139098 patch 8.0.1351: warning for unused variables building with MinGW
Problem:    Warning for unused variables building with MinGW.
Solution:   Change a few #ifdefs (suggested by John Marriott). Remove
            superfluous checks of FEAT_MBYTE.
2017-11-27 23:24:08 +01:00
1355aad2b9 patch 8.0.1350: cannot build with +eval and -multi_byte
Problem:    Cannot build with +eval and -multi_byte.
Solution:   Adjust #ifdefs. (John Marriott)  Always include the multi_byte
            feature when an input method feature is enabled.
2017-11-27 22:49:01 +01:00
17471e84a7 patch 8.0.1349: options test fails when using Motif or GTK GUI
Problem:    Options test fails when using Motif or GTK GUI.
Solution:   Use "fixed" instead of "fixedsys" for Unix. Don't try "xxx" for
            guifonteset.  Don't set 'termencoding' to anything but "utf-8" for
            GTK.  Give an error if 'termencoding' can't be converted.
2017-11-26 23:47:18 +01:00
c8c75796a6 patch 8.0.1348: make testclean deletes script file on MS-Windows
Problem:    Make testclean deletes script file on MS-Windows.
Solution:   Rename file to avoid it starting with an "x".
2017-11-26 17:18:06 +01:00
e0aa23f7e3 patch 8.0.1347: MS-Windows: build broken by misplaced curly
Problem:    MS-Windows: build broken by misplaced curly.
Solution:   Move curly after #endif
2017-11-26 17:08:03 +01:00
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
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
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
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
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
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
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
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
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
29 changed files with 990 additions and 568 deletions

View File

@ -119,7 +119,6 @@ SRC_ALL = \
src/testdir/test[0-9]*a.ok \ src/testdir/test[0-9]*a.ok \
src/testdir/test_[a-z]*.ok \ src/testdir/test_[a-z]*.ok \
src/testdir/test49.vim \ src/testdir/test49.vim \
src/testdir/test60.vim \
src/testdir/test83-tags? \ src/testdir/test83-tags? \
src/testdir/test77a.com \ src/testdir/test77a.com \
src/testdir/test_*.vim \ src/testdir/test_*.vim \
@ -138,7 +137,7 @@ SRC_ALL = \
src/testdir/samples/*.txt \ src/testdir/samples/*.txt \
src/testdir/samples/test000 \ src/testdir/samples/test000 \
src/testdir/if_ver*.vim \ src/testdir/if_ver*.vim \
src/testdir/xterm_ramp.vim \ src/testdir/color_ramp.vim \
src/proto.h \ src/proto.h \
src/proto/arabic.pro \ src/proto/arabic.pro \
src/proto/beval.pro \ src/proto/beval.pro \
@ -585,6 +584,7 @@ RT_ALL = \
runtime/doc/*.txt \ runtime/doc/*.txt \
runtime/doc/Makefile \ runtime/doc/Makefile \
runtime/doc/doctags.c \ runtime/doc/doctags.c \
runtime/doc/test_urls.vim \
runtime/doc/vim.1 \ runtime/doc/vim.1 \
runtime/doc/evim.1 \ runtime/doc/evim.1 \
runtime/doc/vimdiff.1 \ runtime/doc/vimdiff.1 \

View File

@ -16,6 +16,7 @@ matrix:
before_build: before_build:
- '"C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64 /release' - '"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: build_script:
- src/appveyor.bat - src/appveyor.bat

View File

@ -4258,7 +4258,8 @@ A jump table for the options with a short description can be found at |Q_op|.
{not in Vi} {not in Vi}
{only available when compiled with |+mbyte|} {only available when compiled with |+mbyte|}
This option specifies a function that will be called to 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: > Example: >
function ImActivateFunc(active) function ImActivateFunc(active)
@ -4374,6 +4375,7 @@ A jump table for the options with a short description can be found at |Q_op|.
{only available when compiled with |+mbyte|} {only available when compiled with |+mbyte|}
This option specifies a function that is called to obtain the status 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. of Input Method. It must return a positive number when IME is active.
It is not used in the GUI.
Example: > Example: >
function ImStatusFunc() function ImStatusFunc()
@ -6152,11 +6154,34 @@ A jump table for the options with a short description can be found at |Q_op|.
Example: > Example: >
set encoding=utf-8 set encoding=utf-8
set gfn=Ricty_Diminished:h12:cSHIFTJIS set gfn=Ricty_Diminished:h12
set rop=type:directx set rop=type:directx
< <
If select a raster font (Courier, Terminal or FixedSys) to If select a raster font (Courier, Terminal or FixedSys which
'guifont', it fallbacks to be drawn by GDI automatically. 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. Other render types are currently not supported.

68
runtime/doc/test_urls.vim Normal file
View File

@ -0,0 +1,68 @@
" Test for URLs in help documents.
"
" Opens a new window with all found URLS followed by return code from curl
" (anything other than 0 means unreachable)
"
" Written by Christian Brabandt.
func Test_check_URLs()
if has("win32")
echoerr "Doesn't work on MS-Windows"
return
endif
if executable('curl')
" Note: does not follow redirects!
let s:command = 'curl --silent --fail --output /dev/null --head '
elseif executable('wget')
" Note: only allow a couple of redirects
let s:command = 'wget --quiet -S --spider --max-redirect=2 --timeout=5 --tries=2 -O /dev/null '
else
echoerr 'Only works when "curl" or "wget" is available'
return
endif
let pat='\(https\?\|ftp\)://[^\t* ]\+'
exe 'helpgrep' pat
helpclose
let urls = map(getqflist(), 'v:val.text')
" do not use submatch(1)!
let urls = map(urls, {key, val -> matchstr(val, pat)})
" remove examples like user@host (invalid urls)
let urls = filter(urls, 'v:val !~ "@"')
" Remove example URLs which are invalid
let urls = filter(urls, {key, val -> val !~ '\<\(\(my\|some\)\?host\|machine\|hostname\|file\)\>'})
new
put =urls
" remove some more invalid items
" empty lines
v/./d
" remove # anchors
%s/#.*$//e
" remove trailing stuff (parenthesis, dot, comma, quotes), but only for HTTP
" links
g/^h/s#[.,)'"/>][:.]\?$##
g#^[hf]t\?tp:/\(/\?\.*\)$#d
silent! g/ftp://,$/d
silent! g/=$/d
let a = getline(1,'$')
let a = uniq(sort(a))
%d
call setline(1, a)
" Do the testing.
set nomore
%s/.*/\=TestURL(submatch(0))/
" highlight the failures
/.* \([0-9]*[1-9]\|[0-9]\{2,}\)$
endfunc
func TestURL(url)
" Relies on the return code to determine whether a page is valid
echom printf("Testing URL: %d/%d %s", line('.'), line('$'), a:url)
call system(s:command . shellescape(a:url))
return printf("%s %d", a:url, v:shell_error)
endfunc
call Test_check_URLs()

View File

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

View File

@ -1825,7 +1825,6 @@ write_viminfo(char_u *file, int forceit)
FILE *fp_out = NULL; /* output viminfo file */ FILE *fp_out = NULL; /* output viminfo file */
char_u *tempname = NULL; /* name of temp viminfo file */ char_u *tempname = NULL; /* name of temp viminfo file */
stat_T st_new; /* mch_stat() of potential new file */ stat_T st_new; /* mch_stat() of potential new file */
char_u *wp;
#if defined(UNIX) || defined(VMS) #if defined(UNIX) || defined(VMS)
mode_t umask_save; mode_t umask_save;
#endif #endif
@ -1847,27 +1846,29 @@ write_viminfo(char_u *file, int forceit)
fp_in = mch_fopen((char *)fname, READBIN); fp_in = mch_fopen((char *)fname, READBIN);
if (fp_in == NULL) if (fp_in == NULL)
{ {
int fd;
/* if it does exist, but we can't read it, don't try writing */ /* if it does exist, but we can't read it, don't try writing */
if (mch_stat((char *)fname, &st_new) == 0) if (mch_stat((char *)fname, &st_new) == 0)
goto end; goto end;
#if defined(UNIX) || defined(VMS)
/* /* Create the new .viminfo non-accessible for others, because it may
* For Unix we create the .viminfo non-accessible for others, * contain text from non-accessible documents. It is up to the user to
* because it may contain text from non-accessible documents. * widen access (e.g. to a group). This may also fail if there is a
*/ * race condition, then just give up. */
umask_save = umask(077); fd = mch_open((char *)fname,
#endif O_CREAT|O_EXTRA|O_EXCL|O_WRONLY|O_NOFOLLOW, 0600);
fp_out = mch_fopen((char *)fname, WRITEBIN); if (fd < 0)
#if defined(UNIX) || defined(VMS) goto end;
(void)umask(umask_save); fp_out = fdopen(fd, WRITEBIN);
#endif
} }
else else
{ {
/* /*
* There is an existing viminfo file. Create a temporary file to * There is an existing viminfo file. Create a temporary file to
* write the new viminfo into, in the same directory as the * 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 #ifdef UNIX
/* /*
@ -1901,12 +1902,18 @@ write_viminfo(char_u *file, int forceit)
#endif #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 * May try twice: Once normal and once with shortname set, just in
* case somebody puts his viminfo file in an 8.3 filesystem. * case somebody puts his viminfo file in an 8.3 filesystem.
*/ */
for (;;) for (;;)
{ {
int next_char = 'z';
char_u *wp;
tempname = buf_modname( tempname = buf_modname(
#ifdef UNIX #ifdef UNIX
shortname, shortname,
@ -1924,126 +1931,128 @@ write_viminfo(char_u *file, int forceit)
break; break;
/* /*
* Check if tempfile already exists. Never overwrite an * Try a series of names. Change one character, just before
* existing file! * 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 #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 * Check if tempfile is same as original file. May happen
* write the viminfo file then. * 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); vim_free(tempname);
tempname = NULL; tempname = NULL;
shortname = TRUE;
break; 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 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 * Make sure the original owner can read/write the tempfile and
* otherwise preserve permissions, making sure the group matches. * 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 (st_old.st_uid != tmp_st.st_uid)
/* Changing the owner might fail, in which case the
if (mch_stat((char *)tempname, &tmp_st) >= 0) * file will now owned by the current user, oh well. */
{ ignored = fchown(fileno(fp_out), st_old.st_uid, -1);
if (st_old.st_uid != tmp_st.st_uid) if (st_old.st_gid != tmp_st.st_gid
/* Changing the owner might fail, in which case the && fchown(fileno(fp_out), -1, st_old.st_gid) == -1)
* file will now owned by the current user, oh well. */ /* can't set the group to what it should be, remove
ignored = fchown(fileno(fp_out), st_old.st_uid, -1); * group permissions */
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 */
(void)mch_setperm(tempname, 0600); (void)mch_setperm(tempname, 0600);
} }
#endif else
/* can't stat the file, set conservative permissions */
(void)mch_setperm(tempname, 0600);
} }
#endif
} }
/* /*

View File

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

View File

@ -635,7 +635,8 @@
/* #define FEAT_MBYTE_IME */ /* #define FEAT_MBYTE_IME */
# endif # endif
#if defined(FEAT_MBYTE_IME) && !defined(FEAT_MBYTE) /* Input methods are only useful with +multi_byte. */
#if (defined(FEAT_MBYTE_IME) || defined(FEAT_XIM)) && !defined(FEAT_MBYTE)
# define FEAT_MBYTE # define FEAT_MBYTE
#endif #endif

View File

@ -2890,7 +2890,7 @@ vgetorpeek(int advance)
+ typebuf.tb_len] != NUL) + typebuf.tb_len] != NUL)
typebuf.tb_noremap[typebuf.tb_off typebuf.tb_noremap[typebuf.tb_off
+ typebuf.tb_len++] = RM_YES; + typebuf.tb_len++] = RM_YES;
#ifdef USE_IM_CONTROL #ifdef FEAT_MBYTE
/* Get IM status right after getting keys, not after the /* Get IM status right after getting keys, not after the
* timeout for a mapping (focus may be lost by then). */ * timeout for a mapping (focus may be lost by then). */
vgetc_im_active = im_get_status(); 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 KeyTyped; /* TRUE if user typed current char */
EXTERN int KeyStuffed; /* TRUE if current char from stuffbuf */ 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 EXTERN int vgetc_im_active; /* Input Method was active for last
character obtained from vgetc() */ character obtained from vgetc() */
#endif #endif

View File

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

View File

@ -4,6 +4,7 @@
* *
* Contributors: * Contributors:
* - Ken Takata * - Ken Takata
* - Yasuhiro Matsumoto
* *
* Copyright (C) 2013 MURAOKA Taro <koron.kaoriya@gmail.com> * Copyright (C) 2013 MURAOKA Taro <koron.kaoriya@gmail.com>
* THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE. * THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE.
@ -23,7 +24,21 @@
#include <math.h> #include <math.h>
#include <d2d1.h> #include <d2d1.h>
#include <d2d1helper.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" #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 static DWRITE_PIXEL_GEOMETRY
ToPixelGeometry(int value) 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 class AdjustedGlyphRun : public DWRITE_GLYPH_RUN
{ {
private: private:
FLOAT &mAccum;
FLOAT mDelta; FLOAT mDelta;
FLOAT *mAdjustedAdvances; FLOAT *mAdjustedAdvances;
public: public:
AdjustedGlyphRun( AdjustedGlyphRun(
const DWRITE_GLYPH_RUN *glyphRun, const DWRITE_GLYPH_RUN *glyphRun,
FLOAT cellWidth) : FLOAT cellWidth,
FLOAT &accum) :
DWRITE_GLYPH_RUN(*glyphRun), DWRITE_GLYPH_RUN(*glyphRun),
mAccum(accum),
mDelta(0.0f), mDelta(0.0f),
mAdjustedAdvances(new FLOAT[glyphRun->glyphCount]) mAdjustedAdvances(new FLOAT[glyphRun->glyphCount])
{ {
@ -209,45 +348,44 @@ public:
glyphAdvances = mAdjustedAdvances; glyphAdvances = mAdjustedAdvances;
} }
~AdjustedGlyphRun(void) ~AdjustedGlyphRun()
{ {
mAccum += mDelta;
delete[] mAdjustedAdvances; delete[] mAdjustedAdvances;
} }
FLOAT getDelta(void) const
{
return mDelta;
}
static FLOAT adjustToCell(FLOAT value, FLOAT cellWidth) 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) if (cellCount < 1)
cellCount = 1; cellCount = 1;
return cellCount * cellWidth; 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: public:
GdiTextRenderer( TextRenderer(
IDWriteBitmapRenderTarget* bitmapRenderTarget, DWriteContext* pDWC) :
IDWriteRenderingParams* renderingParams) :
cRefCount_(0), cRefCount_(0),
pRenderTarget_(bitmapRenderTarget), pDWC_(pDWC)
pRenderingParams_(renderingParams)
{ {
pRenderTarget_->AddRef();
pRenderingParams_->AddRef();
AddRef(); AddRef();
} }
// add "virtual" to avoid a compiler warning // add "virtual" to avoid a compiler warning
virtual ~GdiTextRenderer() virtual ~TextRenderer()
{ {
SafeRelease(&pRenderTarget_);
SafeRelease(&pRenderingParams_);
} }
IFACEMETHOD(IsPixelSnappingDisabled)( IFACEMETHOD(IsPixelSnappingDisabled)(
@ -263,7 +401,8 @@ public:
__out DWRITE_MATRIX* transform) __out DWRITE_MATRIX* transform)
{ {
// forward the render target's transform // forward the render target's transform
pRenderTarget_->GetCurrentTransform(transform); pDWC_->mRT->GetTransform(
reinterpret_cast<D2D1_MATRIX_3X2_F*>(transform));
return S_OK; return S_OK;
} }
@ -271,43 +410,12 @@ public:
__maybenull void* clientDrawingContext, __maybenull void* clientDrawingContext,
__out FLOAT* pixelsPerDip) __out FLOAT* pixelsPerDip)
{ {
*pixelsPerDip = pRenderTarget_->GetPixelsPerDip(); float dpiX, unused;
pDWC_->mRT->GetDpi(&dpiX, &unused);
*pixelsPerDip = dpiX / 96.0f;
return S_OK; 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)( IFACEMETHOD(DrawUnderline)(
__maybenull void* clientDrawingContext, __maybenull void* clientDrawingContext,
FLOAT baselineOriginX, FLOAT baselineOriginX,
@ -340,6 +448,69 @@ public:
return E_NOTIMPL; 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: public:
IFACEMETHOD_(unsigned long, AddRef) () IFACEMETHOD_(unsigned long, AddRef) ()
{ {
@ -385,80 +556,28 @@ public:
private: private:
long cRefCount_; long cRefCount_;
IDWriteBitmapRenderTarget* pRenderTarget_; DWriteContext* pDWC_;
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::DWriteContext() : DWriteContext::DWriteContext() :
mDpiScaleX(1.f), mHDC(NULL),
mDpiScaleY(1.f),
mDrawing(false), mDrawing(false),
mFallbackDC(false),
mD2D1Factory(NULL), mD2D1Factory(NULL),
mRT(NULL), mRT(NULL),
mBrush(NULL), mBrush(NULL),
mDWriteFactory(NULL), mDWriteFactory(NULL),
mDWriteFactory2(NULL),
mGdiInterop(NULL), mGdiInterop(NULL),
mRenderingParams(NULL), mRenderingParams(NULL),
mFontCache(8),
mTextFormat(NULL), mTextFormat(NULL),
mLastHFont(NULL),
mFontWeight(DWRITE_FONT_WEIGHT_NORMAL), mFontWeight(DWRITE_FONT_WEIGHT_NORMAL),
mFontStyle(DWRITE_FONT_STYLE_NORMAL), mFontStyle(DWRITE_FONT_STYLE_NORMAL),
mTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_DEFAULT) mTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_DEFAULT)
{ {
HRESULT hr; 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, hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,
__uuidof(ID2D1Factory), NULL, __uuidof(ID2D1Factory), NULL,
reinterpret_cast<void**>(&mD2D1Factory)); reinterpret_cast<void**>(&mD2D1Factory));
@ -495,6 +614,15 @@ DWriteContext::DWriteContext() :
mDWriteFactory); 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)) if (SUCCEEDED(hr))
{ {
hr = mDWriteFactory->GetGdiInterop(&mGdiInterop); hr = mDWriteFactory->GetGdiInterop(&mGdiInterop);
@ -515,20 +643,24 @@ DWriteContext::~DWriteContext()
SafeRelease(&mRenderingParams); SafeRelease(&mRenderingParams);
SafeRelease(&mGdiInterop); SafeRelease(&mGdiInterop);
SafeRelease(&mDWriteFactory); SafeRelease(&mDWriteFactory);
SafeRelease(&mDWriteFactory2);
SafeRelease(&mBrush); SafeRelease(&mBrush);
SafeRelease(&mRT); SafeRelease(&mRT);
SafeRelease(&mD2D1Factory); SafeRelease(&mD2D1Factory);
} }
HRESULT 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; HRESULT hr = S_OK;
IDWriteTextFormat *pTextFormat = NULL;
IDWriteFont *font = NULL; IDWriteFont *font = NULL;
IDWriteFontFamily *fontFamily = NULL; IDWriteFontFamily *fontFamily = NULL;
IDWriteLocalizedStrings *localizedFamilyNames = NULL; IDWriteLocalizedStrings *localizedFamilyNames = NULL;
float fontSize = 0;
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
@ -561,33 +693,30 @@ DWriteContext::SetLOGFONT(const LOGFONTW &logFont, float fontSize)
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
// If no font size was passed in use the lfHeight of the LOGFONT. // Use lfHeight of the LOGFONT as font size.
if (fontSize == 0) fontSize = float(logFont.lfHeight);
if (fontSize < 0)
{ {
// Convert from pixels to DIPs. // Negative lfHeight represents the size of the em unit.
fontSize = PixelsToDipsY(logFont.lfHeight); fontSize = -fontSize;
if (fontSize < 0) }
{ else
// Negative lfHeight represents the size of the em unit. {
fontSize = -fontSize; // Positive lfHeight represents the cell height (ascent +
} // descent).
else DWRITE_FONT_METRICS fontMetrics;
{ font->GetMetrics(&fontMetrics);
// Positive lfHeight represents the cell height (ascent +
// descent).
DWRITE_FONT_METRICS fontMetrics;
font->GetMetrics(&fontMetrics);
// Convert the cell height (ascent + descent) from design units // Convert the cell height (ascent + descent) from design units
// to ems. // to ems.
float cellHeight = static_cast<float>( float cellHeight = static_cast<float>(
fontMetrics.ascent + fontMetrics.descent) fontMetrics.ascent + fontMetrics.descent)
/ fontMetrics.designUnitsPerEm; / fontMetrics.designUnitsPerEm;
// Divide the font size by the cell height to get the font em // Divide the font size by the cell height to get the font em
// size. // size.
fontSize /= cellHeight; fontSize /= cellHeight;
}
} }
} }
@ -612,123 +741,165 @@ DWriteContext::SetLOGFONT(const LOGFONTW &logFont, float fontSize)
font->GetStretch(), font->GetStretch(),
fontSize, fontSize,
localeName, localeName,
&mTextFormat); &pTextFormat);
} }
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ hr = pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
mFontWeight = static_cast<DWRITE_FONT_WEIGHT>(logFont.lfWeight);
mFontStyle = logFont.lfItalic ? DWRITE_FONT_STYLE_ITALIC if (SUCCEEDED(hr))
: DWRITE_FONT_STYLE_NORMAL; hr = pTextFormat->SetParagraphAlignment(
} DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
if (SUCCEEDED(hr))
hr = pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
SafeRelease(&localizedFamilyNames); SafeRelease(&localizedFamilyNames);
SafeRelease(&fontFamily); SafeRelease(&fontFamily);
SafeRelease(&font); 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; return hr;
} }
void void
DWriteContext::SetFont(HFONT hFont) DWriteContext::SetFont(HFONT hFont)
{ {
if (mLastHFont != hFont) FontCache::Item item;
if (mFontCache.get(hFont, item))
{ {
LOGFONTW lf; if (item.pTextFormat != NULL)
if (GetObjectW(hFont, sizeof(lf), &lf))
{ {
SetFont(lf); item.pTextFormat->AddRef();
mLastHFont = hFont; 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 void
DWriteContext::SetFont(const LOGFONTW &logFont) DWriteContext::BindDC(HDC hdc, RECT *rect)
{ {
SafeRelease(&mTextFormat); Flush();
mLastHFont = NULL; mRT->BindDC(hdc, rect);
mRT->SetTransform(D2D1::IdentityMatrix());
HRESULT hr = SetLOGFONT(logFont, 0.f); mHDC = hdc;
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);
} }
void void
DWriteContext::DrawText(HDC hdc, const WCHAR* text, int len, DWriteContext::AssureDrawing()
int x, int y, int w, int h, int cellWidth, COLORREF color)
{ {
HRESULT hr = S_OK; if (mDrawing == false)
IDWriteBitmapRenderTarget *bmpRT = NULL; {
mRT->BeginDraw();
mDrawing = true;
}
}
// Skip when any fonts are not set. ID2D1Brush*
if (mTextFormat == NULL) 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; return;
}
// Check possibility of zero divided error. AssureDrawing();
if (cellWidth == 0 || mDpiScaleX == 0.0f || mDpiScaleY == 0.0f)
return;
if (SUCCEEDED(hr)) HRESULT hr;
hr = mGdiInterop->CreateBitmapRenderTarget(hdc, w, h, &bmpRT); IDWriteTextLayout *textLayout = NULL;
hr = mDWriteFactory->CreateTextLayout(text, len, mTextFormat,
FLOAT(w), FLOAT(h), &textLayout);
if (SUCCEEDED(hr)) 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(); TextRenderer renderer(this);
BitBlt(memdc, 0, 0, w, h, hdc, x, y, SRCCOPY); TextRendererContext context = { color, FLOAT(cellWidth), 0.0f };
textLayout->Draw(&context, &renderer, FLOAT(x), FLOAT(y));
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);
} }
SafeRelease(&bmpRT); SafeRelease(&textLayout);
} }
float void
DWriteContext::PixelsToDipsX(int x) 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 void
DWriteContext::PixelsToDipsY(int y) DWriteContext::Flush()
{ {
return y / mDpiScaleY; if (mDrawing)
{
mRT->EndDraw();
mDrawing = false;
}
} }
void void
@ -757,6 +928,10 @@ DWriteContext::SetRenderingParams(
SafeRelease(&mRenderingParams); SafeRelease(&mRenderingParams);
mRenderingParams = renderingParams; mRenderingParams = renderingParams;
mTextAntialiasMode = textAntialiasMode; mTextAntialiasMode = textAntialiasMode;
Flush();
mRT->SetTextRenderingParams(mRenderingParams);
mRT->SetTextAntialiasMode(mTextAntialiasMode);
} }
} }
@ -824,40 +999,23 @@ DWriteContext_Open(void)
return new DWriteContext(); 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 void
DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, RECT *rect) DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, RECT *rect)
{ {
if (ctx != NULL && ctx->mRT != NULL) if (ctx != NULL)
{ ctx->BindDC(hdc, rect);
ctx->mRT->BindDC(hdc, rect);
ctx->mRT->SetTextAntialiasMode(ctx->mTextAntialiasMode);
}
} }
void void
DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont) DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont)
{ {
if (ctx != NULL) if (ctx != NULL)
{
ctx->SetFont(hFont); ctx->SetFont(hFont);
}
} }
void void
DWriteContext_DrawText( DWriteContext_DrawText(
DWriteContext *ctx, DWriteContext *ctx,
HDC hdc,
const WCHAR* text, const WCHAR* text,
int len, int len,
int x, int x,
@ -865,20 +1023,28 @@ DWriteContext_DrawText(
int w, int w,
int h, int h,
int cellWidth, int cellWidth,
COLORREF color) COLORREF color,
UINT fuOptions,
CONST RECT *lprc,
CONST INT * lpDx)
{ {
if (ctx != NULL) 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 void
DWriteContext_EndDraw(DWriteContext *ctx) DWriteContext_FillRect(DWriteContext *ctx, RECT *rc, COLORREF color)
{ {
if (ctx != NULL && ctx->mRT != NULL) if (ctx != NULL)
{ ctx->FillRect(rc, color);
ctx->mRT->EndDraw(); }
ctx->mDrawing = false;
} void
DWriteContext_Flush(DWriteContext *ctx)
{
if (ctx != NULL)
ctx->Flush();
} }
void void

View File

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

View File

@ -2024,15 +2024,15 @@ gui_mac_handle_window_activate(
switch (eventKind) switch (eventKind)
{ {
case kEventWindowActivated: case kEventWindowActivated:
#if defined(USE_IM_CONTROL) # if defined(FEAT_MBYTE)
im_on_window_switch(TRUE); im_on_window_switch(TRUE);
#endif # endif
return noErr; return noErr;
case kEventWindowDeactivated: case kEventWindowDeactivated:
#if defined(USE_IM_CONTROL) # if defined(FEAT_MBYTE)
im_on_window_switch(FALSE); im_on_window_switch(FALSE);
#endif # endif
return noErr; return noErr;
} }
} }
@ -6230,7 +6230,7 @@ char_u *FullPathFromFSSpec_save(FSSpec file)
#endif #endif
} }
#if (defined(USE_IM_CONTROL) || defined(PROTO)) && defined(USE_CARBONKEYHANDLER) #if (defined(FEAT_MBYTE) || defined(PROTO)) && defined(USE_CARBONKEYHANDLER)
/* /*
* Input Method Control functions. * Input Method Control functions.
*/ */
@ -6317,7 +6317,7 @@ im_set_active(int active)
ScriptLanguageRecord *slptr = NULL; ScriptLanguageRecord *slptr = NULL;
OSStatus err; OSStatus err;
if (! gui.in_use) if (!gui.in_use)
return; return;
if (im_initialized == 0) if (im_initialized == 0)
@ -6379,7 +6379,7 @@ im_get_status(void)
return im_is_active; 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_enabled = 0;
static int s_directx_load_attempted = 0; static int s_directx_load_attempted = 0;
# define IS_ENABLE_DIRECTX() (s_directx_enabled && s_dwc != NULL) # define IS_ENABLE_DIRECTX() (s_directx_enabled && s_dwc != NULL)
static int directx_enabled(void);
static void directx_binddc(void);
#endif #endif
#ifdef FEAT_MENU #ifdef FEAT_MENU
static int gui_mswin_get_menu_height(int fix_window); static int gui_mswin_get_menu_height(int fix_window);
#endif #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) #if defined(FEAT_RENDER_OPTIONS) || defined(PROTO)
int int
gui_mch_set_rendering_options(char_u *s) gui_mch_set_rendering_options(char_u *s)
@ -369,6 +355,34 @@ static int allow_scrollbar = FALSE;
# define MyTranslateMessage(x) TranslateMessage(x) # define MyTranslateMessage(x) TranslateMessage(x)
#endif #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) #if defined(FEAT_MBYTE) || defined(GLOBAL_IME)
/* use of WindowProc depends on wide_WindowProc */ /* use of WindowProc depends on wide_WindowProc */
# define MyWindowProc vim_WindowProc # define MyWindowProc vim_WindowProc
@ -484,13 +498,13 @@ static void TrackUserActivity(UINT uMsg);
* *
* These LOGFONT used for IME. * These LOGFONT used for IME.
*/ */
#ifdef FEAT_MBYTE #if defined(FEAT_MBYTE_IME) || defined(GLOBAL_IME)
# ifdef USE_IM_CONTROL
/* holds LOGFONT for 'guifontwide' if available, otherwise 'guifont' */ /* holds LOGFONT for 'guifontwide' if available, otherwise 'guifont' */
static LOGFONT norm_logfont; static LOGFONT norm_logfont;
#endif
#ifdef FEAT_MBYTE_IME
/* holds LOGFONT for 'guifont' always. */ /* holds LOGFONT for 'guifont' always. */
static LOGFONT sub_logfont; static LOGFONT sub_logfont;
# endif
#endif #endif
#ifdef FEAT_MBYTE_IME #ifdef FEAT_MBYTE_IME
@ -591,6 +605,10 @@ _OnBlinkTimer(
blink_timer = (UINT) SetTimer(NULL, 0, (UINT)blink_ontime, blink_timer = (UINT) SetTimer(NULL, 0, (UINT)blink_ontime,
(TIMERPROC)_OnBlinkTimer); (TIMERPROC)_OnBlinkTimer);
} }
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
} }
static void static void
@ -1002,6 +1020,19 @@ _OnMouseMoveOrRelease(
_OnMouseEvent(button, x, y, FALSE, keyFlags); _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 #ifdef FEAT_MENU
/* /*
* Find the vimmenu_T with the given id * Find the vimmenu_T with the given id
@ -1236,6 +1267,7 @@ _TextAreaWndProc(
HANDLE_MSG(hwnd, WM_XBUTTONDBLCLK,_OnMouseButtonDown); HANDLE_MSG(hwnd, WM_XBUTTONDBLCLK,_OnMouseButtonDown);
HANDLE_MSG(hwnd, WM_XBUTTONDOWN,_OnMouseButtonDown); HANDLE_MSG(hwnd, WM_XBUTTONDOWN,_OnMouseButtonDown);
HANDLE_MSG(hwnd, WM_XBUTTONUP, _OnMouseMoveOrRelease); HANDLE_MSG(hwnd, WM_XBUTTONUP, _OnMouseMoveOrRelease);
HANDLE_MSG(hwnd, WM_SIZE, _OnSizeTextArea);
#ifdef FEAT_BEVAL_GUI #ifdef FEAT_BEVAL_GUI
case WM_NOTIFY: Handle_WM_Notify(hwnd, (LPNMHDR)lParam); case WM_NOTIFY: Handle_WM_Notify(hwnd, (LPNMHDR)lParam);
@ -1635,6 +1667,11 @@ gui_mch_invert_rectangle(
{ {
RECT rc; RECT rc;
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
/* /*
* Note: InvertRect() excludes right and bottom of rectangle. * Note: InvertRect() excludes right and bottom of rectangle.
*/ */
@ -1663,6 +1700,11 @@ gui_mch_draw_hollow_cursor(guicolor_T color)
HBRUSH hbr; HBRUSH hbr;
RECT rc; RECT rc;
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
/* /*
* Note: FrameRect() excludes right and bottom of rectangle. * Note: FrameRect() excludes right and bottom of rectangle.
*/ */
@ -1703,6 +1745,12 @@ gui_mch_draw_part_cursor(
rc.top = FILL_Y(gui.row) + gui.char_height - h; rc.top = FILL_Y(gui.row) + gui.char_height - h;
rc.right = rc.left + w; rc.right = rc.left + w;
rc.bottom = rc.top + h; rc.bottom = rc.top + h;
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
hbr = CreateSolidBrush(color); hbr = CreateSolidBrush(color);
FillRect(s_hdc, &rc, hbr); FillRect(s_hdc, &rc, hbr);
DeleteBrush(hbr); DeleteBrush(hbr);
@ -2858,10 +2906,6 @@ _OnPaint(
out_flush(); /* make sure all output has been processed */ out_flush(); /* make sure all output has been processed */
(void)BeginPaint(hwnd, &ps); (void)BeginPaint(hwnd, &ps);
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_BeginDraw(s_dwc);
#endif
#ifdef FEAT_MBYTE #ifdef FEAT_MBYTE
/* prevent multi-byte characters from misprinting on an invalid /* prevent multi-byte characters from misprinting on an invalid
@ -2878,19 +2922,11 @@ _OnPaint(
if (!IsRectEmpty(&ps.rcPaint)) 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, gui_redraw(ps.rcPaint.left, ps.rcPaint.top,
ps.rcPaint.right - ps.rcPaint.left + 1, ps.rcPaint.right - ps.rcPaint.left + 1,
ps.rcPaint.bottom - ps.rcPaint.top + 1); ps.rcPaint.bottom - ps.rcPaint.top + 1);
} }
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_EndDraw(s_dwc);
#endif
EndPaint(hwnd, &ps); EndPaint(hwnd, &ps);
} }
} }
@ -3012,6 +3048,11 @@ gui_mch_flash(int msec)
{ {
RECT rc; RECT rc;
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
/* /*
* Note: InvertRect() excludes right and bottom of rectangle. * Note: InvertRect() excludes right and bottom of rectangle.
*/ */
@ -3084,6 +3125,12 @@ gui_mch_delete_lines(
intel_gpu_workaround(); 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.left = FILL_X(gui.scroll_region_left);
rc.right = FILL_X(gui.scroll_region_right + 1); rc.right = FILL_X(gui.scroll_region_right + 1);
rc.top = FILL_Y(row); rc.top = FILL_Y(row);
@ -3117,6 +3164,12 @@ gui_mch_insert_lines(
intel_gpu_workaround(); 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.left = FILL_X(gui.scroll_region_left);
rc.right = FILL_X(gui.scroll_region_right + 1); rc.right = FILL_X(gui.scroll_region_right + 1);
rc.top = FILL_Y(row); rc.top = FILL_Y(row);
@ -3310,6 +3363,8 @@ gui_mch_init_font(char_u *font_name, int fontset UNUSED)
font_name = (char_u *)lf.lfFaceName; font_name = (char_u *)lf.lfFaceName;
#if defined(FEAT_MBYTE_IME) || defined(GLOBAL_IME) #if defined(FEAT_MBYTE_IME) || defined(GLOBAL_IME)
norm_logfont = lf; norm_logfont = lf;
#endif
#ifdef FEAT_MBYTE_IME
sub_logfont = lf; sub_logfont = lf;
#endif #endif
#ifdef FEAT_MBYTE_IME #ifdef FEAT_MBYTE_IME
@ -5743,15 +5798,15 @@ gui_mch_set_sp_color(guicolor_T color)
gui.currSpColor = color; gui.currSpColor = color;
} }
#if defined(FEAT_MBYTE) && defined(FEAT_MBYTE_IME) #ifdef FEAT_MBYTE_IME
/* /*
* Multi-byte handling, originally by Sung-Hoon Baek. * Multi-byte handling, originally by Sung-Hoon Baek.
* First static functions (no prototypes generated). * First static functions (no prototypes generated).
*/ */
#ifdef _MSC_VER # ifdef _MSC_VER
# include <ime.h> /* Apparently not needed for Cygwin, MingW or Borland. */ # include <ime.h> /* Apparently not needed for Cygwin, MingW or Borland. */
#endif # endif
#include <imm.h> # include <imm.h>
/* /*
* handle WM_IME_NOTIFY message * handle WM_IME_NOTIFY message
@ -5903,7 +5958,7 @@ GetResultStr(HWND hwnd, int GCS, int *lenp)
#endif #endif
/* For global functions we need prototypes. */ /* For global functions we need prototypes. */
#if (defined(FEAT_MBYTE) && defined(FEAT_MBYTE_IME)) || defined(PROTO) #if defined(FEAT_MBYTE_IME) || defined(PROTO)
/* /*
* set font to IM. * set font to IM.
@ -6028,7 +6083,7 @@ im_get_status(void)
return status; return status;
} }
#endif /* FEAT_MBYTE && FEAT_MBYTE_IME */ #endif /* FEAT_MBYTE_IME */
#if defined(FEAT_MBYTE) && !defined(FEAT_MBYTE_IME) && defined(GLOBAL_IME) #if defined(FEAT_MBYTE) && !defined(FEAT_MBYTE_IME) && defined(GLOBAL_IME)
/* Win32 with GLOBAL IME */ /* Win32 with GLOBAL IME */
@ -6147,9 +6202,6 @@ gui_mch_draw_string(
#endif #endif
HPEN hpen, old_pen; HPEN hpen, old_pen;
int y; 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 * Italic and bold text seems to have an extra row of pixels at the bottom
@ -6210,6 +6262,11 @@ gui_mch_draw_string(
hbr = hbr_cache[brush_lru]; hbr = hbr_cache[brush_lru];
brush_lru = !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); FillRect(s_hdc, &rc, hbr);
SetBkMode(s_hdc, TRANSPARENT); SetBkMode(s_hdc, TRANSPARENT);
@ -6229,16 +6286,7 @@ gui_mch_draw_string(
#ifdef FEAT_DIRECTX #ifdef FEAT_DIRECTX
if (IS_ENABLE_DIRECTX()) if (IS_ENABLE_DIRECTX())
{ DWriteContext_SetFont(s_dwc, (HFONT)gui.currFont);
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);
}
}
#endif #endif
if (pad_size != Columns || padding == NULL || padding[0] != gui.char_width) if (pad_size != Columns || padding == NULL || padding[0] != gui.char_width)
@ -6349,12 +6397,13 @@ gui_mch_draw_string(
++clen; ++clen;
} }
#if defined(FEAT_DIRECTX) #if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX() && font_is_ttf_or_vector) if (IS_ENABLE_DIRECTX())
{ {
/* Add one to "cells" for italics. */ /* 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), 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 else
#endif #endif
@ -6413,6 +6462,12 @@ gui_mch_draw_string(
foptions, pcliprect, (char *)text, len, padding); 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 */ /* Underline */
if (flags & DRAW_UNDERL) if (flags & DRAW_UNDERL)
{ {
@ -6475,6 +6530,11 @@ gui_mch_flush(void)
BOOL __stdcall GdiFlush(void); BOOL __stdcall GdiFlush(void);
# endif # endif
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
GdiFlush(); GdiFlush();
} }
@ -6483,6 +6543,14 @@ clear_rect(RECT *rcp)
{ {
HBRUSH hbr; 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); hbr = CreateSolidBrush(gui.back_pixel);
FillRect(s_hdc, rcp, hbr); FillRect(s_hdc, rcp, hbr);
DeleteBrush(hbr); DeleteBrush(hbr);
@ -8388,6 +8456,11 @@ gui_mch_drawsign(int row, int col, int typenr)
if (!gui.in_use || (sign = (signicon_t *)sign_get_image(typenr)) == NULL) if (!gui.in_use || (sign = (signicon_t *)sign_get_image(typenr)) == NULL)
return; return;
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
x = TEXT_X(col); x = TEXT_X(col);
y = TEXT_Y(row); y = TEXT_Y(row);
w = gui.char_width * 2; w = gui.char_width * 2;
@ -8867,6 +8940,11 @@ netbeans_draw_multisign_indicator(int row)
x = 0; x = 0;
y = TEXT_Y(row); 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++) for (i = 0; i < gui.char_height - 3; i++)
SetPixel(s_hdc, x+2, y++, gui.currFgColor); SetPixel(s_hdc, x+2, y++, gui.currFgColor);

View File

@ -4782,7 +4782,15 @@ iconv_end(void)
#endif /* FEAT_MBYTE */ #endif /* FEAT_MBYTE */
#ifdef FEAT_EVAL #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
#if defined(FEAT_EVAL) && defined(FEAT_MBYTE)
static void static void
call_imactivatefunc(int active) call_imactivatefunc(int active)
{ {
@ -4794,6 +4802,26 @@ call_imactivatefunc(int active)
argv[0] = (char_u *)"0"; argv[0] = (char_u *)"0";
(void)call_func_retnr(p_imaf, 1, argv, FALSE); (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 #endif
#if defined(FEAT_XIM) || defined(PROTO) #if defined(FEAT_XIM) || defined(PROTO)
@ -4838,14 +4866,7 @@ im_set_active(int active)
im_is_active = (active && !p_imdisable); im_is_active = (active && !p_imdisable);
if (im_is_active != was_active) if (im_is_active != was_active)
{ xim_reset();
#ifdef FEAT_EVAL
if (p_imaf[0] != NUL)
call_imactivatefunc(im_is_active);
else
#endif
xim_reset();
}
} }
void void
@ -5675,6 +5696,11 @@ im_synthesize_keypress(unsigned int keyval, unsigned int state)
void void
xim_reset(void) xim_reset(void)
{ {
#ifdef FEAT_EVAL
if (USE_IMACTIVATEFUNC)
call_imactivatefunc(im_is_active);
else
#endif
if (xic != NULL) if (xic != NULL)
{ {
gtk_im_context_reset(xic); gtk_im_context_reset(xic);
@ -5685,12 +5711,7 @@ xim_reset(void)
{ {
xim_set_focus(gui.in_focus); xim_set_focus(gui.in_focus);
# ifdef FEAT_EVAL if (im_activatekey_keyval != GDK_VoidSymbol)
if (p_imaf[0] != NUL)
call_imactivatefunc(im_is_active);
else
# endif
if (im_activatekey_keyval != GDK_VoidSymbol)
{ {
if (im_is_active) if (im_is_active)
{ {
@ -5855,24 +5876,8 @@ xim_queue_key_press_event(GdkEventKey *event, int down)
im_get_status(void) im_get_status(void)
{ {
# ifdef FEAT_EVAL # ifdef FEAT_EVAL
if (p_imsf[0] != NUL) if (USE_IMSTATUSFUNC)
{ return call_imstatusfunc();
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 # endif
return im_is_active; return im_is_active;
} }
@ -5894,30 +5899,43 @@ im_is_preediting(void)
static int xim_is_active = FALSE; /* XIM should be active in the current static int xim_is_active = FALSE; /* XIM should be active in the current
mode */ mode */
static int xim_has_focus = FALSE; /* XIM is really being used for Vim */ 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 XIMStyle input_style;
static int status_area_enabled = TRUE; static int status_area_enabled = TRUE;
#endif # endif
/* /*
* Switch using XIM on/off. This is used by the code that changes "State". * Switch using XIM on/off. This is used by the code that changes "State".
* When 'imactivatefunc' is defined use that function instead.
*/ */
void void
im_set_active(int active) im_set_active(int active_arg)
{ {
if (xic == NULL) int active = active_arg;
return;
/* If 'imdisable' is set, XIM is never active. */ /* If 'imdisable' is set, XIM is never active. */
if (p_imdisable) if (p_imdisable)
active = FALSE; active = FALSE;
#if !defined(FEAT_GUI_GTK)
else if (input_style & XIMPreeditPosition) else if (input_style & XIMPreeditPosition)
/* There is a problem in switching XIM off when preediting is used, /* 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 * 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. */ * all the time, like it was done in Vim 5.8. */
active = TRUE; 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. */ /* Remember the active state, it is needed when Vim gets keyboard focus. */
xim_is_active = active; xim_is_active = active;
@ -6019,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"); static char e_xim[] = N_("E285: Failed to create input context");
#endif # endif
#if defined(FEAT_GUI_X11) || defined(PROTO) # if defined(FEAT_GUI_X11) || defined(PROTO)
# if defined(XtSpecificationRelease) && XtSpecificationRelease >= 6 && !defined(SUN_SYSTEM) # if defined(XtSpecificationRelease) && XtSpecificationRelease >= 6 && !defined(SUN_SYSTEM)
# define USE_X11R6_XIM # define USE_X11R6_XIM
# endif # endif
static int xim_real_init(Window x11_window, Display *x11_display); 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 xim_destroy_cb(XIM im, XPointer client_data, XPointer call_data);
static void static void
@ -6043,9 +6061,9 @@ xim_instantiate_cb(
Window x11_window; Window x11_window;
Display *x11_display; Display *x11_display;
#ifdef XIM_DEBUG # ifdef XIM_DEBUG
xim_log("xim_instantiate_cb()\n"); xim_log("xim_instantiate_cb()\n");
#endif # endif
gui_get_x11_windis(&x11_window, &x11_display); gui_get_x11_windis(&x11_window, &x11_display);
if (display != x11_display) if (display != x11_display)
@ -6067,9 +6085,9 @@ xim_destroy_cb(
Window x11_window; Window x11_window;
Display *x11_display; Display *x11_display;
#ifdef XIM_DEBUG # ifdef XIM_DEBUG
xim_log("xim_destroy_cb()\n"); xim_log("xim_destroy_cb()\n");
#endif #endif
gui_get_x11_windis(&x11_window, &x11_display); gui_get_x11_windis(&x11_window, &x11_display);
xic = NULL; xic = NULL;
@ -6080,7 +6098,7 @@ xim_destroy_cb(
XRegisterIMInstantiateCallback(x11_display, NULL, NULL, NULL, XRegisterIMInstantiateCallback(x11_display, NULL, NULL, NULL,
xim_instantiate_cb, NULL); xim_instantiate_cb, NULL);
} }
#endif # endif
void void
xim_init(void) xim_init(void)
@ -6088,9 +6106,9 @@ xim_init(void)
Window x11_window; Window x11_window;
Display *x11_display; Display *x11_display;
#ifdef XIM_DEBUG # ifdef XIM_DEBUG
xim_log("xim_init()\n"); xim_log("xim_init()\n");
#endif # endif
gui_get_x11_windis(&x11_window, &x11_display); gui_get_x11_windis(&x11_window, &x11_display);
@ -6101,10 +6119,10 @@ xim_init(void)
gui_set_shellsize(FALSE, FALSE, RESIZE_BOTH); gui_set_shellsize(FALSE, FALSE, RESIZE_BOTH);
#ifdef USE_X11R6_XIM # ifdef USE_X11R6_XIM
XRegisterIMInstantiateCallback(x11_display, NULL, NULL, NULL, XRegisterIMInstantiateCallback(x11_display, NULL, NULL, NULL,
xim_instantiate_cb, NULL); xim_instantiate_cb, NULL);
#endif # endif
} }
static int static int
@ -6116,7 +6134,7 @@ xim_real_init(Window x11_window, Display *x11_display)
*ns, *ns,
*end, *end,
tmp[1024]; tmp[1024];
#define IMLEN_MAX 40 # define IMLEN_MAX 40
char buf[IMLEN_MAX + 7]; char buf[IMLEN_MAX + 7];
XIM xim = NULL; XIM xim = NULL;
XIMStyles *xim_styles; XIMStyles *xim_styles;
@ -6181,7 +6199,7 @@ xim_real_init(Window x11_window, Display *x11_display)
return FALSE; return FALSE;
} }
#ifdef USE_X11R6_XIM # ifdef USE_X11R6_XIM
{ {
XIMCallback destroy_cb; XIMCallback destroy_cb;
@ -6190,7 +6208,7 @@ xim_real_init(Window x11_window, Display *x11_display)
if (XSetIMValues(xim, XNDestroyCallback, &destroy_cb, NULL)) if (XSetIMValues(xim, XNDestroyCallback, &destroy_cb, NULL))
EMSG(_("E287: Warning: Could not set destroy callback to IM")); EMSG(_("E287: Warning: Could not set destroy callback to IM"));
} }
#endif # endif
if (XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL) || !xim_styles) if (XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL) || !xim_styles)
{ {
@ -6266,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, /* A crash was reported when trying to pass gui.norm_font as XNFontSet,
* thus that has been removed. Hopefully the default works... */ * thus that has been removed. Hopefully the default works... */
#ifdef FEAT_XFONTSET # ifdef FEAT_XFONTSET
if (gui.fontset != NOFONTSET) if (gui.fontset != NOFONTSET)
{ {
preedit_list = XVaCreateNestedList(0, preedit_list = XVaCreateNestedList(0,
@ -6282,7 +6300,7 @@ xim_real_init(Window x11_window, Display *x11_display)
NULL); NULL);
} }
else else
#endif # endif
{ {
preedit_list = XVaCreateNestedList(0, preedit_list = XVaCreateNestedList(0,
XNSpotLocation, &over_spot, XNSpotLocation, &over_spot,
@ -6316,7 +6334,8 @@ xim_real_init(Window x11_window, Display *x11_display)
} }
else else
{ {
EMSG(_(e_xim)); if (!is_not_a_term())
EMSG(_(e_xim));
XCloseIM(xim); XCloseIM(xim);
return FALSE; return FALSE;
} }
@ -6324,7 +6343,7 @@ xim_real_init(Window x11_window, Display *x11_display)
return TRUE; return TRUE;
} }
#endif /* FEAT_GUI_X11 */ # endif /* FEAT_GUI_X11 */
/* /*
* Get IM status. When IM is on, return TRUE. Else return FALSE. * Get IM status. When IM is on, return TRUE. Else return FALSE.
@ -6335,6 +6354,10 @@ xim_real_init(Window x11_window, Display *x11_display)
int int
im_get_status(void) im_get_status(void)
{ {
# ifdef FEAT_EVAL
if (USE_IMSTATUSFUNC)
return call_imstatusfunc();
# endif
return xim_has_focus; return xim_has_focus;
} }
@ -6457,41 +6480,39 @@ xim_get_status_area_height(void)
#else /* !defined(FEAT_XIM) */ #else /* !defined(FEAT_XIM) */
# ifndef FEAT_GUI_W32 # if !defined(FEAT_GUI_W32) || !(defined(FEAT_MBYTE_IME) || defined(GLOBAL_IME))
static int im_was_set_active = FALSE;
int int
im_get_status() im_get_status()
{ {
# ifdef FEAT_EVAL # if defined(FEAT_MBYTE) && defined(FEAT_EVAL)
if (p_imsf[0] != NUL) if (USE_IMSTATUSFUNC)
{ return call_imstatusfunc();
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 # endif
return FALSE; return im_was_set_active;
} }
void void
im_set_active(int active) im_set_active(int active_arg)
{ {
# if defined(USE_IM_CONTROL) && defined(FEAT_EVAL) # if defined(FEAT_MBYTE) && defined(FEAT_EVAL)
if (p_imaf[0] != NUL) int active = !p_imdisable && active_arg;
call_imactivatefunc(p_imdisable ? FALSE : active);
if (USE_IMACTIVATEFUNC && active != im_get_status())
{
call_imactivatefunc(active);
im_was_set_active = active;
}
# endif # endif
} }
# ifdef FEAT_GUI
void
im_set_position(int row, int col)
{
}
# endif
# endif # endif
#endif /* FEAT_XIM */ #endif /* FEAT_XIM */

View File

@ -892,7 +892,7 @@ getcount:
int lit = FALSE; /* get extra character literally */ int lit = FALSE; /* get extra character literally */
int langmap_active = FALSE; /* using :lmap mappings */ int langmap_active = FALSE; /* using :lmap mappings */
int lang; /* getting a text character */ int lang; /* getting a text character */
#ifdef USE_IM_CONTROL #ifdef FEAT_MBYTE
int save_smd; /* saved value of p_smd */ int save_smd; /* saved value of p_smd */
#endif #endif
@ -957,7 +957,7 @@ getcount:
State = LANGMAP; State = LANGMAP;
langmap_active = TRUE; langmap_active = TRUE;
} }
#ifdef USE_IM_CONTROL #ifdef FEAT_MBYTE
save_smd = p_smd; save_smd = p_smd;
p_smd = FALSE; /* Don't let the IM code show the mode here */ p_smd = FALSE; /* Don't let the IM code show the mode here */
if (lang && curbuf->b_p_iminsert == B_IMODE_IM) if (lang && curbuf->b_p_iminsert == B_IMODE_IM)
@ -973,7 +973,7 @@ getcount:
++allow_keys; ++allow_keys;
State = NORMAL_BUSY; State = NORMAL_BUSY;
} }
#ifdef USE_IM_CONTROL #ifdef FEAT_MBYTE
if (lang) if (lang)
{ {
if (curbuf->b_p_iminsert != B_IMODE_LMAP) 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 *)&p_ic, PV_NONE,
{(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT}, {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
{"imactivatefunc","imaf",P_STRING|P_VI_DEF|P_SECURE, {"imactivatefunc","imaf",P_STRING|P_VI_DEF|P_SECURE,
#if defined(FEAT_EVAL) && defined(USE_IM_CONTROL) #if defined(FEAT_EVAL) && defined(FEAT_MBYTE)
(char_u *)&p_imaf, PV_NONE, (char_u *)&p_imaf, PV_NONE,
{(char_u *)"", (char_u *)NULL} {(char_u *)"", (char_u *)NULL}
# else # else
@ -1555,14 +1555,14 @@ static struct vimoption options[] =
#endif #endif
{(char_u *)"", (char_u *)0L} SCRIPTID_INIT}, {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
{"imcmdline", "imc", P_BOOL|P_VI_DEF, {"imcmdline", "imc", P_BOOL|P_VI_DEF,
#ifdef USE_IM_CONTROL #ifdef FEAT_MBYTE
(char_u *)&p_imcmdline, PV_NONE, (char_u *)&p_imcmdline, PV_NONE,
#else #else
(char_u *)NULL, PV_NONE, (char_u *)NULL, PV_NONE,
#endif #endif
{(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT}, {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
{"imdisable", "imd", P_BOOL|P_VI_DEF, {"imdisable", "imd", P_BOOL|P_VI_DEF,
#ifdef USE_IM_CONTROL #ifdef FEAT_MBYTE
(char_u *)&p_imdisable, PV_NONE, (char_u *)&p_imdisable, PV_NONE,
#else #else
(char_u *)NULL, PV_NONE, (char_u *)NULL, PV_NONE,
@ -1582,7 +1582,7 @@ static struct vimoption options[] =
{(char_u *)B_IMODE_USE_INSERT, (char_u *)0L} {(char_u *)B_IMODE_USE_INSERT, (char_u *)0L}
SCRIPTID_INIT}, SCRIPTID_INIT},
{"imstatusfunc","imsf",P_STRING|P_VI_DEF|P_SECURE, {"imstatusfunc","imsf",P_STRING|P_VI_DEF|P_SECURE,
#if defined(FEAT_EVAL) && defined(USE_IM_CONTROL) #if defined(FEAT_EVAL) && defined(FEAT_MBYTE)
(char_u *)&p_imsf, PV_NONE, (char_u *)&p_imsf, PV_NONE,
{(char_u *)"", (char_u *)NULL} {(char_u *)"", (char_u *)NULL}
#else #else
@ -6369,8 +6369,13 @@ did_set_string_option(
* display output conversion. */ * display output conversion. */
if (((varp == &p_enc && *p_tenc != NUL) || varp == &p_tenc)) if (((varp == &p_enc && *p_tenc != NUL) || varp == &p_tenc))
{ {
convert_setup(&input_conv, p_tenc, p_enc); if (convert_setup(&input_conv, p_tenc, p_enc) == FAIL
convert_setup(&output_conv, p_enc, p_tenc); || convert_setup(&output_conv, p_enc, p_tenc) == FAIL)
{
EMSG3(_("E950: Cannot convert between %s and %s"),
p_tenc, p_enc);
errmsg = e_invarg;
}
} }
# if defined(WIN3264) && defined(FEAT_MBYTE) # if defined(WIN3264) && defined(FEAT_MBYTE)
@ -8469,7 +8474,7 @@ set_bool_option(
} }
#endif #endif
#ifdef USE_IM_CONTROL #ifdef FEAT_MBYTE
/* 'imdisable' */ /* 'imdisable' */
else if ((int *)varp == &p_imdisable) else if ((int *)varp == &p_imdisable)
{ {

View File

@ -585,11 +585,11 @@ EXTERN char_u *p_imak; /* 'imactivatekey' */
#define IM_OVER_THE_SPOT 1L #define IM_OVER_THE_SPOT 1L
EXTERN long p_imst; /* 'imstyle' */ EXTERN long p_imst; /* 'imstyle' */
#endif #endif
#if defined(FEAT_EVAL) && defined(USE_IM_CONTROL) #if defined(FEAT_EVAL) && defined(FEAT_MBYTE)
EXTERN char_u *p_imaf; /* 'imactivatefunc' */ EXTERN char_u *p_imaf; /* 'imactivatefunc' */
EXTERN char_u *p_imsf; /* 'imstatusfunc' */ EXTERN char_u *p_imsf; /* 'imstatusfunc' */
#endif #endif
#ifdef USE_IM_CONTROL #ifdef FEAT_MBYTE
EXTERN int p_imcmdline; /* 'imcmdline' */ EXTERN int p_imcmdline; /* 'imcmdline' */
EXTERN int p_imdisable; /* 'imdisable' */ EXTERN int p_imdisable; /* 'imdisable' */
#endif #endif

View File

@ -836,7 +836,7 @@ split_message(char_u *mesg, pumitem_T **array)
item->bytelen = p - item->start; item->bytelen = p - item->start;
if (item->cells > max_cells) if (item->cells > max_cells)
max_cells = item->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; height = 2 + ga.ga_len;

View File

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

View File

@ -11,7 +11,8 @@ endfor
for nr in range(8, 15) for nr in range(8, 15)
let s .= "\033[10" . (nr - 8) . "m " let s .= "\033[10" . (nr - 8) . "m "
endfor endfor
let s .= "\033[107m|" " Add | in original color pair to see white background.
let s .= "\033[m|"
call setline(2, s) call setline(2, s)
" 6 x 6 x 6 color cube " 6 x 6 x 6 color cube
@ -22,7 +23,7 @@ for high in range(0, 5)
let nr = low + high * 36 let nr = low + high * 36
let s .= "\033[48;5;" . (nr + 16) . "m " let s .= "\033[48;5;" . (nr + 16) . "m "
endfor endfor
let s .= "\033[107m|" let s .= "\033[m|"
call setline(high + 4, s) call setline(high + 4, s)
endfor endfor
@ -32,9 +33,9 @@ let s = ''
for nr in range(0, 23) for nr in range(0, 23)
let s .= "\033[48;5;" . (nr + 232) . "m " let s .= "\033[48;5;" . (nr + 232) . "m "
endfor endfor
let s .= "\033[107m|" let s .= "\033[m|"
call setline(11, s) call setline(11, s)
set binary set binary
write! <sfile>:h/xterm_ramp.txt write! <sfile>:h/color_ramp.txt
quit quit

View File

@ -19,6 +19,9 @@ let script = [
/#define p_term /#define p_term
let end = line('.') let end = line('.')
" font name that works everywhere (hopefully)
let fontname = has('win32') ? 'fixedsys' : 'fixed'
" Two lists with values: values that work and values that fail. " Two lists with values: values that work and values that fail.
" When not listed, "othernum" or "otherstring" is used. " When not listed, "othernum" or "otherstring" is used.
let test_values = { let test_values = {
@ -93,8 +96,9 @@ let test_values = {
\ 'foldmarker': [['((,))'], ['', 'xxx']], \ 'foldmarker': [['((,))'], ['', 'xxx']],
\ 'formatoptions': [['', 'vt', 'v,t'], ['xxx']], \ 'formatoptions': [['', 'vt', 'v,t'], ['xxx']],
\ 'guicursor': [['', 'n:block-Cursor'], ['xxx']], \ 'guicursor': [['', 'n:block-Cursor'], ['xxx']],
\ 'guifont': [['', 'fixedsys'], []], \ 'guifont': [['', fontname], []],
\ 'guifontwide': [['', 'fixedsys'], []], \ 'guifontwide': [['', fontname], []],
\ 'guifontset': [['', fontname], []],
\ 'helplang': [['', 'de', 'de,it'], ['xxx']], \ 'helplang': [['', 'de', 'de,it'], ['xxx']],
\ 'highlight': [['', 'e:Error'], ['xxx']], \ 'highlight': [['', 'e:Error'], ['xxx']],
\ 'imactivatekey': [['', 'S-space'], ['xxx']], \ 'imactivatekey': [['', 'S-space'], ['xxx']],
@ -126,6 +130,7 @@ let test_values = {
\ 'tagcase': [['smart', 'match'], ['', 'xxx', 'smart,match']], \ 'tagcase': [['smart', 'match'], ['', 'xxx', 'smart,match']],
\ 'term': [[], []], \ 'term': [[], []],
\ 'termsize': [['', '24x80', '0x80', '32x0', '0x0'], ['xxx', '80', '8ax9', '24x80b']], \ 'termsize': [['', '24x80', '0x80', '32x0', '0x0'], ['xxx', '80', '8ax9', '24x80b']],
\ 'termencoding': [has('gui_gtk') ? [] : ['', 'utf-8'], ['xxx']],
\ 'toolbar': [['', 'icons', 'text'], ['xxx']], \ 'toolbar': [['', 'icons', 'text'], ['xxx']],
\ 'toolbariconsize': [['', 'tiny', 'huge'], ['xxx']], \ 'toolbariconsize': [['', 'tiny', 'huge'], ['xxx']],
\ 'ttymouse': [['', 'xterm'], ['xxx']], \ 'ttymouse': [['', 'xterm'], ['xxx']],
@ -189,8 +194,11 @@ while 1
call add(script, "endif") call add(script, "endif")
endif endif
call add(script, 'set ' . name . '&') " cannot change 'termencoding' in GTK
call add(script, 'set ' . shortname . '&') if name != 'termencoding' || !has('gui_gtk')
call add(script, 'set ' . name . '&')
call add(script, 'set ' . shortname . '&')
endif
if name == 'verbosefile' if name == 'verbosefile'
call add(script, 'call delete("xxx")') call add(script, 'call delete("xxx")')
endif endif

View File

@ -24,6 +24,8 @@ func Test_iminsert2()
set iminsert=0 set iminsert=0
set imactivatefunc= set imactivatefunc=
set imstatusfunc= set imstatusfunc=
call assert_equal(1, s:imactivatefunc_called)
call assert_equal(1, s:imstatusfunc_called) let expected = has('gui_running') ? 0 : 1
call assert_equal(expected, s:imactivatefunc_called)
call assert_equal(expected, s:imstatusfunc_called)
endfunc endfunc

View File

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

View File

@ -100,3 +100,11 @@ func Test_writefile_sync_arg()
call writefile(['two'], 'Xtest', 'S') call writefile(['two'], 'Xtest', 'S')
call delete('Xtest') call delete('Xtest')
endfunc 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 #endif
#if defined(USE_IM_CONTROL) || defined(PROTO) #if defined(FEAT_MBYTE) || defined(PROTO)
/* /*
* Save current Input Method status to specified place. * Save current Input Method status to specified place.
*/ */

View File

@ -771,6 +771,36 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1352,
/**/
1351,
/**/
1350,
/**/
1349,
/**/
1348,
/**/
1347,
/**/
1346,
/**/
1345,
/**/
1344,
/**/
1343,
/**/
1342,
/**/
1341,
/**/
1340,
/**/
1339,
/**/
1338,
/**/ /**/
1337, 1337,
/**/ /**/

View File

@ -533,13 +533,6 @@ typedef unsigned long u8char_T; /* long should be 32 bits or more */
# endif # endif
#endif #endif
/*
* Check input method control.
*/
#if defined(FEAT_MBYTE)
# define USE_IM_CONTROL
#endif
/* /*
* For dynamically loaded gettext library. Currently, only for Win32. * For dynamically loaded gettext library. Currently, only for Win32.
*/ */