imTrX.c revision b4ee4795
1/* 2 * Copyright 1992 Sun Microsystems, Inc. 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#define NEED_EVENTS 58#include "Xlibint.h" 59#include "Xlcint.h" 60#include "Ximint.h" 61#include "XimTrInt.h" 62#include "XimTrX.h" 63 64Private Bool 65_XimXRegisterDispatcher( 66 Xim im, 67 Bool (*callback)( 68 Xim, INT16, XPointer, XPointer 69 ), 70 XPointer call_data) 71{ 72 XIntrCallbackPtr rec; 73 XSpecRec *spec = (XSpecRec *)im->private.proto.spec; 74 75 if (!(rec = (XIntrCallbackPtr)Xmalloc(sizeof(XIntrCallbackRec)))) 76 return False; 77 78 rec->func = callback; 79 rec->call_data = call_data; 80 rec->next = spec->intr_cb; 81 spec->intr_cb = rec; 82 return True; 83} 84 85Private void 86_XimXFreeIntrCallback( 87 Xim im) 88{ 89 XSpecRec *spec = (XSpecRec *)im->private.proto.spec; 90 register XIntrCallbackPtr rec, next; 91 92 for (rec = spec->intr_cb; rec;) { 93 next = rec->next; 94 Xfree(rec); 95 rec = next; 96 } 97 return; 98} 99 100Private Bool 101_XimXCallDispatcher(Xim im, INT16 len, XPointer data) 102{ 103 register XIntrCallbackRec *rec; 104 XSpecRec *spec = (XSpecRec *)im->private.proto.spec; 105 106 for (rec = spec->intr_cb; rec; rec = rec->next) { 107 if ((*rec->func)(im, len, data, rec->call_data)) 108 return True; 109 } 110 return False; 111} 112 113Private Bool 114_XimXFilterWaitEvent( 115 Display *d, 116 Window w, 117 XEvent *ev, 118 XPointer arg) 119{ 120 Xim im = (Xim)arg; 121 XSpecRec *spec = (XSpecRec *)im->private.proto.spec; 122 Bool ret; 123 124 spec->ev = (XPointer)ev; 125 ret = _XimFilterWaitEvent(im); 126 127 /* 128 * If ev is a pointer to a stack variable, there could be 129 * a coredump later on if the pointer is dereferenced. 130 * Therefore, reset to NULL to force reinitialization in 131 * _XimXRead(). 132 * 133 * Keep in mind _XimXRead may be called again when the stack 134 * is very different. 135 */ 136 spec->ev = (XPointer)NULL; 137 138 return ret; 139} 140 141Private Bool 142_CheckConnect( 143 Display *display, 144 XEvent *event, 145 XPointer xim) 146{ 147 Xim im = (Xim)xim; 148 XSpecRec *spec = (XSpecRec *)im->private.proto.spec; 149 150 if ((event->type == ClientMessage) 151 && (event->xclient.message_type == spec->imconnectid)) { 152 return True; 153 } 154 return False; 155} 156 157Private Bool 158_XimXConnect(Xim im) 159{ 160 XEvent event; 161 XSpecRec *spec = (XSpecRec *)im->private.proto.spec; 162 CARD32 major_code; 163 CARD32 minor_code; 164 165 if (!(spec->lib_connect_wid = XCreateSimpleWindow(im->core.display, 166 DefaultRootWindow(im->core.display), 0, 0, 1, 1, 1, 0, 0))) { 167 return False; 168 } 169 170 event.xclient.type = ClientMessage; 171 event.xclient.display = im->core.display; 172 event.xclient.window = im->private.proto.im_window; 173 event.xclient.message_type = spec->imconnectid; 174 event.xclient.format = 32; 175 event.xclient.data.l[0] = (CARD32)spec->lib_connect_wid; 176 event.xclient.data.l[1] = spec->major_code; 177 event.xclient.data.l[2] = spec->minor_code; 178 event.xclient.data.l[3] = 0; 179 event.xclient.data.l[4] = 0; 180 181 if(event.xclient.data.l[1] == 1 || event.xclient.data.l[1] == 2) { 182 XWindowAttributes atr; 183 long event_mask; 184 185 XGetWindowAttributes(im->core.display, spec->lib_connect_wid, &atr); 186 event_mask = atr.your_event_mask | PropertyChangeMask; 187 XSelectInput(im->core.display, spec->lib_connect_wid, event_mask); 188 _XRegisterFilterByType(im->core.display, spec->lib_connect_wid, 189 PropertyNotify, PropertyNotify, 190 _XimXFilterWaitEvent, (XPointer)im); 191 } 192 193 XSendEvent(im->core.display, im->private.proto.im_window, 194 False, NoEventMask, &event); 195 XFlush(im->core.display); 196 197 for (;;) { 198 XIfEvent(im->core.display, &event, _CheckConnect, (XPointer)im); 199 if (event.xclient.type != ClientMessage) { 200 return False; 201 } 202 if (event.xclient.message_type == spec->imconnectid) 203 break; 204 } 205 206 spec->ims_connect_wid = (Window)event.xclient.data.l[0]; 207 major_code = (CARD32)event.xclient.data.l[1]; 208 minor_code = (CARD32)event.xclient.data.l[2]; 209 210 if (((major_code == 0) && (minor_code <= 2)) || 211 ((major_code == 1) && (minor_code == 0)) || 212 ((major_code == 2) && (minor_code <= 1))) { 213 spec->major_code = major_code; 214 spec->minor_code = minor_code; 215 } 216 if (((major_code == 0) && (minor_code == 2)) || 217 ((major_code == 2) && (minor_code == 1))) { 218 spec->BoundarySize = (CARD32)event.xclient.data.l[3]; 219 } 220 221 /* ClientMessage Event Filter */ 222 _XRegisterFilterByType(im->core.display, spec->lib_connect_wid, 223 ClientMessage, ClientMessage, 224 _XimXFilterWaitEvent, (XPointer)im); 225 return True; 226} 227 228Private Bool 229_XimXShutdown(Xim im) 230{ 231 XSpecRec *spec = (XSpecRec *)im->private.proto.spec; 232 233 if (!spec) 234 return True; 235 236 /* ClientMessage Event Filter */ 237 _XUnregisterFilter(im->core.display, 238 ((XSpecRec *)im->private.proto.spec)->lib_connect_wid, 239 _XimXFilterWaitEvent, (XPointer)im); 240 XDestroyWindow(im->core.display, 241 ((XSpecRec *)im->private.proto.spec)->lib_connect_wid); 242 _XimXFreeIntrCallback(im); 243 Xfree(spec); 244 im->private.proto.spec = 0; 245 return True; 246} 247 248Private char * 249_NewAtom( 250 char *atomName) 251{ 252 static int sequence = 0; 253 254 (void)sprintf(atomName, "_client%d", sequence); 255 sequence = ((sequence < 20) ? sequence + 1 : 0); 256 return atomName; 257} 258 259Private Bool 260_XimXWrite(Xim im, INT16 len, XPointer data) 261{ 262 Atom atom; 263 char atomName[16]; 264 XSpecRec *spec = (XSpecRec *)im->private.proto.spec; 265 XEvent event; 266 CARD8 *p; 267 CARD32 major_code = spec->major_code; 268 CARD32 minor_code = spec->minor_code; 269 int BoundSize; 270 271 bzero(&event,sizeof(XEvent)); 272 event.xclient.type = ClientMessage; 273 event.xclient.display = im->core.display; 274 event.xclient.window = spec->ims_connect_wid; 275 if(major_code == 1 && minor_code == 0) { 276 BoundSize = 0; 277 } else if((major_code == 0 && minor_code == 2) || 278 (major_code == 2 && minor_code == 1)) { 279 BoundSize = spec->BoundarySize; 280 } else if(major_code == 0 && minor_code == 1) { 281 BoundSize = len; 282 } else { 283 BoundSize = XIM_CM_DATA_SIZE; 284 } 285 if (len > BoundSize) { 286 event.xclient.message_type = spec->improtocolid; 287 atom = XInternAtom(im->core.display, _NewAtom(atomName), False); 288 XChangeProperty(im->core.display, spec->ims_connect_wid, 289 atom, XA_STRING, 8, PropModeAppend, 290 (unsigned char *)data, len); 291 if(major_code == 0) { 292 event.xclient.format = 32; 293 event.xclient.data.l[0] = (long)len; 294 event.xclient.data.l[1] = (long)atom; 295 XSendEvent(im->core.display, spec->ims_connect_wid, 296 False, NoEventMask, &event); 297 } 298 } else { 299 int length; 300 301 event.xclient.format = 8; 302 for(length = 0 ; length < len ; length += XIM_CM_DATA_SIZE) { 303 p = (CARD8 *)&event.xclient.data.b[0]; 304 if((length + XIM_CM_DATA_SIZE) >= len) { 305 event.xclient.message_type = spec->improtocolid; 306 bzero(p, XIM_CM_DATA_SIZE); 307 memcpy((char *)p, (data + length), (len - length)); 308 } else { 309 event.xclient.message_type = spec->immoredataid; 310 memcpy((char *)p, (data + length), XIM_CM_DATA_SIZE); 311 } 312 XSendEvent(im->core.display, spec->ims_connect_wid, 313 False, NoEventMask, &event); 314 } 315 } 316 317 return True; 318} 319 320Private Bool 321_XimXGetReadData( 322 Xim im, 323 char *buf, 324 int buf_len, 325 int *ret_len, 326 XEvent *event) 327{ 328 char *data; 329 int len; 330 331 char tmp_buf[XIM_CM_DATA_SIZE]; 332 XSpecRec *spec = (XSpecRec *)im->private.proto.spec; 333 unsigned long length; 334 Atom prop; 335 int return_code; 336 Atom type_ret; 337 int format_ret; 338 unsigned long nitems; 339 unsigned long bytes_after_ret; 340 unsigned char *prop_ret; 341 342 if ((event->type == ClientMessage) && 343 !((event->xclient.message_type == spec->improtocolid) || 344 (event->xclient.message_type == spec->immoredataid))) { 345 /* This event has nothing to do with us, 346 * FIXME should not have gotten here then... 347 */ 348 return False; 349 } else if ((event->type == ClientMessage) && (event->xclient.format == 8)) { 350 data = event->xclient.data.b; 351 if (buf_len >= XIM_CM_DATA_SIZE) { 352 (void)memcpy(buf, data, XIM_CM_DATA_SIZE); 353 *ret_len = XIM_CM_DATA_SIZE; 354 } else { 355 (void)memcpy(buf, data, buf_len); 356 len = XIM_CM_DATA_SIZE - buf_len; 357 (void)memcpy(tmp_buf, &data[buf_len], len); 358 bzero(data, XIM_CM_DATA_SIZE); 359 (void)memcpy(data, tmp_buf, len); 360 XPutBackEvent(im->core.display, event); 361 *ret_len = buf_len; 362 } 363 } else if ((event->type == ClientMessage) 364 && (event->xclient.format == 32)) { 365 length = (unsigned long)event->xclient.data.l[0]; 366 prop = (Atom)event->xclient.data.l[1]; 367 return_code = XGetWindowProperty(im->core.display, 368 spec->lib_connect_wid, prop, 0L, 369 (long)((length + 3)/ 4), True, AnyPropertyType, 370 &type_ret, &format_ret, &nitems, &bytes_after_ret, &prop_ret); 371 if (return_code != Success || format_ret == 0 || nitems == 0) { 372 if (return_code == Success) 373 XFree(prop_ret); 374 return False; 375 } 376 if (buf_len >= length) { 377 (void)memcpy(buf, prop_ret, (int)nitems); 378 *ret_len = (int)nitems; 379 if (bytes_after_ret > 0) { 380 XFree(prop_ret); 381 XGetWindowProperty(im->core.display, 382 spec->lib_connect_wid, prop, 0L, 383 ((length + bytes_after_ret + 3)/ 4), True, AnyPropertyType, 384 &type_ret, &format_ret, &nitems, &bytes_after_ret, 385 &prop_ret); 386 XChangeProperty(im->core.display, spec->lib_connect_wid, prop, 387 XA_STRING, 8, PropModePrepend, &prop_ret[length], 388 (nitems - length)); 389 } 390 } else { 391 (void)memcpy(buf, prop_ret, buf_len); 392 *ret_len = buf_len; 393 len = nitems - buf_len; 394 395 if (bytes_after_ret > 0) { 396 XFree(prop_ret); 397 XGetWindowProperty(im->core.display, 398 spec->lib_connect_wid, prop, 0L, 399 ((length + bytes_after_ret + 3)/ 4), True, AnyPropertyType, 400 &type_ret, &format_ret, &nitems, &bytes_after_ret, &prop_ret); 401 } 402 XChangeProperty(im->core.display, spec->lib_connect_wid, prop, 403 XA_STRING, 8, PropModePrepend, &prop_ret[buf_len], len); 404 event->xclient.data.l[0] = (long)len; 405 event->xclient.data.l[1] = (long)prop; 406 XPutBackEvent(im->core.display, event); 407 } 408 XFree(prop_ret); 409 } else if (event->type == PropertyNotify) { 410 prop = event->xproperty.atom; 411 return_code = XGetWindowProperty(im->core.display, 412 spec->lib_connect_wid, prop, 0L, 413 1000000L, True, AnyPropertyType, 414 &type_ret, &format_ret, &nitems, &bytes_after_ret, &prop_ret); 415 if (return_code != Success || format_ret == 0 || nitems == 0) { 416 if (return_code == Success) 417 XFree(prop_ret); 418 return False; 419 } 420 if (buf_len >= nitems) { 421 (void)memcpy(buf, prop_ret, (int)nitems); 422 *ret_len = (int)nitems; 423 } else { 424 (void)memcpy(buf, prop_ret, buf_len); 425 *ret_len = buf_len; 426 len = nitems - buf_len; 427 XChangeProperty(im->core.display, spec->lib_connect_wid, prop, 428 XA_STRING, 8, PropModePrepend, &prop_ret[buf_len], len); 429 } 430 XFree(prop_ret); 431 } 432 return True; 433} 434 435Private Bool 436_CheckCMEvent( 437 Display *display, 438 XEvent *event, 439 XPointer xim) 440{ 441 Xim im = (Xim)xim; 442 XSpecRec *spec = (XSpecRec *)im->private.proto.spec; 443 CARD32 major_code = spec->major_code; 444 445 if ((event->type == ClientMessage) 446 &&((event->xclient.message_type == spec->improtocolid) || 447 (event->xclient.message_type == spec->immoredataid))) 448 return True; 449 if((major_code == 1 || major_code == 2) && 450 (event->type == PropertyNotify) && 451 (event->xproperty.state == PropertyNewValue)) 452 return True; 453 return False; 454} 455 456Private Bool 457_XimXRead(Xim im, XPointer recv_buf, int buf_len, int *ret_len) 458{ 459 XEvent *ev; 460 XEvent event; 461 int len = 0; 462 XSpecRec *spec = (XSpecRec *)im->private.proto.spec; 463 XPointer arg = spec->ev; 464 465 if (!arg) { 466 bzero(&event, sizeof(XEvent)); 467 ev = &event; 468 XIfEvent(im->core.display, ev, _CheckCMEvent, (XPointer)im); 469 } else { 470 ev = (XEvent *)arg; 471 spec->ev = (XPointer)NULL; 472 } 473 if (!(_XimXGetReadData(im, recv_buf, buf_len, &len, ev))) 474 return False; 475 *ret_len = len; 476 return True; 477} 478 479Private void 480_XimXFlush(Xim im) 481{ 482 XFlush(im->core.display); 483 return; 484} 485 486Public Bool 487_XimXConf(Xim im, char *address) 488{ 489 XSpecRec *spec; 490 491 if (!(spec = (XSpecRec *)Xmalloc(sizeof(XSpecRec)))) 492 return False; 493 bzero(spec, sizeof(XSpecRec)); 494 495 spec->improtocolid = XInternAtom(im->core.display, _XIM_PROTOCOL, False); 496 spec->imconnectid = XInternAtom(im->core.display, _XIM_XCONNECT, False); 497 spec->immoredataid = XInternAtom(im->core.display, _XIM_MOREDATA, False); 498 spec->major_code = MAJOR_TRANSPORT_VERSION; 499 spec->minor_code = MINOR_TRANSPORT_VERSION; 500 501 im->private.proto.spec = (XPointer)spec; 502 im->private.proto.connect = _XimXConnect; 503 im->private.proto.shutdown = _XimXShutdown; 504 im->private.proto.write = _XimXWrite; 505 im->private.proto.read = _XimXRead; 506 im->private.proto.flush = _XimXFlush; 507 im->private.proto.register_dispatcher = _XimXRegisterDispatcher; 508 im->private.proto.call_dispatcher = _XimXCallDispatcher; 509 510 return True; 511} 512