Change to the linux kernel coding style
[wmaker-crm.git] / WINGs / winputmethod.c
1
2 #include <X11/Xlib.h>
3
4 #include "WINGsP.h"
5
6 typedef struct W_IMContext {
7         XIM xim;
8         XIMStyle ximstyle;
9 } WMIMContext;
10
11 static void instantiateIM_cb(Display * display, XPointer client_data, XPointer call_data)
12 {
13         W_InitIM((W_Screen *) client_data);
14 }
15
16 static void destroyIM_cb(XIM xim, XPointer client_data, XPointer call_data)
17 {
18         W_Screen *scr = (W_Screen *) client_data;
19         W_View *target;
20
21         if (scr->imctx->xim != xim)
22                 return;
23
24         target = scr->rootView->childrenList;
25         while (target != NULL) {
26                 W_DestroyIC(target);
27                 target = target->nextSister;
28         }
29
30         wfree(scr->imctx);
31         scr->imctx = NULL;
32
33         XRegisterIMInstantiateCallback(scr->display, NULL, NULL, NULL, instantiateIM_cb, (XPointer) scr);
34 }
35
36 void W_InitIM(W_Screen * scr)
37 {
38         XIM xim;
39
40         if (scr->imctx)
41                 return;
42
43         xim = XOpenIM(scr->display, NULL, NULL, NULL);
44
45         if (xim) {
46                 XIMStyles *im_styles;
47                 XIMCallback cb;
48                 int i;
49
50                 scr->imctx = wmalloc(sizeof(WMIMContext));
51                 scr->imctx->xim = xim;
52
53                 cb.callback = destroyIM_cb;
54                 cb.client_data = (XPointer) scr;
55                 if (XSetIMValues(scr->imctx->xim, XNDestroyCallback, &cb, NULL))
56                         wwarning("could not add destroy callback for input method");
57                 XUnregisterIMInstantiateCallback(scr->display, NULL, NULL, NULL, instantiateIM_cb, (XPointer) scr);
58                 /* Get available input style */
59                 XGetIMValues(scr->imctx->xim, XNQueryInputStyle, &im_styles, NULL);
60
61                 scr->imctx->ximstyle = 0;
62
63                 for (i = 0; i < im_styles->count_styles && scr->imctx->ximstyle == 0; i++) {
64                         if ((im_styles->supported_styles[i] & XIMPreeditPosition) &&
65                             (im_styles->supported_styles[i] & XIMStatusNothing)) {
66                                 scr->imctx->ximstyle = XIMPreeditPosition | XIMStatusNothing;
67                         } else if ((im_styles->supported_styles[i] & XIMPreeditNothing) &&
68                                    (im_styles->supported_styles[i] & XIMStatusNothing)) {
69                                 scr->imctx->ximstyle = XIMPreeditNothing | XIMStatusNothing;
70                         }
71                 }
72                 XFree(im_styles);
73         } else {
74                 XRegisterIMInstantiateCallback(scr->display, NULL, NULL, NULL, instantiateIM_cb, (XPointer) scr);
75         }
76 }
77
78 void W_CreateIC(WMView * view)
79 {
80         WMScreen *scr = W_VIEW_SCREEN(view);
81         XVaNestedList preedit_attr = NULL;
82
83         if (view->xic || !view->flags.realized || !scr->imctx)
84                 return;
85
86         if (scr->imctx->ximstyle & XIMPreeditPosition) {
87                 XPoint spot;
88                 XRectangle rect;
89                 int ofs;
90
91                 ofs = (view->size.height - WMFontHeight(scr->normalFont)) / 2;
92
93                 rect.x = ofs;
94                 rect.y = ofs;
95                 rect.height = WMFontHeight(scr->normalFont);
96                 rect.width = view->size.width - ofs * 2;
97                 spot.x = rect.x;
98                 spot.y = rect.y + rect.height;
99
100                 // this really needs to be changed, but I don't know how yet -Dan
101                 // it used to be like this with fontsets, but no longer applies to xft
102                 preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &spot,
103                                                    XNArea, &rect, XNFontInfo, scr->normalFont->font, NULL);
104         }
105
106         view->xic = XCreateIC(scr->imctx->xim, XNInputStyle, scr->imctx->ximstyle,
107                               XNClientWindow, view->window,
108                               preedit_attr ? XNPreeditAttributes : NULL, preedit_attr, NULL);
109
110         if (preedit_attr)
111                 XFree(preedit_attr);
112
113         if (view->xic) {
114                 unsigned long fevent = 0;
115                 XGetICValues(view->xic, XNFilterEvents, &fevent, NULL);
116                 XSelectInput(scr->display, view->window,
117                              ButtonPressMask | ButtonReleaseMask | ExposureMask |
118                              KeyPressMask | FocusChangeMask | ButtonMotionMask | fevent);
119         }
120 }
121
122 void W_DestroyIC(WMView * view)
123 {
124         if (view->xic) {
125                 XDestroyIC(view->xic);
126                 view->xic = 0;
127         }
128 }
129
130 static void setPreeditArea(W_View * view)
131 {
132         WMScreen *scr = W_VIEW_SCREEN(view);
133         XVaNestedList preedit_attr = NULL;
134
135         if (view->xic && (scr->imctx->ximstyle & XIMPreeditPosition)) {
136                 XRectangle rect;
137                 int ofs;
138
139                 ofs = (view->size.height - WMFontHeight(scr->normalFont)) / 2;
140                 rect.x = ofs;
141                 rect.y = ofs;
142                 rect.height = WMFontHeight(scr->normalFont);
143                 rect.width = view->size.width - ofs * 2;
144
145                 preedit_attr = XVaCreateNestedList(0, XNArea, &rect, NULL);
146                 XSetICValues(view->xic, XNPreeditAttributes, preedit_attr, NULL);
147
148                 if (preedit_attr) {
149                         XFree(preedit_attr);
150                 }
151         }
152 }
153
154 void W_FocusIC(WMView * view)
155 {
156         WMScreen *scr = W_VIEW_SCREEN(view);
157
158         if (view->xic) {
159                 XSetICFocus(view->xic);
160                 XSetICValues(view->xic, XNFocusWindow, view->window, NULL);
161
162                 if (scr->imctx->ximstyle & XIMPreeditPosition) {
163                         setPreeditArea(view);
164                 }
165         }
166 }
167
168 void W_UnFocusIC(WMView * view)
169 {
170         if (view->xic) {
171                 XUnsetICFocus(view->xic);
172         }
173 }
174
175 void W_SetPreeditPositon(W_View * view, int x, int y)
176 {
177         WMScreen *scr = W_VIEW_SCREEN(view);
178         XVaNestedList preedit_attr = NULL;
179
180         if (view->xic && (scr->imctx->ximstyle & XIMPreeditPosition)) {
181                 XPoint spot;
182                 int ofs;
183
184                 ofs = (view->size.height - WMFontHeight(scr->normalFont)) / 2;
185                 spot.x = x;
186                 spot.y = y + view->size.height - ofs - 3;
187                 preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL);
188                 XSetICValues(view->xic, XNPreeditAttributes, preedit_attr, NULL);
189                 if (preedit_attr) {
190                         XFree(preedit_attr);
191                 }
192         }
193 }
194
195 int
196 W_LookupString(W_View * view, XKeyPressedEvent * event, char *buffer, int buflen, KeySym * keysym, Status * status)
197 {
198         WMScreen *scr = W_VIEW_SCREEN(view);
199
200         XSetInputFocus(scr->display, view->window, RevertToParent, CurrentTime);
201
202         if (view->xic) {
203 #ifdef X_HAVE_UTF8_STRING
204                 return Xutf8LookupString(view->xic, event, buffer, buflen, keysym, status);
205 #else
206                 return XLookupString(event, buffer, buflen, keysym, (XComposeStatus *) status);
207 #endif
208         } else {
209                 return XLookupString(event, buffer, buflen, keysym, (XComposeStatus *) status);
210         }
211 }