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