1 /** @file scim_x11_ic.cpp
2  * implementation of class X11ICManager.
3  */
4 
5 /*
6  * Smart Common Input Method
7  *
8  * Copyright (c) 2002-2005 James Su <suzhe@tsinghua.org.cn>
9  *
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this program; if not, write to the
23  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24  * Boston, MA  02111-1307  USA
25  *
26  * $Id: scim_x11_ic.cpp,v 1.19 2005/06/26 16:35:12 suzhe Exp $
27  *
28  */
29 
30 #include <X11/Xlib.h>
31 #include <X11/keysym.h>
32 #include <X11/Xutil.h>
33 #include "IMdkit/IMdkit.h"
34 #include "IMdkit/Xi18n.h"
35 
36 #include "scim_private.h"
37 #include "scim.h"
38 #include "scim_x11_ic.h"
39 
40 using namespace scim;
41 
42 static int
_is_attr(const char * attr,XICAttribute * attr_list)43 _is_attr (const char *attr, XICAttribute * attr_list)
44 {
45   return !strcmp (attr, attr_list->name);
46 }
47 
X11ICManager()48 X11ICManager::X11ICManager ()
49     : m_ic_list (NULL),
50       m_free_list (NULL)
51 {
52 }
53 
~X11ICManager()54 X11ICManager::~X11ICManager ()
55 {
56     X11IC *it;
57 
58     it = m_ic_list;
59     while (it != NULL) {
60         m_ic_list = it->next;
61         delete it;
62         it = m_ic_list;
63     }
64 
65     it = m_free_list;
66     while (it != NULL) {
67         m_free_list = it->next;
68         delete it;
69         it = m_free_list;
70     }
71 }
72 
73 X11IC *
new_ic()74 X11ICManager::new_ic ()
75 {
76     static CARD16 base_icid = 1;
77     X11IC *rec;
78 
79     if (m_free_list != NULL) {
80         rec = m_free_list;
81         m_free_list = m_free_list->next;
82     } else {
83         rec = new X11IC;
84     }
85 
86     if (base_icid == 0) base_icid = 1;
87 
88     rec->icid = base_icid ++;
89 
90     rec->next = m_ic_list;
91     m_ic_list = rec;
92     return rec;
93 }
94 
95 void
delete_ic(CARD16 icid)96 X11ICManager::delete_ic (CARD16 icid)
97 {
98     X11IC *rec, *last = NULL;
99 
100     for (rec = m_ic_list; rec != NULL; last = rec, rec = rec->next) {
101         if (rec->icid == icid) {
102             if (last != NULL)
103                 last->next = rec->next;
104             else
105                 m_ic_list = rec->next;
106 
107             rec->next = m_free_list;
108             m_free_list = rec;
109 
110             rec->siid = -1;
111             rec->icid = 0;
112             rec->connect_id = 0;
113             rec->client_win = 0;
114             rec->focus_win = 0;
115             rec->shared_siid = false;
116             rec->xims_on = false;
117             rec->encoding = String ();
118             rec->locale = String ();
119 
120             return;
121         }
122     }
123     return;
124 }
125 
126 String
get_connection_locale(CARD16 connect_id)127 X11ICManager::get_connection_locale (CARD16 connect_id)
128 {
129     ConnectionLocaleMap::iterator it =
130         m_connect_locales.find ((int)connect_id);
131 
132     if (it != m_connect_locales.end ())
133         return it->second;
134 
135     return String ();
136 }
137 
138 void
new_connection(IMOpenStruct * call_data)139 X11ICManager::new_connection (IMOpenStruct *call_data)
140 {
141     if (call_data == NULL) return;
142 
143     String locale = scim_validate_locale (String (call_data->lang.name));
144 
145     if (!locale.length ()) {
146         locale = String ("C");
147     }
148 
149     m_connect_locales [(int)call_data->connect_id] = locale;
150 }
151 
152 void
delete_connection(IMCloseStruct * call_data)153 X11ICManager::delete_connection (IMCloseStruct *call_data)
154 {
155     if (call_data == NULL) return;
156 
157     m_connect_locales.erase ((int)call_data->connect_id);
158 }
159 
160 uint32
create_ic(IMChangeICStruct * call_data,int siid)161 X11ICManager::create_ic (IMChangeICStruct *call_data, int siid)
162 {
163     X11IC * rec;
164 
165     rec = new_ic ();
166     if (rec == NULL) return 0;
167 
168     call_data->icid = rec->icid;
169     rec->connect_id = call_data->connect_id;
170     rec->siid = siid;
171     rec->shared_siid = false;
172     rec->xims_on = false;
173     rec->onspot_preedit_started = false;
174     rec->onspot_preedit_length = 0;
175     rec->onspot_caret = 0;
176     rec->focus_win = (Window) 0;
177     rec->client_win = (Window) 0;
178     rec->input_style = 0;
179     rec->pre_attr.spot_location.x = -1;
180     rec->pre_attr.spot_location.y = -1;
181 
182     return store_ic_values (rec, call_data);
183 }
184 
185 X11IC *
find_ic(CARD16 icid)186 X11ICManager::find_ic (CARD16 icid)
187 {
188     X11IC *rec = m_ic_list;
189     while (rec != NULL) {
190         if (rec->icid == icid)
191             return rec;
192         rec = rec->next;
193     }
194     return NULL;
195 }
196 
197 X11IC *
find_ic_by_siid(int siid)198 X11ICManager::find_ic_by_siid (int siid)
199 {
200     X11IC *rec = m_ic_list;
201     while (rec != NULL) {
202         if (rec->siid == siid)
203             return rec;
204         rec = rec->next;
205     }
206     return NULL;
207 }
208 
209 void
destroy_ic(IMDestroyICStruct * call_data)210 X11ICManager::destroy_ic (IMDestroyICStruct *call_data)
211 {
212     if (call_data == NULL) return;
213 
214     delete_ic (call_data->icid);
215 }
216 
217 uint32
store_ic_values(X11IC * rec,IMChangeICStruct * call_data)218 X11ICManager::store_ic_values (X11IC *rec, IMChangeICStruct *call_data)
219 {
220     XICAttribute *ic_attr = call_data->ic_attr;
221     XICAttribute *pre_attr = call_data->preedit_attr;
222     XICAttribute *sts_attr = call_data->status_attr;
223 
224     int i;
225     uint32 attrs = 0;
226 
227     // Set main attributes
228     for (i=0; i< (int) call_data->ic_attr_num; ++i, ++ic_attr) {
229         if (_is_attr (XNInputStyle, ic_attr)) {
230             rec->input_style = * (INT32 *) ic_attr->value;
231             attrs |= SCIM_X11_IC_INPUT_STYLE;
232         } else if (_is_attr (XNClientWindow, ic_attr)) {
233             rec->client_win = *(Window *) ic_attr->value;
234             attrs |= SCIM_X11_IC_CLIENT_WINDOW;
235         } else if (_is_attr (XNFocusWindow, ic_attr)) {
236             rec->focus_win = *(Window *) ic_attr->value;
237             attrs |= SCIM_X11_IC_FOCUS_WINDOW;
238         } else {
239             std::cerr << __FILE__ << "(" << __LINE__ << "):"
240                  <<"Unknown attr: " << ic_attr->name << std::endl;
241         }
242     }
243 
244     // Set preedit attributes
245     for (i = 0; i < (int) call_data->preedit_attr_num; ++i, ++pre_attr) {
246         if (_is_attr (XNArea, pre_attr)) {
247             rec->pre_attr.area = *(XRectangle *) pre_attr->value;
248             attrs |= SCIM_X11_IC_PRE_AREA;
249         } else if (_is_attr (XNAreaNeeded, pre_attr)) {
250             rec->pre_attr.area_needed = *(XRectangle *) pre_attr->value;
251             attrs |= SCIM_X11_IC_PRE_AREA_NEEDED;
252         } else if (_is_attr (XNSpotLocation, pre_attr)) {
253             rec->pre_attr.spot_location = *(XPoint *) pre_attr->value;
254             attrs |= SCIM_X11_IC_PRE_SPOT_LOCATION;
255         } else if (_is_attr (XNColormap, pre_attr)) {
256             rec->pre_attr.cmap = *(Colormap *) pre_attr->value;
257             attrs |= SCIM_X11_IC_PRE_COLORMAP;
258         } else if (_is_attr (XNStdColormap, pre_attr)) {
259             rec->pre_attr.cmap = *(Colormap *) pre_attr->value;
260             attrs |= SCIM_X11_IC_PRE_COLORMAP;
261         } else if (_is_attr (XNForeground, pre_attr)) {
262             rec->pre_attr.foreground = *(CARD32 *) pre_attr->value;
263             attrs |= SCIM_X11_IC_PRE_FOREGROUND;
264         } else if (_is_attr (XNBackground, pre_attr)) {
265             rec->pre_attr.background = *(CARD32 *) pre_attr->value;
266             attrs |= SCIM_X11_IC_PRE_BACKGROUND;
267         } else if (_is_attr (XNBackgroundPixmap, pre_attr)) {
268             rec->pre_attr.bg_pixmap = *(Pixmap *) pre_attr->value;
269             attrs |= SCIM_X11_IC_PRE_BG_PIXMAP;
270         } else if (_is_attr (XNFontSet, pre_attr)) {
271             rec->pre_attr.base_font = (char*) pre_attr->value;
272             attrs |= SCIM_X11_IC_PRE_FONTSET;
273         } else if (_is_attr (XNLineSpace, pre_attr)) {
274             rec->pre_attr.line_space = *(CARD32 *) pre_attr->value;
275             attrs |= SCIM_X11_IC_PRE_LINE_SPACE;
276         } else if (_is_attr (XNCursor, pre_attr)) {
277             rec->pre_attr.cursor = *(Cursor *) pre_attr->value;
278             attrs |= SCIM_X11_IC_PRE_CURSOR;
279         } else {
280             std::cerr << __FILE__ << "(" << __LINE__ << "):"
281                  <<"Unknown attr: " << pre_attr->name << std::endl;
282         }
283     }
284 
285     // Set status attributes
286     for (i = 0; i < (int) call_data->status_attr_num; ++i, ++sts_attr) {
287         if (_is_attr (XNArea, sts_attr)) {
288             rec->sts_attr.area = *(XRectangle *) sts_attr->value;
289             attrs |= SCIM_X11_IC_STS_AREA;
290         } else if (_is_attr (XNAreaNeeded, sts_attr)) {
291             rec->sts_attr.area_needed = *(XRectangle *) sts_attr->value;
292             attrs |= SCIM_X11_IC_STS_AREA_NEEDED;
293         } else if (_is_attr (XNColormap, sts_attr)) {
294             rec->sts_attr.cmap = *(Colormap *) sts_attr->value;
295             attrs |= SCIM_X11_IC_STS_COLORMAP;
296         } else if (_is_attr (XNStdColormap, sts_attr)) {
297             rec->sts_attr.cmap = *(Colormap *) sts_attr->value;
298             attrs |= SCIM_X11_IC_STS_COLORMAP;
299         } else if (_is_attr (XNForeground, sts_attr)) {
300             rec->sts_attr.foreground = *(CARD32 *) sts_attr->value;
301             attrs |= SCIM_X11_IC_STS_FOREGROUND;
302         } else if (_is_attr (XNBackground, sts_attr)) {
303             rec->sts_attr.background = *(CARD32 *) sts_attr->value;
304             attrs |= SCIM_X11_IC_STS_BACKGROUND;
305         } else if (_is_attr (XNBackgroundPixmap, sts_attr)) {
306             rec->sts_attr.bg_pixmap = *(Pixmap *) sts_attr->value;
307             attrs |= SCIM_X11_IC_STS_BG_PIXMAP;
308         } else if (_is_attr (XNFontSet, sts_attr)) {
309             rec->sts_attr.base_font = (char*) sts_attr->value;
310             attrs |= SCIM_X11_IC_STS_FONTSET;
311         } else if (_is_attr (XNLineSpace, sts_attr)) {
312             rec->sts_attr.line_space = *(CARD32 *) sts_attr->value;
313             attrs |= SCIM_X11_IC_STS_LINE_SPACE;
314         } else if (_is_attr (XNCursor, sts_attr)) {
315             rec->sts_attr.cursor = *(Cursor *) sts_attr->value;
316             attrs |= SCIM_X11_IC_STS_CURSOR;
317         } else {
318             std::cerr << __FILE__ << "(" << __LINE__ << "):"
319                  <<"Unknown attr: " << sts_attr->name << std::endl;
320         }
321     }
322 
323     String connect_locale =
324         get_connection_locale ((int)call_data->connect_id);
325 
326     if (connect_locale != rec->locale) {
327         rec->locale = connect_locale;
328         rec->encoding = scim_get_locale_encoding (connect_locale);
329         attrs |= SCIM_X11_IC_ENCODING;
330     }
331 
332     return attrs;
333 }
334 
335 uint32
set_ic_values(IMChangeICStruct * call_data)336 X11ICManager::set_ic_values (IMChangeICStruct *call_data)
337 {
338     if (call_data == NULL) return 0;
339 
340     X11IC *rec = find_ic (call_data->icid);
341 
342     if (rec == NULL) return 0;
343 
344     return store_ic_values (rec, call_data);
345 }
346 
347 uint32
get_ic_values(IMChangeICStruct * call_data)348 X11ICManager::get_ic_values (IMChangeICStruct *call_data)
349 {
350     if (call_data == NULL) return 0;
351 
352     XICAttribute *ic_attr = call_data->ic_attr;
353     XICAttribute *pre_attr = call_data->preedit_attr;
354     XICAttribute *sts_attr = call_data->status_attr;
355 
356     X11IC *rec = find_ic (call_data->icid);
357 
358     if (rec == NULL) return 0;
359 
360     int i;
361     uint32 attrs = 0;
362 
363     for (i = 0; i < (int) call_data->ic_attr_num; ++i, ++ic_attr) {
364         if (_is_attr (XNFilterEvents, ic_attr)) {
365             ic_attr->value = (void *) malloc (sizeof (CARD32));
366             *(CARD32 *) ic_attr->value = KeyPressMask | KeyReleaseMask;
367             ic_attr->value_length = sizeof (CARD32);
368             attrs |= SCIM_X11_IC_FILTER_EVENTS;
369         } else {
370             std::cerr << __FILE__ << "(" << __LINE__ << "):"
371                  <<"Unknown attr: " << ic_attr->name << std::endl;
372         }
373     }
374 
375     // preedit attributes
376     for (i = 0; i < (int) call_data->preedit_attr_num; ++i, ++pre_attr) {
377         if (_is_attr (XNArea, pre_attr)) {
378             pre_attr->value = (void *) malloc (sizeof (XRectangle));
379             *(XRectangle *) pre_attr->value = rec->pre_attr.area;
380             pre_attr->value_length = sizeof (XRectangle);
381             attrs |= SCIM_X11_IC_PRE_AREA;
382         } else if (_is_attr (XNAreaNeeded, pre_attr)) {
383             pre_attr->value = (void *) malloc (sizeof (XRectangle));
384             *(XRectangle *) pre_attr->value = rec->pre_attr.area_needed;
385             pre_attr->value_length = sizeof (XRectangle);
386             attrs |= SCIM_X11_IC_PRE_AREA_NEEDED;
387         } else if (_is_attr (XNSpotLocation, pre_attr)) {
388             pre_attr->value = (void *) malloc (sizeof (XPoint));
389             *(XPoint *) pre_attr->value = rec->pre_attr.spot_location;
390             pre_attr->value_length = sizeof (XPoint);
391             attrs |= SCIM_X11_IC_PRE_SPOT_LOCATION;
392         } else if (_is_attr (XNFontSet, pre_attr)) {
393             CARD16 base_len = (CARD16) rec->pre_attr.base_font.size ();
394             int total_len = sizeof (CARD16) + (CARD16) base_len;
395             char *p;
396             pre_attr->value = (void *) malloc (total_len);
397             p = (char *) pre_attr->value;
398             memmove (p, &base_len, sizeof (CARD16));
399             p += sizeof (CARD16);
400             strncpy (p, rec->pre_attr.base_font.c_str (), base_len);
401             pre_attr->value_length = total_len;
402             attrs |= SCIM_X11_IC_PRE_FONTSET;
403         } else if (_is_attr (XNForeground, pre_attr)) {
404             pre_attr->value = (void *) malloc (sizeof (CARD32));
405             *(CARD32 *) pre_attr->value = rec->pre_attr.foreground;
406             pre_attr->value_length = sizeof (CARD32);
407             attrs |= SCIM_X11_IC_PRE_FOREGROUND;
408         } else if (_is_attr (XNBackground, pre_attr)) {
409             pre_attr->value = (void *) malloc (sizeof (CARD32));
410             *(CARD32 *) pre_attr->value = rec->pre_attr.background;
411             pre_attr->value_length = sizeof (CARD32);
412             attrs |= SCIM_X11_IC_PRE_BACKGROUND;
413         } else if (_is_attr (XNLineSpace, pre_attr)) {
414             pre_attr->value = (void *) malloc (sizeof (CARD32));
415             *(CARD32 *) pre_attr->value = rec->pre_attr.line_space;
416             pre_attr->value_length = sizeof (CARD32);
417             attrs |= SCIM_X11_IC_PRE_LINE_SPACE;
418         } else {
419             std::cerr << __FILE__ << "(" << __LINE__ << "):"
420                  <<"Unknown attr: " << pre_attr->name << std::endl;
421         }
422     }
423 
424     // status attributes
425     for (i = 0; i < (int) call_data->status_attr_num; ++i, ++sts_attr) {
426         if (_is_attr (XNArea, sts_attr)) {
427             sts_attr->value = (void *) malloc (sizeof (XRectangle));
428             *(XRectangle *) sts_attr->value = rec->sts_attr.area;
429             sts_attr->value_length = sizeof (XRectangle);
430             attrs |= SCIM_X11_IC_STS_AREA;
431         } else if (_is_attr (XNAreaNeeded, sts_attr)) {
432             sts_attr->value = (void *) malloc (sizeof (XRectangle));
433             *(XRectangle *) sts_attr->value = rec->sts_attr.area_needed;
434             sts_attr->value_length = sizeof (XRectangle);
435             attrs |= SCIM_X11_IC_STS_AREA_NEEDED;
436         } else if (_is_attr (XNFontSet, sts_attr)) {
437             CARD16 base_len = (CARD16) rec->sts_attr.base_font.size ();
438             int total_len = sizeof (CARD16) + (CARD16) base_len;
439             char *p;
440             sts_attr->value = (void *) malloc (total_len);
441             p = (char *) sts_attr->value;
442             memmove (p, &base_len, sizeof (CARD16));
443             p += sizeof (CARD16);
444             strncpy (p, rec->sts_attr.base_font.c_str (), base_len);
445             sts_attr->value_length = total_len;
446             attrs |= SCIM_X11_IC_STS_FONTSET;
447         } else if (_is_attr (XNForeground, sts_attr)) {
448             sts_attr->value = (void *) malloc (sizeof (CARD32));
449             *(CARD32 *) sts_attr->value = rec->sts_attr.foreground;
450             sts_attr->value_length = sizeof (CARD32);
451             attrs |= SCIM_X11_IC_STS_FOREGROUND;
452         } else if (_is_attr (XNBackground, sts_attr)) {
453             sts_attr->value = (void *) malloc (sizeof (CARD32));
454             *(CARD32 *) sts_attr->value = rec->sts_attr.background;
455             sts_attr->value_length = sizeof (CARD32);
456             attrs |= SCIM_X11_IC_STS_BACKGROUND;
457         } else if (_is_attr (XNLineSpace, sts_attr)) {
458             sts_attr->value = (void *) malloc (sizeof (CARD32));
459             *(CARD32 *) sts_attr->value = rec->sts_attr.line_space;
460             sts_attr->value_length = sizeof (CARD32);
461             attrs |= SCIM_X11_IC_STS_LINE_SPACE;
462         } else {
463             std::cerr << __FILE__ << "(" << __LINE__ << "):"
464                  <<"Unknown attr: " << sts_attr->name << std::endl;
465         }
466     }
467 
468     return attrs;
469 }
470 
471 /*
472 vi:ts=4:nowrap:expandtab
473 */
474