imTrX.c revision 1ab64890
1/* $Xorg: imTrX.c,v 1.4 2000/08/17 19:45:15 cpqbld Exp $ */ 2/****************************************************************** 3 4 Copyright 1992 by Sun Microsystems, Inc. 5 Copyright 1992, 1993, 1994 by FUJITSU LIMITED 6 7Permission to use, copy, modify, distribute, and sell this software 8and its documentation for any purpose is hereby granted without fee, 9provided that the above copyright notice appear in all copies and 10that both that copyright notice and this permission notice appear 11in supporting documentation, and that the name of Sun Microsystems, Inc. 12and FUJITSU LIMITED not be used in advertising or publicity pertaining to 13distribution of the software without specific, written prior permission. 14Sun Microsystems, Inc. and FUJITSU LIMITED makes no representations about 15the suitability of this software for any purpose. 16It is provided "as is" without express or implied warranty. 17 18Sun Microsystems Inc. AND FUJITSU LIMITED DISCLAIMS ALL WARRANTIES WITH 19REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 20AND FITNESS, IN NO EVENT SHALL Sun Microsystems, Inc. AND FUJITSU LIMITED 21BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 22WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 23ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 24IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 25 26 Author: Hideki Hiura (hhiura@Sun.COM) Sun Microsystems, Inc. 27 Takashi Fujiwara FUJITSU LIMITED 28 fujiwara@a80.tech.yk.fujitsu.co.jp 29 30******************************************************************/ 31/* $XFree86: xc/lib/X11/imTrX.c,v 1.3 2003/04/13 19:22:21 dawes Exp $ */ 32 33#ifdef HAVE_CONFIG_H 34#include <config.h> 35#endif 36#include <string.h> 37#include <X11/Xatom.h> 38#define NEED_EVENTS 39#include "Xlibint.h" 40#include "Xlcint.h" 41#include "Ximint.h" 42#include "XimTrInt.h" 43#include "XimTrX.h" 44 45Private Bool 46_XimXRegisterDispatcher( 47 Xim im, 48 Bool (*callback)( 49 Xim, INT16, XPointer, XPointer 50 ), 51 XPointer call_data) 52{ 53 XIntrCallbackPtr rec; 54 XSpecRec *spec = (XSpecRec *)im->private.proto.spec; 55 56 if (!(rec = (XIntrCallbackPtr)Xmalloc(sizeof(XIntrCallbackRec)))) 57 return False; 58 59 rec->func = callback; 60 rec->call_data = call_data; 61 rec->next = spec->intr_cb; 62 spec->intr_cb = rec; 63 return True; 64} 65 66Private void 67_XimXFreeIntrCallback( 68 Xim im) 69{ 70 XSpecRec *spec = (XSpecRec *)im->private.proto.spec; 71 register XIntrCallbackPtr rec, next; 72 73 for (rec = spec->intr_cb; rec;) { 74 next = rec->next; 75 Xfree(rec); 76 rec = next; 77 } 78 return; 79} 80 81Private Bool 82_XimXCallDispatcher(Xim im, INT16 len, XPointer data) 83{ 84 register XIntrCallbackRec *rec; 85 XSpecRec *spec = (XSpecRec *)im->private.proto.spec; 86 87 for (rec = spec->intr_cb; rec; rec = rec->next) { 88 if ((*rec->func)(im, len, data, rec->call_data)) 89 return True; 90 } 91 return False; 92} 93 94Private Bool 95_XimXFilterWaitEvent( 96 Display *d, 97 Window w, 98 XEvent *ev, 99 XPointer arg) 100{ 101 Xim im = (Xim)arg; 102 XSpecRec *spec = (XSpecRec *)im->private.proto.spec; 103 Bool ret; 104 105 spec->ev = (XPointer)ev; 106 ret = _XimFilterWaitEvent(im); 107 108 /* 109 * If ev is a pointer to a stack variable, there could be 110 * a coredump later on if the pointer is dereferenced. 111 * Therefore, reset to NULL to force reinitialization in 112 * _XimXRead(). 113 * 114 * Keep in mind _XimXRead may be called again when the stack 115 * is very different. 116 */ 117 spec->ev = (XPointer)NULL; 118 119 return ret; 120} 121 122Private Bool 123_CheckConnect( 124 Display *display, 125 XEvent *event, 126 XPointer xim) 127{ 128 Xim im = (Xim)xim; 129 XSpecRec *spec = (XSpecRec *)im->private.proto.spec; 130 131 if ((event->type == ClientMessage) 132 && (event->xclient.message_type == spec->imconnectid)) { 133 return True; 134 } 135 return False; 136} 137 138Private Bool 139_XimXConnect(Xim im) 140{ 141 XEvent event; 142 XSpecRec *spec = (XSpecRec *)im->private.proto.spec; 143 CARD32 major_code; 144 CARD32 minor_code; 145 146 if (!(spec->lib_connect_wid = XCreateSimpleWindow(im->core.display, 147 DefaultRootWindow(im->core.display), 0, 0, 1, 1, 1, 0, 0))) { 148 return False; 149 } 150 151 event.xclient.type = ClientMessage; 152 event.xclient.display = im->core.display; 153 event.xclient.window = im->private.proto.im_window; 154 event.xclient.message_type = spec->imconnectid; 155 event.xclient.format = 32; 156 event.xclient.data.l[0] = (CARD32)spec->lib_connect_wid; 157 event.xclient.data.l[1] = spec->major_code; 158 event.xclient.data.l[2] = spec->minor_code; 159 event.xclient.data.l[3] = 0; 160 event.xclient.data.l[4] = 0; 161 162 if(event.xclient.data.l[1] == 1 || event.xclient.data.l[1] == 2) { 163 XWindowAttributes atr; 164 long event_mask; 165 166 XGetWindowAttributes(im->core.display, spec->lib_connect_wid, &atr); 167 event_mask = atr.your_event_mask | PropertyChangeMask; 168 XSelectInput(im->core.display, spec->lib_connect_wid, event_mask); 169 _XRegisterFilterByType(im->core.display, spec->lib_connect_wid, 170 PropertyNotify, PropertyNotify, 171 _XimXFilterWaitEvent, (XPointer)im); 172 } 173 174 XSendEvent(im->core.display, im->private.proto.im_window, 175 False, NoEventMask, &event); 176 XFlush(im->core.display); 177 178 for (;;) { 179 XIfEvent(im->core.display, &event, _CheckConnect, (XPointer)im); 180 if (event.xclient.type != ClientMessage) { 181 return False; 182 } 183 if (event.xclient.message_type == spec->imconnectid) 184 break; 185 } 186 187 spec->ims_connect_wid = (Window)event.xclient.data.l[0]; 188 major_code = (CARD32)event.xclient.data.l[1]; 189 minor_code = (CARD32)event.xclient.data.l[2]; 190 191 if (((major_code == 0) && (minor_code <= 2)) || 192 ((major_code == 1) && (minor_code == 0)) || 193 ((major_code == 2) && (minor_code <= 1))) { 194 spec->major_code = major_code; 195 spec->minor_code = minor_code; 196 } 197 if (((major_code == 0) && (minor_code == 2)) || 198 ((major_code == 2) && (minor_code == 1))) { 199 spec->BoundarySize = (CARD32)event.xclient.data.l[3]; 200 } 201 202 /* ClientMessage Event Filter */ 203 _XRegisterFilterByType(im->core.display, spec->lib_connect_wid, 204 ClientMessage, ClientMessage, 205 _XimXFilterWaitEvent, (XPointer)im); 206 return True; 207} 208 209Private Bool 210_XimXShutdown(Xim im) 211{ 212 XSpecRec *spec = (XSpecRec *)im->private.proto.spec; 213 214 if (!spec) 215 return True; 216 217 /* ClientMessage Event Filter */ 218 _XUnregisterFilter(im->core.display, 219 ((XSpecRec *)im->private.proto.spec)->lib_connect_wid, 220 _XimXFilterWaitEvent, (XPointer)im); 221 XDestroyWindow(im->core.display, 222 ((XSpecRec *)im->private.proto.spec)->lib_connect_wid); 223 _XimXFreeIntrCallback(im); 224 Xfree(spec); 225 im->private.proto.spec = 0; 226 return True; 227} 228 229Private char * 230_NewAtom( 231 char *atomName) 232{ 233 static int sequence = 0; 234 235 (void)sprintf(atomName, "_client%d", sequence); 236 sequence = ((sequence < 20) ? sequence + 1 : 0); 237 return atomName; 238} 239 240Private Bool 241_XimXWrite(Xim im, INT16 len, XPointer data) 242{ 243 Atom atom; 244 char atomName[16]; 245 XSpecRec *spec = (XSpecRec *)im->private.proto.spec; 246 XEvent event; 247 CARD8 *p; 248 CARD32 major_code = spec->major_code; 249 CARD32 minor_code = spec->minor_code; 250 int BoundSize; 251 252 bzero(&event,sizeof(XEvent)); 253 event.xclient.type = ClientMessage; 254 event.xclient.display = im->core.display; 255 event.xclient.window = spec->ims_connect_wid; 256 if(major_code == 1 && minor_code == 0) { 257 BoundSize = 0; 258 } else if((major_code == 0 && minor_code == 2) || 259 (major_code == 2 && minor_code == 1)) { 260 BoundSize = spec->BoundarySize; 261 } else if(major_code == 0 && minor_code == 1) { 262 BoundSize = len; 263 } else { 264 BoundSize = XIM_CM_DATA_SIZE; 265 } 266 if (len > BoundSize) { 267 event.xclient.message_type = spec->improtocolid; 268 atom = XInternAtom(im->core.display, _NewAtom(atomName), False); 269 XChangeProperty(im->core.display, spec->ims_connect_wid, 270 atom, XA_STRING, 8, PropModeAppend, 271 (unsigned char *)data, len); 272 if(major_code == 0) { 273 event.xclient.format = 32; 274 event.xclient.data.l[0] = (long)len; 275 event.xclient.data.l[1] = (long)atom; 276 XSendEvent(im->core.display, spec->ims_connect_wid, 277 False, NoEventMask, &event); 278 } 279 } else { 280 int length; 281 282 event.xclient.format = 8; 283 for(length = 0 ; length < len ; length += XIM_CM_DATA_SIZE) { 284 p = (CARD8 *)&event.xclient.data.b[0]; 285 if((length + XIM_CM_DATA_SIZE) >= len) { 286 event.xclient.message_type = spec->improtocolid; 287 bzero(p, XIM_CM_DATA_SIZE); 288 memcpy((char *)p, (data + length), (len - length)); 289 } else { 290 event.xclient.message_type = spec->immoredataid; 291 memcpy((char *)p, (data + length), XIM_CM_DATA_SIZE); 292 } 293 XSendEvent(im->core.display, spec->ims_connect_wid, 294 False, NoEventMask, &event); 295 } 296 } 297 298 return True; 299} 300 301Private Bool 302_XimXGetReadData( 303 Xim im, 304 char *buf, 305 int buf_len, 306 int *ret_len, 307 XEvent *event) 308{ 309 char *data; 310 int len; 311 312 char tmp_buf[XIM_CM_DATA_SIZE]; 313 XSpecRec *spec = (XSpecRec *)im->private.proto.spec; 314 unsigned long length; 315 Atom prop; 316 int return_code; 317 Atom type_ret; 318 int format_ret; 319 unsigned long nitems; 320 unsigned long bytes_after_ret; 321 unsigned char *prop_ret; 322 323 if ((event->type == ClientMessage) && 324 !((event->xclient.message_type == spec->improtocolid) || 325 (event->xclient.message_type == spec->immoredataid))) { 326 /* This event has nothing to do with us, 327 * FIXME should not have gotten here then... 328 */ 329 return False; 330 } else if ((event->type == ClientMessage) && (event->xclient.format == 8)) { 331 data = event->xclient.data.b; 332 if (buf_len >= XIM_CM_DATA_SIZE) { 333 (void)memcpy(buf, data, XIM_CM_DATA_SIZE); 334 *ret_len = XIM_CM_DATA_SIZE; 335 } else { 336 (void)memcpy(buf, data, buf_len); 337 len = XIM_CM_DATA_SIZE - buf_len; 338 (void)memcpy(tmp_buf, &data[buf_len], len); 339 bzero(data, XIM_CM_DATA_SIZE); 340 (void)memcpy(data, tmp_buf, len); 341 XPutBackEvent(im->core.display, event); 342 *ret_len = buf_len; 343 } 344 } else if ((event->type == ClientMessage) 345 && (event->xclient.format == 32)) { 346 length = (unsigned long)event->xclient.data.l[0]; 347 prop = (Atom)event->xclient.data.l[1]; 348 return_code = XGetWindowProperty(im->core.display, 349 spec->lib_connect_wid, prop, 0L, 350 (long)((length + 3)/ 4), True, AnyPropertyType, 351 &type_ret, &format_ret, &nitems, &bytes_after_ret, &prop_ret); 352 if (return_code != Success || format_ret == 0 || nitems == 0) { 353 if (return_code == Success) 354 XFree(prop_ret); 355 return False; 356 } 357 if (buf_len >= length) { 358 (void)memcpy(buf, prop_ret, (int)nitems); 359 *ret_len = (int)nitems; 360 if (bytes_after_ret > 0) { 361 XGetWindowProperty(im->core.display, 362 spec->lib_connect_wid, prop, 0L, 363 ((length + bytes_after_ret + 3)/ 4), True, AnyPropertyType, 364 &type_ret, &format_ret, &nitems, &bytes_after_ret, 365 &prop_ret); 366 XChangeProperty(im->core.display, spec->lib_connect_wid, prop, 367 XA_STRING, 8, PropModePrepend, &prop_ret[length], 368 (nitems - length)); 369 } 370 } else { 371 (void)memcpy(buf, prop_ret, buf_len); 372 *ret_len = buf_len; 373 len = nitems - buf_len; 374 375 if (bytes_after_ret > 0) { 376 XFree(prop_ret); 377 XGetWindowProperty(im->core.display, 378 spec->lib_connect_wid, prop, 0L, 379 ((length + bytes_after_ret + 3)/ 4), True, AnyPropertyType, 380 &type_ret, &format_ret, &nitems, &bytes_after_ret, &prop_ret); 381 } 382 XChangeProperty(im->core.display, spec->lib_connect_wid, prop, 383 XA_STRING, 8, PropModePrepend, &prop_ret[buf_len], len); 384 event->xclient.data.l[0] = (long)len; 385 event->xclient.data.l[1] = (long)prop; 386 XPutBackEvent(im->core.display, event); 387 } 388 XFree(prop_ret); 389 } else if (event->type == PropertyNotify) { 390 prop = event->xproperty.atom; 391 return_code = XGetWindowProperty(im->core.display, 392 spec->lib_connect_wid, prop, 0L, 393 1000000L, True, AnyPropertyType, 394 &type_ret, &format_ret, &nitems, &bytes_after_ret, &prop_ret); 395 if (return_code != Success || format_ret == 0 || nitems == 0) { 396 if (return_code == Success) 397 XFree(prop_ret); 398 return False; 399 } 400 if (buf_len >= nitems) { 401 (void)memcpy(buf, prop_ret, (int)nitems); 402 *ret_len = (int)nitems; 403 } else { 404 (void)memcpy(buf, prop_ret, buf_len); 405 *ret_len = buf_len; 406 len = nitems - buf_len; 407 XChangeProperty(im->core.display, spec->lib_connect_wid, prop, 408 XA_STRING, 8, PropModePrepend, &prop_ret[buf_len], len); 409 } 410 XFree(prop_ret); 411 } 412 return True; 413} 414 415Private Bool 416_CheckCMEvent( 417 Display *display, 418 XEvent *event, 419 XPointer xim) 420{ 421 Xim im = (Xim)xim; 422 XSpecRec *spec = (XSpecRec *)im->private.proto.spec; 423 CARD32 major_code = spec->major_code; 424 425 if ((event->type == ClientMessage) 426 &&((event->xclient.message_type == spec->improtocolid) || 427 (event->xclient.message_type == spec->immoredataid))) 428 return True; 429 if((major_code == 1 || major_code == 2) && 430 (event->type == PropertyNotify) && 431 (event->xproperty.state == PropertyNewValue)) 432 return True; 433 return False; 434} 435 436Private Bool 437_XimXRead(Xim im, XPointer recv_buf, int buf_len, int *ret_len) 438{ 439 XEvent *ev; 440 XEvent event; 441 int len; 442 XSpecRec *spec = (XSpecRec *)im->private.proto.spec; 443 XPointer arg = spec->ev; 444 445 if (!arg) { 446 bzero(&event, sizeof(XEvent)); 447 ev = &event; 448 XIfEvent(im->core.display, ev, _CheckCMEvent, (XPointer)im); 449 } else { 450 ev = (XEvent *)arg; 451 spec->ev = (XPointer)NULL; 452 } 453 if (!(_XimXGetReadData(im, recv_buf, buf_len, &len, ev))) 454 return False; 455 *ret_len = len; 456 return True; 457} 458 459Private void 460_XimXFlush(Xim im) 461{ 462 XFlush(im->core.display); 463 return; 464} 465 466Public Bool 467_XimXConf(im, address) 468 Xim im; 469 char *address; 470{ 471 XSpecRec *spec; 472 473 if (!(spec = (XSpecRec *)Xmalloc(sizeof(XSpecRec)))) 474 return False; 475 bzero(spec, sizeof(XSpecRec)); 476 477 spec->improtocolid = XInternAtom(im->core.display, _XIM_PROTOCOL, False); 478 spec->imconnectid = XInternAtom(im->core.display, _XIM_XCONNECT, False); 479 spec->immoredataid = XInternAtom(im->core.display, _XIM_MOREDATA, False); 480 spec->major_code = MAJOR_TRANSPORT_VERSION; 481 spec->minor_code = MINOR_TRANSPORT_VERSION; 482 483 im->private.proto.spec = (XPointer)spec; 484 im->private.proto.connect = _XimXConnect; 485 im->private.proto.shutdown = _XimXShutdown; 486 im->private.proto.write = _XimXWrite; 487 im->private.proto.read = _XimXRead; 488 im->private.proto.flush = _XimXFlush; 489 im->private.proto.register_dispatcher = _XimXRegisterDispatcher; 490 im->private.proto.call_dispatcher = _XimXCallDispatcher; 491 492 return True; 493} 494