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 }