1 #ifndef lint
2 static char *rcsid = "$Id: imic.c,v 1.12 2002/01/24 09:07:20 ishisone Exp $";
3 #endif
4 /*
5  * Copyright (c) 1994  Software Research Associates, Inc.
6  *
7  * Permission to use, copy, modify, and distribute this software and its
8  * documentation for any purpose and without fee is hereby granted, provided
9  * that the above copyright notice appear in all copies and that both that
10  * copyright notice and this permission notice appear in supporting
11  * documentation, and that the name of Software Research Associates not be
12  * used in advertising or publicity pertaining to distribution of the
13  * software without specific, written prior permission.  Software Research
14  * Associates makes no representations about the suitability of this software
15  * for any purpose.  It is provided "as is" without express or implied
16  * warranty.
17  *
18  * Author:  Makoto Ishisone, Software Research Associates, Inc., Japan
19  */
20 
21 #include "im.h"
22 
23 #define IMHASHVAL(imp)	((imp)->id % IM_HASH_SIZE)
24 #define ICHASHVAL(icp)	((icp)->id % IC_HASH_SIZE)
25 
26 static IMIM *id2IM _Pt_((IMConnection *conn, unsigned int id));
27 static IMIC *id2IC _Pt_((IMIM *imp, unsigned int id));
28 static unsigned int newIMID _Pt_((IMConnection *conn));
29 static unsigned int newICID _Pt_((IMIM *imp));
30 static void registerIM _Pt_((IMIM *imp));
31 static void registerIC _Pt_((IMIC *icp));
32 static int unregisterIM _Pt_((IMIM *imp));
33 static int unregisterIC _Pt_((IMIC *icp));
34 static int removeIM _Pt_((IMIM *imp));
35 static int removeIC _Pt_((IMIC *icp));
36 
37 /*- id2IM: input-method ID to IM converter -*/
38 static IMIM *
id2IM(conn,id)39 id2IM(conn, id)
40 IMConnection *conn;
41 unsigned int id;
42 {
43     IMIM **imHash = IMIMHash(conn->proto_widget);
44     IMIM *imp;
45 
46     imp = imHash[id % IM_HASH_SIZE];
47     while (imp != NULL) {
48 	if (imp->id == id) return imp;
49 	imp = imp->hash_next;
50     }
51     return NULL;
52 }
53 
54 /*- id2IC: input-context ID to IC converter -*/
55 static IMIC *
id2IC(imp,id)56 id2IC(imp, id)
57 IMIM *imp;
58 unsigned int id;
59 {
60     IMIC **icHash = IMICHash(imp->connection->proto_widget);
61     IMIC *icp;
62 
63     icp = icHash[id % IC_HASH_SIZE];
64     while (icp != NULL) {
65 	if (icp->id == id) return icp;
66 	icp = icp->hash_next;
67     }
68     return NULL;
69 }
70 
71 /*- newIMID: return unused input-method ID -*/
72 static unsigned int
newIMID(conn)73 newIMID(conn)
74 IMConnection *conn;
75 {
76     Widget w = conn->proto_widget;
77     unsigned int id, id_start;
78 
79     id = id_start = IMNextIMID(w);
80     do {
81 	if (id2IM(conn, id) == NULL) return id;	/* unused ID */
82     } while ((id = IMNextIMID(w)) != id_start);
83     return 0;
84 }
85 
86 /*- newICID: return unused input-context ID -*/
87 static unsigned int
newICID(imp)88 newICID(imp)
89 IMIM *imp;
90 {
91     Widget w = imp->connection->proto_widget;
92     unsigned int id, id_start;
93 
94     id = id_start = IMNextICID(w);
95     do {
96 	if (id2IC(imp, id) == NULL) return id;	/* unused ID */
97     } while ((id = IMNextICID(w)) != id_start);
98     return 0;
99 }
100 
101 /*- registerIM: register IM to hash table -*/
102 static void
registerIM(imp)103 registerIM(imp)
104 IMIM *imp;
105 {
106     IMIM **imHash = IMIMHash(imp->connection->proto_widget);
107 
108     imp->hash_next = imHash[IMHASHVAL(imp)];
109     imHash[IMHASHVAL(imp)] = imp;
110 }
111 
112 /*- registerIC: register IC to hash table -*/
113 static void
registerIC(icp)114 registerIC(icp)
115 IMIC *icp;
116 {
117     IMIC **icHash = IMICHash(icp->im->connection->proto_widget);
118 
119     icp->hash_next = icHash[ICHASHVAL(icp)];
120     icHash[ICHASHVAL(icp)] = icp;
121 }
122 
123 /*- unregisterIM: remove IM from hash table -*/
124 static int
unregisterIM(imp)125 unregisterIM(imp)
126 IMIM *imp;
127 {
128     IMIM **imHash = IMIMHash(imp->connection->proto_widget);
129     IMIM *p, *q;
130 
131     p = imHash[IMHASHVAL(imp)];
132     q = NULL;
133 
134     while (p != NULL && p != imp) {
135 	q = p;
136 	p = p->hash_next;
137     }
138     if (p == NULL) return 0;
139 
140     if (q != NULL) {
141 	q->hash_next = p->hash_next;
142     } else {
143 	imHash[IMHASHVAL(imp)] = p->hash_next;
144     }
145     return 1;
146 }
147 
148 /*- unregisterIC: remove IC from hash table -*/
149 static int
unregisterIC(icp)150 unregisterIC(icp)
151 IMIC *icp;
152 {
153     IMIC **icHash = IMICHash(icp->im->connection->proto_widget);
154     IMIC *p, *q;
155 
156     p = icHash[ICHASHVAL(icp)];
157     q = NULL;
158 
159     while (p != NULL && p != icp) {
160 	q = p;
161 	p = p->hash_next;
162     }
163     if (p == NULL) return 0;
164 
165     if (q != NULL) {
166 	q->hash_next = p->hash_next;
167     } else {
168 	icHash[ICHASHVAL(icp)] = p->hash_next;
169     }
170     return 1;
171 }
172 
173 /* removeIM: remove IM from IM list which connection holds */
174 static int
removeIM(imp)175 removeIM(imp)
176 IMIM *imp;
177 {
178     IMConnection *conn = imp->connection;
179     IMIM *p, *q;
180 
181     p = conn->im_list;
182     q = NULL;
183     while (p != NULL) {
184 	if (p == imp) break;
185 	q = p;
186 	p = p->next;
187     }
188 
189     if (p == NULL) return 0;
190 
191     if (q == NULL) {
192 	conn->im_list = p->next;
193     } else {
194 	q->next = p->next;
195     }
196     return 1;
197 }
198 
199 /* removeIC: remove IC from IC list which IM holds */
200 static int
removeIC(icp)201 removeIC(icp)
202 IMIC *icp;
203 {
204     IMIM *imp = icp->im;
205     IMIC *p, *q;
206 
207     p = imp->ic_list;
208     q = NULL;
209     while (p != NULL) {
210 	if (p == icp) break;
211 	q = p;
212 	p = p->next;
213     }
214 
215     if (p == NULL) return 0;
216 
217     if (q == NULL) {
218 	imp->ic_list = p->next;
219     } else {
220 	q->next = p->next;
221     }
222     return 1;
223 }
224 
225 /*
226  * Public functions
227  */
228 
229 IMIM *
IMGetIM(conn,arglen)230 IMGetIM(conn, arglen)
231 IMConnection *conn;
232 int arglen;
233 {
234     unsigned int id;
235     IMIM *imp;
236 
237     /* Check argument length */
238     if (arglen < 2) {
239 	IMSendError(conn, IMBadSomething, 0, 0, "input-method ID expected");
240 	return NULL;
241     }
242 
243     id = IMGetC16(conn, 0);
244     imp = id2IM(conn, id);
245     if (imp != NULL && imp->connection == conn)	return imp;
246     IMSendError(conn, IMBadSomething, 0, 0, "invalid input-method ID");
247     return NULL;
248 }
249 
250 IMIC *
IMGetIC(conn,arglen)251 IMGetIC(conn, arglen)
252 IMConnection *conn;
253 int arglen;
254 {
255     unsigned int imid, icid;
256     IMIM *imp;
257     IMIC *icp;
258 
259     /* Check argument length */
260     if (arglen < 4) {
261 	IMSendError(conn, IMBadSomething, 0, 0, "input-method ID expected");
262 	return NULL;
263     } else if (arglen < 4) {
264 	IMSendError(conn, IMBadSomething, 0, 0, "input-context ID expected");
265 	return NULL;
266     }
267 
268     imid = IMGetC16(conn, 0);
269     icid = IMGetC16(conn, 2);
270 
271     if ((imp = id2IM(conn, imid)) == NULL || imp->connection != conn) {
272 	IMSendError(conn, IMBadSomething, 0, 0, "invalid input-method ID");
273 	return NULL;
274     }
275     if ((icp = id2IC(imp, icid)) == NULL || icp->im != imp) {
276 	IMSendError(conn, IMBadSomething, 0, 0, "invalid input-context ID");
277 	return NULL;
278     }
279     return icp;
280 }
281 
282 IMIM *
IMCreateIM(conn,converter)283 IMCreateIM(conn, converter)
284 IMConnection *conn;
285 IMConverter *converter;
286 {
287     IMIM *imp;
288 
289     imp = XtNew(IMIM);
290 
291     imp->id = newIMID(conn);
292     imp->connection = conn;
293     imp->converter = converter;
294     imp->mask = 0;
295     imp->ic_list = NULL;
296 
297     registerIM(imp);
298     imp->next = conn->im_list;
299     conn->im_list = imp;
300 
301     return imp;
302 }
303 
304 
305 IMIC *
IMCreateIC(imp)306 IMCreateIC(imp)
307 IMIM *imp;
308 {
309     IMIC *icp;
310 
311     icp = XtNew(IMIC);
312 
313     icp->id = newICID(imp);
314 
315     /*
316      * Initialize data
317      */
318     icp->im = imp;
319     icp->conversion = NULL;
320     icp->state = 0;
321     icp->pending_events = NULL;
322     icp->style = IMSTYLE_SEPARATE;
323     icp->common_attr.set_mask = icp->common_attr.change_mask = 0;
324     icp->preedit_attr.set_mask = icp->preedit_attr.change_mask = 0;
325     icp->status_attr.set_mask = icp->status_attr.change_mask = 0;
326     icp->fonts = NULL;
327     icp->num_fonts = 0;
328     icp->status_fonts = NULL;
329     icp->num_status_fonts = 0;
330 
331     registerIC(icp);
332     icp->next = imp->ic_list;
333     imp->ic_list = icp;
334 
335     return icp;
336 }
337 
338 void
IMDestroyIM(imp)339 IMDestroyIM(imp)
340 IMIM *imp;
341 {
342     IMIC *icp = imp->ic_list;
343     IMIC *icp_next;
344 
345     /*
346      * Destroy all the ICs belonging to this IM.
347      */
348     while (icp != NULL) {
349 	icp_next = icp->next;
350 	IMDestroyIC(icp);
351 	icp = icp_next;
352     }
353 
354     (void)unregisterIM(imp);
355     (void)removeIM(imp);
356 
357     XtFree((char *)imp);
358 }
359 
360 void
IMDestroyIC(icp)361 IMDestroyIC(icp)
362 IMIC *icp;
363 {
364     IMPendingEvent *pending;
365 
366     if (icp->state & IC_DESTROYING) return;
367     icp->state |= IC_DESTROYING;
368 
369     /*
370      * Stop conversion.
371      */
372     if (icp->state & IC_CONVERTING) {
373 	IMStopConversion(icp);
374     }
375 
376     /*
377      * Free pending event queue.
378      */
379     pending = icp->pending_events;
380     while (pending != NULL) {
381 	IMPendingEvent *next = pending->next;
382 
383 	XtFree((char *)pending);
384 	pending = next;
385     }
386 
387     /*
388      * Free IC attributes.
389      */
390     IMFreeICAttributes(icp);
391 
392     (void)unregisterIC(icp);
393     (void)removeIC(icp);
394 
395     XtFree((char *)icp);
396 }
397