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