imTrX.c revision 61b2299d
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 XFree(prop_ret); 362 XGetWindowProperty(im->core.display, 363 spec->lib_connect_wid, prop, 0L, 364 ((length + bytes_after_ret + 3)/ 4), True, AnyPropertyType, 365 &type_ret, &format_ret, &nitems, &bytes_after_ret, 366 &prop_ret); 367 XChangeProperty(im->core.display, spec->lib_connect_wid, prop, 368 XA_STRING, 8, PropModePrepend, &prop_ret[length], 369 (nitems - length)); 370 } 371 } else { 372 (void)memcpy(buf, prop_ret, buf_len); 373 *ret_len = buf_len; 374 len = nitems - buf_len; 375 376 if (bytes_after_ret > 0) { 377 XFree(prop_ret); 378 XGetWindowProperty(im->core.display, 379 spec->lib_connect_wid, prop, 0L, 380 ((length + bytes_after_ret + 3)/ 4), True, AnyPropertyType, 381 &type_ret, &format_ret, &nitems, &bytes_after_ret, &prop_ret); 382 } 383 XChangeProperty(im->core.display, spec->lib_connect_wid, prop, 384 XA_STRING, 8, PropModePrepend, &prop_ret[buf_len], len); 385 event->xclient.data.l[0] = (long)len; 386 event->xclient.data.l[1] = (long)prop; 387 XPutBackEvent(im->core.display, event); 388 } 389 XFree(prop_ret); 390 } else if (event->type == PropertyNotify) { 391 prop = event->xproperty.atom; 392 return_code = XGetWindowProperty(im->core.display, 393 spec->lib_connect_wid, prop, 0L, 394 1000000L, True, AnyPropertyType, 395 &type_ret, &format_ret, &nitems, &bytes_after_ret, &prop_ret); 396 if (return_code != Success || format_ret == 0 || nitems == 0) { 397 if (return_code == Success) 398 XFree(prop_ret); 399 return False; 400 } 401 if (buf_len >= nitems) { 402 (void)memcpy(buf, prop_ret, (int)nitems); 403 *ret_len = (int)nitems; 404 } else { 405 (void)memcpy(buf, prop_ret, buf_len); 406 *ret_len = buf_len; 407 len = nitems - buf_len; 408 XChangeProperty(im->core.display, spec->lib_connect_wid, prop, 409 XA_STRING, 8, PropModePrepend, &prop_ret[buf_len], len); 410 } 411 XFree(prop_ret); 412 } 413 return True; 414} 415 416Private Bool 417_CheckCMEvent( 418 Display *display, 419 XEvent *event, 420 XPointer xim) 421{ 422 Xim im = (Xim)xim; 423 XSpecRec *spec = (XSpecRec *)im->private.proto.spec; 424 CARD32 major_code = spec->major_code; 425 426 if ((event->type == ClientMessage) 427 &&((event->xclient.message_type == spec->improtocolid) || 428 (event->xclient.message_type == spec->immoredataid))) 429 return True; 430 if((major_code == 1 || major_code == 2) && 431 (event->type == PropertyNotify) && 432 (event->xproperty.state == PropertyNewValue)) 433 return True; 434 return False; 435} 436 437Private Bool 438_XimXRead(Xim im, XPointer recv_buf, int buf_len, int *ret_len) 439{ 440 XEvent *ev; 441 XEvent event; 442 int len = 0; 443 XSpecRec *spec = (XSpecRec *)im->private.proto.spec; 444 XPointer arg = spec->ev; 445 446 if (!arg) { 447 bzero(&event, sizeof(XEvent)); 448 ev = &event; 449 XIfEvent(im->core.display, ev, _CheckCMEvent, (XPointer)im); 450 } else { 451 ev = (XEvent *)arg; 452 spec->ev = (XPointer)NULL; 453 } 454 if (!(_XimXGetReadData(im, recv_buf, buf_len, &len, ev))) 455 return False; 456 *ret_len = len; 457 return True; 458} 459 460Private void 461_XimXFlush(Xim im) 462{ 463 XFlush(im->core.display); 464 return; 465} 466 467Public Bool 468_XimXConf(Xim im, char *address) 469{ 470 XSpecRec *spec; 471 472 if (!(spec = (XSpecRec *)Xmalloc(sizeof(XSpecRec)))) 473 return False; 474 bzero(spec, sizeof(XSpecRec)); 475 476 spec->improtocolid = XInternAtom(im->core.display, _XIM_PROTOCOL, False); 477 spec->imconnectid = XInternAtom(im->core.display, _XIM_XCONNECT, False); 478 spec->immoredataid = XInternAtom(im->core.display, _XIM_MOREDATA, False); 479 spec->major_code = MAJOR_TRANSPORT_VERSION; 480 spec->minor_code = MINOR_TRANSPORT_VERSION; 481 482 im->private.proto.spec = (XPointer)spec; 483 im->private.proto.connect = _XimXConnect; 484 im->private.proto.shutdown = _XimXShutdown; 485 im->private.proto.write = _XimXWrite; 486 im->private.proto.read = _XimXRead; 487 im->private.proto.flush = _XimXFlush; 488 im->private.proto.register_dispatcher = _XimXRegisterDispatcher; 489 im->private.proto.call_dispatcher = _XimXCallDispatcher; 490 491 return True; 492} 493