1 #ifndef lint
2 static char *rcsid = "$Id: imattr.c,v 1.18 2002/01/10 15:04:05 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 #ifndef XNSeparatorofNestedList
24 #define XNSeparatorofNestedList "separatorofNesttedList"
25 #endif
26 #ifndef XNPreeditState
27 #define XNPreeditState		"preeditState"
28 #endif
29 #ifndef XIMPreeditEnable
30 #define XIMPreeditEnable	1L
31 #define XIMPreeditDisable	2L
32 #endif
33 #ifndef XNResetState
34 #define XNResetState		"resetState"
35 #endif
36 #ifndef XIMInitialState
37 #define XIMInitialState		1L
38 #define XIMPreserveState	2L
39 #endif
40 
41 #define PAD4(n)	((((n) + 3) / 4) * 4)
42 
43 /*
44  * List of supported input styles.
45  */
46 
47 typedef struct {
48     XIMStyle xim_style;		/* X11R5 spec. */
49     int conversion_style;	/* kinput2 spec. */
50 } InputStyle;
51 
52 static InputStyle styles[] = {
53     { XIMPreeditPosition|XIMStatusArea, IMSTYLE_OVER_THE_SPOT },
54     { XIMPreeditPosition|XIMStatusNothing, IMSTYLE_OVER_THE_SPOT },
55     { XIMPreeditArea|XIMStatusArea, IMSTYLE_OFF_THE_SPOT },
56     { XIMPreeditCallbacks|XIMStatusCallbacks, IMSTYLE_ON_THE_SPOT },
57     { XIMPreeditCallbacks|XIMStatusNothing, IMSTYLE_ON_THE_SPOT },
58     { XIMPreeditNothing|XIMStatusNothing, IMSTYLE_SEPARATE },
59     { 0 },
60 };
61 
62 #define NEST_NONE	0
63 #define NEST_PREEDIT	1
64 #define NEST_STATUS	2
65 
66 #define CHECK_ICATTR_SIZE(validsize, code) \
67 	if (len != validsize) { badSizeError(icp, code); return -1; }
68 
69 #undef OP_C
70 #undef OP_S
71 #undef OP_G
72 
73 #define OP_C	1	/* Create */
74 #define OP_S	2	/* SetValues */
75 #define OP_G	4	/* GetValues */
76 
77 typedef struct {
78     char *name;		/* attribute name */
79     int type;		/* type of attribute value */
80     int valid_ops;	/* valid operations for this attribute */
81     int (*set_proc) _Pt_((IMIM *, char *, int));
82     int (*get_proc) _Pt_((IMIM *, unsigned int, int));
83 } IMAttribute;
84 
85 typedef struct {
86     char *name;		/* attribute name */
87     int type;		/* type of attribute value */
88     int valid_ops;	/* valid operations for this attribute */
89     int (*set_proc) _Pt_((IMIC *, char *, int, int, int, int));
90     int (*get_proc) _Pt_((IMIC *, unsigned int, int, int, char *, int));
91 } ICAttribute;
92 
93 
94 /*
95  * IM attributes
96  */
97 
98 static int getQueryInputStyle _Pt_((IMIM *imp, unsigned int id, int offset));
99 
100 static IMAttribute imAttributes[] = {
101     { XNQueryInputStyle, TYPE_XIM_STYLES, OP_G,
102 	  NULL, getQueryInputStyle },
103 };
104 
105 static int numImAttributes = XtNumber(imAttributes);
106 
107 
108 /*
109  * IC attributes
110  */
111 
112 static int setInputStyle _Pt_((IMIC *, char *, int, int, int, int));
113 static int setClientWindow _Pt_((IMIC *, char *, int, int, int, int));
114 static int setFocusWindow _Pt_((IMIC *, char *, int, int, int, int));
115 static int setPreeditAttributes _Pt_((IMIC *, char *, int, int, int, int));
116 static int setStatusAttributes _Pt_((IMIC *, char *, int, int, int, int));
117 static int setArea _Pt_((IMIC *, char *, int, int, int, int));
118 static int setAreaNeeded _Pt_((IMIC *, char *, int, int, int, int));
119 static int setForeground _Pt_((IMIC *, char *, int, int, int, int));
120 static int setBackground _Pt_((IMIC *, char *, int, int, int, int));
121 static int setColormap _Pt_((IMIC *, char *, int, int, int, int));
122 static int setBgPixmap _Pt_((IMIC *, char *, int, int, int, int));
123 static int setLineSpace _Pt_((IMIC *, char *, int, int, int, int));
124 static int setCursor _Pt_((IMIC *, char *, int, int, int, int));
125 static int setSpotLocation _Pt_((IMIC *, char *, int, int, int, int));
126 static int setStdColormap _Pt_((IMIC *, char *, int, int, int, int));
127 static int setFontSet _Pt_((IMIC *, char *, int, int, int, int));
128 static int setPreeditState _Pt_((IMIC *, char *, int, int, int, int));
129 static int setResetState _Pt_((IMIC *, char *, int, int, int, int));
130 
131 static int getPreeditAttributes _Pt_((IMIC *, unsigned int, int, int, char *, int));
132 static int getStatusAttributes _Pt_((IMIC *, unsigned int, int, int, char *, int));
133 static int getInputStyle _Pt_((IMIC *, unsigned int, int, int, char *, int));
134 static int getClientWindow _Pt_((IMIC *, unsigned int, int, int, char *, int));
135 static int getFocusWindow _Pt_((IMIC *, unsigned int, int, int, char *, int));
136 static int getFilterEvents _Pt_((IMIC *, unsigned int, int, int, char *, int));
137 static int getArea _Pt_((IMIC *, unsigned int, int, int, char *, int));
138 static int getAreaNeeded _Pt_((IMIC *, unsigned int, int, int, char *, int));
139 static int getSpotLocation _Pt_((IMIC *, unsigned int, int, int, char *, int));
140 static int getColormap _Pt_((IMIC *, unsigned int, int, int, char *, int));
141 static int getStdColormap _Pt_((IMIC *, unsigned int, int, int, char *, int));
142 static int getForeground _Pt_((IMIC *, unsigned int, int, int, char *, int));
143 static int getBackground _Pt_((IMIC *, unsigned int, int, int, char *, int));
144 static int getBgPixmap _Pt_((IMIC *, unsigned int, int, int, char *, int));
145 static int getFontSet _Pt_((IMIC *, unsigned int, int, int, char *, int));
146 static int getLineSpace _Pt_((IMIC *, unsigned int, int, int, char *, int));
147 static int getCursor _Pt_((IMIC *, unsigned int, int, int, char *, int));
148 static int getPreeditState _Pt_((IMIC *, unsigned int, int, int, char *, int));
149 static int getResetState _Pt_((IMIC *, unsigned int, int, int, char *, int));
150 
151 static ICAttribute icAttributes[] = {
152     { XNInputStyle, TYPE_CARD32, OP_C|OP_G,
153 	  setInputStyle, getInputStyle },
154     { XNClientWindow, TYPE_WINDOW, OP_C|OP_S|OP_G,
155 	  setClientWindow, getClientWindow },
156     { XNFocusWindow, TYPE_WINDOW, OP_C|OP_S|OP_G,
157 	  setFocusWindow, getFocusWindow },
158     { XNFilterEvents, TYPE_CARD32, OP_G,
159 	  NULL, getFilterEvents },
160     { XNPreeditAttributes, TYPE_NESTED_LIST, OP_C|OP_S|OP_G,
161 	  setPreeditAttributes, getPreeditAttributes },
162     { XNStatusAttributes, TYPE_NESTED_LIST, OP_C|OP_S|OP_G,
163 	  setStatusAttributes, getStatusAttributes },
164     { XNArea, TYPE_XRECTANGLE, OP_C|OP_S|OP_G,
165 	  setArea, getArea },
166     { XNAreaNeeded, TYPE_XRECTANGLE, OP_C|OP_S|OP_G,
167 	  setAreaNeeded, getAreaNeeded },
168     { XNSpotLocation, TYPE_XPOINT, OP_C|OP_S|OP_G,
169 	  setSpotLocation, getSpotLocation },
170     { XNColormap, TYPE_CARD32, OP_C|OP_S|OP_G,
171 	  setColormap, getColormap },
172     { XNStdColormap, TYPE_CARD32, OP_C|OP_S|OP_G,
173 	  setStdColormap, getStdColormap },
174     { XNForeground, TYPE_CARD32, OP_C|OP_S|OP_G,
175 	  setForeground, getForeground },
176     { XNBackground, TYPE_CARD32, OP_C|OP_S|OP_G,
177 	  setBackground, getBackground },
178     { XNBackgroundPixmap, TYPE_CARD32, OP_C|OP_S|OP_G,
179 	  setBgPixmap, getBgPixmap },
180     { XNFontSet, TYPE_XFONTSET, OP_C|OP_S|OP_G,
181 	  setFontSet, getFontSet },
182     { XNLineSpace, TYPE_CARD16, OP_C|OP_S|OP_G,	  /* should be TYPE_INT16 */
183 	  setLineSpace, getLineSpace },
184     { XNCursor, TYPE_CARD32, OP_C|OP_S|OP_G,
185 	  setCursor, getCursor },
186     { XNSeparatorofNestedList, TYPE_SEPARATOR, OP_G,
187 	  NULL, NULL },
188     { XNPreeditState, TYPE_CARD32, OP_C|OP_S|OP_G,
189       setPreeditState, getPreeditState },
190     { XNResetState, TYPE_CARD32, OP_C|OP_S|OP_G,
191       setResetState, getResetState },
192 };
193 
194 static int numIcAttributes = XtNumber(icAttributes);
195 
196 
197 static unsigned int getC16 _Pt_((char *data, int order));
198 static int getI16 _Pt_((char *data, int order));
199 static unsigned long getC32 _Pt_((char *data, int order));
200 static int validateClientWindow _Pt_((IMIC *icp));
201 static int validateFocusWindow _Pt_((IMIC *icp));
202 static void badSizeError _Pt_((IMIC *icp, int code));
203 static void unnestedError _Pt_((IMIC *icp));
204 static IMPSAttributes *getPSPtr _Pt_((IMIC *icp, int type));
205 static int getIMValues _Pt_((IMIM *imp, char *data, int len, int offset));
206 static int getICValues _Pt_((IMIC *icp, char *data, int len, int nest,
207 			     int offset, int *sepp));
208 static int setICValues _Pt_((IMIC *icp, char *data, int len,
209 			     int major, int op));
210 static int getPSAttributes _Pt_((IMIC *icp, unsigned int id, int nest,
211 				 int offset, char *data, int len));
212 static void changeFonts _Pt_((IMIC *icp, int preedit));
213 static void fillCommonDefault _Pt_((IMIC *icp, unsigned long mask));
214 static int getNaturalLineSpace _Pt_((IMIC *icp, int preedit));
215 static void fillPSDefault _Pt_((IMIC *icp, int type, unsigned long mask));
216 static int validateCommonAttr _Pt_((IMIC *icp, int checkonly));
217 static int validatePSAttr _Pt_((IMIC *icp, int type, int checkonly));
218 static void changeConversionAttributes _Pt_((IMIC *icp));
219 static void computeAreaNeeded _Pt_((IMIC *icp));
220 static void computeAreaForQuery _Pt_((IMIC *icp));
221 
222 
223 /*
224  * Functions reading out numbers from byte buffer
225  */
226 
227 static unsigned int
getC16(data,order)228 getC16(data, order)
229 char *data;
230 int order;
231 {
232     unsigned char *p = (unsigned char *)data;
233     unsigned int x;
234 
235     x = (order == ORDER_BIG) ? ((p[0] << 8) | p[1]) : (p[0] | p[1] << 8);
236     return x;
237 }
238 
239 static int
getI16(data,order)240 getI16(data, order)
241 char *data;
242 int order;
243 {
244     unsigned char *p = (unsigned char *)data;
245     long l;
246 
247     l = (order == ORDER_BIG) ? ((p[0] << 8) | p[1]) : (p[0] | p[1] << 8);
248     return (l < 32768) ? (int)l : (int)(l - 65536L);
249 }
250 
251 static unsigned long
getC32(data,order)252 getC32(data, order)
253 char *data;
254 int order;
255 {
256     unsigned char *p = (unsigned char *)data;
257     unsigned long x;
258 
259     if (order == ORDER_BIG) {
260 	x = (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
261     } else {
262 	x = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
263     }
264     return x;
265 }
266 
267 
268 /*
269  * Functions that check the validity of resources.
270  */
271 
272 static int
validateClientWindow(icp)273 validateClientWindow(icp)
274 IMIC *icp;
275 {
276     return IMValidateWindow(XtDisplay(icp->im->connection->proto_widget),
277 			    icp->common_attr.client, &icp->client_profile);
278 }
279 
280 static int
validateFocusWindow(icp)281 validateFocusWindow(icp)
282 IMIC *icp;
283 {
284     IMCommonAttributes *ap = &icp->common_attr;
285 
286     /*
287      * This function assumes that the client window has already
288      * been validated.
289      */
290     if ((ap->set_mask & ATTR_MASK_CLIENT) && ap->focus == ap->client) {
291 	icp->focus_profile = icp->client_profile;
292 	return 1;
293     } else {
294 	return IMValidateWindow(XtDisplay(icp->im->connection->proto_widget),
295 				icp->common_attr.focus, &icp->focus_profile);
296     }
297 }
298 
299 
300 /*
301  * Functions submit errors
302  */
303 
304 static void
badSizeError(icp,code)305 badSizeError(icp, code)
306 IMIC *icp;
307 int code;
308 {
309     DPRINT(("bad size error for IC #%d\n", icp->id));
310     IMSendError(icp->im->connection, code, icp->im->id, icp->id,
311 		"invalid size of attribute value");
312 }
313 
314 static void
unnestedError(icp)315 unnestedError(icp)
316 IMIC *icp;
317 {
318     DPRINT(("unnested error for IC #%d\n", icp->id));
319     IMSendError(icp->im->connection, IMBadSomething, icp->im->id, icp->id,
320 		"either preedit or status specification required");
321 }
322 
323 
324 /*
325  * Functions getting IM attributes
326  */
327 
328 static IMPSAttributes *
getPSPtr(icp,type)329 getPSPtr(icp, type)
330 IMIC *icp;
331 int type;
332 {
333     switch (type) {
334     case NEST_PREEDIT: return &icp->preedit_attr;
335     case NEST_STATUS: return &icp->status_attr;
336     default: return NULL;
337     }
338 }
339 
340 static int
getIMValues(imp,data,len,offset)341 getIMValues(imp, data, len, offset)
342 IMIM *imp;
343 char *data;
344 int len;
345 int offset;		/* request offset */
346 {
347     unsigned int id;		/* attribute ID */
348     IMAttribute *attrp;
349     IMConnection *conn = imp->connection;
350     int byte_order = conn->byte_order;
351 
352     while (len >= 2) {
353 	id = getC16(data, byte_order);
354 	data += 2;
355 	len -= 2;
356 
357 	if (id > numImAttributes) {
358 	    /* invalid attribute ID */
359 	    IMCancelRequest(conn, offset);
360 	    IMSendError(conn, IMBadSomething, imp->id, 0,
361 			"invalid IM attribute ID");
362 	    return -1;
363 	}
364 
365 	attrp = &imAttributes[id];
366 	if (!(attrp->valid_ops & OP_G)) {
367 	    IMCancelRequest(conn, offset);
368 	    IMSendError(conn, IMBadSomething, imp->id, 0,
369 			"invalid operation (IMGetValues) for this attribute");
370 	    return -1;
371 	}
372 
373 	if ((*attrp->get_proc)(imp, id, offset) < 0) return -1;
374     }
375     return 0;
376 }
377 
378 /* ARGSUSED */
379 static int
getQueryInputStyle(imp,id,offset)380 getQueryInputStyle(imp, id, offset)
381 IMIM *imp;
382 unsigned int id;
383 int offset;
384 {
385     IMConnection *conn = imp->connection;
386     unsigned int num_styles, num_bytes;
387     InputStyle *stp;
388 
389     TRACE(("imlib:getQueryInputStyle()\n"));
390 
391     for (num_styles = 0, stp = styles; stp->xim_style != 0; stp++) {
392 	num_styles++;
393     }
394     num_bytes = num_styles * 4 + 4;
395     IMPutC16(conn, id);
396     IMPutC16(conn, num_bytes);
397     IMPutC16(conn, num_styles);
398     IMPutC16(conn, 0);
399     for (stp = styles; stp->xim_style != 0; stp++) {
400 	IMPutC32(conn, stp->xim_style);
401     }
402     return 0;
403 }
404 
405 
406 /*
407  * Functions setting IC attributes
408  */
409 
410 static int
setICValues(icp,data,len,nest,op)411 setICValues(icp, data, len, nest, op)
412 IMIC *icp;
413 char *data;
414 int len;
415 int nest;
416 int op;
417 {
418     IMConnection *conn = icp->im->connection;
419     unsigned int imid = icp->im->id;
420     unsigned int icid = icp->id;
421     unsigned int id;
422     unsigned int value_len;
423     unsigned int attr_len;
424     char *value;
425     ICAttribute *attrp;
426     int byte_order = icp->im->connection->byte_order;
427 
428     TRACE(("imlib:setICValues()\n"));
429 
430     while (len > 0) {
431 	if (len < 4) {
432 	    DPRINT(("attribute data length < 4\n"));
433 	    IMSendError(conn, IMBadSomething, imid, icid, "Bad attribute data");
434 	    return -1;
435 	}
436 	id = getC16(data, byte_order);
437 	value_len = getC16(data + 2, byte_order);
438 	attr_len = PAD4(4 + value_len);
439 
440 	if (attr_len > len) {
441 	    DPRINT(("attribute data length > request length\n"));
442 	    IMSendError(conn, IMBadSomething, imid, icid,
443 			"Bad attribute length");
444 	    return -1;
445 	}
446 	value = data + 4;
447 
448 	if (id > numIcAttributes) {
449 	    DPRINT(("invalid IC attribute ID %d\n", id));
450 	    IMSendError(conn, IMBadSomething, imid, icid,
451 			"invalid IC attribute ID");
452 	    return -1;
453 	}
454 	attrp = &icAttributes[id];
455 	if (!(attrp->valid_ops & op)) {
456 	    DPRINT(("invalid operation (%s) for IC attr %d\n",
457 		    op == OP_C ? "create" : "set", id));
458 	    IMSendError(conn, IMBadSomething, imid, icid,
459 			"invalid operation for this attribute");
460 	    return -1;
461 	}
462 
463 	/*
464 	 * Call attribute set procedure.
465 	 */
466 	if ((*attrp->set_proc)(icp, value, (int)value_len, byte_order, nest, op) < 0) {
467 	    /*
468 	     * Error has occured.  The set procedure has already sent
469 	     * appropriate error message, so just return here.
470 	     */
471 	    return -1;
472 	}
473 
474 	data += attr_len;
475 	len -= attr_len;
476     }
477     return 0;
478 }
479 
480 /* ARGSUSED */
481 static int
setInputStyle(icp,value,len,order,nest,op)482 setInputStyle(icp, value, len, order, nest, op)
483 IMIC *icp;
484 char *value;
485 int len;
486 int order;
487 int nest;
488 int op;
489 {
490     TRACE(("imlib:setInputStyle()\n"));
491 
492     CHECK_ICATTR_SIZE(4, IMBadStyle);
493 
494     /*
495      * InputStyle must be set with CreateIC.
496      */
497     if (op != OP_C) {
498 	DPRINT(("trying to change input style through SetICValues\n"));
499 	IMSendError(icp->im->connection, IMBadStyle,
500 		    icp->im->id, icp->id,
501 		    "InputStyle cannot be changed by SetICValues");
502 	return -1;
503     }
504 
505     icp->common_attr.input_style = (XIMStyle)getC32(value, order);
506     icp->common_attr.set_mask |= ATTR_MASK_INPUT_STYLE;
507     icp->common_attr.change_mask |= ATTR_MASK_INPUT_STYLE;
508     TRACE(("\tinput style: %ld\n", icp->common_attr.input_style));
509     return 0;
510 }
511 
512 /* ARGSUSED */
513 static int
setClientWindow(icp,value,len,order,nest,op)514 setClientWindow(icp, value, len, order, nest, op)
515 IMIC *icp;
516 char *value;
517 int len;
518 int order;
519 int nest;
520 int op;
521 {
522     TRACE(("imlib:setClientWindow()\n"));
523 
524     CHECK_ICATTR_SIZE(4, IMBadClientWindow);
525 
526     /*
527      * ClientWindow cannot be changed.
528      */
529     if (icp->common_attr.set_mask & ATTR_MASK_CLIENT) {
530 	DPRINT(("client window already specified\n"));
531 	IMSendError(icp->im->connection, IMBadClientWindow,
532 		    icp->im->id, icp->id, "ClientWindow already set");
533 	return -1;
534     }
535 
536     icp->common_attr.client = (Window)getC32(value, order);
537     TRACE(("\tclient window: %08lx\n", icp->common_attr.client));
538 
539     icp->common_attr.set_mask |= ATTR_MASK_CLIENT;
540     icp->common_attr.change_mask |= ATTR_MASK_CLIENT;
541 
542     return 0;
543 }
544 
545 /* ARGSUSED */
546 static int
setFocusWindow(icp,value,len,order,nest,op)547 setFocusWindow(icp, value, len, order, nest, op)
548 IMIC *icp;
549 char *value;
550 int len;
551 int order;
552 int nest;
553 int op;
554 {
555     Window focus;
556 
557     TRACE(("imlib:setFocusWindow()\n"));
558 
559     CHECK_ICATTR_SIZE(4, IMBadFocusWindow);
560 
561     focus = (Window)getC32(value, order);
562     TRACE(("\tfocus window: %08lx\n", focus));
563 
564     if (!(icp->common_attr.set_mask & ATTR_MASK_FOCUS) ||
565 	focus != icp->common_attr.focus) {
566 	icp->common_attr.change_mask |= ATTR_MASK_FOCUS;
567     }
568     icp->common_attr.focus = focus;
569     icp->common_attr.set_mask |= ATTR_MASK_FOCUS;
570     return 0;
571 }
572 
573 /* ARGSUSED */
574 static int
setPreeditAttributes(icp,value,len,order,nest,op)575 setPreeditAttributes(icp, value, len, order, nest, op)
576 IMIC *icp;
577 char *value;
578 int len;
579 int order;
580 int nest;
581 int op;
582 {
583     TRACE(("imlib:setPreeditAttributes()\n"));
584     return setICValues(icp, value, len, NEST_PREEDIT, op);
585 }
586 
587 /* ARGSUSED */
588 static int
setStatusAttributes(icp,value,len,order,nest,op)589 setStatusAttributes(icp, value, len, order, nest, op)
590 IMIC *icp;
591 char *value;
592 int len;
593 int order;
594 int nest;
595 int op;
596 {
597     TRACE(("imlib:setStatusAttributes()\n"));
598     return setICValues(icp, value, len, NEST_STATUS, op);
599 }
600 
601 /* ARGSUSED */
602 static int
setArea(icp,value,len,order,nest,op)603 setArea(icp, value, len, order, nest, op)
604 IMIC *icp;
605 char *value;
606 int len;
607 int order;
608 int nest;
609 int op;
610 {
611     IMPSAttributes *ap;
612     XRectangle area;
613 
614     TRACE(("imlib:setArea()\n"));
615 
616     CHECK_ICATTR_SIZE(8, IMBadArea);
617 
618     if ((ap = getPSPtr(icp, nest)) == NULL) {
619 	unnestedError(icp);
620 	return -1;
621     }
622 
623     area.x = getI16(value, order);
624     area.y = getI16(value + 2, order);
625     area.width = getC16(value + 4, order);
626     area.height = getC16(value + 6, order);
627     TRACE(("\tarea: %d, %d, %d, %d\n",
628 	   area.x, area.y, area.width, area.height));
629 
630     if (!(ap->set_mask & ATTR_MASK_AREA) ||
631 	area.x != ap->area.x ||
632 	area.y != ap->area.y ||
633 	area.width != ap->area.width ||
634 	area.height != ap->area.height) {
635 	ap->change_mask |= ATTR_MASK_AREA;
636     }
637 
638     ap->area.x = area.x;
639     ap->area.y = area.y;
640     ap->area.width = area.width;
641     ap->area.height = area.height;
642     ap->set_mask |= ATTR_MASK_AREA;
643 
644     return 0;
645 }
646 
647 /* ARGSUSED */
648 static int
setAreaNeeded(icp,value,len,order,nest,op)649 setAreaNeeded(icp, value, len, order, nest, op)
650 IMIC *icp;
651 char *value;
652 int len;
653 int order;
654 int nest;
655 int op;
656 {
657     IMPSAttributes *ap;
658     XRectangle area;
659 
660     TRACE(("imlib:setAreaNeeded()\n"));
661 
662     CHECK_ICATTR_SIZE(8, IMBadArea);
663 
664     if ((ap = getPSPtr(icp, nest)) == NULL) {
665 	unnestedError(icp);
666 	return -1;
667     }
668 
669     area.width = getC16(value + 4, order);
670     area.height = getC16(value + 6, order);
671     TRACE(("\tarea needed: %d, %d\n", area.width, area.height));
672 
673     if (!(ap->set_mask & ATTR_MASK_AREA_NEEDED) ||
674 	area.width != ap->area_needed.width ||
675 	area.height != ap->area_needed.height) {
676 	ap->change_mask |= ATTR_MASK_AREA_NEEDED;
677     }
678 
679     ap->area_needed.width = area.width;
680     ap->area_needed.height = area.height;
681     ap->set_mask |= ATTR_MASK_AREA_NEEDED;
682 
683     return 0;
684 }
685 
686 /* ARGSUSED */
687 static int
setForeground(icp,value,len,order,nest,op)688 setForeground(icp, value, len, order, nest, op)
689 IMIC *icp;
690 char *value;
691 int len;
692 int order;
693 int nest;
694 int op;
695 {
696     IMPSAttributes *ap;
697     Pixel fore;
698 
699     TRACE(("imlib:setForeground()\n"));
700 
701     CHECK_ICATTR_SIZE(4, IMBadForeground);
702 
703     if ((ap = getPSPtr(icp, nest)) == NULL) {
704 	unnestedError(icp);
705 	return -1;
706     }
707 
708     fore = getC32(value, order);
709     TRACE(("\tforeground: %ld\n", fore));
710 
711     if (!(ap->set_mask & ATTR_MASK_FOREGROUND) || fore != ap->foreground) {
712 	ap->change_mask |= ATTR_MASK_FOREGROUND;
713     }
714     ap->foreground = fore;
715     ap->set_mask |= ATTR_MASK_FOREGROUND;
716     return 0;
717 }
718 
719 /* ARGSUSED */
720 static int
setBackground(icp,value,len,order,nest,op)721 setBackground(icp, value, len, order, nest, op)
722 IMIC *icp;
723 char *value;
724 int len;
725 int order;
726 int nest;
727 int op;
728 {
729     IMPSAttributes *ap;
730     Pixel back;
731 
732     TRACE(("imlib:setBackground()\n"));
733 
734     CHECK_ICATTR_SIZE(4, IMBadBackground);
735 
736     if ((ap = getPSPtr(icp, nest)) == NULL) {
737 	unnestedError(icp);
738 	return -1;
739     }
740 
741     back = getC32(value, order);
742     TRACE(("\tbackground: %ld\n", back));
743 
744     if (!(ap->set_mask & ATTR_MASK_BACKGROUND) || back != ap->background) {
745 	ap->change_mask |= ATTR_MASK_BACKGROUND;
746     }
747     ap->background = back;
748     ap->set_mask |= ATTR_MASK_BACKGROUND;
749     return 0;
750 }
751 
752 /* ARGSUSED */
753 static int
setColormap(icp,value,len,order,nest,op)754 setColormap(icp, value, len, order, nest, op)
755 IMIC *icp;
756 char *value;
757 int len;
758 int order;
759 int nest;
760 int op;
761 {
762     IMPSAttributes *ap;
763     Colormap cmap;
764 
765     TRACE(("imlib:setColormap()\n"));
766 
767     CHECK_ICATTR_SIZE(4, IMBadColormap);
768 
769     if ((ap = getPSPtr(icp, nest)) == NULL) {
770 	unnestedError(icp);
771 	return -1;
772     }
773 
774     cmap = getC32(value, order);
775     TRACE(("\tcolormap: %08lx\n", cmap));
776 
777     if (!(ap->set_mask & ATTR_MASK_COLORMAP) || cmap != ap->colormap) {
778 	ap->change_mask |= ATTR_MASK_COLORMAP;
779     }
780     ap->colormap = cmap;
781     ap->set_mask |= ATTR_MASK_COLORMAP;
782     return 0;
783 }
784 
785 /* ARGSUSED */
786 static int
setBgPixmap(icp,value,len,order,nest,op)787 setBgPixmap(icp, value, len, order, nest, op)
788 IMIC *icp;
789 char *value;
790 int len;
791 int order;
792 int nest;
793 int op;
794 {
795     IMPSAttributes *ap;
796     Pixmap pixmap;
797 
798     TRACE(("imlib:setBgPixmap()\n"));
799 
800     CHECK_ICATTR_SIZE(4, IMBadPixmap);
801 
802     if ((ap = getPSPtr(icp, nest)) == NULL) {
803 	unnestedError(icp);
804 	return -1;
805     }
806 
807     pixmap = getC32(value, order);
808     TRACE(("\tbackground pixmap: %08lx\n", pixmap));
809 
810     if (!(ap->set_mask & ATTR_MASK_BG_PIXMAP) || pixmap != ap->bg_pixmap) {
811 	ap->change_mask |= ATTR_MASK_BG_PIXMAP;
812     }
813 
814     ap->bg_pixmap = pixmap;
815     ap->set_mask |= ATTR_MASK_BG_PIXMAP;
816 
817     return 0;
818 }
819 
820 /* ARGSUSED */
821 static int
setLineSpace(icp,value,len,order,nest,op)822 setLineSpace(icp, value, len, order, nest, op)
823 IMIC *icp;
824 char *value;
825 int len;
826 int order;
827 int nest;
828 int op;
829 {
830     IMPSAttributes *ap;
831     int line_space;
832 
833     TRACE(("imlib:setLineSpace()\n"));
834 
835     CHECK_ICATTR_SIZE(2, IMBadSomething);
836 
837     if ((ap = getPSPtr(icp, nest)) == NULL) {
838 	unnestedError(icp);
839 	return -1;
840     }
841 
842     line_space = getI16(value, order);	/* ??? linespacing is 'int' */
843     TRACE(("\tline space: %d\n", line_space));
844 
845     if (!(ap->set_mask & ATTR_MASK_LINESPACE) ||
846 	line_space != ap->line_space) {
847 	ap->change_mask |= ATTR_MASK_LINESPACE;
848     }
849     ap->line_space = line_space;
850     ap->set_mask |= ATTR_MASK_LINESPACE;
851     return 0;
852 }
853 
854 /* ARGSUSED */
855 static int
setCursor(icp,value,len,order,nest,op)856 setCursor(icp, value, len, order, nest, op)
857 IMIC *icp;
858 char *value;
859 int len;
860 int order;
861 int nest;
862 int op;
863 {
864     IMPSAttributes *ap;
865     Cursor cursor;
866 
867     TRACE(("imlib:setCursor()\n"));
868 
869     CHECK_ICATTR_SIZE(4, IMBadCursor);
870 
871     if ((ap = getPSPtr(icp, nest)) == NULL) {
872 	unnestedError(icp);
873 	return -1;
874     }
875 
876     cursor = getC32(value, order);
877     TRACE(("\tcursor: %08lx\n", cursor));
878 
879     if (!(ap->set_mask & ATTR_MASK_CURSOR) || cursor != ap->cursor) {
880 	ap->change_mask |= ATTR_MASK_CURSOR;
881     }
882     ap->cursor = cursor;
883     ap->set_mask |= ATTR_MASK_CURSOR;
884     return 0;
885 }
886 
887 /* ARGSUSED */
888 static int
setSpotLocation(icp,value,len,order,nest,op)889 setSpotLocation(icp, value, len, order, nest, op)
890 IMIC *icp;
891 char *value;
892 int len;
893 int order;
894 int nest;
895 int op;
896 {
897     IMPSAttributes *ap;
898     XPoint spot;
899 
900     TRACE(("imlib:setSpotLocation()\n"));
901 
902     CHECK_ICATTR_SIZE(4, IMBadSpotLocation);
903 
904     if (nest == NEST_STATUS) {
905 	DPRINT(("spot location specified in a status attribute list\n"));
906 	IMSendError(icp->im->connection, IMBadSpotLocation,
907 		    icp->im->id, icp->id,
908 		    "spot location isn't a status attribute");
909 	return -1;
910     }
911 
912     ap = &icp->preedit_attr;
913 
914     spot.x = getI16(value, order);
915     spot.y = getI16(value + 2, order);
916     TRACE(("\tspot location: %d, %d\n", spot.x, spot.y));
917 
918     if (!(ap->set_mask & ATTR_MASK_SPOT_LOCATION) ||
919 	spot.x != ap->spot_location.x || spot.y != ap->spot_location.y) {
920 	ap->change_mask |= ATTR_MASK_SPOT_LOCATION;
921     }
922     ap->spot_location.x = spot.x;
923     ap->spot_location.y = spot.y;
924     ap->set_mask |= ATTR_MASK_SPOT_LOCATION;
925     return 0;
926 }
927 
928 /* ARGSUSED */
929 static int
setStdColormap(icp,value,len,order,nest,op)930 setStdColormap(icp, value, len, order, nest, op)
931 IMIC *icp;
932 char *value;
933 int len;
934 int order;
935 int nest;
936 int op;
937 {
938     IMPSAttributes *ap;
939     Atom colormap_name;
940     XStandardColormap *stdcolormaps;
941     Widget w = icp->im->connection->proto_widget;
942     Display *dpy = XtDisplay(w);
943     int ncolormaps;
944     Window root;
945     XAEHandle h;
946     int status;
947 
948     TRACE(("imlib:setStdColormap()\n"));
949 
950     CHECK_ICATTR_SIZE(4, IMBadAtom);
951 
952     if ((ap = getPSPtr(icp, nest)) == NULL) {
953 	unnestedError(icp);
954 	return -1;
955     }
956 
957     colormap_name = getC32(value, order);
958     if (icp->common_attr.set_mask & ATTR_MASK_CLIENT) {
959 	root = icp->client_profile.root;
960     } else if (icp->common_attr.set_mask & ATTR_MASK_FOCUS) {
961 	root = icp->focus_profile.root;
962     } else {
963 	/*
964 	 * Client has not specified client window yet.
965 	 * Reading standard colormap property should been deffered
966 	 * until the window is set, but for now...
967 	 */
968 	DDPRINT(2, ("std colormap specified, leaving client window unspecified\n"));
969 	root = RootWindowOfScreen(XtScreen(w));
970     }
971 
972     h = XAESetIgnoreErrors(dpy);
973     status = XGetRGBColormaps(dpy, root,
974 			      &stdcolormaps, &ncolormaps, colormap_name);
975     XAEUnset(h);
976     if (!status || ncolormaps < 0) {
977 	DPRINT(("can't get standard colormap (%ld)\n", colormap_name));
978 	IMSendError(icp->im->connection, IMBadName, icp->im->id, icp->id,
979 		"invalid standard colormap name");
980 	return -1;
981     }
982 
983     if (!(ap->set_mask & ATTR_MASK_STD_COLORMAP) ||
984 	colormap_name != ap->std_colormap) {
985 	ap->change_mask |= ATTR_MASK_STD_COLORMAP;
986     }
987     ap->std_colormap = colormap_name;
988     ap->colormap = stdcolormaps[0].colormap;
989     TRACE(("\tstandard colormap: %ld (colormap=%08lx)\n",
990 	   colormap_name, ap->colormap));
991 
992     ap->set_mask |= ATTR_MASK_STD_COLORMAP | ATTR_MASK_COLORMAP;
993     XFree((char *)stdcolormaps);
994     return 0;
995 }
996 
997 /* ARGSUSED */
998 static int
setFontSet(icp,value,len,order,nest,op)999 setFontSet(icp, value, len, order, nest, op)
1000 IMIC *icp;
1001 char *value;
1002 int len;
1003 int order;
1004 int nest;
1005 int op;
1006 {
1007     IMPSAttributes *ap;
1008     unsigned int name_list_len;
1009     char *name_list;
1010 
1011     TRACE(("imlib:setFontSet()\n"));
1012 
1013     if (len < 2) {
1014 	badSizeError(icp, IMBadName);
1015 	return -1;
1016     }
1017     name_list_len = getC16(value, order);
1018     if (2 + name_list_len > len) {
1019 	badSizeError(icp, IMBadName);
1020 	return -1;
1021     }
1022 
1023     if ((ap = getPSPtr(icp, nest)) == NULL) {
1024 	unnestedError(icp);
1025 	return -1;
1026     }
1027 
1028     name_list = XtMalloc(name_list_len + 1);
1029     bcopy(value + 2, name_list, name_list_len);
1030     name_list[name_list_len] = '\0';
1031     TRACE(("\tfontset: %s\n", name_list));
1032 
1033     if (ap->set_mask & ATTR_MASK_FONT_SET) {
1034 	if (!strcmp(name_list, ap->font_set)) {
1035 	    XtFree(name_list);
1036 	} else {
1037 	    ap->change_mask |= ATTR_MASK_FONT_SET;
1038 	    if (ap->font_set != IMDefaultFontSet(icp->im)) {
1039 		XtFree(ap->font_set);
1040 	    }
1041 	    ap->font_set = name_list;
1042 	}
1043     } else {
1044 	ap->font_set = name_list;
1045 	ap->set_mask |= ATTR_MASK_FONT_SET;
1046 	ap->change_mask |= ATTR_MASK_FONT_SET;
1047     }
1048     return 0;
1049 }
1050 
1051 /* ARGSUSED */
1052 static int
setPreeditState(icp,value,len,order,nest,op)1053 setPreeditState(icp, value, len, order, nest, op)
1054 IMIC *icp;
1055 char *value;
1056 int len;
1057 int order;
1058 int nest;
1059 int op;
1060 {
1061     IMCommonAttributes *ap = &icp->common_attr;
1062     unsigned long preedit_state;
1063 
1064     TRACE(("imlib:setPreeditState()\n"));
1065 
1066     CHECK_ICATTR_SIZE(4, IMBadSomething);
1067 
1068     if (nest == NEST_STATUS) {
1069 	DPRINT(("preedit state specified in a status attribute list\n"));
1070 	IMSendError(icp->im->connection, IMBadSomething,
1071 		    icp->im->id, icp->id,
1072 		    "preedit state isn't a status attribute");
1073 	return -1;
1074     }
1075 
1076     preedit_state = getC32(value, order);
1077 
1078     ap->set_mask |= ATTR_MASK_PREEDIT_STATE;
1079     ap->change_mask |= ATTR_MASK_PREEDIT_STATE;
1080     ap->preedit_state = preedit_state;
1081     return 0;
1082 }
1083 
1084 /* ARGSUSED */
1085 static int
setResetState(icp,value,len,order,nest,op)1086 setResetState(icp, value, len, order, nest, op)
1087 IMIC *icp;
1088 char *value;
1089 int len;
1090 int order;
1091 int nest;
1092 int op;
1093 {
1094     IMCommonAttributes *ap = &icp->common_attr;
1095     unsigned long reset_state;
1096 
1097     TRACE(("imlib:setResetState()\n"));
1098 
1099     CHECK_ICATTR_SIZE(4, IMBadSomething);
1100 
1101     reset_state = getC32(value, order);
1102 
1103     ap->set_mask |= ATTR_MASK_RESET_STATE;
1104     ap->change_mask |= ATTR_MASK_RESET_STATE;
1105     ap->reset_state = reset_state;
1106     return 0;
1107 }
1108 
1109 
1110 /*
1111  * Functions getting IC attributes
1112  */
1113 
1114 static int
getICValues(icp,data,len,nest,offset,sepp)1115 getICValues(icp, data, len, nest, offset, sepp)
1116 IMIC *icp;
1117 char *data;
1118 int len;
1119 int nest;		/* NEST_NONE, NEST_PREEDIT or NEST_STATUS */
1120 int offset;		/* request offset */
1121 int *sepp;		/* Out: true if ended with a nested list separator */
1122 {
1123     unsigned int id;		/* attribute ID */
1124     ICAttribute *attrp;
1125     IMConnection *conn = icp->im->connection;
1126     int byte_order = conn->byte_order;
1127     char *org_data = data;
1128     int r;
1129 
1130     TRACE(("imlib:getICValues()\n"));
1131 
1132     while (len >= 2) {
1133 	id = getC16(data, byte_order);
1134 	data += 2;
1135 	len -= 2;
1136 
1137 	if (id > numIcAttributes) {
1138 	    /* invalid attribute ID */
1139 	    DPRINT(("invalid IC attribute ID (%d) specified\n", id));
1140 	    IMCancelRequest(conn, offset);
1141 	    IMSendError(conn, IMBadSomething, icp->im->id, icp->id,
1142 			"invalid IC attribute ID");
1143 	    return -1;
1144 	}
1145 
1146 	attrp = &icAttributes[id];
1147 	if (attrp->type == TYPE_SEPARATOR) {
1148 	    /* nested list separator */
1149 	    *sepp = 1;
1150 	    return data - org_data;
1151 	}
1152 
1153 	if (!(attrp->valid_ops & OP_G)) {
1154 	    DPRINT(("invalid operation (get) for IC attr %d\n", id));
1155 	    IMCancelRequest(conn, offset);
1156 	    IMSendError(conn, IMBadSomething, icp->im->id, icp->id,
1157 			"invalid operation (ICGetValues) for this attribute");
1158 	    return -1;
1159 	}
1160 
1161 	r = (*attrp->get_proc)(icp, id, nest, offset, data, len);
1162 	/*
1163 	 * The return value of get_proc is usually 0, indicating success.
1164 	 * If it is less than 0, there are some errors.
1165 	 * If it is greater than 0,
1166 	 */
1167 	if (r < 0) return -1;
1168 
1169 	data += r;		/* r is extra offset */
1170 	len -= r;
1171     }
1172     *sepp = 0;
1173     return data - org_data;
1174 }
1175 
1176 /* ARGSUSED */
1177 static int
getPSAttributes(icp,id,nest,offset,data,len)1178 getPSAttributes(icp, id, nest, offset, data, len)
1179 IMIC *icp;
1180 unsigned int id;
1181 int nest;
1182 int offset;
1183 char *data;
1184 int len;
1185 {
1186     IMConnection *conn = icp->im->connection;
1187     unsigned int length;
1188     int length_offset;
1189     int attr_offset;
1190     int nested_separator;
1191     int r;
1192 
1193     IMPutC16(conn, id);
1194 
1195     length_offset = IMWritePos(conn);
1196     IMPutC16(conn, 0);		/* dummy -- overwritten afterwards */
1197 
1198     attr_offset = IMWritePos(conn);
1199 
1200     r = getICValues(icp, data, len, nest, offset, &nested_separator);
1201     if (r < 0) return -1;
1202     if (!nested_separator) {
1203 	/* there's no nested list separator */
1204 	DPRINT(("nested list doesn't end with separator\n"));
1205 	/*
1206 	 * X11R6 Xlib sends nested attribute list which has no
1207 	 * separator at its end.  In order to accommodate to it,
1208 	 * don't send error for that.
1209 	 */
1210 #ifdef notdef
1211 	IMCancelRequest(conn, offset);
1212 	IMSendError(conn, IMBadSomething, icp->im->id, icp->id,
1213 		    "corrupted nested list");
1214 	return -1;
1215 #endif
1216     }
1217 
1218     /*
1219      * Nested list is written on the output buffer.
1220      * Calculate the length of the list.
1221      */
1222     length = IMWritePos(conn) - attr_offset;
1223 
1224     /* rewrite attribute length field */
1225     IMRewriteC16(conn, length_offset, length);
1226     IMPutPad(conn);
1227 
1228     return r;
1229 }
1230 
1231 /* ARGSUSED */
1232 static int
getPreeditAttributes(icp,id,nest,offset,data,len)1233 getPreeditAttributes(icp, id, nest, offset, data, len)
1234 IMIC *icp;
1235 unsigned int id;
1236 int nest;		/* unused */
1237 int offset;
1238 char *data;
1239 int len;
1240 {
1241     TRACE(("imlib:getPreeditAttributes()\n"));
1242     return getPSAttributes(icp, id, NEST_PREEDIT, offset, data, len);
1243 }
1244 
1245 /* ARGSUSED */
1246 static int
getStatusAttributes(icp,id,nest,offset,data,len)1247 getStatusAttributes(icp, id, nest, offset, data, len)
1248 IMIC *icp;
1249 unsigned int id;
1250 int nest;		/* unused */
1251 int offset;
1252 char *data;
1253 int len;
1254 {
1255     TRACE(("imlib:getStatusAttributes()\n"));
1256     return getPSAttributes(icp, id, NEST_STATUS, offset, data, len);
1257 }
1258 
1259 /* ARGSUSED */
1260 static int
getInputStyle(icp,id,nest,offset,data,len)1261 getInputStyle(icp, id, nest, offset, data, len)
1262 IMIC *icp;
1263 unsigned int id;
1264 int nest;
1265 int offset;
1266 char *data;
1267 int len;
1268 {
1269     IMConnection *conn = icp->im->connection;
1270 
1271     TRACE(("imlib:getInputStyle()\n"));
1272 
1273     /*
1274      * Input style must have been specified, (and validated)
1275      * at IC creation.  No need for checking.
1276      */
1277     IMPutC16(conn, id);		/* attribute ID */
1278     IMPutC16(conn, 4);		/* value length */
1279     IMPutC32(conn, icp->common_attr.input_style);
1280     return 0;
1281 }
1282 
1283 /* ARGSUSED */
1284 static int
getClientWindow(icp,id,nest,offset,data,len)1285 getClientWindow(icp, id, nest, offset, data, len)
1286 IMIC *icp;
1287 unsigned int id;
1288 int nest;
1289 int offset;
1290 char *data;
1291 int len;
1292 {
1293     IMConnection *conn = icp->im->connection;
1294 
1295     TRACE(("imlib:getClientWindow()\n"));
1296 
1297     if (icp->common_attr.set_mask & ATTR_MASK_CLIENT) {
1298 	IMPutC16(conn, id);		/* attribute ID */
1299 	IMPutC16(conn, 4);		/* value length */
1300 	IMPutC32(conn, icp->common_attr.client);
1301 	return 0;
1302     } else {
1303 	/* no default is available */
1304 	DPRINT(("getClientWindow without setting client window previously\n"));
1305 	IMCancelRequest(conn, offset);
1306 	IMSendError(conn, IMBadClientWindow, icp->im->id, icp->id,
1307 		    "client window not specified yet");
1308 	return -1;
1309     }
1310 }
1311 
1312 /* ARGSUSED */
1313 static int
getFocusWindow(icp,id,nest,offset,data,len)1314 getFocusWindow(icp, id, nest, offset, data, len)
1315 IMIC *icp;
1316 unsigned int id;
1317 int nest;
1318 int offset;
1319 char *data;
1320 int len;
1321 {
1322     IMConnection *conn = icp->im->connection;
1323 
1324     TRACE(("imlib:getFocusWindow()\n"));
1325 
1326     if (!(icp->common_attr.set_mask & ATTR_MASK_FOCUS)) {
1327 	/* fill default value */
1328 	fillCommonDefault(icp, (unsigned long)ATTR_MASK_FOCUS);
1329     }
1330 
1331     if (icp->common_attr.set_mask & ATTR_MASK_FOCUS) {
1332 	IMPutC16(conn, id);		/* attribute ID */
1333 	IMPutC16(conn, 4);		/* value length */
1334 	IMPutC32(conn, icp->common_attr.focus);
1335 	return 0;
1336     } else {
1337 	/*
1338 	 * Couldn't get the default value.  That is, neither
1339 	 * focus window nor client window is specified yet.
1340 	 */
1341 	DPRINT(("getFocusWindow without setting focus/client window previously\n"));
1342 	IMCancelRequest(conn, offset);
1343 	IMSendError(conn, IMBadFocusWindow, icp->im->id, icp->id,
1344 		    "neither of client/focus window not specified yet");
1345 	return -1;
1346     }
1347 }
1348 
1349 /* ARGSUSED */
1350 static int
getFilterEvents(icp,id,nest,offset,data,len)1351 getFilterEvents(icp, id, nest, offset, data, len)
1352 IMIC *icp;
1353 unsigned int id;
1354 int nest;
1355 int offset;
1356 char *data;
1357 int len;
1358 {
1359     IMConnection *conn = icp->im->connection;
1360 
1361     TRACE(("imlib:getFilterEvents()\n"));
1362 
1363     /* We need only Key events */
1364     IMPutC16(conn, id);		/* attribute ID */
1365     IMPutC16(conn, 4);		/* value length */
1366     IMPutC32(conn, KeyPressMask | KeyReleaseMask);
1367     return 0;
1368 }
1369 
1370 /* ARGSUSED */
1371 static int
getArea(icp,id,nest,offset,data,len)1372 getArea(icp, id, nest, offset, data, len)
1373 IMIC *icp;
1374 unsigned int id;
1375 int nest;
1376 int offset;
1377 char *data;
1378 int len;
1379 {
1380     IMConnection *conn = icp->im->connection;
1381     IMPSAttributes *ap;
1382 
1383     TRACE(("imlib:getArea()\n"));
1384 
1385     if ((ap = getPSPtr(icp, nest)) == NULL) {
1386 	IMCancelRequest(conn, offset);
1387 	unnestedError(icp);
1388 	return -1;
1389     }
1390 
1391     if (!(ap->set_mask & ATTR_MASK_AREA)) {
1392 	fillPSDefault(icp, nest, (unsigned long)ATTR_MASK_AREA);
1393     }
1394 
1395     IMPutC16(conn, id);		/* attribute ID */
1396     IMPutC16(conn, 8);		/* value length */
1397     IMPutI16(conn, ap->area.x);
1398     IMPutI16(conn, ap->area.y);
1399     IMPutC16(conn, ap->area.width);
1400     IMPutC16(conn, ap->area.height);
1401     return 0;
1402 }
1403 
1404 /* ARGSUSED */
1405 static int
getAreaNeeded(icp,id,nest,offset,data,len)1406 getAreaNeeded(icp, id, nest, offset, data, len)
1407 IMIC *icp;
1408 unsigned int id;
1409 int nest;
1410 int offset;
1411 char *data;
1412 int len;
1413 {
1414     IMConnection *conn = icp->im->connection;
1415     IMPSAttributes *ap;
1416 
1417     TRACE(("imlib:getAreaNeeded()\n"));
1418 
1419     if ((ap = getPSPtr(icp, nest)) == NULL) {
1420 	IMCancelRequest(conn, offset);
1421 	unnestedError(icp);
1422 	return -1;
1423     }
1424 
1425     /*
1426      * Always call fillPSDefault to get appropriate AreaNeeded value.
1427      */
1428     fillPSDefault(icp, nest, (unsigned long)ATTR_MASK_AREA_NEEDED);
1429 
1430     TRACE(("\tarea needed: %d, %d, %d, %d\n",
1431 	   ap->area_needed.x, ap->area_needed.y,
1432 	   ap->area_needed.width, ap->area_needed.height));
1433 
1434     IMPutC16(conn, id);		/* attribute ID */
1435     IMPutC16(conn, 8);		/* value length */
1436     IMPutI16(conn, ap->area_needed.x);
1437     IMPutI16(conn, ap->area_needed.y);
1438     IMPutC16(conn, ap->area_needed.width);
1439     IMPutC16(conn, ap->area_needed.height);
1440     return 0;
1441 }
1442 
1443 /* ARGSUSED */
1444 static int
getSpotLocation(icp,id,nest,offset,data,len)1445 getSpotLocation(icp, id, nest, offset, data, len)
1446 IMIC *icp;
1447 unsigned int id;
1448 int nest;
1449 int offset;
1450 char *data;
1451 int len;
1452 {
1453     IMConnection *conn = icp->im->connection;
1454     IMPSAttributes *ap = &icp->preedit_attr;
1455 
1456     TRACE(("imlib:getSpotLocation()\n"));
1457 
1458     if (nest == NEST_STATUS) {
1459 	IMCancelRequest(conn, offset);
1460 	IMSendError(conn, IMBadSomething, icp->im->id, icp->id,
1461 		    "spot location isn't a status attribute");
1462 	return -1;
1463     }
1464 
1465     if (!(ap->set_mask & ATTR_MASK_SPOT_LOCATION)) {
1466 	fillPSDefault(icp, NEST_PREEDIT,
1467 		      (unsigned long)ATTR_MASK_SPOT_LOCATION);
1468     }
1469 
1470     IMPutC16(conn, id);		/* attribute ID */
1471     IMPutC16(conn, 4);		/* value length */
1472     IMPutI16(conn, ap->spot_location.x);
1473     IMPutI16(conn, ap->spot_location.y);
1474     return 0;
1475 }
1476 
1477 /* ARGSUSED */
1478 static int
getColormap(icp,id,nest,offset,data,len)1479 getColormap(icp, id, nest, offset, data, len)
1480 IMIC *icp;
1481 unsigned int id;
1482 int nest;
1483 int offset;
1484 char *data;
1485 int len;
1486 {
1487     IMConnection *conn = icp->im->connection;
1488     IMPSAttributes *ap;
1489 
1490     TRACE(("imlib:getColormap()\n"));
1491 
1492     if ((ap = getPSPtr(icp, nest)) == NULL) {
1493 	IMCancelRequest(conn, offset);
1494 	unnestedError(icp);
1495 	return -1;
1496     }
1497 
1498     if (!(ap->set_mask & ATTR_MASK_COLORMAP)) {
1499 	fillPSDefault(icp, nest, (unsigned long)ATTR_MASK_COLORMAP);
1500     }
1501 
1502     IMPutC16(conn, id);		/* attribute ID */
1503     IMPutC16(conn, 4);		/* value length */
1504     IMPutC32(conn, ap->colormap);
1505     return 0;
1506 }
1507 
1508 /* ARGSUSED */
1509 static int
getStdColormap(icp,id,nest,offset,data,len)1510 getStdColormap(icp, id, nest, offset, data, len)
1511 IMIC *icp;
1512 unsigned int id;
1513 int nest;
1514 int offset;
1515 char *data;
1516 int len;
1517 {
1518     IMConnection *conn = icp->im->connection;
1519     IMPSAttributes *ap;
1520     Atom colormap_name;
1521 
1522     TRACE(("imlib:getStdColormap()\n"));
1523 
1524     if ((ap = getPSPtr(icp, nest)) == NULL) {
1525 	IMCancelRequest(conn, offset);
1526 	unnestedError(icp);
1527 	return -1;
1528     }
1529 
1530     if (ap->set_mask & ATTR_MASK_STD_COLORMAP) {
1531 	colormap_name = ap->std_colormap;
1532     } else {
1533 	/* what to do? */
1534 	colormap_name = None;
1535 	DPRINT(("client asks standard colormap, but not specified\n"));
1536     }
1537 
1538     IMPutC16(conn, id);		/* attribute ID */
1539     IMPutC16(conn, 4);		/* value length */
1540     IMPutC32(conn, colormap_name);
1541     return 0;
1542 }
1543 
1544 /* ARGSUSED */
1545 static int
getForeground(icp,id,nest,offset,data,len)1546 getForeground(icp, id, nest, offset, data, len)
1547 IMIC *icp;
1548 unsigned int id;
1549 int nest;
1550 int offset;
1551 char *data;
1552 int len;
1553 {
1554     IMConnection *conn = icp->im->connection;
1555     IMPSAttributes *ap;
1556 
1557     TRACE(("imlib:getForeground()\n"));
1558 
1559     if ((ap = getPSPtr(icp, nest)) == NULL) {
1560 	IMCancelRequest(conn, offset);
1561 	unnestedError(icp);
1562 	return -1;
1563     }
1564 
1565     if (!(ap->set_mask & ATTR_MASK_FOREGROUND)) {
1566 	fillPSDefault(icp, nest, (unsigned long)ATTR_MASK_FOREGROUND);
1567     }
1568 
1569     IMPutC16(conn, id);		/* attribute ID */
1570     IMPutC16(conn, 4);		/* value length */
1571     IMPutC32(conn, ap->foreground);
1572     return 0;
1573 }
1574 
1575 /* ARGSUSED */
1576 static int
getBackground(icp,id,nest,offset,data,len)1577 getBackground(icp, id, nest, offset, data, len)
1578 IMIC *icp;
1579 unsigned int id;
1580 int nest;
1581 int offset;
1582 char *data;
1583 int len;
1584 {
1585     IMConnection *conn = icp->im->connection;
1586     IMPSAttributes *ap;
1587 
1588     TRACE(("imlib:getBackground()\n"));
1589 
1590     if ((ap = getPSPtr(icp, nest)) == NULL) {
1591 	IMCancelRequest(conn, offset);
1592 	unnestedError(icp);
1593 	return -1;
1594     }
1595 
1596     if (!(ap->set_mask & ATTR_MASK_BACKGROUND)) {
1597 	fillPSDefault(icp, nest, (unsigned long)ATTR_MASK_BACKGROUND);
1598     }
1599 
1600     IMPutC16(conn, id);		/* attribute ID */
1601     IMPutC16(conn, 4);		/* value length */
1602     IMPutC32(conn, ap->background);
1603     return 0;
1604 }
1605 
1606 /* ARGSUSED */
1607 static int
getBgPixmap(icp,id,nest,offset,data,len)1608 getBgPixmap(icp, id, nest, offset, data, len)
1609 IMIC *icp;
1610 unsigned int id;
1611 int nest;
1612 int offset;
1613 char *data;
1614 int len;
1615 {
1616     IMConnection *conn = icp->im->connection;
1617     IMPSAttributes *ap;
1618 
1619     TRACE(("imlib:getBgPixmap()\n"));
1620 
1621     if ((ap = getPSPtr(icp, nest)) == NULL) {
1622 	IMCancelRequest(conn, offset);
1623 	unnestedError(icp);
1624 	return -1;
1625     }
1626 
1627     if (!(ap->set_mask & ATTR_MASK_BG_PIXMAP)) {
1628 	fillPSDefault(icp, nest, (unsigned long)ATTR_MASK_BG_PIXMAP);
1629     }
1630 
1631     IMPutC16(conn, id);		/* attribute ID */
1632     IMPutC16(conn, 4);		/* value length */
1633     IMPutC32(conn, ap->bg_pixmap);
1634     return 0;
1635 }
1636 
1637 /* ARGSUSED */
1638 static int
getFontSet(icp,id,nest,offset,data,len)1639 getFontSet(icp, id, nest, offset, data, len)
1640 IMIC *icp;
1641 unsigned int id;
1642 int nest;
1643 int offset;
1644 char *data;
1645 int len;
1646 {
1647     IMConnection *conn = icp->im->connection;
1648     IMPSAttributes *ap;
1649     int name_len;
1650 
1651     TRACE(("imlib:getFontSet()\n"));
1652 
1653     if ((ap = getPSPtr(icp, nest)) == NULL) {
1654 	IMCancelRequest(conn, offset);
1655 	unnestedError(icp);
1656 	return -1;
1657     }
1658 
1659     if (!(ap->set_mask & ATTR_MASK_FONT_SET)) {
1660 	fillPSDefault(icp, nest, (unsigned long)ATTR_MASK_FONT_SET);
1661     }
1662 
1663     name_len = strlen(ap->font_set);
1664 
1665     IMPutC16(conn, id);		/* attribute ID */
1666 
1667     IMPutC16(conn, (unsigned int)name_len);	/* value length */
1668     IMPutString(conn, ap->font_set, name_len);
1669     IMPutPad(conn);
1670     return 0;
1671 }
1672 
1673 /* ARGSUSED */
1674 static int
getLineSpace(icp,id,nest,offset,data,len)1675 getLineSpace(icp, id, nest, offset, data, len)
1676 IMIC *icp;
1677 unsigned int id;
1678 int nest;
1679 int offset;
1680 char *data;
1681 int len;
1682 {
1683     IMConnection *conn = icp->im->connection;
1684     IMPSAttributes *ap;
1685 
1686     TRACE(("imlib:getLineSpace()\n"));
1687 
1688     if ((ap = getPSPtr(icp, nest)) == NULL) {
1689 	IMCancelRequest(conn, offset);
1690 	unnestedError(icp);
1691 	return -1;
1692     }
1693 
1694     if (!(ap->set_mask & ATTR_MASK_LINESPACE)) {
1695 	fillPSDefault(icp, nest, (unsigned long)ATTR_MASK_LINESPACE);
1696     }
1697 
1698     IMPutC16(conn, id);		/* attribute ID */
1699     IMPutC16(conn, 4);	/* value length */
1700     IMPutC32(conn, (unsigned long)ap->line_space);
1701     return 0;
1702 }
1703 
1704 /* ARGSUSED */
1705 static int
getCursor(icp,id,nest,offset,data,len)1706 getCursor(icp, id, nest, offset, data, len)
1707 IMIC *icp;
1708 unsigned int id;
1709 int nest;
1710 int offset;
1711 char *data;
1712 int len;
1713 {
1714     IMConnection *conn = icp->im->connection;
1715     IMPSAttributes *ap;
1716 
1717     TRACE(("imlib:getCursor()\n"));
1718 
1719     if ((ap = getPSPtr(icp, nest)) == NULL) {
1720 	IMCancelRequest(conn, offset);
1721 	unnestedError(icp);
1722 	return -1;
1723     }
1724 
1725     if (!(ap->set_mask & ATTR_MASK_CURSOR)) {
1726 	fillPSDefault(icp, nest, (unsigned long)ATTR_MASK_CURSOR);
1727     }
1728 
1729     IMPutC16(conn, id);		/* attribute ID */
1730     IMPutC16(conn, 4);		/* value length */
1731     IMPutC32(conn, ap->cursor);
1732     return 0;
1733 }
1734 
1735 /* ARGSUSED */
1736 static int
getPreeditState(icp,id,nest,offset,data,len)1737 getPreeditState(icp, id, nest, offset, data, len)
1738 IMIC *icp;
1739 unsigned int id;
1740 int nest;
1741 int offset;
1742 char *data;
1743 int len;
1744 {
1745     IMConnection *conn = icp->im->connection;
1746 
1747     TRACE(("imlib:getPreeditState()\n"));
1748 
1749     if (nest == NEST_STATUS) {
1750 	IMCancelRequest(conn, offset);
1751 	IMSendError(conn, IMBadSomething, icp->im->id, icp->id,
1752 		    "preedit state isn't a status attribute");
1753 	return -1;
1754     }
1755 
1756     IMPutC16(conn, id);		/* attribute ID */
1757     IMPutC16(conn, 4);		/* value length */
1758     IMPutC32(conn,
1759 	     (icp->state & IC_CONVERTING) ?
1760 	     XIMPreeditEnable : XIMPreeditDisable);
1761     return 0;
1762 }
1763 
1764 /* ARGSUSED */
1765 static int
getResetState(icp,id,nest,offset,data,len)1766 getResetState(icp, id, nest, offset, data, len)
1767 IMIC *icp;
1768 unsigned int id;
1769 int nest;
1770 int offset;
1771 char *data;
1772 int len;
1773 {
1774     IMConnection *conn = icp->im->connection;
1775 
1776     TRACE(("imlib:getResetState()\n"));
1777 
1778     IMPutC16(conn, id);		/* attribute ID */
1779     IMPutC16(conn, 4);		/* value length */
1780     IMPutC32(conn, icp->common_attr.reset_state);
1781     return 0;
1782 }
1783 
1784 static void
changeFonts(icp,preedit)1785 changeFonts(icp, preedit)
1786 IMIC *icp;
1787 int preedit;
1788 {
1789     FontBank bank = IMFontBank(icp->im);
1790     String font_set;
1791     XFontStruct ***fontsp;
1792     int *num_fontsp;
1793 
1794     TRACE(("imlib:changeFonts()\n"));
1795 
1796     if (preedit) {
1797 	font_set = icp->preedit_attr.font_set;
1798 	fontsp = &icp->fonts;
1799 	num_fontsp = &icp->num_fonts;
1800     } else {
1801 	font_set = icp->status_attr.font_set;
1802 	fontsp = &icp->status_fonts;
1803 	num_fontsp = &icp->num_status_fonts;
1804     }
1805 
1806     /*
1807      * Unload previous fonts.
1808      */
1809     if (*num_fontsp > 0) {
1810 	FontBankFreeFonts(bank, *fontsp, *num_fontsp);
1811     }
1812 
1813     /*
1814      * Load new fonts and store them in the IC structure.
1815      */
1816     *fontsp = FontBankGet(bank, font_set, num_fontsp);
1817 }
1818 
1819 
1820 /*
1821  * Functions computing default attribute values
1822  */
1823 
1824 static void
fillCommonDefault(icp,mask)1825 fillCommonDefault(icp, mask)
1826 IMIC *icp;
1827 unsigned long mask;
1828 {
1829     IMCommonAttributes *ap = &icp->common_attr;
1830 
1831     TRACE(("imlib:fillCommonDefault()\n"));
1832 
1833     /*
1834      * Don't bother with the attributes which have been set.
1835      */
1836     mask &= ~ap->set_mask;
1837 
1838     /*
1839      * The attributes that have default value are FocusWindow,
1840      * PreeditState and ResetState.
1841      */
1842     if (mask & ATTR_MASK_FOCUS) {
1843 	/* if ClientWindow is not set... no way */
1844 	if (mask & ATTR_MASK_CLIENT) {
1845 	    ap->focus = ap->client;
1846 	    ap->set_mask |= ATTR_MASK_FOCUS;
1847 	    icp->focus_profile = icp->client_profile;
1848 	    TRACE(("\tdefault focus window: %08lx\n", ap->focus));
1849 	}
1850     }
1851     if (mask & ATTR_MASK_PREEDIT_STATE) {
1852 	/* unless the client specified, we should start with disabled state. */
1853 	ap->set_mask |= ATTR_MASK_PREEDIT_STATE;
1854 	ap->reset_state = XIMPreeditDisable;
1855     }
1856     if (mask & ATTR_MASK_RESET_STATE) {
1857 	/* the default reset state must be the initial state. */
1858 	ap->set_mask |= ATTR_MASK_RESET_STATE;
1859 	ap->reset_state = XIMInitialState;
1860     }
1861 }
1862 
1863 static int
getNaturalLineSpace(icp,preedit)1864 getNaturalLineSpace(icp, preedit)
1865 IMIC *icp;
1866 int preedit;
1867 {
1868     XFontStruct **fonts;
1869     int num_fonts;
1870     int max_ascent = 0, max_descent = 0;
1871     int i;
1872 
1873     changeFonts(icp, preedit);
1874     if (preedit) {
1875 	fonts = icp->fonts;
1876 	num_fonts = icp->num_fonts;
1877     } else {
1878 	fonts = icp->status_fonts;
1879 	num_fonts = icp->num_status_fonts;
1880     }
1881 
1882     for (i = 0; i < num_fonts; i++) {
1883 	XFontStruct *font = fonts[i];
1884 	if (max_ascent < font->ascent) max_ascent = font->ascent;
1885 	if (max_descent < font->descent) max_descent = font->descent;
1886     }
1887 
1888     if (max_ascent + max_descent < MIN_LINE_SPACING) {
1889 	return MIN_LINE_SPACING;
1890     } else {
1891 	return max_ascent + max_descent;
1892     }
1893 }
1894 
1895 static void
fillPSDefault(icp,type,mask)1896 fillPSDefault(icp, type, mask)
1897 IMIC *icp;
1898 int type;	/* NEST_PREEDIT or NEST_STATUS */
1899 unsigned long mask;
1900 {
1901     IMPSAttributes *ap;
1902     IMConnection *conn = icp->im->connection;
1903     Widget pw = conn->proto_widget;
1904     int preedit;
1905 #ifdef DEBUG
1906     char *typename = (type == NEST_PREEDIT) ? "preedit" : "status";
1907 #endif
1908 
1909     TRACE(("imlib:fillPSDefault(%s)\n", typename));
1910 
1911     preedit = (type == NEST_PREEDIT);
1912     ap = preedit ? &icp->preedit_attr : &icp->status_attr;
1913 
1914     /*
1915      * Don't bother with the attributes which have been set.
1916      * But area_needed needs to be computed each time (to get
1917      * correct X and Y coordinates).
1918      */
1919     mask &= ~ap->set_mask | ATTR_MASK_AREA_NEEDED;
1920 
1921     if (mask & ATTR_MASK_AREA) {
1922 	computeAreaForQuery(icp);
1923 	ap->set_mask |= ATTR_MASK_AREA;
1924 	DDPRINT(5, ("\tdefault %s area: %d,%d,%d,%d\n", typename,
1925 		    ap->area.x, ap->area.y, ap->area.width, ap->area.height));
1926     }
1927     if (mask & ATTR_MASK_FOREGROUND) {
1928 	ap->foreground = IMDefaultForeground(pw);
1929 	ap->set_mask |= ATTR_MASK_FOREGROUND;
1930 	DDPRINT(5, ("\tdefault %s foreground: %ld\n",
1931 		    typename, ap->foreground));
1932     }
1933     if (mask & ATTR_MASK_BACKGROUND) {
1934 	ap->background = IMDefaultBackground(pw);
1935 	ap->set_mask |= ATTR_MASK_BACKGROUND;
1936 	DDPRINT(5, ("\tdefault %s background: %ld\n",
1937 		    typename, ap->background));
1938     }
1939     if (mask & ATTR_MASK_COLORMAP) {
1940 	ap->colormap = pw->core.colormap;
1941 	ap->set_mask |= ATTR_MASK_COLORMAP;
1942 	DDPRINT(5, ("\tdefault %s colormap: %08lx\n",
1943 		    typename, ap->colormap));
1944     }
1945     if (mask & ATTR_MASK_STD_COLORMAP) {
1946 	/* you can't fill default. what to do? */
1947 	DDPRINT(5, ("\tdefault %s std colormap: N/A\n", typename));
1948     }
1949     if (mask & ATTR_MASK_BG_PIXMAP) {
1950 	ap->bg_pixmap = None;
1951 	ap->set_mask |= ATTR_MASK_BG_PIXMAP;
1952 	DDPRINT(5, ("\tdefault %s background pixmap: None\n", typename));
1953     }
1954     if (mask & ATTR_MASK_LINESPACE) {
1955 	if (!(ap->set_mask & ATTR_MASK_FONT_SET)) {
1956 	    fillPSDefault(icp, type, (unsigned long)ATTR_MASK_FONT_SET);
1957 	}
1958 	ap->line_space = getNaturalLineSpace(icp, type == NEST_PREEDIT);
1959 	ap->set_mask |= ATTR_MASK_LINESPACE;
1960 	DDPRINT(5, ("\tdefault line space: %d\n", ap->line_space));
1961     }
1962     if (mask & ATTR_MASK_CURSOR) {
1963 	ap->cursor = None;
1964 	ap->set_mask |= ATTR_MASK_CURSOR;
1965 	DDPRINT(5, ("\tdefault %s cursor: None\n", typename));
1966     }
1967     if (mask & ATTR_MASK_AREA_NEEDED) {
1968 	computeAreaNeeded(icp);
1969 	DDPRINT(5, ("\t%s area_needed: %d,%d,%d,%d\n", typename,
1970 		    ap->area_needed.x, ap->area_needed.y,
1971 		    ap->area_needed.width, ap->area_needed.height));
1972     }
1973     if (mask & ATTR_MASK_FONT_SET) {
1974 	ap->font_set = IMDefaultFontSet(icp->im);
1975 	ap->set_mask |= ATTR_MASK_FONT_SET;
1976 	DDPRINT(5, ("\tdefault %s fontset: %s\n", typename, ap->font_set));
1977     }
1978     if (mask & ATTR_MASK_SPOT_LOCATION) {
1979 	ap->spot_location.x = ap->spot_location.y = 0;
1980 	ap->set_mask |= ATTR_MASK_SPOT_LOCATION;
1981 	DDPRINT(5, ("\tdefault spot location: %d, %d\n",
1982 		    ap->spot_location.x, ap->spot_location.y));
1983     }
1984 }
1985 
1986 /*
1987  * Function validating attribute values
1988  */
1989 
1990 static int
validateCommonAttr(icp,checkonly)1991 validateCommonAttr(icp, checkonly)
1992 IMIC *icp;
1993 int checkonly;
1994 {
1995     IMCommonAttributes *ap = &icp->common_attr;
1996     IMConnection *conn = icp->im->connection;
1997     unsigned long mask = ap->change_mask;
1998     int ret = 0;
1999 
2000     TRACE(("imlib:validateCommonAttr()\n"));
2001 
2002     mask &= ap->set_mask;
2003 
2004 #define SENDERROR(code, msg) \
2005     if (!checkonly && ret == 0) { \
2006 	IMSendError(conn, code, icp->im->id, icp->id, msg); ret = -1; \
2007     }
2008 
2009     if (mask & ATTR_MASK_INPUT_STYLE) {
2010 	XIMStyle xstyle = icp->common_attr.input_style;
2011 	InputStyle *isp = styles;
2012 
2013 	while (isp->xim_style != 0) {
2014 	    if (isp->xim_style == xstyle) break;
2015 	    isp++;
2016 	}
2017 	if (isp->xim_style == 0) {
2018 	    DPRINT(("unsupported input style\n"));
2019 	    ap->set_mask &= ~ATTR_MASK_INPUT_STYLE;
2020 	    SENDERROR(IMBadStyle, "unsupported input style");
2021 	} else {
2022 	    icp->style = isp->conversion_style;
2023 	}
2024     }
2025     if (mask & ATTR_MASK_CLIENT) {
2026 	if (!validateClientWindow(icp)) {
2027 	    DPRINT(("invalid client window ID\n"));
2028 	    ap->set_mask &= ~ATTR_MASK_CLIENT;
2029 	    SENDERROR(IMBadClientWindow, "invalid client window ID");
2030 	}
2031     }
2032     if (mask & ATTR_MASK_FOCUS) {
2033 	if (!validateFocusWindow(icp)) {
2034 	    DPRINT(("invalid focus window ID\n"));
2035 	    ap->set_mask &= ~ATTR_MASK_FOCUS;
2036 	    SENDERROR(IMBadFocusWindow, "invalid focus window ID");
2037 	}
2038     }
2039     if (mask & ATTR_MASK_PREEDIT_STATE) {
2040 	unsigned long preedit_state = ap->preedit_state;
2041 
2042 	if (preedit_state != XIMPreeditEnable &&
2043 	    preedit_state != XIMPreeditDisable) {
2044 	    DPRINT(("invalid preedit state\n"));
2045 	    ap->set_mask &= ~ATTR_MASK_PREEDIT_STATE;
2046 	    SENDERROR(IMBadSomething, "invalid preedit state");
2047 	}
2048     }
2049     if (mask & ATTR_MASK_RESET_STATE) {
2050 	unsigned long reset_state = ap->reset_state;
2051 
2052 	if (reset_state != XIMInitialState &&
2053 	    reset_state != XIMPreserveState) {
2054 	    /*
2055 	     * Xlib document says invalid values should be interpreted as
2056 	     * XIMInitialState.
2057 	     */
2058 	    DPRINT(("invalid reset state -- forcing initial state\n"));
2059 	    ap->reset_state = XIMInitialState;
2060 	}
2061     }
2062 
2063     return ret;
2064 #undef SENDERROR
2065 }
2066 
2067 static int
validatePSAttr(icp,type,checkonly)2068 validatePSAttr(icp, type, checkonly)
2069 IMIC *icp;
2070 int type;
2071 int checkonly;
2072 {
2073     /*
2074      * Check validity of preedit/status attribute values.
2075      * 'type' is either NEST_PREEDIT or NEST_STATUS, indicating
2076      * whether preedit or status attributes are to be checked.
2077      * 'mask' is the attribute mask to be checked.
2078      * If all the attributes are valid, this function return 0.
2079      * Otherwise it issues an error message for the first invalid
2080      * value detected, and returns -1.
2081      */
2082     IMPSAttributes *ap;
2083     IMConnection *conn = icp->im->connection;
2084     unsigned long mask;
2085     int preedit;
2086     int ret = 0;
2087 
2088     TRACE(("imlib:validatePSAttr()\n"));
2089 
2090     preedit = (type == NEST_PREEDIT);
2091     ap = preedit ? &icp->preedit_attr : &icp->status_attr;
2092 
2093     /* do not check unset attributes */
2094     mask = ap->change_mask & ap->set_mask;
2095 
2096 #define SENDERROR(code, msg) \
2097     if (!checkonly && ret == 0) { \
2098 	IMSendError(conn, code, icp->im->id, icp->id, msg); ret = -1; \
2099     }
2100 
2101     if (mask & ATTR_MASK_AREA) {
2102 	if (ap->area.width == 0 || ap->area.height == 0) {
2103 	    ap->set_mask &= ~ATTR_MASK_AREA;
2104 	    DPRINT(("zero area width/height\n"));
2105 	    SENDERROR(IMBadArea, "invalid area width/height");
2106 	}
2107     }
2108 
2109 #ifdef notdef
2110     if (mask & ATTR_MASK_COLORMAP) {
2111     }
2112 
2113     if (mask & ATTR_MASK_BG_PIXMAP) {
2114     }
2115 #endif
2116 
2117     if (mask & ATTR_MASK_LINESPACE) {
2118 	if (ap->line_space < MIN_LINE_SPACING) {
2119 	    ap->set_mask &= ~ATTR_MASK_LINESPACE;
2120 	    /*
2121 	     * we don't send error message in this case, because
2122 	     * there exist some applications which send invalid line
2123 	     * spacing and we don't want to break them.
2124 	     */
2125 	    DPRINT(("line space too small %d\n", ap->line_space));
2126 	}
2127     }
2128 
2129 #ifdef notdef
2130     if (mask & ATTR_MASK_CURSOR) {
2131 	/* How should we check it? */
2132     }
2133 #endif
2134 
2135     if (mask & ATTR_MASK_AREA_NEEDED) {
2136     }
2137 #ifdef notdef
2138     if (mask & ATTR_MASK_FONT_SET) {
2139     }
2140     if (mask & ATTR_MASK_SPOT_LOCATION) {
2141     }
2142 #endif
2143 
2144     return ret;
2145 #undef SENDERROR
2146 }
2147 
2148 
2149 /*
2150  * Functions to extract necessary attributes and make conversion argument
2151  */
2152 
2153 static void
changeConversionAttributes(icp)2154 changeConversionAttributes(icp)
2155 IMIC *icp;
2156 {
2157     unsigned long mask;
2158     ConversionAttributes attr;
2159 
2160     TRACE(("imlib:changeConversionAttributes()\n"));
2161     mask = IMMakeConvAttributes(icp, &attr);
2162     CControlChangeAttributes(icp->conversion, mask, &attr);
2163 }
2164 
2165 static void
computeAreaNeeded(icp)2166 computeAreaNeeded(icp)
2167 IMIC *icp;
2168 {
2169     IMPSAttributes *pattr = &icp->preedit_attr;
2170     IMPSAttributes *sattr = &icp->status_attr;
2171     IMWindowProfile *cpr = &icp->client_profile;
2172     int width, height;
2173     int min_width, min_height;
2174     int default_status_width;
2175     int font_height;
2176 
2177     TRACE(("computeAreaNeeded()\n"));
2178 
2179     if (icp->style == IMSTYLE_SEPARATE) return;
2180 
2181     /*
2182      * Get the current dimension of the client window.
2183      */
2184     (void)validateClientWindow(icp);
2185 
2186     /*
2187      * Compute the dimensions of the status region.
2188      */
2189     fillPSDefault(icp, NEST_STATUS, (unsigned long)ATTR_MASK_LINESPACE);
2190     font_height = sattr->line_space + 2;
2191     width = height = 0;
2192     if (sattr->set_mask & ATTR_MASK_AREA_NEEDED) {
2193 	width = sattr->area_needed.width;
2194 	height = sattr->area_needed.height;
2195 	TRACE(("\tstatus areaNeeded was: (%d,%d)\n", width, height));
2196     }
2197 
2198     min_width = font_height * 3;
2199     min_height = font_height;
2200     if (min_width < MIN_AREA_WIDTH) min_width = MIN_AREA_WIDTH;
2201     if (min_height < MIN_AREA_HEIGHT) min_height = MIN_AREA_HEIGHT;
2202 
2203     if (width == 0) {
2204 	default_status_width =
2205 	    IMStatusWidth(icp->im->connection->proto_widget);
2206 	if (default_status_width > 0) {
2207 	    width = default_status_width;
2208 	} else {
2209 	    width = cpr->width / 5;		/* wild guess */
2210 	}
2211     }
2212 
2213     if (width < min_width) width = min_width;
2214     if (height < min_height) height = min_height;
2215 
2216     sattr->area_needed.x = 0;
2217     sattr->area_needed.y = cpr->height - height;
2218     sattr->area_needed.width = width;
2219     sattr->area_needed.height = height;
2220     TRACE(("\tstatus areaNeeded is now: (%d, %d, %d, %d)\n",
2221 	    sattr->area_needed.x, sattr->area_needed.y, width, height));
2222 
2223     /*
2224      * Compute the dimensions of the pre-edit region.
2225      */
2226     if (icp->style != IMSTYLE_OFF_THE_SPOT) return;
2227 
2228     fillPSDefault(icp, NEST_PREEDIT, (unsigned long)ATTR_MASK_LINESPACE);
2229     font_height = pattr->line_space + 2;
2230     width = height = 0;
2231     if (pattr->set_mask & ATTR_MASK_AREA_NEEDED) {
2232 	width = pattr->area_needed.width;
2233 	height = pattr->area_needed.height;
2234 	TRACE(("\tpreedit areaNeeded was: (%d,%d)\n",
2235 		width, height));
2236     }
2237 
2238     min_width = (cpr->width - sattr->area_needed.width) / 2;
2239     min_height = font_height;
2240     if (min_width < MIN_AREA_WIDTH) min_width = MIN_AREA_WIDTH;
2241     if (min_height < MIN_AREA_HEIGHT) min_height = MIN_AREA_HEIGHT;
2242 
2243     if (width < min_width) width = min_width;
2244     if (height < min_height) height = min_height;
2245 
2246     pattr->area_needed.x = sattr->area_needed.width;
2247     pattr->area_needed.y = cpr->height - height;
2248     pattr->area_needed.width = width;
2249     pattr->area_needed.height = height;
2250     TRACE(("\tpreedit areaNeeded is now: (%d, %d, %d, %d)\n",
2251 	    pattr->area_needed.x, pattr->area_needed.y, width, height));
2252 }
2253 
2254 static void
computeAreaForQuery(icp)2255 computeAreaForQuery(icp)
2256 IMIC *icp;
2257 {
2258     IMPSAttributes *pattr = &icp->preedit_attr;
2259     IMPSAttributes *sattr = &icp->status_attr;
2260 
2261     TRACE(("computeAreaForQuery()\n"));
2262 
2263     if (icp->style == IMSTYLE_SEPARATE) return;
2264 
2265     computeAreaNeeded(icp);
2266 
2267     if (!(pattr->set_mask & ATTR_MASK_AREA)) {
2268 	if (icp->style == IMSTYLE_OVER_THE_SPOT) {
2269 	    IMWindowProfile *fpr = &icp->focus_profile;
2270 
2271 	    pattr->area.x = 0;
2272 	    pattr->area.y = 0;
2273 	    pattr->area.width = fpr->width;
2274 	    pattr->area.height = fpr->height;
2275 	} else {	/* IMSTYLE_OFF_THE_SPOT */
2276 	    pattr->area = pattr->area_needed;
2277 	}
2278     }
2279 
2280     if (!(sattr->set_mask & ATTR_MASK_AREA)) {
2281 	sattr->area = sattr->area_needed;
2282     }
2283 }
2284 
2285 
2286 /*
2287  * Public functions
2288  */
2289 
2290 /*- IMPutIMAttrList: write list of supported IM attributes to output buffer -*/
2291 void
IMPutIMAttrList(imp)2292 IMPutIMAttrList(imp)
2293 IMIM *imp;
2294 {
2295     IMConnection *conn = imp->connection;
2296     IMAttribute *iap;
2297     int offset, list_start, list_end;
2298     int n;
2299 
2300     TRACE(("IMPutIMAttrList()\n"));
2301 
2302     offset = IMWritePos(conn);
2303     IMPutC16(conn, 0);		/* dummy. overwritten afterwards */
2304 
2305     list_start = IMWritePos(conn);
2306     for (n = 0, iap = imAttributes; n < numImAttributes; n++, iap++) {
2307 	int length;
2308 
2309 	IMPutC16(conn, (unsigned int)n);
2310 	IMPutC16(conn, (unsigned int)iap->type);
2311 	length = strlen(iap->name);
2312 	IMPutC16(conn, (unsigned int)length);
2313 	IMPutString(conn, iap->name, length);
2314 	IMPutPad(conn);
2315     }
2316     list_end = IMWritePos(conn);
2317     IMRewriteC16(conn, offset, (unsigned int)(list_end - list_start));
2318 }
2319 
2320 /*- IMPutICAttrList: write list of supported IC attributes to output buffer -*/
2321 void
IMPutICAttrList(imp)2322 IMPutICAttrList(imp)
2323 IMIM *imp;
2324 {
2325     IMConnection *conn = imp->connection;
2326     ICAttribute *iap;
2327     int offset, list_start, list_end;
2328     int n;
2329 
2330     TRACE(("IMPutICAttrList()\n"));
2331 
2332     offset = IMWritePos(conn);
2333     IMPutC16(conn, 0);		/* dummy. overwritten afterwards */
2334     IMPutC16(conn, 0);		/* unused */
2335 
2336     list_start = IMWritePos(conn);
2337     for (n = 0, iap = icAttributes; n < numIcAttributes; n++, iap++) {
2338 	int length;
2339 
2340 	IMPutC16(conn, (unsigned int)n);
2341 	IMPutC16(conn, (unsigned int)iap->type);
2342 	length = strlen(iap->name);
2343 	IMPutC16(conn, (unsigned int)length);
2344 	IMPutString(conn, iap->name, length);
2345 	IMPutPad(conn);
2346     }
2347     list_end = IMWritePos(conn);
2348     IMRewriteC16(conn, offset, (unsigned int)(list_end - list_start));
2349 }
2350 
2351 /* ARGSUSED */
2352 int
IMSetIMValues(imp,data,len,major)2353 IMSetIMValues(imp, data, len, major)
2354 IMIM *imp;
2355 char *data;
2356 int len;
2357 int major;
2358 {
2359     TRACE(("IMSetIMValues(): not supported yet\n"));
2360     /* not supported yet */
2361 
2362     IMSendError(imp->connection, IMBadProtocol, imp->id, 0,
2363 		"this protocol is not supported yet");
2364     return -1;
2365 }
2366 
2367 int
IMGetIMValues(imp,data,len,offset)2368 IMGetIMValues(imp, data, len, offset)
2369 IMIM *imp;
2370 char *data;
2371 int len;
2372 int offset;		/* request offset */
2373 {
2374     IMConnection *conn = imp->connection;
2375     int pos, list_start, list_end;
2376 
2377     TRACE(("IMGetIMValues()\n"));
2378 
2379     pos = IMWritePos(conn);
2380     IMPutC16(conn, 0);		/* length of the list. to be overwritten. */
2381 
2382     list_start = IMWritePos(conn);
2383 
2384     if (getIMValues(imp, data, len, offset) < 0) return -1;
2385 
2386     list_end = IMWritePos(conn);
2387     IMRewriteC16(conn, pos, (unsigned int)(list_end - list_start));
2388     return 0;
2389 }
2390 
2391 int
IMSetICValues(icp,data,len,major)2392 IMSetICValues(icp, data, len, major)
2393 IMIC *icp;
2394 char *data;
2395 int len;
2396 int major;
2397 {
2398     int r1, r2, r3;
2399 
2400     TRACE(("IMSetICValues()\n"));
2401 
2402     /* clear change mask */
2403     icp->common_attr.change_mask = 0;
2404     icp->preedit_attr.change_mask = 0;
2405     icp->status_attr.change_mask = 0;
2406 
2407     /* read the specified data and set attributes */
2408     r1 = setICValues(icp, data, len, 0,
2409 		     (major == XIM_CREATE_IC) ? OP_C : OP_S);
2410 
2411     /* validate attributes */
2412     r2 = IMValidateICAttributes(icp, (r1 < 0));
2413 
2414     /*
2415      * If the operation is CREATE_IC, input style attribute must be set.
2416      */
2417     if (major == XIM_CREATE_IC &&
2418 	!(icp->common_attr.set_mask & ATTR_MASK_INPUT_STYLE) &&
2419 	r1 == 0 && r2 == 0) {
2420 	DPRINT(("input style not specified by CreateIC\n"));
2421 	IMSendError(icp->im->connection, IMBadSomething, icp->im->id, icp->id,
2422 		    "inputStyle resource must be set");
2423 	r3 = -1;
2424     } else {
2425 	r3 = 0;
2426     }
2427 
2428     if (r1 == 0 && r2 == 0) {
2429 	/* if conversion is taking place... */
2430 	if (icp->state & IC_CONVERTING) {
2431 	    changeConversionAttributes(icp);
2432 	}
2433 
2434 	/* if preedit state is specified... */
2435 	if (icp->common_attr.change_mask & ATTR_MASK_PREEDIT_STATE) {
2436 	    TRACE(("changing preedit state to %s\n",
2437 		   (icp->common_attr.preedit_state == XIMPreeditEnable) ?
2438 		   "enabled" : "disabled"));
2439 	    if (icp->common_attr.preedit_state == XIMPreeditEnable) {
2440 		IMStartConversion(icp);
2441 	    } else {
2442 		IMStopConversion(icp);
2443 	    }
2444 	}
2445     }
2446 
2447     return (r1 < 0 || r2 < 0 || r3 < 0) ? -1 : 0;
2448 }
2449 
2450 int
IMGetICValues(icp,data,len,offset)2451 IMGetICValues(icp, data, len, offset)
2452 IMIC *icp;
2453 char *data;
2454 int len;
2455 int offset;		/* request offset */
2456 {
2457     int nested_separator;
2458     int r;
2459     IMConnection *conn = icp->im->connection;
2460     int pos, list_start, list_end;
2461 
2462     TRACE(("IMGetICValues()\n"));
2463 
2464     pos = IMWritePos(conn);
2465     IMPutC16(conn, 0);		/* dummy. overwritten afterwards */
2466     IMPutC16(conn, 0);		/* unused */
2467 
2468     list_start = IMWritePos(conn);
2469 
2470     r = getICValues(icp, data, len, NEST_NONE, offset, &nested_separator);
2471     if (r < 0) return -1;
2472 
2473     list_end = IMWritePos(conn);
2474     IMRewriteC16(conn, pos, (unsigned int)(list_end - list_start));
2475 
2476     if (nested_separator) {
2477 	/*
2478 	 * There must have been some unbalanced NestedListSeparator.
2479 	 */
2480 	DPRINT(("getICvalues: unmatched separator\n"));
2481 	IMCancelRequest(icp->im->connection, offset);
2482 	IMSendError(icp->im->connection, IMBadSomething, icp->im->id, icp->id,
2483 		    "corrupted nested list");
2484 	return -1;
2485     }
2486     return 0;
2487 }
2488 
2489 void
IMFillDefault(icp,common_mask,preedit_mask,status_mask)2490 IMFillDefault(icp, common_mask, preedit_mask, status_mask)
2491 IMIC *icp;
2492 unsigned long common_mask;
2493 unsigned long preedit_mask;
2494 unsigned long status_mask;
2495 {
2496     TRACE(("IMFillDefault()\n"));
2497 
2498     if (common_mask != 0) fillCommonDefault(icp, common_mask);
2499     if (preedit_mask != 0) fillPSDefault(icp, NEST_PREEDIT, preedit_mask);
2500     if (status_mask != 0) fillPSDefault(icp, NEST_STATUS, status_mask);
2501 }
2502 
2503 int
IMValidateWindow(dpy,win,profilep)2504 IMValidateWindow(dpy, win, profilep)
2505 Display *dpy;
2506 Window win;
2507 IMWindowProfile *profilep;
2508 {
2509     Window root;
2510     int x, y;
2511     unsigned int width, height, border, depth;
2512     XAEHandle h;
2513     int s;
2514 
2515     TRACE(("IMValidateWindow(win: %08lx)\n", win));
2516 
2517     h = XAESetIgnoreErrors(dpy);
2518     s = XGetGeometry(dpy, win, &root, &x, &y,
2519 		     &width, &height, &border, &depth);
2520     XAEUnset(h);
2521 
2522     if (profilep != NULL && s) {
2523 	profilep->width = width;
2524 	profilep->height = width;
2525 	profilep->root = root;
2526     }
2527     return s;
2528 }
2529 
2530 int
IMValidateICAttributes(icp,checkonly)2531 IMValidateICAttributes(icp, checkonly)
2532 IMIC *icp;
2533 int checkonly;
2534 {
2535     int error_occured;
2536     int r;
2537 
2538     TRACE(("IMValidateICAttributes()\n"));
2539 
2540     /*
2541      * Be careful not to send multiple error messages.
2542      */
2543 
2544     error_occured = 0;
2545 
2546     r = validateCommonAttr(icp, checkonly);
2547     if (r < 0) error_occured = 1;
2548 
2549     r = validatePSAttr(icp, NEST_PREEDIT, (checkonly && error_occured));
2550     if (r < 0) error_occured = 1;
2551 
2552     r = validatePSAttr(icp, NEST_STATUS, (checkonly && error_occured));
2553     if (r < 0) error_occured = 1;
2554 
2555     return error_occured ? -1 : 0;
2556 }
2557 
2558 void
IMFreeICAttributes(icp)2559 IMFreeICAttributes(icp)
2560 IMIC *icp;
2561 {
2562     IMPSAttributes *pattr = &icp->preedit_attr;
2563     IMPSAttributes *sattr = &icp->status_attr;
2564     FontBank bank = IMFontBank(icp->im);
2565 
2566     TRACE(("IMFreeICAttributes()\n"));
2567 
2568     if (pattr->set_mask & ATTR_MASK_FONT_SET) XtFree(pattr->font_set);
2569     if (sattr->set_mask & ATTR_MASK_FONT_SET) XtFree(sattr->font_set);
2570 
2571     if (icp->num_fonts > 0) {
2572 	FontBankFreeFonts(bank, icp->fonts, icp->num_fonts);
2573     }
2574     if (icp->num_status_fonts > 0) {
2575 	FontBankFreeFonts(bank, icp->status_fonts, icp->num_status_fonts);
2576     }
2577 }
2578 
2579 unsigned long
IMMakeConvAttributes(icp,attr)2580 IMMakeConvAttributes(icp, attr)
2581 IMIC *icp;
2582 ConversionAttributes *attr;
2583 {
2584     IMCommonAttributes *cattr;
2585     IMPSAttributes *pattr, *sattr;
2586     unsigned long cmask;		/* changed attributes */
2587     unsigned long mask;			/* attributes to be set */
2588 
2589     TRACE(("IMMakeConvAttributes()\n"));
2590     mask = 0L;
2591 
2592     cattr = &icp->common_attr;
2593     pattr = &icp->preedit_attr;
2594     sattr = &icp->status_attr;
2595 
2596     /*
2597      * Check changes of common attributes.
2598      */
2599     cmask = cattr->change_mask;
2600 
2601     /* focus window */
2602     if (cmask & ATTR_MASK_FOCUS) {
2603 	attr->focuswindow = cattr->focus;
2604 	mask |= CAFocusWindow;
2605     }
2606 
2607     /*
2608      * Check changes of preedit attributes.
2609      */
2610     cmask = pattr->change_mask;
2611 
2612     /* client area */
2613     if (cmask & ATTR_MASK_AREA) {
2614 	attr->clientarea.x = pattr->area.x;
2615 	attr->clientarea.y = pattr->area.y;
2616 	attr->clientarea.width = pattr->area.width;
2617 	attr->clientarea.height = pattr->area.height;
2618 	mask |= CAClientArea;
2619     }
2620 
2621     /* foreground/background */
2622     if (cmask & ATTR_MASK_FOREGROUND) {
2623 	attr->foreground = pattr->foreground;
2624 	mask |= CAColor;
2625     }
2626     if (cmask & ATTR_MASK_BACKGROUND) {
2627 	attr->background = pattr->background;
2628 	mask |= CAColor;
2629     }
2630 
2631     /* colormap */
2632     if (cmask & ATTR_MASK_COLORMAP) {
2633 	attr->colormap = pattr->colormap;
2634 	mask |= CAColormap;
2635     }
2636 
2637     /* background pixmap */
2638     if (cmask & ATTR_MASK_BG_PIXMAP) {
2639 	attr->background_pixmap = pattr->bg_pixmap;
2640 	mask |= CABackgroundPixmap;
2641     }
2642 
2643     /* line spacing */
2644     if (cmask & ATTR_MASK_LINESPACE) {
2645 	attr->linespacing = pattr->line_space;
2646 	mask |= CALineSpacing;
2647     }
2648 
2649     /* cursor */
2650     if (cmask & ATTR_MASK_CURSOR) {
2651 	attr->cursor = pattr->cursor;
2652 	mask |= CACursor;
2653     }
2654 
2655     /* font */
2656     if (cmask & ATTR_MASK_FONT_SET) {
2657 	changeFonts(icp, 1);
2658 	attr->fonts = icp->fonts;
2659 	attr->num_fonts = icp->num_fonts;
2660 	mask |= CAFonts;
2661     }
2662 
2663     /* spot location */
2664     if ((cmask & ATTR_MASK_SPOT_LOCATION) &&
2665 	icp->style == IMSTYLE_OVER_THE_SPOT) {
2666 	attr->spotx = pattr->spot_location.x;
2667 	attr->spoty = pattr->spot_location.y;
2668 	mask |= CASpotLocation;
2669     }
2670 
2671     /*
2672      * Check changes of status attributes.
2673      */
2674     cmask = sattr->change_mask;
2675 
2676     /* status area */
2677     if (cmask & ATTR_MASK_AREA) {
2678 	attr->statusarea.x = sattr->area.x;
2679 	attr->statusarea.y = sattr->area.y;
2680 	attr->statusarea.width = sattr->area.width;
2681 	attr->statusarea.height = sattr->area.height;
2682 	mask |= CAStatusArea;
2683     }
2684 
2685     /* font */
2686     if (cmask & ATTR_MASK_FONT_SET) {
2687 	changeFonts(icp, 0);
2688 	attr->status_fonts = icp->status_fonts;
2689 	attr->num_status_fonts = icp->num_status_fonts;
2690 	mask |= CAStatusFonts;
2691     }
2692 
2693     return mask;
2694 }
2695 
2696 void
IMMoveLocation(icp,x,y)2697 IMMoveLocation(icp, x, y)
2698 IMIC *icp;
2699 int x;
2700 int y;
2701 {
2702     TRACE(("IMMoveLocation()\n"));
2703 
2704     icp->preedit_attr.spot_location.x = x;
2705     icp->preedit_attr.spot_location.y = y;
2706     icp->preedit_attr.set_mask |= ATTR_MASK_SPOT_LOCATION;
2707     icp->preedit_attr.change_mask = ATTR_MASK_SPOT_LOCATION;
2708     if (icp->state & IC_CONVERTING) {
2709 	changeConversionAttributes(icp);
2710     }
2711 }
2712