NTEmacs IMEパッチ作成(24.4)
IMEパッチ
これまで gnupack のものを使用してきたが、最新がリリースされていないので、24.3ベースでパッチを作成してみる。 まずは gnupack の 概要 又は ダウンロードファイル一覧 から24.3のものを入手する。 現時点での最新は emacs-24.3-ime-2013-05-03.patch.tar.gz であった。
まずは24.4のソースにパッチをあててみる
rockers:~/svn/emacs-24.4$ patch -b -p1 < emacs-24.3-ime-2013-05-03.patch
NGのところをそれぞれ対応する。 24.3のパッチ適用済ツリーと比較して作業。
★具体的には
- TotoiseSVNで、24.3のパッチ適用済ツリーの「変更をチェック」と24.4の(24.3用)パッチ適用済ツリーの「変更をチェック」を両方出す
- rejファイルから、失敗した部分の内容を確認し、24.3のdiffを元に対象箇所を特定
- 24.4の対象箇所を探し、ケースバイケースで手動マージを行う
作業内容
OK
patching file lib-src/hexl.c Hunk #1 succeeded at 158 (offset -4 lines). Hunk #2 succeeded at 216 (offset -4 lines).
OK
patching file lib-src/make-docfile.c
OK
patching file lib-src/makefile.w32-in Hunk #1 succeeded at 144 (offset 4 lines). Hunk #2 succeeded at 161 (offset 4 lines).
Hunk#1 は元ソースで対応と同じ(#ifndef _TIMEZONE_DEFINED) Hunk#2 は手動マージ
patching file lib-src/ntlib.c Reversed (or previously applied) patch detected! Assume -R? [n] Apply anyway? [n] Skipping patch. 2 out of 2 hunks ignored -- saving rejects to file lib-src/ntlib.c.rej
OK
patching file lib-src/ntlib.h Hunk #1 succeeded at 25 with fuzz 1.
OK
patching file lisp/cedet/cedet-cscope.el
OK
patching file lisp/image.el Hunk #1 succeeded at 126 (offset 15 lines).
OK(ファイル追加)
patching file lisp/international/w32-ime.el
OK
patching file lisp/loadup.el Hunk #1 succeeded at 253 (offset 4 lines).
OK(ファイル追加)
patching file lisp/site/site-init.el
OK(ファイル追加)
patching file lisp/site/site-start.el
Hunk#1はOK Hunk#2は手動マージ
patching file lisp/startup.el Hunk #1 succeeded at 594 with fuzz 2 (offset 77 lines). Hunk #2 FAILED at 1519. 1 out of 2 hunks FAILED -- saving rejects to file lisp/startup.el.rej
Hunk#1はよーく見ると元ソースで対応済みなのでマージ不要
patching file nt/addpm.c Reversed (or previously applied) patch detected! Assume -R? [n] Apply anyway? [n] Skipping patch. 1 out of 1 hunk ignored -- saving rejects to file nt/addpm.c.rej
Hunk#1は元ソースで対応済みなのでマージ不要
patching file nt/addsection.c Reversed (or previously applied) patch detected! Assume -R? [n] Apply anyway? [n] Skipping patch. 1 out of 1 hunk ignored -- saving rejects to file nt/addsection.c.rej
OK (#undef HAVE_STRUCT_UTIMBUF を #define HAVE_STRUCT_UTIMBUF 1 としており、実際にはコンフィギュレーション変更である)
patching file nt/config.nt Hunk #1 succeeded at 1023 (offset 120 lines).
24.3のパッチ適用済ファイルの方は、改行コードがUnixになっていたため、Winに戻してdiffをとる
24.3->24.4で追加されたIMPORTANTの記載が若干気になるが、、
patching file nt/configure.bat Hunk #1 FAILED at 1. 1 out of 1 hunk FAILED -- saving rejects to file nt/configure.bat.rej
OK
patching file nt/gmake.defs Hunk #1 succeeded at 169 (offset 8 lines). Hunk #2 succeeded at 219 (offset 8 lines). Hunk #3 succeeded at 328 (offset 8 lines).
順次比較して作業。多分、合っていると思う。。
patching file nt/inc/ms-w32.h Hunk #1 FAILED at 115. Hunk #2 succeeded at 180 with fuzz 2 (offset 47 lines). Hunk #3 FAILED at 274. Hunk #4 succeeded at 392 with fuzz 1 (offset 75 lines). Hunk #5 FAILED at 366. Hunk #6 succeeded at 507 (offset 91 lines). 3 out of 6 hunks FAILED -- saving rejects to file nt/inc/ms-w32.h.rej
OK
patching file nt/inc/sys/socket.h Hunk #1 succeeded at 99 (offset 4 lines).
元々のパッチは、プロトタイプ宣言先頭の _CRTIMP を削除するという内容。 24.4では元々無くなっているので対応不要。
patching file nt/inc/sys/stat.h Hunk #1 FAILED at 101. 1 out of 1 hunk FAILED -- saving rejects to file nt/inc/sys/stat.h.rej
元々のパッチは _W64 と _TIMEZONE_DEFINED による切り分けを追加。 24.4では _TIMEVAL_DEFINED と _TIMEZONE_DEFINED により切り分けられているので対応不要。
patching file nt/inc/sys/time.h Hunk #1 FAILED at 6. 1 out of 1 hunk FAILED -- saving rejects to file nt/inc/sys/time.h.rej
元々のパッチは #ifdef GNUC の切り分けを #if defined(GNUC) && !defined(_W64) に変更していたもの 24.4では元々対応済みなので不要。
patching file nt/preprep.c Reversed (or previously applied) patch detected! Assume -R? [n] Apply anyway? [n] Skipping patch. 1 out of 1 hunk ignored -- saving rejects to file nt/preprep.c.rej
OK(ファイル追加)
patching file site-lisp/cmigemo.el
OK(ファイル追加)
patching file site-lisp/cp5022x.el
OK(ファイル追加)
patching file site-lisp/ezsetup.el
OK(ファイル追加)
patching file site-lisp/ja-coding.el
OK(ファイル追加)
patching file site-lisp/smart-ime.el
Hunk #5の #ifdef USE_W32_CALL_LISP_THREAD のところを手動マージ
patching file src/alloc.c Hunk #1 succeeded at 22 with fuzz 1 (offset -2 lines). Hunk #2 succeeded at 35 (offset -2 lines). Hunk #3 succeeded at 346 (offset 16 lines). Hunk #4 succeeded at 3770 with fuzz 1 (offset 3318 lines). Hunk #5 FAILED at 663. Hunk #6 succeeded at 3774 (offset 278 lines). Hunk #7 succeeded at 5341 (offset 304 lines). Hunk #8 succeeded at 5631 (offset 411 lines). Hunk #9 succeeded at 5652 with fuzz 1 (offset 408 lines). Hunk #10 succeeded at 5663 (offset 408 lines). Hunk #11 succeeded at 5722 with fuzz 2 (offset 376 lines). 1 out of 11 hunks FAILED -- saving rejects to file src/alloc.c.rej
OK
patching file src/atimer.c
Hunk #2の FAILは周囲のdiffが異なっていたため。手動マージ
patching file src/callproc.c Hunk #1 succeeded at 30 with fuzz 1 (offset 1 line). Hunk #2 FAILED at 1167. Hunk #3 succeeded at 1241 (offset 67 lines). 1 out of 3 hunks FAILED -- saving rejects to file src/callproc.c.rej
OK
patching file src/cm.h
OK(ファイル追加)
patching file src/cmigemo.c
Hunk #2 file_name_completion_stat() のところは、元ソースが大きく変わっており、処理する対象が無さそう
patching file src/dired.c Hunk #1 succeeded at 51 with fuzz 2 (offset -29 lines). Hunk #2 FAILED at 831. 1 out of 2 hunks FAILED -- saving rejects to file src/dired.c.rej
OK
patching file src/dispnew.c Hunk #1 succeeded at 6119 (offset -122 lines).
OK
patching file src/doprnt.c
OK
patching file src/emacs.c Hunk #1 succeeded at 770 with fuzz 2 (offset 58 lines). Hunk #2 succeeded at 1534 (offset 106 lines).
frame.c HUNK #1
24.3
#if !HAVE_NS
24.4
#if !HAVE_NS && !HAVE_NTGUI
変更後
#if !HAVE_NS && !HAVE_NTGUI && !defined USE_W32_IME
patching file src/frame.c Hunk #1 FAILED at 1959. Hunk #2 succeeded at 2744 (offset 49 lines). 1 out of 2 hunks FAILED -- saving rejects to file src/frame.c.rej
OK
patching file src/frame.h Hunk #1 succeeded at 1217 (offset 58 lines).
OK
patching file src/gmalloc.c
image.c
Hunk #5
_setjmp だか __setjmp だかの定義の問題らしい。 解決されているっぽく見えるのでとりあえず置いておく
Hunk #6 も #5同様
Hunk #10 は解決されてそう。DEF_IMGLIB_FN の引数の型かな
patching file src/image.c Hunk #1 succeeded at 536 (offset -5 lines). Hunk #2 succeeded at 548 (offset -5 lines). Hunk #3 succeeded at 622 (offset -6 lines). Hunk #4 succeeded at 3197 (offset 135 lines). Hunk #5 FAILED at 5563. Hunk #6 FAILED at 5760. Hunk #7 succeeded at 6587 (offset 147 lines). Hunk #8 succeeded at 6668 (offset 142 lines). Hunk #9 succeeded at 8657 (offset 550 lines). Hunk #10 FAILED at 8275. Hunk #11 succeeded at 8871 (offset 559 lines). Hunk #12 succeeded at 8899 (offset 561 lines). Hunk #13 succeeded at 8970 (offset 563 lines). Hunk #14 succeeded at 9038 with fuzz 2 (offset 563 lines). Hunk #15 succeeded at 9052 (offset 566 lines). Hunk #16 succeeded at 9638 (offset 564 lines). Hunk #17 succeeded at 9685 (offset 584 lines). 3 out of 17 hunks FAILED -- saving rejects to file src/image.c.rej
Hunk #1 なんでFAILかわからないが行追加だけなので同様に行う
patching file src/keyboard.c Hunk #1 FAILED at 72. Hunk #2 succeeded at 4778 (offset 127 lines). Hunk #3 succeeded at 8854 with fuzz 1 (offset -46 lines). Hunk #4 succeeded at 8976 (offset -95 lines). Hunk #5 succeeded at 9061 (offset -147 lines). Hunk #6 succeeded at 9734 (offset -258 lines). 1 out of 6 hunks FAILED -- saving rejects to file src/keyboard.c.rej
Hunk #3 かなりソースが変わっているので適用部分無し。そのまま
patching file src/lisp.h Hunk #1 succeeded at 286 with fuzz 1 (offset 84 lines). Hunk #2 succeeded at 628 with fuzz 2 (offset 223 lines). Hunk #3 FAILED at 1752. Hunk #4 succeeded at 3670 (offset 737 lines). 1 out of 4 hunks FAILED -- saving rejects to file src/lisp.h.rej
Hunk #1 また、cmigemo だが、、入れておく
patching file src/makefile.w32-in Hunk #1 FAILED at 134. Hunk #2 succeeded at 153 (offset 1 line). Hunk #3 succeeded at 225 (offset 1 line). Hunk #4 succeeded at 1720 with fuzz 1 (offset 29 lines). 1 out of 4 hunks FAILED -- saving rejects to file src/makefile.w32-in.rej
OK
patching file src/print.c Hunk #1 succeeded at 1950 (offset 12 lines).
SIZE_T の定義等。 解決されてそうな感じなので一旦そのまま
patching file src/ralloc.c Hunk #1 FAILED at 52. Hunk #2 FAILED at 170. Hunk #3 FAILED at 224. Hunk #4 FAILED at 254. Hunk #5 FAILED at 392. Hunk #6 FAILED at 472. Hunk #7 FAILED at 568. Hunk #8 FAILED at 774. Hunk #9 FAILED at 855. Hunk #10 FAILED at 906. Hunk #11 FAILED at 963. Hunk #12 FAILED at 1088. 12 out of 12 hunks FAILED -- saving rejects to file src/ralloc.c.rej
OK
patching file src/regex.c Hunk #1 succeeded at 364 (offset -4 lines).
OK
patching file src/sound.c Hunk #1 succeeded at 1243 (offset -45 lines). Hunk #2 succeeded at 1283 (offset -45 lines).
OK
patching file src/term.c Hunk #1 succeeded at 62 with fuzz 2 (offset -1 lines).
OK
patching file src/unexw32.c Hunk #1 succeeded at 216 (offset 1 line). Hunk #2 succeeded at 482 (offset 1 line). Hunk #3 succeeded at 498 (offset 1 line). Hunk #4 succeeded at 513 (offset 1 line).
OK
patching file src/vm-limit.c Hunk #1 succeeded at 51 with fuzz 2 (offset 30 lines).
w32.c Hunk #1 FAILED at 29. time.hのinclude順。解決されてそうなので一旦そのまま
Hunk #2 FAILED at 65. epaths.h のinclude。解決済
Hunk #3 FAILED at 96. __GNUC__ と _W64の絡み。解決済
Hunk #4 FAILED at 114. if _WIN32_WINNT < 0x500 及び endif の追加。元ソースで解決済
Hunk #5 FAILED at 162. ifndef FSCTL_GET_REPARSE_POINT、元ソースで解決済
Hunk #10 FAILED at 2014. get_emacs_configuration 関数が無くなっているので関係無し
Hunk #13 FAILED at 2499. nameをポインタとしてみるか、name[1]で見るか。解決済のようだ
Hunk #15 FAILED at 3371. generate_inode_val()が無くなっているので関係なし
Hunk #21 FAILED at 6820. TEXT()の追加のみ
patching file src/w32.c Hunk #1 FAILED at 29. Hunk #2 FAILED at 65. Hunk #3 FAILED at 96. Hunk #4 FAILED at 114. Hunk #5 FAILED at 162. Hunk #6 succeeded at 332 with fuzz 2 (offset 49 lines). Hunk #7 succeeded at 2030 (offset 781 lines). Hunk #8 succeeded at 2530 (offset 845 lines). Hunk #9 succeeded at 2810 with fuzz 2 (offset 888 lines). Hunk #10 FAILED at 2014. Hunk #11 succeeded at 3219 (offset 767 lines). Hunk #12 succeeded at 3238 (offset 767 lines). Hunk #13 FAILED at 2499. Hunk #14 succeeded at 3296 with fuzz 1 (offset 767 lines). Hunk #15 FAILED at 3371. Hunk #16 succeeded at 6823 (offset 1600 lines). Hunk #17 succeeded at 7260 (offset 1605 lines). Hunk #18 succeeded at 8055 (offset 1661 lines). Hunk #19 succeeded at 8129 (offset 1661 lines). Hunk #20 succeeded at 8312 (offset 1660 lines). Hunk #21 FAILED at 6820. Hunk #22 succeeded at 8852 (offset 1997 lines). Hunk #23 succeeded at 8876 (offset 1997 lines). Hunk #24 succeeded at 8971 (offset 1997 lines). 9 out of 24 hunks FAILED -- saving rejects to file src/w32.c.rej
OK
patching file src/w32.h Hunk #2 succeeded at 227 with fuzz 2 (offset 38 lines).
OK
patching file src/w32common.h
w32fns.c かなり重そうだ。。
Hunk #6 FAILED at 233.
ここはかなり重要な部分と思われ。 ImmGetCompositionString_Proc とかの定義を ifndef USE_W32_IME する
@@ -233,21 +316,25 @@ typedef BOOL (WINAPI * TrackMouseEvent_Proc) (IN OUT LPTRACKMOUSEEVENT lpEventTrack); +#ifndef USE_W32_IME typedef LONG (WINAPI * ImmGetCompositionString_Proc) (IN HIMC context, IN DWORD index, OUT LPVOID buffer, IN DWORD bufLen); typedef HIMC (WINAPI * ImmGetContext_Proc) (IN HWND window); typedef HWND (WINAPI * ImmReleaseContext_Proc) (IN HWND wnd, IN HIMC context); typedef HWND (WINAPI * ImmSetCompositionWindow_Proc) (IN HIMC context, IN COMPOSITIONFORM *form); +#endif /* USE_W32_IME */ typedef HMONITOR (WINAPI * MonitorFromPoint_Proc) (IN POINT pt, IN DWORD flags); typedef BOOL (WINAPI * GetMonitorInfo_Proc) (IN HMONITOR monitor, OUT struct MONITOR_INFO* info); TrackMouseEvent_Proc track_mouse_event_fn = NULL; +#ifndef USE_W32_IME ImmGetCompositionString_Proc get_composition_string_fn = NULL; ImmGetContext_Proc get_ime_context_fn = NULL; ImmReleaseContext_Proc release_ime_context_fn = NULL; ImmSetCompositionWindow_Proc set_ime_composition_window_fn = NULL; +#endif /* USE_W32_IME */ MonitorFromPoint_Proc monitor_from_point_fn = NULL; GetMonitorInfo_Proc get_monitor_info_fn = NULL;
Hunk #9 FAILED at 328.
check_x_display_info関数の前に、cons2ptr(),ptr2cons()を追加
@@ -328,6 +422,22 @@ #define MB_EMACS_SILENT (0xFFFFFFFF - 1) +#ifdef USE_W32_CALL_LISP_THREAD +static void *cons2ptr(Lisp_Object c) +{ + return (void *) (XFASTINT(XCAR(c)) << sizeof(EMACS_INT) /2 * 8 | + XFASTINT(XCDR(c)) & ((EMACS_INT)1 << + sizeof(EMACS_INT) /2 * 8) - 1); +} + +static Lisp_Object ptr2cons(const void *p) +{ + return Fcons(make_number((EMACS_INT)p >> sizeof(EMACS_UINT)/2*8), + make_number((EMACS_INT)p & + ((EMACS_INT)1 << sizeof(EMACS_UINT)/2*8)-1)); +} +#endif + /* Error if we are not connected to MS-Windows. */ void check_w32 (void)
Hunk #20 FAILED at 4100.
ここも重要なとこですなあ。
WM_IME_NOTIFY を処理するところ。
@@ -4100,8 +4283,83 @@ return retval; } +#ifdef USE_W32_IME + case WM_IME_NOTIFY: + if (wParam == IMN_SETOPENSTATUS) + { + if (w32_get_ime_status(hwnd)){ + struct frame *f = x_window_to_frame (dpyinfo, hwnd); + if (f) { + set_ime_font = 0; + w32_set_ime_conv_window (hwnd, f); + } + } + if (!IME_event_off_count) + my_post_msg (&wmsg, hwnd, WM_MULE_IME_STATUS, 0, 0); + else + IME_event_off_count--; + } + goto dflt; + + case WM_IME_STARTCOMPOSITION: + { + struct frame *f = x_window_to_frame (dpyinfo, hwnd); + if (f && !set_ime_font) + { +#if !defined(USE_W32_CALL_LISP_THREAD) + my_post_msg (&wmsg, hwnd, WM_MULE_IME_SET_FONT, (WPARAM) f, 0); +#else /* USE_W32_CALL_LISP_THREAD */ + w32_set_ime_font(hwnd, f); +#endif + set_ime_font = 1; + } + } + goto dflt; + + case WM_IME_SETCONTEXT: + set_ime_font = 0; + goto dflt; + + case WM_IME_COMPOSITION: + if (lParam & GCS_RESULTSTR) + if (w32_get_ime_composition_string (hwnd)) + return 0; + else + break; + goto dflt; + + case WM_IME_REQUEST: + if (wParam == IMR_RECONVERTSTRING) { +#ifdef RECONVERSION + if (!ime_enable_reconversion || !w32_get_ime_status(hwnd)) + return 0; + if (lParam) + return w32_get_ime_reconversion_string (hwnd, wParam, + (RECONVERTSTRING*) lParam); + else + return sizeof(RECONVERTSTRING) + (RECONV_LENG * 2 + 1) * CHRSZ; +#endif + } else if (wParam == IMR_DOCUMENTFEED) { +#ifdef DOCUMENTFEED + if (!ime_enable_document_feed) + return 0; + if (lParam) + return w32_get_ime_documentfeed_string (hwnd, wParam, + (RECONVERTSTRING*) lParam); + else + return sizeof(RECONVERTSTRING) + (DOCFEED_LENG * 2 + DOCFEED_CSTR_LENG + 1) * CHRSZ; +#endif + } + goto dflt; +#endif /* USE_W32_IME */ default: + +#ifdef USE_W32_IME + if (MESSAGE_IMM_COM_P(msg)) + return conversion_agent_wndproc (hwnd, msg, wParam, lParam); +#endif /* USE_W32_IME */ + /* Check for messages registered at runtime. */ if (msg == msh_mousewheel) {
Hunk #26 FAILED at 6408.
要るのか?(LPOFNHOOKPROC)のキャスト
@@ -6408,7 +6684,7 @@ /* Prevent redisplay. */ specbind (Qinhibit_redisplay, Qt); block_input (); - file_details->lpfnHook = file_dialog_callback; + file_details->lpfnHook = (LPOFNHOOKPROC) file_dialog_callback; #ifdef NTGUI_UNICODE file_opened = GetOpenFileNameW (file_details);
Hunk #28 FAILED at 6589.
なるほど、ここも肝の部分だ。 「w32 specialized functions」の括りの前に、「Input Method Editor」の括り(USE_W32_IME〜endif)を挿入している。 diffが変に出ちゃっているのでわかりにくい。 どうせなら、ファイル分ければいいのに、、
@@ -6589,157 +6926,1614 @@ /*********************************************************************** - w32 specialized functions + Input Method Editor ***********************************************************************/ +#ifdef USE_W32_IME +BOOL fIME = FALSE; -DEFUN ("w32-send-sys-command", Fw32_send_sys_command, - Sw32_send_sys_command, 1, 2, 0, - doc: /* Send frame a Windows WM_SYSCOMMAND message of type COMMAND. -Some useful values for COMMAND are #xf030 to maximize frame (#xf020 -to minimize), #xf120 to restore frame to original size, and #xf100 -to activate the menubar for keyboard access. #xf140 activates the -screen saver if defined. +typedef BOOL (WINAPI *IMMGETOPENSTATUSPROC)(HIMC); +IMMGETOPENSTATUSPROC ImmGetOpenStatusProc; -If optional parameter FRAME is not specified, use selected frame. */) - (Lisp_Object command, Lisp_Object frame) -{ - FRAME_PTR f = check_x_frame (frame); +typedef BOOL (WINAPI *IMMSETOPENSTATUSPROC)(HIMC, BOOL); +IMMSETOPENSTATUSPROC ImmSetOpenStatusProc; - CHECK_NUMBER (command); +typedef BOOL (WINAPI *IMMSETCOMPOSITIONWINDOWPROC)(HIMC, LPCOMPOSITIONFORM); +IMMSETCOMPOSITIONWINDOWPROC ImmSetCompositionWindowProc; - PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0); +typedef LONG (WINAPI *IMMGETCOMPOSITIONSTRINGPROC) + (HIMC, DWORD, LPVOID, DWORD); +IMMGETCOMPOSITIONSTRINGPROC ImmGetCompositionStringProc; - return Qnil; -} +typedef LONG (WINAPI *IMMSETCOMPOSITIONSTRINGPROC) + (HIMC, DWORD, LPCVOID, DWORD, LPCVOID, DWORD); +IMMSETCOMPOSITIONSTRINGPROC ImmSetCompositionStringProc; -DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0, - doc: /* Get Windows to perform OPERATION on DOCUMENT. -This is a wrapper around the ShellExecute system function, which -invokes the application registered to handle OPERATION for DOCUMENT. +typedef BOOL (WINAPI *IMMSETCOMPOSITIONFONTPROC) (HIMC, LPLOGFONTA); +IMMSETCOMPOSITIONFONTPROC ImmSetCompositionFontProc; -OPERATION is either nil or a string that names a supported operation. -What operations can be used depends on the particular DOCUMENT and its -handler application, but typically it is one of the following common -operations: +typedef HIMC (WINAPI *IMMGETCONTEXTPROC)(HWND); +IMMGETCONTEXTPROC ImmGetContextProc; - \"open\" - open DOCUMENT, which could be a file, a directory, or an - executable program. If it is an application, that - application is launched in the current buffer's default - directory. Otherwise, the application associated with - DOCUMENT is launched in the buffer's default directory. - \"print\" - print DOCUMENT, which must be a file - \"explore\" - start the Windows Explorer on DOCUMENT - \"edit\" - launch an editor and open DOCUMENT for editing; which - editor is launched depends on the association for the - specified DOCUMENT - \"find\" - initiate search starting from DOCUMENT which must specify - a directory - nil - invoke the default OPERATION, or \"open\" if default is - not defined or unavailable +typedef BOOL (WINAPI *IMMGETCONVERSIONSTATUSPROC)(HIMC, LPDWORD, LPDWORD); +IMMGETCONVERSIONSTATUSPROC ImmGetConversionStatusProc; -DOCUMENT is typically the name of a document file or a URL, but can -also be a program executable to run, or a directory to open in the -Windows Explorer. +typedef BOOL (WINAPI *IMMSETCONVERSIONSTATUSPROC)(HIMC, DWORD, DWORD); +IMMSETCONVERSIONSTATUSPROC ImmSetConversionStatusProc; -If DOCUMENT is a program executable, the optional third arg PARAMETERS -can be a string containing command line parameters that will be passed -to the program; otherwise, PARAMETERS should be nil or unspecified. +typedef BOOL (WINAPI *IMMGETCONVERSIONLISTPROC) + (HKL, HIMC, LPCTSTR, LPCANDIDATELIST, DWORD, UINT); +IMMGETCONVERSIONLISTPROC ImmGetConversionListProc; -Optional fourth argument SHOW-FLAG can be used to control how the -application will be displayed when it is invoked. If SHOW-FLAG is nil -or unspecified, the application is displayed normally, otherwise it is -an integer representing a ShowWindow flag: +typedef BOOL (WINAPI *IMMCONFIGUREIMEPROC)(HKL, HWND, DWORD, LPVOID); +IMMCONFIGUREIMEPROC ImmConfigureIMEProc; - 0 - start hidden - 1 - start normally - 3 - start maximized - 6 - start minimized */) - (Lisp_Object operation, Lisp_Object document, Lisp_Object parameters, Lisp_Object show_flag) -{ - Lisp_Object current_dir; - char *errstr; +typedef BOOL (WINAPI *IMMNOTIFYIMEPROC)(HIMC, DWORD, DWORD, DWORD); +IMMNOTIFYIMEPROC ImmNotifyIMEProc; - CHECK_STRING (document); +typedef BOOL (WINAPI *IMMRELEASECONTEXTPROC)(HWND, HIMC); +IMMRELEASECONTEXTPROC ImmReleaseContextProc; - /* Encode filename, current directory and parameters. */ - current_dir = ENCODE_FILE (BVAR (current_buffer, directory)); - document = ENCODE_FILE (document); - if (STRINGP (parameters)) - parameters = ENCODE_SYSTEM (parameters); +typedef HIMC (WINAPI *IMMCREATECONTEXTPROC)(void); +IMMCREATECONTEXTPROC ImmCreateContextProc; - if ((int) ShellExecute (NULL, - (STRINGP (operation) ? - SDATA (operation) : NULL), - SDATA (document), - (STRINGP (parameters) ? - SDATA (parameters) : NULL), - SDATA (current_dir), - (INTEGERP (show_flag) ? - XINT (show_flag) : SW_SHOWDEFAULT)) - > 32) - return Qt; - errstr = w32_strerror (0); - /* The error string might be encoded in the locale's encoding. */ - if (!NILP (Vlocale_coding_system)) - { - Lisp_Object decoded = - code_convert_string_norecord (build_unibyte_string (errstr), - Vlocale_coding_system, 0); - errstr = SSDATA (decoded); +typedef BOOL (WINAPI *IMMDESTROYCONTEXTPROC)(HIMC); +IMMDESTROYCONTEXTPROC ImmDestroyContextProc; + +typedef HIMC (WINAPI *IMMASSOCIATECONTEXTPROC) (HWND, HIMC); +IMMASSOCIATECONTEXTPROC ImmAssociateContextProc; + +typedef BOOL (WINAPI *IMMGETCANDIDATELISTPROC) + (HIMC, DWORD, LPCANDIDATELIST, DWORD); +IMMGETCANDIDATELISTPROC ImmGetCandidateListProc; + +typedef BOOL (WINAPI *IMMGETCANDIDATELISTCOUNTPROC) (HIMC, LPDWORD); +IMMGETCANDIDATELISTCOUNTPROC ImmGetCandidateListCountProc; + +typedef BOOL (WINAPI *IMMGETHOTKEYPROC)(DWORD, LPUINT, LPUINT, LPHKL); +IMMGETHOTKEYPROC ImmGetHotKeyProc; + +typedef BOOL (WINAPI *IMMGETPROPERTYPROC)(HKL, DWORD); +IMMGETPROPERTYPROC ImmGetPropertyProc; + +// Lisp_Object Vime_control; + +static void +w32_set_ime_conv_window (hwnd, f) + HWND hwnd; + struct frame *f; +{ + if (fIME && !NILP (Vime_control)) + { + HIMC himc; + COMPOSITIONFORM compform; + struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f)); + + /* If Vw32_ime_composition_window is set, try it. */ + if (!NILP (Vw32_ime_composition_window) + && WINDOWP (Vw32_ime_composition_window) + && WINDOW_FRAME (XWINDOW (Vw32_ime_composition_window)) + == WINDOW_FRAME (w)) + w = XWINDOW (Vw32_ime_composition_window); + + himc = (ImmGetContextProc) (hwnd); + compform.dwStyle = CFS_RECT; + + compform.ptCurrentPos.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); + compform.ptCurrentPos.y = WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y); +#if 0 + if (FRAME_FONT (f)->vertical_centering == 1) + compform.ptCurrentPos.y += FRAME_FONT (f)->baseline_offset; +#endif + compform.rcArea.left = (WINDOW_BOX_LEFT_EDGE_X (w) + + WINDOW_LEFT_MARGIN_WIDTH (w) + + WINDOW_LEFT_FRINGE_WIDTH (w)); + + compform.rcArea.top = (WINDOW_TOP_EDGE_Y (w) + + WINDOW_HEADER_LINE_HEIGHT (w)); + + compform.rcArea.right = (WINDOW_BOX_RIGHT_EDGE_X (w) + - WINDOW_RIGHT_MARGIN_WIDTH (w) + - WINDOW_RIGHT_FRINGE_WIDTH (w)) + 1; + + compform.rcArea.bottom = (WINDOW_BOTTOM_EDGE_Y (w) + - WINDOW_MODE_LINE_HEIGHT (w)); + + (ImmSetCompositionWindowProc) (himc, &compform); + (ImmReleaseContextProc) (hwnd, himc); } - error ("ShellExecute failed: %s", errstr); } -/* Lookup virtual keycode from string representing the name of a - non-ascii keystroke into the corresponding virtual key, using - lispy_function_keys. */ +static void +w32_set_ime_status (hwnd, openp) + HWND hwnd; + int openp; +{ + HIMC himc; + + himc = (ImmGetContextProc) (hwnd); + (ImmSetOpenStatusProc) (himc, openp); + (ImmReleaseContextProc) (hwnd, himc); +} + static int -lookup_vk_code (char *key) +w32_get_ime_status (hwnd) + HWND hwnd; { - int i; + HIMC himc; + int ret; - for (i = 0; i < 256; i++) - if (lispy_function_keys[i] - && strcmp (lispy_function_keys[i], key) == 0) - return i; + himc = (ImmGetContextProc) (hwnd); + ret = (ImmGetOpenStatusProc) (himc); + (ImmReleaseContextProc) (hwnd, himc); - return -1; + return ret; } -/* Convert a one-element vector style key sequence to a hot key - definition. */ -static Lisp_Object -w32_parse_hot_key (Lisp_Object key) +static int +w32_set_ime_mode (hwnd, mode, mask) + HWND hwnd; + int mode; + int mask; { - /* Copied from Fdefine_key and store_in_keymap. */ - register Lisp_Object c; - int vk_code; - int lisp_modifiers; - int w32_modifiers; - struct gcpro gcpro1; + HIMC himc; + DWORD cmode, smode; - CHECK_VECTOR (key); + himc = (ImmGetContextProc) (hwnd); + if (!(ImmGetConversionStatusProc) (himc, &cmode, &smode)) + return 0; - if (XFASTINT (Flength (key)) != 1) - return Qnil; + cmode = (cmode & (~mask)) | (mode & mask); - GCPRO1 (key); + (ImmSetConversionStatusProc) (himc, cmode, smode); + (ImmReleaseContextProc) (hwnd, himc); - c = Faref (key, make_number (0)); + return 1; +} - if (CONSP (c) && lucid_event_type_list_p (c)) - c = Fevent_convert_list (c); +static BOOL +w32_get_ime_composition_string (hwnd) + HWND hwnd; +{ + HIMC hIMC; + int size; + HANDLE himestr; +#ifdef IME_UNICODE + LPWSTR lpstr; +#else + LPSTR lpstr; +#endif - UNGCPRO; + struct frame *f; - if (! INTEGERP (c) && ! SYMBOLP (c)) - error ("Key definition is invalid"); + hIMC = (ImmGetContextProc) (hwnd); + if (!hIMC) + return FALSE; + + size = (ImmGetCompositionStringProc) (hIMC, GCS_RESULTSTR, NULL, 0); +#ifdef IME_UNICODE + size += sizeof (WCHAR); +#else + size += sizeof (CHAR); +#endif + himestr = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, size); + if (!himestr) + abort (); - /* Work out the base key and the modifiers. */ - if (SYMBOLP (c)) - { - c = parse_modifiers (c); - lisp_modifiers = XINT (Fcar (Fcdr (c))); + (ImmGetCompositionStringProc) (hIMC, GCS_RESULTSTR, himestr, size); + (ImmReleaseContextProc) (hwnd, hIMC); + { + W32Msg wmsg; + f = SELECTED_FRAME (); + my_post_msg (&wmsg, hwnd, WM_MULE_IME_REPORT, + (WPARAM) himestr, (LPARAM) f); + } + return TRUE; +} + +#ifdef RECONVERSION +#ifdef USE_W32_CALL_LISP_THREAD +struct get_reconversion_string_arg { + WPARAM wparam; + RECONVERTSTRING *reconv; /* in */ +#ifdef IME_UNICODE + unsigned short *compstr; /* in */ +#else + unsigned char *compstr; /* in */ +#endif + DWORD size; /* in,out */ +}; +#endif /* USE_W32_CALL_LISP_THREAD */ + +static EMACS_INT compstr_beginning_pos(int max_char) +{ + EMACS_INT bol, point = PT, pt; + for (bol = XFASTINT(Fline_beginning_position(Qnil)), pt = PT; + PT >= bol && PT > point - max_char; ) { + pt = PT; + if (NILP(Fforward_word (make_number (-1)))) + break; + } + Fgoto_char (make_number(point)); + return pt; +} + +static EMACS_INT compstr_end_pos(int max_char) +{ + EMACS_INT eol, point = PT, pt; + + for (eol = XFASTINT(Fline_end_position(Qnil)), pt = PT; + PT <= eol && PT < point + max_char;) { + pt = PT; + if (NILP(Fforward_word (make_number (1)))) + break; + } + Fgoto_char (make_number(point)); + return pt; +} + +#if !defined(USE_W32_CALL_LISP_THREAD) +static LRESULT +get_reconversion_string (HWND hwnd, + RECONVERTSTRING *reconv, + unsigned short *compstr) +{ + EMACS_INT pt, pt_byte, start, end, len, t_start, t_end, compstr_len; + W32Msg wmsg; + + if (!NILP (BVAR (current_buffer, read_only))) + return 0; + + pt = PT; + pt_byte = PT_BYTE; + + if (compstr) + { + t_start = PT; + start = compstr_beginning_pos (DOCFEED_LENG); + end = compstr_end_pos (DOCFEED_LENG); + } + else if (!NILP (BVAR (current_buffer, mark_active)) + && !NILP (Vtransient_mark_mode)) + { + if (marker_position (BVAR (current_buffer, mark)) < PT) + { + t_start = marker_position (BVAR (current_buffer, mark)); + t_end = PT; + } + else + { + t_start = PT; + t_end = marker_position (BVAR (current_buffer, mark)); + } + Fgoto_char (make_number (t_end)); + while (!NILP (Fbolp ()) && t_start < PT) + Fforward_char (make_number (-1)); + if (t_start >= PT) + return 0; + t_end = PT; + } + else + { + while (!NILP (Fbolp ()) && NILP (Fbobp ())) + Fforward_char (make_number (1)); + if (!NILP (Fbobp ())) + return 0; + + t_end = PT; + Fforward_word (make_number (-1)); + t_start = PT; + } + + if (!compstr) + { + if (t_start == t_end) + return 0; + + Fgoto_char (make_number (t_start)); + start = compstr_beginning_pos (RECONV_LENG); + Fgoto_char (make_number (t_end)); + end = compstr_end_pos (RECONV_LENG); + } + + len = end - start; + if (reconv) + { + int pos; + WCHAR *s; + + s = (WCHAR *) (reconv + 1); + + for (pos = start; pos < t_start; pos++) + *s++ = (WCHAR) FETCH_CHAR (CHAR_TO_BYTE (pos)); + + if (compstr) + { + for (compstr_len = 0; compstr[compstr_len]; compstr_len++) + *s++ = compstr[compstr_len]; + + len += compstr_len; + } + else + compstr_len = t_end - t_start; + + for (; pos < end; pos++) + *s++ = (WCHAR) FETCH_CHAR (CHAR_TO_BYTE (pos)); + + *s = 0; + } + else + { + SET_PT_BOTH (pt, pt_byte); + if (compstr) + { + for (compstr_len = 0; compstr[compstr_len]; compstr_len++) + ; + + len += compstr_len; + } + return (sizeof (RECONVERTSTRING) + (len + 1) * CHRSZ); + } + + reconv->dwStrOffset = sizeof (RECONVERTSTRING); + reconv->dwStrLen = len; + reconv->dwCompStrOffset = + reconv->dwTargetStrOffset = (t_start - start) * CHRSZ; + reconv->dwCompStrLen = + reconv->dwTargetStrLen = compstr_len; + + if (!compstr) + my_post_msg (&wmsg, hwnd, WM_MULE_IME_DEL_RANGE, (WPARAM) t_start, (LPARAM) t_end); + + return (reconv->dwSize = sizeof (RECONVERTSTRING) + (len + 1) * CHRSZ); +} + +static LRESULT +w32_get_ime_reconversion_string (HWND hwnd, + WPARAM wParam, + RECONVERTSTRING *reconv) +{ + return get_reconversion_string (hwnd, reconv, NULL); +} +#else /* USE_W32_CALL_LISP_THREAD */ +static Lisp_Object +get_reconversion_string (Lisp_Object arg_) +{ + struct get_reconversion_string_arg *arg = cons2ptr(arg_); + EMACS_INT pt, pt_byte, point, start, end, len, + t_start, t_end, del_start, del_end, compstr_len = 0; + Lisp_Object str; + struct gcpro gcpro1; + + if (!NILP (BVAR (current_buffer, read_only))) { + arg->size = 0; + return Qnil; + } + + pt = PT; + pt_byte = PT_BYTE; + + if (arg->compstr) { /* DOCUMENT_FEED */ +#ifdef DOCUMENTFEED + t_start = compstr_beginning_pos(DOCFEED_LENG); + t_end = compstr_end_pos(DOCFEED_LENG); + point = PT; +#endif + } else if (!NILP (BVAR (current_buffer, mark_active)) + && !NILP (Vtransient_mark_mode)) { + if (marker_position (BVAR (current_buffer, mark)) < PT) { + t_start = marker_position (BVAR (current_buffer, mark)); + point = t_end = PT; + } else { + point = t_start = PT; + t_end = marker_position (BVAR (current_buffer, mark)); + } + Fgoto_char(make_number(t_end)); + while (!NILP(Fbolp()) && t_start < PT) + Fforward_char(make_number(-1)); + if (t_start >= PT) + return Qnil; + t_end = PT; + } else { + point = PT; + + while (!NILP(Fbolp()) && NILP(Fbobp())) + Fforward_char(make_number(1)); + if (!NILP(Fbobp())) + return Qnil; + + t_end = PT; + Fforward_word (make_number (-1)); + t_start = PT; + } + if (t_start == t_end) { + arg->size = 0; + return Qnil; + } + + if (arg->compstr) { + start = t_start; + end = t_end; + t_start = point - t_start; + } else { + + start = compstr_beginning_pos(RECONV_LENG); + end = compstr_end_pos(RECONV_LENG); + + del_start = t_start; + del_end = t_end; + + t_start -= start; + t_end -= start; + } + + GCPRO1(str); + str = make_buffer_string (start, end, 1); + +#ifdef IME_UNICODE + len = end - start; + if (arg->reconv) { + int pos; + WCHAR *uc_code, *s; + + uc_code = (WCHAR *) (arg->reconv + 1); + s = uc_code; + + for (pos = 0; pos < t_start; pos++) + *s++ = (WCHAR) XFASTINT(Faref(str, make_number(pos))); + + if (arg->compstr) + for (compstr_len = 0; arg->compstr[compstr_len]; compstr_len++) + *s++ = arg->compstr[compstr_len]; + + for (; pos < len; pos++) + *s++ = (WCHAR) XFASTINT(Faref(str, make_number(pos))); + + *s = 0; + } else { + if (arg->compstr) + for (compstr_len = 0; arg->compstr[compstr_len]; compstr_len++) + ; + } + +#define STROFFSET(s,o) ((o) * CHRSZ) +#define STRSIZE(s, b, e) ((e) - (b)) +#else /* IME_UNICODE */ + if (!arg->reconv + && !NILP (Ftext_property_any (make_number (0), + Flength (str), + intern ("read-only"), + Qt, + str))) { + SET_PT_BOTH (pt, pt_byte); + UNGCPRO; + return Qt; /* Cannot signal here */ + } + str = ENCODE_SYSTEM (str); + + len = SBYTES(str); + if (arg->compstr) + compstr_len = strlen(arg->compstr); + +#define STROFFSET(s,o) (_mbsninc(SDATA(s), (o)) - SDATA(s)) +#define STRSIZE(s, b, e) (_mbsninc(SDATA(s), (e)) - _mbsninc(SDATA(s), (b))) + + if (arg->reconv) { + if (arg->compstr) { + LPSTR s = (LPSTR)(arg->reconv + 1); + strncpy(s, SDATA(str), STROFFSET(str, t_start)); + strcpy(s + STROFFSET(str, t_start), arg->compstr); + strcpy(s + STROFFSET(str, t_start) + compstr_len, + SDATA(str) + STROFFSET(str, t_start)); + } else + strcpy ((LPSTR)(arg->reconv + 1), SDATA(str)); + } +#endif + + if (arg->reconv) { + arg->reconv->dwStrOffset = sizeof (RECONVERTSTRING); + arg->reconv->dwStrLen = len + compstr_len; + + if (arg->compstr) { + arg->reconv->dwCompStrOffset = + arg->reconv->dwTargetStrOffset = STROFFSET(str, t_start); + arg->reconv->dwCompStrLen = + arg->reconv->dwTargetStrLen = compstr_len; + + } else { + arg->reconv->dwTargetStrOffset = + arg->reconv->dwCompStrOffset = STROFFSET(str, t_start); + arg->reconv->dwTargetStrLen = + arg->reconv->dwCompStrLen = STRSIZE(str, t_start, t_end); + + del_range(del_start, del_end); + Fgoto_char (make_number(del_start)); + } + } else { + SET_PT_BOTH (pt, pt_byte); + } + arg->size = sizeof(RECONVERTSTRING) + (len + compstr_len + 1) * CHRSZ; + if (arg->reconv != NULL && arg->compstr != NULL) + arg->compstr[0] = 0; + + UNGCPRO; + return Qt; +} + +static LRESULT +w32_get_ime_reconversion_string(HWND hwnd, + WPARAM wParam, + RECONVERTSTRING *reconv) +{ + struct get_reconversion_string_arg grs = + {IMR_RECONVERTSTRING, reconv, NULL, 0}; + + if (NILP(w32_call_lisp_thread(get_reconversion_string, &grs))) + return 0; + return reconv->dwSize; +} +#endif /* USE_W32_CALL_LISP_THREAD */ +#endif /* RECONVERSION */ + +#if defined(DOCUMENTFEED) +#if !defined(USE_W32_CALL_LISP_THREAD) +static LRESULT +w32_get_ime_documentfeed_string (HWND hwnd, + WPARAM wParam, + RECONVERTSTRING *reconv) +{ + unsigned short ime_compstr[DOCFEED_CSTR_LENG]; + HIMC hIMC; + LONG l; + + if (hIMC = (ImmGetContextProc) (hwnd)) + { + if ((ImmGetCompositionStringProc) (hIMC, GCS_COMPSTR, NULL, 0) + >= DOCFEED_CSTR_LENG * CHRSZ) + { + (ImmReleaseContextProc) (hwnd, hIMC); + return 0; + } + + switch (l = (ImmGetCompositionStringProc) + (hIMC, GCS_COMPSTR, ime_compstr, + (DOCFEED_CSTR_LENG - 1) * CHRSZ)) + { + case IMM_ERROR_NODATA: + case IMM_ERROR_GENERAL: + ime_compstr[0] = 0; + break; + default: + ime_compstr[l / CHRSZ] = 0; + break; + } + (ImmReleaseContextProc) (hwnd, hIMC); + + return get_reconversion_string (hwnd, reconv, ime_compstr); + } + + return 0; +} +#else /* USE_W32_CALL_LISP_THREAD */ +static LRESULT +w32_get_ime_documentfeed_string(HWND hwnd, + WPARAM wParam, + RECONVERTSTRING *reconv) +{ +#ifdef IME_UNICODE + unsigned short ime_compstr[DOCFEED_CSTR_LENG]; +#else + unsigned char ime_compstr[DOCFEED_CSTR_LENG]; +#endif + struct get_reconversion_string_arg grs = + {IMR_DOCUMENTFEED, reconv, ime_compstr, 0} ; + HIMC himc; + LONG l; + + if (!(himc = (ImmGetContextProc) (hwnd))) + return 0; + + if (ImmGetCompositionStringProc(himc, GCS_COMPSTR, NULL, 0) + >= DOCFEED_CSTR_LENG * CHRSZ) { + (ImmReleaseContextProc) (hwnd, himc); + return 0; + } + + switch (l = (ImmGetCompositionStringProc) + (himc, GCS_COMPSTR, ime_compstr, + (DOCFEED_CSTR_LENG - 1) * CHRSZ)) { + + case IMM_ERROR_NODATA: + case IMM_ERROR_GENERAL: + ime_compstr[0] = 0; + break; + default: + ime_compstr[l / CHRSZ] = 0; + break; + } + (ImmReleaseContextProc) (hwnd, himc); + + grs.size = l; + + if (NILP(w32_call_lisp_thread(get_reconversion_string, &grs))) + return 0; + return reconv->dwSize; +} +#endif /* USE_W32_CALL_LISP_THREAD */ +#endif /* DOCUMENTFEED */ + +void +w32_ime_control_init (void) +{ + HMODULE hImm32; + HMODULE hUser32; + + hImm32 = GetModuleHandle ("IMM32.DLL"); + if (!hImm32) + hImm32 = LoadLibrary ("IMM32.DLL"); + + fIME = FALSE; + Vime_control = Qnil; + IME_event_off_count = 0; + + if (hImm32) + { + ImmGetOpenStatusProc = + (IMMGETOPENSTATUSPROC) + GetProcAddress (hImm32, + ImmGetOpenStatus_Name); + ImmSetOpenStatusProc = + (IMMSETOPENSTATUSPROC) + GetProcAddress (hImm32, + ImmSetOpenStatus_Name); + ImmSetCompositionWindowProc = + (IMMSETCOMPOSITIONWINDOWPROC) + GetProcAddress (hImm32, + ImmSetCompositionWindow_Name); + ImmGetContextProc = + (IMMGETCONTEXTPROC) + GetProcAddress (hImm32, + ImmGetContext_Name); + ImmGetConversionStatusProc = + (IMMGETCONVERSIONSTATUSPROC) + GetProcAddress (hImm32, + ImmGetConversionStatus_Name); + ImmSetConversionStatusProc = + (IMMSETCONVERSIONSTATUSPROC) + GetProcAddress (hImm32, + ImmSetConversionStatus_Name); + ImmNotifyIMEProc = + (IMMNOTIFYIMEPROC) + GetProcAddress (hImm32, + ImmNotifyIME_Name); + ImmReleaseContextProc = + (IMMRELEASECONTEXTPROC) + GetProcAddress (hImm32, + ImmReleaseContext_Name); + ImmCreateContextProc = + (IMMCREATECONTEXTPROC) + GetProcAddress (hImm32, + ImmCreateContext_Name); + ImmDestroyContextProc = + (IMMDESTROYCONTEXTPROC) + GetProcAddress (hImm32, + ImmDestroyContext_Name); + ImmAssociateContextProc = + (IMMASSOCIATECONTEXTPROC) + GetProcAddress (hImm32, + ImmAssociateContext_Name); + ImmGetHotKeyProc = + (IMMGETHOTKEYPROC) + GetProcAddress (hImm32, + ImmGetHotKey_Name); + ImmGetPropertyProc = + (IMMGETPROPERTYPROC) + GetProcAddress (hImm32, ImmGetProperty_Name); + ImmGetCompositionStringProc = + (IMMGETCOMPOSITIONSTRINGPROC) + GetProcAddress (hImm32, ImmGetCompositionString_Name); + ImmSetCompositionStringProc = + (IMMSETCOMPOSITIONSTRINGPROC) + GetProcAddress (hImm32, ImmSetCompositionString_Name); + ImmSetCompositionFontProc = + (IMMSETCOMPOSITIONFONTPROC) + GetProcAddress (hImm32, ImmSetCompositionFont_Name); + ImmGetConversionListProc = + (IMMGETCONVERSIONLISTPROC) + GetProcAddress (hImm32, + ImmGetConversionList_Name); + ImmConfigureIMEProc = + (IMMCONFIGUREIMEPROC) + GetProcAddress (hImm32, + ImmConfigureIME_Name); + ImmGetCandidateListProc = + (IMMGETCANDIDATELISTPROC) + GetProcAddress (hImm32, + ImmGetCandidateList_Name); + ImmGetCandidateListCountProc = + (IMMGETCANDIDATELISTCOUNTPROC) + GetProcAddress (hImm32, + ImmGetCandidateListCount_Name); + + if (ImmGetOpenStatusProc && + ImmSetOpenStatusProc && + ImmSetCompositionWindowProc && + ImmGetCompositionStringProc && + ImmSetCompositionStringProc && + ImmSetCompositionFontProc && + ImmGetPropertyProc && + ImmGetContextProc && + ImmGetConversionStatusProc && + ImmSetConversionStatusProc && + ImmGetConversionListProc && + ImmConfigureIMEProc && + ImmNotifyIMEProc && + ImmReleaseContextProc && + ImmCreateContextProc && + ImmDestroyContextProc && + ImmAssociateContextProc && + ImmGetCandidateListProc && + ImmGetCandidateListCountProc && + ImmGetHotKeyProc) + { + fIME = TRUE; + Vime_control = Qt; + } + } +} + +#ifdef USE_W32_CALL_LISP_THREAD +struct apc_data { + Lisp_Object (*func)(Lisp_Object); + Lisp_Object val; + void *arg; + HANDLE ev; +}; + +static Lisp_Object apc_error_handler (Lisp_Object arg) +{ + return Qnil; +} + +static VOID CALLBACK apc_func_stub(ULONG_PTR data_) +{ + struct apc_data *apc_data = (struct apc_data *)data_; + Lisp_Object arg = ptr2cons(apc_data->arg); + struct gcpro gcpro1; + + GCPRO1(arg); + apc_data->val = + internal_condition_case_1 + (apc_data->func, arg, Qt, apc_error_handler); + + UNGCPRO; + SetEvent(apc_data->ev); +} + +static Lisp_Object w32_call_lisp_thread +(Lisp_Object (*func)(Lisp_Object), void *arg) +{ + struct apc_data apc_data = { + func, Qnil, arg, + CreateEvent(NULL, FALSE, FALSE, NULL) + }; + DWORD v; + deferred_msg dummy = {0}; + + dummy.completed = 1; + + + w32_apc_mutex_acquire(); + if (apc_data.ev == NULL) + abort(); + + if (QueueUserAPC(apc_func_stub, + hMainThread, (ULONG_PTR)&apc_data) == 0) + abort (); + + while ((v = MsgWaitForMultipleObjectsEx + (1, &apc_data.ev, INFINITE, QS_SENDMESSAGE, MWMO_ALERTABLE)) != WAIT_OBJECT_0) + if (v == WAIT_OBJECT_0 + 1) + w32_msg_pump(&dummy); + else if (v != WAIT_IO_COMPLETION) + abort(); + + w32_apc_mutex_release(); + return apc_data.val; +} +#endif + +#ifdef HAVE_NTGUI +EXFUN (Ffont_at, 3); +#if !defined(USE_W32_CALL_LISP_THREAD) +static int +need_set_ime_font (PLOGFONT p) +{ + if (!p || + (p->lfHeight == ime_logfont.lfHeight + && p->lfWidth == ime_logfont.lfWidth + && p->lfEscapement == ime_logfont.lfEscapement + && p->lfOrientation == ime_logfont.lfOrientation + && p->lfWeight == ime_logfont.lfWeight + && p->lfItalic == ime_logfont.lfItalic + && p->lfUnderline == ime_logfont.lfUnderline + && p->lfStrikeOut == ime_logfont.lfStrikeOut + && p->lfCharSet == ime_logfont.lfCharSet + && p->lfOutPrecision == ime_logfont.lfOutPrecision + && p->lfClipPrecision == ime_logfont.lfClipPrecision + && p->lfQuality == ime_logfont.lfQuality + && p->lfPitchAndFamily == ime_logfont.lfPitchAndFamily + && strncmp (p->lfFaceName, ime_logfont.lfFaceName, LF_FACESIZE) == 0)) + return 0; + else + return 1; +} +void +w32_set_ime_logfont (hwnd, f) + HWND hwnd; + struct frame *f; +{ + Lisp_Object ime_font = Qnil, temp = Qnil, font = Qnil, family; + struct gcpro gcpro1, gcpro2; + extern Lisp_Object QCfamily; + int fsid = -1; + LOGFONT logfont = {0}; + + if (!IsWindow (hwnd)) + return; + + if (!fIME || NILP(Vime_control)) + return; + + GCPRO2(font, temp); + + if (STRINGP(ime_font = get_frame_param (f, Qime_font)) + /* fontset */ + && ((fsid = fs_query_fontset(ime_font, 0)) >= 0 + && !NILP(font = fontset_ascii(fsid)) + && !NILP(font = font_spec_from_name(font)) + && !NILP(temp = Ffontset_font(temp, make_number(0x3042), Qnil)) + && !NILP(family = XCAR(temp)) + /* font */ + || !NILP(font = font_spec_from_name(ime_font)) + && SYMBOLP(family = AREF (font, FONT_FAMILY_INDEX)) + && STRINGP(family = SYMBOL_NAME(family))) + + /* use font object */ + /* frame-parameter */ + || (FONTP(font = ime_font) + /* frame fontset */ + || ((fsid = FRAME_FONTSET(f)) >= 0 + && !NILP(font = + Ffont_at(make_number(0), Qnil, + temp = Fchar_to_string(make_number(0x3042)))))) + && SYMBOLP(family = Ffont_get(font, QCfamily)) + && STRINGP(family = SYMBOL_NAME(family)) + && !NILP(font = copy_font_spec(font))) { + Lisp_Object tail; + + fill_in_logfont (f, &logfont, font); + + logfont.lfWidth = 0; + + family = ENCODE_SYSTEM(family); + + strcpy(logfont.lfFaceName, SDATA(family)); + + /* rescale */ + for (tail = Vface_font_rescale_alist; CONSP (tail); tail = XCDR (tail)) { + temp = XCAR (tail); + if (!FLOATP (XCDR (temp))) + continue; + + if (STRINGP (XCAR (temp))) { + if (fast_string_match_ignore_case (XCAR (temp), family) >= 0) { + logfont.lfHeight *= XFLOAT_DATA (XCDR (temp)); + break; + } + } else if (FONT_SPEC_P (XCAR (temp))) { + Lisp_Object name; + if (!NILP(name = Ffont_get(XCAR (temp), QCfamily)) && + STRINGP(name) && + xstrcasecmp(SDATA(name), SDATA(family)) == 0) { + logfont.lfHeight *= XFLOAT_DATA (XCDR (temp)); + break; + } + } + } + } else { + HFONT hfont = FONT_HANDLE (FRAME_FONT (f)); + GetObject (hfont, sizeof (logfont), &logfont); + } + UNGCPRO; + + if (need_set_ime_font (&logfont)) + { + ime_logfont = logfont; + PostMessage (hwnd, WM_MULE_IMM_SET_IMEFONT, (WPARAM) f, 0); + } +} +static void +w32_set_ime_font (hwnd) + HWND hwnd; +{ + HIMC himc; + + if (!fIME || NILP (Vime_control)) + return; + + himc = (ImmGetContextProc) (hwnd); + if (!himc) + return; + (ImmSetCompositionFontProc) (himc, &ime_logfont); + (ImmReleaseContextProc) (hwnd, himc); +} +#else /* USE_W32_CALL_LISP_THREAD */ + +struct get_imefont_arg { + HWND hwnd; + struct frame *f; + LOGFONT lf; +}; + +static Lisp_Object +w32_get_ime_font (Lisp_Object arg_) +{ + struct get_imefont_arg *arg = cons2ptr(arg_); + + Lisp_Object ime_font = Qnil, temp = Qnil, font = Qnil, family; + struct gcpro gcpro1, gcpro2; + extern Lisp_Object QCfamily; + int fsid = -1; + + if (!fIME || NILP(Vime_control)) + return Qnil; + + GCPRO2(font, temp); + + if (STRINGP(ime_font = get_frame_param (arg->f, Qime_font)) + /* fontset */ + && ((fsid = fs_query_fontset(ime_font, 0)) >= 0 + && !NILP(font = fontset_ascii(fsid)) + && !NILP(font = font_spec_from_name(font)) + && !NILP(temp = Ffontset_font(temp, make_number(0x3042), Qnil)) + && !NILP(family = XCAR(temp)) + /* font */ + || !NILP(font = font_spec_from_name(ime_font)) + && SYMBOLP(family = AREF (font, FONT_FAMILY_INDEX)) + && STRINGP(family = SYMBOL_NAME(family))) + + /* use font object */ + /* frame-parameter */ + || (FONTP(font = ime_font) + /* frame fontset */ + || ((fsid = FRAME_FONTSET(arg->f)) >= 0 + && !NILP(font = + Ffont_at(make_number(0), Qnil, + temp = Fchar_to_string(make_number(0x3042)))))) + && SYMBOLP(family = Ffont_get(font, QCfamily)) + && STRINGP(family = SYMBOL_NAME(family)) + && !NILP(font = copy_font_spec(font))) { + Lisp_Object tail; + + fill_in_logfont (arg->f, &arg->lf, font); + arg->lf.lfWidth = 0; + + family = ENCODE_SYSTEM(family); + +#ifdef _MSC_VER + strcpy_s(arg->lf.lfFaceName, + sizeof(arg->lf.lfFaceName), SDATA(family)); +#else + strcpy(arg->lf.lfFaceName, SDATA(family)); +#endif + + /* rescale if ime font isn't ascii*/ + for (tail = Vface_font_rescale_alist; CONSP (tail); tail = XCDR (tail)) { + temp = XCAR (tail); + if (!FLOATP (XCDR (temp))) + continue; + + if (STRINGP (XCAR (temp))) { + if (fast_string_match_ignore_case (XCAR (temp), family) >= 0) { + arg->lf.lfHeight *= XFLOAT_DATA (XCDR (temp)); + break; + } + } else if (FONT_SPEC_P (XCAR (temp))) { + Lisp_Object name; + if (!NILP(name = Ffont_get(XCAR (temp), QCfamily)) && + STRINGP(name) && + xstrcasecmp(SDATA(name), SDATA(family)) == 0) { + arg->lf.lfHeight *= XFLOAT_DATA (XCDR (temp)); + break; + } + } + } + } else { + HFONT hfont = FONT_HANDLE (FRAME_FONT (arg->f)); + GetObject (hfont, sizeof (arg->lf), &arg->lf); + } + UNGCPRO; + + return Qt; +} + +static void +w32_set_ime_font (hwnd, f) + HWND hwnd; + struct frame *f; +{ + HIMC himc; + struct get_imefont_arg gia = { + hwnd, f, {0} + }; + + if (NILP(w32_call_lisp_thread(w32_get_ime_font, &gia)) || + !(himc = (ImmGetContextProc) (hwnd))) + return; + + (ImmSetCompositionFontProc) (himc, &gia.lf); + (ImmReleaseContextProc) (hwnd, himc); +} +#endif /* USE_W32_CALL_LISP_THREAD */ +#endif /* HAVE_NTGUI */ + +static LRESULT CALLBACK +conversion_agent_wndproc (HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) +/* HWND hwnd; + UINT message; + WPARAM wparam; + LPARAM lparam; */ +{ + HIMC himc, holdimc; + + switch (message) + { + case WM_MULE_IMM_SET_STATUS: + if (InSendMessage()) + ReplyMessage(1); + w32_set_ime_status (hwnd, (int) wparam); + break; + + case WM_MULE_IMM_GET_STATUS: + return w32_get_ime_status (hwnd); + + case WM_MULE_IMM_SET_MODE: + return w32_set_ime_mode (hwnd, (int) wparam, (int) lparam); + +#if !defined(USE_W32_CALL_LISP_THREAD) + case WM_MULE_IMM_SET_IMEFONT: + w32_set_ime_font (hwnd); +#endif + case WM_MULE_IMM_SET_CONVERSION_WINDOW: + if (w32_get_ime_status (hwnd)) + w32_set_ime_conv_window (hwnd, (struct frame *) wparam); + break; + + case WM_MULE_IMM_PERFORM_RECONVERSION: + if (ime_enable_reconversion) + w32_perform_reconversion(hwnd, (RECONVERTSTRING*)lparam); + break; + +#if 0 + case WM_MULE_IMM_GET_COMPOSITION_STRING: + return w32_get_ime_composition_string (hwnd); +#endif + + default: + return DefWindowProc (hwnd, message, wparam, lparam); + } + return 0; +} + + + +/* + Emacs Lisp function entries +*/ + +DEFUN ("ime-force-on", Fime_force_on, Sime_force_on, 0, 1, 0, + doc: /* Force status of IME open. */) + (Lisp_Object eventp) +{ + if (fIME && !NILP (Vime_control)) + { + HIMC himc; + HWND hwnd; + + if (!NILP (Fime_get_mode ())) + return Qnil; +#ifdef HAVE_NTGUI + if (NILP (eventp)) + IME_event_off_count++; + hwnd = FRAME_W32_WINDOW (SELECTED_FRAME ()); +#else + hwnd = hwndConsole; +#endif + SendMessage (hwnd, WM_MULE_IMM_SET_STATUS, 1, 0); + } + return Qnil; +} + +DEFUN ("ime-force-off", Fime_force_off, Sime_force_off, 0, 1, 0, + doc: /* Force status of IME close. */) + (Lisp_Object eventp) +{ + if (fIME && !NILP (Vime_control)) + { + HIMC himc; + HWND hwnd; + + if (NILP (Fime_get_mode ())) + return Qnil; +#ifdef HAVE_NTGUI + if (NILP (eventp)) + IME_event_off_count++; + hwnd = FRAME_W32_WINDOW (SELECTED_FRAME ()); +#else + hwnd = hwndConsole; +#endif + SendMessage (hwnd, WM_MULE_IMM_SET_STATUS, 0, 0); + } + return Qnil; +} + +DEFUN ("ime-get-mode", Fime_get_mode, Sime_get_mode, 0, 0, "", + doc: /* Get IME status. +t means status of IME is open. nil means it is close. */) + (void) +{ + if (fIME && !NILP (Vime_control)) + { + HWND hwnd; + int result; + +#ifdef HAVE_NTGUI + hwnd = FRAME_W32_WINDOW (SELECTED_FRAME ()); +#else + hwnd = hwndConsole; +#endif + result = SendMessage (hwnd, WM_MULE_IMM_GET_STATUS, 0, 0); + + return result ? Qt : Qnil; + } + else + return Qnil; +} + +DEFUN ("w32-set-ime-mode", + Fw32_set_ime_mode, + Sw32_set_ime_mode, 1, 2, 0, + doc: /* Set IME mode to MODE. If FRAME is omitted, the selected frame is used. */) + (Lisp_Object mode, Lisp_Object frame) +{ + FRAME_PTR f; + + if (NILP (frame)) + { + f = SELECTED_FRAME (); + } + else + { + CHECK_FRAME (frame); + f = XFRAME (frame); + } + if (fIME && !NILP (Vime_control)) + { + HWND hwnd; + int ret; + int newmode, mask; + + newmode = 0; + mask = 0; + + hwnd = FRAME_W32_WINDOW (f); + + if (EQ (mode, intern ("katakana"))) + { + newmode |= IME_CMODE_KATAKANA; + mask |= IME_CMODE_KATAKANA; + } + else if (EQ (mode, intern ("hiragana"))) + { + newmode &= ~IME_CMODE_KATAKANA; + mask |= IME_CMODE_KATAKANA; + } + else if (EQ (mode, intern ("kanji"))) + { + newmode |= IME_CMODE_HANJACONVERT; + mask |= IME_CMODE_HANJACONVERT; + } + else if (EQ (mode, intern ("nokanji"))) + { + newmode &= ~IME_CMODE_HANJACONVERT; + mask |= IME_CMODE_HANJACONVERT; + } + else if (EQ (mode, intern ("code"))) + { + newmode |= IME_CMODE_CHARCODE; + mask |= IME_CMODE_CHARCODE; + } + else if (EQ (mode, intern ("nocode"))) + { + newmode &= ~IME_CMODE_CHARCODE; + mask |= IME_CMODE_CHARCODE; + } + else if (EQ (mode, intern ("non-convert"))) + { + newmode |= IME_CMODE_NOCONVERSION; + mask |= IME_CMODE_NOCONVERSION; + } + else if (EQ (mode, intern ("convert"))) + { + newmode &= ~IME_CMODE_NOCONVERSION; + mask |= IME_CMODE_NOCONVERSION; + } + else + error ("unknown mode!!"); + + ret = SendMessage (hwnd, WM_MULE_IMM_SET_MODE, + (WPARAM) newmode, (LPARAM) mask); + + if (!ret) + return Qnil; + + return Qt; + } + return Qnil; +} + +DEFUN ("w32-ime-register-word-dialog", + Fw32_ime_register_word_dialog, + Sw32_ime_register_word_dialog, 2, 2, 0, + doc: /* Open IME regist word dialog. */) + (Lisp_Object reading, Lisp_Object word) +{ + HKL hkl; + int reading_len, word_len; + REGISTERWORD regword; + Lisp_Object encoded_reading, encoded_word; + + CHECK_STRING (reading); + CHECK_STRING (word); + + if (fIME && !NILP (Vime_control) && ImmConfigureIMEProc) + { + hkl = GetKeyboardLayout (0); + encoded_reading = Fencode_coding_string (reading, + Vlocale_coding_system, + Qnil, Qnil); + reading_len = SBYTES (encoded_reading); + regword.lpReading = SDATA (encoded_reading); + + encoded_word = Fencode_coding_string (word, + Vlocale_coding_system, + Qnil, Qnil); + word_len = SBYTES (encoded_word); + regword.lpWord = SDATA (encoded_word); + (ImmConfigureIMEProc) (hkl, FRAME_W32_WINDOW (SELECTED_FRAME ()), + IME_CONFIG_REGISTERWORD, ®word); + } + return Qnil; +} + +DEFUN ("ime-get-property", Fime_get_property, Sime_get_property, 1, 1, 0, + doc: /* Retrieves the property and capabilities of the IME associated with the specified input locale. +INDEX is one of igp-property, igp-conversion, igp-sentence, igp-ui, igp-setcompstr, igp-select of igp-getimeversion*/) + (Lisp_Object index) +{ + int i; + Lisp_Object val; + DWORD v; + struct gcpro gcpro1; + + static const struct { + const char *name; + DWORD index; + } index_map[] = { + {"property", IGP_PROPERTY}, + {"conversion", IGP_CONVERSION}, + {"sentence", IGP_SENTENCE}, + {"ui", IGP_UI}, + {"setcompstr", IGP_SETCOMPSTR}, + {"select", IGP_SELECT}, + {"getimeversion", IGP_GETIMEVERSION}, + }, prop_map[] = { + {"at-caret", IME_PROP_AT_CARET}, + {"special-ui", IME_PROP_SPECIAL_UI}, + {"candlist-start-from-1", IME_PROP_CANDLIST_START_FROM_1}, + {"unicode", IME_PROP_UNICODE}, + {"complete-on-unselect", IME_PROP_COMPLETE_ON_UNSELECT}, + }, ui_map[] = { + {"rot2700", UI_CAP_2700}, + {"rot90", UI_CAP_ROT90}, + {"rotany", UI_CAP_ROTANY}, + }, setcompstr_map[] = { + {"compstr", SCS_CAP_COMPSTR}, + {"makeread", SCS_CAP_MAKEREAD}, + {"setreconvertstring", SCS_CAP_SETRECONVERTSTRING}, + }, select_map[] = { + {"conversion", SELECT_CAP_CONVERSION}, + {"sentence", SELECT_CAP_SENTENCE}, + }, imeversion_map[] = { + {"ver-0310", IMEVER_0310}, + {"ver-0400", IMEVER_0400}, + }; + + CHECK_SYMBOL(index); + for (i = 0; i < sizeof(index_map) / sizeof(index_map[0]); i++) + if (EQ(index, intern(index_map[i].name))) + break; + if (i >= sizeof(index_map) / sizeof(index_map[0])) + return Qnil; + + v = (*ImmGetPropertyProc)(GetKeyboardLayout(0), index_map[i].index); + val = Qnil; + GCPRO1(val); +#define MAKE_CAP_LIST(map) do { \ + int j; \ + for (j = sizeof(map) / sizeof(map[0]) - 1; j >= 0 ; j--) \ + if (v & map[j].index) \ + val = Fcons(intern(map[j].name), val); \ +} while(0) + + switch (index_map[i].index) { + case IGP_PROPERTY: + MAKE_CAP_LIST(prop_map); + break; + case IGP_UI: + MAKE_CAP_LIST(ui_map); + break; + case IGP_SETCOMPSTR: + MAKE_CAP_LIST(setcompstr_map); + break; + case IGP_SELECT: + MAKE_CAP_LIST(select_map); + break; + case IGP_GETIMEVERSION: + MAKE_CAP_LIST(imeversion_map); + break; + } + UNGCPRO; + return val; +} + +#ifdef RECONVERSION +BOOL w32_perform_reconversion(HWND hwnd, RECONVERTSTRING *reconv) +{ + struct frame *f = SELECTED_FRAME (); + HIMC himc; + BOOL result = FALSE; + + himc = (ImmGetContextProc) (hwnd); + if (!himc) { + xfree(reconv); + return FALSE; + } + + if ((*ImmSetCompositionStringProc) (himc, + SCS_QUERYRECONVERTSTRING, + reconv, reconv->dwSize, + NULL, 0 ) + && (*ImmSetCompositionStringProc) (himc, + SCS_SETRECONVERTSTRING, + reconv, reconv->dwSize, + NULL, 0)) { + /* Set the position of candidate list dialog. */ + (ImmReleaseContextProc) (hwnd, himc); + w32_set_ime_conv_window (hwnd, f); + result = TRUE; + } else + (ImmReleaseContextProc) (hwnd, himc); + xfree(reconv); + return result; +} + +DEFUN ("w32-ime-perform-reconversion", + Fw32_ime_perform_reconversion, + Sw32_ime_perform_reconversion, 0, 0, "", + doc: /* perfom ime reconversion. */) + (void) +#if !defined(USE_W32_CALL_LISP_THREAD) +{ + HWND hwnd = FRAME_W32_WINDOW(SELECTED_FRAME()); + DWORD size; + RECONVERTSTRING *reconv; + + if (!ime_enable_reconversion || + NILP(Fime_get_mode())) + return Qnil; + + if ((size = get_reconversion_string (hwnd, NULL, NULL)) + && (reconv = xmalloc (size)) != NULL + && (memset (reconv, 0, size), (reconv->dwSize = size)) + && get_reconversion_string (hwnd, reconv, NULL)) + PostMessage(hwnd, WM_MULE_IMM_PERFORM_RECONVERSION, 0, (LPARAM) reconv); + + return Qt; +} +#else /* USE_W32_CALL_LISP_THREAD */ +{ + Lisp_Object temp; + struct gcpro gcpro1; + struct get_reconversion_string_arg grs = {0, NULL, NULL, 0}; + + if (!ime_enable_reconversion || + NILP(Fime_get_mode())) + return Qnil; + + GCPRO1(temp); + + if (!NILP(get_reconversion_string(temp = ptr2cons(&grs))) + && grs.size > 0 + && (grs.reconv = xmalloc(grs.size)) != NULL + && (memset(grs.reconv, 0, grs.size), + (grs.reconv->dwSize = grs.size)) + && !NILP(get_reconversion_string(temp))) { + + // del_range(grs.start, grs.end); + + PostMessage(FRAME_W32_WINDOW(SELECTED_FRAME()), + WM_MULE_IMM_PERFORM_RECONVERSION, 0, (LPARAM)grs.reconv); + } + UNGCPRO; + return Qt; +} +#endif /* USE_W32_CALL_LISP_THREAD */ +#endif + +#endif /* USE_W32_IME */ + + +/*********************************************************************** + w32 specialized functions + ***********************************************************************/ + +DEFUN ("w32-send-sys-command", Fw32_send_sys_command, + Sw32_send_sys_command, 1, 2, 0, + doc: /* Send frame a Windows WM_SYSCOMMAND message of type COMMAND. +Some useful values for COMMAND are #xf030 to maximize frame (#xf020 +to minimize), #xf120 to restore frame to original size, and #xf100 +to activate the menubar for keyboard access. #xf140 activates the +screen saver if defined. + +If optional parameter FRAME is not specified, use selected frame. */) + (Lisp_Object command, Lisp_Object frame) +{ + FRAME_PTR f = check_x_frame (frame); + + CHECK_NUMBER (command); + + PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0); + + return Qnil; +} + +DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0, + doc: /* Get Windows to perform OPERATION on DOCUMENT. +This is a wrapper around the ShellExecute system function, which +invokes the application registered to handle OPERATION for DOCUMENT. + +OPERATION is either nil or a string that names a supported operation. +What operations can be used depends on the particular DOCUMENT and its +handler application, but typically it is one of the following common +operations: + + \"open\" - open DOCUMENT, which could be a file, a directory, or an + executable program. If it is an application, that + application is launched in the current buffer's default + directory. Otherwise, the application associated with + DOCUMENT is launched in the buffer's default directory. + \"print\" - print DOCUMENT, which must be a file + \"explore\" - start the Windows Explorer on DOCUMENT + \"edit\" - launch an editor and open DOCUMENT for editing; which + editor is launched depends on the association for the + specified DOCUMENT + \"find\" - initiate search starting from DOCUMENT which must specify + a directory + nil - invoke the default OPERATION, or \"open\" if default is + not defined or unavailable + +DOCUMENT is typically the name of a document file or a URL, but can +also be a program executable to run, or a directory to open in the +Windows Explorer. + +If DOCUMENT is a program executable, the optional third arg PARAMETERS +can be a string containing command line parameters that will be passed +to the program; otherwise, PARAMETERS should be nil or unspecified. + +Optional fourth argument SHOW-FLAG can be used to control how the +application will be displayed when it is invoked. If SHOW-FLAG is nil +or unspecified, the application is displayed normally, otherwise it is +an integer representing a ShowWindow flag: + + 0 - start hidden + 1 - start normally + 3 - start maximized + 6 - start minimized */) + (Lisp_Object operation, Lisp_Object document, Lisp_Object parameters, Lisp_Object show_flag) +{ + Lisp_Object current_dir; + char *errstr; + + CHECK_STRING (document); + + /* Encode filename, current directory and parameters. */ + current_dir = ENCODE_FILE (BVAR (current_buffer, directory)); + document = ENCODE_FILE (document); + if (STRINGP (parameters)) + parameters = ENCODE_SYSTEM (parameters); + + if ((uintptr_t)ShellExecute (NULL,(STRINGP (operation) ? + SDATA (operation) : NULL), + SDATA (document), + (STRINGP (parameters) ? + SDATA (parameters) : NULL), + SDATA (current_dir), + (INTEGERP (show_flag) ? + XINT (show_flag) : SW_SHOWDEFAULT)) > 32) + return Qt; + errstr = w32_strerror (0); + /* The error string might be encoded in the locale's encoding. */ + if (!NILP (Vlocale_coding_system)) + { + Lisp_Object decoded = + code_convert_string_norecord (build_unibyte_string (errstr), + Vlocale_coding_system, 0); + errstr = SSDATA (decoded); + } + error ("ShellExecute failed: %s", errstr); +} + +/* Lookup virtual keycode from string representing the name of a + non-ascii keystroke into the corresponding virtual key, using + lispy_function_keys. */ +static int +lookup_vk_code (char *key) +{ + int i; + + for (i = 0; i < 256; i++) + if (lispy_function_keys[i] + && strcmp (lispy_function_keys[i], key) == 0) + return i; + + return -1; +} + +/* Convert a one-element vector style key sequence to a hot key + definition. */ +static Lisp_Object +w32_parse_hot_key (Lisp_Object key) +{ + /* Copied from Fdefine_key and store_in_keymap. */ + register Lisp_Object c; + int vk_code; + int lisp_modifiers; + int w32_modifiers; + struct gcpro gcpro1; + + CHECK_VECTOR (key); + + if (XFASTINT (Flength (key)) != 1) + return Qnil; + + GCPRO1 (key); + + c = Faref (key, make_number (0)); + + if (CONSP (c) && lucid_event_type_list_p (c)) + c = Fevent_convert_list (c); + + UNGCPRO; + + if (! INTEGERP (c) && ! SYMBOLP (c)) + error ("Key definition is invalid"); + + /* Work out the base key and the modifiers. */ + if (SYMBOLP (c)) + { + c = parse_modifiers (c); + lisp_modifiers = XINT (Fcar (Fcdr (c))); c = Fcar (c); if (!SYMBOLP (c)) emacs_abort ();
default-printer-name と、w32_strerror()の間に w32-memory-info を追加している。
Hunk #30 FAILED at 7211.
@@ -7211,6 +9007,87 @@ return build_string (pname_buf); } + +DEFUN ("w32-memory-info", Fw32_memory_info, Sw32_memory_info, + 0, 0, 0, doc: /* Retrieves information about the memory usage. +return value is a list of + +reserved_heap_size + +GlobalMemoryStatusEx: + MemoryLoad; + TotalPhys; + AvailPhys; + TotalPageFile; + AvailPageFile; + TotalVirtual; + AvailVirtual; + AvailExtendedVirtual; + +GetProcessMemoryInfo: + PageFaultCount; + PeakWorkingSetSize; + WorkingSetSize; + QuotaPeakPagedPoolUsage; + QuotaPagedPoolUsage; + QuotaPeakNonPagedPoolUsage; + QuotaNonPagedPoolUsage; + PagefileUsage; + PeakPagefileUsage; + PrivateUsage; (Xp or above) */) (void) +{ + PROCESS_MEMORY_COUNTERS_EX pmc = {sizeof(PROCESS_MEMORY_COUNTERS_EX)}; + MEMORYSTATUSEX msx = {sizeof(MEMORYSTATUSEX)}; + OSVERSIONINFO osi = {sizeof(OSVERSIONINFO)}; + + int os_version; + struct gcpro gcpro1, gcpro2; + Lisp_Object pm, sm; + + if (GetVersionEx(&osi) == 0) + return Qnil; + + os_version = (osi.dwMajorVersion << 8) | osi.dwMinorVersion ; + if (os_version < 0x501) + pmc.cb = sizeof(PROCESS_MEMORY_COUNTERS); + + if (GlobalMemoryStatusEx(&msx) == 0 || + GetProcessMemoryInfo(GetCurrentProcess(), + (PPROCESS_MEMORY_COUNTERS)&pmc, sizeof(pmc)) == 0) + return Qnil; + + GCPRO2(sm, pm); + + sm = Qnil; + sm = Fcons(make_fixnum_or_float(msx.ullAvailExtendedVirtual), sm); + sm = Fcons(make_fixnum_or_float(msx.ullAvailVirtual), sm); + sm = Fcons(make_fixnum_or_float(msx.ullTotalVirtual), sm); + sm = Fcons(make_fixnum_or_float(msx.ullAvailPageFile), sm); + sm = Fcons(make_fixnum_or_float(msx.ullTotalPageFile), sm); + sm = Fcons(make_fixnum_or_float(msx.ullAvailPhys), sm); + sm = Fcons(make_fixnum_or_float(msx.ullTotalPhys), sm); + sm = Fcons(make_fixnum_or_float(msx.dwMemoryLoad), sm); + + pm = Qnil; + if (os_version >= 0x501) + pm = Fcons(make_fixnum_or_float(pmc.PrivateUsage), pm); + pm = Fcons(make_fixnum_or_float(pmc.PeakPagefileUsage), pm); + pm = Fcons(make_fixnum_or_float(pmc.PagefileUsage), pm); + pm = Fcons(make_fixnum_or_float(pmc.QuotaNonPagedPoolUsage), pm); + pm = Fcons(make_fixnum_or_float(pmc.QuotaPeakNonPagedPoolUsage), pm); + pm = Fcons(make_fixnum_or_float(pmc.QuotaPagedPoolUsage), pm); + pm = Fcons(make_fixnum_or_float(pmc.QuotaPeakPagedPoolUsage), pm); + pm = Fcons(make_fixnum_or_float(pmc.WorkingSetSize), pm); + pm = Fcons(make_fixnum_or_float(pmc.PeakWorkingSetSize), pm); + pm = Fcons(make_fixnum_or_float(pmc.PageFaultCount), pm); + pm = Fcons(pm, Qnil); + + sm = Fcons(sm, pm); + + RETURN_UNGCPRO(Fcons(make_fixnum_or_float(reserved_heap_size), sm)); +} + + /* Equivalent of strerror for W32 error codes. */
Hunk #36 FAILED at 7966.
globals_of_w32fns() の中の USE_W32_IME 切り分け
USE_W32_CALL_LISP_THREAD と IME_UNICODE を参照した切り分け。
わっかりにくいなあ。。
@@ -7966,14 +9885,18 @@ set_ime_composition_window_fn = (ImmSetCompositionWindow_Proc) GetProcAddress (imm32_lib, "ImmSetCompositionWindow"); } +#endif /* USE_W32_IME */ + DEFVAR_INT ("w32-ansi-code-page", w32_ansi_code_page, doc: /* The ANSI code page used by the system. */); w32_ansi_code_page = GetACP (); +#if !defined(USE_W32_CALL_LISP_THREAD) || defined(IME_UNICODE) if (os_subtype == OS_NT) w32_unicode_gui = 1; else +#endif w32_unicode_gui = 0; /* MessageBox does not work without this when linked to comctl32.dll 6.0. */
emacs_abort()の TEXTマクロ
Hunk #37 FAILED at 7987.
@@ -7987,14 +9910,14 @@ { int button; button = MessageBox (NULL, - "A fatal error has occurred!\n\n" + TEXT("A fatal error has occurred!\n\n" "Would you like to attach a debugger?\n\n" "Select YES to debug, NO to abort Emacs" #if __GNUC__ "\n\n(type \"gdb -p <emacs-PID>\" and\n" "\"continue\" inside GDB before clicking YES.)" #endif - , "Emacs Abort Dialog", + ), TEXT("Emacs Abort Dialog"), MB_ICONEXCLAMATION | MB_TASKMODAL | MB_SETFOREGROUND | MB_YESNO); switch (button)
Hunk #38 FAILED at 8008.
USE_W32_CALL_LISP_THREAD 切り分け部分を最後に追加
@@ -8008,3 +9931,63 @@ break; } } + + +#ifdef USE_W32_CALL_LISP_THREAD +#ifdef _MSC_VER +#include <intrin.h> +#pragma intrinsic(_InterlockedCompareExchange, _InterlockedExchange) +#endif + +static long apc_mutex; +static HANDLE apc_mutex_ev; + +void w32_apc_mutex_init(void) +{ +#if 0 + apc_mutex = 0; + apc_mutex_ev = CreateEvent(NULL, FALSE, FALSE, NULL); +#endif +} + +void w32_apc_mutex_term(void) +{ +#if 0 + CloseHandle(apc_mutex_ev); +#endif +} + +void w32_apc_mutex_acquire(void) +{ +#if 0 + const DWORD tid = GetCurrentThreadId(); + const BOOL proc_msg = dwWindowsThreadId == tid; + DWORD locker, v; + deferred_msg dummy = {0}; + MSG msg; + dummy.completed = 1; + + while ((locker = + InterlockedCompareExchange(&apc_mutex, tid, 0)) != 0 + && locker != tid) + while ((v = proc_msg + ? MsgWaitForMultipleObjectsEx + (1, &apc_mutex_ev, INFINITE, + QS_ALLINPUT | QS_ALLPOSTMESSAGE, MWMO_ALERTABLE) + : WaitForSingleObjectEx(apc_mutex_ev, INFINITE, TRUE)) + != WAIT_OBJECT_0) + if (v == WAIT_OBJECT_0 + 1) + w32_msg_pump(&dummy); + else if (v != WAIT_IO_COMPLETION) + abort(); +#endif +} + +void w32_apc_mutex_release(void) +{ +#if 0 + InterlockedExchange(&apc_mutex, 0); + SetEvent(apc_mutex_ev); +#endif +} +#endif
patching file src/w32fns.c Hunk #2 succeeded at 69 (offset 3 lines). Hunk #3 succeeded at 91 (offset 3 lines). Hunk #4 succeeded at 108 (offset 3 lines). Hunk #5 succeeded at 137 (offset -1 lines). Hunk #6 FAILED at 233. Hunk #7 succeeded at 286 (offset 29 lines). Hunk #8 succeeded at 323 (offset 29 lines). Hunk #9 FAILED at 328. Hunk #10 succeeded at 427 (offset -11 lines). Hunk #11 succeeded at 1959 (offset 55 lines). Hunk #12 succeeded at 2064 with fuzz 1 (offset 43 lines). Hunk #13 succeeded at 2539 (offset 71 lines). Hunk #14 succeeded at 2569 (offset 71 lines). Hunk #15 succeeded at 2786 (offset 72 lines). Hunk #16 succeeded at 2927 (offset 72 lines). Hunk #17 succeeded at 3260 (offset 72 lines). Hunk #18 succeeded at 3297 (offset 72 lines). Hunk #19 succeeded at 3416 (offset 93 lines). Hunk #20 FAILED at 4100. Hunk #21 succeeded at 4479 (offset 140 lines). Hunk #22 succeeded at 4502 (offset 140 lines). Hunk #23 succeeded at 6609 (offset 361 lines). Hunk #24 succeeded at 6642 (offset 365 lines). Hunk #25 succeeded at 6685 (offset 376 lines). Hunk #26 FAILED at 6408. Hunk #27 succeeded at 6922 (offset 461 lines). Hunk #28 FAILED at 6589. Hunk #29 succeeded at 7785 (offset 693 lines). Hunk #30 FAILED at 7211. Hunk #31 succeeded at 8298 (offset 758 lines). Hunk #32 succeeded at 8315 (offset 756 lines). Hunk #33 succeeded at 8595 (offset 767 lines). Hunk #34 succeeded at 8659 with fuzz 2 (offset 768 lines). Hunk #35 succeeded at 8885 with fuzz 2 (offset 931 lines). Hunk #36 FAILED at 7966. Hunk #37 FAILED at 7987. Hunk #38 FAILED at 8008. 9 out of 38 hunks FAILED -- saving rejects to file src/w32fns.c.rej
fill_in_logfont のグローバル関数化。なんじゃあこりゃあ。。
patching file src/w32font.c Hunk #1 FAILED at 99. Hunk #2 FAILED at 1963. 2 out of 2 hunks FAILED -- saving rejects to file src/w32font.c.rej
OK
patching file src/w32font.h
OK
patching file src/w32heap.c
OK
patching file src/w32heap.h
OK
patching file src/w32inevt.h
patching file src/w32proc.c Hunk #1 FAILED at 41. Hunk #2 succeeded at 66 (offset 4 lines). Hunk #3 succeeded at 1715 (offset 150 lines). Hunk #4 succeeded at 1767 (offset 150 lines). Hunk #5 succeeded at 1795 (offset 150 lines). Hunk #6 succeeded at 1810 (offset 150 lines). Hunk #7 succeeded at 2097 (offset 165 lines). Hunk #8 succeeded at 2113 with fuzz 2 (offset 165 lines). Hunk #9 FAILED at 2866. Hunk #10 FAILED at 2884. Hunk #11 FAILED at 2898. 4 out of 11 hunks FAILED -- saving rejects to file src/w32proc.c.rej
patching file src/w32term.c Hunk #1 succeeded at 64 (offset 1 line). Hunk #2 FAILED at 110. Hunk #3 succeeded at 4910 with fuzz 2 (offset 57 lines). Hunk #4 succeeded at 5379 with fuzz 2 (offset 70 lines). Hunk #5 FAILED at 6562. Hunk #6 succeeded at 6673 (offset 55 lines). 2 out of 6 hunks FAILED -- saving rejects to file src/w32term.c.rej
patching file src/w32term.h Hunk #1 succeeded at 569 (offset -19 lines). Hunk #2 succeeded at 607 with fuzz 2 (offset -18 lines).
patching file src/w32xfns.c Hunk #1 succeeded at 178 (offset 1 line).
patching file src/window.c Hunk #1 succeeded at 132 with fuzz 2 (offset 1 line). Hunk #2 succeeded at 480 with fuzz 2 (offset 20 lines). Hunk #3 FAILED at 528. Hunk #4 succeeded at 3567 (offset 265 lines). Hunk #5 succeeded at 7256 (offset 559 lines). 1 out of 5 hunks FAILED -- saving rejects to file src/window.c.rej
patching file src/xdisp.c Hunk #1 FAILED at 11166. 1 out of 1 hunk FAILED -- saving rejects to file src/xdisp.c.rej