winex11: Don't create a win data structure for HWND_MESSAGE windows.
[wine] / dlls / winex11.drv / ime.c
1 /*
2  * The IME for interfacing with XIM
3  *
4  * Copyright 2008 CodeWeavers, Aric Stewart
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 /*
22  * Notes:
23  *  The normal flow for IMM/IME Processing is as follows.
24  * 1) The Keyboard Driver generates key messages which are first passed to
25  *    the IMM and then to IME via ImeProcessKey. If the IME returns 0  then
26  *    it does not want the key and the keyboard driver then generates the
27  *    WM_KEYUP/WM_KEYDOWN messages.  However if the IME is going to process the
28  *    key it returns non-zero.
29  * 2) If the IME is going to process the key then the IMM calls ImeToAsciiEx to
30  *    process the key.  the IME modifies the HIMC structure to reflect the
31  *    current state and generates any messages it needs the IMM to process.
32  * 3) IMM checks the messages and send them to the application in question. From
33  *    here the IMM level deals with if the application is IME aware or not.
34  *
35  *  This flow does not work well for the X11 driver and XIM.
36  *   (It works fine for Mac)
37  *  As such we will have to reroute step 1.  Instead the x11drv driver will
38  *  generate an XIM events and call directly into this IME implimenetaion.
39  *  As such we will have to use the alternative ImmGenerateMessage path to be
40  *  generate the messages that we want the IMM layer to send to the application.
41  */
42
43 #include "config.h"
44
45 #include <stdarg.h>
46 #include "windef.h"
47 #include "winbase.h"
48 #include "wingdi.h"
49 #include "winuser.h"
50 #include "winerror.h"
51 #include "wine/debug.h"
52 #include "imm.h"
53 #include "ddk/imm.h"
54 #include "winnls.h"
55 #include "x11drv.h"
56
57 WINE_DEFAULT_DEBUG_CHANNEL(imm);
58
59 #define FROM_X11 ((HIMC)0xcafe1337)
60
61 typedef struct _IMEPRIVATE {
62     BOOL bInComposition;
63     BOOL bInternalState;
64     HFONT textfont;
65     HWND hwndDefault;
66 } IMEPRIVATE, *LPIMEPRIVATE;
67
68 typedef struct _tagTRANSMSG {
69     UINT message;
70     WPARAM wParam;
71     LPARAM lParam;
72 } TRANSMSG, *LPTRANSMSG;
73
74 static const WCHAR UI_CLASS_NAME[] = {'W','i','n','e','X','1','1','I','M','E',0};
75
76 static HIMC *hSelectedFrom = NULL;
77 static INT  hSelectedCount = 0;
78
79 /* MSIME messages */
80 static UINT WM_MSIME_SERVICE;
81 static UINT WM_MSIME_RECONVERTOPTIONS;
82 static UINT WM_MSIME_MOUSE;
83 static UINT WM_MSIME_RECONVERTREQUEST;
84 static UINT WM_MSIME_RECONVERT;
85 static UINT WM_MSIME_QUERYPOSITION;
86 static UINT WM_MSIME_DOCUMENTFEED;
87
88 static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
89                                           LPARAM lParam);
90 static void UpdateDataInDefaultIMEWindow(HIMC hHIMC, HWND hwnd, BOOL showable);
91
92 static HIMC RealIMC(HIMC hIMC)
93 {
94     if (hIMC == FROM_X11)
95     {
96         INT i;
97         HWND wnd = GetFocus();
98         HIMC winHimc = ImmGetContext(wnd);
99         for (i = 0; i < hSelectedCount; i++)
100             if (winHimc == hSelectedFrom[i])
101                 return winHimc;
102         return NULL;
103     }
104     else
105         return hIMC;
106 }
107
108 static LPINPUTCONTEXT LockRealIMC(HIMC hIMC)
109 {
110     HIMC real_imc = RealIMC(hIMC);
111     if (real_imc)
112         return (LPINPUTCONTEXT)ImmLockIMC(real_imc);
113     else
114         return NULL;
115 }
116
117 static BOOL UnlockRealIMC(HIMC hIMC)
118 {
119     HIMC real_imc = RealIMC(hIMC);
120     if (real_imc)
121         return ImmUnlockIMC(real_imc);
122     else
123         return FALSE;
124 }
125
126 static void IME_RegisterClasses(void)
127 {
128     static int done;
129     WNDCLASSW wndClass;
130
131     if (done) return;
132     done = 1;
133
134     ZeroMemory(&wndClass, sizeof(WNDCLASSW));
135     wndClass.style = CS_GLOBALCLASS | CS_IME | CS_HREDRAW | CS_VREDRAW;
136     wndClass.lpfnWndProc = IME_WindowProc;
137     wndClass.cbClsExtra = 0;
138     wndClass.cbWndExtra = 2 * sizeof(LONG);
139     wndClass.hInstance = x11drv_module;
140     wndClass.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
141     wndClass.hIcon = LoadIconW(NULL, (LPWSTR)IDI_APPLICATION);
142     wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW +1);
143     wndClass.lpszMenuName   = 0;
144     wndClass.lpszClassName = UI_CLASS_NAME;
145
146     RegisterClassW(&wndClass);
147
148     WM_MSIME_SERVICE = RegisterWindowMessageA("MSIMEService");
149     WM_MSIME_RECONVERTOPTIONS = RegisterWindowMessageA("MSIMEReconvertOptions");
150     WM_MSIME_MOUSE = RegisterWindowMessageA("MSIMEMouseOperation");
151     WM_MSIME_RECONVERTREQUEST = RegisterWindowMessageA("MSIMEReconvertRequest");
152     WM_MSIME_RECONVERT = RegisterWindowMessageA("MSIMEReconvert");
153     WM_MSIME_QUERYPOSITION = RegisterWindowMessageA("MSIMEQueryPosition");
154     WM_MSIME_DOCUMENTFEED = RegisterWindowMessageA("MSIMEDocumentFeed");
155 }
156
157 void IME_UnregisterClasses(void)
158 {
159     UnregisterClassW(UI_CLASS_NAME, x11drv_module);
160 }
161
162 static HIMCC ImeCreateBlankCompStr(void)
163 {
164     HIMCC rc;
165     LPCOMPOSITIONSTRING ptr;
166     rc = ImmCreateIMCC(sizeof(COMPOSITIONSTRING));
167     ptr = (LPCOMPOSITIONSTRING)ImmLockIMCC(rc);
168     memset(ptr,0,sizeof(COMPOSITIONSTRING));
169     ptr->dwSize = sizeof(COMPOSITIONSTRING);
170     ImmUnlockIMCC(rc);
171     return rc;
172 }
173
174 static int updateField(DWORD origLen, DWORD origOffset, DWORD currentOffset,
175                        LPBYTE target, LPBYTE source, DWORD* lenParam,
176                        DWORD* offsetParam, BOOL wchars )
177 {
178      if (origLen > 0 && origOffset > 0)
179      {
180         int truelen = origLen;
181         if (wchars)
182             truelen *= sizeof(WCHAR);
183
184         memcpy(&target[currentOffset], &source[origOffset], truelen);
185
186         *lenParam = origLen;
187         *offsetParam = currentOffset;
188         currentOffset += truelen;
189      }
190      return currentOffset;
191 }
192
193 static HIMCC updateCompStr(HIMCC old, LPWSTR compstr, DWORD len)
194 {
195     /* we need to make sure the CompStr, CompClaus and CompAttr fields are all
196      * set and correct */
197     int needed_size;
198     HIMCC   rc;
199     LPBYTE newdata = NULL;
200     LPBYTE olddata = NULL;
201     LPCOMPOSITIONSTRING new_one;
202     LPCOMPOSITIONSTRING lpcs = NULL;
203     INT current_offset = 0;
204
205     TRACE("%s, %i\n",debugstr_wn(compstr,len),len);
206
207     if (old == NULL && compstr == NULL && len == 0)
208         return NULL;
209
210     if (old != NULL)
211     {
212         olddata = ImmLockIMCC(old);
213         lpcs = (LPCOMPOSITIONSTRING)olddata;
214     }
215
216     needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) +
217                   len + sizeof(DWORD) * 2;
218
219     if (lpcs != NULL)
220     {
221         needed_size += lpcs->dwCompReadAttrLen;
222         needed_size += lpcs->dwCompReadClauseLen;
223         needed_size += lpcs->dwCompReadStrLen * sizeof(DWORD);
224         needed_size += lpcs->dwResultReadClauseLen;
225         needed_size += lpcs->dwResultReadStrLen * sizeof(DWORD);
226         needed_size += lpcs->dwResultClauseLen;
227         needed_size += lpcs->dwResultStrLen * sizeof(DWORD);
228         needed_size += lpcs->dwPrivateSize;
229     }
230     rc = ImmCreateIMCC(needed_size);
231     newdata = ImmLockIMCC(rc);
232     new_one = (LPCOMPOSITIONSTRING)newdata;
233
234     new_one->dwSize = needed_size;
235     current_offset = sizeof(COMPOSITIONSTRING);
236     if (lpcs != NULL)
237     {
238         current_offset = updateField(lpcs->dwCompReadAttrLen,
239                                      lpcs->dwCompReadAttrOffset,
240                                      current_offset, newdata, olddata,
241                                      &new_one->dwCompReadAttrLen,
242                                      &new_one->dwCompReadAttrOffset, FALSE);
243
244         current_offset = updateField(lpcs->dwCompReadClauseLen,
245                                      lpcs->dwCompReadClauseOffset,
246                                      current_offset, newdata, olddata,
247                                      &new_one->dwCompReadClauseLen,
248                                      &new_one->dwCompReadClauseOffset, FALSE);
249
250         current_offset = updateField(lpcs->dwCompReadStrLen,
251                                      lpcs->dwCompReadStrOffset,
252                                      current_offset, newdata, olddata,
253                                      &new_one->dwCompReadStrLen,
254                                      &new_one->dwCompReadStrOffset, TRUE);
255
256         /* new CompAttr, CompClause, CompStr, dwCursorPos */
257         new_one->dwDeltaStart = 0;
258
259         current_offset = updateField(lpcs->dwResultReadClauseLen,
260                                      lpcs->dwResultReadClauseOffset,
261                                      current_offset, newdata, olddata,
262                                      &new_one->dwResultReadClauseLen,
263                                      &new_one->dwResultReadClauseOffset, FALSE);
264
265         current_offset = updateField(lpcs->dwResultReadStrLen,
266                                      lpcs->dwResultReadStrOffset,
267                                      current_offset, newdata, olddata,
268                                      &new_one->dwResultReadStrLen,
269                                      &new_one->dwResultReadStrOffset, TRUE);
270
271         current_offset = updateField(lpcs->dwResultClauseLen,
272                                      lpcs->dwResultClauseOffset,
273                                      current_offset, newdata, olddata,
274                                      &new_one->dwResultClauseLen,
275                                      &new_one->dwResultClauseOffset, FALSE);
276
277         current_offset = updateField(lpcs->dwResultStrLen,
278                                      lpcs->dwResultStrOffset,
279                                      current_offset, newdata, olddata,
280                                      &new_one->dwResultStrLen,
281                                      &new_one->dwResultStrOffset, TRUE);
282
283         current_offset = updateField(lpcs->dwPrivateSize,
284                                      lpcs->dwPrivateOffset,
285                                      current_offset, newdata, olddata,
286                                      &new_one->dwPrivateSize,
287                                      &new_one->dwPrivateOffset, FALSE);
288     }
289
290     /* set new data */
291     /* CompAttr */
292     new_one->dwCompAttrLen = len;
293     if (len > 0)
294     {
295         new_one->dwCompAttrOffset = current_offset;
296         memset(&newdata[current_offset],ATTR_INPUT,len);
297         current_offset += len;
298     }
299
300     /* CompClause */
301     if (len > 0)
302     {
303         new_one->dwCompClauseLen = sizeof(DWORD) * 2;
304         new_one->dwCompClauseOffset = current_offset;
305         *(DWORD*)(&newdata[current_offset]) = 0;
306         current_offset += sizeof(DWORD);
307         *(DWORD*)(&newdata[current_offset]) = len;
308         current_offset += sizeof(DWORD);
309     }
310
311     /* CompStr */
312     new_one->dwCompStrLen = len;
313     if (len > 0)
314     {
315         new_one->dwCompStrOffset = current_offset;
316         memcpy(&newdata[current_offset],compstr,len*sizeof(WCHAR));
317     }
318
319     /* CursorPos */
320     new_one->dwCursorPos = len;
321
322     ImmUnlockIMCC(rc);
323     if (lpcs)
324         ImmUnlockIMCC(old);
325
326     return rc;
327 }
328
329 static HIMCC updateResultStr(HIMCC old, LPWSTR resultstr, DWORD len)
330 {
331     /* we need to make sure the ResultStr and ResultClause fields are all
332      * set and correct */
333     int needed_size;
334     HIMCC   rc;
335     LPBYTE newdata = NULL;
336     LPBYTE olddata = NULL;
337     LPCOMPOSITIONSTRING new_one;
338     LPCOMPOSITIONSTRING lpcs = NULL;
339     INT current_offset = 0;
340
341     TRACE("%s, %i\n",debugstr_wn(resultstr,len),len);
342
343     if (old == NULL && resultstr == NULL && len == 0)
344         return NULL;
345
346     if (old != NULL)
347     {
348         olddata = ImmLockIMCC(old);
349         lpcs = (LPCOMPOSITIONSTRING)olddata;
350     }
351
352     needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) +
353                   sizeof(DWORD) * 2;
354
355     if (lpcs != NULL)
356     {
357         needed_size += lpcs->dwCompReadAttrLen;
358         needed_size += lpcs->dwCompReadClauseLen;
359         needed_size += lpcs->dwCompReadStrLen * sizeof(DWORD);
360         needed_size += lpcs->dwCompAttrLen;
361         needed_size += lpcs->dwCompClauseLen;
362         needed_size += lpcs->dwCompStrLen * sizeof(DWORD);
363         needed_size += lpcs->dwResultReadClauseLen;
364         needed_size += lpcs->dwResultReadStrLen * sizeof(DWORD);
365         needed_size += lpcs->dwPrivateSize;
366     }
367     rc = ImmCreateIMCC(needed_size);
368     newdata = ImmLockIMCC(rc);
369     new_one = (LPCOMPOSITIONSTRING)newdata;
370
371     new_one->dwSize = needed_size;
372     current_offset = sizeof(COMPOSITIONSTRING);
373     if (lpcs != NULL)
374     {
375         current_offset = updateField(lpcs->dwCompReadAttrLen,
376                                      lpcs->dwCompReadAttrOffset,
377                                      current_offset, newdata, olddata,
378                                      &new_one->dwCompReadAttrLen,
379                                      &new_one->dwCompReadAttrOffset, FALSE);
380
381         current_offset = updateField(lpcs->dwCompReadClauseLen,
382                                      lpcs->dwCompReadClauseOffset,
383                                      current_offset, newdata, olddata,
384                                      &new_one->dwCompReadClauseLen,
385                                      &new_one->dwCompReadClauseOffset, FALSE);
386
387         current_offset = updateField(lpcs->dwCompReadStrLen,
388                                      lpcs->dwCompReadStrOffset,
389                                      current_offset, newdata, olddata,
390                                      &new_one->dwCompReadStrLen,
391                                      &new_one->dwCompReadStrOffset, TRUE);
392
393         current_offset = updateField(lpcs->dwCompAttrLen,
394                                      lpcs->dwCompAttrOffset,
395                                      current_offset, newdata, olddata,
396                                      &new_one->dwCompAttrLen,
397                                      &new_one->dwCompAttrOffset, FALSE);
398
399         current_offset = updateField(lpcs->dwCompClauseLen,
400                                      lpcs->dwCompClauseOffset,
401                                      current_offset, newdata, olddata,
402                                      &new_one->dwCompClauseLen,
403                                      &new_one->dwCompClauseOffset, FALSE);
404
405         current_offset = updateField(lpcs->dwCompStrLen,
406                                      lpcs->dwCompStrOffset,
407                                      current_offset, newdata, olddata,
408                                      &new_one->dwCompStrLen,
409                                      &new_one->dwCompStrOffset, TRUE);
410
411         new_one->dwCursorPos = lpcs->dwCursorPos;
412         new_one->dwDeltaStart = 0;
413
414         current_offset = updateField(lpcs->dwResultReadClauseLen,
415                                      lpcs->dwResultReadClauseOffset,
416                                      current_offset, newdata, olddata,
417                                      &new_one->dwResultReadClauseLen,
418                                      &new_one->dwResultReadClauseOffset, FALSE);
419
420         current_offset = updateField(lpcs->dwResultReadStrLen,
421                                      lpcs->dwResultReadStrOffset,
422                                      current_offset, newdata, olddata,
423                                      &new_one->dwResultReadStrLen,
424                                      &new_one->dwResultReadStrOffset, TRUE);
425
426         /* new ResultClause , ResultStr */
427
428         current_offset = updateField(lpcs->dwPrivateSize,
429                                      lpcs->dwPrivateOffset,
430                                      current_offset, newdata, olddata,
431                                      &new_one->dwPrivateSize,
432                                      &new_one->dwPrivateOffset, FALSE);
433     }
434
435     /* set new data */
436     /* ResultClause */
437     if (len > 0)
438     {
439         new_one->dwResultClauseLen = sizeof(DWORD) * 2;
440         new_one->dwResultClauseOffset = current_offset;
441         *(DWORD*)(&newdata[current_offset]) = 0;
442         current_offset += sizeof(DWORD);
443         *(DWORD*)(&newdata[current_offset]) = len;
444         current_offset += sizeof(DWORD);
445     }
446
447     /* ResultStr */
448     new_one->dwResultStrLen = len;
449     if (len > 0)
450     {
451         new_one->dwResultStrOffset = current_offset;
452         memcpy(&newdata[current_offset],resultstr,len*sizeof(WCHAR));
453     }
454     ImmUnlockIMCC(rc);
455     if (lpcs)
456         ImmUnlockIMCC(old);
457
458     return rc;
459 }
460
461 static void GenerateIMEMessage(HIMC hIMC, UINT msg, WPARAM wParam,
462                                LPARAM lParam)
463 {
464     LPINPUTCONTEXT lpIMC;
465     LPTRANSMSG lpTransMsg;
466
467     lpIMC = LockRealIMC(hIMC);
468     if (lpIMC == NULL)
469         return;
470
471     lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + 1) *
472                                     sizeof(TRANSMSG));
473     if (!lpIMC->hMsgBuf)
474         return;
475
476     lpTransMsg = (LPTRANSMSG)ImmLockIMCC(lpIMC->hMsgBuf);
477     if (!lpTransMsg)
478         return;
479
480     lpTransMsg += lpIMC->dwNumMsgBuf;
481     lpTransMsg->message = msg;
482     lpTransMsg->wParam = wParam;
483     lpTransMsg->lParam = lParam;
484
485     ImmUnlockIMCC(lpIMC->hMsgBuf);
486     lpIMC->dwNumMsgBuf++;
487
488     ImmGenerateMessage(RealIMC(hIMC));
489     UnlockRealIMC(hIMC);
490 }
491
492 static void GenerateIMECHARMessages(HIMC hIMC, LPWSTR String, DWORD length)
493 {
494     LPINPUTCONTEXT lpIMC;
495     LPTRANSMSG lpTransMsg;
496     INT i;
497
498     if (length <= 0)
499         return;
500
501     lpIMC = LockRealIMC(hIMC);
502     if (lpIMC == NULL)
503         return;
504
505     lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf,
506                                   (lpIMC->dwNumMsgBuf + length) *
507                                     sizeof(TRANSMSG));
508     if (!lpIMC->hMsgBuf)
509         return;
510
511     lpTransMsg = (LPTRANSMSG)ImmLockIMCC(lpIMC->hMsgBuf);
512     if (!lpTransMsg)
513         return;
514
515     lpTransMsg += lpIMC->dwNumMsgBuf;
516     for (i = 0; i < length; i++)
517     {
518         lpTransMsg->message = WM_IME_CHAR;
519         lpTransMsg->wParam = String[i];
520         lpTransMsg->lParam = 1;
521         lpTransMsg ++;
522     }
523
524     ImmUnlockIMCC(lpIMC->hMsgBuf);
525     lpIMC->dwNumMsgBuf+=length;
526
527     ImmGenerateMessage(RealIMC(hIMC));
528     UnlockRealIMC(hIMC);
529 }
530
531 static BOOL IME_RemoveFromSelected(HIMC hIMC)
532 {
533     int i;
534     for (i = 0; i < hSelectedCount; i++)
535         if (hSelectedFrom[i] == hIMC)
536         {
537             if (i < hSelectedCount - 1)
538                 memmove(&hSelectedFrom[i], &hSelectedFrom[i+1], (hSelectedCount - i - 1)*sizeof(HIMC));
539             hSelectedCount --;
540             return TRUE;
541         }
542     return FALSE;
543 }
544
545 static void IME_AddToSelected(HIMC hIMC)
546 {
547     hSelectedCount++;
548     if (hSelectedFrom)
549         hSelectedFrom = HeapReAlloc(GetProcessHeap(), 0, hSelectedFrom, hSelectedCount*sizeof(HIMC));
550     else
551         hSelectedFrom = HeapAlloc(GetProcessHeap(), 0, sizeof(HIMC));
552     hSelectedFrom[hSelectedCount-1] = hIMC;
553 }
554
555 BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo, LPWSTR lpszUIClass,
556                        LPCWSTR lpszOption)
557 {
558     TRACE("\n");
559     IME_RegisterClasses();
560     lpIMEInfo->dwPrivateDataSize = sizeof (IMEPRIVATE);
561     lpIMEInfo->fdwProperty = IME_PROP_UNICODE | IME_PROP_AT_CARET;
562     lpIMEInfo->fdwConversionCaps = IME_CMODE_NATIVE;
563     lpIMEInfo->fdwSentenceCaps = IME_SMODE_AUTOMATIC;
564     lpIMEInfo->fdwUICaps = UI_CAP_2700;
565     /* Tell App we cannot accept ImeSetCompositionString calls */
566     lpIMEInfo->fdwSCSCaps = 0;
567     lpIMEInfo->fdwSelectCaps = SELECT_CAP_CONVERSION;
568
569     lstrcpyW(lpszUIClass,UI_CLASS_NAME);
570
571     return TRUE;
572 }
573
574 BOOL WINAPI ImeConfigure(HKL hKL,HWND hWnd, DWORD dwMode, LPVOID lpData)
575 {
576     FIXME("(%p, %p, %d, %p): stub\n", hKL, hWnd, dwMode, lpData);
577     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
578     return FALSE;
579 }
580
581 DWORD WINAPI ImeConversionList(HIMC hIMC, LPCWSTR lpSource,
582                 LPCANDIDATELIST lpCandList, DWORD dwBufLen, UINT uFlag)
583
584 {
585     FIXME("(%p, %s, %p, %d, %d): stub\n", hIMC, debugstr_w(lpSource),
586                                           lpCandList, dwBufLen, uFlag);
587     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
588     return 0;
589 }
590
591 BOOL WINAPI ImeDestroy(UINT uForce)
592 {
593     TRACE("\n");
594     HeapFree(GetProcessHeap(),0,hSelectedFrom);
595     hSelectedFrom = NULL;
596     hSelectedCount = 0;
597     return TRUE;
598 }
599
600 LRESULT WINAPI ImeEscape(HIMC hIMC, UINT uSubFunc, LPVOID lpData)
601 {
602     FIXME("(%p, %d, %p): stub\n", hIMC, uSubFunc, lpData);
603     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
604     return 0;
605 }
606
607 BOOL WINAPI ImeProcessKey(HIMC hIMC, UINT vKey, LPARAM lKeyData,
608                              CONST LPBYTE lpbKeyState)
609 {
610     /* See the comment at the head of this file */
611     TRACE("We do no processing via this route\n");
612     return FALSE;
613 }
614
615 BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect)
616 {
617     LPINPUTCONTEXT lpIMC;
618     TRACE("%p %s\n",hIMC,(fSelect)?"TRUE":"FALSE");
619
620     if (hIMC == FROM_X11)
621     {
622         ERR("ImeSelect should never be called from X11\n");
623         return FALSE;
624     }
625
626     if (!hIMC)
627         return TRUE;
628
629     /* not selected */
630     if (!fSelect)
631         return IME_RemoveFromSelected(hIMC);
632
633     IME_AddToSelected(hIMC);
634
635     /* Initialize our structures */
636     lpIMC = LockRealIMC(hIMC);
637     if (lpIMC != NULL)
638     {
639         LPIMEPRIVATE myPrivate;
640         myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
641         myPrivate->bInComposition = FALSE;
642         myPrivate->bInternalState = FALSE;
643         myPrivate->textfont = NULL;
644         myPrivate->hwndDefault = NULL;
645         ImmUnlockIMCC(lpIMC->hPrivate);
646         UnlockRealIMC(hIMC);
647     }
648
649     return TRUE;
650 }
651
652 BOOL WINAPI ImeSetActiveContext(HIMC hIMC,BOOL fFlag)
653 {
654     FIXME("(%p, %x): stub\n", hIMC, fFlag);
655     return TRUE;
656 }
657
658 UINT WINAPI ImeToAsciiEx (UINT uVKey, UINT uScanCode,
659                           CONST LPBYTE lpbKeyState, LPDWORD lpdwTransKey,
660                           UINT fuState, HIMC hIMC)
661 {
662     /* See the comment at the head of this file */
663     TRACE("We do no processing via this route\n");
664     return 0;
665 }
666
667 BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
668 {
669     BOOL bRet = FALSE;
670     LPINPUTCONTEXT lpIMC;
671
672     TRACE("%p %i %i %i\n",hIMC,dwAction,dwIndex,dwValue);
673
674     lpIMC = LockRealIMC(hIMC);
675     if (lpIMC == NULL)
676         return FALSE;
677
678     switch (dwAction)
679     {
680         case NI_OPENCANDIDATE: FIXME("NI_OPENCANDIDATE\n"); break;
681         case NI_CLOSECANDIDATE: FIXME("NI_CLOSECANDIDATE\n"); break;
682         case NI_SELECTCANDIDATESTR: FIXME("NI_SELECTCANDIDATESTR\n"); break;
683         case NI_CHANGECANDIDATELIST: FIXME("NI_CHANGECANDIDATELIST\n"); break;
684         case NI_SETCANDIDATE_PAGESTART: FIXME("NI_SETCANDIDATE_PAGESTART\n"); break;
685         case NI_SETCANDIDATE_PAGESIZE: FIXME("NI_SETCANDIDATE_PAGESIZE\n"); break;
686         case NI_CONTEXTUPDATED:
687             switch (dwValue)
688             {
689                 case IMC_SETCOMPOSITIONWINDOW: FIXME("IMC_SETCOMPOSITIONWINDOW\n"); break;
690                 case IMC_SETCONVERSIONMODE: FIXME("IMC_SETCONVERSIONMODE\n"); break;
691                 case IMC_SETSENTENCEMODE: FIXME("IMC_SETSENTENCEMODE\n"); break;
692                 case IMC_SETCANDIDATEPOS: FIXME("IMC_SETCANDIDATEPOS\n"); break;
693                 case IMC_SETCOMPOSITIONFONT:
694                     {
695                         LPIMEPRIVATE myPrivate;
696                         TRACE("IMC_SETCOMPOSITIONFONT\n");
697
698                         myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
699                         if (myPrivate->textfont)
700                         {
701                             DeleteObject(myPrivate->textfont);
702                             myPrivate->textfont = NULL;
703                         }
704                         myPrivate->textfont = CreateFontIndirectW(&lpIMC->lfFont.W);
705                         ImmUnlockIMCC(lpIMC->hPrivate);
706                     }
707                     break;
708                 case IMC_SETOPENSTATUS:
709                 {
710                     LPIMEPRIVATE myPrivate;
711                     TRACE("IMC_SETOPENSTATUS\n");
712
713                     myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
714                     if (lpIMC->fOpen != myPrivate->bInternalState &&
715                         myPrivate->bInComposition)
716                     {
717                         if(lpIMC->fOpen == FALSE)
718                         {
719                             X11DRV_ForceXIMReset(lpIMC->hWnd);
720                             GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION,0,0);
721                             myPrivate->bInComposition = FALSE;
722                         }
723                         else
724                         {
725                             GenerateIMEMessage(hIMC,WM_IME_STARTCOMPOSITION,0,0);
726                             GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, 0, 0);
727                         }
728                     }
729                     myPrivate->bInternalState = lpIMC->fOpen;
730                     bRet = TRUE;
731                 }
732                 break;
733                 default: FIXME("Unknown\n"); break;
734             }
735             break;
736         case NI_COMPOSITIONSTR:
737             switch (dwIndex)
738             {
739                 case CPS_COMPLETE:
740                 {
741                     HIMCC newCompStr;
742                     DWORD cplen = 0;
743                     LPWSTR cpstr;
744                     LPCOMPOSITIONSTRING cs = NULL;
745                     LPBYTE cdata = NULL;
746                     LPIMEPRIVATE myPrivate;
747
748                     TRACE("CPS_COMPLETE\n");
749
750                     /* clear existing result */
751                     newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0);
752
753                     ImmDestroyIMCC(lpIMC->hCompStr);
754                     lpIMC->hCompStr = newCompStr;
755
756                     if (lpIMC->hCompStr)
757                     {
758                         cdata = ImmLockIMCC(lpIMC->hCompStr);
759                         cs = (LPCOMPOSITIONSTRING)cdata;
760                         cplen = cs->dwCompStrLen;
761                         cpstr = (LPWSTR)&(cdata[cs->dwCompStrOffset]);
762                         ImmUnlockIMCC(lpIMC->hCompStr);
763                     }
764                     if (cplen > 0)
765                     {
766                         WCHAR param = cpstr[0];
767
768                         newCompStr = updateResultStr(lpIMC->hCompStr, cpstr, cplen);
769                         ImmDestroyIMCC(lpIMC->hCompStr);
770                         lpIMC->hCompStr = newCompStr;
771                         newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0);
772                         ImmDestroyIMCC(lpIMC->hCompStr);
773                         lpIMC->hCompStr = newCompStr;
774
775                         GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, 0,
776                                                   GCS_COMPSTR);
777
778                         GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, param,
779                                             GCS_RESULTSTR|GCS_RESULTCLAUSE);
780                     }
781
782                     GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION, 0, 0);
783
784                     myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
785                     myPrivate->bInComposition = FALSE;
786                     ImmUnlockIMCC(lpIMC->hPrivate);
787
788                     bRet = TRUE;
789                 }
790                 break;
791                 case CPS_CONVERT: FIXME("CPS_CONVERT\n"); break;
792                 case CPS_REVERT: FIXME("CPS_REVERT\n"); break;
793                 case CPS_CANCEL:
794                 {
795                     LPIMEPRIVATE myPrivate;
796
797                     TRACE("CPS_CANCEL\n");
798
799                     X11DRV_ForceXIMReset(lpIMC->hWnd);
800
801                     if (lpIMC->hCompStr)
802                         ImmDestroyIMCC(lpIMC->hCompStr);
803                     lpIMC->hCompStr = ImeCreateBlankCompStr();
804
805                     myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
806                     if (myPrivate->bInComposition)
807                     {
808                         GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0);
809                         myPrivate->bInComposition = FALSE;
810                     }
811                     ImmUnlockIMCC(lpIMC->hPrivate);
812                     bRet = TRUE;
813                 }
814                 break;
815                 default: FIXME("Unknown\n"); break;
816             }
817             break;
818         default: FIXME("Unknown Message\n"); break;
819     }
820
821     UnlockRealIMC(hIMC);
822     return bRet;
823 }
824
825 BOOL WINAPI ImeRegisterWord(LPCWSTR lpszReading, DWORD dwStyle,
826                             LPCWSTR lpszRegister)
827 {
828     FIXME("(%s, %d, %s): stub\n", debugstr_w(lpszReading), dwStyle,
829                                   debugstr_w(lpszRegister));
830     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
831     return FALSE;
832 }
833
834 BOOL WINAPI ImeUnregisterWord(LPCWSTR lpszReading, DWORD dwStyle,
835                               LPCWSTR lpszUnregister)
836 {
837     FIXME("(%s, %d, %s): stub\n", debugstr_w(lpszReading), dwStyle,
838                                   debugstr_w(lpszUnregister));
839     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
840     return FALSE;
841 }
842
843 UINT WINAPI ImeGetRegisterWordStyle(UINT nItem, LPSTYLEBUFW lpStyleBuf)
844 {
845     FIXME("(%d, %p): stub\n", nItem, lpStyleBuf);
846     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
847     return 0;
848 }
849
850 UINT WINAPI ImeEnumRegisterWord(REGISTERWORDENUMPROCW lpfnEnumProc,
851                                 LPCWSTR lpszReading, DWORD dwStyle,
852                                 LPCWSTR lpszRegister, LPVOID lpData)
853 {
854     FIXME("(%p, %s, %d, %s, %p): stub\n", lpfnEnumProc,
855             debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister),
856             lpData);
857     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
858     return 0;
859 }
860
861 BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp,
862                                     DWORD dwCompLen, LPCVOID lpRead,
863                                     DWORD dwReadLen)
864 {
865     LPINPUTCONTEXT lpIMC;
866     DWORD flags = 0;
867     WCHAR wParam  = 0;
868     LPIMEPRIVATE myPrivate;
869
870     TRACE("(%p, %d, %p, %d, %p, %d):\n",
871          hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
872
873
874     if (hIMC != FROM_X11)
875         FIXME("PROBLEM: This only sets the wine level string\n");
876
877     /*
878     * Explanation:
879     *  this sets the composition string in the imm32.dll level
880     *  of the composition buffer. we cannot manipulate the xim level
881     *  buffer, which means that once the xim level buffer changes again
882     *  any call to this function from the application will be lost
883     */
884
885     if (lpRead && dwReadLen)
886         FIXME("Reading string unimplemented\n");
887
888     lpIMC = LockRealIMC(hIMC);
889
890     if (lpIMC == NULL)
891         return FALSE;
892
893     myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
894
895     if (dwIndex == SCS_SETSTR)
896     {
897         HIMCC newCompStr;
898
899         if (!myPrivate->bInComposition)
900         {
901             GenerateIMEMessage(hIMC, WM_IME_STARTCOMPOSITION, 0, 0);
902             myPrivate->bInComposition = TRUE;
903         }
904
905         flags = GCS_COMPSTR;
906
907         if (dwCompLen && lpComp)
908         {
909             newCompStr = updateCompStr(lpIMC->hCompStr, (LPWSTR)lpComp, dwCompLen / sizeof(WCHAR));
910             ImmDestroyIMCC(lpIMC->hCompStr);
911             lpIMC->hCompStr = newCompStr;
912
913              wParam = ((const WCHAR*)lpComp)[0];
914              flags |= GCS_COMPCLAUSE | GCS_COMPATTR | GCS_DELTASTART;
915         }
916         else
917         {
918             newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0);
919             ImmDestroyIMCC(lpIMC->hCompStr);
920             lpIMC->hCompStr = newCompStr;
921         }
922     }
923
924     UpdateDataInDefaultIMEWindow(hIMC, myPrivate->hwndDefault,FALSE);
925
926     GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, wParam, flags);
927     ImmUnlockIMCC(lpIMC->hPrivate);
928     UnlockRealIMC(hIMC);
929
930     return TRUE;
931 }
932
933 DWORD WINAPI ImeGetImeMenuItems(HIMC hIMC,  DWORD dwFlags,  DWORD dwType,
934             LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu,
935             DWORD dwSize)
936 {
937     FIXME("(%p, %x %x %p %p %x): stub\n", hIMC, dwFlags, dwType,
938                                 lpImeParentMenu, lpImeMenu, dwSize);
939     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
940     return 0;
941 }
942
943 /* Interfaces to XIM and other parts of winex11drv */
944
945 void IME_SetOpenStatus(BOOL fOpen)
946 {
947     LPINPUTCONTEXT lpIMC;
948     LPIMEPRIVATE myPrivate;
949
950     lpIMC = LockRealIMC(FROM_X11);
951     if (lpIMC == NULL)
952         return;
953
954     myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
955
956     if (myPrivate->bInternalState && fOpen == FALSE)
957     {
958         ShowWindow(myPrivate->hwndDefault, SW_HIDE);
959         ImmDestroyIMCC(lpIMC->hCompStr);
960         lpIMC->hCompStr = ImeCreateBlankCompStr();
961     }
962
963     ImmUnlockIMCC(lpIMC->hPrivate);
964     UnlockRealIMC(FROM_X11);
965
966     if (myPrivate->bInComposition && fOpen == FALSE)
967     {
968         GenerateIMEMessage(FROM_X11, WM_IME_ENDCOMPOSITION, 0, 0);
969         myPrivate->bInComposition = FALSE;
970     }
971
972     if (!myPrivate->bInternalState && fOpen == TRUE)
973         ImmSetOpenStatus(RealIMC(FROM_X11), fOpen);
974 }
975
976 LRESULT IME_SendMessageToSelectedHWND(UINT msg, WPARAM wParam, LPARAM lParam)
977 {
978     LPINPUTCONTEXT lpIMC;
979     LRESULT rc = 0;
980
981     if (!hSelectedFrom)
982         return rc;
983
984     lpIMC = LockRealIMC(FROM_X11);
985     if (lpIMC)
986         rc = SendMessageW(lpIMC->hWnd,msg,wParam,lParam);
987
988     UnlockRealIMC(FROM_X11);
989     return rc;
990 }
991
992 INT IME_GetCursorPos(void)
993 {
994     LPINPUTCONTEXT lpIMC;
995     INT rc = 0;
996     LPCOMPOSITIONSTRING compstr;
997
998     if (!hSelectedFrom)
999         return rc;
1000
1001     lpIMC = LockRealIMC(FROM_X11);
1002     if (lpIMC)
1003     {
1004         compstr = (LPCOMPOSITIONSTRING)ImmLockIMCC(lpIMC->hCompStr);
1005         rc = compstr->dwCursorPos;
1006         ImmUnlockIMCC(lpIMC->hCompStr);
1007     }
1008     UnlockRealIMC(FROM_X11);
1009     return rc;
1010 }
1011
1012 void IME_SetCursorPos(DWORD pos)
1013 {
1014     LPINPUTCONTEXT lpIMC;
1015     LPCOMPOSITIONSTRING compstr;
1016
1017     if (!hSelectedFrom)
1018         return;
1019
1020     lpIMC = LockRealIMC(FROM_X11);
1021     if (!lpIMC)
1022         return;
1023
1024     compstr = (LPCOMPOSITIONSTRING)ImmLockIMCC(lpIMC->hCompStr);
1025     if (!compstr)
1026     {
1027         UnlockRealIMC(FROM_X11);
1028         return;
1029     }
1030
1031     compstr->dwCursorPos = pos;
1032     ImmUnlockIMCC(lpIMC->hCompStr);
1033     UnlockRealIMC(FROM_X11);
1034     GenerateIMEMessage(FROM_X11, WM_IME_COMPOSITION, pos, GCS_CURSORPOS);
1035     return;
1036 }
1037
1038 void IME_UpdateAssociation(HWND focus)
1039 {
1040     ImmGetContext(focus);
1041
1042     if (!focus || !hSelectedFrom)
1043         return;
1044
1045     ImmAssociateContext(focus,RealIMC(FROM_X11));
1046 }
1047
1048
1049 BOOL IME_SetCompositionString(DWORD dwIndex, LPCVOID lpComp, DWORD dwCompLen,
1050                               LPCVOID lpRead, DWORD dwReadLen)
1051 {
1052     return ImeSetCompositionString(FROM_X11, dwIndex, lpComp, dwCompLen,
1053                                     lpRead, dwReadLen);
1054 }
1055
1056 BOOL IME_NotifyIME(DWORD dwAction, DWORD dwIndex, DWORD dwValue)
1057 {
1058     return NotifyIME(FROM_X11, dwAction, dwIndex, dwValue);
1059 }
1060
1061 /*****
1062  * Internal functions to help with IME window management
1063  */
1064 static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd)
1065 {
1066     PAINTSTRUCT ps;
1067     RECT rect;
1068     HDC hdc;
1069     LPCOMPOSITIONSTRING compstr;
1070     LPBYTE compdata = NULL;
1071     HMONITOR monitor;
1072     MONITORINFO mon_info;
1073     INT offX=0, offY=0;
1074     LPINPUTCONTEXT lpIMC;
1075
1076     lpIMC = LockRealIMC(hIMC);
1077     if (lpIMC == NULL)
1078         return;
1079
1080     hdc = BeginPaint(hwnd,&ps);
1081
1082     GetClientRect(hwnd,&rect);
1083     FillRect(hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1));
1084
1085     compdata = ImmLockIMCC(lpIMC->hCompStr);
1086     compstr = (LPCOMPOSITIONSTRING)compdata;
1087
1088     if (compstr->dwCompStrLen && compstr->dwCompStrOffset)
1089     {
1090         SIZE size;
1091         POINT pt;
1092         HFONT oldfont = NULL;
1093         LPWSTR CompString;
1094         LPIMEPRIVATE myPrivate;
1095
1096         CompString = (LPWSTR)(compdata + compstr->dwCompStrOffset);
1097         myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
1098
1099         if (myPrivate->textfont)
1100             oldfont = SelectObject(hdc,myPrivate->textfont);
1101
1102         ImmUnlockIMCC(lpIMC->hPrivate);
1103
1104         GetTextExtentPoint32W(hdc, CompString, compstr->dwCompStrLen, &size);
1105         pt.x = size.cx;
1106         pt.y = size.cy;
1107         LPtoDP(hdc,&pt,1);
1108
1109         /*
1110          * How this works based on tests on windows:
1111          * CFS_POINT: then we start our window at the point and grow it as large
1112          *    as it needs to be for the string.
1113          * CFS_RECT:  we still use the ptCurrentPos as a starting point and our
1114          *    window is only as large as we need for the string, but we do not
1115          *    grow such that our window exceeds the given rect.  Wrapping if
1116          *    needed and possible.   If our ptCurrentPos is outside of our rect
1117          *    then no window is displayed.
1118          * CFS_FORCE_POSITION: appears to behave just like CFS_POINT
1119          *    maybe becase the default MSIME does not do any IME adjusting.
1120          */
1121         if (lpIMC->cfCompForm.dwStyle != CFS_DEFAULT)
1122         {
1123             POINT cpt = lpIMC->cfCompForm.ptCurrentPos;
1124             ClientToScreen(lpIMC->hWnd,&cpt);
1125             rect.left = cpt.x;
1126             rect.top = cpt.y;
1127             rect.right = rect.left + pt.x;
1128             rect.bottom = rect.top + pt.y;
1129             monitor = MonitorFromPoint(cpt, MONITOR_DEFAULTTOPRIMARY);
1130         }
1131         else /* CFS_DEFAULT */
1132         {
1133             /* Windows places the default IME window in the bottom left */
1134             HWND target = lpIMC->hWnd;
1135             if (!target) target = GetFocus();
1136
1137             GetWindowRect(target,&rect);
1138             rect.top = rect.bottom;
1139             rect.right = rect.left + pt.x + 20;
1140             rect.bottom = rect.top + pt.y + 20;
1141             offX=offY=10;
1142             monitor = MonitorFromWindow(target, MONITOR_DEFAULTTOPRIMARY);
1143         }
1144
1145         if (lpIMC->cfCompForm.dwStyle == CFS_RECT)
1146         {
1147             RECT client;
1148             client =lpIMC->cfCompForm.rcArea;
1149             MapWindowPoints( lpIMC->hWnd, 0, (POINT *)&client, 2 );
1150             IntersectRect(&rect,&rect,&client);
1151             /* TODO:  Wrap the input if needed */
1152         }
1153
1154         if (lpIMC->cfCompForm.dwStyle == CFS_DEFAULT)
1155         {
1156             /* make sure we are on the desktop */
1157             mon_info.cbSize = sizeof(mon_info);
1158             GetMonitorInfoW(monitor, &mon_info);
1159
1160             if (rect.bottom > mon_info.rcWork.bottom)
1161             {
1162                 int shift = rect.bottom - mon_info.rcWork.bottom;
1163                 rect.top -= shift;
1164                 rect.bottom -= shift;
1165             }
1166             if (rect.left < 0)
1167             {
1168                 rect.right -= rect.left;
1169                 rect.left = 0;
1170             }
1171             if (rect.right > mon_info.rcWork.right)
1172             {
1173                 int shift = rect.right - mon_info.rcWork.right;
1174                 rect.left -= shift;
1175                 rect.right -= shift;
1176             }
1177         }
1178
1179         SetWindowPos(hwnd, HWND_TOPMOST, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE);
1180
1181         TextOutW(hdc, offX,offY, CompString, compstr->dwCompStrLen);
1182
1183         if (oldfont)
1184             SelectObject(hdc,oldfont);
1185     }
1186
1187     ImmUnlockIMCC(lpIMC->hCompStr);
1188
1189     EndPaint(hwnd,&ps);
1190     UnlockRealIMC(hIMC);
1191 }
1192
1193 static void UpdateDataInDefaultIMEWindow(HIMC hIMC, HWND hwnd, BOOL showable)
1194 {
1195     LPCOMPOSITIONSTRING compstr;
1196     LPINPUTCONTEXT lpIMC;
1197
1198     lpIMC = LockRealIMC(hIMC);
1199     if (lpIMC == NULL)
1200         return;
1201
1202     if (lpIMC->hCompStr)
1203         compstr = ImmLockIMCC(lpIMC->hCompStr);
1204     else
1205         compstr = NULL;
1206
1207     if (compstr == NULL || compstr->dwCompStrLen == 0)
1208         ShowWindow(hwnd,SW_HIDE);
1209     else if (showable)
1210         ShowWindow(hwnd,SW_SHOWNOACTIVATE);
1211
1212     RedrawWindow(hwnd,NULL,NULL,RDW_ERASENOW|RDW_INVALIDATE);
1213
1214     if (compstr != NULL)
1215         ImmUnlockIMCC(lpIMC->hCompStr);
1216
1217     UnlockRealIMC(hIMC);
1218 }
1219
1220 static void DefaultIMEComposition(HIMC hIMC, HWND hwnd, LPARAM lParam)
1221 {
1222     TRACE("IME message WM_IME_COMPOSITION 0x%lx\n", lParam);
1223     if (lParam & GCS_RESULTSTR)
1224     {
1225         LPCOMPOSITIONSTRING compstr;
1226         LPBYTE compdata;
1227         LPWSTR ResultStr;
1228         HIMCC newCompStr;
1229         LPINPUTCONTEXT lpIMC;
1230
1231         lpIMC = LockRealIMC(hIMC);
1232         if (lpIMC == NULL)
1233             return;
1234
1235         TRACE("Posting result as IME_CHAR\n");
1236         compdata = ImmLockIMCC(lpIMC->hCompStr);
1237         compstr = (LPCOMPOSITIONSTRING)compdata;
1238         ResultStr = (LPWSTR)(compdata + compstr->dwResultStrOffset);
1239         GenerateIMECHARMessages(hIMC, ResultStr, compstr->dwResultStrLen);
1240         ImmUnlockIMCC(lpIMC->hCompStr);
1241
1242         /* clear the buffer */
1243         newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0);
1244         ImmDestroyIMCC(lpIMC->hCompStr);
1245         lpIMC->hCompStr = newCompStr;
1246         UnlockRealIMC(hIMC);
1247     }
1248     else
1249          UpdateDataInDefaultIMEWindow(hIMC,hwnd,TRUE);
1250 }
1251
1252 static void DefaultIMEStartComposition(HIMC hIMC, HWND hwnd )
1253 {
1254     LPINPUTCONTEXT lpIMC;
1255
1256     lpIMC = LockRealIMC(hIMC);
1257     if (lpIMC == NULL)
1258         return;
1259
1260     TRACE("IME message WM_IME_STARTCOMPOSITION\n");
1261     lpIMC->hWnd = GetFocus();
1262     ShowWindow(hwnd,SW_SHOWNOACTIVATE);
1263     UnlockRealIMC(hIMC);
1264 }
1265
1266 static LRESULT ImeHandleNotify(HIMC hIMC, HWND hwnd, UINT msg, WPARAM wParam,
1267                                LPARAM lParam)
1268 {
1269     switch (wParam)
1270     {
1271         case IMN_OPENSTATUSWINDOW:
1272             FIXME("WM_IME_NOTIFY:IMN_OPENSTATUSWINDOW\n");
1273             break;
1274         case IMN_CLOSESTATUSWINDOW:
1275             FIXME("WM_IME_NOTIFY:IMN_CLOSESTATUSWINDOW\n");
1276             break;
1277         case IMN_OPENCANDIDATE:
1278             FIXME("WM_IME_NOTIFY:IMN_OPENCANDIDATE\n");
1279             break;
1280         case IMN_CHANGECANDIDATE:
1281             FIXME("WM_IME_NOTIFY:IMN_CHANGECANDIDATE\n");
1282             break;
1283         case IMN_CLOSECANDIDATE:
1284             FIXME("WM_IME_NOTIFY:IMN_CLOSECANDIDATE\n");
1285             break;
1286         case IMN_SETCONVERSIONMODE:
1287             FIXME("WM_IME_NOTIFY:IMN_SETCONVERSIONMODE\n");
1288             break;
1289         case IMN_SETSENTENCEMODE:
1290             FIXME("WM_IME_NOTIFY:IMN_SETSENTENCEMODE\n");
1291             break;
1292         case IMN_SETOPENSTATUS:
1293             FIXME("WM_IME_NOTIFY:IMN_SETOPENSTATUS\n");
1294             break;
1295         case IMN_SETCANDIDATEPOS:
1296             FIXME("WM_IME_NOTIFY:IMN_SETCANDIDATEPOS\n");
1297             break;
1298         case IMN_SETCOMPOSITIONFONT:
1299             FIXME("WM_IME_NOTIFY:IMN_SETCOMPOSITIONFONT\n");
1300             break;
1301         case IMN_SETCOMPOSITIONWINDOW:
1302             FIXME("WM_IME_NOTIFY:IMN_SETCOMPOSITIONWINDOW\n");
1303             break;
1304         case IMN_GUIDELINE:
1305             FIXME("WM_IME_NOTIFY:IMN_GUIDELINE\n");
1306             break;
1307         case IMN_SETSTATUSWINDOWPOS:
1308             FIXME("WM_IME_NOTIFY:IMN_SETSTATUSWINDOWPOS\n");
1309             break;
1310         default:
1311             FIXME("WM_IME_NOTIFY:<Unknown 0x%lx>\n",wParam);
1312             break;
1313     }
1314     return 0;
1315 }
1316
1317 static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT msg, WPARAM wParam,
1318                                           LPARAM lParam)
1319 {
1320     LRESULT rc = 0;
1321     HIMC    hIMC;
1322
1323     TRACE("Incoming Message 0x%x  (0x%08lx, 0x%08lx)\n", msg, wParam, lParam);
1324
1325     /*
1326      * Each UI window contains the current Input Context.
1327      * This Input Context can be obtained by calling GetWindowLong
1328      * with IMMGWL_IMC when the UI window receives a WM_IME_xxx message.
1329      * The UI window can refer to this Input Context and handles the
1330      * messages.
1331      */
1332
1333     hIMC = (HIMC)GetWindowLongW(hwnd,IMMGWL_IMC);
1334     if (!hIMC)
1335         hIMC = RealIMC(FROM_X11);
1336
1337     /* if we have no hIMC there are many messages we cannot process */
1338     if (hIMC == NULL)
1339     {
1340         switch (msg) {
1341         case WM_IME_STARTCOMPOSITION:
1342         case WM_IME_ENDCOMPOSITION:
1343         case WM_IME_COMPOSITION:
1344         case WM_IME_NOTIFY:
1345         case WM_IME_CONTROL:
1346         case WM_IME_COMPOSITIONFULL:
1347         case WM_IME_SELECT:
1348         case WM_IME_CHAR:
1349             return 0L;
1350         default:
1351             break;
1352         }
1353     }
1354
1355     switch(msg)
1356     {
1357         case WM_CREATE:
1358         {
1359             LPIMEPRIVATE myPrivate;
1360             LPINPUTCONTEXT lpIMC;
1361
1362             SetWindowTextA(hwnd,"Wine Ime Active");
1363
1364             lpIMC = LockRealIMC(hIMC);
1365             if (lpIMC)
1366             {
1367                 myPrivate = (LPIMEPRIVATE)ImmLockIMCC(lpIMC->hPrivate);
1368                 myPrivate->hwndDefault = hwnd;
1369                 ImmUnlockIMCC(lpIMC->hPrivate);
1370             }
1371             UnlockRealIMC(hIMC);
1372
1373             return TRUE;
1374         }
1375         case WM_PAINT:
1376             PaintDefaultIMEWnd(hIMC, hwnd);
1377             return FALSE;
1378
1379         case WM_NCCREATE:
1380             return TRUE;
1381
1382         case WM_SETFOCUS:
1383             if (wParam)
1384                 SetFocus((HWND)wParam);
1385             else
1386                 FIXME("Received focus, should never have focus\n");
1387             break;
1388         case WM_IME_COMPOSITION:
1389             DefaultIMEComposition(hIMC, hwnd, lParam);
1390             break;
1391         case WM_IME_STARTCOMPOSITION:
1392             DefaultIMEStartComposition(hIMC, hwnd);
1393             break;
1394         case WM_IME_ENDCOMPOSITION:
1395             TRACE("IME message %s, 0x%lx, 0x%lx\n",
1396                     "WM_IME_ENDCOMPOSITION", wParam, lParam);
1397             ShowWindow(hwnd,SW_HIDE);
1398             break;
1399         case WM_IME_SELECT:
1400             TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_IME_SELECT", wParam, lParam);
1401             break;
1402         case WM_IME_CONTROL:
1403             TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_IME_CONTROL", wParam, lParam);
1404             rc = 1;
1405             break;
1406         case WM_IME_NOTIFY:
1407             rc = ImeHandleNotify(hIMC,hwnd,msg,wParam,lParam);
1408             break;
1409        default:
1410             TRACE("Non-standard message 0x%x\n",msg);
1411     }
1412     /* check the MSIME messages */
1413     if (msg == WM_MSIME_SERVICE)
1414     {
1415             TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_SERVICE", wParam, lParam);
1416             rc = FALSE;
1417     }
1418     else if (msg == WM_MSIME_RECONVERTOPTIONS)
1419     {
1420             TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_RECONVERTOPTIONS", wParam, lParam);
1421     }
1422     else if (msg == WM_MSIME_MOUSE)
1423     {
1424             TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_MOUSE", wParam, lParam);
1425     }
1426     else if (msg == WM_MSIME_RECONVERTREQUEST)
1427     {
1428             TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_RECONVERTREQUEST", wParam, lParam);
1429     }
1430     else if (msg == WM_MSIME_RECONVERT)
1431     {
1432             TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_RECONVERT", wParam, lParam);
1433     }
1434     else if (msg == WM_MSIME_QUERYPOSITION)
1435     {
1436             TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_QUERYPOSITION", wParam, lParam);
1437     }
1438     else if (msg == WM_MSIME_DOCUMENTFEED)
1439     {
1440             TRACE("IME message %s, 0x%lx, 0x%lx\n","WM_MSIME_DOCUMENTFEED", wParam, lParam);
1441     }
1442     /* DefWndProc if not an IME message */
1443     if (!rc && !((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
1444                       (msg >= WM_IME_SETCONTEXT && msg <= WM_IME_KEYUP)))
1445         rc = DefWindowProcW(hwnd,msg,wParam,lParam);
1446
1447     return rc;
1448 }