Initial revision
[bpt/emacs.git] / lwlib / dispatch.c
1 /* Defines a function to find the Widget that XtDispatchEvent() would use.
2 Copyright (C) 1992 Lucid, Inc.
3
4 This file is part of the Lucid Widget Library.
5
6 The Lucid Widget Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
9 any later version.
10
11 The Lucid Widget Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20 /*
21 * The function XtWidgetToDispatchTo(), given an XEvent, returns the
22 * widget that XtDispatchEvent() would send that event to if called now.
23 * This file copies much code from the X11r4 Xt source, and is thus a
24 * portability problem. It also requires data structures defined in
25 * IntrinsicI.h, which is a non-exported Xt header file, so you can't
26 * compile this file unless you have the Xt sources online.
27 */
28
29 #include <IntrinsicI.h> /* Don't change this: see comments in Imakefile. */
30 #include <X11/Xatom.h>
31 #include "dispatch.h"
32
33 #ifdef THIS_IS_X11R4
34
35 #ifdef THIS_IS_X11R5
36 ERROR!! only one of THIS_IS_X11R4 or THIS_IS_X11R5 must be defined.
37 #endif
38
39 #else /* ! THIS_IS_X11R4 */
40
41 #ifndef THIS_IS_X11R5
42 ERROR!! one of THIS_IS_X11R4 or THIS_IS_X11R5 must be defined.
43 #endif
44
45 #endif /* ! THIS_IS_X11R4 */
46
47
48 /* ## All of the code on this page was copied from the X11R5 lib/Xt/Event.c,
49 ## but is compatible with X11R4; the code in Event.c is different, but
50 ## functionally equivalent for our purposes.
51 */
52
53 #if __STDC__
54 #define Const const
55 #else
56 #define Const /**/
57 #endif
58
59 #define NonMaskableMask ((EventMask)0x80000000L)
60
61 #define COMP_EXPOSE (widget->core.widget_class->core_class.compress_exposure)
62 #define COMP_EXPOSE_TYPE (COMP_EXPOSE & 0x0f)
63 #define GRAPHICS_EXPOSE ((XtExposeGraphicsExpose & COMP_EXPOSE) || \
64 (XtExposeGraphicsExposeMerged & COMP_EXPOSE))
65 #define NO_EXPOSE (XtExposeNoExpose & COMP_EXPOSE)
66
67
68 /* -- lots of stuff we don't need to copy, omitted -- */
69
70
71 static EventMask Const masks[] = {
72 0, /* Error, should never see */
73 0, /* Reply, should never see */
74 KeyPressMask, /* KeyPress */
75 KeyReleaseMask, /* KeyRelease */
76 ButtonPressMask, /* ButtonPress */
77 ButtonReleaseMask, /* ButtonRelease */
78 PointerMotionMask /* MotionNotify */
79 | ButtonMotionMask,
80 EnterWindowMask, /* EnterNotify */
81 LeaveWindowMask, /* LeaveNotify */
82 FocusChangeMask, /* FocusIn */
83 FocusChangeMask, /* FocusOut */
84 KeymapStateMask, /* KeymapNotify */
85 ExposureMask, /* Expose */
86 NonMaskableMask, /* GraphicsExpose, in GC */
87 NonMaskableMask, /* NoExpose, in GC */
88 VisibilityChangeMask, /* VisibilityNotify */
89 SubstructureNotifyMask, /* CreateNotify */
90 StructureNotifyMask /* DestroyNotify */
91 | SubstructureNotifyMask,
92 StructureNotifyMask /* UnmapNotify */
93 | SubstructureNotifyMask,
94 StructureNotifyMask /* MapNotify */
95 | SubstructureNotifyMask,
96 SubstructureRedirectMask, /* MapRequest */
97 StructureNotifyMask /* ReparentNotify */
98 | SubstructureNotifyMask,
99 StructureNotifyMask /* ConfigureNotify */
100 | SubstructureNotifyMask,
101 SubstructureRedirectMask, /* ConfigureRequest */
102 StructureNotifyMask /* GravityNotify */
103 | SubstructureNotifyMask,
104 ResizeRedirectMask, /* ResizeRequest */
105 StructureNotifyMask /* CirculateNotify */
106 | SubstructureNotifyMask,
107 SubstructureRedirectMask, /* CirculateRequest */
108 PropertyChangeMask, /* PropertyNotify */
109 NonMaskableMask, /* SelectionClear */
110 NonMaskableMask, /* SelectionRequest */
111 NonMaskableMask, /* SelectionNotify */
112 ColormapChangeMask, /* ColormapNotify */
113 NonMaskableMask, /* ClientMessage */
114 NonMaskableMask /* MappingNotify */
115 };
116
117 #ifdef THIS_IS_X11R4
118
119 static /* in R5, this is not static, so we don't need to define it at all */
120 EventMask _XtConvertTypeToMask (eventType)
121 int eventType;
122 {
123 eventType &= 0x7f; /* Events sent with XSendEvent have high bit set. */
124 if (eventType < XtNumber(masks))
125 return masks[eventType];
126 else
127 return 0;
128 }
129
130 #endif /* R4 */
131
132 /* -- _XtOnGrabList() omitted -- */
133
134
135 static Widget LookupSpringLoaded(grabList)
136 XtGrabList grabList;
137 {
138 XtGrabList gl;
139
140 for (gl = grabList; gl != NULL; gl = gl->next) {
141 if (gl->spring_loaded)
142 if (XtIsSensitive(gl->widget))
143 return gl->widget;
144 else
145 return NULL;
146 if (gl->exclusive) break;
147 }
148 return NULL;
149 }
150
151
152 \f
153 /* This function is new. */
154
155 static Boolean WouldDispatchEvent(event, widget, mask, pd)
156 register XEvent *event;
157 Widget widget;
158 EventMask mask;
159 XtPerDisplay pd;
160 {
161 XtEventRec *p;
162 Boolean would_dispatched = False;
163
164 if ((mask == ExposureMask) ||
165 ((event->type == NoExpose) && NO_EXPOSE) ||
166 ((event->type == GraphicsExpose) && GRAPHICS_EXPOSE) )
167 if (widget->core.widget_class->core_class.expose != NULL )
168 return True;
169
170
171 if ((mask == VisibilityChangeMask) &&
172 XtClass(widget)->core_class.visible_interest)
173 return True;
174
175 for (p=widget->core.event_table; p != NULL; p = p->next)
176 if ((mask & p->mask) != 0
177 #ifdef THIS_IS_X11R4
178 || (mask == 0 && p->non_filter)
179 #endif
180 )
181 return True;
182
183 return False;
184 }
185
186
187 /* #### This function is mostly copied from DecideToDispatch().
188 */
189
190 typedef enum _GrabType {pass, ignore, remap} GrabType;
191
192 Widget
193 XtWidgetToDispatchTo (XEvent* event)
194 {
195 register Widget widget;
196 EventMask mask;
197 GrabType grabType;
198 Widget dspWidget;
199 Time time = 0;
200 XtPerDisplay pd;
201 XtPerDisplayInput pdi;
202 XtGrabList grabList;
203
204 widget = XtWindowToWidget (event->xany.display, event->xany.window);
205 pd = _XtGetPerDisplay(event->xany.display);
206 pdi = _XtGetPerDisplayInput(event->xany.display);
207 grabList = *_XtGetGrabList(pdi);
208
209 mask = _XtConvertTypeToMask(event->xany.type);
210 grabType = pass;
211 switch (event->xany.type & 0x7f) {
212 case KeyPress:
213 case KeyRelease: grabType = remap; break;
214 case ButtonPress:
215 case ButtonRelease: grabType = remap; break;
216 case MotionNotify: grabType = ignore;
217 #define XKnownButtons (Button1MotionMask|Button2MotionMask|Button3MotionMask|\
218 Button4MotionMask|Button5MotionMask)
219 mask |= (event->xmotion.state & XKnownButtons);
220 #undef XKnownButtons
221 break;
222 case EnterNotify: grabType = ignore; break;
223 }
224
225 if (widget == NULL) {
226 if (grabType != remap) return False;
227 /* event occurred in a non-widget window, but we've promised also
228 to dispatch it to the nearest accessible spring_loaded widget */
229 else if ((widget = LookupSpringLoaded(grabList)) != NULL)
230 return widget;
231 return False;
232 }
233
234 switch(grabType) {
235 case pass:
236 return widget;
237
238 case ignore:
239 if ((grabList == NULL || _XtOnGrabList(widget,grabList))
240 && XtIsSensitive(widget)) {
241 return widget;
242 }
243 return NULL;
244
245 case remap:
246
247 {
248 Widget was_dispatched_to= NULL;
249 extern Widget _XtFindRemapWidget();
250 extern void _XtUngrabBadGrabs();
251
252 dspWidget = _XtFindRemapWidget(event, widget, mask, pdi);
253
254 if ((grabList == NULL ||
255 _XtOnGrabList(dspWidget, grabList)) &&
256 XtIsSensitive(dspWidget)) {
257 if (WouldDispatchEvent (event, dspWidget, mask, pd))
258 was_dispatched_to = dspWidget;
259 }
260
261 /* Also dispatch to nearest accessible spring_loaded. */
262 /* Fetch this afterward to reflect modal list changes */
263 grabList = *_XtGetGrabList(pdi);
264 widget = LookupSpringLoaded(grabList);
265 if (widget != NULL && widget != dspWidget) {
266 if (!was_dispatched_to)
267 was_dispatched_to = widget;
268 }
269
270 return was_dispatched_to;
271 }
272 }
273 /* should never reach here */
274 return NULL;
275 }