close_delete_destroy upgrade
[fvwm.git] / fvwm / events.c
blobda114e17bc2fa4a02caa50f3602531528e976cc5
1 /* This program is free software; you can redistribute it and/or modify
2 * it under the terms of the GNU General Public License as published by
3 * the Free Software Foundation; either version 2 of the License, or
4 * (at your option) any later version.
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 /****************************************************************************
17 * This module is based on Twm, but has been siginificantly modified
18 * by Rob Nation
19 ****************************************************************************/
20 /*****************************************************************************/
21 /** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
22 /** Salt Lake City, Utah **/
23 /** Portions Copyright 1989 by the Massachusetts Institute of Technology **/
24 /** Cambridge, Massachusetts **/
25 /** **/
26 /** All Rights Reserved **/
27 /** **/
28 /** Permission to use, copy, modify, and distribute this software and **/
29 /** its documentation for any purpose and without fee is hereby **/
30 /** granted, provided that the above copyright notice appear in all **/
31 /** copies and that both that copyright notice and this permis- **/
32 /** sion notice appear in supporting documentation, and that the **/
33 /** names of Evans & Sutherland and M.I.T. not be used in advertising **/
34 /** in publicity pertaining to distribution of the software without **/
35 /** specific, written prior permission. **/
36 /** **/
37 /** EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD **/
38 /** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
39 /** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND OR **/
40 /** M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
41 /** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
42 /** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
43 /** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
44 /** OR PERFORMANCE OF THIS SOFTWARE. **/
45 /*****************************************************************************/
48 /***********************************************************************
50 * fvwm event handling
52 ***********************************************************************/
54 #include "config.h"
56 #if HAVE_SYS_BSDTYPES_H
57 #include <sys/bsdtypes.h>
58 #endif
60 #include <stdio.h>
61 #include <errno.h>
62 #include <string.h>
63 #include <sys/types.h>
64 #include <sys/time.h>
65 #include <unistd.h>
67 #include "libs/fvwmlib.h"
68 #include "fvwm.h"
69 #include "externs.h"
70 #include "cursor.h"
71 #include "functions.h"
72 #include "bindings.h"
73 #include "misc.h"
74 #include "screen.h"
75 #include "defaults.h"
76 #include "events.h"
77 #include "libs/Colorset.h"
78 #include "fvwmsignal.h"
79 #ifdef SHAPE
80 #include <X11/extensions/shape.h>
81 #endif /* SHAPE */
82 #include "module_interface.h"
83 #include "session.h"
84 #include "borders.h"
85 #include "colormaps.h"
86 #include "add_window.h"
87 #include "icccm2.h"
88 #include "icons.h"
89 #include "gnome.h"
90 #include "update.h"
91 #include "style.h"
92 #include "stack.h"
93 #include "geometry.h"
94 #include "focus.h"
95 #include "move_resize.h"
96 #include "virtual.h"
97 #ifdef HAVE_STROKE
98 #include "stroke.h"
99 #endif /* HAVE_STROKE */
101 #ifndef XUrgencyHint
102 #define XUrgencyHint (1L << 8)
103 #endif
105 extern void StartupStuff(void);
107 int Context = C_NO_CONTEXT; /* current button press context */
108 static int Button = 0;
109 FvwmWindow *ButtonWindow = NULL; /* button press window structure */
110 XEvent Event; /* the current event */
111 FvwmWindow *Tmp_win = NULL; /* the current fvwm window */
113 int last_event_type=0;
114 static Window last_event_window=0;
115 Time lastTimestamp = CurrentTime; /* until Xlib does this for us */
118 STROKE_CODE(static int send_motion;)
119 STROKE_CODE(static char sequence[MAX_SEQUENCE+1];)
121 #ifdef SHAPE
122 extern int ShapeEventBase;
123 void HandleShapeNotify(void);
124 #endif /* SHAPE */
126 Window PressedW;
129 ** LASTEvent is the number of X events defined - it should be defined
130 ** in X.h (to be like 35), but since extension (eg SHAPE) events are
131 ** numbered beyond LASTEvent, we need to use a bigger number than the
132 ** default, so let's undefine the default and use 256 instead.
134 #undef LASTEvent
135 #ifndef LASTEvent
136 #define LASTEvent 256
137 #endif /* !LASTEvent */
138 typedef void (*PFEH)(void);
139 PFEH EventHandlerJumpTable[LASTEvent];
140 static int flush_property_notify(Atom atom, Window w);
142 /***********************************************************************
144 * Procedure:
145 * HandleFocusIn - handles focus in events
147 ************************************************************************/
148 void HandleFocusIn(void)
150 XEvent d;
151 Window w = None;
152 Window focus_w = None;
153 Window focus_fw = None;
154 Pixel fc = 0;
155 Pixel bc = 0;
156 FvwmWindow *ffw_old = Scr.Focus;
157 static Window last_focus_w = None;
158 static Window last_focus_fw = None;
159 static Bool is_never_focused = True;
161 DBUG("HandleFocusIn","Routine Entered");
163 /* This is a hack to make the PointerKey command work */
164 if (Event.xfocus.detail != NotifyPointer)
165 /**/
166 w= Event.xany.window;
167 while(XCheckTypedEvent(dpy,FocusIn,&d))
169 /* dito */
170 if (d.xfocus.detail != NotifyPointer)
171 /**/
172 w = d.xany.window;
174 /* dito */
175 if (w == None)
177 return;
179 /**/
180 if (XFindContext (dpy, w, FvwmContext, (caddr_t *) &Tmp_win) == XCNOENT)
182 Tmp_win = NULL;
185 if (!Tmp_win)
187 if (w != Scr.NoFocusWin)
189 Scr.UnknownWinFocused = w;
190 focus_w = w;
192 else
194 DrawDecorations(Scr.Hilite, DRAW_ALL, False, True, None);
195 if (Scr.ColormapFocus == COLORMAP_FOLLOWS_FOCUS)
197 if((Scr.Hilite)&&(!IS_ICONIFIED(Scr.Hilite)))
199 InstallWindowColormaps(Scr.Hilite);
201 else
203 InstallWindowColormaps(NULL);
208 /* Not very useful if no window that fvwm and its modules know about has the
209 * focus. */
210 fc = GetColor("White");
211 bc = GetColor("Black");
213 else if (Tmp_win != Scr.Hilite
214 /* domivogt (16-May-2000): This check is necessary to force sending
215 * a M_FOCUS_CHANGE packet after an unmanaged window was focused.
216 * Otherwise fvwm would believe that Scr.Hilite was still focused and
217 * not send any info to the modules. */
218 || last_focus_fw == None)
220 DrawDecorations(Tmp_win, DRAW_ALL, True, True, None);
221 focus_w = Tmp_win->w;
222 focus_fw = Tmp_win->frame;
223 fc = Tmp_win->hicolors.fore;
224 bc = Tmp_win->hicolors.back;
225 Scr.Focus = Tmp_win;
226 if (Scr.ColormapFocus == COLORMAP_FOLLOWS_FOCUS)
228 if((Scr.Hilite)&&(!IS_ICONIFIED(Scr.Hilite)))
230 InstallWindowColormaps(Scr.Hilite);
232 else
234 InstallWindowColormaps(NULL);
238 else
240 return;
242 if (is_never_focused || last_focus_fw == None ||
243 focus_w != last_focus_w || focus_fw != last_focus_fw)
245 BroadcastPacket(M_FOCUS_CHANGE, 5, focus_w, focus_fw,
246 (unsigned long)IsLastFocusSetByMouse(), fc, bc);
247 last_focus_w = focus_w;
248 last_focus_fw = focus_fw;
249 is_never_focused = False;
251 if (Scr.Focus != ffw_old)
253 focus_grab_buttons(Scr.Focus, True);
254 focus_grab_buttons(ffw_old, False);
258 /***********************************************************************
260 * Procedure:
261 * HandleKeyPress - key press event handler
263 ************************************************************************/
264 void HandleKeyPress(void)
266 char *action;
268 DBUG("HandleKeyPress","Routine Entered");
270 Context = GetContext(Tmp_win, &Event, &PressedW);
271 PressedW = None;
273 /* Here's a real hack - some systems have two keys with the
274 * same keysym and different keycodes. This converts all
275 * the cases to one keycode. */
276 Event.xkey.keycode =
277 XKeysymToKeycode(dpy,XKeycodeToKeysym(dpy,Event.xkey.keycode,0));
279 /* Check if there is something bound to the key */
280 action = CheckBinding(Scr.AllBindings, STROKE_ARG(0) Event.xkey.keycode,
281 Event.xkey.state, GetUnusedModifiers(), Context,
282 KEY_BINDING);
283 if (action != NULL)
285 ButtonWindow = Tmp_win;
286 old_execute_function(action, Tmp_win, &Event, Context, -1, 0, NULL);
287 ButtonWindow = NULL;
288 return;
291 /* if we get here, no function key was bound to the key. Send it
292 * to the client if it was in a window we know about.
294 if (Scr.Focus && Event.xkey.window != Scr.Focus->w)
296 Event.xkey.window = Scr.Focus->w;
297 XSendEvent(dpy, Scr.Focus->w, False, KeyPressMask, &Event);
299 else if (Tmp_win && Event.xkey.window != Tmp_win->w)
301 Event.xkey.window = Tmp_win->w;
302 XSendEvent(dpy, Tmp_win->w, False, KeyPressMask, &Event);
307 /***********************************************************************
309 * Procedure:
310 * HandlePropertyNotify - property notify event handler
312 ***********************************************************************/
313 void HandlePropertyNotify(void)
315 XTextProperty text_prop;
316 Bool OnThisPage = False;
317 Bool was_size_inc_set;
318 int old_wmhints_flags;
319 int old_width_inc;
320 int old_height_inc;
321 int old_base_width;
322 int old_base_height;
324 #ifdef I18N_MB
325 Atom actual = None;
326 int actual_format;
327 unsigned long nitems, bytesafter;
328 char *prop = NULL;
329 char **list;
330 int num;
331 #endif
333 DBUG("HandlePropertyNotify","Routine Entered");
335 if ((!Tmp_win)||
336 (XGetGeometry(dpy, Tmp_win->w, &JunkRoot, &JunkX, &JunkY,
337 &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth) == 0))
338 return;
341 * Make sure at least part of window is on this page
342 * before giving it focus...
344 OnThisPage = IsRectangleOnThisPage(&(Tmp_win->frame_g), Tmp_win->Desk);
346 switch (Event.xproperty.atom)
348 case XA_WM_TRANSIENT_FOR:
349 flush_property_notify(XA_WM_TRANSIENT_FOR, Tmp_win->w);
350 if(XGetTransientForHint(dpy, Tmp_win->w, &Tmp_win->transientfor))
352 SET_TRANSIENT(Tmp_win, 1);
353 RaiseWindow(Tmp_win);
355 else
357 SET_TRANSIENT(Tmp_win, 0);
359 break;
361 case XA_WM_NAME:
362 flush_property_notify(XA_WM_NAME, Tmp_win->w);
363 #ifdef I18N_MB
364 if (XGetWindowProperty (dpy, Tmp_win->w, Event.xproperty.atom, 0L,
365 MAX_WINDOW_NAME_LEN, False, AnyPropertyType,
366 &actual, &actual_format, &nitems, &bytesafter,
367 (unsigned char **) &prop) != Success ||
368 actual == None)
369 return;
370 if (prop) {
371 if (actual == XA_STRING) {
372 /* STRING encoding, use this as it is */
373 free_window_names (Tmp_win, True, False);
374 Tmp_win->name = prop;
375 Tmp_win->name_list = NULL;
376 } else {
377 /* not STRING encoding, try to convert */
378 text_prop.value = prop;
379 text_prop.encoding = actual;
380 text_prop.format = actual_format;
381 text_prop.nitems = nitems;
382 if (
383 XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >= Success
384 && num > 0 && *list) {
385 /* XXX: does not consider the conversion is REALLY succeeded */
386 XFree(prop); /* return of XGetWindowProperty() */
387 free_window_names (Tmp_win, True, False);
388 Tmp_win->name = *list;
389 Tmp_win->name_list = list;
390 } else {
391 if (list) XFreeStringList(list);
392 XFree(prop); /* return of XGetWindowProperty() */
393 if (!XGetWMName(dpy, Tmp_win->w, &text_prop))
394 return; /* why cannot read... */
395 free_window_names (Tmp_win, True, False);
396 Tmp_win->name = (char *)text_prop.value;
397 Tmp_win->name_list = NULL;
400 } else {
401 /* XXX: fallback to original behavior, is it needed ? */
402 if (!XGetWMName(dpy, Tmp_win->w, &text_prop))
403 return;
404 free_window_names (Tmp_win, True, False);
405 Tmp_win->name = (char *)text_prop.value;
406 Tmp_win->name_list = NULL;
408 #else
409 if (!XGetWMName(dpy, Tmp_win->w, &text_prop))
410 return;
411 free_window_names (Tmp_win, True, False);
412 Tmp_win->name = (char *)text_prop.value;
413 if (Tmp_win->name && strlen(Tmp_win->name) > MAX_WINDOW_NAME_LEN)
414 /* limit to prevent hanging X server */
415 Tmp_win->name[MAX_WINDOW_NAME_LEN] = 0;
416 #endif
418 SET_NAME_CHANGED(Tmp_win, 1);
420 if (Tmp_win->name == NULL)
421 Tmp_win->name = NoName;
422 BroadcastName(M_WINDOW_NAME,Tmp_win->w,Tmp_win->frame,
423 (unsigned long)Tmp_win,Tmp_win->name);
425 /* fix the name in the title bar */
426 if(!IS_ICONIFIED(Tmp_win))
427 DrawDecorations(
428 Tmp_win, DRAW_TITLE, (Scr.Hilite == Tmp_win), True, None);
431 * if the icon name is NoName, set the name of the icon to be
432 * the same as the window
434 if (Tmp_win->icon_name == NoName)
436 Tmp_win->icon_name = Tmp_win->name;
437 BroadcastName(M_ICON_NAME,Tmp_win->w,Tmp_win->frame,
438 (unsigned long)Tmp_win,Tmp_win->icon_name);
439 RedoIconName(Tmp_win);
441 break;
443 case XA_WM_ICON_NAME:
444 flush_property_notify(XA_WM_ICON_NAME, Tmp_win->w);
445 #ifdef I18N_MB
446 if (XGetWindowProperty (dpy, Tmp_win->w, Event.xproperty.atom, 0L,
447 MAX_ICON_NAME_LEN, False, AnyPropertyType,
448 &actual, &actual_format, &nitems, &bytesafter,
449 (unsigned char **) &prop) != Success ||
450 actual == None)
451 return;
452 if (prop) {
453 if (actual == XA_STRING) {
454 /* STRING encoding, use this as it is */
455 free_window_names (Tmp_win, False, True);
456 Tmp_win->icon_name = prop;
457 Tmp_win->icon_name_list = NULL;
458 } else {
459 /* not STRING encoding, try to convert */
460 text_prop.value = prop;
461 text_prop.encoding = actual;
462 text_prop.format = actual_format;
463 text_prop.nitems = nitems;
464 if (XmbTextPropertyToTextList(dpy, &text_prop, &list, &num) >= Success
465 && num > 0 && *list) {
466 /* XXX: does not consider the conversion is REALLY succeeded */
467 XFree(prop); /* return of XGetWindowProperty() */
468 free_window_names (Tmp_win, False, True);
469 Tmp_win->icon_name = *list;
470 Tmp_win->icon_name_list = list;
471 } else {
472 if (list) XFreeStringList(list);
473 XFree(prop); /* return of XGetWindowProperty() */
474 if (!XGetWMIconName (dpy, Tmp_win->w, &text_prop))
475 return; /* why cannot read... */
476 free_window_names (Tmp_win, False, True);
477 Tmp_win->icon_name = (char *)text_prop.value;
478 Tmp_win->icon_name_list = NULL;
481 } else {
482 /* XXX: fallback to original behavior, is it needed ? */
483 if (!XGetWMIconName(dpy, Tmp_win->w, &text_prop))
484 return;
485 free_window_names (Tmp_win, False, True);
486 Tmp_win->icon_name = (char *)text_prop.value;
487 Tmp_win->icon_name_list = NULL;
489 #else
490 if (!XGetWMIconName (dpy, Tmp_win->w, &text_prop))
491 return;
492 free_window_names (Tmp_win, False, True);
493 Tmp_win->icon_name = (char *) text_prop.value;
494 if (Tmp_win->icon_name && strlen(Tmp_win->icon_name) >
495 MAX_ICON_NAME_LEN)
496 /* limit to prevent hanging X server */
497 Tmp_win->icon_name[MAX_ICON_NAME_LEN] = 0;
498 #endif
499 if (Tmp_win->icon_name == NULL)
500 Tmp_win->icon_name = NoName;
501 BroadcastName(M_ICON_NAME,Tmp_win->w,Tmp_win->frame,
502 (unsigned long)Tmp_win,Tmp_win->icon_name);
503 RedoIconName(Tmp_win);
504 break;
506 case XA_WM_HINTS:
507 flush_property_notify(XA_WM_HINTS, Tmp_win->w);
508 /* clasen@mathematik.uni-freiburg.de - 02/01/1998 - new -
509 the urgency flag is an ICCCM 2.0 addition to the WM_HINTS. */
510 old_wmhints_flags = 0;
511 if (Tmp_win->wmhints)
513 old_wmhints_flags = Tmp_win->wmhints->flags;
514 XFree ((char *) Tmp_win->wmhints);
516 Tmp_win->wmhints = XGetWMHints(dpy, Event.xany.window);
517 if(Tmp_win->wmhints == NULL)
519 return;
523 * rebuild icon if the client either provides an icon
524 * pixmap or window or has reset the hints to `no icon'.
526 if ((Tmp_win->wmhints->flags & (IconPixmapHint|IconWindowHint)) ||
527 (old_wmhints_flags & (IconPixmapHint|IconWindowHint)))
529 if(Tmp_win->icon_bitmap_file == Scr.DefaultIcon)
530 Tmp_win->icon_bitmap_file = NULL;
531 if(!Tmp_win->icon_bitmap_file &&
532 !(Tmp_win->wmhints->flags&(IconPixmapHint|IconWindowHint)))
534 Tmp_win->icon_bitmap_file =
535 (Scr.DefaultIcon) ? strdup(Scr.DefaultIcon) : NULL;
537 Tmp_win->iconPixmap = (Window)NULL;
538 if(IS_ICONIFIED(Tmp_win))
540 SET_ICONIFIED(Tmp_win, 0);
541 SET_ICON_UNMAPPED(Tmp_win, 0);
542 CreateIconWindow(Tmp_win, Tmp_win->icon_g.x,Tmp_win->icon_g.y);
543 BroadcastPacket(M_ICONIFY, 7,
544 Tmp_win->w, Tmp_win->frame,
545 (unsigned long)Tmp_win,
546 Tmp_win->icon_g.x, Tmp_win->icon_g.y,
547 Tmp_win->icon_g.width, Tmp_win->icon_g.height);
548 /* domivogt (15-Sep-1999): BroadcastConfig informs modules of the
549 * configuration change including the iconified flag. So this
550 * flag must be set here. I'm not sure if the two calls of the
551 * SET_ICONIFIED macro after BroadcastConfig are necessary, but
552 * since it's only minimal overhead I prefer to be on the safe
553 * side. */
554 SET_ICONIFIED(Tmp_win, 1);
555 BroadcastConfig(M_CONFIGURE_WINDOW, Tmp_win);
556 SET_ICONIFIED(Tmp_win, 0);
558 if (!IS_ICON_SUPPRESSED(Tmp_win))
560 LowerWindow(Tmp_win);
561 AutoPlaceIcon(Tmp_win);
562 if(Tmp_win->Desk == Scr.CurrentDesk)
564 if(Tmp_win->icon_w)
565 XMapWindow(dpy, Tmp_win->icon_w);
566 if(Tmp_win->icon_pixmap_w != None)
567 XMapWindow(dpy, Tmp_win->icon_pixmap_w);
570 SET_ICONIFIED(Tmp_win, 1);
571 DrawIconWindow(Tmp_win);
575 /* clasen@mathematik.uni-freiburg.de - 02/01/1998 - new -
576 the urgency flag is an ICCCM 2.0 addition to the WM_HINTS.
577 Treat urgency changes by calling user-settable functions.
578 These could e.g. deiconify and raise the window or temporarily
579 change the decor. */
580 if (!(old_wmhints_flags & XUrgencyHint) &&
581 (Tmp_win->wmhints->flags & XUrgencyHint))
583 old_execute_function(
584 "Function UrgencyFunc", Tmp_win, &Event, C_WINDOW, -1, 0, NULL);
587 if ((old_wmhints_flags & XUrgencyHint) &&
588 !(Tmp_win->wmhints->flags & XUrgencyHint))
590 old_execute_function(
591 "Function UrgencyDoneFunc", Tmp_win, &Event, C_WINDOW, -1, 0, NULL);
593 break;
594 case XA_WM_NORMAL_HINTS:
595 was_size_inc_set = IS_SIZE_INC_SET(Tmp_win);
596 old_width_inc = Tmp_win->hints.width_inc;
597 old_height_inc = Tmp_win->hints.height_inc;
598 old_base_width = Tmp_win->hints.base_width;
599 old_base_height = Tmp_win->hints.base_height;
600 GetWindowSizeHints(Tmp_win);
601 if (old_width_inc != Tmp_win->hints.width_inc ||
602 old_height_inc != Tmp_win->hints.height_inc)
604 int units_w;
605 int units_h;
606 int wdiff;
607 int hdiff;
609 if (!was_size_inc_set && old_width_inc == 1 && old_height_inc == 1)
611 /* This is a hack for xvile. It sets the _inc hints after it
612 * requested that the window is mapped but before it's really
613 * visible. */
614 /* do nothing */
616 else
618 /* we have to resize the unmaximized window to keep the size in
619 * resize increments constant */
620 units_w = Tmp_win->normal_g.width - 2 * Tmp_win->boundary_width -
621 old_base_width;
622 units_h = Tmp_win->normal_g.height - Tmp_win->title_g.height -
623 2 * Tmp_win->boundary_width - old_base_height;
624 units_w /= old_width_inc;
625 units_h /= old_height_inc;
627 /* update the 'invisible' geometry */
628 wdiff = units_w * (Tmp_win->hints.width_inc - old_width_inc) +
629 (Tmp_win->hints.base_width - old_base_width);
630 hdiff = units_h * (Tmp_win->hints.height_inc - old_height_inc) +
631 (Tmp_win->hints.base_height - old_base_height);
632 gravity_resize(
633 Tmp_win->hints.win_gravity, &Tmp_win->normal_g, wdiff, hdiff);
635 gravity_constrain_size(
636 Tmp_win->hints.win_gravity, Tmp_win, &Tmp_win->normal_g);
637 if (!IS_MAXIMIZED(Tmp_win))
639 rectangle new_g;
641 get_relative_geometry(&new_g, &Tmp_win->normal_g);
642 if (IS_SHADED(Tmp_win))
643 get_shaded_geometry(Tmp_win, &new_g, &new_g);
644 ForceSetupFrame(
645 Tmp_win, new_g.x, new_g.y, new_g.width, new_g.height, False);
647 else
649 int w;
650 int h;
652 maximize_adjust_offset(Tmp_win);
653 /* domivogt (07-Apr-2000): as terrible hack to work around a xterm
654 * bug: when the font size is changed in a xterm, xterm simply assumes
655 * that the wm will grant its new size. Of course this is wrong if
656 * the xterm is maximised. To make xterm happy, we first send a
657 * ConfigureNotify with the current (maximised) geometry + 1 pixel in
658 * height, then another one with the correct old geometry. Changing
659 * the font multiple times will cause the xterm to shrink because
660 * gravity_constrain_size doesn't know about the initially requested
661 * dimensions. */
662 w = Tmp_win->max_g.width;
663 h = Tmp_win->max_g.height;
664 gravity_constrain_size(
665 Tmp_win->hints.win_gravity, Tmp_win, &Tmp_win->max_g);
666 if (w != Tmp_win->max_g.width ||
667 h != Tmp_win->max_g.height)
669 rectangle new_g;
671 /* This is in case the size_inc changed and the old dimensions are
672 * not multiples of the new values. */
673 get_relative_geometry(&new_g, &Tmp_win->max_g);
674 if (IS_SHADED(Tmp_win))
675 get_shaded_geometry(Tmp_win, &new_g, &new_g);
676 ForceSetupFrame(
677 Tmp_win, new_g.x, new_g.y, new_g.width, new_g.height, False);
679 else
681 SendConfigureNotify(
682 Tmp_win, Tmp_win->frame_g.x, Tmp_win->frame_g.y,
683 Tmp_win->frame_g.width, Tmp_win->frame_g.height+1, 0, False);
684 XSync(dpy, 0);
685 /* free some CPU */
686 usleep(1);
687 SendConfigureNotify(
688 Tmp_win, Tmp_win->frame_g.x, Tmp_win->frame_g.y,
689 Tmp_win->frame_g.width, Tmp_win->frame_g.height, 0, False);
690 XSync(dpy, 0);
693 GNOME_SetWinArea(Tmp_win);
695 BroadcastConfig(M_CONFIGURE_WINDOW,Tmp_win);
696 break;
698 default:
699 if(Event.xproperty.atom == _XA_WM_PROTOCOLS)
700 FetchWmProtocols (Tmp_win);
701 else if (Event.xproperty.atom == _XA_WM_COLORMAP_WINDOWS)
703 FetchWmColormapWindows (Tmp_win); /* frees old data */
704 ReInstallActiveColormap();
706 else if(Event.xproperty.atom == _XA_WM_STATE)
708 if((Tmp_win != NULL)&&(HAS_CLICK_FOCUS(Tmp_win))
709 &&(Tmp_win == Scr.Focus))
711 if (OnThisPage)
713 Scr.Focus = NULL;
714 SetFocusWindow(Tmp_win, 0);
718 break;
723 /***********************************************************************
725 * Procedure:
726 * HandleClientMessage - client message event handler
728 ************************************************************************/
729 void HandleClientMessage(void)
731 XEvent button;
733 DBUG("HandleClientMessage","Routine Entered");
735 /* Process GNOME Messages */
736 if (GNOME_ProcessClientMessage(Tmp_win, &Event))
738 return;
741 if ((Event.xclient.message_type == _XA_WM_CHANGE_STATE)&&
742 (Tmp_win)&&(Event.xclient.data.l[0]==IconicState)&&
743 !IS_ICONIFIED(Tmp_win))
745 XQueryPointer( dpy, Scr.Root, &JunkRoot, &JunkChild,
746 &(button.xmotion.x_root),
747 &(button.xmotion.y_root),
748 &JunkX, &JunkY, &JunkMask);
749 button.type = 0;
750 old_execute_function("Iconify", Tmp_win, &button, C_FRAME, -1, 0, NULL);
751 return;
754 /* FIXME: Is this safe enough ? I guess if clients behave
755 according to ICCCM and send these messages only if they
756 when grabbed the pointer, it is OK */
758 extern Atom _XA_WM_COLORMAP_NOTIFY;
759 if (Event.xclient.message_type == _XA_WM_COLORMAP_NOTIFY) {
760 set_client_controls_colormaps(Event.xclient.data.l[1]);
761 return;
766 ** CKH - if we get here, it was an unknown client message, so send
767 ** it to the client if it was in a window we know about. I'm not so
768 ** sure this should be done or not, since every other window manager
769 ** I've looked at doesn't. But it might be handy for a free drag and
770 ** drop setup being developed for Linux.
772 if (Tmp_win)
774 if(Event.xclient.window != Tmp_win->w)
776 Event.xclient.window = Tmp_win->w;
777 XSendEvent(dpy, Tmp_win->w, False, NoEventMask, &Event);
782 /***********************************************************************
784 * Procedure:
785 * HandleExpose - expose event handler
787 ***********************************************************************/
788 void HandleExpose(void)
790 if (Event.xexpose.count != 0)
791 return;
793 DBUG("HandleExpose","Routine Entered");
795 if (Tmp_win)
797 draw_window_parts draw_parts;
799 if (Event.xany.window == Tmp_win->title_w)
800 draw_parts = DRAW_TITLE;
801 else if (Event.xany.window == Tmp_win->decor_w ||
802 Event.xany.window == Tmp_win->frame)
803 draw_parts = DRAW_FRAME;
804 else
805 draw_parts = DRAW_BUTTONS;
806 DrawDecorations(
807 Tmp_win, draw_parts, (Scr.Hilite == Tmp_win), True, Event.xany.window);
809 return;
814 /***********************************************************************
816 * Procedure:
817 * HandleDestroyNotify - DestroyNotify event handler
819 ***********************************************************************/
820 void HandleDestroyNotify(void)
822 DBUG("HandleDestroyNotify","Routine Entered");
824 destroy_window(Tmp_win);
825 GNOME_SetClientList();
831 /***********************************************************************
833 * Procedure:
834 * HandleMapRequest - MapRequest event handler
836 ************************************************************************/
837 void HandleMapRequest(void)
839 DBUG("HandleMapRequest","Routine Entered");
841 if (fFvwmInStartup)
843 /* Just map the damn thing, decorations are added later
844 * in CaptureAllWindows. */
845 XMapWindow (dpy, Event.xmaprequest.window);
846 return;
848 HandleMapRequestKeepRaised(None, NULL);
850 void HandleMapRequestKeepRaised(Window KeepRaised, FvwmWindow *ReuseWin)
852 extern long isIconicState;
853 extern Bool isIconifiedByParent;
854 extern Boolean PPosOverride;
855 Bool OnThisPage = False;
857 Event.xany.window = Event.xmaprequest.window;
859 if (ReuseWin == NULL)
861 if(XFindContext(dpy, Event.xany.window, FvwmContext,
862 (caddr_t *)&Tmp_win)==XCNOENT)
864 Tmp_win = NULL;
867 else
869 Tmp_win = ReuseWin;
872 if(!PPosOverride)
873 XFlush(dpy);
875 /* If the window has never been mapped before ... */
876 if(!Tmp_win || (Tmp_win && DO_REUSE_DESTROYED(Tmp_win)))
878 /* Add decorations. */
879 Tmp_win = AddWindow(Event.xany.window, ReuseWin);
880 if (Tmp_win == NULL)
881 return;
884 * Make sure at least part of window is on this page
885 * before giving it focus...
887 OnThisPage = IsRectangleOnThisPage(&(Tmp_win->frame_g), Tmp_win->Desk);
889 if(KeepRaised != None)
891 XRaiseWindow(dpy, KeepRaised);
893 /* If it's not merely iconified, and we have hints, use them. */
894 if (!IS_ICONIFIED(Tmp_win))
896 int state;
898 if(Tmp_win->wmhints && (Tmp_win->wmhints->flags & StateHint))
899 state = Tmp_win->wmhints->initial_state;
900 else
901 state = NormalState;
903 if(DO_START_ICONIC(Tmp_win))
904 state = IconicState;
906 if(isIconicState != DontCareState)
907 state = isIconicState;
909 MyXGrabServer(dpy);
910 switch (state)
912 case DontCareState:
913 case NormalState:
914 case InactiveState:
915 default:
916 if (Tmp_win->Desk == Scr.CurrentDesk)
918 Bool do_grab_focus;
920 XMapWindow(dpy, Tmp_win->frame);
921 XMapWindow(dpy, Tmp_win->w);
922 SET_MAP_PENDING(Tmp_win, 1);
923 SetMapStateProp(Tmp_win, NormalState);
924 if (Scr.flags.is_map_desk_in_progress)
925 do_grab_focus = False;
926 if (!OnThisPage)
927 do_grab_focus = True;
928 else if (DO_GRAB_FOCUS(Tmp_win) &&
929 (!IS_TRANSIENT(Tmp_win) || Tmp_win->transientfor == Scr.Root))
931 do_grab_focus = True;
933 else if (IS_TRANSIENT(Tmp_win) && DO_GRAB_FOCUS_TRANSIENT(Tmp_win) &&
934 Scr.Focus && Scr.Focus->w == Tmp_win->transientfor)
936 /* it's a transient and its transientfor currently has focus. */
937 do_grab_focus = True;
939 else if (IS_TRANSIENT(Tmp_win) && DO_GRAB_FOCUS(Tmp_win) &&
940 !(XGetGeometry(dpy, Tmp_win->transientfor, &JunkRoot, &JunkX,
941 &JunkY, &JunkWidth, &JunkHeight, &JunkBW,
942 &JunkDepth)))
944 /* Gee, the transientfor does not exist! These evil application
945 * programmers must hate us a lot. */
946 Tmp_win->transientfor = Scr.Root;
947 do_grab_focus = True;
949 else
950 do_grab_focus = False;
951 if (do_grab_focus)
953 SetFocusWindow(Tmp_win, 1);
955 else
957 /* make sure the old focused window still has grabbed all necessary
958 * buttons. */
959 if (Scr.Focus)
961 focus_grab_buttons(Scr.Focus, True);
965 else
967 #if 0
968 /* nope, this is forbidden by the ICCCM */
969 XMapWindow(dpy, Tmp_win->w);
970 SetMapStateProp(Tmp_win, NormalState);
971 #else
972 /* Since we will not get a MapNotify, set the IS_MAPPED flag manually.
974 SET_MAPPED(Tmp_win, 1);
975 SetMapStateProp(Tmp_win, IconicState);
976 #endif
978 break;
980 case IconicState:
981 if (isIconifiedByParent)
983 isIconifiedByParent = False;
984 SET_ICONIFIED_BY_PARENT(Tmp_win, 1);
986 if (Tmp_win->wmhints)
988 Iconify(Tmp_win, Tmp_win->wmhints->icon_x,
989 Tmp_win->wmhints->icon_y);
991 else
993 Iconify(Tmp_win, 0, 0);
995 break;
997 if(!PPosOverride)
998 XSync(dpy,0);
999 MyXUngrabServer(dpy);
1001 /* If no hints, or currently an icon, just "deiconify" */
1002 else
1004 DeIconify(Tmp_win);
1006 if (IS_SHADED(Tmp_win))
1008 BroadcastPacket(M_WINDOWSHADE, 3, Tmp_win->w, Tmp_win->frame,
1009 (unsigned long)Tmp_win);
1012 if (!IS_ICONIFIED(Tmp_win) && Scr.Focus && Scr.Focus != Tmp_win &&
1013 !is_on_top_of_layer(Scr.Focus))
1015 if (Tmp_win->Desk == Scr.CurrentDesk &&
1016 Tmp_win->frame_g.x + Tmp_win->frame_g.width > Scr.Focus->frame_g.x &&
1017 Scr.Focus->frame_g.x + Scr.Focus->frame_g.width > Tmp_win->frame_g.x &&
1018 Tmp_win->frame_g.y + Tmp_win->frame_g.height > Scr.Focus->frame_g.y &&
1019 Scr.Focus->frame_g.y + Scr.Focus->frame_g.height > Tmp_win->frame_g.y)
1021 /* The newly mapped window overlaps the focused window. Make sure
1022 * ClickToFocusRaises and MouseFocusClickRaises work again.
1024 * Note: There are many conditions under which we do not have to call
1025 * focus_grab_buttons(), but it is not worth the effort to write them
1026 * down here. Rather do some unnecessary work in this function. */
1027 focus_grab_buttons(Scr.Focus, True);
1031 /* Just to be on the safe side, we make sure that STARTICONIC
1032 can only influence the initial transition from withdrawn state. */
1033 SET_DO_START_ICONIC(Tmp_win, 0);
1034 if (DO_DELETE_ICON_MOVED(Tmp_win))
1036 SET_DELETE_ICON_MOVED(Tmp_win, 0);
1037 SET_ICON_MOVED(Tmp_win, 0);
1039 /* Clean out the global so that it isn't used on additional map events. */
1040 isIconicState = DontCareState;
1041 GNOME_SetClientList();
1045 /***********************************************************************
1047 * Procedure:
1048 * HandleMapNotify - MapNotify event handler
1050 ***********************************************************************/
1051 void HandleMapNotify(void)
1053 Bool OnThisPage = False;
1055 DBUG("HandleMapNotify","Routine Entered");
1057 if (!Tmp_win)
1059 if((Event.xmap.override_redirect == True)&&
1060 (Event.xmap.window != Scr.NoFocusWin))
1062 XSelectInput(dpy,Event.xmap.window,FocusChangeMask);
1063 Scr.UnknownWinFocused = Event.xmap.window;
1065 return;
1068 /* Except for identifying over-ride redirect window mappings, we
1069 * don't need or want windows associated with the substructurenotifymask */
1070 if(Event.xmap.event != Event.xmap.window)
1071 return;
1073 SET_MAP_PENDING(Tmp_win, 0);
1074 /* don't map if the event was caused by a de-iconify */
1075 if (IS_DEICONIFY_PENDING(Tmp_win))
1077 return;
1081 Make sure at least part of window is on this page
1082 before giving it focus...
1084 OnThisPage = IsRectangleOnThisPage(&(Tmp_win->frame_g), Tmp_win->Desk);
1087 * Need to do the grab to avoid race condition of having server send
1088 * MapNotify to client before the frame gets mapped; this is bad because
1089 * the client would think that the window has a chance of being viewable
1090 * when it really isn't.
1092 MyXGrabServer (dpy);
1093 if (Tmp_win->icon_w)
1094 XUnmapWindow(dpy, Tmp_win->icon_w);
1095 if(Tmp_win->icon_pixmap_w != None)
1096 XUnmapWindow(dpy, Tmp_win->icon_pixmap_w);
1097 XMapSubwindows(dpy, Tmp_win->frame);
1098 XMapSubwindows(dpy, Tmp_win->decor_w);
1100 if(Tmp_win->Desk == Scr.CurrentDesk)
1102 XMapWindow(dpy, Tmp_win->frame);
1105 if(IS_ICONIFIED(Tmp_win))
1106 BroadcastPacket(M_DEICONIFY, 3,
1107 Tmp_win->w, Tmp_win->frame, (unsigned long)Tmp_win);
1108 else
1109 BroadcastPacket(M_MAP, 3,
1110 Tmp_win->w,Tmp_win->frame, (unsigned long)Tmp_win);
1112 if((!IS_TRANSIENT(Tmp_win) && DO_GRAB_FOCUS(Tmp_win)) ||
1113 (IS_TRANSIENT(Tmp_win) && DO_GRAB_FOCUS_TRANSIENT(Tmp_win) &&
1114 Scr.Focus && Scr.Focus->w == Tmp_win->transientfor))
1116 if (OnThisPage)
1118 SetFocusWindow(Tmp_win, 1);
1121 if((!(HAS_BORDER(Tmp_win)|HAS_TITLE(Tmp_win)))&&(Tmp_win->boundary_width <2))
1123 DrawDecorations(
1124 Tmp_win, DRAW_ALL, False, True, Tmp_win->decor_w);
1126 else if (Tmp_win == Scr.Focus && Tmp_win != Scr.Hilite)
1128 /* BUG 679: must redraw decorations here to make sure the window is properly
1129 * hilighted after being de-iconified by a key press. */
1130 DrawDecorations(Tmp_win, DRAW_ALL, True, True, None);
1132 XSync(dpy,0);
1133 MyXUngrabServer (dpy);
1134 XFlush (dpy);
1135 SET_MAPPED(Tmp_win, 1);
1136 SET_ICONIFIED(Tmp_win, 0);
1137 SET_ICON_UNMAPPED(Tmp_win, 0);
1138 if (DO_ICONIFY_AFTER_MAP(Tmp_win))
1140 /* finally, if iconification was requested before the window was mapped,
1141 * request it now. */
1142 Iconify(Tmp_win, 0, 0);
1143 SET_ICONIFY_AFTER_MAP(Tmp_win, 0);
1148 /***********************************************************************
1150 * Procedure:
1151 * HandleUnmapNotify - UnmapNotify event handler
1153 ************************************************************************/
1154 void HandleUnmapNotify(void)
1156 int dstx, dsty;
1157 Window dumwin;
1158 XEvent dummy;
1159 int weMustUnmap;
1160 int focus_grabbed = 0;
1161 Bool must_return = False;
1163 DBUG("HandleUnmapNotify","Routine Entered");
1166 * Don't ignore events as described below.
1168 if(Event.xunmap.event != Event.xunmap.window &&
1169 (Event.xunmap.event != Scr.Root || !Event.xunmap.send_event))
1171 must_return = True;
1175 * The July 27, 1988 ICCCM spec states that a client wishing to switch
1176 * to WithdrawnState should send a synthetic UnmapNotify with the
1177 * event field set to (pseudo-)root, in case the window is already
1178 * unmapped (which is the case for fvwm for IconicState). Unfortunately,
1179 * we looked for the FvwmContext using that field, so try the window
1180 * field also.
1182 weMustUnmap = 0;
1183 if (!Tmp_win)
1185 Event.xany.window = Event.xunmap.window;
1186 weMustUnmap = 1;
1187 if (XFindContext(dpy, Event.xany.window,
1188 FvwmContext, (caddr_t *)&Tmp_win) == XCNOENT)
1189 Tmp_win = NULL;
1192 if(!Tmp_win)
1193 return;
1195 if (Event.xunmap.window == Tmp_win->frame)
1197 SET_DEICONIFY_PENDING(Tmp_win , 0);
1200 if (must_return)
1201 return;
1203 if(weMustUnmap)
1204 XUnmapWindow(dpy, Event.xunmap.window);
1205 if(Tmp_win == Scr.Hilite)
1207 Scr.Hilite = NULL;
1209 if(Scr.PreviousFocus == Tmp_win)
1210 Scr.PreviousFocus = NULL;
1211 focus_grabbed = (Tmp_win == Scr.Focus) &&
1212 ((!IS_TRANSIENT(Tmp_win) && DO_GRAB_FOCUS(Tmp_win)) ||
1213 (IS_TRANSIENT(Tmp_win) && DO_GRAB_FOCUS_TRANSIENT(Tmp_win)));
1214 restore_focus_after_unmap(Tmp_win);
1215 if (!IS_MAPPED(Tmp_win) && !IS_ICONIFIED(Tmp_win))
1217 return;
1220 MyXGrabServer(dpy);
1222 if(XCheckTypedWindowEvent (dpy, Event.xunmap.window, DestroyNotify,&dummy))
1224 destroy_window(Tmp_win);
1226 else
1228 * The program may have unmapped the client window, from either
1229 * NormalState or IconicState. Handle the transition to WithdrawnState.
1231 * We need to reparent the window back to the root (so that fvwm exiting
1232 * won't cause it to get mapped) and then throw away all state (pretend
1233 * that we've received a DestroyNotify).
1235 if (XTranslateCoordinates (dpy, Event.xunmap.window, Scr.Root,
1236 0, 0, &dstx, &dsty, &dumwin))
1238 XEvent ev;
1239 Bool reparented;
1241 reparented = XCheckTypedWindowEvent (dpy, Event.xunmap.window,
1242 ReparentNotify, &ev);
1243 SetMapStateProp (Tmp_win, WithdrawnState);
1244 if (reparented)
1246 if (Tmp_win->old_bw)
1247 XSetWindowBorderWidth (dpy, Event.xunmap.window, Tmp_win->old_bw);
1248 if((!IS_ICON_SUPPRESSED(Tmp_win))&&
1249 (Tmp_win->wmhints && (Tmp_win->wmhints->flags & IconWindowHint)))
1250 XUnmapWindow (dpy, Tmp_win->wmhints->icon_window);
1252 else
1254 RestoreWithdrawnLocation (Tmp_win, False, Scr.Root);
1256 XRemoveFromSaveSet (dpy, Event.xunmap.window);
1257 XSelectInput (dpy, Event.xunmap.window, NoEventMask);
1258 destroy_window(Tmp_win); /* do not need to mash event before */
1260 * Flush any pending events for the window.
1262 /* Bzzt! it could be about to re-map */
1263 /* while(XCheckWindowEvent(dpy, Event.xunmap.window,
1264 StructureNotifyMask | PropertyChangeMask |
1265 ColormapChangeMask | VisibilityChangeMask |
1266 EnterWindowMask | LeaveWindowMask, &dummy));
1268 } /* else window no longer exists and we'll get a destroy notify */
1269 MyXUngrabServer(dpy);
1271 XFlush (dpy);
1273 if (focus_grabbed)
1275 CoerceEnterNotifyOnCurrentWindow();
1277 GNOME_SetClientList();
1281 /***********************************************************************
1283 * Procedure:
1284 * HandleButtonPress - ButtonPress event handler
1286 ***********************************************************************/
1287 void HandleButtonPress(void)
1289 int LocalContext;
1290 char *action;
1291 Window OldPressedW;
1292 Window eventw;
1293 Bool do_regrab_buttons = False;
1294 Bool do_pass_click;
1296 DBUG("HandleButtonPress","Routine Entered");
1298 GrabEm(CRS_NONE, GRAB_PASSIVE);
1299 if (!Tmp_win && Event.xany.window != Scr.Root)
1301 /* event in unmanaged window or subwindow of a client */
1302 /* DV: of course we should never have got an event in this case since the
1303 * button should not be grabbed. */
1304 XSync(dpy,0);
1305 XAllowEvents(dpy,ReplayPointer,CurrentTime);
1306 XSync(dpy,0);
1307 UngrabEm(GRAB_PASSIVE);
1308 return;
1310 if (Event.xbutton.subwindow != None &&
1311 (Tmp_win == None || Event.xany.window != Tmp_win->w))
1313 eventw = Event.xbutton.subwindow;
1315 else
1317 eventw = Event.xany.window;
1319 if (!XGetGeometry(dpy, eventw, &JunkRoot, &JunkX, &JunkY,
1320 &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth))
1322 /* The window has already died. Just pass the event to the application. */
1323 XSync(dpy,0);
1324 XAllowEvents(dpy,ReplayPointer,CurrentTime);
1325 XSync(dpy,0);
1326 UngrabEm(GRAB_PASSIVE);
1327 return;
1329 if (Tmp_win && HAS_NEVER_FOCUS(Tmp_win))
1331 /* It might seem odd to try to focus a window that never is given focus by
1332 * fvwm, but the window might want to take focus itself, and SetFocus will
1333 * tell it to do so in this case instead of giving it focus. */
1334 SetFocusWindow(Tmp_win, 1);
1336 /* click to focus stuff goes here */
1337 if((Tmp_win)&&(HAS_CLICK_FOCUS(Tmp_win))&&(Tmp_win != Scr.Ungrabbed))
1339 if (Tmp_win != Scr.Focus)
1340 SetFocusWindow(Tmp_win, 1);
1341 /* RBW - 12/09/.1999- I'm not sure we need to check both cases, but
1342 I'll leave this as is for now. */
1343 if (!DO_NOT_RAISE_CLICK_FOCUS_CLICK(Tmp_win)
1344 #if 0
1345 /* DV - this forces that every focus click on the decorations raises
1346 * the window. This somewhat negates the ClickToFocusRaisesOff style.
1349 ((Event.xany.window != Tmp_win->w)&&
1350 (Event.xbutton.subwindow != Tmp_win->w)&&
1351 (Event.xany.window != Tmp_win->Parent)&&
1352 (Event.xbutton.subwindow != Tmp_win->Parent))
1353 #endif
1356 /* We can't raise the window immediately because the action bound to the
1357 * click might be "Lower" or "RaiseLower". So mark the window as
1358 * scheduled to be raised after the binding is executed. Functions that
1359 * modify the stacking order will reset this flag. */
1360 SET_SCHEDULED_FOR_RAISE(Tmp_win, 1);
1361 do_regrab_buttons = True;
1364 Context = GetContext(Tmp_win,&Event, &PressedW);
1365 if (!IS_ICONIFIED(Tmp_win) && Context == C_WINDOW)
1367 if (Tmp_win && IS_SCHEDULED_FOR_RAISE(Tmp_win))
1369 RaiseWindow(Tmp_win);
1370 SET_SCHEDULED_FOR_RAISE(Tmp_win, 0);
1372 if (do_regrab_buttons)
1373 focus_grab_buttons(Tmp_win, (Tmp_win == Scr.Focus));
1374 XSync(dpy,0);
1375 /* Pass click event to just clicked to focus window? Do not swallow the
1376 * click if the window didn't accept the focus. */
1377 if (!DO_NOT_PASS_CLICK_FOCUS_CLICK(Tmp_win) || Scr.Focus != Tmp_win)
1379 XAllowEvents(dpy,ReplayPointer,CurrentTime);
1381 else /* don't pass click to just focused window */
1383 XAllowEvents(dpy,AsyncPointer,CurrentTime);
1385 XSync(dpy,0);
1386 UngrabEm(GRAB_PASSIVE);
1387 return;
1389 if (!IS_ICONIFIED(Tmp_win))
1391 DrawDecorations(Tmp_win, DRAW_ALL, True, True, PressedW);
1394 else if (Tmp_win && Event.xbutton.window == Tmp_win->Parent &&
1395 (HAS_SLOPPY_FOCUS(Tmp_win) || HAS_MOUSE_FOCUS(Tmp_win) ||
1396 HAS_NEVER_FOCUS(Tmp_win)) &&
1397 DO_RAISE_MOUSE_FOCUS_CLICK(Tmp_win))
1399 FvwmWindow *tmp = Scr.Ungrabbed;
1402 RBW - Release the Parent grab here (whether we raise or not). We
1403 have to wait till this point or we would miss the raise click, which
1404 is not contemporaneous with the focus change.
1405 Scr.Ungrabbed should always be NULL here. I don't know anything
1406 useful we could do if it's not, other than ignore this window.
1408 if (!is_on_top_of_layer(Tmp_win) &&
1409 MaskUsedModifiers(Event.xbutton.state) == 0)
1411 RaiseWindow(Tmp_win);
1412 focus_grab_buttons(Tmp_win, True);
1413 Scr.Ungrabbed = tmp;
1414 XSync(dpy,0);
1415 XAllowEvents(dpy,ReplayPointer,CurrentTime);
1416 XSync(dpy,0);
1417 UngrabEm(GRAB_PASSIVE);
1418 return;
1420 focus_grab_buttons(Tmp_win, True);
1421 Scr.Ungrabbed = tmp;
1424 Context = GetContext(Tmp_win, &Event, &PressedW);
1425 LocalContext = Context;
1426 if (Tmp_win)
1428 if (Context == C_TITLE)
1429 DrawDecorations(
1430 Tmp_win, DRAW_TITLE, (Scr.Hilite == Tmp_win), True, None);
1431 else if (Context & (C_LALL | C_RALL))
1432 DrawDecorations(
1433 Tmp_win, DRAW_BUTTONS, (Scr.Hilite == Tmp_win), True, PressedW);
1434 else
1436 DrawDecorations(
1437 Tmp_win, DRAW_FRAME, (Scr.Hilite == Tmp_win),
1438 (HAS_DEPRESSABLE_BORDER(Tmp_win) && PressedW != None), PressedW);
1442 ButtonWindow = Tmp_win;
1444 /* we have to execute a function or pop up a menu */
1445 STROKE_CODE(stroke_init());
1446 STROKE_CODE(send_motion = TRUE);
1447 /* need to search for an appropriate mouse binding */
1448 action = CheckBinding(Scr.AllBindings, STROKE_ARG(0) Event.xbutton.button,
1449 Event.xbutton.state, GetUnusedModifiers(), Context,
1450 MOUSE_BINDING);
1451 do_pass_click = True;
1452 if (action && *action)
1454 old_execute_function(action, Tmp_win, &Event, Context, -1, 0, NULL);
1455 if (Context != C_WINDOW && Context != C_NO_CONTEXT)
1457 WaitForButtonsUp(True);
1458 do_pass_click = False;
1461 else if (Scr.Root == Event.xany.window)
1464 * do gnome buttonpress forwarding if win == root
1466 GNOME_ProxyButtonEvent(&Event);
1467 do_pass_click = False;
1470 if (do_pass_click)
1472 XSync(dpy,0);
1473 XAllowEvents(dpy,ReplayPointer,CurrentTime);
1474 XSync(dpy,0);
1477 if (ButtonWindow && IS_SCHEDULED_FOR_RAISE(ButtonWindow))
1479 /* now that we know the action did not restack the window we can raise it.
1481 RaiseWindow(ButtonWindow);
1482 SET_SCHEDULED_FOR_RAISE(ButtonWindow, 0);
1484 if (do_regrab_buttons)
1486 focus_grab_buttons(Tmp_win, (Tmp_win == Scr.Focus));
1489 OldPressedW = PressedW;
1490 PressedW = None;
1491 if (ButtonWindow && check_if_fvwm_window_exists(ButtonWindow))
1493 if (LocalContext == C_TITLE)
1494 DrawDecorations(
1495 ButtonWindow, DRAW_TITLE, (Scr.Hilite == ButtonWindow), True, None);
1496 else if (LocalContext & (C_LALL | C_RALL))
1497 DrawDecorations(
1498 ButtonWindow, DRAW_BUTTONS, (Scr.Hilite == ButtonWindow), True,
1499 OldPressedW);
1500 else
1501 DrawDecorations(
1502 ButtonWindow, DRAW_FRAME, (Scr.Hilite == ButtonWindow),
1503 HAS_DEPRESSABLE_BORDER(ButtonWindow), None);
1505 ButtonWindow = NULL;
1506 UngrabEm(GRAB_PASSIVE);
1509 #ifdef HAVE_STROKE
1510 /***********************************************************************
1512 * Procedure:
1513 * HandleButtonRelease - ButtonRelease event handler
1515 ************************************************************************/
1516 void HandleButtonRelease()
1518 char *action;
1519 int real_modifier;
1520 Window dummy;
1522 DBUG("HandleButtonRelease","Routine Entered");
1524 send_motion = FALSE;
1525 stroke_trans (sequence);
1527 DBUG("HandleButtonRelease",sequence);
1529 Context = GetContext(Tmp_win,&Event, &dummy);
1531 /* Allows modifier to work (Only R context works here). */
1532 real_modifier = Event.xbutton.state - (1 << (7 + Event.xbutton.button));
1534 /* need to search for an appropriate stroke binding */
1535 action = CheckBinding(
1536 Scr.AllBindings, sequence, Event.xbutton.button, real_modifier,
1537 GetUnusedModifiers(), Context, STROKE_BINDING);
1538 /* got a match, now process it */
1539 if (action != NULL && (action[0] != 0))
1541 old_execute_function(action, Tmp_win, &Event, Context, -1, 0, NULL);
1542 WaitForButtonsUp(True);
1544 else
1547 * do gnome buttonpress forwarding if win == root
1549 if (Scr.Root == Event.xany.window)
1551 GNOME_ProxyButtonEvent(&Event);
1557 /***********************************************************************
1559 * Procedure:
1560 * HandleMotionNotify - MotionNotify event handler
1562 ************************************************************************/
1563 void HandleMotionNotify()
1565 DBUG("HandleMotionNotify","Routine Entered");
1567 if (send_motion == TRUE)
1568 stroke_record (Event.xmotion.x,Event.xmotion.y);
1571 #endif /* HAVE_STROKE */
1573 /***********************************************************************
1575 * Procedure:
1576 * HandleEnterNotify - EnterNotify event handler
1578 ************************************************************************/
1579 void HandleEnterNotify(void)
1581 XEnterWindowEvent *ewp = &Event.xcrossing;
1582 XEvent d;
1584 DBUG("HandleEnterNotify","Routine Entered");
1586 /* Ignore EnterNotify events while a window is resized or moved as a wire
1587 * frame; otherwise the window list may be screwed up. */
1588 if (Scr.flags.is_wire_frame_displayed)
1589 return;
1591 /* look for a matching leaveNotify which would nullify this enterNotify */
1592 if(XCheckTypedWindowEvent (dpy, ewp->window, LeaveNotify, &d))
1595 * RBW - if we're in startup, this is a coerced focus, so we don't
1596 * want to save the event time, or exit prematurely.
1598 if (!fFvwmInStartup)
1600 StashEventTime(&d);
1601 if((d.xcrossing.mode==NotifyNormal)&&
1602 (d.xcrossing.detail!=NotifyInferior))
1603 return;
1607 if (ewp->window == Scr.Root)
1609 if (!Scr.flags.is_pointer_on_this_screen)
1611 Scr.flags.is_pointer_on_this_screen = 1;
1612 if (Scr.LastScreenFocus && Scr.LastScreenFocus != &Scr.FvwmRoot &&
1613 (HAS_SLOPPY_FOCUS(Scr.LastScreenFocus) ||
1614 HAS_CLICK_FOCUS(Scr.LastScreenFocus)))
1616 SetFocusWindow(Scr.LastScreenFocus, 1);
1618 else if (Scr.LastScreenFocus != &Scr.FvwmRoot)
1620 ForceDeleteFocus(1);
1622 else
1624 /* This was the first EnterNotify event for the root window - ignore */
1626 Scr.LastScreenFocus = NULL;
1628 else if (!Scr.Focus || HAS_MOUSE_FOCUS(Scr.Focus))
1630 DeleteFocus(1);
1632 if (Scr.ColormapFocus == COLORMAP_FOLLOWS_MOUSE)
1634 InstallWindowColormaps(NULL);
1636 return;
1638 else
1640 Scr.flags.is_pointer_on_this_screen = 1;
1643 /* an EnterEvent in one of the PanFrameWindows activates the Paging */
1644 if (ewp->window==Scr.PanFrameTop.win
1645 || ewp->window==Scr.PanFrameLeft.win
1646 || ewp->window==Scr.PanFrameRight.win
1647 || ewp->window==Scr.PanFrameBottom.win )
1649 int delta_x=0, delta_y=0;
1651 /* this was in the HandleMotionNotify before, HEDU */
1652 Scr.flags.is_pointer_on_this_screen = 1;
1653 HandlePaging(Scr.EdgeScrollX,Scr.EdgeScrollY,
1654 &ewp->x_root,&ewp->y_root,
1655 &delta_x,&delta_y,True,True,False);
1656 return;
1659 /* make sure its for one of our windows */
1660 if (!Tmp_win)
1662 /* handle a subwindow cmap */
1663 EnterSubWindowColormap(Event.xany.window);
1664 return;
1667 if (HAS_MOUSE_FOCUS(Tmp_win) || HAS_SLOPPY_FOCUS(Tmp_win))
1669 SetFocusWindow(Tmp_win, 1);
1671 else if (HAS_NEVER_FOCUS(Tmp_win))
1673 /* Give the window a chance to grab the buttons needed for raise-on-click */
1674 if (Scr.Focus != Tmp_win)
1676 focus_grab_buttons(Tmp_win, False);
1677 focus_grab_buttons(Scr.Focus, True);
1680 else if (HAS_CLICK_FOCUS(Tmp_win) && Tmp_win == Scr.Focus &&
1681 do_accept_input_focus(Tmp_win))
1683 /* We have to refresh the focus window here in case we left the focused
1684 * fvwm window. Motif apps may lose the input focus otherwise. But do not
1685 * try to refresh the focus of applications that want to handle it
1686 * themselves. */
1687 FOCUS_SET(Tmp_win->w);
1689 if (Scr.ColormapFocus == COLORMAP_FOLLOWS_MOUSE)
1691 if((!IS_ICONIFIED(Tmp_win))&&(Event.xany.window == Tmp_win->w))
1692 InstallWindowColormaps(Tmp_win);
1693 else
1694 InstallWindowColormaps(NULL);
1697 /* We get an EnterNotify with mode == UnGrab when fvwm releases
1698 the grab held during iconification. We have to ignore this,
1699 or icon title will be initially raised. */
1700 if (IS_ICONIFIED(Tmp_win) && (ewp->mode == NotifyNormal))
1702 SET_ICON_ENTERED(Tmp_win,1);
1703 DrawIconWindow(Tmp_win);
1706 return;
1710 /***********************************************************************
1712 * Procedure:
1713 * HandleLeaveNotify - LeaveNotify event handler
1715 ************************************************************************/
1716 void HandleLeaveNotify(void)
1718 DBUG("HandleLeaveNotify","Routine Entered");
1720 /* Ignore LeaveNotify events while a window is resized or moved as a wire
1721 * frame; otherwise the window list may be screwed up. */
1722 if (Scr.flags.is_wire_frame_displayed)
1723 return;
1725 /* CDE-like behaviour of raising the icon title if the icon
1726 gets the focus (in particular if the cursor is over the icon) */
1727 if (Tmp_win && IS_ICONIFIED(Tmp_win))
1729 SET_ICON_ENTERED(Tmp_win,0);
1730 DrawIconWindow (Tmp_win);
1733 /* If we leave the root window, then we're really moving
1734 * another screen on a multiple screen display, and we
1735 * need to de-focus and unhighlight to make sure that we
1736 * don't end up with more than one highlighted window at a time */
1737 if(Event.xcrossing.window == Scr.Root
1738 /* domivogt (16-May-2000): added this test because somehow fvwm sometimes
1739 * gets a LeaveNotify on the root window although it is single screen. */
1740 && Scr.NumberOfScreens > 1)
1742 if(Event.xcrossing.mode == NotifyNormal)
1744 if (Event.xcrossing.detail != NotifyInferior)
1746 Scr.flags.is_pointer_on_this_screen = 0;
1747 Scr.LastScreenFocus = Scr.Focus;
1748 if (Scr.Focus != NULL)
1750 DeleteFocus(1);
1752 if (Scr.Hilite != NULL)
1753 DrawDecorations(Scr.Hilite, DRAW_ALL, False, True, None);
1757 else
1759 /* handle a subwindow cmap */
1760 LeaveSubWindowColormap(Event.xany.window);
1766 /***********************************************************************
1768 * Procedure:
1769 * HandleConfigureRequest - ConfigureRequest event handler
1771 ************************************************************************/
1772 void HandleConfigureRequest(void)
1774 rectangle new_g;
1775 int dx;
1776 int dy;
1777 int dw;
1778 int dh;
1779 int constr_w;
1780 int constr_h;
1781 int oldnew_w;
1782 int oldnew_h;
1783 XWindowChanges xwc;
1784 unsigned long xwcm;
1785 XConfigureRequestEvent *cre = &Event.xconfigurerequest;
1786 Bool do_send_event = False;
1788 DBUG("HandleConfigureRequest","Routine Entered");
1791 * Event.xany.window is Event.xconfigurerequest.parent, so Tmp_win will
1792 * be wrong
1794 Event.xany.window = cre->window; /* mash parent field */
1795 if (XFindContext (dpy, cre->window, FvwmContext, (caddr_t *) &Tmp_win) ==
1796 XCNOENT)
1797 Tmp_win = NULL;
1799 #define EXPERIMENTAL_ANTI_RACE_CONDITION_CODE
1800 #ifdef EXPERIMENTAL_ANTI_RACE_CONDITION_CODE
1801 /* merge all pending ConfigureRequests for the window into a single event */
1802 if (Tmp_win)
1804 XEvent e;
1805 XConfigureRequestEvent *ecre;
1807 /* free some CPU */
1808 usleep(1);
1809 while (XCheckTypedWindowEvent(dpy, cre->window, ConfigureRequest, &e))
1811 unsigned long vma;
1812 unsigned long vmo;
1813 const unsigned long xm = CWX | CWWidth;
1814 const unsigned long ym = CWY | CWHeight;
1816 ecre = &e.xconfigurerequest;
1817 vma = cre->value_mask & ecre->value_mask;
1818 vmo = cre->value_mask | ecre->value_mask;
1819 if (((vma & xm) == 0 && (vmo & xm) == xm) ||
1820 ((vma & ym) == 0 && (vmo & ym) == ym))
1822 /* can't merge events since location of window might get screwed up */
1823 XPutBackEvent(dpy, &e);
1824 break;
1826 if (ecre->value_mask & CWX)
1828 cre->value_mask |= CWX;
1829 cre->x = ecre->x;
1831 if (ecre->value_mask & CWY)
1833 cre->value_mask |= CWY;
1834 cre->y = ecre->y;
1836 if (ecre->value_mask & CWWidth)
1838 cre->value_mask |= CWWidth;
1839 cre->width = ecre->width;
1841 if (ecre->value_mask & CWHeight)
1843 cre->value_mask |= CWHeight;
1844 cre->height = ecre->height;
1846 if (ecre->value_mask & CWBorderWidth)
1848 cre->value_mask |= CWBorderWidth;
1849 cre->border_width = ecre->border_width;
1851 if (ecre->value_mask & CWStackMode)
1853 cre->value_mask &= !CWStackMode;
1854 cre->value_mask |= (ecre->value_mask & CWStackMode);
1855 cre->above = ecre->above;
1856 cre->detail = ecre->detail;
1858 } /* while */
1859 } /* if */
1860 #endif
1863 * According to the July 27, 1988 ICCCM draft, we should ignore size and
1864 * position fields in the WM_NORMAL_HINTS property when we map a window.
1865 * Instead, we'll read the current geometry. Therefore, we should respond
1866 * to configuration requests for windows which have never been mapped.
1868 if (!Tmp_win || cre->window == Tmp_win->icon_w ||
1869 cre->window == Tmp_win->icon_pixmap_w)
1871 xwcm = cre->value_mask &
1872 (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
1873 xwc.x = cre->x;
1874 xwc.y = cre->y;
1875 if((Tmp_win)&&((Tmp_win->icon_pixmap_w == cre->window)))
1877 Tmp_win->icon_p_height = cre->height+ cre->border_width +
1878 cre->border_width;
1880 else if((Tmp_win)&&((Tmp_win->icon_w == cre->window)))
1882 Tmp_win->icon_xl_loc = cre->x;
1883 Tmp_win->icon_g.x = cre->x +
1884 (Tmp_win->icon_g.width - Tmp_win->icon_p_width)/2;
1885 Tmp_win->icon_g.y = cre->y - Tmp_win->icon_p_height;
1886 if(!IS_ICON_UNMAPPED(Tmp_win))
1887 BroadcastPacket(M_ICON_LOCATION, 7,
1888 Tmp_win->w, Tmp_win->frame,
1889 (unsigned long)Tmp_win,
1890 Tmp_win->icon_g.x, Tmp_win->icon_g.y,
1891 Tmp_win->icon_p_width,
1892 Tmp_win->icon_g.height + Tmp_win->icon_p_height);
1894 xwc.width = cre->width;
1895 xwc.height = cre->height;
1896 xwc.border_width = cre->border_width;
1898 XConfigureWindow(dpy, Event.xany.window, xwcm, &xwc);
1900 if(Tmp_win)
1902 if (cre->window != Tmp_win->icon_pixmap_w &&
1903 Tmp_win->icon_pixmap_w != None)
1905 xwc.x = Tmp_win->icon_g.x;
1906 xwc.y = Tmp_win->icon_g.y - Tmp_win->icon_p_height;
1907 xwcm = cre->value_mask & (CWX | CWY);
1908 XConfigureWindow(dpy, Tmp_win->icon_pixmap_w, xwcm, &xwc);
1910 if(Tmp_win->icon_w != None)
1912 xwc.x = Tmp_win->icon_g.x;
1913 xwc.y = Tmp_win->icon_g.y;
1914 xwcm = cre->value_mask & (CWX | CWY);
1915 XConfigureWindow(dpy, Tmp_win->icon_w, xwcm, &xwc);
1918 if (!Tmp_win)
1919 return;
1922 #ifdef SHAPE
1923 if (ShapesSupported)
1925 int xws, yws, xbs, ybs;
1926 unsigned wws, hws, wbs, hbs;
1927 int boundingShaped, clipShaped;
1929 if (XShapeQueryExtents(dpy, Tmp_win->w,&boundingShaped, &xws, &yws, &wws,
1930 &hws,&clipShaped, &xbs, &ybs, &wbs, &hbs))
1932 Tmp_win->wShaped = boundingShaped;
1934 else
1936 Tmp_win->wShaped = 0;
1939 #endif /* SHAPE */
1941 if (cre->window == Tmp_win->w)
1943 #if 0
1944 fprintf(stderr, "cre: %d(%d) %d(%d) %d(%d)x%d(%d)\n",
1945 cre->x, (int)(cre->value_mask & CWX),
1946 cre->y, (int)(cre->value_mask & CWY),
1947 cre->width, (int)(cre->value_mask & CWWidth),
1948 cre->height, (int)(cre->value_mask & CWHeight));
1949 #endif
1950 /* Don't modify frame_XXX fields before calling SetupWindow! */
1951 dx = 0;
1952 dy = 0;
1953 dw = 0;
1954 dh = 0;
1956 /* for restoring */
1957 if (cre->value_mask & CWBorderWidth)
1959 Tmp_win->old_bw = cre->border_width;
1961 /* override even if border change */
1963 if (cre->value_mask & CWX)
1964 dx = cre->x - Tmp_win->frame_g.x - Tmp_win->boundary_width;
1965 if (cre->value_mask & CWY)
1966 dy = cre->y - Tmp_win->frame_g.y - Tmp_win->boundary_width -
1967 Tmp_win->title_g.height;
1968 if (cre->value_mask & CWWidth)
1969 dw = cre->width - (Tmp_win->frame_g.width - 2 * Tmp_win->boundary_width);
1971 if (cre->value_mask & CWHeight)
1973 if (cre->height < (WINDOW_FREAKED_OUT_HEIGHT - Tmp_win->title_g.height -
1974 2 * Tmp_win->boundary_width))
1976 dh = cre->height - (Tmp_win->frame_g.height -
1977 2 * Tmp_win->boundary_width -
1978 Tmp_win->title_g.height);
1980 else
1982 /* patch to ignore height changes to astronomically large windows
1983 * (needed for XEmacs 20.4); don't care if the window is shaded here -
1984 * we won't use 'height' in this case anyway */
1985 /* inform the buggy app about the size that *we* want */
1986 do_send_event = True;
1991 * SetupWindow (x,y) are the location of the upper-left outer corner and
1992 * are passed directly to XMoveResizeWindow (frame). The (width,height)
1993 * are the inner size of the frame. The inner width is the same as the
1994 * requested client window width; the inner height is the same as the
1995 * requested client window height plus any title bar slop.
1997 new_g = Tmp_win->frame_g;
1998 if (IS_SHADED(Tmp_win))
1999 new_g.height = Tmp_win->normal_g.height;
2000 oldnew_w = new_g.width + dw;
2001 oldnew_h = new_g.height + dh;
2002 constr_w = oldnew_w;
2003 constr_h = oldnew_h;
2004 constrain_size(
2005 Tmp_win, (unsigned int *)&constr_w, (unsigned int *)&constr_h, 0, 0,
2006 False);
2007 dw += (constr_w - oldnew_w);
2008 dh += (constr_h - oldnew_h);
2009 if (dx && dw)
2011 new_g.x = Tmp_win->frame_g.x + dx;
2012 new_g.width = Tmp_win->frame_g.width + dw;
2014 else if (dx && !dw)
2016 new_g.x = Tmp_win->frame_g.x + dx;
2018 else if (!dx && dw)
2020 gravity_resize(Tmp_win->hints.win_gravity, &new_g, dw, 0);
2022 if (dy && dh)
2024 new_g.y = Tmp_win->frame_g.y + dy;
2025 new_g.height = Tmp_win->frame_g.height + dh;
2027 else if (dy && !dh)
2029 new_g.y = Tmp_win->frame_g.y + dy;
2031 else if (!dy && dh)
2033 gravity_resize(Tmp_win->hints.win_gravity, &new_g, 0, dh);
2036 /* dont allow clients to resize maximized windows */
2037 if (!IS_MAXIMIZED(Tmp_win) || (!dw && !dh))
2039 if (IS_SHADED(Tmp_win))
2040 get_shaded_geometry(Tmp_win, &new_g, &new_g);
2041 SetupFrame(
2042 Tmp_win, new_g.x, new_g.y, new_g.width, new_g.height, False);
2044 /* make sure the window structure has the new position */
2045 update_absolute_geometry(Tmp_win);
2046 maximize_adjust_offset(Tmp_win);
2047 GNOME_SetWinArea(Tmp_win);
2050 /* Stacking order change requested... */
2051 /* Handle this *after* geometry changes, since we need the new
2052 geometry in occlusion calculations */
2053 if ( (cre->value_mask & CWStackMode) && !DO_IGNORE_RESTACK(Tmp_win) )
2055 FvwmWindow *otherwin = NULL;
2057 if (cre->value_mask & CWSibling)
2059 if (XFindContext (dpy, cre->above, FvwmContext,
2060 (caddr_t *) &otherwin) == XCNOENT)
2062 otherwin = NULL;
2066 if ((cre->detail != Above) && (cre->detail != Below))
2068 HandleUnusualStackmodes (cre->detail, Tmp_win, cre->window,
2069 otherwin, cre->above);
2071 /* only allow clients to restack windows within their layer */
2072 else if (!otherwin || compare_window_layers(otherwin, Tmp_win) != 0)
2074 switch (cre->detail)
2076 case Above:
2077 RaiseWindow (Tmp_win);
2078 break;
2079 case Below:
2080 LowerWindow (Tmp_win);
2081 break;
2084 else
2086 xwc.sibling = otherwin->frame;
2087 xwc.stack_mode = cre->detail;
2088 xwcm = CWSibling | CWStackMode;
2089 XConfigureWindow (dpy, Tmp_win->frame, xwcm, &xwc);
2091 /* Maintain the condition that icon windows are stacked
2092 immediately below their frame */
2093 /* 1. for Tmp_win */
2094 xwc.sibling = Tmp_win->frame;
2095 xwc.stack_mode = Below;
2096 xwcm = CWSibling | CWStackMode;
2097 if (Tmp_win->icon_w != None)
2099 XConfigureWindow(dpy, Tmp_win->icon_w, xwcm, &xwc);
2101 if (Tmp_win->icon_pixmap_w != None)
2103 XConfigureWindow(dpy, Tmp_win->icon_pixmap_w, xwcm, &xwc);
2106 /* 2. for otherwin */
2107 if (cre->detail == Below)
2109 xwc.sibling = otherwin->frame;
2110 xwc.stack_mode = Below;
2111 xwcm = CWSibling | CWStackMode;
2112 if (otherwin->icon_w != None)
2114 XConfigureWindow(dpy, otherwin->icon_w, xwcm, &xwc);
2116 if (otherwin->icon_pixmap_w != None)
2118 XConfigureWindow(dpy, otherwin->icon_pixmap_w, xwcm, &xwc);
2122 /* Maintain the stacking order ring */
2123 if (cre->detail == Above)
2125 remove_window_from_stack_ring(Tmp_win);
2126 add_window_to_stack_ring_after(
2127 Tmp_win, get_prev_window_in_stack_ring(otherwin));
2129 else /* cre->detail == Below */
2131 remove_window_from_stack_ring(Tmp_win);
2132 add_window_to_stack_ring_after(Tmp_win, otherwin);
2136 Let the modules know that Tmp_win changed its place
2137 in the stacking order
2139 BroadcastRestackThisWindow(Tmp_win);
2143 #if 1
2144 /* This causes some ddd windows not to be drawn properly. Reverted back to
2145 * the old method in SetupFrame. */
2146 /* domivogt (15-Oct-1999): enabled this to work around buggy apps that
2147 * ask for a nonsense height and expect that they really get it. */
2148 if (do_send_event)
2150 SendConfigureNotify(
2151 Tmp_win, Tmp_win->frame_g.x, Tmp_win->frame_g.y,
2152 new_g.width, new_g.height, cre->border_width, True);
2153 XSync(dpy,0);
2155 #endif
2158 /***********************************************************************
2160 * Procedure:
2161 * SendConfigureNotify - inform a client window of its geometry.
2163 * The input (frame) geometry will be translated to client geometry
2164 * before sending.
2166 ************************************************************************/
2167 void SendConfigureNotify(
2168 FvwmWindow *tmp_win, int x, int y, unsigned int w, unsigned int h, int bw,
2169 Bool send_for_frame_too)
2171 if (!tmp_win || IS_SHADED(tmp_win))
2172 return;
2174 XEvent client_event;
2176 client_event.type = ConfigureNotify;
2177 client_event.xconfigure.display = dpy;
2178 client_event.xconfigure.event = tmp_win->w;
2179 client_event.xconfigure.window = tmp_win->w;
2180 client_event.xconfigure.x = x + tmp_win->boundary_width;
2181 client_event.xconfigure.y = y + tmp_win->boundary_width +
2182 ((HAS_BOTTOM_TITLE(tmp_win)) ? 0 : tmp_win->title_g.height);
2183 client_event.xconfigure.width = w - 2 * tmp_win->boundary_width;
2184 client_event.xconfigure.height = h -
2185 2 * tmp_win->boundary_width - tmp_win->title_g.height;
2186 client_event.xconfigure.border_width = bw;
2187 client_event.xconfigure.above = tmp_win->frame;
2188 client_event.xconfigure.override_redirect = False;
2189 XSendEvent(dpy, tmp_win->w, False, StructureNotifyMask, &client_event);
2190 if (send_for_frame_too)
2192 /* This is for buggy tk, which waits for the real ConfigureNotify
2193 * on frame instead of the synthetic one on w. The geometry data
2194 * in the event will not be correct for the frame, but tk doesn't
2195 * look at that data anyway. */
2196 client_event.xconfigure.event = tmp_win->frame;
2197 client_event.xconfigure.window = tmp_win->frame;
2198 XSendEvent(dpy, tmp_win->frame, False,StructureNotifyMask,&client_event);
2203 /***********************************************************************
2205 * Procedure:
2206 * HandleShapeNotify - shape notification event handler
2208 ***********************************************************************/
2209 #ifdef SHAPE
2210 void HandleShapeNotify (void)
2212 DBUG("HandleShapeNotify","Routine Entered");
2214 if (ShapesSupported)
2216 XShapeEvent *sev = (XShapeEvent *) &Event;
2218 if (!Tmp_win)
2219 return;
2220 if (sev->kind != ShapeBounding)
2221 return;
2222 Tmp_win->wShaped = sev->shaped;
2223 SetShape(Tmp_win,Tmp_win->frame_g.width);
2226 #endif /* SHAPE*/
2228 /***********************************************************************
2230 * Procedure:
2231 * HandleVisibilityNotify - record fully visible windows for
2232 * use in the RaiseLower function and the OnTop type windows.
2234 ************************************************************************/
2235 void HandleVisibilityNotify(void)
2237 XVisibilityEvent *vevent = (XVisibilityEvent *) &Event;
2239 DBUG("HandleVisibilityNotify","Routine Entered");
2241 if(Tmp_win && Tmp_win->frame == last_event_window)
2243 if(vevent->state == VisibilityUnobscured)
2245 SET_FULLY_VISIBLE(Tmp_win, 1);
2246 SET_PARTIALLY_VISIBLE(Tmp_win, 1);
2248 else if (vevent->state == VisibilityPartiallyObscured)
2250 SET_FULLY_VISIBLE(Tmp_win, 0);
2251 SET_PARTIALLY_VISIBLE(Tmp_win, 1);
2253 else
2255 SET_FULLY_VISIBLE(Tmp_win, 0);
2256 SET_PARTIALLY_VISIBLE(Tmp_win, 0);
2262 /***************************************************************************
2264 * Waits for next X or module event, fires off startup routines when startup
2265 * modules have finished or after a timeout if the user has specified a
2266 * command line module that doesn't quit or gets stuck.
2268 ****************************************************************************/
2269 fd_set init_fdset;
2271 int My_XNextEvent(Display *dpy, XEvent *event)
2273 extern fd_set_size_t fd_width;
2274 extern int x_fd;
2275 fd_set in_fdset, out_fdset;
2276 Window targetWindow;
2277 int num_fd;
2278 int i;
2279 static struct timeval timeout;
2280 static struct timeval *timeoutP = &timeout;
2282 DBUG("My_XNextEvent","Routine Entered");
2284 /* include this next bit if HandleModuleInput() gets called anywhere else
2285 * with queueing turned on. Because this routine is the only place that
2286 * queuing is on _and_ ExecuteCommandQueue is always called immediately after
2287 * it is impossible for there to be anything in the queue at this point */
2288 #if 0
2289 /* execute any commands queued up */
2290 DBUG("My_XNextEvent", "executing module comand queue");
2291 ExecuteCommandQueue()
2292 #endif
2294 /* check for any X events already queued up.
2295 * Side effect: this does an XFlush if no events are queued
2296 * Make sure nothing between here and the select causes further X
2297 * requests to be sent or the select may block even though there are
2298 * events in the queue */
2299 if(XPending(dpy)) {
2300 DBUG("My_XNextEvent","taking care of queued up events & returning (1)");
2301 XNextEvent(dpy,event);
2302 StashEventTime(event);
2303 return 1;
2306 /* The SIGCHLD signal is sent every time one of our child processes
2307 * dies, and the SIGCHLD handler now reaps them automatically. We
2308 * should therefore never see a zombie */
2309 #if 0
2310 DBUG("My_XNextEvent","no X events waiting - about to reap children");
2311 /* Zap all those zombies! */
2312 /* If we get to here, then there are no X events waiting to be processed.
2313 * Just take a moment to check for dead children. */
2314 ReapChildren();
2315 #endif
2317 /* check for termination of all startup modules */
2318 if (fFvwmInStartup) {
2319 for(i=0;i<npipes;i++)
2320 if (FD_ISSET(i, &init_fdset))
2321 break;
2322 if (i == npipes || writePipes[i+1] == 0)
2324 DBUG("My_XNextEvent", "Starting up after command lines modules\n");
2325 timeoutP = NULL; /* set an infinite timeout to stop ticking */
2326 StartupStuff(); /* This may cause X requests to be sent */
2327 return 0; /* so return without select()ing */
2331 /* Some signals can interrupt us while we wait for any action
2332 * on our descriptors. While some of these signals may be asking
2333 * fvwm to die, some might be harmless. Harmless interruptions
2334 * mean we have to start waiting all over again ... */
2337 /* The timeouts become undefined whenever the select returns, and so
2338 * we have to reinitialise them */
2339 timeout.tv_sec = 42;
2340 timeout.tv_usec = 0;
2342 FD_ZERO(&in_fdset);
2343 FD_ZERO(&out_fdset);
2344 FD_SET(x_fd, &in_fdset);
2346 /* nothing is done here if fvwm was compiled without session support */
2347 if (sm_fd >= 0)
2348 FD_SET(sm_fd, &in_fdset);
2350 for(i=0; i<npipes; i++) {
2351 if(readPipes[i]>=0)
2352 FD_SET(readPipes[i], &in_fdset);
2353 if(pipeQueue[i]!= NULL)
2354 FD_SET(writePipes[i], &out_fdset);
2357 DBUG("My_XNextEvent","waiting for module input/output");
2358 num_fd = fvwmSelect(fd_width, &in_fdset, &out_fdset, 0, timeoutP);
2360 /* Express route out of FVWM ... */
2361 if ( isTerminated ) return 0;
2363 while (num_fd < 0);
2365 if (num_fd > 0) {
2367 /* Check for module input. */
2368 for (i=0; i<npipes; i++) {
2369 if ((readPipes[i] >= 0) && FD_ISSET(readPipes[i], &in_fdset)) {
2370 if (read(readPipes[i], &targetWindow, sizeof(Window)) > 0) {
2371 DBUG("My_XNextEvent","calling HandleModuleInput");
2372 /* Add one module message to the queue */
2373 HandleModuleInput(targetWindow, i, NULL, True);
2374 } else {
2375 DBUG("My_XNextEvent","calling KillModule");
2376 KillModule(i);
2379 if ((writePipes[i] >= 0) && FD_ISSET(writePipes[i], &out_fdset)) {
2380 DBUG("My_XNextEvent","calling FlushMessageQueue");
2381 FlushMessageQueue(i);
2385 /* execute any commands queued up */
2386 DBUG("My_XNextEvent", "executing module comand queue");
2387 ExecuteCommandQueue();
2389 /* nothing is done here if fvwm was compiled without session support */
2390 if ((sm_fd >= 0) && (FD_ISSET(sm_fd, &in_fdset)))
2391 ProcessICEMsgs();
2393 } else {
2394 /* select has timed out, things must have calmed down so let's decorate */
2395 if (fFvwmInStartup) {
2396 fvwm_msg(ERR, "My_XNextEvent",
2397 "Some command line modules have not quit, "
2398 "Starting up after timeout.\n");
2399 StartupStuff();
2400 timeoutP = NULL; /* set an infinite timeout to stop ticking */
2401 reset_style_changes();
2402 Scr.flags.do_need_window_update = 0;
2406 /* check for X events again, rather than return 0 and get called again */
2407 if(XPending(dpy)) {
2408 DBUG("My_XNextEvent","taking care of queued up events & returning (2)");
2409 XNextEvent(dpy,event);
2410 StashEventTime(event);
2411 return 1;
2414 DBUG("My_XNextEvent","leaving My_XNextEvent");
2415 return 0;
2419 ** Procedure:
2420 ** InitEventHandlerJumpTable
2422 void InitEventHandlerJumpTable(void)
2424 int i;
2426 for (i=0; i<LASTEvent; i++)
2428 EventHandlerJumpTable[i] = NULL;
2430 EventHandlerJumpTable[Expose] = HandleExpose;
2431 EventHandlerJumpTable[DestroyNotify] = HandleDestroyNotify;
2432 EventHandlerJumpTable[MapRequest] = HandleMapRequest;
2433 EventHandlerJumpTable[MapNotify] = HandleMapNotify;
2434 EventHandlerJumpTable[UnmapNotify] = HandleUnmapNotify;
2435 EventHandlerJumpTable[ButtonPress] = HandleButtonPress;
2436 EventHandlerJumpTable[EnterNotify] = HandleEnterNotify;
2437 EventHandlerJumpTable[LeaveNotify] = HandleLeaveNotify;
2438 EventHandlerJumpTable[FocusIn] = HandleFocusIn;
2439 EventHandlerJumpTable[ConfigureRequest] = HandleConfigureRequest;
2440 EventHandlerJumpTable[ClientMessage] = HandleClientMessage;
2441 EventHandlerJumpTable[PropertyNotify] = HandlePropertyNotify;
2442 EventHandlerJumpTable[KeyPress] = HandleKeyPress;
2443 EventHandlerJumpTable[VisibilityNotify] = HandleVisibilityNotify;
2444 EventHandlerJumpTable[ColormapNotify] = HandleColormapNotify;
2445 #ifdef SHAPE
2446 if (ShapesSupported)
2447 EventHandlerJumpTable[ShapeEventBase+ShapeNotify] = HandleShapeNotify;
2448 #endif /* SHAPE */
2449 EventHandlerJumpTable[SelectionClear] = HandleSelectionClear;
2450 EventHandlerJumpTable[SelectionRequest] = HandleSelectionRequest;
2451 STROKE_CODE(EventHandlerJumpTable[ButtonRelease] = HandleButtonRelease);
2452 STROKE_CODE(EventHandlerJumpTable[MotionNotify] = HandleMotionNotify);
2453 #ifdef MOUSE_DROPPINGS
2454 STROKE_CODE(stroke_init(dpy,DefaultRootWindow(dpy)));
2455 #else /* no MOUSE_DROPPINGS */
2456 STROKE_CODE(stroke_init());
2457 #endif /* MOUSE_DROPPINGS */
2460 /***********************************************************************
2462 * Procedure:
2463 * DispatchEvent - handle a single X event stored in global var Event
2465 ************************************************************************/
2466 void DispatchEvent(Bool preserve_Tmp_win)
2468 Window w = Event.xany.window;
2469 FvwmWindow *s_Tmp_win = NULL;
2471 DBUG("DispatchEvent","Routine Entered");
2473 if (preserve_Tmp_win)
2474 s_Tmp_win = Tmp_win;
2475 StashEventTime(&Event);
2477 XFlush(dpy);
2478 if (XFindContext (dpy, w, FvwmContext, (caddr_t *) &Tmp_win) == XCNOENT)
2480 Tmp_win = NULL;
2482 last_event_type = Event.type;
2483 last_event_window = w;
2485 if (EventHandlerJumpTable[Event.type])
2487 (*EventHandlerJumpTable[Event.type])();
2490 #ifdef C_ALLOCA
2491 /* If we're using the C version of alloca, see if anything needs to be
2492 * freed up.
2494 alloca(0);
2495 #endif
2497 if (preserve_Tmp_win)
2498 Tmp_win = s_Tmp_win;
2499 DBUG("DispatchEvent","Leaving Routine");
2500 return;
2504 /***********************************************************************
2506 * Procedure:
2507 * HandleEvents - handle X events
2509 ************************************************************************/
2510 void HandleEvents(void)
2512 DBUG("HandleEvents","Routine Entered");
2513 STROKE_CODE(send_motion = FALSE);
2514 while ( !isTerminated )
2516 last_event_type = 0;
2517 if (Scr.flags.do_need_window_update)
2519 flush_window_updates();
2521 if (Scr.flags.do_need_style_list_update)
2523 simplify_style_list();
2525 if(My_XNextEvent(dpy, &Event))
2527 DispatchEvent(False);
2532 /***********************************************************************
2534 * Procedure:
2535 * Find the Fvwm context for the Event.
2537 ************************************************************************/
2538 int GetContext(FvwmWindow *t, XEvent *e, Window *w)
2540 int Context,i;
2542 Context = C_NO_CONTEXT;
2543 if (e->type == KeyPress && e->xkey.window == Scr.Root &&
2544 e->xkey.subwindow != None)
2546 /* Translate root coordinates into subwindow coordinates. Necessary for
2547 * key bindings that work over unfocused windows. */
2548 e->xkey.window = e->xkey.subwindow;
2549 XTranslateCoordinates(
2550 dpy, Scr.Root, e->xkey.subwindow, e->xkey.x, e->xkey.y, &(e->xkey.x),
2551 &(e->xkey.y), &(e->xkey.subwindow));
2552 XFindContext(dpy, e->xkey.window, FvwmContext, (caddr_t *) &t);
2553 Tmp_win = t;
2555 if (e->type == ButtonPress && t && e->xkey.window == t->frame &&
2556 e->xkey.subwindow != None)
2558 /* Translate frame coordinates into subwindow coordinates. */
2559 e->xkey.window = e->xkey.subwindow;
2560 XTranslateCoordinates(
2561 dpy, t->frame, e->xkey.subwindow, e->xkey.x, e->xkey.y, &(e->xkey.x),
2562 &(e->xkey.y), &(e->xkey.subwindow));
2563 if (e->xkey.window == t->Parent)
2565 e->xkey.window = e->xkey.subwindow;
2566 XTranslateCoordinates(
2567 dpy, t->Parent, e->xkey.subwindow, e->xkey.x, e->xkey.y, &(e->xkey.x),
2568 &(e->xkey.y), &(e->xkey.subwindow));
2571 if(!t)
2572 return C_ROOT;
2574 if (e->type == KeyPress && e->xkey.window == t->frame &&
2575 e->xkey.subwindow == t->decor_w)
2577 /* We can't get keyboard events on the decor_w directly because it is a
2578 * sibling of the parent window which gets all keyboard input. So we have
2579 * to grab keys on the frame and then translate the coordinates to find out
2580 * in which subwindow of the decor_w the event occured. */
2581 e->xkey.window = e->xkey.subwindow;
2582 XTranslateCoordinates(dpy, t->frame, t->decor_w, e->xkey.x, e->xkey.y,
2583 &JunkX, &JunkY, &(e->xkey.subwindow));
2585 *w= e->xany.window;
2587 if (*w == Scr.NoFocusWin)
2588 return C_ROOT;
2589 if (e->type == KeyPress && e->xkey.window == t->frame &&
2590 e->xkey.subwindow == t->decor_w)
2592 /* We can't get keyboard events on the decor_w directly because it is a
2593 * sibling of the parent window which gets all keyboard input. So we have
2594 * to grab keys on the frame and then translate the coordinates to find out
2595 * in which subwindow of the decor_w the event occured. */
2596 e->xkey.window = e->xkey.subwindow;
2597 XTranslateCoordinates(dpy, t->frame, t->decor_w, e->xkey.x, e->xkey.y,
2598 &JunkX, &JunkY, &(e->xkey.subwindow));
2600 *w= e->xany.window;
2602 if (*w == Scr.NoFocusWin)
2603 return C_ROOT;
2604 if (e->xkey.subwindow != None && e->xany.window != t->w)
2605 *w = e->xkey.subwindow;
2606 if (*w == Scr.Root)
2607 return C_ROOT;
2608 if (t)
2610 if (*w == t->title_w)
2611 Context = C_TITLE;
2612 else if (*w == t->w || *w == t->Parent || *w == t->frame)
2613 Context = C_WINDOW;
2614 else if (*w == t->icon_w || *w == t->icon_pixmap_w)
2615 Context = C_ICON;
2616 else if (*w == t->decor_w)
2617 Context = C_SIDEBAR;
2618 else
2620 for(i=0;i<4;i++)
2622 if(*w == t->corners[i])
2624 Context = C_FRAME;
2625 break;
2627 if(*w == t->sides[i])
2629 Context = C_SIDEBAR;
2630 break;
2633 if (i < 4)
2634 Button = i;
2635 else
2637 for (i = 0; i < NUMBER_OF_BUTTONS; i++)
2639 if (*w == t->button_w[i])
2641 if ((!(i & 1) && i / 2 < Scr.nr_left_buttons) ||
2642 ( (i & 1) && i / 2 < Scr.nr_right_buttons))
2644 Context = (1 << i) * C_L1;
2645 Button = i;
2646 break;
2651 } /* else */
2652 } /* if (t) */
2653 return Context;
2657 /**************************************************************************
2659 * Removes expose events for a specific window from the queue
2661 *************************************************************************/
2662 int flush_expose (Window w)
2664 XEvent dummy;
2665 int i=0;
2667 while (XCheckTypedWindowEvent (dpy, w, Expose, &dummy))
2668 i++;
2669 return i;
2672 /* same as above, but merges the expose rectangles into a single big one */
2673 int flush_accumulate_expose(Window w, XEvent *e)
2675 XEvent dummy;
2676 int i = 0;
2677 int x1 = e->xexpose.x;
2678 int y1 = e->xexpose.y;
2679 int x2 = x1 + e->xexpose.width;
2680 int y2 = x2 + e->xexpose.height;
2682 while (XCheckTypedWindowEvent(dpy, w, Expose, &dummy))
2684 x1 = min(x1, dummy.xexpose.x);
2685 y1 = min(y1, dummy.xexpose.y);
2686 x2 = max(x2, dummy.xexpose.x + dummy.xexpose.width);
2687 y2 = max(y2, dummy.xexpose.y + dummy.xexpose.height);
2688 i++;
2690 e->xexpose.x = x1;
2691 e->xexpose.y = y1;
2692 e->xexpose.width = x2 - x1;
2693 e->xexpose.height = y2 - y1;
2695 return i;
2699 /**************************************************************************
2701 * Removes all expose events from the queue and does the necessary redraws
2703 *************************************************************************/
2704 void handle_all_expose(void)
2706 XEvent old_event;
2708 memcpy(&old_event, &Event, sizeof(XEvent));
2709 XPending(dpy);
2710 while (XCheckMaskEvent(dpy, ExposureMask, &Event))
2712 DispatchEvent(True);
2714 memcpy(&Event, &old_event, sizeof(XEvent));
2716 return;
2720 /****************************************************************************
2722 * Records the time of the last processed event. Used in XSetInputFocus
2724 ****************************************************************************/
2725 Bool StashEventTime (XEvent *ev)
2727 Time NewTimestamp = CurrentTime;
2729 switch (ev->type)
2731 case KeyPress:
2732 case KeyRelease:
2733 NewTimestamp = ev->xkey.time;
2734 break;
2735 case ButtonPress:
2736 case ButtonRelease:
2737 NewTimestamp = ev->xbutton.time;
2738 break;
2739 case MotionNotify:
2740 NewTimestamp = ev->xmotion.time;
2741 break;
2742 case EnterNotify:
2743 case LeaveNotify:
2744 NewTimestamp = ev->xcrossing.time;
2745 break;
2746 case PropertyNotify:
2747 NewTimestamp = ev->xproperty.time;
2748 break;
2749 case SelectionClear:
2750 NewTimestamp = ev->xselectionclear.time;
2751 break;
2752 case SelectionRequest:
2753 NewTimestamp = ev->xselectionrequest.time;
2754 break;
2755 case SelectionNotify:
2756 NewTimestamp = ev->xselection.time;
2757 break;
2758 default:
2759 return False;
2761 /* Only update if the new timestamp is later than the old one, or
2762 * if the new one is from a time at least 30 seconds earlier than the
2763 * old one (in which case the system clock may have changed) */
2764 if (NewTimestamp > lastTimestamp ||
2765 lastTimestamp - NewTimestamp > CLOCK_SKEW_MS)
2766 lastTimestamp = NewTimestamp;
2767 return True;
2770 /* CoerceEnterNotifyOnCurrentWindow()
2771 * Pretends to get a HandleEnterNotify on the
2772 * window that the pointer currently is in so that
2773 * the focus gets set correctly from the beginning
2774 * Note that this presently only works if the current
2775 * window is not click_to_focus; I think that
2776 * that behaviour is correct and desirable. --11/08/97 gjb */
2777 void CoerceEnterNotifyOnCurrentWindow(void)
2779 extern FvwmWindow *Tmp_win; /* from events.c */
2780 Window child, root;
2781 int root_x, root_y;
2782 int win_x, win_y;
2783 Bool f = XQueryPointer(dpy, Scr.Root, &root,
2784 &child, &root_x, &root_y, &win_x, &win_y, &JunkMask);
2785 if (f && child != None) {
2786 Event.xany.window = child;
2787 if (XFindContext(dpy, child, FvwmContext, (caddr_t *) &Tmp_win) == XCNOENT)
2788 Tmp_win = NULL;
2789 HandleEnterNotify();
2790 Tmp_win = None;
2794 /* This function discards all queued up ButtonPress, ButtonRelease and
2795 * ButtonMotion events. */
2796 int discard_events(long event_mask)
2798 XEvent e;
2799 int count;
2801 XSync(dpy, 0);
2802 for (count = 0; XCheckMaskEvent(dpy, event_mask, &e); count++)
2804 StashEventTime(&e);
2807 return count;
2810 /* Similar function for certain types of PropertyNotify. */
2811 static int flush_property_notify(Atom atom, Window w)
2813 XEvent e;
2814 int count;
2816 XSync(dpy, 0);
2817 for (count = 0; XCheckMaskEvent(dpy, PropertyChangeMask, &e); count++)
2819 if (e.xproperty.atom != atom)
2821 XPutBackEvent(dpy, &e);
2822 break;
2826 return count;
2829 /***************************************************************************
2831 * Wait for all mouse buttons to be released
2832 * This can ease some confusion on the part of the user sometimes
2834 * Discard superflous button events during this wait period.
2836 ***************************************************************************/
2837 void WaitForButtonsUp(Bool do_handle_expose)
2839 unsigned int mask;
2840 long evmask = ButtonPressMask|ButtonReleaseMask|ButtonMotionMask|
2841 KeyPressMask|KeyReleaseMask;
2843 if (do_handle_expose)
2844 evmask |= ExposureMask;
2845 MyXGrabServer(dpy);
2846 XSync(dpy, 0);
2847 mask = DEFAULT_ALL_BUTTONS_MASK;
2848 while (mask & (DEFAULT_ALL_BUTTONS_MASK))
2850 /* handle expose events */
2851 if (XCheckMaskEvent(dpy, evmask, &Event))
2853 switch (Event.type)
2855 case ButtonReleaseMask:
2856 mask = Event.xbutton.state;
2857 break;
2858 case Expose:
2859 DispatchEvent(True);
2860 break;
2861 default:
2862 break;
2865 else
2867 /* although this should never happen, a bit of additional safety does not
2868 * hurt. */
2869 XQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild, &JunkX, &JunkY,
2870 &JunkX, &JunkY, &mask);
2873 XSync(dpy, 0);
2874 MyXUngrabServer(dpy);
2876 return;