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>
62 #include <sys/types.h>
66 #include "libs/fvwmlib.h"
70 #include "functions.h"
76 #include "libs/Colorset.h"
77 #include "fvwmsignal.h"
79 #include <X11/extensions/shape.h>
81 #include "module_interface.h"
84 #include "colormaps.h"
85 #include "add_window.h"
94 #include "move_resize.h"
98 #endif /* HAVE_STROKE */
101 #define XUrgencyHint (1L << 8)
104 extern void StartupStuff(void);
106 int Context
= C_NO_CONTEXT
; /* current button press context */
107 static int Button
= 0;
108 FvwmWindow
*ButtonWindow
= NULL
; /* button press window structure */
109 XEvent Event
; /* the current event */
110 FvwmWindow
*Tmp_win
= NULL
; /* the current fvwm window */
112 int last_event_type
=0;
113 static Window last_event_window
=0;
114 Time lastTimestamp
= CurrentTime
; /* until Xlib does this for us */
117 STROKE_CODE(static int send_motion
;)
118 STROKE_CODE(static char sequence
[MAX_SEQUENCE
+1];)
121 extern int ShapeEventBase
;
122 void HandleShapeNotify(void);
128 ** LASTEvent is the number of X events defined - it should be defined
129 ** in X.h (to be like 35), but since extension (eg SHAPE) events are
130 ** numbered beyond LASTEvent, we need to use a bigger number than the
131 ** default, so let's undefine the default and use 256 instead.
135 #define LASTEvent 256
136 #endif /* !LASTEvent */
137 typedef void (*PFEH
)(void);
138 PFEH EventHandlerJumpTable
[LASTEvent
];
140 /***********************************************************************
143 * HandleFocusIn - handles focus in events
145 ************************************************************************/
146 void HandleFocusIn(void)
150 Window focus_w
= None
;
151 Window focus_fw
= None
;
154 FvwmWindow
*ffw_old
= Scr
.Focus
;
155 static Window last_focus_w
= None
;
156 static Window last_focus_fw
= None
;
157 static Bool is_never_focused
= True
;
159 DBUG("HandleFocusIn","Routine Entered");
161 /* This is a hack to make the PointerKey command work */
162 if (Event
.xfocus
.detail
!= NotifyPointer
)
164 w
= Event
.xany
.window
;
165 while(XCheckTypedEvent(dpy
,FocusIn
,&d
))
168 if (d
.xfocus
.detail
!= NotifyPointer
)
178 if (XFindContext (dpy
, w
, FvwmContext
, (caddr_t
*) &Tmp_win
) == XCNOENT
)
185 if (w
!= Scr
.NoFocusWin
)
187 Scr
.UnknownWinFocused
= w
;
192 DrawDecorations(Scr
.Hilite
, DRAW_ALL
, False
, True
, None
);
193 if (Scr
.ColormapFocus
== COLORMAP_FOLLOWS_FOCUS
)
195 if((Scr
.Hilite
)&&(!IS_ICONIFIED(Scr
.Hilite
)))
197 InstallWindowColormaps(Scr
.Hilite
);
201 InstallWindowColormaps(NULL
);
206 /* Not very useful if no window that fvwm and its modules know about has the
208 fc
= GetColor("White");
209 bc
= GetColor("Black");
211 else if (Tmp_win
!= Scr
.Hilite
212 /* domivogt (16-May-2000): This check is necessary to force sending
213 * a M_FOCUS_CHANGE packet after an unmanaged window was focused.
214 * Otherwise fvwm would believe that Scr.Hilite was still focused and
215 * not send any info to the modules. */
216 || last_focus_fw
== None
)
218 DrawDecorations(Tmp_win
, DRAW_ALL
, True
, True
, None
);
219 focus_w
= Tmp_win
->w
;
220 focus_fw
= Tmp_win
->frame
;
221 fc
= Tmp_win
->hicolors
.fore
;
222 bc
= Tmp_win
->hicolors
.back
;
224 if (Scr
.ColormapFocus
== COLORMAP_FOLLOWS_FOCUS
)
226 if((Scr
.Hilite
)&&(!IS_ICONIFIED(Scr
.Hilite
)))
228 InstallWindowColormaps(Scr
.Hilite
);
232 InstallWindowColormaps(NULL
);
240 if (is_never_focused
|| last_focus_fw
== None
||
241 focus_w
!= last_focus_w
|| focus_fw
!= last_focus_fw
)
243 BroadcastPacket(M_FOCUS_CHANGE
, 5, focus_w
, focus_fw
,
244 (unsigned long)IsLastFocusSetByMouse(), fc
, bc
);
245 last_focus_w
= focus_w
;
246 last_focus_fw
= focus_fw
;
247 is_never_focused
= False
;
249 if (Scr
.Focus
!= ffw_old
)
251 focus_grab_buttons(Scr
.Focus
, True
);
252 focus_grab_buttons(ffw_old
, False
);
256 /***********************************************************************
259 * HandleKeyPress - key press event handler
261 ************************************************************************/
262 void HandleKeyPress(void)
266 DBUG("HandleKeyPress","Routine Entered");
268 Context
= GetContext(Tmp_win
, &Event
, &PressedW
);
271 /* Here's a real hack - some systems have two keys with the
272 * same keysym and different keycodes. This converts all
273 * the cases to one keycode. */
275 XKeysymToKeycode(dpy
,XKeycodeToKeysym(dpy
,Event
.xkey
.keycode
,0));
277 /* Check if there is something bound to the key */
278 action
= CheckBinding(Scr
.AllBindings
, STROKE_ARG(0) Event
.xkey
.keycode
,
279 Event
.xkey
.state
, GetUnusedModifiers(), Context
,
283 ButtonWindow
= Tmp_win
;
284 ExecuteFunction(action
, Tmp_win
, &Event
, Context
, -1, 0, NULL
);
289 /* if we get here, no function key was bound to the key. Send it
290 * to the client if it was in a window we know about.
292 if (Scr
.Focus
&& Event
.xkey
.window
!= Scr
.Focus
->w
)
294 Event
.xkey
.window
= Scr
.Focus
->w
;
295 XSendEvent(dpy
, Scr
.Focus
->w
, False
, KeyPressMask
, &Event
);
297 else if (Tmp_win
&& Event
.xkey
.window
!= Tmp_win
->w
)
299 Event
.xkey
.window
= Tmp_win
->w
;
300 XSendEvent(dpy
, Tmp_win
->w
, False
, KeyPressMask
, &Event
);
305 /***********************************************************************
308 * HandlePropertyNotify - property notify event handler
310 ***********************************************************************/
311 void HandlePropertyNotify(void)
313 XTextProperty text_prop
;
314 Bool OnThisPage
= False
;
315 Bool was_size_inc_set
;
316 int old_wmhints_flags
;
325 unsigned long nitems
, bytesafter
;
331 DBUG("HandlePropertyNotify","Routine Entered");
334 (XGetGeometry(dpy
, Tmp_win
->w
, &JunkRoot
, &JunkX
, &JunkY
,
335 &JunkWidth
, &JunkHeight
, &JunkBW
, &JunkDepth
) == 0))
339 * Make sure at least part of window is on this page
340 * before giving it focus...
342 OnThisPage
= IsRectangleOnThisPage(&(Tmp_win
->frame_g
), Tmp_win
->Desk
);
344 switch (Event
.xproperty
.atom
)
346 case XA_WM_TRANSIENT_FOR
:
348 if(XGetTransientForHint(dpy
, Tmp_win
->w
, &Tmp_win
->transientfor
))
350 SET_TRANSIENT(Tmp_win
, 1);
351 RaiseWindow(Tmp_win
);
355 SET_TRANSIENT(Tmp_win
, 0);
362 if (XGetWindowProperty (dpy
, Tmp_win
->w
, Event
.xproperty
.atom
, 0L,
363 MAX_WINDOW_NAME_LEN
, False
, AnyPropertyType
,
364 &actual
, &actual_format
, &nitems
, &bytesafter
,
365 (unsigned char **) &prop
) != Success
||
369 if (actual
== XA_STRING
) {
370 /* STRING encoding, use this as it is */
371 free_window_names (Tmp_win
, True
, False
);
372 Tmp_win
->name
= prop
;
373 Tmp_win
->name_list
= NULL
;
375 /* not STRING encoding, try to convert */
376 text_prop
.value
= prop
;
377 text_prop
.encoding
= actual
;
378 text_prop
.format
= actual_format
;
379 text_prop
.nitems
= nitems
;
381 XmbTextPropertyToTextList(dpy
, &text_prop
, &list
, &num
) >= Success
382 && num
> 0 && *list
) {
383 /* XXX: does not consider the conversion is REALLY succeeded */
384 XFree(prop
); /* return of XGetWindowProperty() */
385 free_window_names (Tmp_win
, True
, False
);
386 Tmp_win
->name
= *list
;
387 Tmp_win
->name_list
= list
;
389 if (list
) XFreeStringList(list
);
390 XFree(prop
); /* return of XGetWindowProperty() */
391 if (!XGetWMName(dpy
, Tmp_win
->w
, &text_prop
))
392 return; /* why cannot read... */
393 free_window_names (Tmp_win
, True
, False
);
394 Tmp_win
->name
= (char *)text_prop
.value
;
395 Tmp_win
->name_list
= NULL
;
399 /* XXX: fallback to original behavior, is it needed ? */
400 if (!XGetWMName(dpy
, Tmp_win
->w
, &text_prop
))
402 free_window_names (Tmp_win
, True
, False
);
403 Tmp_win
->name
= (char *)text_prop
.value
;
404 Tmp_win
->name_list
= NULL
;
407 if (!XGetWMName(dpy
, Tmp_win
->w
, &text_prop
))
409 free_window_names (Tmp_win
, True
, False
);
410 Tmp_win
->name
= (char *)text_prop
.value
;
411 if (Tmp_win
->name
&& strlen(Tmp_win
->name
) > MAX_WINDOW_NAME_LEN
)
412 /* limit to prevent hanging X server */
413 Tmp_win
->name
[MAX_WINDOW_NAME_LEN
] = 0;
416 SET_NAME_CHANGED(Tmp_win
, 1);
418 if (Tmp_win
->name
== NULL
)
419 Tmp_win
->name
= NoName
;
420 BroadcastName(M_WINDOW_NAME
,Tmp_win
->w
,Tmp_win
->frame
,
421 (unsigned long)Tmp_win
,Tmp_win
->name
);
423 /* fix the name in the title bar */
424 if(!IS_ICONIFIED(Tmp_win
))
426 Tmp_win
, DRAW_TITLE
, (Scr
.Hilite
== Tmp_win
), True
, None
);
429 * if the icon name is NoName, set the name of the icon to be
430 * the same as the window
432 if (Tmp_win
->icon_name
== NoName
)
434 Tmp_win
->icon_name
= Tmp_win
->name
;
435 BroadcastName(M_ICON_NAME
,Tmp_win
->w
,Tmp_win
->frame
,
436 (unsigned long)Tmp_win
,Tmp_win
->icon_name
);
437 RedoIconName(Tmp_win
);
441 case XA_WM_ICON_NAME
:
443 if (XGetWindowProperty (dpy
, Tmp_win
->w
, Event
.xproperty
.atom
, 0L,
444 MAX_ICON_NAME_LEN
, False
, AnyPropertyType
,
445 &actual
, &actual_format
, &nitems
, &bytesafter
,
446 (unsigned char **) &prop
) != Success
||
450 if (actual
== XA_STRING
) {
451 /* STRING encoding, use this as it is */
452 free_window_names (Tmp_win
, False
, True
);
453 Tmp_win
->icon_name
= prop
;
454 Tmp_win
->icon_name_list
= NULL
;
456 /* not STRING encoding, try to convert */
457 text_prop
.value
= prop
;
458 text_prop
.encoding
= actual
;
459 text_prop
.format
= actual_format
;
460 text_prop
.nitems
= nitems
;
461 if (XmbTextPropertyToTextList(dpy
, &text_prop
, &list
, &num
) >= Success
462 && num
> 0 && *list
) {
463 /* XXX: does not consider the conversion is REALLY succeeded */
464 XFree(prop
); /* return of XGetWindowProperty() */
465 free_window_names (Tmp_win
, False
, True
);
466 Tmp_win
->icon_name
= *list
;
467 Tmp_win
->icon_name_list
= list
;
469 if (list
) XFreeStringList(list
);
470 XFree(prop
); /* return of XGetWindowProperty() */
471 if (!XGetWMIconName (dpy
, Tmp_win
->w
, &text_prop
))
472 return; /* why cannot read... */
473 free_window_names (Tmp_win
, False
, True
);
474 Tmp_win
->icon_name
= (char *)text_prop
.value
;
475 Tmp_win
->icon_name_list
= NULL
;
479 /* XXX: fallback to original behavior, is it needed ? */
480 if (!XGetWMIconName(dpy
, Tmp_win
->w
, &text_prop
))
482 free_window_names (Tmp_win
, False
, True
);
483 Tmp_win
->icon_name
= (char *)text_prop
.value
;
484 Tmp_win
->icon_name_list
= NULL
;
487 if (!XGetWMIconName (dpy
, Tmp_win
->w
, &text_prop
))
489 free_window_names (Tmp_win
, False
, True
);
490 Tmp_win
->icon_name
= (char *) text_prop
.value
;
491 if (Tmp_win
->icon_name
&& strlen(Tmp_win
->icon_name
) >
493 /* limit to prevent hanging X server */
494 Tmp_win
->icon_name
[MAX_ICON_NAME_LEN
] = 0;
496 if (Tmp_win
->icon_name
== NULL
)
497 Tmp_win
->icon_name
= NoName
;
498 BroadcastName(M_ICON_NAME
,Tmp_win
->w
,Tmp_win
->frame
,
499 (unsigned long)Tmp_win
,Tmp_win
->icon_name
);
500 RedoIconName(Tmp_win
);
504 /* clasen@mathematik.uni-freiburg.de - 02/01/1998 - new -
505 the urgency flag is an ICCCM 2.0 addition to the WM_HINTS. */
506 old_wmhints_flags
= 0;
507 if (Tmp_win
->wmhints
) {
508 old_wmhints_flags
= Tmp_win
->wmhints
->flags
;
509 XFree ((char *) Tmp_win
->wmhints
);
511 Tmp_win
->wmhints
= XGetWMHints(dpy
, Event
.xany
.window
);
513 if(Tmp_win
->wmhints
== NULL
)
517 * rebuild icon if the client either provides an icon
518 * pixmap or window or has reset the hints to `no icon'.
520 if ((Tmp_win
->wmhints
->flags
& (IconPixmapHint
|IconWindowHint
)) ||
521 ((old_wmhints_flags
& (IconPixmapHint
|IconWindowHint
)) !=
522 (Tmp_win
->wmhints
->flags
& (IconPixmapHint
|IconWindowHint
))))
524 if(Tmp_win
->icon_bitmap_file
== Scr
.DefaultIcon
)
525 Tmp_win
->icon_bitmap_file
= NULL
;
526 if(!Tmp_win
->icon_bitmap_file
&&
527 !(Tmp_win
->wmhints
->flags
&(IconPixmapHint
|IconWindowHint
)))
529 Tmp_win
->icon_bitmap_file
=
530 (Scr
.DefaultIcon
) ? strdup(Scr
.DefaultIcon
) : NULL
;
533 if (!IS_ICON_SUPPRESSED(Tmp_win
) ||
534 (Tmp_win
->wmhints
->flags
& IconWindowHint
))
537 XDestroyWindow(dpy
,Tmp_win
->icon_w
);
538 XDeleteContext(dpy
, Tmp_win
->icon_w
, FvwmContext
);
539 if(IS_ICON_OURS(Tmp_win
))
541 if(Tmp_win
->icon_pixmap_w
!= None
)
543 XDestroyWindow(dpy
,Tmp_win
->icon_pixmap_w
);
544 XDeleteContext(dpy
, Tmp_win
->icon_pixmap_w
, FvwmContext
);
548 XUnmapWindow(dpy
,Tmp_win
->icon_pixmap_w
);
550 Tmp_win
->icon_w
= None
;
551 Tmp_win
->icon_pixmap_w
= None
;
552 Tmp_win
->iconPixmap
= (Window
)NULL
;
553 if(IS_ICONIFIED(Tmp_win
))
555 SET_ICONIFIED(Tmp_win
, 0);
556 SET_ICON_UNMAPPED(Tmp_win
, 0);
557 CreateIconWindow(Tmp_win
,
558 Tmp_win
->icon_g
.x
,Tmp_win
->icon_g
.y
);
559 BroadcastPacket(M_ICONIFY
, 7,
560 Tmp_win
->w
, Tmp_win
->frame
,
561 (unsigned long)Tmp_win
,
562 Tmp_win
->icon_g
.x
, Tmp_win
->icon_g
.y
,
563 Tmp_win
->icon_g
.width
, Tmp_win
->icon_g
.height
);
564 /* domivogt (15-Sep-1999): BroadcastConfig informs modules of the
565 * configuration change including the iconified flag. So this
566 * flag must be set here. I'm not sure if the two calls of the
567 * SET_ICONIFIED macro after BroadcastConfig are necessary, but
568 * since it's only minimal overhead I prefer to be on the safe
570 SET_ICONIFIED(Tmp_win
, 1);
571 BroadcastConfig(M_CONFIGURE_WINDOW
, Tmp_win
);
572 SET_ICONIFIED(Tmp_win
, 0);
574 if (!IS_ICON_SUPPRESSED(Tmp_win
))
576 LowerWindow(Tmp_win
);
577 AutoPlaceIcon(Tmp_win
);
578 if(Tmp_win
->Desk
== Scr
.CurrentDesk
)
581 XMapWindow(dpy
, Tmp_win
->icon_w
);
582 if(Tmp_win
->icon_pixmap_w
!= None
)
583 XMapWindow(dpy
, Tmp_win
->icon_pixmap_w
);
586 SET_ICONIFIED(Tmp_win
, 1);
587 DrawIconWindow(Tmp_win
);
591 /* clasen@mathematik.uni-freiburg.de - 02/01/1998 - new -
592 the urgency flag is an ICCCM 2.0 addition to the WM_HINTS.
593 Treat urgency changes by calling user-settable functions.
594 These could e.g. deiconify and raise the window or temporarily
596 if (!(old_wmhints_flags
& XUrgencyHint
) &&
597 (Tmp_win
->wmhints
->flags
& XUrgencyHint
))
600 "Function UrgencyFunc", Tmp_win
, &Event
, C_WINDOW
, -1, 0, NULL
);
603 if ((old_wmhints_flags
& XUrgencyHint
) &&
604 !(Tmp_win
->wmhints
->flags
& XUrgencyHint
))
607 "Function UrgencyDoneFunc", Tmp_win
, &Event
, C_WINDOW
, -1, 0, NULL
);
610 case XA_WM_NORMAL_HINTS
:
611 was_size_inc_set
= IS_SIZE_INC_SET(Tmp_win
);
612 old_width_inc
= Tmp_win
->hints
.width_inc
;
613 old_height_inc
= Tmp_win
->hints
.height_inc
;
614 old_base_width
= Tmp_win
->hints
.base_width
;
615 old_base_height
= Tmp_win
->hints
.base_height
;
616 GetWindowSizeHints(Tmp_win
);
617 if (old_width_inc
!= Tmp_win
->hints
.width_inc
||
618 old_height_inc
!= Tmp_win
->hints
.height_inc
)
625 if (!was_size_inc_set
&& old_width_inc
== 1 && old_height_inc
== 1)
627 /* This is a hack for xvile. It sets the _inc hints after it
628 * requested that the window is mapped but before it's really
634 /* we have to resize the unmaximized window to keep the size in
635 * resize increments constant */
636 units_w
= Tmp_win
->normal_g
.width
- 2 * Tmp_win
->boundary_width
-
638 units_h
= Tmp_win
->normal_g
.height
- Tmp_win
->title_g
.height
-
639 2 * Tmp_win
->boundary_width
- old_base_height
;
640 units_w
/= old_width_inc
;
641 units_h
/= old_height_inc
;
643 /* update the 'invisible' geometry */
644 wdiff
= units_w
* (Tmp_win
->hints
.width_inc
- old_width_inc
) +
645 (Tmp_win
->hints
.base_width
- old_base_width
);
646 hdiff
= units_h
* (Tmp_win
->hints
.height_inc
- old_height_inc
) +
647 (Tmp_win
->hints
.base_height
- old_base_height
);
649 Tmp_win
->hints
.win_gravity
, &Tmp_win
->normal_g
, wdiff
, hdiff
);
651 gravity_constrain_size(
652 Tmp_win
->hints
.win_gravity
, Tmp_win
, &Tmp_win
->normal_g
);
653 if (!IS_MAXIMIZED(Tmp_win
))
657 get_relative_geometry(&new_g
, &Tmp_win
->normal_g
);
658 if (IS_SHADED(Tmp_win
))
659 get_shaded_geometry(Tmp_win
, &new_g
, &new_g
);
661 Tmp_win
, new_g
.x
, new_g
.y
, new_g
.width
, new_g
.height
, False
);
668 maximize_adjust_offset(Tmp_win
);
669 /* domivogt (07-Apr-2000): as terrible hack to work around a xterm
670 * bug: when the font size is changed in a xterm, xterm simply assumes
671 * that the wm will grant its new size. Of course this is wrong if
672 * the xterm is maximised. To make xterm happy, we first send a
673 * ConfigureNotify with the current (maximised) geometry + 1 pixel in
674 * height, then another one with the correct old geometry. Changing
675 * the font multiple times will cause the xterm to shrink because
676 * gravity_constrain_size doesn't know about the initially requested
678 w
= Tmp_win
->max_g
.width
;
679 h
= Tmp_win
->max_g
.height
;
680 gravity_constrain_size(
681 Tmp_win
->hints
.win_gravity
, Tmp_win
, &Tmp_win
->max_g
);
682 if (w
!= Tmp_win
->max_g
.width
||
683 h
!= Tmp_win
->max_g
.height
)
687 /* This is in case the size_inc changed and the old dimensions are
688 * not multiples of the new values. */
689 get_relative_geometry(&new_g
, &Tmp_win
->max_g
);
690 if (IS_SHADED(Tmp_win
))
691 get_shaded_geometry(Tmp_win
, &new_g
, &new_g
);
693 Tmp_win
, new_g
.x
, new_g
.y
, new_g
.width
, new_g
.height
, False
);
698 Tmp_win
, Tmp_win
->frame_g
.x
, Tmp_win
->frame_g
.y
,
699 Tmp_win
->frame_g
.width
, Tmp_win
->frame_g
.height
+1, 0, False
);
704 Tmp_win
, Tmp_win
->frame_g
.x
, Tmp_win
->frame_g
.y
,
705 Tmp_win
->frame_g
.width
, Tmp_win
->frame_g
.height
, 0, False
);
709 GNOME_SetWinArea(Tmp_win
);
711 BroadcastConfig(M_CONFIGURE_WINDOW
,Tmp_win
);
715 if(Event
.xproperty
.atom
== _XA_WM_PROTOCOLS
)
716 FetchWmProtocols (Tmp_win
);
717 else if (Event
.xproperty
.atom
== _XA_WM_COLORMAP_WINDOWS
)
719 FetchWmColormapWindows (Tmp_win
); /* frees old data */
720 ReInstallActiveColormap();
722 else if(Event
.xproperty
.atom
== _XA_WM_STATE
)
724 if((Tmp_win
!= NULL
)&&(HAS_CLICK_FOCUS(Tmp_win
))
725 &&(Tmp_win
== Scr
.Focus
))
730 SetFocus(Tmp_win
->w
,Tmp_win
,0);
739 /***********************************************************************
742 * HandleClientMessage - client message event handler
744 ************************************************************************/
745 void HandleClientMessage(void)
749 DBUG("HandleClientMessage","Routine Entered");
751 /* Process GNOME Messages */
752 if (GNOME_ProcessClientMessage(Tmp_win
, &Event
))
757 if ((Event
.xclient
.message_type
== _XA_WM_CHANGE_STATE
)&&
758 (Tmp_win
)&&(Event
.xclient
.data
.l
[0]==IconicState
)&&
759 !IS_ICONIFIED(Tmp_win
))
761 XQueryPointer( dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
,
762 &(button
.xmotion
.x_root
),
763 &(button
.xmotion
.y_root
),
764 &JunkX
, &JunkY
, &JunkMask
);
766 ExecuteFunction("Iconify", Tmp_win
, &button
, C_FRAME
, -1, 0, NULL
);
770 /* FIXME: Is this safe enough ? I guess if clients behave
771 according to ICCCM and send these messages only if they
772 when grabbed the pointer, it is OK */
774 extern Atom _XA_WM_COLORMAP_NOTIFY
;
775 if (Event
.xclient
.message_type
== _XA_WM_COLORMAP_NOTIFY
) {
776 set_client_controls_colormaps(Event
.xclient
.data
.l
[1]);
782 ** CKH - if we get here, it was an unknown client message, so send
783 ** it to the client if it was in a window we know about. I'm not so
784 ** sure this should be done or not, since every other window manager
785 ** I've looked at doesn't. But it might be handy for a free drag and
786 ** drop setup being developed for Linux.
790 if(Event
.xclient
.window
!= Tmp_win
->w
)
792 Event
.xclient
.window
= Tmp_win
->w
;
793 XSendEvent(dpy
, Tmp_win
->w
, False
, NoEventMask
, &Event
);
798 /***********************************************************************
801 * HandleExpose - expose event handler
803 ***********************************************************************/
804 void HandleExpose(void)
806 if (Event
.xexpose
.count
!= 0)
809 DBUG("HandleExpose","Routine Entered");
813 draw_window_parts draw_parts
;
815 if (Event
.xany
.window
== Tmp_win
->title_w
)
816 draw_parts
= DRAW_TITLE
;
817 else if (Event
.xany
.window
== Tmp_win
->decor_w
||
818 Event
.xany
.window
== Tmp_win
->frame
)
819 draw_parts
= DRAW_FRAME
;
821 draw_parts
= DRAW_BUTTONS
;
823 Tmp_win
, draw_parts
, (Scr
.Hilite
== Tmp_win
), True
, Event
.xany
.window
);
830 /***********************************************************************
833 * HandleDestroyNotify - DestroyNotify event handler
835 ***********************************************************************/
836 void HandleDestroyNotify(void)
838 DBUG("HandleDestroyNotify","Routine Entered");
840 destroy_window(Tmp_win
);
841 GNOME_SetClientList();
847 /***********************************************************************
850 * HandleMapRequest - MapRequest event handler
852 ************************************************************************/
853 void HandleMapRequest(void)
855 DBUG("HandleMapRequest","Routine Entered");
859 /* Just map the damn thing, decorations are added later
860 * in CaptureAllWindows. */
861 XMapWindow (dpy
, Event
.xmaprequest
.window
);
864 HandleMapRequestKeepRaised(None
, NULL
);
866 void HandleMapRequestKeepRaised(Window KeepRaised
, FvwmWindow
*ReuseWin
)
868 extern long isIconicState
;
869 extern Bool isIconifiedByParent
;
870 extern Boolean PPosOverride
;
871 Bool OnThisPage
= False
;
873 Event
.xany
.window
= Event
.xmaprequest
.window
;
875 if (ReuseWin
== NULL
)
877 if(XFindContext(dpy
, Event
.xany
.window
, FvwmContext
,
878 (caddr_t
*)&Tmp_win
)==XCNOENT
)
891 /* If the window has never been mapped before ... */
892 if(!Tmp_win
|| (Tmp_win
&& DO_REUSE_DESTROYED(Tmp_win
)))
894 /* Add decorations. */
895 Tmp_win
= AddWindow(Event
.xany
.window
, ReuseWin
);
900 * Make sure at least part of window is on this page
901 * before giving it focus...
903 OnThisPage
= IsRectangleOnThisPage(&(Tmp_win
->frame_g
), Tmp_win
->Desk
);
905 if(KeepRaised
!= None
)
906 XRaiseWindow(dpy
,KeepRaised
);
907 /* If it's not merely iconified, and we have hints, use them. */
908 if (!IS_ICONIFIED(Tmp_win
))
912 if(Tmp_win
->wmhints
&& (Tmp_win
->wmhints
->flags
& StateHint
))
913 state
= Tmp_win
->wmhints
->initial_state
;
917 if(DO_START_ICONIC(Tmp_win
))
920 if(isIconicState
!= DontCareState
)
921 state
= isIconicState
;
930 if (Tmp_win
->Desk
== Scr
.CurrentDesk
)
932 XMapWindow(dpy
, Tmp_win
->w
);
933 XMapWindow(dpy
, Tmp_win
->frame
);
934 SET_MAP_PENDING(Tmp_win
, 1);
935 SetMapStateProp(Tmp_win
, NormalState
);
936 if(((!IS_TRANSIENT(Tmp_win
) ||
937 Tmp_win
->transientfor
== Scr
.Root
) &&
938 DO_GRAB_FOCUS(Tmp_win
)) ||
939 (IS_TRANSIENT(Tmp_win
) && DO_GRAB_FOCUS_TRANSIENT(Tmp_win
) &&
940 Scr
.Focus
&& Scr
.Focus
->w
== Tmp_win
->transientfor
))
944 SetFocus(Tmp_win
->w
, Tmp_win
, 1);
950 XMapWindow(dpy
, Tmp_win
->w
);
951 SetMapStateProp(Tmp_win
, NormalState
);
956 if (isIconifiedByParent
)
958 isIconifiedByParent
= False
;
959 SET_ICONIFIED_BY_PARENT(Tmp_win
, 1);
961 if (Tmp_win
->wmhints
)
963 Iconify(Tmp_win
, Tmp_win
->wmhints
->icon_x
,
964 Tmp_win
->wmhints
->icon_y
);
968 Iconify(Tmp_win
, 0, 0);
974 MyXUngrabServer(dpy
);
976 /* If no hints, or currently an icon, just "deiconify" */
981 if (IS_SHADED(Tmp_win
))
983 BroadcastPacket(M_WINDOWSHADE
, 3, Tmp_win
->w
, Tmp_win
->frame
,
984 (unsigned long)Tmp_win
);
987 if (!IS_ICONIFIED(Tmp_win
) && Scr
.Focus
&& Scr
.Focus
!= Tmp_win
&&
988 !is_on_top_of_layer(Scr
.Focus
))
990 if (Tmp_win
->Desk
== Scr
.CurrentDesk
&&
991 Tmp_win
->frame_g
.x
+ Tmp_win
->frame_g
.width
> Scr
.Focus
->frame_g
.x
&&
992 Scr
.Focus
->frame_g
.x
+ Scr
.Focus
->frame_g
.width
> Tmp_win
->frame_g
.x
&&
993 Tmp_win
->frame_g
.y
+ Tmp_win
->frame_g
.height
> Scr
.Focus
->frame_g
.y
&&
994 Scr
.Focus
->frame_g
.y
+ Scr
.Focus
->frame_g
.height
> Tmp_win
->frame_g
.y
)
996 /* The newly mapped window overlaps the focused window. Make sure
997 * ClickToFocusRaises and MouseFocusClickRaises work again.
999 * Note: There are many conditions under which we do not have to call
1000 * focus_grab_buttons(), but it is not worth the effort to write them
1001 * down here. Rather do some unnecessary work in this function. */
1002 focus_grab_buttons(Scr
.Focus
, True
);
1006 /* Just to be on the safe side, we make sure that STARTICONIC
1007 can only influence the initial transition from withdrawn state. */
1008 SET_DO_START_ICONIC(Tmp_win
, 0);
1009 if (DO_DELETE_ICON_MOVED(Tmp_win
))
1011 SET_DELETE_ICON_MOVED(Tmp_win
, 0);
1012 SET_ICON_MOVED(Tmp_win
, 0);
1014 /* Clean out the global so that it isn't used on additional map events. */
1015 isIconicState
= DontCareState
;
1016 GNOME_SetClientList();
1020 /***********************************************************************
1023 * HandleMapNotify - MapNotify event handler
1025 ***********************************************************************/
1026 void HandleMapNotify(void)
1028 Bool OnThisPage
= False
;
1030 DBUG("HandleMapNotify","Routine Entered");
1034 if((Event
.xmap
.override_redirect
== True
)&&
1035 (Event
.xmap
.window
!= Scr
.NoFocusWin
))
1037 XSelectInput(dpy
,Event
.xmap
.window
,FocusChangeMask
);
1038 Scr
.UnknownWinFocused
= Event
.xmap
.window
;
1043 /* Except for identifying over-ride redirect window mappings, we
1044 * don't need or want windows associated with the substructurenotifymask */
1045 if(Event
.xmap
.event
!= Event
.xmap
.window
)
1048 SET_MAP_PENDING(Tmp_win
, 0);
1049 /* don't map if the event was caused by a de-iconify */
1050 if (IS_DEICONIFY_PENDING(Tmp_win
))
1056 Make sure at least part of window is on this page
1057 before giving it focus...
1059 OnThisPage
= IsRectangleOnThisPage(&(Tmp_win
->frame_g
), Tmp_win
->Desk
);
1062 * Need to do the grab to avoid race condition of having server send
1063 * MapNotify to client before the frame gets mapped; this is bad because
1064 * the client would think that the window has a chance of being viewable
1065 * when it really isn't.
1067 MyXGrabServer (dpy
);
1068 if (Tmp_win
->icon_w
)
1069 XUnmapWindow(dpy
, Tmp_win
->icon_w
);
1070 if(Tmp_win
->icon_pixmap_w
!= None
)
1071 XUnmapWindow(dpy
, Tmp_win
->icon_pixmap_w
);
1072 XMapSubwindows(dpy
, Tmp_win
->frame
);
1073 XMapSubwindows(dpy
, Tmp_win
->decor_w
);
1075 if(Tmp_win
->Desk
== Scr
.CurrentDesk
)
1077 XMapWindow(dpy
, Tmp_win
->frame
);
1080 if(IS_ICONIFIED(Tmp_win
))
1081 BroadcastPacket(M_DEICONIFY
, 3,
1082 Tmp_win
->w
, Tmp_win
->frame
, (unsigned long)Tmp_win
);
1084 BroadcastPacket(M_MAP
, 3,
1085 Tmp_win
->w
,Tmp_win
->frame
, (unsigned long)Tmp_win
);
1087 if((!IS_TRANSIENT(Tmp_win
) && DO_GRAB_FOCUS(Tmp_win
)) ||
1088 (IS_TRANSIENT(Tmp_win
) && DO_GRAB_FOCUS_TRANSIENT(Tmp_win
) &&
1089 Scr
.Focus
&& Scr
.Focus
->w
== Tmp_win
->transientfor
))
1093 SetFocus(Tmp_win
->w
,Tmp_win
,1);
1096 if((!(HAS_BORDER(Tmp_win
)|HAS_TITLE(Tmp_win
)))&&(Tmp_win
->boundary_width
<2))
1098 DrawDecorations(Tmp_win
, DRAW_ALL
, False
, True
, Tmp_win
->decor_w
);
1101 MyXUngrabServer (dpy
);
1103 SET_MAPPED(Tmp_win
, 1);
1104 SET_ICONIFIED(Tmp_win
, 0);
1105 SET_ICON_UNMAPPED(Tmp_win
, 0);
1106 if (DO_ICONIFY_AFTER_MAP(Tmp_win
))
1108 /* finally, if iconification was requested before the window was mapped,
1109 * request it now. */
1110 Iconify(Tmp_win
, 0, 0);
1111 SET_ICONIFY_AFTER_MAP(Tmp_win
, 0);
1116 /***********************************************************************
1119 * HandleUnmapNotify - UnmapNotify event handler
1121 ************************************************************************/
1122 void HandleUnmapNotify(void)
1127 extern FvwmWindow
*colormap_win
;
1129 int focus_grabbed
= 0;
1130 Bool must_return
= False
;
1132 DBUG("HandleUnmapNotify","Routine Entered");
1135 * Don't ignore events as described below.
1137 if(Event
.xunmap
.event
!= Event
.xunmap
.window
&&
1138 (Event
.xunmap
.event
!= Scr
.Root
|| !Event
.xunmap
.send_event
))
1144 * The July 27, 1988 ICCCM spec states that a client wishing to switch
1145 * to WithdrawnState should send a synthetic UnmapNotify with the
1146 * event field set to (pseudo-)root, in case the window is already
1147 * unmapped (which is the case for fvwm for IconicState). Unfortunately,
1148 * we looked for the FvwmContext using that field, so try the window
1154 Event
.xany
.window
= Event
.xunmap
.window
;
1156 if (XFindContext(dpy
, Event
.xany
.window
,
1157 FvwmContext
, (caddr_t
*)&Tmp_win
) == XCNOENT
)
1164 if (Event
.xunmap
.window
== Tmp_win
->frame
)
1166 SET_DEICONIFY_PENDING(Tmp_win
, 0);
1173 XUnmapWindow(dpy
, Event
.xunmap
.window
);
1175 if(Tmp_win
== Scr
.Hilite
)
1178 if(Scr
.PreviousFocus
== Tmp_win
)
1179 Scr
.PreviousFocus
= NULL
;
1181 focus_grabbed
= (Tmp_win
== Scr
.Focus
) &&
1182 ((!IS_TRANSIENT(Tmp_win
) && DO_GRAB_FOCUS(Tmp_win
)) ||
1183 (IS_TRANSIENT(Tmp_win
) && DO_GRAB_FOCUS_TRANSIENT(Tmp_win
)));
1185 if((Tmp_win
== Scr
.Focus
)&&(HAS_CLICK_FOCUS(Tmp_win
)))
1188 SetFocus(Tmp_win
->next
->w
, Tmp_win
->next
, 1);
1190 SetFocus(Scr
.NoFocusWin
,NULL
,1);
1193 if(Scr
.Focus
== Tmp_win
)
1194 SetFocus(Scr
.NoFocusWin
,NULL
,1);
1196 if(Tmp_win
== Scr
.pushed_window
)
1197 Scr
.pushed_window
= NULL
;
1199 if(Tmp_win
== colormap_win
)
1200 colormap_win
= NULL
;
1202 if (!IS_MAPPED(Tmp_win
) && !IS_ICONIFIED(Tmp_win
))
1209 if(XCheckTypedWindowEvent (dpy
, Event
.xunmap
.window
, DestroyNotify
,&dummy
))
1211 destroy_window(Tmp_win
);
1215 * The program may have unmapped the client window, from either
1216 * NormalState or IconicState. Handle the transition to WithdrawnState.
1218 * We need to reparent the window back to the root (so that fvwm exiting
1219 * won't cause it to get mapped) and then throw away all state (pretend
1220 * that we've received a DestroyNotify).
1222 if (XTranslateCoordinates (dpy
, Event
.xunmap
.window
, Scr
.Root
,
1223 0, 0, &dstx
, &dsty
, &dumwin
))
1228 reparented
= XCheckTypedWindowEvent (dpy
, Event
.xunmap
.window
,
1229 ReparentNotify
, &ev
);
1230 SetMapStateProp (Tmp_win
, WithdrawnState
);
1233 if (Tmp_win
->old_bw
)
1234 XSetWindowBorderWidth (dpy
, Event
.xunmap
.window
, Tmp_win
->old_bw
);
1235 if((!IS_ICON_SUPPRESSED(Tmp_win
))&&
1236 (Tmp_win
->wmhints
&& (Tmp_win
->wmhints
->flags
& IconWindowHint
)))
1237 XUnmapWindow (dpy
, Tmp_win
->wmhints
->icon_window
);
1241 RestoreWithdrawnLocation (Tmp_win
,False
);
1243 XRemoveFromSaveSet (dpy
, Event
.xunmap
.window
);
1244 XSelectInput (dpy
, Event
.xunmap
.window
, NoEventMask
);
1245 destroy_window(Tmp_win
); /* do not need to mash event before */
1247 * Flush any pending events for the window.
1249 /* Bzzt! it could be about to re-map */
1250 /* while(XCheckWindowEvent(dpy, Event.xunmap.window,
1251 StructureNotifyMask | PropertyChangeMask |
1252 ColormapChangeMask | VisibilityChangeMask |
1253 EnterWindowMask | LeaveWindowMask, &dummy));
1255 } /* else window no longer exists and we'll get a destroy notify */
1256 MyXUngrabServer(dpy
);
1262 CoerceEnterNotifyOnCurrentWindow();
1264 GNOME_SetClientList();
1268 /***********************************************************************
1271 * HandleButtonPress - ButtonPress event handler
1273 ***********************************************************************/
1274 void HandleButtonPress(void)
1281 DBUG("HandleButtonPress","Routine Entered");
1283 if (!Tmp_win
&& Event
.xany
.window
!= Scr
.Root
)
1285 /* event in unmanaged window or subwindow of a client */
1287 XAllowEvents(dpy
,ReplayPointer
,CurrentTime
);
1291 if (Event
.xbutton
.subwindow
!= None
&&
1292 (Tmp_win
== None
|| Event
.xany
.window
!= Tmp_win
->w
))
1294 eventw
= Event
.xbutton
.subwindow
;
1298 eventw
= Event
.xany
.window
;
1300 if (!XGetGeometry(dpy
, eventw
, &JunkRoot
, &JunkX
, &JunkY
,
1301 &JunkWidth
, &JunkHeight
, &JunkBW
, &JunkDepth
))
1303 /* The window has already died. Just pass the event to the application. */
1305 XAllowEvents(dpy
,ReplayPointer
,CurrentTime
);
1309 if (Tmp_win
&& HAS_NEVER_FOCUS(Tmp_win
))
1311 /* It might seem odd to try to focus a window that never is given focus by
1312 * fvwm, but the window might want to take focus itself, and SetFocus will
1313 * tell it to do so in this case instead of giving it focus. */
1314 SetFocus(Tmp_win
->w
, Tmp_win
, 1);
1316 /* click to focus stuff goes here */
1317 if((Tmp_win
)&&(HAS_CLICK_FOCUS(Tmp_win
))&&(Tmp_win
!= Scr
.Ungrabbed
))
1319 SetFocus(Tmp_win
->w
,Tmp_win
,1);
1320 /* RBW - 12/09/.1999- I'm not sure we need to check both cases, but
1321 I'll leave this as is for now. */
1322 if (!DO_NOT_RAISE_CLICK_FOCUS_CLICK(Tmp_win
)
1324 /* DV - this forces that every focus click on the decorations raises
1325 * the window. This somewhat negates the ClickToFocusRaisesOff style.
1328 ((Event
.xany
.window
!= Tmp_win
->w
)&&
1329 (Event
.xbutton
.subwindow
!= Tmp_win
->w
)&&
1330 (Event
.xany
.window
!= Tmp_win
->Parent
)&&
1331 (Event
.xbutton
.subwindow
!= Tmp_win
->Parent
))
1335 /* We can't raise the window immediately because the action bound to the
1336 * click might be "Lower" or "RaiseLower". So mark the window as scheduled
1337 * to be raised after the binding is executed. Functions that modify the
1338 * stacking order will reset this flag. */
1339 SET_SCHEDULED_FOR_RAISE(Tmp_win
, 1);
1342 Context
= GetContext(Tmp_win
,&Event
, &PressedW
);
1343 if (!IS_ICONIFIED(Tmp_win
) && Context
== C_WINDOW
)
1345 if (Tmp_win
&& IS_SCHEDULED_FOR_RAISE(Tmp_win
))
1347 RaiseWindow(Tmp_win
);
1348 SET_SCHEDULED_FOR_RAISE(Tmp_win
, 0);
1351 /* pass click event to just clicked to focus window? Do not swallow the
1352 * click if the window didn't accept the focus */
1353 if (!DO_NOT_PASS_CLICK_FOCUS_CLICK(Tmp_win
) || Scr
.Focus
!= Tmp_win
)
1355 XAllowEvents(dpy
,ReplayPointer
,CurrentTime
);
1357 else /* don't pass click to just focused window */
1359 XAllowEvents(dpy
,AsyncPointer
,CurrentTime
);
1364 if (!IS_ICONIFIED(Tmp_win
))
1366 DrawDecorations(Tmp_win
, DRAW_ALL
, True
, True
, PressedW
);
1369 else if (Tmp_win
&& Event
.xbutton
.window
== Tmp_win
->Parent
&&
1370 (HAS_SLOPPY_FOCUS(Tmp_win
) || HAS_MOUSE_FOCUS(Tmp_win
) ||
1371 HAS_NEVER_FOCUS(Tmp_win
)) &&
1372 DO_RAISE_MOUSE_FOCUS_CLICK(Tmp_win
))
1374 FvwmWindow
*tmp
= Scr
.Ungrabbed
;
1377 RBW - Release the Parent grab here (whether we raise or not). We
1378 have to wait till this point or we would miss the raise click, which
1379 is not contemporaneous with the focus change.
1380 Scr.Ungrabbed should always be NULL here. I don't know anything
1381 useful we could do if it's not, other than ignore this window.
1383 if (!is_on_top_of_layer(Tmp_win
) &&
1384 MaskUsedModifiers(Event
.xbutton
.state
) == 0)
1386 RaiseWindow(Tmp_win
);
1387 focus_grab_buttons(Tmp_win
, True
);
1388 Scr
.Ungrabbed
= tmp
;
1390 XAllowEvents(dpy
,ReplayPointer
,CurrentTime
);
1394 focus_grab_buttons(Tmp_win
, True
);
1395 Scr
.Ungrabbed
= tmp
;
1399 XAllowEvents(dpy
,ReplayPointer
,CurrentTime
);
1402 Context
= GetContext(Tmp_win
, &Event
, &PressedW
);
1403 LocalContext
= Context
;
1406 if (Context
== C_TITLE
)
1408 Tmp_win
, DRAW_TITLE
, (Scr
.Hilite
== Tmp_win
), True
, None
);
1409 else if (Context
& (C_LALL
| C_RALL
))
1411 Tmp_win
, DRAW_BUTTONS
, (Scr
.Hilite
== Tmp_win
), True
, PressedW
);
1415 Tmp_win
, DRAW_FRAME
, (Scr
.Hilite
== Tmp_win
),
1416 (HAS_DEPRESSABLE_BORDER(Tmp_win
) && PressedW
!= None
), PressedW
);
1420 ButtonWindow
= Tmp_win
;
1422 /* we have to execute a function or pop up a menu */
1423 STROKE_CODE(stroke_init());
1424 STROKE_CODE(send_motion
= TRUE
);
1425 /* need to search for an appropriate mouse binding */
1426 action
= CheckBinding(Scr
.AllBindings
, STROKE_ARG(0) Event
.xbutton
.button
,
1427 Event
.xbutton
.state
, GetUnusedModifiers(), Context
,
1429 if (action
!= NULL
&& (action
[0] != 0))
1432 action
, Tmp_win
, &Event
, Context
, -1, FUNC_DO_SYNC_BUTTONS
, NULL
);
1437 * do gnome buttonpress forwarding if win == root
1439 if (Scr
.Root
== Event
.xany
.window
)
1441 GNOME_ProxyButtonEvent(&Event
);
1445 if (ButtonWindow
&& IS_SCHEDULED_FOR_RAISE(ButtonWindow
))
1447 /* now that we know the action did not restack the window we can raise it.
1449 RaiseWindow(ButtonWindow
);
1450 SET_SCHEDULED_FOR_RAISE(ButtonWindow
, 0);
1453 OldPressedW
= PressedW
;
1455 if (ButtonWindow
&& check_if_fvwm_window_exists(ButtonWindow
))
1457 if (LocalContext
== C_TITLE
)
1459 ButtonWindow
, DRAW_TITLE
, (Scr
.Hilite
== ButtonWindow
), True
, None
);
1460 else if (LocalContext
& (C_LALL
| C_RALL
))
1462 ButtonWindow
, DRAW_BUTTONS
, (Scr
.Hilite
== ButtonWindow
), True
,
1466 ButtonWindow
, DRAW_FRAME
, (Scr
.Hilite
== ButtonWindow
),
1467 HAS_DEPRESSABLE_BORDER(ButtonWindow
), None
);
1469 ButtonWindow
= NULL
;
1470 /* Release any automatic or passive grabs */
1471 XUngrabPointer(dpy
, CurrentTime
);
1475 /***********************************************************************
1478 * HandleButtonRelease - ButtonRelease event handler
1480 ************************************************************************/
1481 void HandleButtonRelease()
1487 DBUG("HandleButtonRelease","Routine Entered");
1489 send_motion
= FALSE
;
1490 stroke_trans (sequence
);
1492 DBUG("HandleButtonRelease",sequence
);
1494 Context
= GetContext(Tmp_win
,&Event
, &dummy
);
1496 /* Allows modifier to work (Only R context works here). */
1497 real_modifier
= Event
.xbutton
.state
- (1 << (7 + Event
.xbutton
.button
));
1499 /* need to search for an appropriate stroke binding */
1500 action
= CheckBinding(
1501 Scr
.AllBindings
, sequence
, Event
.xbutton
.button
, real_modifier
,
1502 GetUnusedModifiers(), Context
, STROKE_BINDING
);
1503 /* got a match, now process it */
1504 if (action
!= NULL
&& (action
[0] != 0))
1507 action
, Tmp_win
, &Event
, Context
, -1, FUNC_DO_SYNC_BUTTONS
, NULL
);
1512 * do gnome buttonpress forwarding if win == root
1514 if (Scr
.Root
== Event
.xany
.window
)
1516 GNOME_ProxyButtonEvent(&Event
);
1522 /***********************************************************************
1525 * HandleMotionNotify - MotionNotify event handler
1527 ************************************************************************/
1528 void HandleMotionNotify()
1530 DBUG("HandleMotionNotify","Routine Entered");
1532 if (send_motion
== TRUE
)
1533 stroke_record (Event
.xmotion
.x
,Event
.xmotion
.y
);
1536 #endif /* HAVE_STROKE */
1538 /***********************************************************************
1541 * HandleEnterNotify - EnterNotify event handler
1543 ************************************************************************/
1544 void HandleEnterNotify(void)
1546 XEnterWindowEvent
*ewp
= &Event
.xcrossing
;
1549 DBUG("HandleEnterNotify","Routine Entered");
1551 /* Ignore EnterNotify events while a window is resized or moved as a wire
1552 * frame; otherwise the window list may be screwed up. */
1553 if (Scr
.flags
.is_wire_frame_displayed
)
1556 /* look for a matching leaveNotify which would nullify this enterNotify */
1557 if(XCheckTypedWindowEvent (dpy
, ewp
->window
, LeaveNotify
, &d
))
1560 * RBW - if we're in startup, this is a coerced focus, so we don't
1561 * want to save the event time, or exit prematurely.
1563 if (!fFvwmInStartup
)
1566 if((d
.xcrossing
.mode
==NotifyNormal
)&&
1567 (d
.xcrossing
.detail
!=NotifyInferior
))
1572 /* an EnterEvent in one of the PanFrameWindows activates the Paging */
1573 if (ewp
->window
==Scr
.PanFrameTop
.win
1574 || ewp
->window
==Scr
.PanFrameLeft
.win
1575 || ewp
->window
==Scr
.PanFrameRight
.win
1576 || ewp
->window
==Scr
.PanFrameBottom
.win
)
1578 int delta_x
=0, delta_y
=0;
1579 /* this was in the HandleMotionNotify before, HEDU */
1580 HandlePaging(Scr
.EdgeScrollX
,Scr
.EdgeScrollY
,
1581 &ewp
->x_root
,&ewp
->y_root
,
1582 &delta_x
,&delta_y
,True
,True
,False
);
1586 if (ewp
->window
== Scr
.Root
)
1588 if (!Scr
.Focus
|| HAS_MOUSE_FOCUS(Scr
.Focus
))
1590 SetFocus(Scr
.NoFocusWin
,NULL
,1);
1592 if (Scr
.ColormapFocus
== COLORMAP_FOLLOWS_MOUSE
)
1594 InstallWindowColormaps(NULL
);
1599 /* make sure its for one of our windows */
1602 /* handle a subwindow cmap */
1603 EnterSubWindowColormap(Event
.xany
.window
);
1607 if (HAS_MOUSE_FOCUS(Tmp_win
) || HAS_SLOPPY_FOCUS(Tmp_win
))
1609 SetFocus(Tmp_win
->w
,Tmp_win
,1);
1611 else if (HAS_NEVER_FOCUS(Tmp_win
))
1613 /* Give the window a chance to grab the buttons needed for raise-on-click */
1614 if (Scr
.Focus
!= Tmp_win
)
1616 focus_grab_buttons(Tmp_win
, False
);
1617 focus_grab_buttons(Scr
.Focus
, True
);
1620 else if (HAS_CLICK_FOCUS(Tmp_win
) && Tmp_win
== Scr
.Focus
&&
1621 do_accept_input_focus(Tmp_win
))
1623 /* We have to refresh the focus window here in case we left the focused
1624 * fvwm window. Motif apps may lose the input focus otherwise. But do not
1625 * try to refresh the focus of applications that want to handle it
1627 FOCUS_SET(Tmp_win
->w
);
1629 if (Scr
.ColormapFocus
== COLORMAP_FOLLOWS_MOUSE
)
1631 if((!IS_ICONIFIED(Tmp_win
))&&(Event
.xany
.window
== Tmp_win
->w
))
1632 InstallWindowColormaps(Tmp_win
);
1634 InstallWindowColormaps(NULL
);
1637 /* We get an EnterNotify with mode == UnGrab when fvwm releases
1638 the grab held during iconification. We have to ignore this,
1639 or icon title will be initially raised. */
1640 if (IS_ICONIFIED(Tmp_win
) && (ewp
->mode
== NotifyNormal
))
1642 SET_ICON_ENTERED(Tmp_win
,1);
1643 DrawIconWindow(Tmp_win
);
1650 /***********************************************************************
1653 * HandleLeaveNotify - LeaveNotify event handler
1655 ************************************************************************/
1656 void HandleLeaveNotify(void)
1658 DBUG("HandleLeaveNotify","Routine Entered");
1660 /* Ignore LeaveNotify events while a window is resized or moved as a wire
1661 * frame; otherwise the window list may be screwed up. */
1662 if (Scr
.flags
.is_wire_frame_displayed
)
1665 /* CDE-like behaviour of raising the icon title if the icon
1666 gets the focus (in particular if the cursor is over the icon) */
1667 if (Tmp_win
&& IS_ICONIFIED(Tmp_win
))
1669 SET_ICON_ENTERED(Tmp_win
,0);
1670 DrawIconWindow (Tmp_win
);
1673 /* If we leave the root window, then we're really moving
1674 * another screen on a multiple screen display, and we
1675 * need to de-focus and unhighlight to make sure that we
1676 * don't end up with more than one highlighted window at a time */
1677 if(Event
.xcrossing
.window
== Scr
.Root
1678 /* domivogt (16-May-2000): added this test because somehow fvwm sometimes
1679 * gets a LeaveNotify on the root window although it is single screen. */
1680 && Scr
.NumberOfScreens
> 1)
1682 if(Event
.xcrossing
.mode
== NotifyNormal
)
1684 if (Event
.xcrossing
.detail
!= NotifyInferior
)
1686 if(Scr
.Focus
!= NULL
)
1687 SetFocus(Scr
.NoFocusWin
, NULL
, 1);
1688 if(Scr
.Hilite
!= NULL
)
1689 DrawDecorations(Scr
.Hilite
, DRAW_ALL
, False
, True
, None
);
1695 /* handle a subwindow cmap */
1696 LeaveSubWindowColormap(Event
.xany
.window
);
1702 /***********************************************************************
1705 * HandleConfigureRequest - ConfigureRequest event handler
1707 ************************************************************************/
1708 void HandleConfigureRequest(void)
1721 XConfigureRequestEvent
*cre
= &Event
.xconfigurerequest
;
1722 Bool do_send_event
= False
;
1724 DBUG("HandleConfigureRequest","Routine Entered");
1727 * Event.xany.window is Event.xconfigurerequest.parent, so Tmp_win will
1730 Event
.xany
.window
= cre
->window
; /* mash parent field */
1731 if (XFindContext (dpy
, cre
->window
, FvwmContext
, (caddr_t
*) &Tmp_win
) ==
1735 #define EXPERIMENTAL_ANTI_RACE_CONDITION_CODE
1736 #ifdef EXPERIMENTAL_ANTI_RACE_CONDITION_CODE
1737 /* merge all pending ConfigureRequests for the window into a single event */
1741 XConfigureRequestEvent
*ecre
;
1745 while (XCheckTypedWindowEvent(dpy
, cre
->window
, ConfigureRequest
, &e
))
1749 const unsigned long xm
= CWX
| CWWidth
;
1750 const unsigned long ym
= CWY
| CWHeight
;
1752 ecre
= &e
.xconfigurerequest
;
1753 vma
= cre
->value_mask
& ecre
->value_mask
;
1754 vmo
= cre
->value_mask
| ecre
->value_mask
;
1755 if (((vma
& xm
) == 0 && (vmo
& xm
) == xm
) ||
1756 ((vma
& ym
) == 0 && (vmo
& ym
) == ym
))
1758 /* can't merge events since location of window might get screwed up */
1759 XPutBackEvent(dpy
, &e
);
1762 if (ecre
->value_mask
& CWX
)
1764 cre
->value_mask
|= CWX
;
1767 if (ecre
->value_mask
& CWY
)
1769 cre
->value_mask
|= CWY
;
1772 if (ecre
->value_mask
& CWWidth
)
1774 cre
->value_mask
|= CWWidth
;
1775 cre
->width
= ecre
->width
;
1777 if (ecre
->value_mask
& CWHeight
)
1779 cre
->value_mask
|= CWHeight
;
1780 cre
->height
= ecre
->height
;
1782 if (ecre
->value_mask
& CWBorderWidth
)
1784 cre
->value_mask
|= CWBorderWidth
;
1785 cre
->border_width
= ecre
->border_width
;
1787 if (ecre
->value_mask
& CWStackMode
)
1789 cre
->value_mask
&= !CWStackMode
;
1790 cre
->value_mask
|= (ecre
->value_mask
& CWStackMode
);
1791 cre
->above
= ecre
->above
;
1792 cre
->detail
= ecre
->detail
;
1799 * According to the July 27, 1988 ICCCM draft, we should ignore size and
1800 * position fields in the WM_NORMAL_HINTS property when we map a window.
1801 * Instead, we'll read the current geometry. Therefore, we should respond
1802 * to configuration requests for windows which have never been mapped.
1804 if (!Tmp_win
|| cre
->window
== Tmp_win
->icon_w
||
1805 cre
->window
== Tmp_win
->icon_pixmap_w
)
1807 xwcm
= cre
->value_mask
&
1808 (CWX
| CWY
| CWWidth
| CWHeight
| CWBorderWidth
);
1811 if((Tmp_win
)&&((Tmp_win
->icon_pixmap_w
== cre
->window
)))
1813 Tmp_win
->icon_p_height
= cre
->height
+ cre
->border_width
+
1816 else if((Tmp_win
)&&((Tmp_win
->icon_w
== cre
->window
)))
1818 Tmp_win
->icon_xl_loc
= cre
->x
;
1819 Tmp_win
->icon_g
.x
= cre
->x
+
1820 (Tmp_win
->icon_g
.width
- Tmp_win
->icon_p_width
)/2;
1821 Tmp_win
->icon_g
.y
= cre
->y
- Tmp_win
->icon_p_height
;
1822 if(!IS_ICON_UNMAPPED(Tmp_win
))
1823 BroadcastPacket(M_ICON_LOCATION
, 7,
1824 Tmp_win
->w
, Tmp_win
->frame
,
1825 (unsigned long)Tmp_win
,
1826 Tmp_win
->icon_g
.x
, Tmp_win
->icon_g
.y
,
1827 Tmp_win
->icon_p_width
,
1828 Tmp_win
->icon_g
.height
+ Tmp_win
->icon_p_height
);
1830 xwc
.width
= cre
->width
;
1831 xwc
.height
= cre
->height
;
1832 xwc
.border_width
= cre
->border_width
;
1834 XConfigureWindow(dpy
, Event
.xany
.window
, xwcm
, &xwc
);
1838 if (cre
->window
!= Tmp_win
->icon_pixmap_w
&&
1839 Tmp_win
->icon_pixmap_w
!= None
)
1841 xwc
.x
= Tmp_win
->icon_g
.x
;
1842 xwc
.y
= Tmp_win
->icon_g
.y
- Tmp_win
->icon_p_height
;
1843 xwcm
= cre
->value_mask
& (CWX
| CWY
);
1844 XConfigureWindow(dpy
, Tmp_win
->icon_pixmap_w
, xwcm
, &xwc
);
1846 if(Tmp_win
->icon_w
!= None
)
1848 xwc
.x
= Tmp_win
->icon_g
.x
;
1849 xwc
.y
= Tmp_win
->icon_g
.y
;
1850 xwcm
= cre
->value_mask
& (CWX
| CWY
);
1851 XConfigureWindow(dpy
, Tmp_win
->icon_w
, xwcm
, &xwc
);
1859 if (ShapesSupported
)
1861 int xws
, yws
, xbs
, ybs
;
1862 unsigned wws
, hws
, wbs
, hbs
;
1863 int boundingShaped
, clipShaped
;
1865 if (XShapeQueryExtents(dpy
, Tmp_win
->w
,&boundingShaped
, &xws
, &yws
, &wws
,
1866 &hws
,&clipShaped
, &xbs
, &ybs
, &wbs
, &hbs
))
1868 Tmp_win
->wShaped
= boundingShaped
;
1872 Tmp_win
->wShaped
= 0;
1877 if (cre
->window
== Tmp_win
->w
)
1880 fprintf(stderr
, "cre: %d(%d) %d(%d) %d(%d)x%d(%d)\n",
1881 cre
->x
, (int)(cre
->value_mask
& CWX
),
1882 cre
->y
, (int)(cre
->value_mask
& CWY
),
1883 cre
->width
, (int)(cre
->value_mask
& CWWidth
),
1884 cre
->height
, (int)(cre
->value_mask
& CWHeight
));
1886 /* Don't modify frame_XXX fields before calling SetupWindow! */
1893 if (cre
->value_mask
& CWBorderWidth
)
1895 Tmp_win
->old_bw
= cre
->border_width
;
1897 /* override even if border change */
1899 if (cre
->value_mask
& CWX
)
1900 dx
= cre
->x
- Tmp_win
->frame_g
.x
- Tmp_win
->boundary_width
;
1901 if (cre
->value_mask
& CWY
)
1902 dy
= cre
->y
- Tmp_win
->frame_g
.y
- Tmp_win
->boundary_width
-
1903 Tmp_win
->title_g
.height
;
1904 if (cre
->value_mask
& CWWidth
)
1905 dw
= cre
->width
- (Tmp_win
->frame_g
.width
- 2 * Tmp_win
->boundary_width
);
1907 if (cre
->value_mask
& CWHeight
)
1909 if (cre
->height
< (WINDOW_FREAKED_OUT_HEIGHT
- Tmp_win
->title_g
.height
-
1910 2 * Tmp_win
->boundary_width
))
1912 dh
= cre
->height
- (Tmp_win
->frame_g
.height
-
1913 2 * Tmp_win
->boundary_width
-
1914 Tmp_win
->title_g
.height
);
1918 /* patch to ignore height changes to astronomically large windows
1919 * (needed for XEmacs 20.4); don't care if the window is shaded here -
1920 * we won't use 'height' in this case anyway */
1921 /* inform the buggy app about the size that *we* want */
1922 do_send_event
= True
;
1927 * SetupWindow (x,y) are the location of the upper-left outer corner and
1928 * are passed directly to XMoveResizeWindow (frame). The (width,height)
1929 * are the inner size of the frame. The inner width is the same as the
1930 * requested client window width; the inner height is the same as the
1931 * requested client window height plus any title bar slop.
1933 new_g
= Tmp_win
->frame_g
;
1934 if (IS_SHADED(Tmp_win
))
1935 new_g
.height
= Tmp_win
->normal_g
.height
;
1936 oldnew_w
= new_g
.width
+ dw
;
1937 oldnew_h
= new_g
.height
+ dh
;
1938 constr_w
= oldnew_w
;
1939 constr_h
= oldnew_h
;
1941 Tmp_win
, (unsigned int *)&constr_w
, (unsigned int *)&constr_h
, 0, 0,
1943 dw
+= (constr_w
- oldnew_w
);
1944 dh
+= (constr_h
- oldnew_h
);
1947 new_g
.x
= Tmp_win
->frame_g
.x
+ dx
;
1948 new_g
.width
= Tmp_win
->frame_g
.width
+ dw
;
1952 new_g
.x
= Tmp_win
->frame_g
.x
+ dx
;
1956 gravity_resize(Tmp_win
->hints
.win_gravity
, &new_g
, dw
, 0);
1960 new_g
.y
= Tmp_win
->frame_g
.y
+ dy
;
1961 new_g
.height
= Tmp_win
->frame_g
.height
+ dh
;
1965 new_g
.y
= Tmp_win
->frame_g
.y
+ dy
;
1969 gravity_resize(Tmp_win
->hints
.win_gravity
, &new_g
, 0, dh
);
1972 /* dont allow clients to resize maximized windows */
1973 if (!IS_MAXIMIZED(Tmp_win
) || (!dw
&& !dh
))
1975 if (IS_SHADED(Tmp_win
))
1976 get_shaded_geometry(Tmp_win
, &new_g
, &new_g
);
1978 Tmp_win
, new_g
.x
, new_g
.y
, new_g
.width
, new_g
.height
, False
);
1980 /* make sure the window structure has the new position */
1981 update_absolute_geometry(Tmp_win
);
1982 maximize_adjust_offset(Tmp_win
);
1983 GNOME_SetWinArea(Tmp_win
);
1986 /* Stacking order change requested... */
1987 /* Handle this *after* geometry changes, since we need the new
1988 geometry in occlusion calculations */
1989 if ( (cre
->value_mask
& CWStackMode
) && !DO_IGNORE_RESTACK(Tmp_win
) )
1991 FvwmWindow
*otherwin
= NULL
;
1993 if (cre
->value_mask
& CWSibling
)
1995 if (XFindContext (dpy
, cre
->above
, FvwmContext
,
1996 (caddr_t
*) &otherwin
) == XCNOENT
)
2002 if ((cre
->detail
!= Above
) && (cre
->detail
!= Below
))
2004 HandleUnusualStackmodes (cre
->detail
, Tmp_win
, cre
->window
,
2005 otherwin
, cre
->above
);
2007 /* only allow clients to restack windows within their layer */
2008 else if (!otherwin
|| compare_window_layers(otherwin
, Tmp_win
) != 0)
2010 switch (cre
->detail
)
2013 RaiseWindow (Tmp_win
);
2016 LowerWindow (Tmp_win
);
2022 xwc
.sibling
= otherwin
->frame
;
2023 xwc
.stack_mode
= cre
->detail
;
2024 xwcm
= CWSibling
| CWStackMode
;
2025 XConfigureWindow (dpy
, Tmp_win
->frame
, xwcm
, &xwc
);
2027 /* Maintain the condition that icon windows are stacked
2028 immediately below their frame */
2029 /* 1. for Tmp_win */
2030 xwc
.sibling
= Tmp_win
->frame
;
2031 xwc
.stack_mode
= Below
;
2032 xwcm
= CWSibling
| CWStackMode
;
2033 if (Tmp_win
->icon_w
!= None
)
2035 XConfigureWindow(dpy
, Tmp_win
->icon_w
, xwcm
, &xwc
);
2037 if (Tmp_win
->icon_pixmap_w
!= None
)
2039 XConfigureWindow(dpy
, Tmp_win
->icon_pixmap_w
, xwcm
, &xwc
);
2042 /* 2. for otherwin */
2043 if (cre
->detail
== Below
)
2045 xwc
.sibling
= otherwin
->frame
;
2046 xwc
.stack_mode
= Below
;
2047 xwcm
= CWSibling
| CWStackMode
;
2048 if (otherwin
->icon_w
!= None
)
2050 XConfigureWindow(dpy
, otherwin
->icon_w
, xwcm
, &xwc
);
2052 if (otherwin
->icon_pixmap_w
!= None
)
2054 XConfigureWindow(dpy
, otherwin
->icon_pixmap_w
, xwcm
, &xwc
);
2058 /* Maintain the stacking order ring */
2059 if (cre
->detail
== Above
)
2061 remove_window_from_stack_ring(Tmp_win
);
2062 add_window_to_stack_ring_after(
2063 Tmp_win
, get_prev_window_in_stack_ring(otherwin
));
2065 else /* cre->detail == Below */
2067 remove_window_from_stack_ring(Tmp_win
);
2068 add_window_to_stack_ring_after(Tmp_win
, otherwin
);
2072 Let the modules know that Tmp_win changed its place
2073 in the stacking order
2075 BroadcastRestackThisWindow(Tmp_win
);
2080 /* This causes some ddd windows not to be drawn properly. Reverted back to
2081 * the old method in SetupFrame. */
2082 /* domivogt (15-Oct-1999): enabled this to work around buggy apps that
2083 * ask for a nonsense height and expect that they really get it. */
2086 SendConfigureNotify(
2087 Tmp_win
, Tmp_win
->frame_g
.x
, Tmp_win
->frame_g
.y
,
2088 new_g
.width
, new_g
.height
, cre
->border_width
, True
);
2094 /***********************************************************************
2097 * SendConfigureNotify - inform a client window of its geometry.
2099 * The input (frame) geometry will be translated to client geometry
2102 ************************************************************************/
2103 void SendConfigureNotify(
2104 FvwmWindow
*tmp_win
, int x
, int y
, unsigned int w
, unsigned int h
, int bw
,
2105 Bool send_for_frame_too
)
2107 if (!tmp_win
|| IS_SHADED(tmp_win
))
2110 XEvent client_event
;
2112 client_event
.type
= ConfigureNotify
;
2113 client_event
.xconfigure
.display
= dpy
;
2114 client_event
.xconfigure
.event
= tmp_win
->w
;
2115 client_event
.xconfigure
.window
= tmp_win
->w
;
2116 client_event
.xconfigure
.x
= x
+ tmp_win
->boundary_width
;
2117 client_event
.xconfigure
.y
= y
+ tmp_win
->boundary_width
+
2118 ((HAS_BOTTOM_TITLE(tmp_win
)) ? 0 : tmp_win
->title_g
.height
);
2119 client_event
.xconfigure
.width
= w
- 2 * tmp_win
->boundary_width
;
2120 client_event
.xconfigure
.height
= h
-
2121 2 * tmp_win
->boundary_width
- tmp_win
->title_g
.height
;
2122 client_event
.xconfigure
.border_width
= bw
;
2123 client_event
.xconfigure
.above
= tmp_win
->frame
;
2124 client_event
.xconfigure
.override_redirect
= False
;
2125 XSendEvent(dpy
, tmp_win
->w
, False
, StructureNotifyMask
, &client_event
);
2126 if (send_for_frame_too
)
2128 /* This is for buggy tk, which waits for the real ConfigureNotify
2129 * on frame instead of the synthetic one on w. The geometry data
2130 * in the event will not be correct for the frame, but tk doesn't
2131 * look at that data anyway. */
2132 client_event
.xconfigure
.event
= tmp_win
->frame
;
2133 client_event
.xconfigure
.window
= tmp_win
->frame
;
2134 XSendEvent(dpy
, tmp_win
->frame
, False
,StructureNotifyMask
,&client_event
);
2139 /***********************************************************************
2142 * HandleShapeNotify - shape notification event handler
2144 ***********************************************************************/
2146 void HandleShapeNotify (void)
2148 DBUG("HandleShapeNotify","Routine Entered");
2150 if (ShapesSupported
)
2152 XShapeEvent
*sev
= (XShapeEvent
*) &Event
;
2156 if (sev
->kind
!= ShapeBounding
)
2158 Tmp_win
->wShaped
= sev
->shaped
;
2159 SetShape(Tmp_win
,Tmp_win
->frame_g
.width
);
2164 /***********************************************************************
2167 * HandleVisibilityNotify - record fully visible windows for
2168 * use in the RaiseLower function and the OnTop type windows.
2170 ************************************************************************/
2171 void HandleVisibilityNotify(void)
2173 XVisibilityEvent
*vevent
= (XVisibilityEvent
*) &Event
;
2175 DBUG("HandleVisibilityNotify","Routine Entered");
2177 if(Tmp_win
&& Tmp_win
->frame
== last_event_window
)
2179 if(vevent
->state
== VisibilityUnobscured
)
2181 SET_FULLY_VISIBLE(Tmp_win
, 1);
2182 SET_PARTIALLY_VISIBLE(Tmp_win
, 1);
2184 else if (vevent
->state
== VisibilityPartiallyObscured
)
2186 SET_FULLY_VISIBLE(Tmp_win
, 0);
2187 SET_PARTIALLY_VISIBLE(Tmp_win
, 1);
2191 SET_FULLY_VISIBLE(Tmp_win
, 0);
2192 SET_PARTIALLY_VISIBLE(Tmp_win
, 0);
2198 /***************************************************************************
2200 * Waits for next X or module event, fires off startup routines when startup
2201 * modules have finished or after a timeout if the user has specified a
2202 * command line module that doesn't quit or gets stuck.
2204 ****************************************************************************/
2207 int My_XNextEvent(Display
*dpy
, XEvent
*event
)
2209 extern fd_set_size_t fd_width
;
2211 fd_set in_fdset
, out_fdset
;
2212 Window targetWindow
;
2214 static struct timeval timeout
= {42, 0};
2215 static struct timeval
*timeoutP
= &timeout
;
2217 DBUG("My_XNextEvent","Routine Entered");
2219 /* include this next bit if HandleModuleInput() gets called anywhere else
2220 * with queueing turned on. Because this routine is the only place that
2221 * queuing is on _and_ ExecuteCommandQueue is always called immediately after
2222 * it is impossible for there to be anything in the queue at this point */
2224 /* execute any commands queued up */
2225 DBUG("My_XNextEvent", "executing module comand queue");
2226 ExecuteCommandQueue()
2229 /* check for any X events already queued up.
2230 * Side effect: this does an XFlush if no events are queued
2231 * Make sure nothing between here and the select causes further X
2232 * requests to be sent or the select may block even though there
2233 * events in the queue */
2235 DBUG("My_XNextEvent","taking care of queued up events & returning (1)");
2236 XNextEvent(dpy
,event
);
2237 StashEventTime(event
);
2241 DBUG("My_XNextEvent","no X events waiting - about to reap children");
2242 /* Zap all those zombies! */
2243 /* If we get to here, then there are no X events waiting to be processed.
2244 * Just take a moment to check for dead children. */
2247 /* check for termination of all startup modules */
2248 if (fFvwmInStartup
) {
2249 for(i
=0;i
<npipes
;i
++)
2250 if (FD_ISSET(i
, &init_fdset
))
2252 if (i
== npipes
|| writePipes
[i
+1] == 0)
2254 DBUG("My_XNextEvent", "Starting up after command lines modules\n");
2255 timeoutP
= NULL
; /* set an infinite timeout to stop ticking */
2256 StartupStuff(); /* This may cause X requests to be sent */
2257 return 0; /* so return without select()ing */
2262 FD_ZERO(&out_fdset
);
2263 FD_SET(x_fd
,&in_fdset
);
2264 /* nothing is done here if fvwm was compiled without session support */
2266 FD_SET(sm_fd
, &in_fdset
);
2267 for(i
=0; i
<npipes
; i
++) {
2269 FD_SET(readPipes
[i
], &in_fdset
);
2270 if(pipeQueue
[i
]!= NULL
)
2271 FD_SET(writePipes
[i
], &out_fdset
);
2274 DBUG("My_XNextEvent","waiting for module input/output");
2275 if (fvwmSelect(fd_width
, &in_fdset
, &out_fdset
, 0, timeoutP
) > 0) {
2277 /* Check for module input. */
2278 for (i
=0; i
<npipes
; i
++) {
2279 if ((readPipes
[i
] >= 0) && FD_ISSET(readPipes
[i
], &in_fdset
)) {
2280 if (read(readPipes
[i
], &targetWindow
, sizeof(Window
)) > 0) {
2281 DBUG("My_XNextEvent","calling HandleModuleInput");
2282 /* Add one module message to the queue */
2283 HandleModuleInput(targetWindow
, i
, NULL
, True
);
2285 DBUG("My_XNextEvent","calling KillModule");
2289 if ((writePipes
[i
] >= 0) && FD_ISSET(writePipes
[i
], &out_fdset
)) {
2290 DBUG("My_XNextEvent","calling FlushMessageQueue");
2291 FlushMessageQueue(i
);
2295 /* execute any commands queued up */
2296 DBUG("My_XNextEvent", "executing module comand queue");
2297 ExecuteCommandQueue();
2299 /* nothing is done here if fvwm was compiled without session support */
2300 if ((sm_fd
>= 0) && (FD_ISSET(sm_fd
, &in_fdset
)))
2304 /* select has timed out, things must have calmed down so let's decorate */
2305 if (fFvwmInStartup
) {
2306 fvwm_msg(ERR
, "My_XNextEvent",
2307 "Some command line modules have not quit, "
2308 "Starting up after timeout.\n");
2310 timeoutP
= NULL
; /* set an infinite timeout to stop ticking */
2311 reset_style_changes();
2312 Scr
.flags
.do_need_window_update
= 0;
2316 /* check for X events again, rather than return 0 and get called again */
2318 DBUG("My_XNextEvent","taking care of queued up events & returning (2)");
2319 XNextEvent(dpy
,event
);
2320 StashEventTime(event
);
2324 DBUG("My_XNextEvent","leaving My_XNextEvent");
2330 ** InitEventHandlerJumpTable
2332 void InitEventHandlerJumpTable(void)
2336 for (i
=0; i
<LASTEvent
; i
++)
2338 EventHandlerJumpTable
[i
] = NULL
;
2340 EventHandlerJumpTable
[Expose
] = HandleExpose
;
2341 EventHandlerJumpTable
[DestroyNotify
] = HandleDestroyNotify
;
2342 EventHandlerJumpTable
[MapRequest
] = HandleMapRequest
;
2343 EventHandlerJumpTable
[MapNotify
] = HandleMapNotify
;
2344 EventHandlerJumpTable
[UnmapNotify
] = HandleUnmapNotify
;
2345 EventHandlerJumpTable
[ButtonPress
] = HandleButtonPress
;
2346 EventHandlerJumpTable
[EnterNotify
] = HandleEnterNotify
;
2347 EventHandlerJumpTable
[LeaveNotify
] = HandleLeaveNotify
;
2348 EventHandlerJumpTable
[FocusIn
] = HandleFocusIn
;
2349 EventHandlerJumpTable
[ConfigureRequest
] = HandleConfigureRequest
;
2350 EventHandlerJumpTable
[ClientMessage
] = HandleClientMessage
;
2351 EventHandlerJumpTable
[PropertyNotify
] = HandlePropertyNotify
;
2352 EventHandlerJumpTable
[KeyPress
] = HandleKeyPress
;
2353 EventHandlerJumpTable
[VisibilityNotify
] = HandleVisibilityNotify
;
2354 EventHandlerJumpTable
[ColormapNotify
] = HandleColormapNotify
;
2356 if (ShapesSupported
)
2357 EventHandlerJumpTable
[ShapeEventBase
+ShapeNotify
] = HandleShapeNotify
;
2359 EventHandlerJumpTable
[SelectionClear
] = HandleSelectionClear
;
2360 EventHandlerJumpTable
[SelectionRequest
] = HandleSelectionRequest
;
2361 STROKE_CODE(EventHandlerJumpTable
[ButtonRelease
] = HandleButtonRelease
);
2362 STROKE_CODE(EventHandlerJumpTable
[MotionNotify
] = HandleMotionNotify
);
2363 #ifdef MOUSE_DROPPINGS
2364 STROKE_CODE(stroke_init(dpy
,DefaultRootWindow(dpy
)));
2365 #else /* no MOUSE_DROPPINGS */
2366 STROKE_CODE(stroke_init());
2367 #endif /* MOUSE_DROPPINGS */
2370 /***********************************************************************
2373 * DispatchEvent - handle a single X event stored in global var Event
2375 ************************************************************************/
2376 void DispatchEvent(Bool preserve_Tmp_win
)
2378 Window w
= Event
.xany
.window
;
2379 FvwmWindow
*s_Tmp_win
= NULL
;
2381 DBUG("DispatchEvent","Routine Entered");
2383 if (preserve_Tmp_win
)
2384 s_Tmp_win
= Tmp_win
;
2385 StashEventTime(&Event
);
2388 if (XFindContext (dpy
, w
, FvwmContext
, (caddr_t
*) &Tmp_win
) == XCNOENT
)
2392 last_event_type
= Event
.type
;
2393 last_event_window
= w
;
2395 if (EventHandlerJumpTable
[Event
.type
])
2397 (*EventHandlerJumpTable
[Event
.type
])();
2401 /* If we're using the C version of alloca, see if anything needs to be
2407 if (preserve_Tmp_win
)
2408 Tmp_win
= s_Tmp_win
;
2409 DBUG("DispatchEvent","Leaving Routine");
2414 /***********************************************************************
2417 * HandleEvents - handle X events
2419 ************************************************************************/
2420 void HandleEvents(void)
2422 DBUG("HandleEvents","Routine Entered");
2423 STROKE_CODE(send_motion
= FALSE
);
2424 while ( !isTerminated
)
2426 last_event_type
= 0;
2427 if (Scr
.flags
.do_need_window_update
)
2429 flush_window_updates();
2431 if (Scr
.flags
.do_need_style_list_update
)
2433 simplify_style_list();
2435 if(My_XNextEvent(dpy
, &Event
))
2437 DispatchEvent(False
);
2442 /***********************************************************************
2445 * Find the Fvwm context for the Event.
2447 ************************************************************************/
2448 int GetContext(FvwmWindow
*t
, XEvent
*e
, Window
*w
)
2452 Context
= C_NO_CONTEXT
;
2453 if (e
->type
== KeyPress
&& e
->xkey
.window
== Scr
.Root
&&
2454 e
->xkey
.subwindow
!= None
)
2456 /* Translate root coordinates into subwindow coordinates. Necessary for
2457 * key bindings that work over unfocused windows. */
2458 e
->xkey
.window
= e
->xkey
.subwindow
;
2459 XTranslateCoordinates(
2460 dpy
, Scr
.Root
, e
->xkey
.subwindow
, e
->xkey
.x
, e
->xkey
.y
, &(e
->xkey
.x
),
2461 &(e
->xkey
.y
), &(e
->xkey
.subwindow
));
2462 XFindContext(dpy
, e
->xkey
.window
, FvwmContext
, (caddr_t
*) &t
);
2465 if (e
->type
== ButtonPress
&& t
&& e
->xkey
.window
== t
->frame
&&
2466 e
->xkey
.subwindow
!= None
)
2468 /* Translate frame coordinates into subwindow coordinates. */
2469 e
->xkey
.window
= e
->xkey
.subwindow
;
2470 XTranslateCoordinates(
2471 dpy
, t
->frame
, e
->xkey
.subwindow
, e
->xkey
.x
, e
->xkey
.y
, &(e
->xkey
.x
),
2472 &(e
->xkey
.y
), &(e
->xkey
.subwindow
));
2473 if (e
->xkey
.window
== t
->Parent
)
2475 e
->xkey
.window
= e
->xkey
.subwindow
;
2476 XTranslateCoordinates(
2477 dpy
, t
->Parent
, e
->xkey
.subwindow
, e
->xkey
.x
, e
->xkey
.y
, &(e
->xkey
.x
),
2478 &(e
->xkey
.y
), &(e
->xkey
.subwindow
));
2484 if (e
->type
== KeyPress
&& e
->xkey
.window
== t
->frame
&&
2485 e
->xkey
.subwindow
== t
->decor_w
)
2487 /* We can't get keyboard events on the decor_w directly beacause it is a
2488 * sibling of the parent window which gets all keyboard input. So we have to
2489 * grab keys on the frame and then translate the coordinates to find out in
2490 * which subwindow of the decor_w the event occured. */
2491 e
->xkey
.window
= e
->xkey
.subwindow
;
2492 XTranslateCoordinates(dpy
, t
->frame
, t
->decor_w
, e
->xkey
.x
, e
->xkey
.y
,
2493 &JunkX
, &JunkY
, &(e
->xkey
.subwindow
));
2497 if (*w
== Scr
.NoFocusWin
)
2499 if (e
->type
== KeyPress
&& e
->xkey
.window
== t
->frame
&&
2500 e
->xkey
.subwindow
== t
->decor_w
)
2502 /* We can't get keyboard events on the decor_w directly beacause it is a
2503 * sibling of the parent window which gets all keyboard input. So we have to
2504 * grab keys on the frame and then translate the coordinates to find out in
2505 * which subwindow of the decor_w the event occured. */
2506 e
->xkey
.window
= e
->xkey
.subwindow
;
2507 XTranslateCoordinates(dpy
, t
->frame
, t
->decor_w
, e
->xkey
.x
, e
->xkey
.y
,
2508 &JunkX
, &JunkY
, &(e
->xkey
.subwindow
));
2512 if (*w
== Scr
.NoFocusWin
)
2514 if (e
->xkey
.subwindow
!= None
&& e
->xany
.window
!= t
->w
)
2515 *w
= e
->xkey
.subwindow
;
2520 if (*w
== t
->title_w
)
2522 else if (*w
== t
->w
|| *w
== t
->Parent
|| *w
== t
->frame
)
2524 else if (*w
== t
->icon_w
|| *w
== t
->icon_pixmap_w
)
2526 else if (*w
== t
->decor_w
)
2527 Context
= C_SIDEBAR
;
2532 if(*w
== t
->corners
[i
])
2537 if(*w
== t
->sides
[i
])
2539 Context
= C_SIDEBAR
;
2547 for (i
= 0; i
< NUMBER_OF_BUTTONS
; i
++)
2549 if (*w
== t
->button_w
[i
])
2551 if ((!(i
& 1) && i
/ 2 < Scr
.nr_left_buttons
) ||
2552 ( (i
& 1) && i
/ 2 < Scr
.nr_right_buttons
))
2554 Context
= (1 << i
) * C_L1
;
2567 /**************************************************************************
2569 * Removes expose events for a specific window from the queue
2571 *************************************************************************/
2572 int flush_expose (Window w
)
2577 while (XCheckTypedWindowEvent (dpy
, w
, Expose
, &dummy
))
2583 /**************************************************************************
2585 * Removes all expose events from the queue and does the necessary redraws
2587 *************************************************************************/
2588 void handle_all_expose(void)
2592 memcpy(&old_event
, &Event
, sizeof(XEvent
));
2594 while (XCheckMaskEvent(dpy
, ExposureMask
, &Event
))
2596 DispatchEvent(True
);
2598 memcpy(&Event
, &old_event
, sizeof(XEvent
));
2604 /****************************************************************************
2606 * Records the time of the last processed event. Used in XSetInputFocus
2608 ****************************************************************************/
2609 Bool
StashEventTime (XEvent
*ev
)
2611 Time NewTimestamp
= CurrentTime
;
2617 NewTimestamp
= ev
->xkey
.time
;
2621 NewTimestamp
= ev
->xbutton
.time
;
2624 NewTimestamp
= ev
->xmotion
.time
;
2628 NewTimestamp
= ev
->xcrossing
.time
;
2630 case PropertyNotify
:
2631 NewTimestamp
= ev
->xproperty
.time
;
2633 case SelectionClear
:
2634 NewTimestamp
= ev
->xselectionclear
.time
;
2636 case SelectionRequest
:
2637 NewTimestamp
= ev
->xselectionrequest
.time
;
2639 case SelectionNotify
:
2640 NewTimestamp
= ev
->xselection
.time
;
2645 /* Only update if the new timestamp is later than the old one, or
2646 * if the new one is from a time at least 30 seconds earlier than the
2647 * old one (in which case the system clock may have changed) */
2648 if (NewTimestamp
> lastTimestamp
||
2649 lastTimestamp
- NewTimestamp
> CLOCK_SKEW_MS
)
2650 lastTimestamp
= NewTimestamp
;
2654 /* CoerceEnterNotifyOnCurrentWindow()
2655 * Pretends to get a HandleEnterNotify on the
2656 * window that the pointer currently is in so that
2657 * the focus gets set correctly from the beginning
2658 * Note that this presently only works if the current
2659 * window is not click_to_focus; I think that
2660 * that behaviour is correct and desirable. --11/08/97 gjb */
2661 void CoerceEnterNotifyOnCurrentWindow(void)
2663 extern FvwmWindow
*Tmp_win
; /* from events.c */
2667 Bool f
= XQueryPointer(dpy
, Scr
.Root
, &root
,
2668 &child
, &root_x
, &root_y
, &win_x
, &win_y
, &JunkMask
);
2669 if (f
&& child
!= None
) {
2670 Event
.xany
.window
= child
;
2671 if (XFindContext(dpy
, child
, FvwmContext
, (caddr_t
*) &Tmp_win
) == XCNOENT
)
2673 HandleEnterNotify();