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