Tizen 2.1 base
[platform/core/uifw/ise-engine-sunpinyin.git] / wrapper / xim / ic.c
1 /*
2  * Copyright (c) 2010 Mike Qin <mikeandmore@gmail.com>
3  *
4  * The contents of this file are subject to the terms of either the GNU Lesser
5  * General Public License Version 2.1 only ("LGPL") or the Common Development and
6  * Distribution License ("CDDL")(collectively, the "License"). You may not use this
7  * file except in compliance with the License. You can obtain a copy of the CDDL at
8  * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
9  * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
10  * specific language governing permissions and limitations under the License. When
11  * distributing the software, include this License Header Notice in each file and
12  * include the full text of the License in the License file as well as the
13  * following notice:
14  *
15  * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
16  * (CDDL)
17  * For Covered Software in this distribution, this License shall be governed by the
18  * laws of the State of California (excluding conflict-of-law provisions).
19  * Any litigation relating to this License shall be subject to the jurisdiction of
20  * the Federal Courts of the Northern District of California and the state courts
21  * of the State of California, with venue lying in Santa Clara County, California.
22  *
23  * Contributor(s):
24  *
25  * If you wish your version of this file to be governed by only the CDDL or only
26  * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
27  * include this software in this distribution under the [CDDL or LGPL Version 2.1]
28  * license." If you don't indicate a single choice of license, a recipient has the
29  * option to distribute your version of this file under either the CDDL or the LGPL
30  * Version 2.1, or to extend the choice of license to its licensees as provided
31  * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
32  * Version 2 license, then the option applies only if the new code is made subject
33  * to such option by the copyright holder.
34  */
35
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <unistd.h>
39
40 #include <X11/Xlib.h>
41 #include <X11/Xos.h>
42 #include <X11/Xfuncs.h>
43 #include <X11/Xutil.h>
44 #include <X11/Xatom.h>
45
46 #include "common.h"
47 #include "settings.h"
48 #include "ic.h"
49 #include "xmisc.h"
50 #include "xim.h"
51
52 static IC* icmaps[MAX_IC_NUM];
53 static IC ics[MAX_IC_NUM];
54
55 static size_t free_stack_sz = 0;
56 static IC* free_stack[MAX_IC_NUM];
57
58 static IC* current_ic;
59
60 // check if this ic is available
61 static int
62 __find_application_pid(Window w)
63 {
64     if (w == DefaultRootWindow(dpy))
65         return 0;
66
67     Atom actual_type;
68     int actual_format;
69     unsigned long nitems;
70     unsigned long bytes;
71     unsigned char* prop;
72     int status = XGetWindowProperty(
73         dpy, w, XInternAtom(dpy, "_NET_WM_PID", True), 0,
74         1024L, False, AnyPropertyType, &actual_type, &actual_format, &nitems,
75         &bytes, (unsigned char**) &prop);
76     if (status != 0) {
77         if (status == BadRequest)
78             return 0;
79         return -1;
80     }
81     if (!prop) {
82         Window parent;
83         Window root;
84         Window* children = NULL;
85         unsigned int sz = 0;
86         status = XQueryTree(dpy, w, &root, &parent, &children, &sz);
87         if (status != 0) {
88             if (status == BadRequest)
89                 return 0;
90             return -1;
91         }
92         if (children)
93             XFree(children);
94         return __find_application_pid(parent);
95     } else {
96         // TODO: is this portable?
97         return prop[1] * 256 + prop[0];
98     }
99 }
100
101 static bool
102 __ic_available(IC* ic)
103 {
104     int pid = __find_application_pid(ic->client_window);
105     if (pid == -1)
106         return false;
107     if (pid == 0)
108         return true;
109     // verify if a process is running
110     char path[256];
111     snprintf(path, 255, "/proc/%d", pid);
112     struct stat buf;
113     if (stat(path, &buf) != 0) {
114         LOG("GC can't catch the process %d", pid);
115         return false;
116     }
117     if (!S_ISDIR(buf.st_mode)) {
118         LOG("GC can't catch the process %d", pid);
119         return false;
120     }
121     return true;
122 }
123
124 static void
125 __scan_all_ic()
126 {
127     int i = 0;
128     for (i = 0; i < MAX_IC_NUM; i++) {
129         IC* ic = icmaps[i];
130         if (ic == NULL)
131             continue;
132
133         if (__ic_available(ic) == false) {
134             LOG("GC detected garbage %d", ic->icid);
135             icmgr_destroy_ic(i);
136         }
137     }
138 }
139
140 static void
141 __reset_ic(IC* ic)
142 {
143     int id = ic->icid;
144     memset(ic, 0, sizeof(IC));
145     ic->icid = id;
146     ic->is_chn_punc = true;
147 }
148
149 void
150 icmgr_init(void)
151 {
152     memset(ics, 0, sizeof(IC) * MAX_IC_NUM);
153     int i;
154     for (i = 0; i < MAX_IC_NUM; i++) {
155         ics[i].icid = i;
156         __reset_ic(&ics[i]);
157
158         free_stack[free_stack_sz] = &ics[i];
159         free_stack_sz++;
160     }
161     current_ic = NULL;
162
163     icmgr_ui_init();
164 }
165
166 void
167 icmgr_finalize(void)
168 {
169     memset(icmaps, 0, sizeof(IC*) * MAX_IC_NUM);
170     current_ic = NULL;
171 }
172
173
174 IC*
175 icmgr_create_ic(int connect_id)
176 {
177     static int created_cnt = 0;
178
179     created_cnt++;
180     if (created_cnt == GC_THRESHOLD || free_stack_sz < MAX_IC_NUM / 3) {
181         __scan_all_ic();
182         created_cnt = 0;
183     }
184
185     if (free_stack_sz == 0) {
186         LOG("Error free stack empty!!");
187         return NULL;
188     }
189
190     free_stack_sz--;
191     IC* ic = free_stack[free_stack_sz];
192
193     icmaps[ic->icid] = ic;
194     __reset_ic(ic);
195
196     /* icmgr_set_current(ic->icid); */
197
198     ic->connect_id = connect_id;
199
200     /* current_ic = ic; */
201     return ic;
202 }
203
204 void
205 icmgr_destroy_ic(int icid)
206 {
207     IC* ic = icmaps[icid];
208     if (ic == NULL)
209         return;
210
211     memset(ic, 0, sizeof(IC));
212     ic->icid = icid;
213
214     icmaps[icid] = NULL;
215
216     // return to free stack
217     free_stack[free_stack_sz] = ic;
218     free_stack_sz++;
219
220     current_ic = NULL;
221 }
222
223 bool
224 icmgr_set_current(int icid)
225 {
226     IC* ic = icmaps[icid];
227     if (ic == NULL)
228         return false;
229     current_ic = ic;
230     return true;
231 }
232
233 IC*
234 icmgr_get_current(void)
235 {
236     return current_ic;
237 }
238
239 void
240 icmgr_toggle_english(void)
241 {
242     if (current_ic) {
243         current_ic->is_english = !current_ic->is_english;
244     }
245 }
246
247 void
248 icmgr_toggle_full(void)
249 {
250     if (current_ic) {
251         current_ic->is_full = !current_ic->is_full;
252     }
253 }
254
255 void
256 icmgr_toggle_punc(void)
257 {
258     if (current_ic) {
259         current_ic->is_chn_punc = !current_ic->is_chn_punc;
260     }
261 }
262
263 IC*
264 icmgr_get(int icid)
265 {
266     return icmaps[icid];
267 }
268
269 void
270 icmgr_clear_current(void)
271 {
272     current_ic = NULL;
273 }
274
275 void
276 icmgr_refresh(void)
277 {
278     if (current_ic == NULL) {
279         icmgr_ui_refresh();
280         return;
281     }
282
283     /* refresh preedit */
284     if (current_ic->is_enabled) {
285         if (current_ic->is_english && preedit_status())
286             preedit_pause();
287         else if (!current_ic->is_english && !preedit_status())
288             preedit_go_on();
289
290         preedit_set_full(current_ic->is_full);
291         preedit_set_chinese_punc(current_ic->is_chn_punc);
292     } else {
293         preedit_pause();
294     }
295     icmgr_ui_refresh();
296 }
297
298 extern IC_UI icmgr_gtk;
299 extern IC_UI icmgr_skin;
300
301 static IC_UI* current_icmgr_ui = NULL;
302
303 static void
304 init_front_end()
305 {
306     varchar skin_name;
307     settings_get(SKIN_NAME, skin_name);
308     if (strcmp(skin_name, "classic") == 0) {
309         current_icmgr_ui = &icmgr_gtk;
310     } else {
311         current_icmgr_ui = &icmgr_skin;
312     }
313
314     if (!current_icmgr_ui->init(skin_name)) {
315         fprintf(stderr, "Error init front end!\n");
316         exit(-1);
317     }
318 }
319
320 void
321 icmgr_ui_init(void)
322 {
323     ui_tray_init();
324     init_front_end();
325 }
326
327 void
328 icmgr_ui_refresh(void)
329 {
330     ui_tray_refresh();
331     if (current_icmgr_ui != NULL) {
332         varchar skin_name;
333         settings_get(SKIN_NAME, skin_name);
334         if (strcmp(skin_name, current_icmgr_ui->get_name()) != 0) {
335             current_icmgr_ui->dispose();
336             init_front_end();
337         }
338         current_icmgr_ui->refresh();
339     } else {
340         init_front_end();
341     }
342 }
343