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