]> cvs.zerfleddert.de Git - micropolis/blob - src/tk/tkshare.c
Fixes for compilation with gcc 15
[micropolis] / src / tk / tkshare.c
1 /*
2 * tkShare.c --
3 *
4 * This module implements a simple mechanism for sharing
5 * mouse- and button-related events among collections of
6 * windows. It is used primarily for menus. For example,
7 * if one menu is posted and mouse moves over the menu button
8 * for a different menu, then the menubutton needs to see the
9 * event so that it can post itself and unpost the first menu.
10 *
11 * Copyright 1990-1992 Regents of the University of California
12 * Permission to use, copy, modify, and distribute this
13 * software and its documentation for any purpose and without
14 * fee is hereby granted, provided that the above copyright
15 * notice appear in all copies. The University of California
16 * makes no representations about the suitability of this
17 * software for any purpose. It is provided "as is" without
18 * express or implied warranty.
19 */
20
21 #ifndef lint
22 static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkShare.c,v 1.10 92/05/31 16:20:12 ouster Exp $ SPRITE (Berkeley)";
23 #endif /* not lint */
24
25 #include "tkconfig.h"
26 #include "tk.h"
27
28 /*
29 * the global variable below is used to tell TkPointerEvent
30 * not to do any processing on an event that we're forwarding from one
31 * window to another. This is really ugly. Eventually this file and
32 * tkGrab.c need to get merged together to produce something cleaner.
33 */
34
35 XEvent *tkShareEventPtr = NULL;
36
37 /*
38 * Sharing is implemented in terms of groups of windows, where events
39 * are shared among all the windows in a group. One of the following
40 * structures exists for each group.
41 */
42
43 typedef struct Group {
44 Tk_Uid groupId; /* Identifies group uniquely among all
45 * share groups. */
46 Tk_Window *windows; /* Pointer to array of windows in
47 * this group. Malloc'ed. */
48 int numWindows; /* Number of windows currently in
49 * this group. */
50 Tk_Window lastWindow; /* Last window found that contained
51 * an event. Needed in order to
52 * notify window when mouse moves out
53 * of it. NULL means nobody to
54 * notify. */
55 XEvent *activeEvent; /* If non-NULL, means that a recursive
56 * call to Tk_HandleEvent is in
57 * progress for this share group, and
58 * identifies event. NULL means no
59 * recursive call in progress. Used
60 * to avoid infinite recursion. */
61 struct Group *nextPtr; /* Next in list of all share groups. */
62 } Group;
63
64 static Group *groupList = NULL; /* First in list of all share groups
65 * currently defined. */
66
67 /*
68 * Forward declarations for procedures defined later in this file:
69 */
70
71 static void DeleteGroup _ANSI_ARGS_((Group *groupPtr));
72 static void ShareEventProc _ANSI_ARGS_((ClientData clientData,
73 XEvent *eventPtr));
74 \f
75 /*
76 *----------------------------------------------------------------------
77 *
78 * Tk_ShareEvents --
79 *
80 * Add tkwin to a group of windows sharing events.
81 *
82 * Results:
83 * None.
84 *
85 * Side effects:
86 * In the future, if a button- or mouse-related event occurs for
87 * any window in the same group as tkwin, but the mouse is actually
88 * in tkwin (the event went to a different window because of a
89 * grab) then a synthetic event will be generated with tkwin as
90 * window and adjusted coordinates.
91 *
92 *----------------------------------------------------------------------
93 */
94
95 void
96 Tk_ShareEvents (
97 Tk_Window tkwin, /* Token for window. */
98 Tk_Uid groupId /* Identifier for group among which
99 * events are to be shared. */
100 )
101 {
102 register Group *groupPtr;
103
104 /*
105 * See if this group exists. If so, add the window to the group.
106 */
107
108 for (groupPtr = groupList; groupPtr != NULL;
109 groupPtr = groupPtr->nextPtr) {
110 Tk_Window *new;
111
112 if (groupPtr->groupId != groupId) {
113 continue;
114 }
115 new = (Tk_Window *) ckalloc((unsigned)
116 (groupPtr->numWindows+1) * sizeof(Tk_Window *));
117 memcpy((VOID *) (new+1), (VOID *) groupPtr->windows,
118 (groupPtr->numWindows * sizeof(Tk_Window *)));
119 ckfree((char *) groupPtr->windows);
120 groupPtr->windows = new;
121 groupPtr->windows[0] = tkwin;
122 groupPtr->numWindows++;
123 break;
124 }
125
126 if (groupPtr == NULL) {
127 /*
128 * Group doesn't exist. Make a new one.
129 */
130
131 groupPtr = (Group *) ckalloc(sizeof(Group));
132 groupPtr->groupId = groupId;
133 groupPtr->windows = (Tk_Window *) ckalloc(sizeof (Tk_Window *));
134 groupPtr->windows[0] = tkwin;
135 groupPtr->numWindows = 1;
136 groupPtr->lastWindow = NULL;
137 groupPtr->activeEvent = NULL;
138 groupPtr->nextPtr = groupList;
139 groupList = groupPtr;
140 }
141
142 /*
143 * Create an event handler so we find out about relevant events
144 * that are directed to tkwin.
145 */
146
147 Tk_CreateEventHandler(tkwin,
148 ButtonPressMask|ButtonReleaseMask|PointerMotionMask,
149 ShareEventProc, (ClientData) groupPtr);
150 }
151 \f
152 /*
153 *----------------------------------------------------------------------
154 *
155 * Tk_UnshareEvents --
156 *
157 * Remove tkwin from a group of windows sharing events.
158 *
159 * Results:
160 * None.
161 *
162 * Side effects:
163 * Tkwin will no longer participate in event-sharing for the
164 * given group, either as source of events or as destination.
165 *
166 *----------------------------------------------------------------------
167 */
168
169 void
170 Tk_UnshareEvents (
171 Tk_Window tkwin, /* Token for window. */
172 Tk_Uid groupId /* Identifier for group. */
173 )
174 {
175 register Group *groupPtr;
176 int i;
177
178 for (groupPtr = groupList; groupPtr != NULL;
179 groupPtr = groupPtr->nextPtr) {
180 if (groupPtr->groupId != groupId) {
181 continue;
182 }
183 if (groupPtr->lastWindow == tkwin) {
184 groupPtr->lastWindow = NULL;
185 }
186 for (i = 0; i < groupPtr->numWindows; i++) {
187 if (groupPtr->windows[i] != tkwin) {
188 continue;
189 }
190 if ((i+1) < groupPtr->numWindows) {
191 memcpy((VOID *) (groupPtr->windows + i),
192 (VOID *) (groupPtr->windows + i + 1),
193 (groupPtr->numWindows - (i+1))*sizeof(Tk_Window *));
194 }
195 groupPtr->numWindows--;
196 Tk_DeleteEventHandler(tkwin,
197 ButtonPressMask|ButtonReleaseMask|PointerMotionMask,
198 ShareEventProc, (ClientData) groupPtr);
199 if (groupPtr->numWindows == 0) {
200 DeleteGroup(groupPtr);
201 }
202 return;
203 }
204 }
205 }
206 \f
207 /*
208 *----------------------------------------------------------------------
209 *
210 * DeleteGroup --
211 *
212 * This procedure is called when a group has no more members.
213 * It deletes the group from the list of existing groups.
214 *
215 * Results:
216 * None.
217 *
218 * Side effects:
219 * Memory gets freed.
220 *
221 *----------------------------------------------------------------------
222 */
223
224 static void
225 DeleteGroup (
226 Group *groupPtr /* Group to delete. */
227 )
228 {
229 if (groupList == groupPtr) {
230 groupList = groupPtr->nextPtr;
231 } else {
232 register Group *prevPtr;
233
234 for (prevPtr = groupList; ; prevPtr = prevPtr->nextPtr) {
235 if (prevPtr == NULL) {
236 panic("DeleteGroup couldn't find group on shareList");
237 }
238 if (prevPtr->nextPtr == groupPtr) {
239 prevPtr->nextPtr = groupPtr->nextPtr;
240 break;
241 }
242 }
243 }
244 ckfree((char *) groupPtr->windows);
245 ckfree((char *) groupPtr);
246 }
247 \f
248 /*
249 *----------------------------------------------------------------------
250 *
251 * ShareEventProc --
252 *
253 * This procedure is invoked by the Tk dispatcher when an event
254 * occurs for which we need to implement sharing.
255 *
256 * Results:
257 * None.
258 *
259 * Side effects:
260 * If the mouse is actually in a window other than the one for
261 * which the event occurred, generate a new event translated to
262 * that window.
263 *
264 *----------------------------------------------------------------------
265 */
266
267 static void
268 ShareEventProc(
269 ClientData clientData, /* Information about share group. */
270 register XEvent *eventPtr /* Event that just occurred. */
271 )
272 {
273 register Group *groupPtr = (Group *) clientData;
274 register Tk_Window tkwin;
275 Window window;
276 XEvent newEvent, *savedActive, *savedShareEventPtr;
277 int i, x, y;
278 Tk_Uid savedId;
279 register Group *grpPtr;
280
281 /*
282 * If this event was a synthetic one that we generated, then
283 * don't bother to process it again.
284 */
285
286 if (groupPtr->activeEvent == eventPtr) {
287 return;
288 }
289 savedActive = groupPtr->activeEvent;
290 groupPtr->activeEvent = &newEvent;
291 savedId = groupPtr->groupId;
292
293 savedShareEventPtr = tkShareEventPtr;
294 tkShareEventPtr = &newEvent;
295
296 /*
297 * Scan through all of the windows for this group to find the
298 * first one (if any) that contains the event.
299 */
300
301 tkwin = NULL; /* Not needed, but stops compiler warning. */
302 for (i = 0; i < groupPtr->numWindows; i++) {
303 Tk_Window tkwin2;
304
305 tkwin = groupPtr->windows[i];
306 Tk_GetRootCoords(tkwin, &x, &y);
307 x = eventPtr->xmotion.x_root - x - Tk_Changes(tkwin)->border_width;
308 y = eventPtr->xmotion.y_root - y - Tk_Changes(tkwin)->border_width;
309 if ((x < 0) || (y < 0) || (x >= Tk_Width(tkwin))
310 || (y >= Tk_Height(tkwin))) {
311 continue;
312 }
313 for (tkwin2 = tkwin; ; tkwin2 = Tk_Parent(tkwin2)) {
314 if (tkwin2 == NULL) {
315 goto foundWindow;
316 }
317 if (!Tk_IsMapped(tkwin2)) {
318 break;
319 }
320 if (((Tk_FakeWin *) (tkwin2))->flags & TK_TOP_LEVEL) {
321 goto foundWindow;
322 }
323 }
324 }
325
326 foundWindow:
327 window = None; /* Not really needed but stops compiler warning. */
328 if (i >= groupPtr->numWindows) {
329 tkwin = NULL;
330 } else {
331 window = Tk_WindowId(tkwin);
332 }
333
334 /*
335 * SPECIAL NOTE: it is possible that any or all of the information
336 * in groupPtr could be modified as part of the processing of the
337 * events that we generate and hand to Tk_HandleEvent below. For this
338 * to work smoothly, it is imperative that we extract any information
339 * we need from groupPtr (and from tkwin's, since they could be
340 * deleted) before the first call to Tk_HandleEvent below. The code
341 * below may potentially pass an X window identifier to Tk_HandleEvent
342 * after the window has been deleted, but as long as identifiers
343 * aren't recycled Tk_HandleEvent will simply discard the event if
344 * this occurs.
345 */
346
347 /*
348 * If the pointer is in a different window now than the last time
349 * we were invoked, send a LeaveNotify event to the old window and
350 * an EnterNotify event to the new window.
351 */
352
353 newEvent = *eventPtr;
354 newEvent.xany.send_event = True;
355 if (tkwin != groupPtr->lastWindow) {
356 newEvent = *eventPtr;
357 newEvent.xany.send_event = True;
358 newEvent.xcrossing.mode = TK_NOTIFY_SHARE;
359 newEvent.xcrossing.detail = NotifyAncestor;
360 newEvent.xcrossing.same_screen = True;
361 newEvent.xcrossing.state = eventPtr->xmotion.state;
362 if (groupPtr->lastWindow != NULL) {
363 newEvent.xcrossing.type = LeaveNotify;
364 newEvent.xcrossing.window = Tk_WindowId(groupPtr->lastWindow);
365 Tk_GetRootCoords(groupPtr->lastWindow, &newEvent.xcrossing.x,
366 &newEvent.xcrossing.y);
367 newEvent.xcrossing.x = eventPtr->xmotion.x_root
368 - newEvent.xcrossing.x
369 - Tk_Changes(groupPtr->lastWindow)->border_width;
370 newEvent.xcrossing.y = eventPtr->xmotion.y_root
371 - newEvent.xcrossing.y
372 - Tk_Changes(groupPtr->lastWindow)->border_width;
373 Tk_HandleEvent(&newEvent);
374 }
375 if (tkwin != NULL) {
376 newEvent.xcrossing.type = EnterNotify;
377 newEvent.xcrossing.window = window;
378 newEvent.xcrossing.x = x;
379 newEvent.xcrossing.y = y;
380 Tk_HandleEvent(&newEvent);
381 }
382 groupPtr->lastWindow = tkwin;
383 }
384
385 /*
386 * If the pointer is in the window to which the event was sent,
387 * then we needn't do any forwarding at all. Ditto if the pointer
388 * isn't in any window at all.
389 */
390
391 if ((tkwin != NULL) && (Tk_WindowId(tkwin) != eventPtr->xmotion.window)) {
392 newEvent = *eventPtr;
393 newEvent.xmotion.send_event = True;
394 newEvent.xmotion.window = window;
395 newEvent.xmotion.x = x;
396 newEvent.xmotion.y = y;
397 Tk_HandleEvent(&newEvent);
398 }
399
400 /*
401 * Only restore the activeEvent if the group still exists.
402 * (It could be deleted as a side effect of processing the event.)
403 */
404
405 for (grpPtr = groupList; grpPtr != NULL; grpPtr = grpPtr->nextPtr) {
406 if (grpPtr->groupId == savedId) {
407 groupPtr->activeEvent = savedActive;
408 break;
409 }
410 }
411
412 tkShareEventPtr = savedShareEventPtr;
413 }
Impressum, Datenschutz