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