1 /****************************************************************** 2 3 Copyright 1992, 1993, 1994 by FUJITSU LIMITED 4 5 Permission to use, copy, modify, distribute, and sell this software 6 and its documentation for any purpose is hereby granted without fee, 7 provided that the above copyright notice appear in all copies and 8 that both that copyright notice and this permission notice appear 9 in supporting documentation, and that the name of FUJITSU LIMITED 10 not be used in advertising or publicity pertaining to distribution 11 of the software without specific, written prior permission. 12 FUJITSU LIMITED makes no representations about the suitability of 13 this software for any purpose. 14 It is provided "as is" without express or implied warranty. 15 16 FUJITSU LIMITED DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 17 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 18 EVENT SHALL FUJITSU LIMITED BE LIABLE FOR ANY SPECIAL, INDIRECT OR 19 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF 20 USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 21 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 22 PERFORMANCE OF THIS SOFTWARE. 23 24 Author: Takashi Fujiwara FUJITSU LIMITED 25 fujiwara (at) a80.tech.yk.fujitsu.co.jp 26 27 ******************************************************************/ 28 29 #ifdef HAVE_CONFIG_H 30 #include <config.h> 31 #endif 32 #include <X11/Xatom.h> 33 #include "Xlibint.h" 34 #include "Xutil.h" 35 #include "Xlcint.h" 36 #include "Ximint.h" 37 38 static long 39 _XimTriggerCheck( 40 Xim im, 41 XKeyEvent *ev, 42 INT32 len, 43 CARD32 *keylist) 44 { 45 register long i; 46 KeySym keysym; 47 CARD32 buf32[BUFSIZE/4]; 48 char *buf = (char *)buf32; 49 int modifier; 50 int modifier_mask; 51 CARD32 min_len = sizeof(CARD32) /* sizeof keysym */ 52 + sizeof(CARD32) /* sizeof modifier */ 53 + sizeof(CARD32); /* sizeof modifier mask */ 54 55 XLookupString(ev, buf, BUFSIZE, &keysym, NULL); 56 if (!keysym) 57 return -1; 58 59 for (i = 0; len >= min_len; i += 3, len -= min_len) { 60 modifier = keylist[i + 1]; 61 modifier_mask = keylist[i + 2]; 62 if (((KeySym)keylist[i] == keysym) 63 && ((ev->state & modifier_mask) == modifier)) 64 return i; 65 } 66 return -1; 67 } 68 69 static long 70 _XimTriggerOnCheck( 71 Xim im, 72 XKeyEvent *ev) 73 { 74 return _XimTriggerCheck(im, ev, (INT32)im->private.proto.im_onkeylist[0], 75 &im->private.proto.im_onkeylist[1]); 76 } 77 78 static long 79 _XimTriggerOffCheck( 80 Xim im, 81 XKeyEvent *ev) 82 { 83 return _XimTriggerCheck(im, ev, (INT32)im->private.proto.im_offkeylist[0], 84 &im->private.proto.im_offkeylist[1]); 85 } 86 87 static Bool 88 _XimOnKeysCheck( 89 Xic ic, 90 XKeyEvent *ev) 91 { 92 Xim im = (Xim)ic->core.im; 93 long idx; 94 95 if (IS_DYNAMIC_EVENT_FLOW(ic->core.im) && 96 im->private.proto.im_onkeylist && 97 im->private.proto.im_onkeylist[0]) { 98 if ((idx = _XimTriggerOnCheck(im, ev)) >= 0) { 99 (void)_XimTriggerNotify(im, ic, 0, (CARD32)idx); /* Trigger on */ 100 return True; 101 } 102 } 103 return False; 104 } 105 106 static Bool 107 _XimOffKeysCheck( 108 Xic ic, 109 XKeyEvent *ev) 110 { 111 Xim im = (Xim)ic->core.im; 112 long idx; 113 114 if (IS_DYNAMIC_EVENT_FLOW(ic->core.im) && 115 im->private.proto.im_offkeylist && 116 im->private.proto.im_offkeylist[0]) { 117 if ((idx = _XimTriggerOffCheck(im, ev)) >= 0) { 118 _XimTriggerNotify(im, ic, 1, (CARD32)idx); /* Trigger off */ 119 return True; 120 } 121 } 122 return False; 123 } 124 125 void 126 _XimPendingFilter( 127 Xic ic) 128 { 129 Xim im = (Xim)ic->core.im; 130 131 if (IS_NEED_SYNC_REPLY(im)) { 132 (void)_XimProcSyncReply(im, ic); 133 UNMARK_NEED_SYNC_REPLY(im); 134 } 135 return; 136 } 137 138 static Bool 139 _XimProtoKeypressFilter( 140 Xic ic, 141 XKeyEvent *ev, 142 Window w) 143 { 144 Xim im = (Xim)ic->core.im; 145 146 if (_XimIsFabricatedSerial(im, ev)) { 147 _XimPendingFilter(ic); 148 _XimUnfabricateSerial(im, ic, ev); 149 return NOTFILTERD; 150 } 151 /* w=0 is used for _XimIsFabricatedSerial() only */ 152 if (!w) 153 return NOTFILTERD; 154 155 if (IS_NEGLECT_EVENT(ic, KeyPressMask)) 156 return FILTERD; 157 158 #ifdef XIM_CONNECTABLE 159 if (!IS_IC_CONNECTED(ic)) { 160 if (IS_CONNECTABLE(im)) { 161 if (_XimConnectServer(im)) { 162 if (!_XimReCreateIC(ic)) { 163 _XimDelayModeSetAttr(im); 164 return NOTFILTERD; 165 } 166 } else { 167 return NOTFILTERD; 168 } 169 } else { 170 return NOTFILTERD; 171 } 172 } 173 #else 174 if (!IS_IC_CONNECTED(ic)) 175 return NOTFILTERD; 176 #endif /* XIM_CONNECTABLE */ 177 178 if (!IS_FORWARD_EVENT(ic, KeyPressMask)) { 179 if (_XimOnKeysCheck(ic, ev)) 180 return FILTERD; 181 return NOTFILTERD; 182 } 183 if (_XimOffKeysCheck(ic, ev)) 184 return FILTERD; 185 186 if (_XimForwardEvent(ic, (XEvent *)ev, 187 IS_SYNCHRONOUS_EVENT(ic, KeyPressMask))) 188 return FILTERD; 189 190 return NOTFILTERD; 191 } 192 193 static Bool 194 _XimFilterKeypress( 195 Display *d, 196 Window w, 197 XEvent *ev, 198 XPointer client_data) 199 { 200 return _XimProtoKeypressFilter((Xic)client_data, (XKeyEvent *)ev, w); 201 } 202 203 static Bool 204 _XimProtoKeyreleaseFilter( 205 Xic ic, 206 XKeyEvent *ev, 207 Window w) 208 { 209 Xim im = (Xim)ic->core.im; 210 211 if (_XimIsFabricatedSerial(im, ev)) { 212 _XimPendingFilter(ic); 213 _XimUnfabricateSerial(im, ic, ev); 214 return NOTFILTERD; 215 } 216 /* w=0 is used for _XimIsFabricatedSerial() only */ 217 if (!w) 218 return NOTFILTERD; 219 220 if (IS_NEGLECT_EVENT(ic, KeyReleaseMask)) 221 return FILTERD; 222 223 #ifdef XIM_CONNECTABLE 224 if (!IS_IC_CONNECTED(ic)) { 225 if (IS_CONNECTABLE(im)) { 226 if (_XimConnectServer(im)) { 227 if (!_XimReCreateIC(ic)) { 228 _XimDelayModeSetAttr(im); 229 return NOTFILTERD; 230 } 231 } else { 232 return NOTFILTERD; 233 } 234 } else { 235 return NOTFILTERD; 236 } 237 } 238 #else 239 if (!IS_IC_CONNECTED(ic)) 240 return NOTFILTERD; 241 #endif /* XIM_CONNECTABLE */ 242 243 if (!IS_FORWARD_EVENT(ic, KeyReleaseMask)) { 244 if (_XimOnKeysCheck(ic, ev)) 245 return FILTERD; 246 return NOTFILTERD; 247 } 248 if (_XimOffKeysCheck(ic, ev)) 249 return FILTERD; 250 251 if (_XimForwardEvent(ic, (XEvent *)ev, 252 IS_SYNCHRONOUS_EVENT(ic, KeyPressMask))) 253 return FILTERD; 254 255 return NOTFILTERD; 256 } 257 258 static Bool 259 _XimFilterKeyrelease( 260 Display *d, 261 Window w, 262 XEvent *ev, 263 XPointer client_data) 264 { 265 return _XimProtoKeyreleaseFilter((Xic)client_data, (XKeyEvent *)ev, w); 266 } 267 268 static void 269 _XimRegisterKeyPressFilter( 270 Xic ic) 271 { 272 if (ic->core.focus_window) { 273 if (!(ic->private.proto.registed_filter_event & KEYPRESS_MASK)) { 274 _XRegisterFilterByType (ic->core.im->core.display, 275 0, 276 KeyPress, KeyPress, 277 _XimFilterKeypress, 278 (XPointer)ic); 279 _XRegisterFilterByType (ic->core.im->core.display, 280 ic->core.focus_window, 281 KeyPress, KeyPress, 282 _XimFilterKeypress, 283 (XPointer)ic); 284 ic->private.proto.registed_filter_event |= KEYPRESS_MASK; 285 } 286 } 287 return; 288 } 289 290 static void 291 _XimRegisterKeyReleaseFilter( 292 Xic ic) 293 { 294 if (ic->core.focus_window) { 295 if (!(ic->private.proto.registed_filter_event & KEYRELEASE_MASK)) { 296 _XRegisterFilterByType (ic->core.im->core.display, 297 0, 298 KeyRelease, KeyRelease, 299 _XimFilterKeyrelease, 300 (XPointer)ic); 301 _XRegisterFilterByType (ic->core.im->core.display, 302 ic->core.focus_window, 303 KeyRelease, KeyRelease, 304 _XimFilterKeyrelease, 305 (XPointer)ic); 306 ic->private.proto.registed_filter_event |= KEYRELEASE_MASK; 307 } 308 } 309 return; 310 } 311 312 static void 313 _XimUnregisterKeyPressFilter( 314 Xic ic) 315 { 316 if (ic->core.focus_window) { 317 if (ic->private.proto.registed_filter_event & KEYPRESS_MASK) { 318 _XUnregisterFilter (ic->core.im->core.display, 319 ic->core.focus_window, 320 _XimFilterKeypress, 321 (XPointer)ic); 322 _XUnregisterFilter (ic->core.im->core.display, 323 0, 324 _XimFilterKeypress, 325 (XPointer)ic); 326 ic->private.proto.registed_filter_event &= ~KEYPRESS_MASK; 327 } 328 } 329 return; 330 } 331 332 static void 333 _XimUnregisterKeyReleaseFilter( 334 Xic ic) 335 { 336 if (ic->core.focus_window) { 337 if (ic->private.proto.registed_filter_event & KEYRELEASE_MASK) { 338 _XUnregisterFilter (ic->core.im->core.display, 339 ic->core.focus_window, 340 _XimFilterKeyrelease, 341 (XPointer)ic); 342 _XUnregisterFilter (ic->core.im->core.display, 343 0, 344 _XimFilterKeyrelease, 345 (XPointer)ic); 346 ic->private.proto.registed_filter_event &= ~KEYRELEASE_MASK; 347 } 348 } 349 return; 350 } 351 352 void 353 _XimRegisterFilter( 354 Xic ic) 355 { 356 _XimRegisterKeyPressFilter(ic); 357 if (IS_FORWARD_EVENT(ic, KeyReleaseMask)) 358 _XimRegisterKeyReleaseFilter(ic); 359 return; 360 } 361 362 void 363 _XimUnregisterFilter( 364 Xic ic) 365 { 366 Xim im = (Xim)ic->core.im; 367 _XimUnregisterKeyPressFilter(ic); 368 _XimUnregisterKeyReleaseFilter(ic); 369 /* It is possible that the event from IM is received after unregister 370 * the filter. 371 * Reset any existing fabricated state since we will not be able to 372 * clear the fabricated state for those event in filter. 373 */ 374 im->private.proto.fabricated_serial = 0; 375 im->private.proto.fabricated_time = 0; 376 UNMARK_FABRICATED(im); 377 _XimPendingFilter(ic); 378 return; 379 } 380 381 void 382 _XimReregisterFilter( 383 Xic ic) 384 { 385 if (IS_FORWARD_EVENT(ic, KeyReleaseMask)) 386 _XimRegisterKeyReleaseFilter(ic); 387 else 388 _XimUnregisterKeyReleaseFilter(ic); 389 390 return; 391 } 392 393 static Bool 394 _XimFilterServerDestroy( 395 Display *d, 396 Window w, 397 XEvent *ev, 398 XPointer client_data) 399 { 400 Xim im = (Xim)client_data; 401 402 if (ev->type == DestroyNotify) { 403 UNMARK_SERVER_CONNECTED(im); 404 #ifdef XIM_CONNECTABLE 405 if (!IS_SERVER_CONNECTED(im) && IS_RECONNECTABLE(im)) { 406 _XimServerReconectableDestroy(); 407 return True; 408 } 409 #endif /* XIM_CONNECTABLE */ 410 _XimServerDestroy(im); 411 } 412 return True; 413 } 414 415 void 416 _XimRegisterServerFilter( 417 Xim im) 418 { 419 if (im->private.proto.im_window) { 420 if (!(im->private.proto.registed_filter_event & DESTROYNOTIFY_MASK)) { 421 _XRegisterFilterByMask(im->core.display, 422 im->private.proto.im_window, 423 StructureNotifyMask, 424 _XimFilterServerDestroy, 425 (XPointer)im); 426 XSelectInput(im->core.display, im->private.proto.im_window, 427 StructureNotifyMask); 428 im->private.proto.registed_filter_event |= DESTROYNOTIFY_MASK; 429 } 430 } 431 return; 432 } 433 434 void 435 _XimUnregisterServerFilter( 436 Xim im) 437 { 438 if (im->private.proto.im_window) { 439 if (im->private.proto.registed_filter_event & DESTROYNOTIFY_MASK) { 440 _XUnregisterFilter(im->core.display, 441 im->private.proto.im_window, 442 _XimFilterServerDestroy, 443 (XPointer)im); 444 im->private.proto.registed_filter_event &= ~DESTROYNOTIFY_MASK; 445 } 446 } 447 return; 448 } 449 450