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