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