Event.c revision 35525df4
1/*********************************************************** 2Copyright (c) 1993, Oracle and/or its affiliates. 3 4Permission is hereby granted, free of charge, to any person obtaining a 5copy of this software and associated documentation files (the "Software"), 6to deal in the Software without restriction, including without limitation 7the rights to use, copy, modify, merge, publish, distribute, sublicense, 8and/or sell copies of the Software, and to permit persons to whom the 9Software is furnished to do so, subject to the following conditions: 10 11The above copyright notice and this permission notice (including the next 12paragraph) shall be included in all copies or substantial portions of the 13Software. 14 15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21DEALINGS IN THE SOFTWARE. 22 23Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. 24 25 All Rights Reserved 26 27Permission to use, copy, modify, and distribute this software and its 28documentation for any purpose and without fee is hereby granted, 29provided that the above copyright notice appear in all copies and that 30both that copyright notice and this permission notice appear in 31supporting documentation, and that the name of Digital not be 32used in advertising or publicity pertaining to distribution of the 33software without specific, written prior permission. 34 35DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 36ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 37DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 38ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 39WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 40ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 41SOFTWARE. 42 43******************************************************************/ 44 45/* 46 47Copyright 1987, 1988, 1998 The Open Group 48 49Permission to use, copy, modify, distribute, and sell this software and its 50documentation for any purpose is hereby granted without fee, provided that 51the above copyright notice appear in all copies and that both that 52copyright notice and this permission notice appear in supporting 53documentation. 54 55The above copyright notice and this permission notice shall be included in 56all copies or substantial portions of the Software. 57 58THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 59IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 60FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 61OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 62AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 63CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 64 65Except as contained in this notice, the name of The Open Group shall not be 66used in advertising or otherwise to promote the sale, use or other dealings 67in this Software without prior written authorization from The Open Group. 68 69*/ 70 71#ifdef HAVE_CONFIG_H 72#include <config.h> 73#endif 74#include "IntrinsicI.h" 75#include "Shell.h" 76#include "StringDefs.h" 77 78typedef struct _XtEventRecExt { 79 int type; 80 XtPointer select_data[1]; /* actual dimension is [mask] */ 81} XtEventRecExt; 82 83#define EXT_TYPE(p) (((XtEventRecExt*) ((p)+1))->type) 84#define EXT_SELECT_DATA(p,n) (((XtEventRecExt*) ((p)+1))->select_data[n]) 85 86#define NonMaskableMask ((EventMask)0x80000000L) 87 88/* 89 * These are definitions to make the code that handles exposure compression 90 * easier to read. 91 * 92 * COMP_EXPOSE - The compression exposure field of "widget" 93 * COMP_EXPOSE_TYPE - The type of compression (lower 4 bits of COMP_EXPOSE. 94 * GRAPHICS_EXPOSE - TRUE if the widget wants graphics expose events 95 * dispatched. 96 * NO_EXPOSE - TRUE if the widget wants No expose events dispatched. 97 */ 98 99#define COMP_EXPOSE (widget->core.widget_class->core_class.compress_exposure) 100#define COMP_EXPOSE_TYPE (COMP_EXPOSE & 0x0f) 101#define GRAPHICS_EXPOSE ((XtExposeGraphicsExpose & COMP_EXPOSE) || \ 102 (XtExposeGraphicsExposeMerged & COMP_EXPOSE)) 103#define NO_EXPOSE (XtExposeNoExpose & COMP_EXPOSE) 104 105EventMask 106XtBuildEventMask(Widget widget) 107{ 108 EventMask mask = 0L; 109 110 if (widget != NULL) { 111 XtEventTable ev; 112 113 WIDGET_TO_APPCON(widget); 114 115 LOCK_APP(app); 116 for (ev = widget->core.event_table; ev != NULL; ev = ev->next) { 117 if (!ev->select) 118 continue; 119 120 if (!ev->has_type_specifier) 121 mask |= ev->mask; 122 else { 123 if (EXT_TYPE(ev) < LASTEvent) { 124 Cardinal i; 125 126 for (i = 0; i < ev->mask; i++) 127 if (EXT_SELECT_DATA(ev, i)) 128 mask |= *(EventMask *) EXT_SELECT_DATA(ev, i); 129 } 130 } 131 } 132 LOCK_PROCESS; 133 if (widget->core.widget_class->core_class.expose != NULL) 134 mask |= ExposureMask; 135 if (widget->core.widget_class->core_class.visible_interest) 136 mask |= VisibilityChangeMask; 137 UNLOCK_PROCESS; 138 if (widget->core.tm.translations) 139 mask |= widget->core.tm.translations->eventMask; 140 141 mask = mask & ~NonMaskableMask; 142 UNLOCK_APP(app); 143 } 144 return mask; 145} 146 147static void 148CallExtensionSelector(Widget widget, ExtSelectRec *rec, Boolean forceCall) 149{ 150 XtEventRec *p; 151 XtPointer *data; 152 int *types; 153 Cardinal i, count = 0; 154 155 for (p = widget->core.event_table; p != NULL; p = p->next) 156 if (p->has_type_specifier && 157 EXT_TYPE(p) >= rec->min && EXT_TYPE(p) <= rec->max) 158 count = (Cardinal) (count + p->mask); 159 160 if (count == 0 && !forceCall) 161 return; 162 163 data = (XtPointer *) ALLOCATE_LOCAL(count * sizeof(XtPointer)); 164 types = (int *) ALLOCATE_LOCAL(count * sizeof(int)); 165 count = 0; 166 167 for (p = widget->core.event_table; p != NULL; p = p->next) 168 if (p->has_type_specifier && 169 EXT_TYPE(p) >= rec->min && EXT_TYPE(p) <= rec->max) 170 for (i = 0; i < p->mask; i++) { 171 types[count] = EXT_TYPE(p); 172 data[count++] = EXT_SELECT_DATA(p, i); 173 } 174 175 (*rec->proc) (widget, types, data, (int) count, rec->client_data); 176 DEALLOCATE_LOCAL((char *) types); 177 DEALLOCATE_LOCAL((char *) data); 178} 179 180static void 181RemoveEventHandler(Widget widget, 182 XtPointer select_data, 183 int type, 184 Boolean has_type_specifier, 185 Boolean other, 186 const XtEventHandler proc, 187 const XtPointer closure, 188 Boolean raw) 189{ 190 XtEventRec *p, **pp; 191 EventMask oldMask = XtBuildEventMask(widget); 192 193 if (raw) 194 raw = 1; 195 pp = &widget->core.event_table; 196 while ((p = *pp) && 197 (p->proc != proc || p->closure != closure || p->select == raw || 198 has_type_specifier != p->has_type_specifier || 199 (has_type_specifier && EXT_TYPE(p) != type))) 200 pp = &p->next; 201 if (!p) 202 return; 203 204 /* un-register it */ 205 if (!has_type_specifier) { 206 EventMask eventMask = *(EventMask *) select_data; 207 208 eventMask &= ~NonMaskableMask; 209 if (other) 210 eventMask |= NonMaskableMask; 211 p->mask &= ~eventMask; 212 } 213 else { 214 Cardinal i; 215 216 /* p->mask specifies count of EXT_SELECT_DATA(p,i) 217 * search through the list of selection data, if not found 218 * don't remove this handler 219 */ 220 for (i = 0; i < p->mask && select_data != EXT_SELECT_DATA(p, i);) 221 i++; 222 if (i == p->mask) 223 return; 224 if (p->mask == 1) 225 p->mask = 0; 226 else { 227 p->mask--; 228 while (i < p->mask) { 229 EXT_SELECT_DATA(p, i) = EXT_SELECT_DATA(p, i + 1); 230 i++; 231 } 232 } 233 } 234 235 if (!p->mask) { /* delete it entirely */ 236 *pp = p->next; 237 XtFree((char *) p); 238 } 239 240 /* Reset select mask if realized and not raw. */ 241 if (!raw && XtIsRealized(widget) && !widget->core.being_destroyed) { 242 EventMask mask = XtBuildEventMask(widget); 243 Display *dpy = XtDisplay(widget); 244 245 if (oldMask != mask) 246 XSelectInput(dpy, XtWindow(widget), (long) mask); 247 248 if (has_type_specifier) { 249 XtPerDisplay pd = _XtGetPerDisplay(dpy); 250 int i; 251 252 for (i = 0; i < pd->ext_select_count; i++) { 253 if (type >= pd->ext_select_list[i].min && 254 type <= pd->ext_select_list[i].max) { 255 CallExtensionSelector(widget, pd->ext_select_list + i, 256 TRUE); 257 break; 258 } 259 if (type < pd->ext_select_list[i].min) 260 break; 261 } 262 } 263 } 264} 265 266/* Function Name: AddEventHandler 267 * Description: An Internal routine that does the actual work of 268 * adding the event handlers. 269 * Arguments: widget - widget to register an event handler for. 270 * eventMask - events to mask for. 271 * other - pass non maskable events to this procedure. 272 * proc - procedure to register. 273 * closure - data to pass to the event handler. 274 * position - where to add this event handler. 275 * force_new_position - If the element is already in the 276 * list, this will force it to the 277 * beginning or end depending on position. 278 * raw - If FALSE call XSelectInput for events in mask. 279 * Returns: none 280 */ 281 282static void 283AddEventHandler(Widget widget, 284 XtPointer select_data, 285 int type, 286 Boolean has_type_specifier, 287 Boolean other, 288 XtEventHandler proc, 289 XtPointer closure, 290 XtListPosition position, 291 Boolean force_new_position, 292 Boolean raw) 293{ 294 register XtEventRec *p, **pp; 295 EventMask oldMask = 0, eventMask = 0; 296 297 if (!has_type_specifier) { 298 eventMask = *(EventMask *) select_data & ~NonMaskableMask; 299 if (other) 300 eventMask |= NonMaskableMask; 301 if (!eventMask) 302 return; 303 } 304 else if (!type) 305 return; 306 307 if (XtIsRealized(widget) && !raw) 308 oldMask = XtBuildEventMask(widget); 309 310 if (raw) 311 raw = 1; 312 pp = &widget->core.event_table; 313 while ((p = *pp) && 314 (p->proc != proc || p->closure != closure || p->select == raw || 315 has_type_specifier != p->has_type_specifier || 316 (has_type_specifier && EXT_TYPE(p) != type))) 317 pp = &p->next; 318 319 if (!p) { /* New proc to add to list */ 320 if (has_type_specifier) { 321 p = (XtEventRec *) __XtMalloc(sizeof(XtEventRec) + 322 sizeof(XtEventRecExt)); 323 EXT_TYPE(p) = type; 324 EXT_SELECT_DATA(p, 0) = select_data; 325 p->mask = 1; 326 p->has_type_specifier = True; 327 } 328 else { 329 p = (XtEventRec *) __XtMalloc(sizeof(XtEventRec)); 330 p->mask = eventMask; 331 p->has_type_specifier = False; 332 } 333 p->proc = proc; 334 p->closure = closure; 335 p->select = !raw; 336 337 if (position == XtListHead) { 338 p->next = widget->core.event_table; 339 widget->core.event_table = p; 340 } 341 else { 342 *pp = p; 343 p->next = NULL; 344 } 345 } 346 else { 347 if (force_new_position) { 348 *pp = p->next; 349 350 if (position == XtListHead) { 351 p->next = widget->core.event_table; 352 widget->core.event_table = p; 353 } 354 else { 355 /* 356 * Find the last element in the list. 357 */ 358 while (*pp) 359 pp = &(*pp)->next; 360 *pp = p; 361 p->next = NULL; 362 } 363 } 364 365 if (!has_type_specifier) 366 p->mask |= eventMask; 367 else { 368 Cardinal i; 369 370 /* p->mask specifies count of EXT_SELECT_DATA(p,i) */ 371 for (i = 0; i < p->mask && select_data != EXT_SELECT_DATA(p, i);) 372 i++; 373 if (i == p->mask) { 374 p = (XtEventRec *) XtRealloc((char *) p, 375 (Cardinal) (sizeof(XtEventRec) + 376 sizeof(XtEventRecExt) + 377 p->mask * 378 sizeof(XtPointer))); 379 EXT_SELECT_DATA(p, i) = select_data; 380 p->mask++; 381 *pp = p; 382 } 383 } 384 } 385 386 if (XtIsRealized(widget) && !raw) { 387 EventMask mask = XtBuildEventMask(widget); 388 Display *dpy = XtDisplay(widget); 389 390 if (oldMask != mask) 391 XSelectInput(dpy, XtWindow(widget), (long) mask); 392 393 if (has_type_specifier) { 394 XtPerDisplay pd = _XtGetPerDisplay(dpy); 395 int i; 396 397 for (i = 0; i < pd->ext_select_count; i++) { 398 if (type >= pd->ext_select_list[i].min && 399 type <= pd->ext_select_list[i].max) { 400 CallExtensionSelector(widget, pd->ext_select_list + i, 401 FALSE); 402 break; 403 } 404 if (type < pd->ext_select_list[i].min) 405 break; 406 } 407 } 408 } 409} 410 411void 412XtRemoveEventHandler(Widget widget, 413 EventMask eventMask, 414 _XtBoolean other, 415 XtEventHandler proc, 416 XtPointer closure) 417{ 418 WIDGET_TO_APPCON(widget); 419 LOCK_APP(app); 420 RemoveEventHandler(widget, (XtPointer) &eventMask, 0, FALSE, 421 (Boolean) other, proc, closure, FALSE); 422 UNLOCK_APP(app); 423} 424 425void 426XtAddEventHandler(Widget widget, 427 EventMask eventMask, 428 _XtBoolean other, 429 XtEventHandler proc, 430 XtPointer closure) 431{ 432 WIDGET_TO_APPCON(widget); 433 LOCK_APP(app); 434 AddEventHandler(widget, (XtPointer) &eventMask, 0, FALSE, (Boolean) other, 435 proc, closure, XtListTail, FALSE, FALSE); 436 UNLOCK_APP(app); 437} 438 439void 440XtInsertEventHandler(Widget widget, 441 EventMask eventMask, 442 _XtBoolean other, 443 XtEventHandler proc, 444 XtPointer closure, 445 XtListPosition position) 446{ 447 WIDGET_TO_APPCON(widget); 448 LOCK_APP(app); 449 AddEventHandler(widget, (XtPointer) &eventMask, 0, FALSE, (Boolean) other, 450 proc, closure, position, TRUE, FALSE); 451 UNLOCK_APP(app); 452} 453 454void 455XtRemoveRawEventHandler(Widget widget, 456 EventMask eventMask, 457 _XtBoolean other, 458 XtEventHandler proc, 459 XtPointer closure) 460{ 461 WIDGET_TO_APPCON(widget); 462 LOCK_APP(app); 463 RemoveEventHandler(widget, (XtPointer) &eventMask, 0, FALSE, 464 (Boolean) other, proc, closure, TRUE); 465 UNLOCK_APP(app); 466} 467 468void 469XtInsertRawEventHandler(Widget widget, 470 EventMask eventMask, 471 _XtBoolean other, 472 XtEventHandler proc, 473 XtPointer closure, 474 XtListPosition position) 475{ 476 WIDGET_TO_APPCON(widget); 477 LOCK_APP(app); 478 AddEventHandler(widget, (XtPointer) &eventMask, 0, FALSE, (Boolean) other, 479 proc, closure, position, TRUE, TRUE); 480 UNLOCK_APP(app); 481} 482 483void 484XtAddRawEventHandler(Widget widget, 485 EventMask eventMask, 486 _XtBoolean other, 487 XtEventHandler proc, 488 XtPointer closure) 489{ 490 WIDGET_TO_APPCON(widget); 491 LOCK_APP(app); 492 AddEventHandler(widget, (XtPointer) &eventMask, 0, FALSE, (Boolean) other, 493 proc, closure, XtListTail, FALSE, TRUE); 494 UNLOCK_APP(app); 495} 496 497void 498XtRemoveEventTypeHandler(Widget widget, 499 int type, 500 XtPointer select_data, 501 XtEventHandler proc, 502 XtPointer closure) 503{ 504 WIDGET_TO_APPCON(widget); 505 LOCK_APP(app); 506 RemoveEventHandler(widget, select_data, type, TRUE, 507 FALSE, proc, closure, FALSE); 508 UNLOCK_APP(app); 509} 510 511void 512XtInsertEventTypeHandler(Widget widget, 513 int type, 514 XtPointer select_data, 515 XtEventHandler proc, 516 XtPointer closure, 517 XtListPosition position) 518{ 519 WIDGET_TO_APPCON(widget); 520 LOCK_APP(app); 521 AddEventHandler(widget, select_data, type, TRUE, FALSE, 522 proc, closure, position, TRUE, FALSE); 523 UNLOCK_APP(app); 524} 525 526typedef struct _WWPair { 527 struct _WWPair *next; 528 Window window; 529 Widget widget; 530} *WWPair; 531 532typedef struct _WWTable { 533 unsigned int mask; /* size of hash table - 1 */ 534 unsigned int rehash; /* mask - 2 */ 535 unsigned int occupied; /* number of occupied entries */ 536 unsigned int fakes; /* number occupied by WWfake */ 537 Widget *entries; /* the entries */ 538 WWPair pairs; /* bogus entries */ 539} *WWTable; 540 541static const WidgetRec WWfake; /* placeholder for deletions */ 542 543#define WWHASH(tab,win) ((win) & tab->mask) 544#define WWREHASHVAL(tab,win) ((((win) % tab->rehash) + 2) | 1) 545#define WWREHASH(tab,idx,rehash) ((unsigned)(idx + rehash) & (tab->mask)) 546#define WWTABLE(display) (_XtGetPerDisplay(display)->WWtable) 547 548static void ExpandWWTable(WWTable); 549 550void 551XtRegisterDrawable(Display *display, Drawable drawable, Widget widget) 552{ 553 WWTable tab; 554 int idx; 555 Widget entry; 556 Window window = (Window) drawable; 557 558 WIDGET_TO_APPCON(widget); 559 560 LOCK_APP(app); 561 LOCK_PROCESS; 562 tab = WWTABLE(display); 563 564 if (window != XtWindow(widget)) { 565 WWPair pair; 566 pair = XtNew(struct _WWPair); 567 568 pair->next = tab->pairs; 569 pair->window = window; 570 pair->widget = widget; 571 tab->pairs = pair; 572 UNLOCK_PROCESS; 573 UNLOCK_APP(app); 574 return; 575 } 576 if ((tab->occupied + (tab->occupied >> 2)) > tab->mask) 577 ExpandWWTable(tab); 578 579 idx = (int) WWHASH(tab, window); 580 if ((entry = tab->entries[idx]) && entry != &WWfake) { 581 int rehash = (int) WWREHASHVAL(tab, window); 582 583 do { 584 idx = (int) WWREHASH(tab, idx, rehash); 585 } while ((entry = tab->entries[idx]) && entry != &WWfake); 586 } 587 if (!entry) 588 tab->occupied++; 589 else if (entry == &WWfake) 590 tab->fakes--; 591 tab->entries[idx] = widget; 592 UNLOCK_PROCESS; 593 UNLOCK_APP(app); 594} 595 596void 597XtUnregisterDrawable(Display *display, Drawable drawable) 598{ 599 WWTable tab; 600 int idx; 601 Widget entry; 602 Window window = (Window) drawable; 603 Widget widget = XtWindowToWidget(display, window); 604 DPY_TO_APPCON(display); 605 606 if (widget == NULL) 607 return; 608 609 LOCK_APP(app); 610 LOCK_PROCESS; 611 tab = WWTABLE(display); 612 if (window != XtWindow(widget)) { 613 WWPair *prev, pair; 614 615 prev = &tab->pairs; 616 while ((pair = *prev) && pair->window != window) 617 prev = &pair->next; 618 if (pair) { 619 *prev = pair->next; 620 XtFree((char *) pair); 621 } 622 UNLOCK_PROCESS; 623 UNLOCK_APP(app); 624 return; 625 } 626 idx = (int) WWHASH(tab, window); 627 if ((entry = tab->entries[idx])) { 628 if (entry != widget) { 629 int rehash = (int) WWREHASHVAL(tab, window); 630 631 do { 632 idx = (int) WWREHASH(tab, idx, rehash); 633 if (!(entry = tab->entries[idx])) { 634 UNLOCK_PROCESS; 635 UNLOCK_APP(app); 636 return; 637 } 638 } while (entry != widget); 639 } 640 tab->entries[idx] = (Widget) &WWfake; 641 tab->fakes++; 642 } 643 UNLOCK_PROCESS; 644 UNLOCK_APP(app); 645} 646 647static void 648ExpandWWTable(register WWTable tab) 649{ 650 unsigned int oldmask; 651 register Widget *oldentries, *entries; 652 register Cardinal oldidx, newidx, rehash; 653 register Widget entry; 654 655 LOCK_PROCESS; 656 oldmask = tab->mask; 657 oldentries = tab->entries; 658 tab->occupied -= tab->fakes; 659 tab->fakes = 0; 660 if ((tab->occupied + (tab->occupied >> 2)) > tab->mask) { 661 tab->mask = (tab->mask << 1) + 1; 662 tab->rehash = tab->mask - 2; 663 } 664 entries = tab->entries = 665 (Widget *) __XtCalloc(tab->mask + 1, sizeof(Widget)); 666 for (oldidx = 0; oldidx <= oldmask; oldidx++) { 667 if ((entry = oldentries[oldidx]) && entry != &WWfake) { 668 newidx = (Cardinal) WWHASH(tab, XtWindow(entry)); 669 if (entries[newidx]) { 670 rehash = (Cardinal) WWREHASHVAL(tab, XtWindow(entry)); 671 do { 672 newidx = (Cardinal) WWREHASH(tab, newidx, rehash); 673 } while (entries[newidx]); 674 } 675 entries[newidx] = entry; 676 } 677 } 678 XtFree((char *) oldentries); 679 UNLOCK_PROCESS; 680} 681 682Widget 683XtWindowToWidget(register Display *display, register Window window) 684{ 685 WWTable tab; 686 int idx; 687 Widget entry; 688 WWPair pair; 689 DPY_TO_APPCON(display); 690 691 if (!window) 692 return NULL; 693 694 LOCK_APP(app); 695 LOCK_PROCESS; 696 tab = WWTABLE(display); 697 idx = (int) WWHASH(tab, window); 698 if ((entry = tab->entries[idx]) && XtWindow(entry) != window) { 699 int rehash = (int) WWREHASHVAL(tab, window); 700 701 do { 702 idx = (int) WWREHASH(tab, idx, rehash); 703 } while ((entry = tab->entries[idx]) && XtWindow(entry) != window); 704 } 705 if (entry) { 706 UNLOCK_PROCESS; 707 UNLOCK_APP(app); 708 return entry; 709 } 710 for (pair = tab->pairs; pair; pair = pair->next) { 711 if (pair->window == window) { 712 entry = pair->widget; 713 UNLOCK_PROCESS; 714 UNLOCK_APP(app); 715 return entry; 716 } 717 } 718 UNLOCK_PROCESS; 719 UNLOCK_APP(app); 720 return NULL; 721} 722 723void 724_XtAllocWWTable(XtPerDisplay pd) 725{ 726 register WWTable tab; 727 728 tab = (WWTable) __XtMalloc(sizeof(struct _WWTable)); 729 tab->mask = 0x7f; 730 tab->rehash = tab->mask - 2; 731 tab->entries = (Widget *) __XtCalloc(tab->mask + 1, sizeof(Widget)); 732 tab->occupied = 0; 733 tab->fakes = 0; 734 tab->pairs = NULL; 735 pd->WWtable = tab; 736} 737 738void 739_XtFreeWWTable(register XtPerDisplay pd) 740{ 741 register WWPair pair, next; 742 743 for (pair = pd->WWtable->pairs; pair; pair = next) { 744 next = pair->next; 745 XtFree((char *) pair); 746 } 747 XtFree((char *) pd->WWtable->entries); 748 XtFree((char *) pd->WWtable); 749} 750 751#define EHMAXSIZE 25 /* do not make whopping big */ 752 753static Boolean 754CallEventHandlers(Widget widget, XEvent *event, EventMask mask) 755{ 756 register XtEventRec *p; 757 XtEventHandler *proc; 758 XtPointer *closure; 759 Boolean cont_to_disp = True; 760 int i, numprocs; 761 762 /* Have to copy the procs into an array, because one of them might 763 * call XtRemoveEventHandler, which would break our linked list. */ 764 765 numprocs = 0; 766 for (p = widget->core.event_table; p; p = p->next) { 767 if ((!p->has_type_specifier && (mask & p->mask)) || 768 (p->has_type_specifier && event->type == EXT_TYPE(p))) 769 numprocs++; 770 } 771 proc = XtMallocArray((Cardinal) numprocs, (Cardinal) 772 (sizeof(XtEventHandler) + sizeof(XtPointer))); 773 closure = (XtPointer *) (proc + numprocs); 774 775 numprocs = 0; 776 for (p = widget->core.event_table; p; p = p->next) { 777 if ((!p->has_type_specifier && (mask & p->mask)) || 778 (p->has_type_specifier && event->type == EXT_TYPE(p))) { 779 proc[numprocs] = p->proc; 780 closure[numprocs] = p->closure; 781 numprocs++; 782 } 783 } 784 /* FUNCTIONS CALLED THROUGH POINTER proc: 785 Selection.c:ReqCleanup, 786 "Shell.c":EventHandler, 787 PassivGrab.c:ActiveHandler, 788 PassivGrab.c:RealizeHandler, 789 Keyboard.c:QueryEventMask, 790 _XtHandleFocus, 791 Selection.c:HandleSelectionReplies, 792 Selection.c:HandleGetIncrement, 793 Selection.c:HandleIncremental, 794 Selection.c:HandlePropertyGone, 795 Selection.c:HandleSelectionEvents 796 */ 797 for (i = 0; i < numprocs && cont_to_disp; i++) 798 (*(proc[i])) (widget, closure[i], event, &cont_to_disp); 799 XtFree((char *) proc); 800 return cont_to_disp; 801} 802 803static void CompressExposures(XEvent *, Widget); 804 805#define KnownButtons (Button1MotionMask|Button2MotionMask|Button3MotionMask|\ 806 Button4MotionMask|Button5MotionMask) 807 808/* keep this SMALL to avoid blowing stack cache! */ 809/* because some compilers allocate all local locals on procedure entry */ 810#define EHSIZE 4 811 812Boolean 813XtDispatchEventToWidget(Widget widget, XEvent *event) 814{ 815 register XtEventRec *p; 816 Boolean was_dispatched = False; 817 Boolean call_tm = False; 818 Boolean cont_to_disp; 819 EventMask mask; 820 821 WIDGET_TO_APPCON(widget); 822 823 LOCK_APP(app); 824 825 mask = _XtConvertTypeToMask(event->type); 826 if (event->type == MotionNotify) 827 mask |= (event->xmotion.state & KnownButtons); 828 829 LOCK_PROCESS; 830 if ((mask == ExposureMask) || 831 ((event->type == NoExpose) && NO_EXPOSE) || 832 ((event->type == GraphicsExpose) && GRAPHICS_EXPOSE)) { 833 834 if (widget->core.widget_class->core_class.expose != NULL) { 835 836 /* We need to mask off the bits that could contain the information 837 * about whether or not we desire Graphics and NoExpose events. */ 838 839 if ((COMP_EXPOSE_TYPE == XtExposeNoCompress) || 840 (event->type == NoExpose)) 841 842 (*widget->core.widget_class->core_class.expose) 843 (widget, event, (Region) NULL); 844 else { 845 CompressExposures(event, widget); 846 } 847 was_dispatched = True; 848 } 849 } 850 851 if ((mask == VisibilityChangeMask) && 852 XtClass(widget)->core_class.visible_interest) { 853 was_dispatched = True; 854 /* our visibility just changed... */ 855 switch (((XVisibilityEvent *) event)->state) { 856 case VisibilityUnobscured: 857 widget->core.visible = TRUE; 858 break; 859 860 case VisibilityPartiallyObscured: 861 /* what do we want to say here? */ 862 /* well... some of us is visible */ 863 widget->core.visible = TRUE; 864 break; 865 866 case VisibilityFullyObscured: 867 widget->core.visible = FALSE; 868 /* do we want to mark our children obscured? */ 869 break; 870 } 871 } 872 UNLOCK_PROCESS; 873 874 /* to maintain "copy" semantics we check TM now but call later */ 875 if (widget->core.tm.translations && 876 (mask & widget->core.tm.translations->eventMask)) 877 call_tm = True; 878 879 cont_to_disp = True; 880 p = widget->core.event_table; 881 if (p) { 882 if (p->next) { 883 XtEventHandler proc[EHSIZE]; 884 XtPointer closure[EHSIZE]; 885 int numprocs = 0; 886 887 /* Have to copy the procs into an array, because one of them might 888 * call XtRemoveEventHandler, which would break our linked list. */ 889 890 for (; p; p = p->next) { 891 if ((!p->has_type_specifier && (mask & p->mask)) || 892 (p->has_type_specifier && event->type == EXT_TYPE(p))) { 893 if (numprocs >= EHSIZE) 894 break; 895 proc[numprocs] = p->proc; 896 closure[numprocs] = p->closure; 897 numprocs++; 898 } 899 } 900 if (numprocs) { 901 if (p) { 902 cont_to_disp = CallEventHandlers(widget, event, mask); 903 } 904 else { 905 int i; 906 907 for (i = 0; i < numprocs && cont_to_disp; i++) 908 (*(proc[i])) (widget, closure[i], event, &cont_to_disp); 909 /* FUNCTIONS CALLED THROUGH POINTER proc: 910 Selection.c:ReqCleanup, 911 "Shell.c":EventHandler, 912 PassivGrab.c:ActiveHandler, 913 PassivGrab.c:RealizeHandler, 914 Keyboard.c:QueryEventMask, 915 _XtHandleFocus, 916 Selection.c:HandleSelectionReplies, 917 Selection.c:HandleGetIncrement, 918 Selection.c:HandleIncremental, 919 Selection.c:HandlePropertyGone, 920 Selection.c:HandleSelectionEvents 921 */ 922 } 923 was_dispatched = True; 924 } 925 } 926 else if ((!p->has_type_specifier && (mask & p->mask)) || 927 (p->has_type_specifier && event->type == EXT_TYPE(p))) { 928 (*p->proc) (widget, p->closure, event, &cont_to_disp); 929 was_dispatched = True; 930 } 931 } 932 if (call_tm && cont_to_disp) 933 _XtTranslateEvent(widget, event); 934 UNLOCK_APP(app); 935 return (was_dispatched | call_tm); 936} 937 938/* 939 * This structure is passed into the check exposure proc. 940 */ 941 942typedef struct _CheckExposeInfo { 943 int type1, type2; /* Types of events to check for. */ 944 Boolean maximal; /* Ignore non-exposure events? */ 945 Boolean non_matching; /* Was there an event that did not 946 match either type? */ 947 Window window; /* Window to match. */ 948} CheckExposeInfo; 949 950#define GetCount(ev) (((XExposeEvent *)(ev))->count) 951 952static void SendExposureEvent(XEvent *, Widget, XtPerDisplay); 953static Bool CheckExposureEvent(Display *, XEvent *, char *); 954static void AddExposureToRectangularRegion(XEvent *, Region); 955 956/* Function Name: CompressExposures 957 * Description: Handles all exposure compression 958 * Arguments: event - the xevent that is to be dispatched 959 * widget - the widget that this event occurred in. 960 * Returns: none. 961 * 962 * NOTE: Event must be of type Expose or GraphicsExpose. 963 */ 964 965static void 966CompressExposures(XEvent *event, Widget widget) 967{ 968 CheckExposeInfo info; 969 int count; 970 Display *dpy = XtDisplay(widget); 971 XtPerDisplay pd = _XtGetPerDisplay(dpy); 972 XtEnum comp_expose; 973 XtEnum comp_expose_type; 974 Boolean no_region; 975 976 LOCK_PROCESS; 977 comp_expose = COMP_EXPOSE; 978 UNLOCK_PROCESS; 979 comp_expose_type = comp_expose & 0x0f; 980 no_region = ((comp_expose & XtExposeNoRegion) ? True : False); 981 982 if (no_region) 983 AddExposureToRectangularRegion(event, pd->region); 984 else 985 XtAddExposureToRegion(event, pd->region); 986 987 if (GetCount(event) != 0) 988 return; 989 990 if ((comp_expose_type == XtExposeCompressSeries) || 991 (XEventsQueued(dpy, QueuedAfterReading) == 0)) { 992 SendExposureEvent(event, widget, pd); 993 return; 994 } 995 996 if (comp_expose & XtExposeGraphicsExposeMerged) { 997 info.type1 = Expose; 998 info.type2 = GraphicsExpose; 999 } 1000 else { 1001 info.type1 = event->type; 1002 info.type2 = 0; 1003 } 1004 info.maximal = (comp_expose_type == XtExposeCompressMaximal); 1005 info.non_matching = FALSE; 1006 info.window = XtWindow(widget); 1007 1008 /* 1009 * We have to be very careful here not to hose down the processor 1010 * when blocking until count gets to zero. 1011 * 1012 * First, check to see if there are any events in the queue for this 1013 * widget, and of the correct type. 1014 * 1015 * Once we cannot find any more events, check to see that count is zero. 1016 * If it is not then block until we get another exposure event. 1017 * 1018 * If we find no more events, and count on the last one we saw was zero we 1019 * we can be sure that all events have been processed. 1020 * 1021 * Unfortunately, we wind up having to look at the entire queue 1022 * event if we're not doing Maximal compression, due to the 1023 * semantics of XCheckIfEvent (we can't abort without re-ordering 1024 * the event queue as a side-effect). 1025 */ 1026 1027 count = 0; 1028 while (TRUE) { 1029 XEvent event_return; 1030 1031 if (XCheckIfEvent(dpy, &event_return, 1032 CheckExposureEvent, (char *) &info)) { 1033 1034 count = GetCount(&event_return); 1035 if (no_region) 1036 AddExposureToRectangularRegion(&event_return, pd->region); 1037 else 1038 XtAddExposureToRegion(&event_return, pd->region); 1039 } 1040 else if (count != 0) { 1041 XIfEvent(dpy, &event_return, CheckExposureEvent, (char *) &info); 1042 count = GetCount(&event_return); 1043 if (no_region) 1044 AddExposureToRectangularRegion(&event_return, pd->region); 1045 else 1046 XtAddExposureToRegion(&event_return, pd->region); 1047 } 1048 else /* count == 0 && XCheckIfEvent Failed. */ 1049 break; 1050 } 1051 1052 SendExposureEvent(event, widget, pd); 1053} 1054 1055void 1056XtAddExposureToRegion(XEvent *event, Region region) 1057{ 1058 XRectangle rect; 1059 XExposeEvent *ev = (XExposeEvent *) event; 1060 1061 /* These Expose and GraphicsExpose fields are at identical offsets */ 1062 1063 if (event->type == Expose || event->type == GraphicsExpose) { 1064 rect.x = (Position) ev->x; 1065 rect.y = (Position) ev->y; 1066 rect.width = (Dimension) ev->width; 1067 rect.height = (Dimension) ev->height; 1068 XUnionRectWithRegion(&rect, region, region); 1069 } 1070} 1071 1072#ifndef MAX 1073#define MAX(a,b) (((a) > (b)) ? (a) : (b)) 1074#endif 1075 1076#ifndef MIN 1077#define MIN(a,b) (((a) < (b)) ? (a) : (b)) 1078#endif 1079 1080static void 1081AddExposureToRectangularRegion(XEvent *event, /* when called internally, type is always appropriate */ 1082 Region region) 1083{ 1084 XRectangle rect; 1085 XExposeEvent *ev = (XExposeEvent *) event; 1086 1087 /* These Expose and GraphicsExpose fields are at identical offsets */ 1088 1089 rect.x = (Position) ev->x; 1090 rect.y = (Position) ev->y; 1091 rect.width = (Dimension) ev->width; 1092 rect.height = (Dimension) ev->height; 1093 1094 if (XEmptyRegion(region)) { 1095 XUnionRectWithRegion(&rect, region, region); 1096 } 1097 else { 1098 XRectangle merged, bbox; 1099 1100 XClipBox(region, &bbox); 1101 merged.x = MIN(rect.x, bbox.x); 1102 merged.y = MIN(rect.y, bbox.y); 1103 merged.width = (unsigned short) (MAX(rect.x + rect.width, 1104 bbox.x + bbox.width) - merged.x); 1105 merged.height = (unsigned short) (MAX(rect.y + rect.height, 1106 bbox.y + bbox.height) - merged.y); 1107 XUnionRectWithRegion(&merged, region, region); 1108 } 1109} 1110 1111static Region nullRegion; 1112 1113/* READ-ONLY VARIABLES: nullRegion */ 1114 1115void 1116_XtEventInitialize(void) 1117{ 1118#ifndef __lock_lint 1119 nullRegion = XCreateRegion(); 1120#endif 1121} 1122 1123/* Function Name: SendExposureEvent 1124 * Description: Sets the x, y, width, and height of the event 1125 * to be the clip box of Expose Region. 1126 * Arguments: event - the X Event to mangle; Expose or GraphicsExpose. 1127 * widget - the widget that this event occurred in. 1128 * pd - the per display information for this widget. 1129 * Returns: none. 1130 */ 1131 1132static void 1133SendExposureEvent(XEvent *event, Widget widget, XtPerDisplay pd) 1134{ 1135 XtExposeProc expose; 1136 XRectangle rect; 1137 XtEnum comp_expose; 1138 XExposeEvent *ev = (XExposeEvent *) event; 1139 1140 XClipBox(pd->region, &rect); 1141 ev->x = rect.x; 1142 ev->y = rect.y; 1143 ev->width = rect.width; 1144 ev->height = rect.height; 1145 1146 LOCK_PROCESS; 1147 comp_expose = COMP_EXPOSE; 1148 expose = widget->core.widget_class->core_class.expose; 1149 UNLOCK_PROCESS; 1150 if (comp_expose & XtExposeNoRegion) 1151 (*expose) (widget, event, NULL); 1152 else 1153 (*expose) (widget, event, pd->region); 1154 (void) XIntersectRegion(nullRegion, pd->region, pd->region); 1155} 1156 1157/* Function Name: CheckExposureEvent 1158 * Description: Checks the event queue for an expose event 1159 * Arguments: display - the display connection. 1160 * event - the event to check. 1161 * arg - a pointer to the exposure info structure. 1162 * Returns: TRUE if we found an event of the correct type 1163 * with the right window. 1164 * 1165 * NOTE: The only valid types (info.type1 and info.type2) are Expose 1166 * and GraphicsExpose. 1167 */ 1168 1169static Bool 1170CheckExposureEvent(Display *disp _X_UNUSED, XEvent *event, char *arg) 1171{ 1172 CheckExposeInfo *info = ((CheckExposeInfo *) arg); 1173 1174 if ((info->type1 == event->type) || (info->type2 == event->type)) { 1175 if (!info->maximal && info->non_matching) 1176 return FALSE; 1177 if (event->type == GraphicsExpose) 1178 return (event->xgraphicsexpose.drawable == info->window); 1179 return (event->xexpose.window == info->window); 1180 } 1181 info->non_matching = TRUE; 1182 return (FALSE); 1183} 1184 1185static EventMask const masks[] = { 1186 0, /* Error, should never see */ 1187 0, /* Reply, should never see */ 1188 KeyPressMask, /* KeyPress */ 1189 KeyReleaseMask, /* KeyRelease */ 1190 ButtonPressMask, /* ButtonPress */ 1191 ButtonReleaseMask, /* ButtonRelease */ 1192 PointerMotionMask /* MotionNotify */ 1193 | ButtonMotionMask, 1194 EnterWindowMask, /* EnterNotify */ 1195 LeaveWindowMask, /* LeaveNotify */ 1196 FocusChangeMask, /* FocusIn */ 1197 FocusChangeMask, /* FocusOut */ 1198 KeymapStateMask, /* KeymapNotify */ 1199 ExposureMask, /* Expose */ 1200 NonMaskableMask, /* GraphicsExpose, in GC */ 1201 NonMaskableMask, /* NoExpose, in GC */ 1202 VisibilityChangeMask, /* VisibilityNotify */ 1203 SubstructureNotifyMask, /* CreateNotify */ 1204 StructureNotifyMask /* DestroyNotify */ 1205 | SubstructureNotifyMask, 1206 StructureNotifyMask /* UnmapNotify */ 1207 | SubstructureNotifyMask, 1208 StructureNotifyMask /* MapNotify */ 1209 | SubstructureNotifyMask, 1210 SubstructureRedirectMask, /* MapRequest */ 1211 StructureNotifyMask /* ReparentNotify */ 1212 | SubstructureNotifyMask, 1213 StructureNotifyMask /* ConfigureNotify */ 1214 | SubstructureNotifyMask, 1215 SubstructureRedirectMask, /* ConfigureRequest */ 1216 StructureNotifyMask /* GravityNotify */ 1217 | SubstructureNotifyMask, 1218 ResizeRedirectMask, /* ResizeRequest */ 1219 StructureNotifyMask /* CirculateNotify */ 1220 | SubstructureNotifyMask, 1221 SubstructureRedirectMask, /* CirculateRequest */ 1222 PropertyChangeMask, /* PropertyNotify */ 1223 NonMaskableMask, /* SelectionClear */ 1224 NonMaskableMask, /* SelectionRequest */ 1225 NonMaskableMask, /* SelectionNotify */ 1226 ColormapChangeMask, /* ColormapNotify */ 1227 NonMaskableMask, /* ClientMessage */ 1228 NonMaskableMask /* MappingNotify */ 1229}; 1230 1231EventMask 1232_XtConvertTypeToMask(int eventType) 1233{ 1234 if ((Cardinal) eventType < XtNumber(masks)) 1235 return masks[eventType]; 1236 else 1237 return NoEventMask; 1238} 1239 1240Boolean 1241_XtOnGrabList(register Widget widget, XtGrabRec *grabList) 1242{ 1243 register XtGrabRec *gl; 1244 1245 for (; widget != NULL; widget = (Widget) widget->core.parent) { 1246 for (gl = grabList; gl != NULL; gl = gl->next) { 1247 if (gl->widget == widget) 1248 return TRUE; 1249 if (gl->exclusive) 1250 break; 1251 } 1252 } 1253 return FALSE; 1254} 1255 1256static Widget 1257LookupSpringLoaded(XtGrabList grabList) 1258{ 1259 XtGrabList gl; 1260 1261 for (gl = grabList; gl != NULL; gl = gl->next) { 1262 if (gl->spring_loaded) { 1263 if (XtIsSensitive(gl->widget)) 1264 return gl->widget; 1265 else 1266 return NULL; 1267 } 1268 if (gl->exclusive) 1269 break; 1270 } 1271 return NULL; 1272} 1273 1274static Boolean 1275DispatchEvent(XEvent *event, Widget widget) 1276{ 1277 1278 if (event->type == EnterNotify && 1279 event->xcrossing.mode == NotifyNormal && 1280 widget->core.widget_class->core_class.compress_enterleave) { 1281 if (XPending(event->xcrossing.display)) { 1282 XEvent nextEvent; 1283 XPeekEvent(event->xcrossing.display, &nextEvent); 1284 1285 if (nextEvent.type == LeaveNotify && 1286 event->xcrossing.window == nextEvent.xcrossing.window && 1287 nextEvent.xcrossing.mode == NotifyNormal && 1288 ((event->xcrossing.detail != NotifyInferior && 1289 nextEvent.xcrossing.detail != NotifyInferior) || 1290 (event->xcrossing.detail == NotifyInferior && 1291 nextEvent.xcrossing.detail == NotifyInferior))) { 1292 /* skip the enter/leave pair */ 1293 XNextEvent(event->xcrossing.display, &nextEvent); 1294 1295 return False; 1296 } 1297 } 1298 } 1299 1300 if (event->type == MotionNotify && 1301 widget->core.widget_class->core_class.compress_motion) { 1302 while (XPending(event->xmotion.display)) { 1303 XEvent nextEvent; 1304 XPeekEvent(event->xmotion.display, &nextEvent); 1305 1306 if (nextEvent.type == MotionNotify && 1307 event->xmotion.window == nextEvent.xmotion.window && 1308 event->xmotion.subwindow == nextEvent.xmotion.subwindow) { 1309 /* replace the current event with the next one */ 1310 XNextEvent(event->xmotion.display, event); 1311 } 1312 else 1313 break; 1314 } 1315 } 1316 1317 return XtDispatchEventToWidget(widget, event); 1318} 1319 1320typedef enum _GrabType { pass, ignore, remap } GrabType; 1321 1322static Boolean 1323_XtDefaultDispatcher(XEvent *event) 1324{ 1325 register Widget widget; 1326 GrabType grabType; 1327 XtPerDisplayInput pdi; 1328 XtGrabList grabList; 1329 Boolean was_dispatched = False; 1330 DPY_TO_APPCON(event->xany.display); 1331 1332 /* the default dispatcher discards all extension events */ 1333 if (event->type >= LASTEvent) 1334 return False; 1335 1336 LOCK_APP(app); 1337 1338 switch (event->type) { 1339 case KeyPress: 1340 case KeyRelease: 1341 case ButtonPress: 1342 case ButtonRelease: 1343 grabType = remap; 1344 break; 1345 case MotionNotify: 1346 case EnterNotify: 1347 grabType = ignore; 1348 break; 1349 default: 1350 grabType = pass; 1351 break; 1352 } 1353 1354 widget = XtWindowToWidget(event->xany.display, event->xany.window); 1355 pdi = _XtGetPerDisplayInput(event->xany.display); 1356 1357 grabList = *_XtGetGrabList(pdi); 1358 1359 if (widget == NULL) { 1360 if (grabType == remap 1361 && (widget = LookupSpringLoaded(grabList)) != NULL) { 1362 /* event occurred in a non-widget window, but we've promised also 1363 to dispatch it to the nearest accessible spring_loaded widget */ 1364 was_dispatched = (XFilterEvent(event, XtWindow(widget)) 1365 || XtDispatchEventToWidget(widget, event)); 1366 } 1367 else 1368 was_dispatched = (Boolean) XFilterEvent(event, None); 1369 } 1370 else if (grabType == pass) { 1371 if (event->type == LeaveNotify || 1372 event->type == FocusIn || event->type == FocusOut) { 1373 if (XtIsSensitive(widget)) 1374 was_dispatched = (XFilterEvent(event, XtWindow(widget)) || 1375 XtDispatchEventToWidget(widget, event)); 1376 } 1377 else 1378 was_dispatched = (XFilterEvent(event, XtWindow(widget)) || 1379 XtDispatchEventToWidget(widget, event)); 1380 } 1381 else if (grabType == ignore) { 1382 if ((grabList == NULL || _XtOnGrabList(widget, grabList)) 1383 && XtIsSensitive(widget)) { 1384 was_dispatched = (XFilterEvent(event, XtWindow(widget)) 1385 || DispatchEvent(event, widget)); 1386 } 1387 } 1388 else if (grabType == remap) { 1389 EventMask mask = _XtConvertTypeToMask(event->type); 1390 Widget dspWidget; 1391 Boolean was_filtered = False; 1392 1393 dspWidget = _XtFindRemapWidget(event, widget, mask, pdi); 1394 1395 if ((grabList == NULL || _XtOnGrabList(dspWidget, grabList)) 1396 && XtIsSensitive(dspWidget)) { 1397 if ((was_filtered = 1398 (Boolean) XFilterEvent(event, XtWindow(dspWidget)))) { 1399 /* If this event activated a device grab, release it. */ 1400 _XtUngrabBadGrabs(event, widget, mask, pdi); 1401 was_dispatched = True; 1402 } 1403 else 1404 was_dispatched = XtDispatchEventToWidget(dspWidget, event); 1405 } 1406 else 1407 _XtUngrabBadGrabs(event, widget, mask, pdi); 1408 1409 if (!was_filtered) { 1410 /* Also dispatch to nearest accessible spring_loaded. */ 1411 /* Fetch this afterward to reflect modal list changes */ 1412 grabList = *_XtGetGrabList(pdi); 1413 widget = LookupSpringLoaded(grabList); 1414 if (widget != NULL && widget != dspWidget) { 1415 was_dispatched = (XFilterEvent(event, XtWindow(widget)) 1416 || XtDispatchEventToWidget(widget, event) 1417 || was_dispatched); 1418 } 1419 } 1420 } 1421 UNLOCK_APP(app); 1422 return was_dispatched; 1423} 1424 1425Boolean 1426XtDispatchEvent(XEvent *event) 1427{ 1428 Boolean was_dispatched, safe; 1429 int dispatch_level; 1430 int starting_count; 1431 XtPerDisplay pd; 1432 Time time = 0; 1433 XtEventDispatchProc dispatch = _XtDefaultDispatcher; 1434 XtAppContext app = XtDisplayToApplicationContext(event->xany.display); 1435 1436 LOCK_APP(app); 1437 dispatch_level = ++app->dispatch_level; 1438 starting_count = app->destroy_count; 1439 1440 switch (event->type) { 1441 case KeyPress: 1442 case KeyRelease: 1443 time = event->xkey.time; 1444 break; 1445 case ButtonPress: 1446 case ButtonRelease: 1447 time = event->xbutton.time; 1448 break; 1449 case MotionNotify: 1450 time = event->xmotion.time; 1451 break; 1452 case EnterNotify: 1453 case LeaveNotify: 1454 time = event->xcrossing.time; 1455 break; 1456 case PropertyNotify: 1457 time = event->xproperty.time; 1458 break; 1459 case SelectionClear: 1460 time = event->xselectionclear.time; 1461 break; 1462 1463 case MappingNotify: 1464 _XtRefreshMapping(event, True); 1465 break; 1466 } 1467 pd = _XtGetPerDisplay(event->xany.display); 1468 1469 if (time) 1470 pd->last_timestamp = time; 1471 pd->last_event = *event; 1472 1473 if (pd->dispatcher_list) { 1474 dispatch = pd->dispatcher_list[event->type]; 1475 if (dispatch == NULL) 1476 dispatch = _XtDefaultDispatcher; 1477 } 1478 was_dispatched = (*dispatch) (event); 1479 1480 /* 1481 * To make recursive XtDispatchEvent work, we need to do phase 2 destroys 1482 * only on those widgets destroyed by this particular dispatch. 1483 * 1484 */ 1485 1486 if (app->destroy_count > starting_count) 1487 _XtDoPhase2Destroy(app, dispatch_level); 1488 1489 app->dispatch_level = dispatch_level - 1; 1490 1491 if ((safe = _XtSafeToDestroy(app))) { 1492 if (app->dpy_destroy_count != 0) 1493 _XtCloseDisplays(app); 1494 if (app->free_bindings) 1495 _XtDoFreeBindings(app); 1496 } 1497 UNLOCK_APP(app); 1498 LOCK_PROCESS; 1499 if (_XtAppDestroyCount != 0 && safe) 1500 _XtDestroyAppContexts(); 1501 UNLOCK_PROCESS; 1502 return was_dispatched; 1503} 1504 1505static void 1506GrabDestroyCallback(Widget widget, 1507 XtPointer closure _X_UNUSED, 1508 XtPointer call_data _X_UNUSED) 1509{ 1510 /* Remove widget from grab list if it destroyed */ 1511 XtRemoveGrab(widget); 1512} 1513 1514static XtGrabRec * 1515NewGrabRec(Widget widget, Boolean exclusive, Boolean spring_loaded) 1516{ 1517 register XtGrabList gl; 1518 1519 gl = XtNew(XtGrabRec); 1520 gl->next = NULL; 1521 gl->widget = widget; 1522 XtSetBit(gl->exclusive, exclusive); 1523 XtSetBit(gl->spring_loaded, spring_loaded); 1524 1525 return gl; 1526} 1527 1528void 1529XtAddGrab(Widget widget, _XtBoolean exclusive, _XtBoolean spring_loaded) 1530{ 1531 register XtGrabList gl; 1532 XtGrabList *grabListPtr; 1533 XtAppContext app = XtWidgetToApplicationContext(widget); 1534 1535 LOCK_APP(app); 1536 LOCK_PROCESS; 1537 grabListPtr = _XtGetGrabList(_XtGetPerDisplayInput(XtDisplay(widget))); 1538 1539 if (spring_loaded && !exclusive) { 1540 XtAppWarningMsg(app, 1541 "grabError", "xtAddGrab", XtCXtToolkitError, 1542 "XtAddGrab requires exclusive grab if spring_loaded is TRUE", 1543 NULL, NULL); 1544 exclusive = TRUE; 1545 } 1546 1547 gl = NewGrabRec(widget, (Boolean) exclusive, (Boolean) spring_loaded); 1548 gl->next = *grabListPtr; 1549 *grabListPtr = gl; 1550 1551 XtAddCallback(widget, XtNdestroyCallback, 1552 GrabDestroyCallback, (XtPointer) NULL); 1553 UNLOCK_PROCESS; 1554 UNLOCK_APP(app); 1555} 1556 1557void 1558XtRemoveGrab(Widget widget) 1559{ 1560 register XtGrabList gl; 1561 register Boolean done; 1562 XtGrabList *grabListPtr; 1563 XtAppContext app = XtWidgetToApplicationContext(widget); 1564 1565 LOCK_APP(app); 1566 LOCK_PROCESS; 1567 1568 grabListPtr = _XtGetGrabList(_XtGetPerDisplayInput(XtDisplay(widget))); 1569 1570 for (gl = *grabListPtr; gl != NULL; gl = gl->next) { 1571 if (gl->widget == widget) 1572 break; 1573 } 1574 1575 if (gl == NULL) { 1576 XtAppWarningMsg(app, 1577 "grabError", "xtRemoveGrab", XtCXtToolkitError, 1578 "XtRemoveGrab asked to remove a widget not on the list", 1579 NULL, NULL); 1580 UNLOCK_PROCESS; 1581 UNLOCK_APP(app); 1582 return; 1583 } 1584 1585 do { 1586 gl = *grabListPtr; 1587 done = (gl->widget == widget); 1588 *grabListPtr = gl->next; 1589 XtRemoveCallback(gl->widget, XtNdestroyCallback, 1590 GrabDestroyCallback, (XtPointer) NULL); 1591 XtFree((char *) gl); 1592 } while (!done); 1593 UNLOCK_PROCESS; 1594 UNLOCK_APP(app); 1595 return; 1596} 1597 1598void 1599XtMainLoop(void) 1600{ 1601 XtAppMainLoop(_XtDefaultAppContext()); 1602} 1603 1604void 1605XtAppMainLoop(XtAppContext app) 1606{ 1607 XtInputMask m = XtIMAll; 1608 XtInputMask t; 1609 1610 LOCK_APP(app); 1611 do { 1612 if (m == 0) { 1613 m = XtIMAll; 1614 /* wait for any event, blocking */ 1615 XtAppProcessEvent(app, m); 1616 } 1617 else if (((t = XtAppPending(app)) & m)) { 1618 /* wait for certain events, stepping through choices */ 1619 XtAppProcessEvent(app, t & m); 1620 } 1621 m >>= 1; 1622 } while (app->exit_flag == FALSE); 1623 UNLOCK_APP(app); 1624} 1625 1626void 1627_XtFreeEventTable(XtEventTable *event_table) 1628{ 1629 register XtEventTable event; 1630 1631 event = *event_table; 1632 while (event != NULL) { 1633 register XtEventTable next = event->next; 1634 1635 XtFree((char *) event); 1636 event = next; 1637 } 1638} 1639 1640Time 1641XtLastTimestampProcessed(Display *dpy) 1642{ 1643 Time time; 1644 1645 DPY_TO_APPCON(dpy); 1646 1647 LOCK_APP(app); 1648 LOCK_PROCESS; 1649 time = _XtGetPerDisplay(dpy)->last_timestamp; 1650 UNLOCK_PROCESS; 1651 UNLOCK_APP(app); 1652 return (time); 1653} 1654 1655XEvent * 1656XtLastEventProcessed(Display *dpy) 1657{ 1658 XEvent *le = NULL; 1659 1660 DPY_TO_APPCON(dpy); 1661 1662 LOCK_APP(app); 1663 le = &_XtGetPerDisplay(dpy)->last_event; 1664 if (!le->xany.serial) 1665 le = NULL; 1666 UNLOCK_APP(app); 1667 return le; 1668} 1669 1670void 1671_XtSendFocusEvent(Widget child, int type) 1672{ 1673 child = XtIsWidget(child) ? child : _XtWindowedAncestor(child); 1674 if (XtIsSensitive(child) && !child->core.being_destroyed 1675 && XtIsRealized(child) 1676 && (XtBuildEventMask(child) & FocusChangeMask)) { 1677 XFocusChangeEvent event; 1678 Display *dpy = XtDisplay(child); 1679 1680 event.type = type; 1681 event.serial = LastKnownRequestProcessed(dpy); 1682 event.send_event = True; 1683 event.display = dpy; 1684 1685 event.window = XtWindow(child); 1686 event.mode = NotifyNormal; 1687 event.detail = NotifyAncestor; 1688 if (XFilterEvent((XEvent *) &event, XtWindow(child))) 1689 return; 1690 XtDispatchEventToWidget(child, (XEvent *) &event); 1691 } 1692} 1693 1694static XtEventDispatchProc * 1695NewDispatcherList(void) 1696{ 1697 XtEventDispatchProc *l = (XtEventDispatchProc *) 1698 __XtCalloc((Cardinal) 128, 1699 (Cardinal) 1700 sizeof(XtEventDispatchProc)); 1701 1702 return l; 1703} 1704 1705XtEventDispatchProc 1706XtSetEventDispatcher(Display *dpy, 1707 int event_type, 1708 XtEventDispatchProc proc) 1709{ 1710 XtEventDispatchProc *list; 1711 XtEventDispatchProc old_proc; 1712 register XtPerDisplay pd; 1713 1714 DPY_TO_APPCON(dpy); 1715 1716 LOCK_APP(app); 1717 LOCK_PROCESS; 1718 pd = _XtGetPerDisplay(dpy); 1719 1720 list = pd->dispatcher_list; 1721 if (!list) { 1722 if (proc) 1723 list = pd->dispatcher_list = NewDispatcherList(); 1724 else 1725 return _XtDefaultDispatcher; 1726 } 1727 old_proc = list[event_type]; 1728 list[event_type] = proc; 1729 if (old_proc == NULL) 1730 old_proc = _XtDefaultDispatcher; 1731 UNLOCK_PROCESS; 1732 UNLOCK_APP(app); 1733 return old_proc; 1734} 1735 1736void 1737XtRegisterExtensionSelector(Display *dpy, 1738 int min_event_type, 1739 int max_event_type, 1740 XtExtensionSelectProc proc, 1741 XtPointer client_data) 1742{ 1743 XtPerDisplay pd; 1744 int i; 1745 1746 DPY_TO_APPCON(dpy); 1747 1748 if (dpy == NULL) 1749 XtErrorMsg("nullDisplay", 1750 "xtRegisterExtensionSelector", XtCXtToolkitError, 1751 "XtRegisterExtensionSelector requires a non-NULL display", 1752 NULL, NULL); 1753 1754 LOCK_APP(app); 1755 LOCK_PROCESS; 1756 pd = _XtGetPerDisplay(dpy); 1757 1758 for (i = 0; i < pd->ext_select_count; i++) { 1759 ExtSelectRec *e = &pd->ext_select_list[i]; 1760 1761 if (e->min == min_event_type && e->max == max_event_type) { 1762 e->proc = proc; 1763 e->client_data = client_data; 1764 return; 1765 } 1766 if ((min_event_type >= e->min && min_event_type <= e->max) || 1767 (max_event_type >= e->min && max_event_type <= e->max)) { 1768 XtErrorMsg("rangeError", "xtRegisterExtensionSelector", 1769 XtCXtToolkitError, 1770 "Attempt to register multiple selectors for one extension event type", 1771 NULL, NULL); 1772 UNLOCK_PROCESS; 1773 UNLOCK_APP(app); 1774 return; 1775 } 1776 } 1777 pd->ext_select_count++; 1778 pd->ext_select_list = XtReallocArray(pd->ext_select_list, 1779 (Cardinal) pd->ext_select_count, 1780 (Cardinal) sizeof(ExtSelectRec)); 1781 for (i = pd->ext_select_count - 1; i > 0; i--) { 1782 if (pd->ext_select_list[i - 1].min > min_event_type) { 1783 pd->ext_select_list[i] = pd->ext_select_list[i - 1]; 1784 } 1785 else 1786 break; 1787 } 1788 pd->ext_select_list[i].min = min_event_type; 1789 pd->ext_select_list[i].max = max_event_type; 1790 pd->ext_select_list[i].proc = proc; 1791 pd->ext_select_list[i].client_data = client_data; 1792 UNLOCK_PROCESS; 1793 UNLOCK_APP(app); 1794} 1795 1796void 1797_XtExtensionSelect(Widget widget) 1798{ 1799 int i; 1800 XtPerDisplay pd; 1801 1802 WIDGET_TO_APPCON(widget); 1803 1804 LOCK_APP(app); 1805 LOCK_PROCESS; 1806 1807 pd = _XtGetPerDisplay(XtDisplay(widget)); 1808 1809 for (i = 0; i < pd->ext_select_count; i++) { 1810 CallExtensionSelector(widget, pd->ext_select_list + i, FALSE); 1811 } 1812 UNLOCK_PROCESS; 1813 UNLOCK_APP(app); 1814} 1815