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