1/* 2 * Copyright (c) 1992, Oracle and/or its affiliates. 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 63static 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 = 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 84static 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 spec->intr_cb = NULL; 97 return; 98} 99 100static 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 113static 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 141static 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 157static 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 228static 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 248static 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 259static 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 320static 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 >= (int)nitems) { 377 (void)memcpy(buf, prop_ret, (int)nitems); 378 *ret_len = (int)nitems; 379 if (bytes_after_ret > 0) { 380 XFree(prop_ret); 381 if (XGetWindowProperty(im->core.display, 382 spec->lib_connect_wid, prop, 0L, 383 ((length + bytes_after_ret + 3)/ 4), 384 True, AnyPropertyType, 385 &type_ret, &format_ret, &nitems, 386 &bytes_after_ret, 387 &prop_ret) == Success) { 388 XChangeProperty(im->core.display, spec->lib_connect_wid, prop, 389 XA_STRING, 8, PropModePrepend, &prop_ret[length], 390 (nitems - length)); 391 } else { 392 return False; 393 } 394 } 395 } else { 396 (void)memcpy(buf, prop_ret, buf_len); 397 *ret_len = buf_len; 398 len = nitems - buf_len; 399 400 if (bytes_after_ret > 0) { 401 XFree(prop_ret); 402 if (XGetWindowProperty(im->core.display, 403 spec->lib_connect_wid, prop, 0L, 404 ((length + bytes_after_ret + 3)/ 4), 405 True, AnyPropertyType, 406 &type_ret, &format_ret, &nitems, 407 &bytes_after_ret, &prop_ret) != Success) { 408 return False; 409 } 410 } 411 XChangeProperty(im->core.display, spec->lib_connect_wid, prop, 412 XA_STRING, 8, PropModePrepend, &prop_ret[buf_len], len); 413 event->xclient.data.l[0] = (long)len; 414 event->xclient.data.l[1] = (long)prop; 415 XPutBackEvent(im->core.display, event); 416 } 417 XFree(prop_ret); 418 } else if (event->type == PropertyNotify) { 419 prop = event->xproperty.atom; 420 return_code = XGetWindowProperty(im->core.display, 421 spec->lib_connect_wid, prop, 0L, 422 1000000L, True, AnyPropertyType, 423 &type_ret, &format_ret, &nitems, &bytes_after_ret, &prop_ret); 424 if (return_code != Success || format_ret == 0 || nitems == 0) { 425 if (return_code == Success) 426 XFree(prop_ret); 427 return False; 428 } 429 if (buf_len >= nitems) { 430 (void)memcpy(buf, prop_ret, (int)nitems); 431 *ret_len = (int)nitems; 432 } else { 433 (void)memcpy(buf, prop_ret, buf_len); 434 *ret_len = buf_len; 435 len = nitems - buf_len; 436 XChangeProperty(im->core.display, spec->lib_connect_wid, prop, 437 XA_STRING, 8, PropModePrepend, &prop_ret[buf_len], len); 438 } 439 XFree(prop_ret); 440 } 441 return True; 442} 443 444static Bool 445_CheckCMEvent( 446 Display *display, 447 XEvent *event, 448 XPointer xim) 449{ 450 Xim im = (Xim)xim; 451 XSpecRec *spec = (XSpecRec *)im->private.proto.spec; 452 CARD32 major_code = spec->major_code; 453 454 if ((event->type == ClientMessage) 455 &&((event->xclient.message_type == spec->improtocolid) || 456 (event->xclient.message_type == spec->immoredataid))) 457 return True; 458 if((major_code == 1 || major_code == 2) && 459 (event->type == PropertyNotify) && 460 (event->xproperty.state == PropertyNewValue)) 461 return True; 462 return False; 463} 464 465static Bool 466_XimXRead(Xim im, XPointer recv_buf, int buf_len, int *ret_len) 467{ 468 XEvent *ev; 469 XEvent event; 470 int len = 0; 471 XSpecRec *spec = (XSpecRec *)im->private.proto.spec; 472 XPointer arg = spec->ev; 473 474 if (!arg) { 475 bzero(&event, sizeof(XEvent)); 476 ev = &event; 477 XIfEvent(im->core.display, ev, _CheckCMEvent, (XPointer)im); 478 } else { 479 ev = (XEvent *)arg; 480 spec->ev = (XPointer)NULL; 481 } 482 if (!(_XimXGetReadData(im, recv_buf, buf_len, &len, ev))) 483 return False; 484 *ret_len = len; 485 return True; 486} 487 488static void 489_XimXFlush(Xim im) 490{ 491 XFlush(im->core.display); 492 return; 493} 494 495Bool 496_XimXConf(Xim im, char *address) 497{ 498 XSpecRec *spec; 499 500 if (!(spec = Xcalloc(1, sizeof(XSpecRec)))) 501 return False; 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