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
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 **/
26 /** All Rights Reserved **/
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. **/
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 /***********************************************************************
52 ***********************************************************************/
56 #if HAVE_SYS_BSDTYPES_H
57 #include <sys/bsdtypes.h>
63 #include <sys/types.h>
67 #include "libs/fvwmlib.h"
71 #include "functions.h"
77 #include "libs/Colorset.h"
78 #include "fvwmsignal.h"
80 #include <X11/extensions/shape.h>
82 #include "module_interface.h"
85 #include "colormaps.h"
86 #include "add_window.h"
95 #include "move_resize.h"
99 #endif /* HAVE_STROKE */
102 #define XUrgencyHint (1L << 8)
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];)
122 extern int ShapeEventBase
;
123 void HandleShapeNotify(void);
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.
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 /***********************************************************************
145 * HandleFocusIn - handles focus in events
147 ************************************************************************/
148 void HandleFocusIn(void)
152 Window focus_w
= None
;
153 Window focus_fw
= None
;
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
)
166 w
= Event
.xany
.window
;
167 while(XCheckTypedEvent(dpy
,FocusIn
,&d
))
170 if (d
.xfocus
.detail
!= NotifyPointer
)
180 if (XFindContext (dpy
, w
, FvwmContext
, (caddr_t
*) &Tmp_win
) == XCNOENT
)
187 if (w
!= Scr
.NoFocusWin
)
189 Scr
.UnknownWinFocused
= w
;
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
);
203 InstallWindowColormaps(NULL
);
208 /* Not very useful if no window that fvwm and its modules know about has the
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
;
226 if (Scr
.ColormapFocus
== COLORMAP_FOLLOWS_FOCUS
)
228 if((Scr
.Hilite
)&&(!IS_ICONIFIED(Scr
.Hilite
)))
230 InstallWindowColormaps(Scr
.Hilite
);
234 InstallWindowColormaps(NULL
);
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 /***********************************************************************
261 * HandleKeyPress - key press event handler
263 ************************************************************************/
264 void HandleKeyPress(void)
268 DBUG("HandleKeyPress","Routine Entered");
270 Context
= GetContext(Tmp_win
, &Event
, &PressedW
);
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. */
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
,
285 ButtonWindow
= Tmp_win
;
286 old_execute_function(action
, Tmp_win
, &Event
, Context
, -1, 0, NULL
);
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 /***********************************************************************
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
;
327 unsigned long nitems
, bytesafter
;
333 DBUG("HandlePropertyNotify","Routine Entered");
336 (XGetGeometry(dpy
, Tmp_win
->w
, &JunkRoot
, &JunkX
, &JunkY
,
337 &JunkWidth
, &JunkHeight
, &JunkBW
, &JunkDepth
) == 0))
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
);
357 SET_TRANSIENT(Tmp_win
, 0);
362 flush_property_notify(XA_WM_NAME
, Tmp_win
->w
);
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
||
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
;
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
;
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
;
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
;
401 /* XXX: fallback to original behavior, is it needed ? */
402 if (!XGetWMName(dpy
, Tmp_win
->w
, &text_prop
))
404 free_window_names (Tmp_win
, True
, False
);
405 Tmp_win
->name
= (char *)text_prop
.value
;
406 Tmp_win
->name_list
= NULL
;
409 if (!XGetWMName(dpy
, Tmp_win
->w
, &text_prop
))
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;
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
))
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
);
443 case XA_WM_ICON_NAME
:
444 flush_property_notify(XA_WM_ICON_NAME
, Tmp_win
->w
);
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
||
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
;
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
;
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
;
482 /* XXX: fallback to original behavior, is it needed ? */
483 if (!XGetWMIconName(dpy
, Tmp_win
->w
, &text_prop
))
485 free_window_names (Tmp_win
, False
, True
);
486 Tmp_win
->icon_name
= (char *)text_prop
.value
;
487 Tmp_win
->icon_name_list
= NULL
;
490 if (!XGetWMIconName (dpy
, Tmp_win
->w
, &text_prop
))
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
) >
496 /* limit to prevent hanging X server */
497 Tmp_win
->icon_name
[MAX_ICON_NAME_LEN
] = 0;
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
);
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
)
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
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
)
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
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
);
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
)
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
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
-
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
);
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
))
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
);
645 Tmp_win
, new_g
.x
, new_g
.y
, new_g
.width
, new_g
.height
, False
);
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
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
)
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
);
677 Tmp_win
, new_g
.x
, new_g
.y
, new_g
.width
, new_g
.height
, False
);
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
);
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
);
693 GNOME_SetWinArea(Tmp_win
);
695 BroadcastConfig(M_CONFIGURE_WINDOW
,Tmp_win
);
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
))
714 SetFocusWindow(Tmp_win
, 0);
723 /***********************************************************************
726 * HandleClientMessage - client message event handler
728 ************************************************************************/
729 void HandleClientMessage(void)
733 DBUG("HandleClientMessage","Routine Entered");
735 /* Process GNOME Messages */
736 if (GNOME_ProcessClientMessage(Tmp_win
, &Event
))
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
);
750 old_execute_function("Iconify", Tmp_win
, &button
, C_FRAME
, -1, 0, NULL
);
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]);
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.
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 /***********************************************************************
785 * HandleExpose - expose event handler
787 ***********************************************************************/
788 void HandleExpose(void)
790 if (Event
.xexpose
.count
!= 0)
793 DBUG("HandleExpose","Routine Entered");
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
;
805 draw_parts
= DRAW_BUTTONS
;
807 Tmp_win
, draw_parts
, (Scr
.Hilite
== Tmp_win
), True
, Event
.xany
.window
);
814 /***********************************************************************
817 * HandleDestroyNotify - DestroyNotify event handler
819 ***********************************************************************/
820 void HandleDestroyNotify(void)
822 DBUG("HandleDestroyNotify","Routine Entered");
824 destroy_window(Tmp_win
);
825 GNOME_SetClientList();
831 /***********************************************************************
834 * HandleMapRequest - MapRequest event handler
836 ************************************************************************/
837 void HandleMapRequest(void)
839 DBUG("HandleMapRequest","Routine Entered");
843 /* Just map the damn thing, decorations are added later
844 * in CaptureAllWindows. */
845 XMapWindow (dpy
, Event
.xmaprequest
.window
);
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
)
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
);
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
))
898 if(Tmp_win
->wmhints
&& (Tmp_win
->wmhints
->flags
& StateHint
))
899 state
= Tmp_win
->wmhints
->initial_state
;
903 if(DO_START_ICONIC(Tmp_win
))
906 if(isIconicState
!= DontCareState
)
907 state
= isIconicState
;
916 if (Tmp_win
->Desk
== Scr
.CurrentDesk
)
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
;
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
,
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
;
950 do_grab_focus
= False
;
953 SetFocusWindow(Tmp_win
, 1);
957 /* make sure the old focused window still has grabbed all necessary
961 focus_grab_buttons(Scr
.Focus
, True
);
968 /* nope, this is forbidden by the ICCCM */
969 XMapWindow(dpy
, Tmp_win
->w
);
970 SetMapStateProp(Tmp_win
, NormalState
);
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
);
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
);
993 Iconify(Tmp_win
, 0, 0);
999 MyXUngrabServer(dpy
);
1001 /* If no hints, or currently an icon, just "deiconify" */
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 /***********************************************************************
1048 * HandleMapNotify - MapNotify event handler
1050 ***********************************************************************/
1051 void HandleMapNotify(void)
1053 Bool OnThisPage
= False
;
1055 DBUG("HandleMapNotify","Routine Entered");
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
;
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
)
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
))
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
);
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
))
1118 SetFocusWindow(Tmp_win
, 1);
1121 if((!(HAS_BORDER(Tmp_win
)|HAS_TITLE(Tmp_win
)))&&(Tmp_win
->boundary_width
<2))
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
);
1133 MyXUngrabServer (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 /***********************************************************************
1151 * HandleUnmapNotify - UnmapNotify event handler
1153 ************************************************************************/
1154 void HandleUnmapNotify(void)
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
))
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
1185 Event
.xany
.window
= Event
.xunmap
.window
;
1187 if (XFindContext(dpy
, Event
.xany
.window
,
1188 FvwmContext
, (caddr_t
*)&Tmp_win
) == XCNOENT
)
1195 if (Event
.xunmap
.window
== Tmp_win
->frame
)
1197 SET_DEICONIFY_PENDING(Tmp_win
, 0);
1204 XUnmapWindow(dpy
, Event
.xunmap
.window
);
1205 if(Tmp_win
== Scr
.Hilite
)
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
))
1222 if(XCheckTypedWindowEvent (dpy
, Event
.xunmap
.window
, DestroyNotify
,&dummy
))
1224 destroy_window(Tmp_win
);
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
))
1241 reparented
= XCheckTypedWindowEvent (dpy
, Event
.xunmap
.window
,
1242 ReparentNotify
, &ev
);
1243 SetMapStateProp (Tmp_win
, WithdrawnState
);
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
);
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
);
1275 CoerceEnterNotifyOnCurrentWindow();
1277 GNOME_SetClientList();
1281 /***********************************************************************
1284 * HandleButtonPress - ButtonPress event handler
1286 ***********************************************************************/
1287 void HandleButtonPress(void)
1293 Bool do_regrab_buttons
= False
;
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. */
1305 XAllowEvents(dpy
,ReplayPointer
,CurrentTime
);
1307 UngrabEm(GRAB_PASSIVE
);
1310 if (Event
.xbutton
.subwindow
!= None
&&
1311 (Tmp_win
== None
|| Event
.xany
.window
!= Tmp_win
->w
))
1313 eventw
= Event
.xbutton
.subwindow
;
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. */
1324 XAllowEvents(dpy
,ReplayPointer
,CurrentTime
);
1326 UngrabEm(GRAB_PASSIVE
);
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
)
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
))
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
));
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
);
1386 UngrabEm(GRAB_PASSIVE
);
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
;
1415 XAllowEvents(dpy
,ReplayPointer
,CurrentTime
);
1417 UngrabEm(GRAB_PASSIVE
);
1420 focus_grab_buttons(Tmp_win
, True
);
1421 Scr
.Ungrabbed
= tmp
;
1424 Context
= GetContext(Tmp_win
, &Event
, &PressedW
);
1425 LocalContext
= Context
;
1428 if (Context
== C_TITLE
)
1430 Tmp_win
, DRAW_TITLE
, (Scr
.Hilite
== Tmp_win
), True
, None
);
1431 else if (Context
& (C_LALL
| C_RALL
))
1433 Tmp_win
, DRAW_BUTTONS
, (Scr
.Hilite
== Tmp_win
), True
, PressedW
);
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
,
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
;
1473 XAllowEvents(dpy
,ReplayPointer
,CurrentTime
);
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
;
1491 if (ButtonWindow
&& check_if_fvwm_window_exists(ButtonWindow
))
1493 if (LocalContext
== C_TITLE
)
1495 ButtonWindow
, DRAW_TITLE
, (Scr
.Hilite
== ButtonWindow
), True
, None
);
1496 else if (LocalContext
& (C_LALL
| C_RALL
))
1498 ButtonWindow
, DRAW_BUTTONS
, (Scr
.Hilite
== ButtonWindow
), True
,
1502 ButtonWindow
, DRAW_FRAME
, (Scr
.Hilite
== ButtonWindow
),
1503 HAS_DEPRESSABLE_BORDER(ButtonWindow
), None
);
1505 ButtonWindow
= NULL
;
1506 UngrabEm(GRAB_PASSIVE
);
1510 /***********************************************************************
1513 * HandleButtonRelease - ButtonRelease event handler
1515 ************************************************************************/
1516 void HandleButtonRelease()
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
);
1547 * do gnome buttonpress forwarding if win == root
1549 if (Scr
.Root
== Event
.xany
.window
)
1551 GNOME_ProxyButtonEvent(&Event
);
1557 /***********************************************************************
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 /***********************************************************************
1576 * HandleEnterNotify - EnterNotify event handler
1578 ************************************************************************/
1579 void HandleEnterNotify(void)
1581 XEnterWindowEvent
*ewp
= &Event
.xcrossing
;
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
)
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
)
1601 if((d
.xcrossing
.mode
==NotifyNormal
)&&
1602 (d
.xcrossing
.detail
!=NotifyInferior
))
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);
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
))
1632 if (Scr
.ColormapFocus
== COLORMAP_FOLLOWS_MOUSE
)
1634 InstallWindowColormaps(NULL
);
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
);
1659 /* make sure its for one of our windows */
1662 /* handle a subwindow cmap */
1663 EnterSubWindowColormap(Event
.xany
.window
);
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
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
);
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
);
1710 /***********************************************************************
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
)
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
)
1752 if (Scr
.Hilite
!= NULL
)
1753 DrawDecorations(Scr
.Hilite
, DRAW_ALL
, False
, True
, None
);
1759 /* handle a subwindow cmap */
1760 LeaveSubWindowColormap(Event
.xany
.window
);
1766 /***********************************************************************
1769 * HandleConfigureRequest - ConfigureRequest event handler
1771 ************************************************************************/
1772 void HandleConfigureRequest(void)
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
1794 Event
.xany
.window
= cre
->window
; /* mash parent field */
1795 if (XFindContext (dpy
, cre
->window
, FvwmContext
, (caddr_t
*) &Tmp_win
) ==
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 */
1805 XConfigureRequestEvent
*ecre
;
1809 while (XCheckTypedWindowEvent(dpy
, cre
->window
, ConfigureRequest
, &e
))
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
);
1826 if (ecre
->value_mask
& CWX
)
1828 cre
->value_mask
|= CWX
;
1831 if (ecre
->value_mask
& CWY
)
1833 cre
->value_mask
|= CWY
;
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
;
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
);
1875 if((Tmp_win
)&&((Tmp_win
->icon_pixmap_w
== cre
->window
)))
1877 Tmp_win
->icon_p_height
= cre
->height
+ 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
);
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
);
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
;
1936 Tmp_win
->wShaped
= 0;
1941 if (cre
->window
== Tmp_win
->w
)
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
));
1950 /* Don't modify frame_XXX fields before calling SetupWindow! */
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
);
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
;
2005 Tmp_win
, (unsigned int *)&constr_w
, (unsigned int *)&constr_h
, 0, 0,
2007 dw
+= (constr_w
- oldnew_w
);
2008 dh
+= (constr_h
- oldnew_h
);
2011 new_g
.x
= Tmp_win
->frame_g
.x
+ dx
;
2012 new_g
.width
= Tmp_win
->frame_g
.width
+ dw
;
2016 new_g
.x
= Tmp_win
->frame_g
.x
+ dx
;
2020 gravity_resize(Tmp_win
->hints
.win_gravity
, &new_g
, dw
, 0);
2024 new_g
.y
= Tmp_win
->frame_g
.y
+ dy
;
2025 new_g
.height
= Tmp_win
->frame_g
.height
+ dh
;
2029 new_g
.y
= Tmp_win
->frame_g
.y
+ dy
;
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
);
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
)
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
)
2077 RaiseWindow (Tmp_win
);
2080 LowerWindow (Tmp_win
);
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
);
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. */
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
);
2158 /***********************************************************************
2161 * SendConfigureNotify - inform a client window of its geometry.
2163 * The input (frame) geometry will be translated to client geometry
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
))
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 /***********************************************************************
2206 * HandleShapeNotify - shape notification event handler
2208 ***********************************************************************/
2210 void HandleShapeNotify (void)
2212 DBUG("HandleShapeNotify","Routine Entered");
2214 if (ShapesSupported
)
2216 XShapeEvent
*sev
= (XShapeEvent
*) &Event
;
2220 if (sev
->kind
!= ShapeBounding
)
2222 Tmp_win
->wShaped
= sev
->shaped
;
2223 SetShape(Tmp_win
,Tmp_win
->frame_g
.width
);
2228 /***********************************************************************
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);
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 ****************************************************************************/
2271 int My_XNextEvent(Display
*dpy
, XEvent
*event
)
2273 extern fd_set_size_t fd_width
;
2275 fd_set in_fdset
, out_fdset
;
2276 Window targetWindow
;
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 */
2289 /* execute any commands queued up */
2290 DBUG("My_XNextEvent", "executing module comand queue");
2291 ExecuteCommandQueue()
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 */
2300 DBUG("My_XNextEvent","taking care of queued up events & returning (1)");
2301 XNextEvent(dpy
,event
);
2302 StashEventTime(event
);
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 */
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. */
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
))
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;
2343 FD_ZERO(&out_fdset
);
2344 FD_SET(x_fd
, &in_fdset
);
2346 /* nothing is done here if fvwm was compiled without session support */
2348 FD_SET(sm_fd
, &in_fdset
);
2350 for(i
=0; i
<npipes
; i
++) {
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;
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
);
2375 DBUG("My_XNextEvent","calling KillModule");
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
)))
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");
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 */
2408 DBUG("My_XNextEvent","taking care of queued up events & returning (2)");
2409 XNextEvent(dpy
,event
);
2410 StashEventTime(event
);
2414 DBUG("My_XNextEvent","leaving My_XNextEvent");
2420 ** InitEventHandlerJumpTable
2422 void InitEventHandlerJumpTable(void)
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
;
2446 if (ShapesSupported
)
2447 EventHandlerJumpTable
[ShapeEventBase
+ShapeNotify
] = HandleShapeNotify
;
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 /***********************************************************************
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
);
2478 if (XFindContext (dpy
, w
, FvwmContext
, (caddr_t
*) &Tmp_win
) == XCNOENT
)
2482 last_event_type
= Event
.type
;
2483 last_event_window
= w
;
2485 if (EventHandlerJumpTable
[Event
.type
])
2487 (*EventHandlerJumpTable
[Event
.type
])();
2491 /* If we're using the C version of alloca, see if anything needs to be
2497 if (preserve_Tmp_win
)
2498 Tmp_win
= s_Tmp_win
;
2499 DBUG("DispatchEvent","Leaving Routine");
2504 /***********************************************************************
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 /***********************************************************************
2535 * Find the Fvwm context for the Event.
2537 ************************************************************************/
2538 int GetContext(FvwmWindow
*t
, XEvent
*e
, Window
*w
)
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
);
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
));
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
));
2587 if (*w
== Scr
.NoFocusWin
)
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
));
2602 if (*w
== Scr
.NoFocusWin
)
2604 if (e
->xkey
.subwindow
!= None
&& e
->xany
.window
!= t
->w
)
2605 *w
= e
->xkey
.subwindow
;
2610 if (*w
== t
->title_w
)
2612 else if (*w
== t
->w
|| *w
== t
->Parent
|| *w
== t
->frame
)
2614 else if (*w
== t
->icon_w
|| *w
== t
->icon_pixmap_w
)
2616 else if (*w
== t
->decor_w
)
2617 Context
= C_SIDEBAR
;
2622 if(*w
== t
->corners
[i
])
2627 if(*w
== t
->sides
[i
])
2629 Context
= C_SIDEBAR
;
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
;
2657 /**************************************************************************
2659 * Removes expose events for a specific window from the queue
2661 *************************************************************************/
2662 int flush_expose (Window w
)
2667 while (XCheckTypedWindowEvent (dpy
, w
, Expose
, &dummy
))
2672 /* same as above, but merges the expose rectangles into a single big one */
2673 int flush_accumulate_expose(Window w
, XEvent
*e
)
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
);
2692 e
->xexpose
.width
= x2
- x1
;
2693 e
->xexpose
.height
= y2
- y1
;
2699 /**************************************************************************
2701 * Removes all expose events from the queue and does the necessary redraws
2703 *************************************************************************/
2704 void handle_all_expose(void)
2708 memcpy(&old_event
, &Event
, sizeof(XEvent
));
2710 while (XCheckMaskEvent(dpy
, ExposureMask
, &Event
))
2712 DispatchEvent(True
);
2714 memcpy(&Event
, &old_event
, sizeof(XEvent
));
2720 /****************************************************************************
2722 * Records the time of the last processed event. Used in XSetInputFocus
2724 ****************************************************************************/
2725 Bool
StashEventTime (XEvent
*ev
)
2727 Time NewTimestamp
= CurrentTime
;
2733 NewTimestamp
= ev
->xkey
.time
;
2737 NewTimestamp
= ev
->xbutton
.time
;
2740 NewTimestamp
= ev
->xmotion
.time
;
2744 NewTimestamp
= ev
->xcrossing
.time
;
2746 case PropertyNotify
:
2747 NewTimestamp
= ev
->xproperty
.time
;
2749 case SelectionClear
:
2750 NewTimestamp
= ev
->xselectionclear
.time
;
2752 case SelectionRequest
:
2753 NewTimestamp
= ev
->xselectionrequest
.time
;
2755 case SelectionNotify
:
2756 NewTimestamp
= ev
->xselection
.time
;
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
;
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 */
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
)
2789 HandleEnterNotify();
2794 /* This function discards all queued up ButtonPress, ButtonRelease and
2795 * ButtonMotion events. */
2796 int discard_events(long event_mask
)
2802 for (count
= 0; XCheckMaskEvent(dpy
, event_mask
, &e
); count
++)
2810 /* Similar function for certain types of PropertyNotify. */
2811 static int flush_property_notify(Atom atom
, Window w
)
2817 for (count
= 0; XCheckMaskEvent(dpy
, PropertyChangeMask
, &e
); count
++)
2819 if (e
.xproperty
.atom
!= atom
)
2821 XPutBackEvent(dpy
, &e
);
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
)
2840 long evmask
= ButtonPressMask
|ButtonReleaseMask
|ButtonMotionMask
|
2841 KeyPressMask
|KeyReleaseMask
;
2843 if (do_handle_expose
)
2844 evmask
|= ExposureMask
;
2847 mask
= DEFAULT_ALL_BUTTONS_MASK
;
2848 while (mask
& (DEFAULT_ALL_BUTTONS_MASK
))
2850 /* handle expose events */
2851 if (XCheckMaskEvent(dpy
, evmask
, &Event
))
2855 case ButtonReleaseMask
:
2856 mask
= Event
.xbutton
.state
;
2859 DispatchEvent(True
);
2867 /* although this should never happen, a bit of additional safety does not
2869 XQueryPointer(dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
, &JunkX
, &JunkY
,
2870 &JunkX
, &JunkY
, &mask
);
2874 MyXUngrabServer(dpy
);