2 /* This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 /* This module is based on Twm, but has been siginificantly modified
20 * Copyright 1988 by Evans & Sutherland Computer Corporation,
21 * Salt Lake City, Utah
22 * Portions Copyright 1989 by the Massachusetts Institute of Technology
23 * Cambridge, Massachusetts
27 * Permission to use, copy, modify, and distribute this software and
28 * its documentation for any purpose and without fee is hereby
29 * granted, provided that the above copyright notice appear in all
30 * copies and that both that copyright notice and this permis-
31 * sion notice appear in supporting documentation, and that the
32 * names of Evans & Sutherland and M.I.T. not be used in advertising
33 * in publicity pertaining to distribution of the software without
34 * specific, written prior permission.
36 * EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD
37 * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
38 * ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND OR
39 * M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM-
40 * AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
41 * OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
42 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
43 * OR PERFORMANCE OF THIS SOFTWARE.
46 /* ---------------------------- included header files ---------------------- */
50 #if HAVE_SYS_BSDTYPES_H
51 #include <sys/bsdtypes.h>
56 #include <X11/Xatom.h>
58 #include "libs/ftime.h"
59 #include "libs/fvwmlib.h"
60 #include "libs/System.h"
61 #include "libs/Grab.h"
62 #include "libs/Parse.h"
63 #include "libs/ColorUtils.h"
64 #include "libs/FShape.h"
65 #include "libs/PictureBase.h"
66 #include "libs/Colorset.h"
67 #include "libs/charmap.h"
68 #include "libs/wcontext.h"
72 #include "functions.h"
78 #include "eventhandler.h"
79 #include "eventmask.h"
80 #include "libs/fvwmsignal.h"
81 #include "module_list.h"
82 #include "module_interface.h"
86 #include "add_window.h"
97 #include "decorations.h"
100 #include "colormaps.h"
101 #include "colorset.h"
104 #endif /* HAVE_STROKE */
106 /* ---------------------------- local definitions -------------------------- */
109 #define XUrgencyHint (1L << 8)
113 ** LASTEvent is the number of X events defined - it should be defined
114 ** in X.h (to be like 35), but since extension (eg SHAPE) events are
115 ** numbered beyond LASTEvent, we need to use a bigger number than the
116 ** default, so let's undefine the default and use 256 instead.
119 #define LASTEvent 256
121 #define CR_MOVERESIZE_MASK (CWX | CWY | CWWidth | CWHeight | CWBorderWidth)
123 /* ---------------------------- local macros ------------------------------- */
125 /* ---------------------------- imports ------------------------------------ */
127 extern void StartupStuff(void);
129 /* ---------------------------- included code files ------------------------ */
131 /* ---------------------------- local types -------------------------------- */
133 typedef void (*PFEH
)(const evh_args_t
*ea
);
139 Bool do_return_true_cr
;
140 unsigned long cr_value_mask
;
142 unsigned long ret_type
;
143 } check_if_event_args
;
147 unsigned do_forbid_function
: 1;
148 unsigned do_focus
: 1;
149 unsigned do_swallow_click
: 1;
150 unsigned do_raise
: 1;
153 /* ---------------------------- forward declarations ----------------------- */
155 /* ---------------------------- local variables ---------------------------- */
157 static int Button
= 0;
158 static const FvwmWindow
*xcrossing_last_grab_window
= NULL
;
159 STROKE_CODE(static int send_motion
);
160 STROKE_CODE(static char sequence
[STROKE_MAX_SEQUENCE
+ 1]);
161 static PFEH EventHandlerJumpTable
[LASTEvent
];
163 /* ---------------------------- exported variables (globals) --------------- */
165 int last_event_type
= 0;
166 Window PressedW
= None
;
168 /* ---------------------------- local functions ---------------------------- */
170 static void fake_map_unmap_notify(const FvwmWindow
*fw
, int event_type
)
173 XWindowAttributes winattrs
= {0};
175 if (!XGetWindowAttributes(dpy
, FW_W(fw
), &winattrs
))
181 winattrs
.your_event_mask
& ~StructureNotifyMask
);
182 client_event
.type
= event_type
;
183 client_event
.xmap
.display
= dpy
;
184 client_event
.xmap
.event
= FW_W(fw
);
185 client_event
.xmap
.window
= FW_W(fw
);
189 client_event
.xmap
.override_redirect
= False
;
192 client_event
.xunmap
.from_configure
= False
;
195 /* not possible if called correctly */
199 dpy
, FW_W(fw
), False
, StructureNotifyMask
, &client_event
);
200 XSelectInput(dpy
, FW_W(fw
), winattrs
.your_event_mask
);
206 static Bool
test_map_request(
207 Display
*display
, XEvent
*event
, XPointer arg
)
209 check_if_event_args
*cie_args
;
212 cie_args
= (check_if_event_args
*)arg
;
213 cie_args
->ret_does_match
= False
;
214 if (event
->type
== MapRequest
&&
215 event
->xmaprequest
.window
== cie_args
->w
)
217 cie_args
->ret_type
= MapRequest
;
218 cie_args
->ret_does_match
= True
;
219 rc
= cie_args
->do_return_true
;
223 cie_args
->ret_type
= 0;
227 /* Yes, it is correct that this function always returns False. */
231 Bool
test_button_event(
232 Display
*display
, XEvent
*event
, XPointer arg
)
234 if (event
->type
== ButtonPress
|| event
->type
== ButtonRelease
)
242 Bool
test_typed_window_event(
243 Display
*display
, XEvent
*event
, XPointer arg
)
245 test_typed_window_event_args
*ta
= (test_typed_window_event_args
*)arg
;
247 if (event
->xany
.window
== ta
->w
&&
248 event
->xany
.type
== ta
->event_type
)
256 static Bool
test_resizing_event(
257 Display
*display
, XEvent
*event
, XPointer arg
)
259 check_if_event_args
*cie_args
;
262 cie_args
= (check_if_event_args
*)arg
;
263 cie_args
->ret_does_match
= False
;
264 if (event
->xany
.window
!= cie_args
->w
)
271 case ConfigureRequest
:
272 if ((event
->xconfigurerequest
.value_mask
&
273 cie_args
->cr_value_mask
) != 0)
275 cie_args
->ret_type
= ConfigureRequest
;
276 cie_args
->ret_does_match
= True
;
277 rc
= cie_args
->do_return_true_cr
;
281 if (event
->xproperty
.atom
== XA_WM_NORMAL_HINTS
)
283 cie_args
->ret_type
= PropertyNotify
;
284 cie_args
->ret_does_match
= True
;
285 rc
= cie_args
->do_return_true
;
291 /* Yes, it is correct that this function may always returns False. */
295 static inline void __handle_cr_on_unmanaged(XConfigureRequestEvent
*cre
)
300 xwcm
= (cre
->value_mask
& CR_MOVERESIZE_MASK
);
303 xwc
.width
= cre
->width
;
304 xwc
.height
= cre
->height
;
305 xwc
.border_width
= cre
->border_width
;
306 XConfigureWindow(dpy
, cre
->window
, xwcm
, &xwc
);
311 static inline void __handle_cr_on_icon(
312 XConfigureRequestEvent
*cre
, FvwmWindow
*fw
)
317 xwcm
= (cre
->value_mask
& CR_MOVERESIZE_MASK
);
320 xwc
.width
= cre
->width
;
321 xwc
.height
= cre
->height
;
322 xwc
.border_width
= cre
->border_width
;
323 if (FW_W_ICON_PIXMAP(fw
) == cre
->window
)
327 if (cre
->value_mask
& CWBorderWidth
)
329 fw
->icon_border_width
= cre
->border_width
;
331 bw
= fw
->icon_border_width
;
332 if ((cre
->value_mask
& (CWWidth
| CWHeight
)) ==
333 (CWWidth
| CWHeight
))
335 set_icon_picture_size(
336 fw
, cre
->width
+ 2 * bw
, cre
->height
+ 2 * bw
);
339 set_icon_position(fw
, cre
->x
, cre
->y
);
340 broadcast_icon_geometry(fw
, False
);
341 XConfigureWindow(dpy
, cre
->window
, xwcm
, &xwc
);
342 if (cre
->window
!= FW_W_ICON_PIXMAP(fw
) &&
343 FW_W_ICON_PIXMAP(fw
) != None
)
347 get_icon_picture_geometry(fw
, &g
);
350 xwcm
= cre
->value_mask
& (CWX
| CWY
);
352 dpy
, FW_W_ICON_PIXMAP(fw
), xwcm
, &xwc
);
354 if (FW_W_ICON_TITLE(fw
) != None
)
358 get_icon_title_geometry(fw
, &g
);
361 xwcm
= cre
->value_mask
& (CWX
| CWY
);
363 dpy
, FW_W_ICON_TITLE(fw
), xwcm
, &xwc
);
369 static inline void __handle_cr_on_shaped(FvwmWindow
*fw
)
371 /* suppress compiler warnings w/o shape extension */
377 if (FShapeQueryExtents(
378 dpy
, FW_W(fw
), &boundingShaped
, &i
, &i
, &u
, &u
, &b
,
381 fw
->wShaped
= boundingShaped
;
391 static inline void __handle_cr_restack(
392 int *ret_do_send_event
, XConfigureRequestEvent
*cre
, FvwmWindow
*fw
)
396 FvwmWindow
*fw2
= NULL
;
398 if (cre
->value_mask
& CWSibling
)
401 dpy
, cre
->above
, FvwmContext
,
402 (caddr_t
*)&fw2
) == XCNOENT
)
411 if (cre
->detail
!= Above
&& cre
->detail
!= Below
)
413 HandleUnusualStackmodes(
414 cre
->detail
, fw
, cre
->window
, fw2
, cre
->above
);
416 /* only allow clients to restack windows within their layer */
417 else if (fw2
== NULL
|| compare_window_layers(fw2
, fw
) != 0)
422 RaiseWindow(fw
, True
);
425 LowerWindow(fw
, True
);
431 xwc
.sibling
= FW_W_FRAME(fw2
);
432 xwc
.stack_mode
= cre
->detail
;
433 xwcm
= CWSibling
| CWStackMode
;
434 XConfigureWindow(dpy
, FW_W_FRAME(fw
), xwcm
, &xwc
);
436 /* Maintain the condition that icon windows are stacked
437 * immediately below their frame
439 xwc
.sibling
= FW_W_FRAME(fw
);
440 xwc
.stack_mode
= Below
;
441 xwcm
= CWSibling
| CWStackMode
;
442 if (FW_W_ICON_TITLE(fw
) != None
)
445 dpy
, FW_W_ICON_TITLE(fw
), xwcm
, &xwc
);
447 if (FW_W_ICON_PIXMAP(fw
) != None
)
450 dpy
, FW_W_ICON_PIXMAP(fw
), xwcm
, &xwc
);
453 if (cre
->detail
== Below
)
455 xwc
.sibling
= FW_W_FRAME(fw2
);
456 xwc
.stack_mode
= Below
;
457 xwcm
= CWSibling
| CWStackMode
;
458 if (FW_W_ICON_TITLE(fw2
) != None
)
461 dpy
, FW_W_ICON_TITLE(fw2
), xwcm
, &xwc
);
463 if (FW_W_ICON_PIXMAP(fw2
) != None
)
466 dpy
, FW_W_ICON_PIXMAP(fw2
), xwcm
,
470 /* Maintain the stacking order ring */
471 if (cre
->detail
== Above
)
473 remove_window_from_stack_ring(fw
);
474 add_window_to_stack_ring_after(
475 fw
, get_prev_window_in_stack_ring(fw2
));
477 else /* cre->detail == Below */
479 remove_window_from_stack_ring(fw
);
480 add_window_to_stack_ring_after(fw
, fw2
);
482 BroadcastRestackThisWindow(fw
);
484 /* srt (28-Apr-2001): Tk needs a ConfigureNotify event after a
485 * raise, otherwise it would hang for two seconds */
486 *ret_do_send_event
= 1;
491 static inline void __cr_get_static_position(
492 rectangle
*ret_g
, FvwmWindow
*fw
, XConfigureRequestEvent
*cre
,
495 if (cre
->value_mask
& CWX
)
497 ret_g
->x
= cre
->x
- b
->top_left
.width
;
501 ret_g
->x
= fw
->g
.frame
.x
;
503 if (cre
->value_mask
& CWY
)
505 ret_g
->y
= cre
->y
- b
->top_left
.height
;
509 ret_g
->y
= fw
->g
.frame
.y
;
515 static inline void __cr_get_grav_position(
516 rectangle
*ret_g
, FvwmWindow
*fw
, XConfigureRequestEvent
*cre
,
522 gravity_get_offsets(fw
->hints
.win_gravity
, &grav_x
, &grav_y
);
523 if (cre
->value_mask
& CWX
)
525 ret_g
->x
= cre
->x
- ((grav_x
+ 1) * b
->total_size
.width
) / 2;
529 ret_g
->x
= fw
->g
.frame
.x
;
531 if (cre
->value_mask
& CWY
)
533 ret_g
->y
= cre
->y
- ((grav_y
+ 1) * b
->total_size
.height
) / 2;
537 ret_g
->y
= fw
->g
.frame
.y
;
543 /* Try to detect whether the application uses the ICCCM way of moving its
544 * window or the traditional way, always assuming StaticGravity. */
545 static inline void __cr_detect_icccm_move(
546 FvwmWindow
*fw
, XConfigureRequestEvent
*cre
, size_borders
*b
)
560 if (CR_MOTION_METHOD(fw
) != CR_MOTION_METHOD_AUTO
)
562 if (Scr
.bo
.do_debug_cr_motion_method
== 1)
566 "_cdim: --- already detected (pid %d) %p"
567 " '%s'\n", HAS_EWMH_WM_PID(fw
), fw
,
572 if (HAS_EWMH_WM_PID(fw
))
574 if (Scr
.bo
.do_debug_cr_motion_method
== 1)
577 stderr
,"_cdim: +++ has ewmh_wm_pid: icccm"
578 " %p '%s'\n", fw
, fw
->visible_name
);
580 SET_CR_MOTION_METHOD(fw
, CR_MOTION_METHOD_USE_GRAV
);
581 SET_CR_MOTION_METHOD_DETECTED(fw
, 1);
584 if (fw
->ewmh_window_type
!= EWMH_WINDOW_TYPE_NONE_ID
)
586 if (Scr
.bo
.do_debug_cr_motion_method
== 1)
589 stderr
, "_cdim: +++ has ewmh_window_type:"
590 " icccm %p '%s'\n", fw
,
593 SET_CR_MOTION_METHOD(fw
, CR_MOTION_METHOD_USE_GRAV
);
594 SET_CR_MOTION_METHOD_DETECTED(fw
, 1);
597 if (FShapesSupported
&& fw
->wShaped
)
599 if (Scr
.bo
.do_debug_cr_motion_method
== 1)
602 stderr
, "_cdim: --- shaped window %p "
603 "'%s'\n", fw
, fw
->visible_name
);
605 /* no detection for shaped windows */
608 if (fw
->hints
.win_gravity
== StaticGravity
)
610 if (Scr
.bo
.do_debug_cr_motion_method
== 1)
613 stderr
, "_cdim: --- using StaticGravity"
614 " %p '%s'\n", fw
, fw
->visible_name
);
618 if (fw
->hints
.win_gravity
== StaticGravity
)
620 if (Scr
.bo
.do_debug_cr_motion_method
== 1)
623 stderr
, "_cdim: --- using StaticGravity"
624 " %p '%s'\n", fw
, fw
->visible_name
);
628 has_x
= (cre
->value_mask
& CWX
);
629 has_y
= (cre
->value_mask
& CWY
);
630 if (!has_x
&& !has_y
)
632 if (Scr
.bo
.do_debug_cr_motion_method
== 1)
635 stderr
, "_cdim: --- not moved %p '%s'\n",
636 fw
, fw
->visible_name
);
640 __cr_get_grav_position(&grav_g
, fw
, cre
, b
);
641 __cr_get_static_position(&static_g
, fw
, cre
, b
);
642 if (static_g
.x
== grav_g
.x
)
644 /* both methods have the same result; ignore */
647 if (static_g
.y
== grav_g
.y
)
649 /* both methods have the same result; ignore */
652 if (!has_x
&& !has_y
)
654 if (Scr
.bo
.do_debug_cr_motion_method
== 1)
657 stderr
, "_cdim: --- not moved %p '%s'\n",
658 fw
, fw
->visible_name
);
662 dg_g
.x
= grav_g
.x
- fw
->g
.frame
.x
;
663 dg_g
.y
= grav_g
.y
- fw
->g
.frame
.y
;
664 ds_g
.x
= static_g
.x
- fw
->g
.frame
.x
;
665 ds_g
.y
= static_g
.y
- fw
->g
.frame
.y
;
666 if (Scr
.bo
.do_debug_cr_motion_method
== 1)
669 stderr
, "s %3d/%3d %2d/%2d, g %3d/%3d %2d/%2d: ",
670 static_g
.x
, static_g
.y
, ds_g
.x
, ds_g
.y
, grav_g
.x
,
671 grav_g
.y
, dg_g
.x
, dg_g
.y
);
673 /* check full screen */
674 if ((cre
->value_mask
& (CWX
| CWY
)) == (CWX
| CWY
) &&
676 cre
->width
== Scr
.MyDisplayWidth
&&
677 cre
->height
== Scr
.MyDisplayHeight
)
679 if (grav_g
.x
== -b
->top_left
.width
&&
680 grav_g
.y
== -b
->top_left
.height
)
682 /* Window is fullscreen using the ICCCM way. */
683 SET_CR_MOTION_METHOD(fw
, CR_MOTION_METHOD_USE_GRAV
);
684 SET_CR_MOTION_METHOD_DETECTED(fw
, 1);
685 if (Scr
.bo
.do_debug_cr_motion_method
== 1)
688 stderr
, "+++ fullscreen icccm %p"
689 " '%s'\n", fw
, fw
->visible_name
);
693 else if (static_g
.x
== -b
->top_left
.width
&&
694 static_g
.y
== -b
->top_left
.height
)
696 /* Window is fullscreen using the traditional way. */
697 SET_CR_MOTION_METHOD(fw
, CR_MOTION_METHOD_STATIC_GRAV
);
698 SET_CR_MOTION_METHOD_DETECTED(fw
, 1);
699 if (Scr
.bo
.do_debug_cr_motion_method
== 1)
702 stderr
, "+++ fullscreen traditional"
709 /* check travelling across the screen */
710 if (has_x
&& dg_g
.x
== 0 && ds_g
.x
!= 0 &&
711 has_y
&& dg_g
.y
== 0 && ds_g
.y
!= 0)
713 /* The traditional way causes a shift by the border width or
714 * height. Use ICCCM way. */
715 SET_CR_MOTION_METHOD(fw
, CR_MOTION_METHOD_USE_GRAV
);
716 SET_CR_MOTION_METHOD_DETECTED(fw
, 1);
717 if (Scr
.bo
.do_debug_cr_motion_method
== 1)
720 stderr
, "+++ travelling icccm %p '%s'\n",
721 fw
, fw
->visible_name
);
725 if (has_x
&& dg_g
.x
!= 0 && ds_g
.x
== 0 &&
726 has_y
&& dg_g
.y
!= 0 && ds_g
.y
== 0)
728 /* The ICCCM way causes a shift by the border width or height.
729 * Use traditional way. */
730 SET_CR_MOTION_METHOD(fw
, CR_MOTION_METHOD_STATIC_GRAV
);
731 SET_CR_MOTION_METHOD_DETECTED(fw
, 1);
732 if (Scr
.bo
.do_debug_cr_motion_method
== 1)
735 stderr
, "+++ travelling traditional %p"
736 " '%s'\n", fw
, fw
->visible_name
);
740 /* check placement near border */
741 w
= (cre
->value_mask
& CWWidth
) ?
742 cre
->width
+ b
->total_size
.width
: fw
->g
.frame
.width
;
743 h
= (cre
->value_mask
& CWHeight
) ?
744 cre
->height
+ b
->total_size
.height
: fw
->g
.frame
.height
;
747 mx
= CR_MOTION_METHOD_AUTO
;
749 else if (static_g
.x
== 0 || static_g
.x
+ w
== Scr
.MyDisplayWidth
)
751 mx
= CR_MOTION_METHOD_STATIC_GRAV
;
753 else if (grav_g
.x
== 0 || grav_g
.x
+ w
== Scr
.MyDisplayWidth
)
755 mx
= CR_MOTION_METHOD_USE_GRAV
;
759 mx
= CR_MOTION_METHOD_AUTO
;
763 my
= CR_MOTION_METHOD_AUTO
;
765 else if (static_g
.y
== 0 || static_g
.y
+ h
== Scr
.MyDisplayHeight
)
767 my
= CR_MOTION_METHOD_STATIC_GRAV
;
769 else if (grav_g
.y
== 0 || grav_g
.y
+ h
== Scr
.MyDisplayHeight
)
771 my
= CR_MOTION_METHOD_USE_GRAV
;
775 my
= CR_MOTION_METHOD_AUTO
;
777 m
= (mx
!= CR_MOTION_METHOD_AUTO
) ? mx
: my
;
778 if (m
!= CR_MOTION_METHOD_AUTO
)
780 /* Window was placed next to the display border. */
781 if (m
== my
|| my
== CR_MOTION_METHOD_AUTO
)
783 SET_CR_MOTION_METHOD(fw
, m
);
784 SET_CR_MOTION_METHOD_DETECTED(fw
, 1);
785 if (Scr
.bo
.do_debug_cr_motion_method
== 1)
788 stderr
, "+++ near border %s %p "
790 CR_MOTION_METHOD_USE_GRAV
)
791 ? "icccm" : "traditional", fw
,
797 if (Scr
.bo
.do_debug_cr_motion_method
== 1)
800 stderr
, "--- not detected %p '%s'\n", fw
,
807 #define EXPERIMENTAL_ANTI_RACE_CONDITION_CODE
808 /* This is not a good idea because this interferes with changes in the size
809 * hints of the window. However, it is impossible to be completely safe here.
810 * For example, if the client changes the size inc, then resizes the size of
811 * its window and then changes the size inc again - all in one batch - then
812 * the WM will read the *second* size inc upon the *first* event and use the
813 * wrong one in the ConfigureRequest calculations. */
814 /* dv (31 Mar 2002): The code now handles these situations, so enable it
816 #ifdef EXPERIMENTAL_ANTI_RACE_CONDITION_CODE
817 static inline int __merge_cr_moveresize(
818 const evh_args_t
*ea
, XConfigureRequestEvent
*cre
, FvwmWindow
*fw
,
823 XConfigureRequestEvent
*ecre
;
824 check_if_event_args args
;
826 args
.w
= cre
->window
;
827 args
.do_return_true
= False
;
828 args
.do_return_true_cr
= True
;
829 args
.cr_value_mask
= CR_MOVERESIZE_MASK
;
830 args
.ret_does_match
= False
;
834 /* dv (7 May 2002): No, it's better to not reschedule processes here
835 * because some funny applications (XMMS, GTK) seem to expect that
836 * ConfigureRequests are handled instantly or they freak out. */
839 for (cn_count
= 0; 1; )
846 exec_context_changes_t ecc
;
849 dpy
, &e
, test_resizing_event
, (XPointer
)&args
);
850 ecre
= &e
.xconfigurerequest
;
851 if (args
.ret_does_match
== False
)
855 else if (args
.ret_type
== PropertyNotify
)
857 /* Can't merge events with a PropertyNotify in
858 * between. The event is still on the queue. */
861 else if (args
.ret_type
!= ConfigureRequest
)
863 /* not good. unselected event type! */
866 /* Event was not yet removed from the queue but stored in e. */
869 vma
= cre
->value_mask
& ecre
->value_mask
;
870 vmo
= cre
->value_mask
| ecre
->value_mask
;
871 if (((vma
& xm
) == 0 && (vmo
& xm
) == xm
) ||
872 ((vma
& ym
) == 0 && (vmo
& ym
) == ym
))
874 /* can't merge events since location of window might
878 /* Finally remove the event from the queue */
879 FCheckIfEvent(dpy
, &e
, test_resizing_event
, (XPointer
)&args
);
880 /* partially handle the event */
881 ecre
->value_mask
&= ~args
.cr_value_mask
;
882 ea2
.exc
= exc_clone_context(ea
->exc
, &ecc
, ECC_ETRIGGER
);
883 HandleConfigureRequest(&ea2
);
884 exc_destroy_context(ea2
.exc
);
885 /* collect the size/position changes */
886 if (ecre
->value_mask
& CWX
)
890 if (ecre
->value_mask
& CWY
)
894 if (ecre
->value_mask
& CWWidth
)
896 cre
->width
= ecre
->width
;
898 if (ecre
->value_mask
& CWHeight
)
900 cre
->height
= ecre
->height
;
902 if (ecre
->value_mask
& CWBorderWidth
)
904 cre
->border_width
= ecre
->border_width
;
906 cre
->value_mask
|= (ecre
->value_mask
& CR_MOVERESIZE_MASK
);
914 static inline int __handle_cr_on_client(
915 int *ret_do_send_event
, XConfigureRequestEvent cre
,
916 const evh_args_t
*ea
, FvwmWindow
*fw
, Bool force
)
920 size_rect constr_dim
;
921 size_rect oldnew_dim
;
927 cre
= ea
->exc
->x
.etrigger
->xconfigurerequest
;
929 if ((cre
.value_mask
& (CWWidth
| CWHeight
| CWX
| CWY
)) == 0)
934 get_window_borders(fw
, &b
);
935 #ifdef EXPERIMENTAL_ANTI_RACE_CONDITION_CODE
936 /* Merge all pending ConfigureRequests for the window into a single
937 * event. However, we can not do this if the window uses the motion
938 * method autodetection because the merged event might confuse the
940 if (ea
&& CR_MOTION_METHOD(fw
) == CR_MOTION_METHOD_AUTO
)
942 cn_count
= __merge_cr_moveresize(ea
, &cre
, fw
, &b
);
947 "cre: %d(%d) %d(%d) %d(%d)x%d(%d) fw 0x%08x w 0x%08x "
949 cre
.x
, (int)(cre
.value_mask
& CWX
),
950 cre
.y
, (int)(cre
.value_mask
& CWY
),
951 cre
.width
, (int)(cre
.value_mask
& CWWidth
),
952 cre
.height
, (int)(cre
.value_mask
& CWHeight
),
953 (int)FW_W_FRAME(fw
), (int)FW_W(fw
), (int)cre
.window
,
954 (fw
->name
.name
) ? fw
->name
.name
: "");
956 /* Don't modify frame_g fields before calling SetupWindow! */
957 memset(&d_g
, 0, sizeof(d_g
));
959 if (HAS_NEW_WM_NORMAL_HINTS(fw
))
961 /* get the latest size hints */
963 GetWindowSizeHints(fw
);
964 SET_HAS_NEW_WM_NORMAL_HINTS(fw
, 0);
966 if (!HAS_OVERRIDE_SIZE_HINTS(fw
) && (fw
->hints
.flags
& PMaxSize
))
968 /* Java workaround */
969 if (cre
.height
> fw
->hints
.max_height
&&
970 fw
->hints
.max_height
<= BROKEN_MAXSIZE_LIMIT
)
972 fw
->hints
.max_height
= DEFAULT_MAX_MAX_WINDOW_HEIGHT
;
973 cre
.value_mask
|= CWHeight
;
975 if (cre
.width
> fw
->hints
.max_width
&&
976 fw
->hints
.max_width
<= BROKEN_MAXSIZE_LIMIT
)
978 fw
->hints
.max_width
= DEFAULT_MAX_MAX_WINDOW_WIDTH
;
979 cre
.value_mask
|= CWWidth
;
982 if (!HAS_OVERRIDE_SIZE_HINTS(fw
) && (fw
->hints
.flags
& PMinSize
))
984 if (cre
.width
< fw
->hints
.min_width
&&
985 fw
->hints
.min_width
>= BROKEN_MINSIZE_LIMIT
)
987 fw
->hints
.min_width
= 1;
988 cre
.value_mask
|= CWWidth
;
990 if (cre
.height
< fw
->hints
.min_height
&&
991 fw
->hints
.min_height
>= BROKEN_MINSIZE_LIMIT
)
993 fw
->hints
.min_height
= 1;
994 cre
.value_mask
|= CWHeight
;
998 !is_function_allowed(F_MOVE
, NULL
, fw
, False
, False
))
1000 /* forbid shaded applications to move their windows */
1001 cre
.value_mask
&= ~(CWX
| CWY
);
1002 /* resend the old geometry */
1003 *ret_do_send_event
= 1;
1005 if (IS_MAXIMIZED(fw
))
1007 /* dont allow clients to resize maximized windows */
1008 cre
.value_mask
&= ~(CWWidth
| CWHeight
);
1009 /* resend the old geometry */
1010 *ret_do_send_event
= 1;
1014 else if (!is_function_allowed(F_RESIZE
, NULL
, fw
, False
, False
))
1016 cre
.value_mask
&= ~(CWWidth
| CWHeight
);
1017 *ret_do_send_event
= 1;
1020 if (cre
.value_mask
& CWBorderWidth
)
1023 fw
->attr_backup
.border_width
= cre
.border_width
;
1025 if (!force
&& CR_MOTION_METHOD(fw
) == CR_MOTION_METHOD_AUTO
)
1027 __cr_detect_icccm_move(fw
, &cre
, &b
);
1029 if (!(cre
.value_mask
& (CWX
| CWY
)))
1034 CR_MOTION_METHOD(fw
) == CR_MOTION_METHOD_USE_GRAV
) &&
1035 fw
->hints
.win_gravity
!= StaticGravity
)
1042 gravity_get_offsets(fw
->hints
.win_gravity
, &grav_x
, &grav_y
);
1043 if (cre
.value_mask
& CWX
)
1046 ((grav_x
+ 1) * b
.total_size
.width
) / 2;
1047 d_g
.x
= ref_x
- fw
->g
.frame
.x
;
1049 if (cre
.value_mask
& CWY
)
1052 ((grav_y
+ 1) * b
.total_size
.height
) / 2;
1053 d_g
.y
= ref_y
- fw
->g
.frame
.y
;
1056 else /* ..._USE_GRAV or ..._AUTO */
1058 /* default: traditional cr handling */
1059 if (cre
.value_mask
& CWX
)
1061 d_g
.x
= cre
.x
- fw
->g
.frame
.x
- b
.top_left
.width
;
1063 if (cre
.value_mask
& CWY
)
1065 d_g
.y
= cre
.y
- fw
->g
.frame
.y
- b
.top_left
.height
;
1068 if (cre
.value_mask
& CWHeight
)
1071 (WINDOW_FREAKED_OUT_SIZE
- b
.total_size
.height
))
1073 d_g
.height
= cre
.height
-
1074 (fw
->g
.frame
.height
- b
.total_size
.height
);
1078 /* Ignore height changes to astronomically large
1079 * windows (needed for XEmacs 20.4); don't care if the
1080 * window is shaded here - we won't use 'height' in
1082 * Inform the buggy app about the size that *we* want
1085 *ret_do_send_event
= 1;
1088 if (cre
.value_mask
& CWWidth
)
1090 if (cre
.width
< (WINDOW_FREAKED_OUT_SIZE
- b
.total_size
.width
))
1092 d_g
.width
= cre
.width
-
1093 (fw
->g
.frame
.width
- b
.total_size
.width
);
1098 *ret_do_send_event
= 1;
1102 /* SetupWindow (x,y) are the location of the upper-left outer corner
1103 * and are passed directly to XMoveResizeWindow (frame). The
1104 * (width,height) are the inner size of the frame. The inner width is
1105 * the same as the requested client window width; the inner height is
1106 * the same as the requested client window height plus any title bar
1108 new_g
= fw
->g
.frame
;
1111 new_g
.width
= fw
->g
.normal
.width
;
1112 new_g
.height
= fw
->g
.normal
.height
;
1114 oldnew_dim
.width
= new_g
.width
+ d_g
.width
;
1115 oldnew_dim
.height
= new_g
.height
+ d_g
.height
;
1116 constr_dim
.width
= oldnew_dim
.width
;
1117 constr_dim
.height
= oldnew_dim
.height
;
1119 fw
, NULL
, &constr_dim
.width
, &constr_dim
.height
, 0, 0,
1120 CS_UPDATE_MAX_DEFECT
);
1121 d_g
.width
+= (constr_dim
.width
- oldnew_dim
.width
);
1122 d_g
.height
+= (constr_dim
.height
- oldnew_dim
.height
);
1123 if ((cre
.value_mask
& CWX
) && d_g
.width
)
1125 new_g
.x
= fw
->g
.frame
.x
+ d_g
.x
;
1126 new_g
.width
= fw
->g
.frame
.width
+ d_g
.width
;
1128 else if ((cre
.value_mask
& CWX
) && !d_g
.width
)
1130 new_g
.x
= fw
->g
.frame
.x
+ d_g
.x
;
1132 else if (!(cre
.value_mask
& CWX
) && d_g
.width
)
1134 gravity_resize(fw
->hints
.win_gravity
, &new_g
, d_g
.width
, 0);
1136 if ((cre
.value_mask
& CWY
) && d_g
.height
)
1138 new_g
.y
= fw
->g
.frame
.y
+ d_g
.y
;
1139 new_g
.height
= fw
->g
.frame
.height
+ d_g
.height
;
1141 else if ((cre
.value_mask
& CWY
) && !d_g
.height
)
1143 new_g
.y
= fw
->g
.frame
.y
+ d_g
.y
;
1145 else if (!(cre
.value_mask
& CWY
) && d_g
.height
)
1147 gravity_resize(fw
->hints
.win_gravity
, &new_g
, 0, d_g
.height
);
1150 if (new_g
.x
== fw
->g
.frame
.x
&& new_g
.y
== fw
->g
.frame
.y
&&
1151 new_g
.width
== fw
->g
.frame
.width
&&
1152 new_g
.height
== fw
->g
.frame
.height
)
1154 /* Window will not be moved or resized; send a synthetic
1155 * ConfigureNotify. */
1156 *ret_do_send_event
= 1;
1158 else if ((cre
.value_mask
& CWX
) || (cre
.value_mask
& CWY
) ||
1159 d_g
.width
|| d_g
.height
)
1163 get_shaded_geometry(fw
, &new_g
, &new_g
);
1165 frame_setup_window_app_request(
1166 fw
, new_g
.x
, new_g
.y
, new_g
.width
, new_g
.height
,
1168 /* make sure the window structure has the new position */
1169 update_absolute_geometry(fw
);
1170 maximize_adjust_offset(fw
);
1171 GNOME_SetWinArea(fw
);
1173 else if (DO_FORCE_NEXT_CR(fw
))
1175 *ret_do_send_event
= 1;
1177 SET_FORCE_NEXT_CR(fw
, 0);
1178 SET_FORCE_NEXT_PN(fw
, 0);
1183 void __handle_configure_request(
1184 XConfigureRequestEvent cre
, const evh_args_t
*ea
, FvwmWindow
*fw
,
1187 int do_send_event
= 0;
1190 /* According to the July 27, 1988 ICCCM draft, we should ignore size
1191 * and position fields in the WM_NORMAL_HINTS property when we map a
1192 * window. Instead, we'll read the current geometry. Therefore, we
1193 * should respond to configuration requests for windows which have
1194 * never been mapped. */
1197 __handle_cr_on_unmanaged(&cre
);
1200 if (cre
.window
== FW_W_ICON_TITLE(fw
) ||
1201 cre
.window
== FW_W_ICON_PIXMAP(fw
))
1203 __handle_cr_on_icon(&cre
, fw
);
1205 if (FShapesSupported
)
1207 __handle_cr_on_shaped(fw
);
1209 if (fw
!= NULL
&& cre
.window
== FW_W(fw
))
1211 cn_count
= __handle_cr_on_client(
1212 &do_send_event
, cre
, ea
, fw
, force
);
1214 /* Stacking order change requested. Handle this *after* geometry
1215 * changes, since we need the new geometry in occlusion calculations */
1216 if ((cre
.value_mask
& CWStackMode
) &&
1217 (!DO_IGNORE_RESTACK(fw
) || force
))
1219 __handle_cr_restack(&do_send_event
, &cre
, fw
);
1222 /* This causes some ddd windows not to be drawn properly. Reverted back
1223 * to the old method in frame_setup_window. */
1224 /* domivogt (15-Oct-1999): enabled this to work around buggy apps that
1225 * ask for a nonsense height and expect that they really get it. */
1226 if (cn_count
== 0 && do_send_event
)
1230 else if (cn_count
> 0)
1234 for ( ; cn_count
> 0; cn_count
--)
1236 SendConfigureNotify(
1237 fw
, fw
->g
.frame
.x
, fw
->g
.frame
.y
, fw
->g
.frame
.width
,
1238 fw
->g
.frame
.height
, 0, True
);
1249 static Bool
__predicate_button_click(
1250 Display
*display
, XEvent
*event
, XPointer arg
)
1252 if (event
->type
== ButtonPress
|| event
->type
== ButtonRelease
)
1260 /* Helper function for __handle_focus_raise_click(). */
1261 static Bool
__test_for_motion(int x0
, int y0
)
1268 /* Query the pointer to do this. We can't check for events here since
1269 * the events are still needed if the pointer moves. */
1271 /* However, some special mouse (e.g., a touchpad with the
1272 * synaptic driver) may handle a double click in a special way
1273 * (for dragging through short touching and holding down the
1274 * finger on the touchpad). Bascially, when you execute a
1275 * double click the first button release is queued after the
1276 * second _physical_ mouse release happen. It seems that
1277 * FQueryPointer may not work as expected: it does not see
1278 * that the button is released on a double click. So, we need
1279 * to check for a button press in the future to avoid a fvwm
1280 * lockup! (olicha 2004-01-31) */
1282 for (x
= x0
, y
= y0
; FQueryPointer(
1283 dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
, &JunkX
, &JunkY
,
1284 &x
, &y
, &mask
) == True
; usleep(20000))
1286 if ((mask
& DEFAULT_ALL_BUTTONS_MASK
) == 0)
1288 /* all buttons are released */
1291 else if (abs(x
- x0
) >= Scr
.MoveThreshold
||
1292 abs(y
- y0
) >= Scr
.MoveThreshold
)
1294 /* the pointer has moved */
1297 if (FCheckPeekIfEvent(dpy
, &e
, __predicate_button_click
, NULL
))
1299 /* click in the future */
1304 /* The predicate procedure finds no match, no event
1305 * has been removed from the queue and XFlush was
1306 * called. Nothing to do */
1310 /* pointer has moved off screen */
1314 /* Helper function for __handle_focus_raise_click(). */
1315 static void __check_click_to_focus_or_raise(
1316 hfrc_ret_t
*ret_args
, const exec_context_t
*exc
)
1318 FvwmWindow
* const fw
= exc
->w
.fw
;
1319 const XEvent
*te
= exc
->x
.etrigger
;
1322 unsigned is_client_click
: 1;
1323 unsigned is_focused
: 1;
1326 f
.is_focused
= !!focus_is_focused(fw
);
1327 f
.is_client_click
= (exc
->w
.wcontext
== C_WINDOW
||
1328 exc
->w
.wcontext
== C_EWMH_DESKTOP
);
1329 /* check if we need to raise and/or focus the window */
1330 ret_args
->do_focus
= focus_query_click_to_focus(fw
, exc
->w
.wcontext
);
1331 if (f
.is_client_click
&& !ret_args
->do_focus
&&
1332 !f
.is_focused
&& FP_DO_FOCUS_BY_PROGRAM(FW_FOCUS_POLICY(fw
)) &&
1333 !fpol_query_allow_user_focus(&FW_FOCUS_POLICY(fw
)))
1335 /* Give the window a chance to to take focus itself */
1336 ret_args
->do_focus
= 1;
1338 if (ret_args
->do_focus
&& focus_is_focused(fw
))
1340 ret_args
->do_focus
= 0;
1342 ret_args
->do_raise
=
1343 focus_query_click_to_raise(fw
, f
.is_focused
, exc
->w
.wcontext
);
1344 #define EXPERIMENTAL_ROU_HANDLING_V2
1345 #ifdef EXPERIMENTAL_ROU_HANDLING_V2
1346 /* RBW -- Dang! This works without the one in HandleEnterNotify! */
1347 if (ret_args
->do_raise
&& is_on_top_of_layer_and_above_unmanaged(fw
))
1349 if (ret_args
->do_raise
&& is_on_top_of_layer(fw
))
1352 ret_args
->do_raise
= 0;
1354 if ((ret_args
->do_focus
&&
1355 FP_DO_IGNORE_FOCUS_CLICK_MOTION(FW_FOCUS_POLICY(fw
))) ||
1356 (ret_args
->do_raise
&&
1357 FP_DO_IGNORE_RAISE_CLICK_MOTION(FW_FOCUS_POLICY(fw
))))
1359 /* Pass further events to the application and check if a button
1360 * release or motion event occurs next. If we don't do this
1361 * here, the pointer will seem to be frozen in
1362 * __test_for_motion(). */
1363 XAllowEvents(dpy
, ReplayPointer
, CurrentTime
);
1364 if (__test_for_motion(te
->xbutton
.x_root
, te
->xbutton
.y_root
))
1366 /* the pointer was moved, process event normally */
1367 ret_args
->do_focus
= 0;
1368 ret_args
->do_raise
= 0;
1371 if (ret_args
->do_focus
|| ret_args
->do_raise
)
1373 if (!((ret_args
->do_focus
&&
1374 FP_DO_ALLOW_FUNC_FOCUS_CLICK(FW_FOCUS_POLICY(fw
))) ||
1375 (ret_args
->do_raise
&&
1376 FP_DO_ALLOW_FUNC_RAISE_CLICK(FW_FOCUS_POLICY(fw
)))))
1378 ret_args
->do_forbid_function
= 1;
1380 if (!((ret_args
->do_focus
&&
1381 FP_DO_PASS_FOCUS_CLICK(FW_FOCUS_POLICY(fw
))) ||
1382 (ret_args
->do_raise
&&
1383 FP_DO_PASS_RAISE_CLICK(FW_FOCUS_POLICY(fw
)))))
1385 ret_args
->do_swallow_click
= 1;
1392 /* Finds out if the click on a window must be used to focus or raise it. */
1393 static void __handle_focus_raise_click(
1394 hfrc_ret_t
*ret_args
, const exec_context_t
*exc
)
1396 memset(ret_args
, 0, sizeof(*ret_args
));
1397 if (exc
->w
.fw
== NULL
)
1401 /* check for proper click button and modifiers*/
1402 if (FP_USE_MOUSE_BUTTONS(FW_FOCUS_POLICY(exc
->w
.fw
)) != 0 &&
1403 !(FP_USE_MOUSE_BUTTONS(FW_FOCUS_POLICY(exc
->w
.fw
)) &
1404 (1 << (exc
->x
.etrigger
->xbutton
.button
- 1))))
1406 /* wrong button, handle click normally */
1409 else if (FP_USE_MODIFIERS(FW_FOCUS_POLICY(exc
->w
.fw
)) !=
1410 FPOL_ANY_MODIFIER
&&
1412 FP_USE_MODIFIERS(FW_FOCUS_POLICY(exc
->w
.fw
))) !=
1413 MaskUsedModifiers(exc
->x
.etrigger
->xbutton
.state
))
1415 /* right button but wrong modifiers, handle click normally */
1420 __check_click_to_focus_or_raise(ret_args
, exc
);
1426 /* Helper function for HandleButtonPress */
1427 static Bool
__is_bpress_window_handled(const exec_context_t
*exc
)
1430 const XEvent
*te
= exc
->x
.etrigger
;
1432 if (exc
->w
.fw
== NULL
)
1434 if ((te
->xbutton
.window
!= Scr
.Root
||
1435 te
->xbutton
.subwindow
!= None
) &&
1436 !is_pan_frame(te
->xbutton
.window
))
1438 /* Ignore events in unmanaged windows or subwindows of
1447 eventw
= (te
->xbutton
.subwindow
!= None
&&
1448 te
->xany
.window
!= FW_W(exc
->w
.fw
)) ?
1449 te
->xbutton
.subwindow
: te
->xany
.window
;
1450 if (is_frame_hide_window(eventw
) || eventw
== FW_W_FRAME(exc
->w
.fw
))
1455 dpy
, eventw
, &JunkRoot
, &JunkX
, &JunkY
,
1456 (unsigned int*)&JunkWidth
, (unsigned int*)&JunkHeight
,
1457 (unsigned int*)&JunkBW
, (unsigned int*)&JunkDepth
))
1459 /* The window has already died. */
1466 /* Helper function for __handle_bpress_on_managed */
1467 static Bool
__handle_click_to_focus(const exec_context_t
*exc
)
1469 fpol_set_focus_by_t set_by
;
1471 switch (exc
->w
.wcontext
)
1474 case C_EWMH_DESKTOP
:
1475 set_by
= FOCUS_SET_BY_CLICK_CLIENT
;
1478 set_by
= FOCUS_SET_BY_CLICK_ICON
;
1481 set_by
= FOCUS_SET_BY_CLICK_DECOR
;
1484 SetFocusWindow(exc
->w
.fw
, True
, set_by
);
1485 focus_grab_buttons(exc
->w
.fw
);
1486 if (focus_is_focused(exc
->w
.fw
) && !IS_ICONIFIED(exc
->w
.fw
))
1488 border_draw_decorations(
1489 exc
->w
.fw
, PART_ALL
, True
, True
, CLEAR_ALL
, NULL
,
1493 return focus_is_focused(exc
->w
.fw
);
1496 /* Helper function for __handle_bpress_on_managed */
1497 static Bool
__handle_click_to_raise(const exec_context_t
*exc
)
1502 is_focused
= focus_is_focused(exc
->w
.fw
);
1503 if (focus_query_click_to_raise(exc
->w
.fw
, is_focused
, True
))
1511 /* Helper function for HandleButtonPress */
1512 static void __handle_bpress_stroke(void)
1514 STROKE_CODE(stroke_init());
1515 STROKE_CODE(send_motion
= True
);
1520 /* Helper function for __handle_bpress_on_managed */
1521 static Bool
__handle_bpress_action(
1522 const exec_context_t
*exc
, char *action
)
1528 if (!action
|| *action
== 0)
1533 /* draw pressed in decorations */
1534 part
= border_context_to_parts(exc
->w
.wcontext
);
1535 do_force
= (part
& PART_TITLEBAR
) ? True
: False
;
1536 border_draw_decorations(
1537 exc
->w
.fw
, part
, (Scr
.Hilite
== exc
->w
.fw
), do_force
,
1538 CLEAR_ALL
, NULL
, NULL
);
1539 /* execute the action */
1540 if (IS_ICONIFIED(exc
->w
.fw
))
1542 /* release the pointer since it can't do harm over an icon */
1543 XAllowEvents(dpy
, AsyncPointer
, CurrentTime
);
1545 execute_function(NULL
, exc
, action
, 0);
1546 if (exc
->w
.wcontext
!= C_WINDOW
&& exc
->w
.wcontext
!= C_NO_CONTEXT
)
1548 WaitForButtonsUp(True
);
1551 /* redraw decorations */
1553 if (check_if_fvwm_window_exists(exc
->w
.fw
))
1555 part
= border_context_to_parts(exc
->w
.wcontext
);
1556 do_force
= (part
& PART_TITLEBAR
) ? True
: False
;
1557 border_draw_decorations(
1558 exc
->w
.fw
, part
, (Scr
.Hilite
== exc
->w
.fw
), do_force
,
1559 CLEAR_ALL
, NULL
, NULL
);
1565 /* Handles button presses on the root window. */
1566 static void __handle_bpress_on_root(const exec_context_t
*exc
)
1571 __handle_bpress_stroke();
1572 /* search for an appropriate mouse binding */
1573 action
= CheckBinding(
1574 Scr
.AllBindings
, STROKE_ARG(0) exc
->x
.etrigger
->xbutton
.button
,
1575 exc
->x
.etrigger
->xbutton
.state
, GetUnusedModifiers(), C_ROOT
,
1576 BIND_BUTTONPRESS
, NULL
, NULL
);
1577 if (action
&& *action
)
1579 const exec_context_t
*exc2
;
1580 exec_context_changes_t ecc
;
1582 ecc
.w
.wcontext
= C_ROOT
;
1583 exc2
= exc_clone_context(exc
, &ecc
, ECC_WCONTEXT
);
1584 execute_function(NULL
, exc2
, action
, 0);
1585 exc_destroy_context(exc2
);
1586 WaitForButtonsUp(True
);
1590 /* do gnome buttonpress forwarding if win == root */
1591 GNOME_ProxyButtonEvent(exc
->x
.etrigger
);
1597 /* Handles button presses on unmanaged windows */
1598 static void __handle_bpress_on_unmanaged(const exec_context_t
*exc
)
1600 /* Pass the event to the application. */
1601 XAllowEvents(dpy
, ReplayPointer
, CurrentTime
);
1607 /* Handles button presses on managed windows */
1608 static void __handle_bpress_on_managed(const exec_context_t
*exc
)
1612 FvwmWindow
* const fw
= exc
->w
.fw
;
1615 e
= exc
->x
.etrigger
;
1616 /* Now handle click to focus and click to raise. */
1617 __handle_focus_raise_click(&f
, exc
);
1618 PressedW
= (f
.do_forbid_function
) ? None
: exc
->w
.w
;
1621 if (!__handle_click_to_focus(exc
))
1623 /* Window didn't accept the focus; pass the click to
1624 * the application. */
1625 f
.do_swallow_click
= 0;
1630 if (__handle_click_to_raise(exc
) == True
)
1632 /* We can't raise the window immediately because the
1633 * action bound to the click might be "Lower" or
1634 * "RaiseLower". So mark the window as scheduled to be
1635 * raised after the binding is executed. Functions that
1636 * modify the stacking order will reset this flag. */
1637 SET_SCHEDULED_FOR_RAISE(fw
, 1);
1640 /* handle bindings */
1641 if (!f
.do_forbid_function
)
1643 /* stroke bindings */
1644 __handle_bpress_stroke();
1645 /* mouse bindings */
1646 action
= CheckBinding(
1647 Scr
.AllBindings
, STROKE_ARG(0) e
->xbutton
.button
,
1648 e
->xbutton
.state
, GetUnusedModifiers(),
1649 exc
->w
.wcontext
, BIND_BUTTONPRESS
, &fw
->class,
1651 if (__handle_bpress_action(exc
, action
))
1653 f
.do_swallow_click
= 1;
1656 /* raise the window */
1657 if (IS_SCHEDULED_FOR_RAISE(fw
))
1659 /* Now that we know the action did not restack the window we
1661 * dv (10-Aug-2002): We can safely raise the window after
1662 * redrawing it since all the decorations are drawn in the
1663 * window background and no Expose event is generated. */
1664 RaiseWindow(fw
, False
);
1665 SET_SCHEDULED_FOR_RAISE(fw
, 0);
1668 if (!f
.do_swallow_click
)
1670 /* pass the click to the application */
1671 XAllowEvents(dpy
, ReplayPointer
, CurrentTime
);
1674 else if (f
.do_focus
|| f
.do_raise
)
1676 WaitForButtonsUp(True
);
1682 /* restore focus stolen by unmanaged */
1683 static void __refocus_stolen_focus_win(const evh_args_t
*ea
)
1685 FOCUS_SET(Scr
.StolenFocusWin
);
1686 ea
->exc
->x
.etrigger
->xfocus
.window
= Scr
.StolenFocusWin
;
1687 ea
->exc
->x
.etrigger
->type
= FocusIn
;
1688 Scr
.UnknownWinFocused
= None
;
1689 Scr
.StolenFocusWin
= None
;
1690 dispatch_event(ea
->exc
->x
.etrigger
);
1695 /* ---------------------------- event handlers ----------------------------- */
1697 void HandleButtonPress(const evh_args_t
*ea
)
1699 DBUG("HandleButtonPress", "Routine Entered");
1701 GrabEm(CRS_NONE
, GRAB_PASSIVE
);
1702 if (__is_bpress_window_handled(ea
->exc
) == False
)
1704 __handle_bpress_on_unmanaged(ea
->exc
);
1706 else if (ea
->exc
->w
.fw
!= NULL
)
1708 __handle_bpress_on_managed(ea
->exc
);
1712 __handle_bpress_on_root(ea
->exc
);
1714 UngrabEm(GRAB_PASSIVE
);
1720 void HandleButtonRelease(const evh_args_t
*ea
)
1725 const XEvent
*te
= ea
->exc
->x
.etrigger
;
1728 DBUG("HandleButtonRelease", "Routine Entered");
1729 send_motion
= False
;
1730 stroke_trans (sequence
);
1731 DBUG("HandleButtonRelease",sequence
);
1732 /* Allows modifier to work (Only R context works here). */
1733 real_modifier
= te
->xbutton
.state
- (1 << (7 + te
->xbutton
.button
));
1734 if (ea
->exc
->w
.fw
== NULL
)
1741 class = &ea
->exc
->w
.fw
->class;
1742 name
= ea
->exc
->w
.fw
->name
.name
;
1744 /* need to search for an appropriate stroke binding */
1745 action
= CheckBinding(
1746 Scr
.AllBindings
, sequence
, te
->xbutton
.button
, real_modifier
,
1747 GetUnusedModifiers(), ea
->exc
->w
.wcontext
, BIND_STROKE
,
1749 /* got a match, now process it */
1750 if (action
!= NULL
&& (action
[0] != 0))
1752 execute_function(NULL
, ea
->exc
, action
, 0);
1753 WaitForButtonsUp(True
);
1758 * do gnome buttonpress forwarding if win == root
1760 if (Scr
.Root
== te
->xany
.window
)
1762 GNOME_ProxyButtonEvent(te
);
1768 #endif /* HAVE_STROKE */
1770 void HandleClientMessage(const evh_args_t
*ea
)
1772 const XEvent
*te
= ea
->exc
->x
.etrigger
;
1773 FvwmWindow
* const fw
= ea
->exc
->w
.fw
;
1775 DBUG("HandleClientMessage", "Routine Entered");
1777 /* Process GNOME and EWMH Messages */
1778 if (GNOME_ProcessClientMessage(ea
->exc
))
1782 else if (EWMH_ProcessClientMessage(ea
->exc
))
1787 /* handle deletion of tear out menus */
1788 if (fw
&& IS_TEAR_OFF_MENU(fw
) && te
->xclient
.format
== 32 &&
1789 te
->xclient
.data
.l
[0] == _XA_WM_DELETE_WINDOW
)
1791 menu_close_tear_off_menu(fw
);
1795 if (te
->xclient
.message_type
== _XA_WM_CHANGE_STATE
&&
1796 fw
&& te
->xclient
.data
.l
[0] == IconicState
&& !IS_ICONIFIED(fw
))
1798 const exec_context_t
*exc
;
1799 exec_context_changes_t ecc
;
1801 ecc
.w
.wcontext
= C_WINDOW
;
1802 exc
= exc_clone_context(ea
->exc
, &ecc
, ECC_WCONTEXT
);
1803 execute_function(NULL
, exc
, "Iconify", 0);
1804 exc_destroy_context(exc
);
1808 /* FIXME: Is this safe enough ? I guess if clients behave
1809 * according to ICCCM and send these messages only if they
1810 * grabbed the pointer, it is OK */
1812 extern Atom _XA_WM_COLORMAP_NOTIFY
;
1813 if (te
->xclient
.message_type
== _XA_WM_COLORMAP_NOTIFY
)
1815 set_client_controls_colormaps(te
->xclient
.data
.l
[1]);
1820 /* CKH - if we get here, it was an unknown client message, so send
1821 * it to the client if it was in a window we know about. I'm not so
1822 * sure this should be done or not, since every other window manager
1823 * I've looked at doesn't. But it might be handy for a free drag and
1824 * drop setup being developed for Linux. */
1827 if (te
->xclient
.window
!= FW_W(fw
))
1832 e
.xclient
.window
= FW_W(fw
);
1833 FSendEvent(dpy
, FW_W(fw
), False
, NoEventMask
, &e
);
1838 void HandleColormapNotify(const evh_args_t
*ea
)
1840 colormap_handle_colormap_notify(ea
);
1845 void HandleConfigureRequest(const evh_args_t
*ea
)
1847 const XEvent
*te
= ea
->exc
->x
.etrigger
;
1848 XConfigureRequestEvent cre
;
1849 FvwmWindow
*fw
= ea
->exc
->w
.fw
;
1851 DBUG("HandleConfigureRequest", "Routine Entered");
1853 cre
= te
->xconfigurerequest
;
1854 /* te->xany.window is te->.xconfigurerequest.parent, so the context
1855 * window may be wrong. */
1856 if (XFindContext(dpy
, cre
.window
, FvwmContext
, (caddr_t
*)&fw
) ==
1862 __handle_configure_request(cre
, ea
, fw
, False
);
1865 void HandleDestroyNotify(const evh_args_t
*ea
)
1867 DBUG("HandleDestroyNotify", "Routine Entered");
1869 destroy_window(ea
->exc
->w
.fw
);
1870 EWMH_ManageKdeSysTray(
1871 ea
->exc
->x
.etrigger
->xdestroywindow
.window
,
1872 ea
->exc
->x
.etrigger
->type
);
1873 EWMH_WindowDestroyed();
1874 GNOME_SetClientList();
1879 #define DEBUG_ENTERNOTIFY 0
1880 #if DEBUG_ENTERNOTIFY
1881 static int ecount
=0;
1882 #define ENTER_DBG(x) fprintf x;
1884 #define ENTER_DBG(x)
1886 void HandleEnterNotify(const evh_args_t
*ea
)
1888 const XEnterWindowEvent
*ewp
;
1891 static Bool is_initial_ungrab_pending
= True
;
1892 Bool is_tear_off_menu
;
1893 const XEvent
*te
= ea
->exc
->x
.etrigger
;
1894 FvwmWindow
* const fw
= ea
->exc
->w
.fw
;
1896 DBUG("HandleEnterNotify", "Routine Entered");
1897 ewp
= &te
->xcrossing
;
1898 ENTER_DBG((stderr
, "++++++++ en (%d): fw 0x%08x w 0x%08x sw 0x%08xmode 0x%x detail 0x%x '%s'\n", ++ecount
, (int)fw
, (int)ewp
->window
, (int)ewp
->subwindow
, ewp
->mode
, ewp
->detail
, fw
?fw
->visible_name
:"(none)"));
1900 if (ewp
->window
== Scr
.Root
&& ewp
->subwindow
== None
&&
1901 ewp
->detail
== NotifyInferior
&& ewp
->mode
== NotifyNormal
)
1904 MX_ENTER_WINDOW
, 3, (long)Scr
.Root
, (long)NULL
,
1907 if (Scr
.ColormapFocus
== COLORMAP_FOLLOWS_MOUSE
)
1909 if (fw
&& !IS_ICONIFIED(fw
) && ewp
->window
== FW_W(fw
))
1911 InstallWindowColormaps(fw
);
1915 /* make sure its for one of our windows */
1916 /* handle a subwindow cmap */
1917 InstallWindowColormaps(NULL
);
1922 EnterSubWindowColormap(ewp
->window
);
1924 if (Scr
.flags
.is_wire_frame_displayed
)
1926 ENTER_DBG((stderr
, "en: exit: iwfd\n"));
1927 /* Ignore EnterNotify events while a window is resized or moved
1928 * as a wire frame; otherwise the window list may be screwed
1934 if (ewp
->window
!= FW_W_FRAME(fw
) &&
1935 ewp
->window
!= FW_W_PARENT(fw
) &&
1936 ewp
->window
!= FW_W(fw
) &&
1937 ewp
->window
!= FW_W_ICON_TITLE(fw
) &&
1938 ewp
->window
!= FW_W_ICON_PIXMAP(fw
))
1940 /* Ignore EnterNotify that received by any of the sub
1941 * windows that don't handle this event. unclutter
1942 * triggers these events sometimes, re focusing an
1943 * unfocused window under the pointer */
1944 ENTER_DBG((stderr
, "en: exit: funny window\n"));
1948 if (Scr
.focus_in_pending_window
!= NULL
)
1950 ENTER_DBG((stderr
, "en: exit: fipw\n"));
1951 /* Ignore EnterNotify event while we are waiting for a window to
1952 * receive focus via Focus or FlipFocus commands. */
1953 focus_grab_buttons(fw
);
1956 if (ewp
->mode
== NotifyGrab
)
1958 ENTER_DBG((stderr
, "en: exit: NotifyGrab\n"));
1961 else if (ewp
->mode
== NotifyNormal
)
1963 ENTER_DBG((stderr
, "en: NotifyNormal\n"));
1964 if (ewp
->detail
== NotifyNonlinearVirtual
&&
1965 ewp
->focus
== False
&& ewp
->subwindow
!= None
)
1967 /* This takes care of some buggy apps that forget that
1968 * one of their dialog subwindows has the focus after
1969 * popping up a selection list several times (ddd,
1970 * netscape). I'm not convinced that this does not
1971 * break something else. */
1972 ENTER_DBG((stderr
, "en: NN: refreshing focus\n"));
1976 else if (ewp
->mode
== NotifyUngrab
)
1978 ENTER_DBG((stderr
, "en: NotifyUngrab\n"));
1979 /* Ignore events generated by grabbing or ungrabbing the
1980 * pointer. However, there is no way to prevent the client
1981 * application from handling this event and, for example,
1982 * grabbing the focus. This will interfere with functions that
1983 * transferred the focus to a different window. */
1984 if (is_initial_ungrab_pending
)
1986 ENTER_DBG((stderr
, "en: NU: initial ungrab pending (lgw = NULL)\n"));
1987 is_initial_ungrab_pending
= False
;
1988 xcrossing_last_grab_window
= NULL
;
1992 if (ewp
->detail
== NotifyNonlinearVirtual
&&
1993 ewp
->focus
== False
&& ewp
->subwindow
!= None
)
1995 /* see comment above */
1996 ENTER_DBG((stderr
, "en: NU: refreshing focus\n"));
1999 if (fw
&& fw
== xcrossing_last_grab_window
)
2001 ENTER_DBG((stderr
, "en: exit: NU: is last grab window\n"));
2002 if (ewp
->window
== FW_W_FRAME(fw
) ||
2003 ewp
->window
== FW_W_ICON_TITLE(fw
) ||
2004 ewp
->window
== FW_W_ICON_PIXMAP(fw
))
2006 ENTER_DBG((stderr
, "en: exit: NU: last grab window = NULL\n"));
2007 xcrossing_last_grab_window
= NULL
;
2009 focus_grab_buttons(fw
);
2015 if (ewp
->window
!= FW_W_FRAME(fw
) &&
2016 ewp
->window
!= FW_W_ICON_TITLE(fw
) &&
2017 ewp
->window
!= FW_W_ICON_PIXMAP(fw
))
2019 ENTER_DBG((stderr
, "en: exit: NU: not frame window\n"));
2020 focus_grab_buttons(fw
);
2028 is_initial_ungrab_pending
= False
;
2031 /* look for a matching leaveNotify which would nullify this EnterNotify
2034 * RBW - if we're in startup, this is a coerced focus, so we don't
2035 * want to save the event time, or exit prematurely.
2037 * Ignore LeaveNotify events for tear out menus - handled by menu code
2040 (fw
&& IS_TEAR_OFF_MENU(fw
) && ewp
->window
== FW_W(fw
));
2041 if (!fFvwmInStartup
&& !is_tear_off_menu
&&
2042 FCheckTypedWindowEvent(dpy
, ewp
->window
, LeaveNotify
, &d
))
2044 if (d
.xcrossing
.mode
== NotifyNormal
&&
2045 d
.xcrossing
.detail
!= NotifyInferior
)
2047 ENTER_DBG((stderr
, "en: exit: found LeaveNotify\n"));
2052 if (ewp
->window
== Scr
.Root
)
2054 FvwmWindow
*lf
= get_last_screen_focus_window();
2056 if (!Scr
.flags
.is_pointer_on_this_screen
)
2058 Scr
.flags
.is_pointer_on_this_screen
= 1;
2059 if (lf
&& lf
!= &Scr
.FvwmRoot
&&
2060 !FP_DO_UNFOCUS_LEAVE(FW_FOCUS_POLICY(lf
)))
2062 SetFocusWindow(lf
, True
, FOCUS_SET_FORCE
);
2064 else if (lf
!= &Scr
.FvwmRoot
)
2070 /* This was the first EnterNotify event for the
2071 * root window - ignore */
2073 set_last_screen_focus_window(NULL
);
2075 else if (!(sf
= get_focus_window()) ||
2076 FP_DO_UNFOCUS_LEAVE(FW_FOCUS_POLICY(sf
)))
2081 Scr
.UnknownWinFocused
!= None
&& sf
!= NULL
&&
2082 FW_W(sf
) == Scr
.StolenFocusWin
)
2084 __refocus_stolen_focus_win(ea
);
2086 if (Scr
.ColormapFocus
== COLORMAP_FOLLOWS_MOUSE
)
2088 InstallWindowColormaps(NULL
);
2090 focus_grab_buttons(lf
);
2095 Scr
.flags
.is_pointer_on_this_screen
= 1;
2098 /* An EnterEvent in one of the PanFrameWindows activates the Paging or
2100 if (is_pan_frame(ewp
->window
))
2102 char *edge_command
= NULL
;
2105 Scr
.UnknownWinFocused
!= None
&&
2106 (sf
= get_focus_window()) != NULL
&&
2107 FW_W(sf
) == Scr
.StolenFocusWin
)
2109 __refocus_stolen_focus_win(ea
);
2111 /* check for edge commands */
2112 if (ewp
->window
== Scr
.PanFrameTop
.win
)
2114 edge_command
= Scr
.PanFrameTop
.command
;
2116 else if (ewp
->window
== Scr
.PanFrameBottom
.win
)
2118 edge_command
= Scr
.PanFrameBottom
.command
;
2120 else if (ewp
->window
== Scr
.PanFrameLeft
.win
)
2122 edge_command
= Scr
.PanFrameLeft
.command
;
2124 else if (ewp
->window
== Scr
.PanFrameRight
.win
)
2126 edge_command
= Scr
.PanFrameRight
.command
;
2128 if (edge_command
&& ewp
->mode
== NotifyUngrab
&&
2129 ewp
->detail
== NotifyAncestor
)
2133 else if (edge_command
)
2135 execute_function(NULL
, ea
->exc
, edge_command
, 0);
2139 /* no edge command for this pan frame - so we do
2145 /* this was in the HandleMotionNotify before, HEDU */
2146 Scr
.flags
.is_pointer_on_this_screen
= 1;
2149 &e
, Scr
.EdgeScrollX
, Scr
.EdgeScrollY
, &JunkX
,
2150 &JunkY
, &delta_x
, &delta_y
, True
, True
, False
);
2158 if (IS_EWMH_DESKTOP(FW_W(fw
)))
2161 MX_ENTER_WINDOW
, 3, (long)Scr
.Root
, (long)NULL
,
2165 if (ewp
->window
== FW_W_FRAME(fw
) ||
2166 ewp
->window
== FW_W_ICON_TITLE(fw
) ||
2167 ewp
->window
== FW_W_ICON_PIXMAP(fw
))
2170 MX_ENTER_WINDOW
, 3, (long)FW_W(fw
),
2171 (long)FW_W_FRAME(fw
), (unsigned long)fw
);
2173 sf
= get_focus_window();
2174 if (sf
&& fw
!= sf
&& FP_DO_UNFOCUS_LEAVE(FW_FOCUS_POLICY(sf
)))
2176 ENTER_DBG((stderr
, "en: delete focus\n"));
2179 focus_grab_buttons(fw
);
2180 if (FP_DO_FOCUS_ENTER(FW_FOCUS_POLICY(fw
)))
2182 ENTER_DBG((stderr
, "en: set mousey focus\n"));
2183 if (ewp
->window
== FW_W(fw
))
2185 /* Event is for the client window...*/
2186 #ifndef EXPERIMENTAL_ROU_HANDLING_V2
2187 /* RBW -- This may still be needed at times, I'm not
2189 SetFocusWindowClientEntered(
2190 fw
, True
, FOCUS_SET_BY_ENTER
);
2192 SetFocusWindow(fw
, True
, FOCUS_SET_BY_ENTER
);
2197 /* Event is for the frame...*/
2198 SetFocusWindow(fw
, True
, FOCUS_SET_BY_ENTER
);
2201 else if (focus_is_focused(fw
) && focus_does_accept_input_focus(fw
))
2203 /* We have to refresh the focus window here in case we left the
2204 * focused fvwm window. Motif apps may lose the input focus
2205 * otherwise. But do not try to refresh the focus of
2206 * applications that want to handle it themselves. */
2207 focus_force_refresh_focus(fw
);
2211 /* Give the window a chance to grab the buttons needed for
2213 focus_grab_buttons(sf
);
2216 Scr
.UnknownWinFocused
!= None
&& sf
!= NULL
&&
2217 FW_W(sf
) == Scr
.StolenFocusWin
)
2219 __refocus_stolen_focus_win(ea
);
2221 /* We get an EnterNotify with mode == UnGrab when fvwm releases the
2222 * grab held during iconification. We have to ignore this, or icon
2223 * title will be initially raised. */
2224 if (IS_ICONIFIED(fw
) && (ewp
->mode
== NotifyNormal
) &&
2225 (ewp
->window
== FW_W_ICON_PIXMAP(fw
) ||
2226 ewp
->window
== FW_W_ICON_TITLE(fw
)) &&
2227 FW_W_ICON_PIXMAP(fw
) != None
)
2229 SET_ICON_ENTERED(fw
, 1);
2230 DrawIconWindow(fw
, True
, False
, False
, False
, NULL
);
2232 /* Check for tear off menus */
2233 if (is_tear_off_menu
)
2235 menu_enter_tear_off_menu(ea
->exc
);
2241 void HandleExpose(const evh_args_t
*ea
)
2244 FvwmWindow
* const fw
= ea
->exc
->w
.fw
;
2246 e
= *ea
->exc
->x
.etrigger
;
2248 /* This doesn't work well. Sometimes, the expose count is zero although
2249 * dozens of expose events are pending. This happens all the time
2250 * during a shading animation. Simply flush expose events
2251 * unconditionally. */
2252 if (e
.xexpose
.count
!= 0)
2254 flush_accumulate_expose(e
.xexpose
.window
, &e
);
2257 flush_accumulate_expose(e
.xexpose
.window
, &e
);
2263 if (e
.xany
.window
== FW_W_ICON_TITLE(fw
) ||
2264 e
.xany
.window
== FW_W_ICON_PIXMAP(fw
))
2266 DrawIconWindow(fw
, True
, True
, False
, False
, &e
);
2269 else if (IS_TEAR_OFF_MENU(fw
) && e
.xany
.window
== FW_W(fw
))
2271 /* refresh the contents of the torn out menu */
2272 menu_expose(&e
, NULL
);
2278 void HandleFocusIn(const evh_args_t
*ea
)
2282 Window focus_w
= None
;
2283 Window focus_fw
= None
;
2286 FvwmWindow
*ffw_old
= get_focus_window();
2288 Bool do_force_broadcast
= False
;
2289 Bool is_unmanaged_focused
= False
;
2290 static Window last_focus_w
= None
;
2291 static Window last_focus_fw
= None
;
2292 static Bool was_nothing_ever_focused
= True
;
2293 FvwmWindow
*fw
= ea
->exc
->w
.fw
;
2295 DBUG("HandleFocusIn", "Routine Entered");
2297 Scr
.focus_in_pending_window
= NULL
;
2298 /* This is a hack to make the PointerKey command work */
2299 if (ea
->exc
->x
.etrigger
->xfocus
.detail
!= NotifyPointer
)
2302 w
= ea
->exc
->x
.etrigger
->xany
.window
;
2304 while (FCheckTypedEvent(dpy
, FocusIn
, &d
))
2307 if (d
.xfocus
.detail
!= NotifyPointer
)
2319 if (XFindContext(dpy
, w
, FvwmContext
, (caddr_t
*) &fw
) == XCNOENT
)
2324 Scr
.UnknownWinFocused
= None
;
2327 if (w
!= Scr
.NoFocusWin
)
2329 Scr
.UnknownWinFocused
= w
;
2330 Scr
.StolenFocusWin
=
2331 (ffw_old
!= NULL
) ? FW_W(ffw_old
) : None
;
2333 is_unmanaged_focused
= True
;
2335 /* Only show a non-focused window as focused,
2336 * if the focus is on unmanaged and flickering qt dialogs
2337 * workaround is on. */
2338 if (!Scr
.bo
.do_enable_flickering_qt_dialogs_workaround
||
2339 !is_unmanaged_focused
)
2341 border_draw_decorations(
2342 Scr
.Hilite
, PART_ALL
, False
, True
, CLEAR_ALL
,
2344 if (Scr
.ColormapFocus
== COLORMAP_FOLLOWS_FOCUS
)
2346 if ((Scr
.Hilite
)&&(!IS_ICONIFIED(Scr
.Hilite
)))
2348 InstallWindowColormaps(Scr
.Hilite
);
2352 InstallWindowColormaps(NULL
);
2356 /* Not very useful if no window that fvwm and its modules know
2357 * about has the focus. */
2358 fc
= GetColor(DEFAULT_FORE_COLOR
);
2359 bc
= GetColor(DEFAULT_BACK_COLOR
);
2361 else if (fw
!= Scr
.Hilite
||
2362 /* domivogt (16-May-2000): This check is necessary to force
2363 * sending a M_FOCUS_CHANGE packet after an unmanaged window
2364 * was focused. Otherwise fvwm would believe that Scr.Hilite
2365 * was still focused and not send any info to the modules. */
2366 last_focus_fw
== None
||
2367 IS_FOCUS_CHANGE_BROADCAST_PENDING(fw
))
2369 do_force_broadcast
= IS_FOCUS_CHANGE_BROADCAST_PENDING(fw
);
2370 SET_FOCUS_CHANGE_BROADCAST_PENDING(fw
, 0);
2371 if (fw
!= Scr
.Hilite
)
2373 border_draw_decorations(
2374 fw
, PART_ALL
, True
, True
, CLEAR_ALL
, NULL
,
2378 focus_fw
= FW_W_FRAME(fw
);
2379 fc
= fw
->hicolors
.fore
;
2380 bc
= fw
->hicolors
.back
;
2381 set_focus_window(fw
);
2382 if (Scr
.ColormapFocus
== COLORMAP_FOLLOWS_FOCUS
)
2384 if ((Scr
.Hilite
)&&(!IS_ICONIFIED(Scr
.Hilite
)))
2386 InstallWindowColormaps(Scr
.Hilite
);
2390 InstallWindowColormaps(NULL
);
2398 if (was_nothing_ever_focused
|| last_focus_fw
== None
||
2399 focus_w
!= last_focus_w
|| focus_fw
!= last_focus_fw
||
2402 if (!Scr
.bo
.do_enable_flickering_qt_dialogs_workaround
||
2403 !is_unmanaged_focused
)
2406 M_FOCUS_CHANGE
, 5, (long)focus_w
,
2408 (unsigned long)IsLastFocusSetByMouse(),
2409 (long)fc
, (long)bc
);
2410 EWMH_SetActiveWindow(focus_w
);
2412 last_focus_w
= focus_w
;
2413 last_focus_fw
= focus_fw
;
2414 was_nothing_ever_focused
= False
;
2416 if ((sf
= get_focus_window()) != ffw_old
)
2418 focus_grab_buttons(sf
);
2419 focus_grab_buttons(ffw_old
);
2425 void HandleFocusOut(const evh_args_t
*ea
)
2427 if (Scr
.UnknownWinFocused
!= None
&& Scr
.StolenFocusWin
!= None
&&
2428 ea
->exc
->x
.etrigger
->xfocus
.window
== Scr
.UnknownWinFocused
)
2430 __refocus_stolen_focus_win(ea
);
2436 void __handle_key(const evh_args_t
*ea
, Bool is_press
)
2442 const XEvent
*te
= ea
->exc
->x
.etrigger
;
2443 const FvwmWindow
* const fw
= ea
->exc
->w
.fw
;
2444 Bool is_second_binding
;
2445 const XClassHint
*winClass1
, *winClass2
;
2447 char *name1
, *name2
;
2448 const exec_context_t
*exc
;
2449 exec_context_changes_t ecc
;
2453 /* Here's a real hack - some systems have two keys with the
2454 * same keysym and different keycodes. This converts all
2455 * the cases to one keycode. */
2456 kc
= XKeysymToKeycode(dpy
, XKeycodeToKeysym(dpy
, te
->xkey
.keycode
, 0));
2458 /* Check if there is something bound to the key */
2460 sf
= get_focus_window();
2463 tmp
.res_name
= tmp
.res_class
= name1
= "root";
2469 winClass1
= &sf
->class;
2470 name1
= sf
->name
.name
;
2471 kcontext
= (sf
== fw
? ea
->exc
->w
.wcontext
: C_WINDOW
);
2476 tmp
.res_name
= tmp
.res_class
= name2
= "root";
2481 winClass2
= &fw
->class;
2482 name2
= fw
->name
.name
;
2484 /* Searching the binding list with a different 'type' value
2485 * (ie. BIND_KEYPRESS vs BIND_PKEYPRESS) doesn't make a difference.
2486 * The different context value does though. */
2487 action
= CheckTwoBindings(
2488 &is_second_binding
, Scr
.AllBindings
, STROKE_ARG(0) kc
,
2489 te
->xkey
.state
, GetUnusedModifiers(), kcontext
, BIND_KEYPRESS
,
2490 winClass1
, name1
, ea
->exc
->w
.wcontext
, BIND_PKEYPRESS
,
2497 XAllowEvents(dpy
, AsyncKeyboard
, CurrentTime
);
2501 if (is_second_binding
== False
)
2504 ecc
.w
.wcontext
= kcontext
;
2505 exc
= exc_clone_context(
2506 ea
->exc
, &ecc
, ECC_FW
| ECC_WCONTEXT
);
2508 execute_function(NULL
, exc
, action
, 0);
2509 if (is_second_binding
== False
)
2511 exc_destroy_context(exc
);
2513 XAllowEvents(dpy
, AsyncKeyboard
, CurrentTime
);
2517 /* if we get here, no function key was bound to the key. Send it
2518 * to the client if it was in a window we know about. */
2519 sf
= get_focus_window();
2520 if (sf
&& te
->xkey
.window
!= FW_W(sf
))
2525 e
.xkey
.window
= FW_W(sf
);
2527 dpy
, e
.xkey
.window
, False
,
2528 (is_press
)? KeyPressMask
:KeyReleaseMask
, &e
);
2530 else if (fw
&& te
->xkey
.window
!= FW_W(fw
))
2535 e
.xkey
.window
= FW_W(fw
);
2537 dpy
, e
.xkey
.window
, False
,
2538 (is_press
)? KeyPressMask
:KeyReleaseMask
, &e
);
2540 XAllowEvents(dpy
, AsyncKeyboard
, CurrentTime
);
2545 void HandleKeyPress(const evh_args_t
*ea
)
2547 __handle_key(ea
, True
);
2550 void HandleKeyRelease(const evh_args_t
*ea
)
2552 __handle_key(ea
, False
);
2555 void HandleLeaveNotify(const evh_args_t
*ea
)
2557 const XEvent
*te
= ea
->exc
->x
.etrigger
;
2558 FvwmWindow
* const fw
= ea
->exc
->w
.fw
;
2560 DBUG("HandleLeaveNotify", "Routine Entered");
2562 ENTER_DBG((stderr
, "-------- ln (%d): fw 0x%08x w 0x%08x sw 0x%08x mode 0x%x detail 0x%x '%s'\n", ++ecount
, (int)fw
, (int)te
->xcrossing
.window
, (int)te
->xcrossing
.subwindow
, te
->xcrossing
.mode
, te
->xcrossing
.detail
, fw
?fw
->visible_name
:"(none)"));
2563 /* Ignore LeaveNotify events while a window is resized or moved as a
2564 * wire frame; otherwise the window list may be screwed up. */
2565 if (Scr
.flags
.is_wire_frame_displayed
)
2569 if (te
->xcrossing
.mode
!= NotifyNormal
)
2571 /* Ignore events generated by grabbing or ungrabbing the
2572 * pointer. However, there is no way to prevent the client
2573 * application from handling this event and, for example,
2574 * grabbing the focus. This will interfere with functions that
2575 * transferred the focus to a different window. It is
2576 * necessary to check for LeaveNotify events on the client
2577 * window too in case buttons are not grabbed on it. */
2578 if (te
->xcrossing
.mode
== NotifyGrab
&& fw
&&
2579 (te
->xcrossing
.window
== FW_W_FRAME(fw
) ||
2580 te
->xcrossing
.window
== FW_W(fw
) ||
2581 te
->xcrossing
.window
== FW_W_ICON_TITLE(fw
) ||
2582 te
->xcrossing
.window
== FW_W_ICON_PIXMAP(fw
)))
2584 ENTER_DBG((stderr
, "ln: *** lgw = 0x%08x\n", (int)fw
));
2585 xcrossing_last_grab_window
= fw
;
2587 #ifdef FOCUS_EXPANDS_TITLE
2588 if (fw
&& IS_ICONIFIED(fw
))
2590 SET_ICON_ENTERED(fw
, 0);
2592 fw
, True
, False
, False
, False
, NULL
);
2597 /* CDE-like behaviour of raising the icon title if the icon
2598 gets the focus (in particular if the cursor is over the icon) */
2599 if (fw
&& IS_ICONIFIED(fw
))
2601 SET_ICON_ENTERED(fw
,0);
2602 DrawIconWindow(fw
, True
, False
, False
, False
, NULL
);
2605 /* An LeaveEvent in one of the PanFrameWindows activates
2606 an EdgeLeaveCommand. */
2607 if (is_pan_frame(te
->xcrossing
.window
))
2609 char *edge_command_leave
= NULL
;
2611 /* check for edge commands */
2612 if (te
->xcrossing
.window
== Scr
.PanFrameTop
.win
)
2614 edge_command_leave
= Scr
.PanFrameTop
.command_leave
;
2616 else if (te
->xcrossing
.window
== Scr
.PanFrameBottom
.win
)
2618 edge_command_leave
= Scr
.PanFrameBottom
.command_leave
;
2620 else if (te
->xcrossing
.window
== Scr
.PanFrameLeft
.win
)
2622 edge_command_leave
= Scr
.PanFrameLeft
.command_leave
;
2624 else if (te
->xcrossing
.window
== Scr
.PanFrameRight
.win
)
2626 edge_command_leave
= Scr
.PanFrameRight
.command_leave
;
2628 if (edge_command_leave
&& te
->xcrossing
.mode
== NotifyUngrab
&&
2629 te
->xcrossing
.detail
== NotifyAncestor
)
2633 else if (edge_command_leave
)
2635 execute_function(NULL
, ea
->exc
, edge_command_leave
, 0);
2640 /* If we leave the root window, then we're really moving
2641 * another screen on a multiple screen display, and we
2642 * need to de-focus and unhighlight to make sure that we
2643 * don't end up with more than one highlighted window at a time */
2644 if (te
->xcrossing
.window
== Scr
.Root
&&
2645 /* domivogt (16-May-2000): added this test because somehow fvwm
2646 * sometimes gets a LeaveNotify on the root window although it is
2648 Scr
.NumberOfScreens
> 1)
2650 if (te
->xcrossing
.mode
== NotifyNormal
)
2652 if (te
->xcrossing
.detail
!= NotifyInferior
)
2654 FvwmWindow
*sf
= get_focus_window();
2656 Scr
.flags
.is_pointer_on_this_screen
= 0;
2657 set_last_screen_focus_window(sf
);
2662 if (Scr
.Hilite
!= NULL
)
2664 border_draw_decorations(
2665 Scr
.Hilite
, PART_ALL
, False
,
2666 True
, CLEAR_ALL
, NULL
, NULL
);
2673 /* handle a subwindow cmap */
2674 LeaveSubWindowColormap(te
->xany
.window
);
2677 (te
->xcrossing
.window
== FW_W_FRAME(fw
) ||
2678 te
->xcrossing
.window
== FW_W_ICON_TITLE(fw
) ||
2679 te
->xcrossing
.window
== FW_W_ICON_PIXMAP(fw
)))
2682 MX_LEAVE_WINDOW
, 3, (long)FW_W(fw
),
2683 (long)FW_W_FRAME(fw
), (unsigned long)fw
);
2689 void HandleMapNotify(const evh_args_t
*ea
)
2691 Bool is_on_this_page
= False
;
2692 const XEvent
*te
= ea
->exc
->x
.etrigger
;
2693 FvwmWindow
* const fw
= ea
->exc
->w
.fw
;
2695 DBUG("HandleMapNotify", "Routine Entered");
2699 if (te
->xmap
.override_redirect
== True
&&
2700 te
->xmap
.window
!= Scr
.NoFocusWin
)
2702 XSelectInput(dpy
, te
->xmap
.window
, XEVMASK_ORW
);
2704 Scr
.UnknownWinFocused
= te
->xmap
.window
;
2708 if (te
->xmap
.window
== FW_W_FRAME(fw
))
2710 /* Now that we know the frame is mapped after capturing the
2711 * window we do not need StructureNotifyMask events anymore. */
2712 XSelectInput(dpy
, FW_W_FRAME(fw
), XEVMASK_FRAMEW
);
2715 /* Except for identifying over-ride redirect window mappings, we
2716 * don't need or want windows associated with the
2717 * SubstructureNotifyMask */
2718 if (te
->xmap
.event
!= te
->xmap
.window
)
2722 SET_MAP_PENDING(fw
, 0);
2723 /* don't map if the event was caused by a de-iconify */
2724 if (IS_ICONIFY_PENDING(fw
))
2729 /* Make sure at least part of window is on this page before giving it
2731 is_on_this_page
= IsRectangleOnThisPage(&(fw
->g
.frame
), fw
->Desk
);
2734 * Need to do the grab to avoid race condition of having server send
2735 * MapNotify to client before the frame gets mapped; this is bad because
2736 * the client would think that the window has a chance of being viewable
2737 * when it really isn't.
2739 MyXGrabServer (dpy
);
2740 if (FW_W_ICON_TITLE(fw
))
2742 XUnmapWindow(dpy
, FW_W_ICON_TITLE(fw
));
2744 if (FW_W_ICON_PIXMAP(fw
) != None
)
2746 XUnmapWindow(dpy
, FW_W_ICON_PIXMAP(fw
));
2748 XMapSubwindows(dpy
, FW_W_FRAME(fw
));
2749 if (fw
->Desk
== Scr
.CurrentDesk
)
2751 XMapWindow(dpy
, FW_W_FRAME(fw
));
2753 if (IS_ICONIFIED(fw
))
2756 M_DEICONIFY
, 3, (long)FW_W(fw
), (long)FW_W_FRAME(fw
),
2762 M_MAP
, 3, (long)FW_W(fw
), (long)FW_W_FRAME(fw
),
2766 if (is_on_this_page
&&
2767 focus_query_open_grab_focus(fw
, get_focus_window()) == True
)
2769 SetFocusWindow(fw
, True
, FOCUS_SET_FORCE
);
2771 border_draw_decorations(
2772 fw
, PART_ALL
, (fw
== get_focus_window()) ? True
: False
, True
,
2773 CLEAR_ALL
, NULL
, NULL
);
2774 MyXUngrabServer (dpy
);
2776 SET_ICONIFIED(fw
, 0);
2777 SET_ICON_UNMAPPED(fw
, 0);
2778 if (DO_ICONIFY_AFTER_MAP(fw
))
2780 initial_window_options_t win_opts
;
2782 /* finally, if iconification was requested before the window
2783 * was mapped, request it now. */
2784 memset(&win_opts
, 0, sizeof(win_opts
));
2785 Iconify(fw
, &win_opts
);
2786 SET_ICONIFY_AFTER_MAP(fw
, 0);
2788 focus_grab_buttons_on_layer(fw
->layer
);
2793 void HandleMappingNotify(const evh_args_t
*ea
)
2795 XRefreshKeyboardMapping(&ea
->exc
->x
.etrigger
->xmapping
);
2800 void HandleMapRequest(const evh_args_t
*ea
)
2802 DBUG("HandleMapRequest", "Routine Entered");
2806 /* Just map the damn thing, decorations are added later
2807 * in CaptureAllWindows. */
2808 XMapWindow(dpy
, ea
->exc
->x
.etrigger
->xmaprequest
.window
);
2811 HandleMapRequestKeepRaised(ea
, None
, NULL
, NULL
);
2816 void HandleMapRequestKeepRaised(
2817 const evh_args_t
*ea
, Window KeepRaised
, FvwmWindow
*ReuseWin
,
2818 initial_window_options_t
*win_opts
)
2820 Bool is_on_this_page
= False
;
2821 Bool is_new_window
= False
;
2824 initial_window_options_t win_opts_bak
;
2828 if (win_opts
== NULL
)
2830 memset(&win_opts_bak
, 0, sizeof(win_opts_bak
));
2831 win_opts
= &win_opts_bak
;
2834 if (ReuseWin
== NULL
)
2838 pw
= ea
->exc
->x
.etrigger
->xmaprequest
.parent
;
2839 if (XFindContext(dpy
, ew
, FvwmContext
, (caddr_t
*)&fw
) ==
2844 if (fw
!= NULL
&& IS_MAP_PENDING(fw
))
2846 /* The window is already going to be mapped, no need to
2856 if (fw
== NULL
&& EWMH_IsKdeSysTrayWindow(ew
))
2858 /* This means that the window is swallowed by kicker and that
2859 * kicker restart or exit. As we should assume that kicker
2860 * restart we should return here, if not we go into trouble
2864 if (!win_opts
->flags
.do_override_ppos
)
2869 /* If the window has never been mapped before ... */
2870 if (!fw
|| (fw
&& DO_REUSE_DESTROYED(fw
)))
2872 /* Add decorations. */
2873 fw
= AddWindow(ea
->exc
, ReuseWin
, win_opts
);
2874 if (fw
== AW_NO_WINDOW
)
2878 else if (fw
== AW_UNMANAGED
)
2880 XMapWindow(dpy
, ew
);
2883 is_new_window
= True
;
2886 * Make sure at least part of window is on this page
2887 * before giving it focus...
2889 is_on_this_page
= IsRectangleOnThisPage(&(fw
->g
.frame
), fw
->Desk
);
2890 if (KeepRaised
!= None
)
2892 XRaiseWindow(dpy
, KeepRaised
);
2894 /* If it's not merely iconified, and we have hints, use them. */
2896 if (IS_ICONIFIED(fw
))
2898 /* If no hints, or currently an icon, just "deiconify" */
2901 else if (IS_MAPPED(fw
))
2903 /* the window is already mapped - fake a MapNotify event */
2904 fake_map_unmap_notify(fw
, MapNotify
);
2910 if (fw
->wmhints
&& (fw
->wmhints
->flags
& StateHint
))
2912 state
= fw
->wmhints
->initial_state
;
2916 state
= NormalState
;
2918 if (win_opts
->initial_state
!= DontCareState
)
2920 state
= win_opts
->initial_state
;
2930 if (fw
->Desk
== Scr
.CurrentDesk
)
2934 SET_MAP_PENDING(fw
, 1);
2935 XMapWindow(dpy
, FW_W_FRAME(fw
));
2936 XMapWindow(dpy
, FW_W(fw
));
2937 SetMapStateProp(fw
, NormalState
);
2938 if (Scr
.flags
.is_map_desk_in_progress
)
2940 do_grab_focus
= False
;
2942 else if (!is_on_this_page
)
2944 do_grab_focus
= False
;
2946 else if (focus_query_open_grab_focus(
2947 fw
, get_focus_window()) ==
2950 do_grab_focus
= True
;
2954 do_grab_focus
= False
;
2959 fw
, True
, FOCUS_SET_FORCE
);
2963 /* make sure the old focused window
2964 * still has grabbed all necessary
2967 get_focus_window());
2972 #ifndef ICCCM2_UNMAP_WINDOW_PATCH
2973 /* nope, this is forbidden by the ICCCM2 */
2974 XMapWindow(dpy
, FW_W(fw
));
2975 SetMapStateProp(fw
, NormalState
);
2977 /* Since we will not get a MapNotify, set the
2978 * IS_MAPPED flag manually. */
2980 SetMapStateProp(fw
, IconicState
);
2981 /* fake that the window was mapped to allow
2982 * modules to swallow it */
2984 M_MAP
, 3, (long)FW_W(fw
),
2985 (long)FW_W_FRAME(fw
),
2989 MyXUngrabServer(dpy
);
2995 /* the window will not be mapped - fake a
2996 * MapNotify and an UnmapNotify event. Can't
2997 * remember exactly why this is necessary, but
2998 * probably something w/ (de)iconify state
3000 fake_map_unmap_notify(fw
, MapNotify
);
3001 fake_map_unmap_notify(fw
, UnmapNotify
);
3003 if (win_opts
->flags
.is_iconified_by_parent
||
3004 ((tmp
= get_transientfor_fvwmwindow(fw
)) &&
3007 win_opts
->flags
.is_iconified_by_parent
= 0;
3008 SET_ICONIFIED_BY_PARENT(fw
, 1);
3010 if (USE_ICON_POSITION_HINT(fw
) && fw
->wmhints
&&
3011 (fw
->wmhints
->flags
& IconPositionHint
))
3013 win_opts
->default_icon_x
= fw
->wmhints
->icon_x
;
3014 win_opts
->default_icon_y
= fw
->wmhints
->icon_y
;
3016 Iconify(fw
, win_opts
);
3023 M_WINDOWSHADE
, 3, (long)FW_W(fw
), (long)FW_W_FRAME(fw
),
3026 /* If the newly mapped window overlaps the focused window, make sure
3027 * ClickToFocusRaises and MouseFocusClickRaises work again. */
3028 sf
= get_focus_window();
3031 focus_grab_buttons(sf
);
3033 if (win_opts
->flags
.is_menu
)
3036 SET_MAP_PENDING(fw
, 0);
3038 EWMH_SetClientList();
3039 EWMH_SetClientListStacking();
3040 GNOME_SetClientList();
3046 void HandleMotionNotify(const evh_args_t
*ea
)
3048 DBUG("HandleMotionNotify", "Routine Entered");
3050 if (send_motion
== True
)
3053 ea
->exc
->x
.etrigger
->xmotion
.x
,
3054 ea
->exc
->x
.etrigger
->xmotion
.y
);
3059 #endif /* HAVE_STROKE */
3061 void HandlePropertyNotify(const evh_args_t
*ea
)
3063 Bool OnThisPage
= False
;
3064 Bool has_icon_changed
= False
;
3065 Bool has_icon_pixmap_hint_changed
= False
;
3066 Bool has_icon_window_hint_changed
= False
;
3067 FlocaleNameString new_name
= { NoName
, NULL
};
3068 int old_wmhints_flags
;
3069 const XEvent
*te
= ea
->exc
->x
.etrigger
;
3070 char *urgency_action
= NULL
;
3071 FvwmWindow
* const fw
= ea
->exc
->w
.fw
;
3073 DBUG("HandlePropertyNotify", "Routine Entered");
3075 if (te
->xproperty
.window
== Scr
.Root
&&
3076 te
->xproperty
.state
== PropertyNewValue
&&
3077 (te
->xproperty
.atom
== _XA_XSETROOT_ID
||
3078 te
->xproperty
.atom
== _XA_XROOTPMAP_ID
))
3080 /* background change */
3081 /* _XA_XSETROOT_ID is used by fvwm-root, xli and more (xv sends
3082 * no property notify?). _XA_XROOTPMAP_ID is used by Esetroot
3083 * compatible program: the problem here is that with some
3084 * Esetroot compatible program we get the message _before_ the
3085 * background change. This is fixed with Esetroot 9.2 (not yet
3086 * released, 2002-01-14) */
3088 /* update icon window with some alpha and tear-off menu */
3091 for (t
= Scr
.FvwmRoot
.next
; t
!= NULL
; t
= t
->next
)
3095 int b_cs
= t
->icon_background_cs
;
3096 Bool draw_picture
= False
;
3097 Bool draw_title
= False
;
3099 /* redraw ParentRelative tear-off menu */
3100 menu_redraw_transparent_tear_off_menu(t
, True
);
3102 if (!IS_ICONIFIED(t
) || IS_ICON_SUPPRESSED(t
))
3106 if (Scr
.Hilite
== t
)
3108 if (t
->icon_title_cs_hi
>= 0)
3110 t_cs
= cs
= t
->icon_title_cs_hi
;
3119 if (t
->icon_title_cs
>= 0)
3121 t_cs
= cs
= t
->icon_title_cs
;
3128 if (t
->icon_alphaPixmap
!= None
||
3130 Colorset
[cs
].icon_alpha_percent
< 100) ||
3131 CSET_IS_TRANSPARENT_PR(b_cs
) ||
3132 (!IS_ICON_SHAPED(t
) &&
3133 t
->icon_background_padding
> 0))
3135 draw_picture
= True
;
3137 if (CSET_IS_TRANSPARENT_PR(t_cs
))
3141 if (draw_title
|| draw_picture
)
3144 t
, draw_title
, draw_picture
, False
,
3145 draw_picture
, NULL
);
3148 if (te
->xproperty
.atom
== _XA_XROOTPMAP_ID
)
3150 update_root_transparent_colorset(te
->xproperty
.atom
);
3152 BroadcastPropertyChange(
3153 MX_PROPERTY_CHANGE_BACKGROUND
, 0, 0, "");
3162 dpy
, FW_W(fw
), &JunkRoot
, &JunkX
, &JunkY
,
3163 (unsigned int*)&JunkWidth
, (unsigned int*)&JunkHeight
,
3164 (unsigned int*)&JunkBW
, (unsigned int*)&JunkDepth
) == 0)
3170 * Make sure at least part of window is on this page
3171 * before giving it focus...
3173 OnThisPage
= IsRectangleOnThisPage(&(fw
->g
.frame
), fw
->Desk
);
3175 switch (te
->xproperty
.atom
)
3177 case XA_WM_TRANSIENT_FOR
:
3178 flush_property_notify(XA_WM_TRANSIENT_FOR
, FW_W(fw
));
3179 if (setup_transientfor(fw
) == True
)
3181 RaiseWindow(fw
, False
);
3186 flush_property_notify(XA_WM_NAME
, FW_W(fw
));
3187 if (HAS_EWMH_WM_NAME(fw
))
3191 FlocaleGetNameProperty(XGetWMName
, dpy
, FW_W(fw
), &new_name
);
3192 if (new_name
.name
== NULL
)
3194 FlocaleFreeNameProperty(&new_name
);
3197 if (strlen(new_name
.name
) > MAX_WINDOW_NAME_LEN
)
3199 /* limit to prevent hanging X server */
3200 (new_name
.name
)[MAX_WINDOW_NAME_LEN
] = 0;
3202 if (fw
->name
.name
&& strcmp(new_name
.name
, fw
->name
.name
) == 0)
3204 /* migo: some apps update their names every second */
3205 /* griph: make sure we don't free the property if it
3207 if (new_name
.name
!= fw
->name
.name
)
3209 FlocaleFreeNameProperty(&new_name
);
3214 free_window_names(fw
, True
, False
);
3215 fw
->name
= new_name
;
3216 SET_NAME_CHANGED(fw
, 1);
3217 if (fw
->name
.name
== NULL
)
3219 fw
->name
.name
= NoName
; /* must not happen */
3221 setup_visible_name(fw
, False
);
3222 BroadcastWindowIconNames(fw
, True
, False
);
3224 /* fix the name in the title bar */
3225 if (!IS_ICONIFIED(fw
))
3227 border_draw_decorations(
3228 fw
, PART_TITLE
, (Scr
.Hilite
== fw
), True
,
3229 CLEAR_ALL
, NULL
, NULL
);
3231 EWMH_SetVisibleName(fw
, False
);
3233 * if the icon name is NoName, set the name of the icon to be
3234 * the same as the window
3236 if (!WAS_ICON_NAME_PROVIDED(fw
))
3238 fw
->icon_name
= fw
->name
;
3239 setup_visible_name(fw
, True
);
3240 BroadcastWindowIconNames(fw
, False
, True
);
3245 case XA_WM_ICON_NAME
:
3246 flush_property_notify(XA_WM_ICON_NAME
, FW_W(fw
));
3247 if (HAS_EWMH_WM_ICON_NAME(fw
))
3251 FlocaleGetNameProperty(
3252 XGetWMIconName
, dpy
, FW_W(fw
), &new_name
);
3253 if (new_name
.name
== NULL
)
3255 FlocaleFreeNameProperty(&new_name
);
3258 if (new_name
.name
&& strlen(new_name
.name
) > MAX_ICON_NAME_LEN
)
3260 /* limit to prevent hanging X server */
3261 (new_name
.name
)[MAX_ICON_NAME_LEN
] = 0;
3263 if (fw
->icon_name
.name
&&
3264 strcmp(new_name
.name
, fw
->icon_name
.name
) == 0)
3266 /* migo: some apps update their names every second */
3267 /* griph: make sure we don't free the property if it
3269 if (new_name
.name
!= fw
->icon_name
.name
)
3271 FlocaleFreeNameProperty(&new_name
);
3276 free_window_names(fw
, False
, True
);
3277 fw
->icon_name
= new_name
;
3278 SET_WAS_ICON_NAME_PROVIDED(fw
, 1);
3279 if (fw
->icon_name
.name
== NULL
)
3281 /* currently never happens */
3282 fw
->icon_name
.name
= fw
->name
.name
;
3283 SET_WAS_ICON_NAME_PROVIDED(fw
, 0);
3285 setup_visible_name(fw
, True
);
3286 BroadcastWindowIconNames(fw
, False
, True
);
3288 EWMH_SetVisibleName(fw
, True
);
3292 flush_property_notify(XA_WM_HINTS
, FW_W(fw
));
3293 /* clasen@mathematik.uni-freiburg.de - 02/01/1998 - new -
3294 * the urgency flag is an ICCCM 2.0 addition to the WM_HINTS.
3296 old_wmhints_flags
= 0;
3299 old_wmhints_flags
= fw
->wmhints
->flags
;
3300 XFree ((char *) fw
->wmhints
);
3303 if (fw
->wmhints
== NULL
)
3309 * rebuild icon if the client either provides an icon
3310 * pixmap or window or has reset the hints to `no icon'.
3312 if ((fw
->wmhints
->flags
& IconPixmapHint
) ||
3313 (old_wmhints_flags
& IconPixmapHint
))
3315 ICON_DBG((stderr
, "hpn: iph changed (%d) '%s'\n", !!(int)(fw
->wmhints
->flags
& IconPixmapHint
), fw
->name
));
3316 has_icon_pixmap_hint_changed
= True
;
3318 if ((fw
->wmhints
->flags
& IconWindowHint
) ||
3319 (old_wmhints_flags
& IconWindowHint
))
3321 ICON_DBG((stderr
, "hpn: iwh changed (%d) '%s'\n", !!(int)(fw
->wmhints
->flags
& IconWindowHint
), fw
->name
));
3322 has_icon_window_hint_changed
= True
;
3323 SET_USE_EWMH_ICON(fw
, False
);
3325 increase_icon_hint_count(fw
);
3326 if (has_icon_window_hint_changed
||
3327 has_icon_pixmap_hint_changed
)
3329 if (ICON_OVERRIDE_MODE(fw
) == ICON_OVERRIDE
)
3331 ICON_DBG((stderr
, "hpn: icon override '%s'\n", fw
->name
));
3332 has_icon_changed
= False
;
3334 else if (ICON_OVERRIDE_MODE(fw
) ==
3335 NO_ACTIVE_ICON_OVERRIDE
)
3337 if (has_icon_pixmap_hint_changed
)
3339 if (WAS_ICON_HINT_PROVIDED(fw
) ==
3342 ICON_DBG((stderr
, "hpn: using further iph '%s'\n", fw
->name
));
3343 has_icon_changed
= True
;
3345 else if (fw
->icon_bitmap_file
==
3347 fw
->icon_bitmap_file
==
3350 ICON_DBG((stderr
, "hpn: using first iph '%s'\n", fw
->name
));
3351 has_icon_changed
= True
;
3355 /* ignore the first icon pixmap
3356 * hint if the application did
3357 * not provide it from the
3359 ICON_DBG((stderr
, "hpn: first iph ignored '%s'\n", fw
->name
));
3360 has_icon_changed
= False
;
3363 else if (has_icon_window_hint_changed
)
3365 ICON_DBG((stderr
, "hpn: using iwh '%s'\n", fw
->name
));
3366 has_icon_changed
= True
;
3370 ICON_DBG((stderr
, "hpn: iwh not changed, hint ignored '%s'\n", fw
->name
));
3371 has_icon_changed
= False
;
3374 else /* NO_ICON_OVERRIDE */
3376 ICON_DBG((stderr
, "hpn: using hint '%s'\n", fw
->name
));
3377 has_icon_changed
= True
;
3380 if (USE_EWMH_ICON(fw
))
3382 has_icon_changed
= False
;
3385 if (has_icon_changed
)
3387 ICON_DBG((stderr
, "hpn: icon changed '%s'\n", fw
->name
));
3388 /* Okay, the icon hint has changed and style
3389 * options tell us to honour this change. Now
3390 * let's see if we have to use the application
3391 * provided pixmap or window (if any), the icon
3392 * file provided by the window's style or the
3393 * default style's icon. */
3394 if (fw
->icon_bitmap_file
== Scr
.DefaultIcon
)
3396 fw
->icon_bitmap_file
= NULL
;
3398 if (!fw
->icon_bitmap_file
&&
3399 !(fw
->wmhints
->flags
&
3400 (IconPixmapHint
|IconWindowHint
)))
3402 fw
->icon_bitmap_file
=
3404 Scr
.DefaultIcon
: NULL
;
3406 fw
->iconPixmap
= (Window
)NULL
;
3407 ChangeIconPixmap(fw
);
3411 /* clasen@mathematik.uni-freiburg.de - 02/01/1998 - new -
3412 * the urgency flag is an ICCCM 2.0 addition to the WM_HINTS.
3413 * Treat urgency changes by calling user-settable functions.
3414 * These could e.g. deiconify and raise the window or
3415 * temporarily change the decor. */
3416 if (!(old_wmhints_flags
& XUrgencyHint
) &&
3417 (fw
->wmhints
->flags
& XUrgencyHint
))
3419 urgency_action
= "Function UrgencyFunc";
3421 if ((old_wmhints_flags
& XUrgencyHint
) &&
3422 !(fw
->wmhints
->flags
& XUrgencyHint
))
3424 urgency_action
= "Function UrgencyDoneFunc";
3428 const exec_context_t
*exc
;
3429 exec_context_changes_t ecc
;
3432 ecc
.w
.wcontext
= C_WINDOW
;
3433 exc
= exc_clone_context(
3434 ea
->exc
, &ecc
, ECC_FW
| ECC_WCONTEXT
);
3435 execute_function(NULL
, exc
, urgency_action
, 0);
3436 exc_destroy_context(exc
);
3439 case XA_WM_NORMAL_HINTS
:
3440 /* just mark wm normal hints as changed and look them up when
3441 * the next ConfigureRequest w/ x, y, width or height set
3443 SET_HAS_NEW_WM_NORMAL_HINTS(fw
, 1);
3446 if (te
->xproperty
.atom
== _XA_WM_PROTOCOLS
)
3448 FetchWmProtocols (fw
);
3450 else if (te
->xproperty
.atom
== _XA_WM_COLORMAP_WINDOWS
)
3452 FetchWmColormapWindows (fw
); /* frees old data */
3453 ReInstallActiveColormap();
3455 else if (te
->xproperty
.atom
== _XA_WM_STATE
)
3457 if (fw
&& OnThisPage
&& focus_is_focused(fw
) &&
3458 FP_DO_FOCUS_ENTER(FW_FOCUS_POLICY(fw
)))
3460 /* refresh the focus - why? */
3461 focus_force_refresh_focus(fw
);
3466 EWMH_ProcessPropertyNotify(ea
->exc
);
3472 void HandleReparentNotify(const evh_args_t
*ea
)
3474 const XEvent
*te
= ea
->exc
->x
.etrigger
;
3475 FvwmWindow
* const fw
= ea
->exc
->w
.fw
;
3481 if (te
->xreparent
.parent
== Scr
.Root
)
3483 /* Ignore reparenting to the root window. In some cases these
3484 * events are selected although the window is no longer
3488 if (te
->xreparent
.parent
!= FW_W_FRAME(fw
))
3490 /* window was reparented by someone else, destroy the frame */
3491 SetMapStateProp(fw
, WithdrawnState
);
3492 EWMH_RestoreInitialStates(fw
, te
->type
);
3493 if (!IS_TEAR_OFF_MENU(fw
))
3495 XRemoveFromSaveSet(dpy
, te
->xreparent
.window
);
3496 XSelectInput(dpy
, te
->xreparent
.window
, NoEventMask
);
3500 XSelectInput(dpy
, te
->xreparent
.window
, XEVMASK_MENUW
);
3502 discard_events(XEVMASK_FRAMEW
);
3504 EWMH_ManageKdeSysTray(te
->xreparent
.window
, te
->type
);
3505 EWMH_WindowDestroyed();
3511 void HandleSelectionRequest(const evh_args_t
*ea
)
3513 icccm2_handle_selection_request(ea
->exc
->x
.etrigger
);
3518 void HandleSelectionClear(const evh_args_t
*ea
)
3520 icccm2_handle_selection_clear();
3525 void HandleShapeNotify(const evh_args_t
*ea
)
3527 FvwmWindow
* const fw
= ea
->exc
->w
.fw
;
3529 DBUG("HandleShapeNotify", "Routine Entered");
3531 if (FShapesSupported
)
3533 const FShapeEvent
*sev
=
3534 (const FShapeEvent
*)(ea
->exc
->x
.etrigger
);
3540 if (sev
->kind
!= FShapeBounding
)
3545 fw
, fw
->g
.frame
.width
, fw
->g
.frame
.height
, sev
->shaped
);
3546 GNOME_SetWinArea(fw
);
3547 EWMH_SetFrameStrut(fw
);
3548 if (!IS_ICONIFIED(fw
))
3550 border_redraw_decorations(fw
);
3557 void HandleUnmapNotify(const evh_args_t
*ea
)
3563 const XEvent
*te
= ea
->exc
->x
.etrigger
;
3566 Bool must_return
= False
;
3567 Bool do_map
= False
;
3568 FvwmWindow
* const fw
= ea
->exc
->w
.fw
;
3572 DBUG("HandleUnmapNotify", "Routine Entered");
3574 /* Don't ignore events as described below. */
3575 if (te
->xunmap
.event
!= te
->xunmap
.window
&&
3576 (te
->xunmap
.event
!= Scr
.Root
|| !te
->xunmap
.send_event
))
3582 * The July 27, 1988 ICCCM spec states that a client wishing to switch
3583 * to WithdrawnState should send a synthetic UnmapNotify with the
3584 * event field set to (pseudo-)root, in case the window is already
3585 * unmapped (which is the case for fvwm for IconicState).
3586 * Unfortunately, we looked for the FvwmContext using that field, so
3587 * try the window field also. */
3593 dpy
, te
->xunmap
.window
, FvwmContext
,
3594 (caddr_t
*)&fw
) == XCNOENT
)
3600 pw
= FW_W_PARENT(fw
);
3601 if (te
->xunmap
.window
== FW_W_FRAME(fw
))
3603 SET_ICONIFY_PENDING(fw
, 0);
3613 Bool is_map_request_pending
;
3614 check_if_event_args args
;
3616 args
.w
= te
->xunmap
.window
;
3617 args
.do_return_true
= False
;
3618 args
.do_return_true_cr
= False
;
3619 /* Using FCheckTypedWindowEvent() does not work here. I don't
3620 * have the slightest idea why, but using FCheckIfEvent() with
3621 * the appropriate predicate procedure works fine. */
3622 FCheckIfEvent(dpy
, &dummy
, test_map_request
, (XPointer
)&args
);
3623 /* Unfortunately, there is no procedure in X that simply tests
3624 * if an event of a certain type in on the queue without
3625 * waiting and without removing it from the queue.
3626 * XCheck...Event() does not wait but removes the event while
3627 * XPeek...() does not remove the event but waits. To solve
3628 * this, the predicate procedure sets a flag in the passed in
3629 * structure and returns False unconditionally. */
3630 is_map_request_pending
= (args
.ret_does_match
== True
);
3631 if (!is_map_request_pending
)
3633 XUnmapWindow(dpy
, te
->xunmap
.window
);
3636 if (fw
== Scr
.Hilite
)
3640 focus_grabbed
= focus_query_close_release_focus(fw
);
3641 restore_focus_after_unmap(fw
, False
);
3642 if (!IS_MAPPED(fw
) && !IS_ICONIFIED(fw
))
3648 * The program may have unmapped the client window, from either
3649 * NormalState or IconicState. Handle the transition to WithdrawnState.
3651 * We need to reparent the window back to the root (so that fvwm exiting
3652 * won't cause it to get mapped) and then throw away all state (pretend
3653 * that we've received a DestroyNotify).
3655 if (!FCheckTypedWindowEvent(
3656 dpy
, te
->xunmap
.window
, DestroyNotify
, &dummy
) &&
3657 XTranslateCoordinates(
3658 dpy
, te
->xunmap
.window
, Scr
.Root
, 0, 0, &dstx
, &dsty
,
3662 SetMapStateProp(fw
, WithdrawnState
);
3663 EWMH_RestoreInitialStates(fw
, te
->type
);
3664 if (FCheckTypedWindowEvent(
3665 dpy
, te
->xunmap
.window
, ReparentNotify
, &dummy
))
3667 if (fw
->attr_backup
.border_width
)
3669 XSetWindowBorderWidth(
3670 dpy
, te
->xunmap
.window
,
3671 fw
->attr_backup
.border_width
);
3673 if ((!IS_ICON_SUPPRESSED(fw
))&&
3675 (fw
->wmhints
->flags
& IconWindowHint
)))
3677 XUnmapWindow(dpy
, fw
->wmhints
->icon_window
);
3682 RestoreWithdrawnLocation(fw
, False
, Scr
.Root
);
3684 if (!IS_TEAR_OFF_MENU(fw
))
3686 XRemoveFromSaveSet(dpy
, te
->xunmap
.window
);
3687 XSelectInput(dpy
, te
->xunmap
.window
, NoEventMask
);
3690 MyXUngrabServer(dpy
);
3691 if (FCheckTypedWindowEvent(dpy
, pw
, MapRequest
, &map_event
))
3693 /* the client tried to map the window again while it
3694 * was still inside the decoration windows */
3699 if (focus_grabbed
== True
)
3701 CoerceEnterNotifyOnCurrentWindow();
3703 EWMH_ManageKdeSysTray(te
->xunmap
.window
, te
->type
);
3704 EWMH_WindowDestroyed();
3705 GNOME_SetClientList();
3708 map_event
.xmaprequest
.window
= cw
;
3709 map_event
.xmaprequest
.parent
= Scr
.Root
;
3710 dispatch_event(&map_event
);
3711 /* note: we really should handle all map and unmap notify
3712 * events for that window in a loop here */
3718 void HandleVisibilityNotify(const evh_args_t
*ea
)
3720 FvwmWindow
* const fw
= ea
->exc
->w
.fw
;
3722 DBUG("HandleVisibilityNotify", "Routine Entered");
3724 if (fw
&& ea
->exc
->x
.etrigger
->xvisibility
.window
== FW_W_FRAME(fw
))
3726 switch (ea
->exc
->x
.etrigger
->xvisibility
.state
)
3728 case VisibilityUnobscured
:
3729 SET_FULLY_VISIBLE(fw
, 1);
3730 SET_PARTIALLY_VISIBLE(fw
, 1);
3732 case VisibilityPartiallyObscured
:
3733 SET_FULLY_VISIBLE(fw
, 0);
3734 SET_PARTIALLY_VISIBLE(fw
, 1);
3737 SET_FULLY_VISIBLE(fw
, 0);
3738 SET_PARTIALLY_VISIBLE(fw
, 0);
3741 /* Make sure the button grabs are up to date */
3742 focus_grab_buttons(fw
);
3748 /* ---------------------------- interface functions ------------------------ */
3750 /* Inform a client window of its geometry.
3752 * The input (frame) geometry will be translated to client geometry
3753 * before sending. */
3754 void SendConfigureNotify(
3755 FvwmWindow
*fw
, int x
, int y
, int w
, int h
, int bw
,
3756 Bool send_for_frame_too
)
3758 XEvent client_event
;
3761 if (!fw
|| IS_SHADED(fw
))
3765 client_event
.type
= ConfigureNotify
;
3766 client_event
.xconfigure
.display
= dpy
;
3767 client_event
.xconfigure
.event
= FW_W(fw
);
3768 client_event
.xconfigure
.window
= FW_W(fw
);
3769 get_window_borders(fw
, &b
);
3770 client_event
.xconfigure
.x
= x
+ b
.top_left
.width
;
3771 client_event
.xconfigure
.y
= y
+ b
.top_left
.height
;
3772 client_event
.xconfigure
.width
= w
- b
.total_size
.width
;
3773 client_event
.xconfigure
.height
= h
- b
.total_size
.height
;
3774 client_event
.xconfigure
.border_width
= bw
;
3775 client_event
.xconfigure
.above
= FW_W_FRAME(fw
);
3776 client_event
.xconfigure
.override_redirect
= False
;
3779 "send cn: %d %d %dx%d fw 0x%08x w 0x%08x ew 0x%08x '%s'\n",
3780 client_event
.xconfigure
.x
, client_event
.xconfigure
.y
,
3781 client_event
.xconfigure
.width
, client_event
.xconfigure
.height
,
3782 (int)FW_W_FRAME(fw
), (int)FW_W(fw
),
3783 (int)client_event
.xconfigure
.window
,
3784 (fw
->name
.name
) ? fw
->name
.name
: "");
3787 dpy
, FW_W(fw
), False
, StructureNotifyMask
, &client_event
);
3788 if (send_for_frame_too
)
3790 /* This is for buggy tk, which waits for the real
3791 * ConfigureNotify on frame instead of the synthetic one on w.
3792 * The geometry data in the event will not be correct for the
3793 * frame, but tk doesn't look at that data anyway. */
3794 client_event
.xconfigure
.event
= FW_W_FRAME(fw
);
3795 client_event
.xconfigure
.window
= FW_W_FRAME(fw
);
3797 dpy
, FW_W_FRAME(fw
), False
, StructureNotifyMask
,
3806 ** InitEventHandlerJumpTable
3808 void InitEventHandlerJumpTable(void)
3812 for (i
=0; i
<LASTEvent
; i
++)
3814 EventHandlerJumpTable
[i
] = NULL
;
3816 EventHandlerJumpTable
[Expose
] = HandleExpose
;
3817 EventHandlerJumpTable
[DestroyNotify
] = HandleDestroyNotify
;
3818 EventHandlerJumpTable
[MapRequest
] = HandleMapRequest
;
3819 EventHandlerJumpTable
[MapNotify
] = HandleMapNotify
;
3820 EventHandlerJumpTable
[UnmapNotify
] = HandleUnmapNotify
;
3821 EventHandlerJumpTable
[ButtonPress
] = HandleButtonPress
;
3822 EventHandlerJumpTable
[EnterNotify
] = HandleEnterNotify
;
3823 EventHandlerJumpTable
[LeaveNotify
] = HandleLeaveNotify
;
3824 EventHandlerJumpTable
[FocusIn
] = HandleFocusIn
;
3825 EventHandlerJumpTable
[FocusOut
] = HandleFocusOut
;
3826 EventHandlerJumpTable
[ConfigureRequest
] = HandleConfigureRequest
;
3827 EventHandlerJumpTable
[ClientMessage
] = HandleClientMessage
;
3828 EventHandlerJumpTable
[PropertyNotify
] = HandlePropertyNotify
;
3829 EventHandlerJumpTable
[KeyPress
] = HandleKeyPress
;
3830 EventHandlerJumpTable
[KeyRelease
] = HandleKeyRelease
;
3831 EventHandlerJumpTable
[VisibilityNotify
] = HandleVisibilityNotify
;
3832 EventHandlerJumpTable
[ColormapNotify
] = HandleColormapNotify
;
3833 if (FShapesSupported
)
3835 EventHandlerJumpTable
[FShapeEventBase
+FShapeNotify
] =
3838 EventHandlerJumpTable
[SelectionClear
] = HandleSelectionClear
;
3839 EventHandlerJumpTable
[SelectionRequest
] = HandleSelectionRequest
;
3840 EventHandlerJumpTable
[ReparentNotify
] = HandleReparentNotify
;
3841 EventHandlerJumpTable
[MappingNotify
] = HandleMappingNotify
;
3842 STROKE_CODE(EventHandlerJumpTable
[ButtonRelease
] = HandleButtonRelease
);
3843 STROKE_CODE(EventHandlerJumpTable
[MotionNotify
] = HandleMotionNotify
);
3844 #ifdef MOUSE_DROPPINGS
3845 STROKE_CODE(stroke_init(dpy
,DefaultRootWindow(dpy
)));
3846 #else /* no MOUSE_DROPPINGS */
3847 STROKE_CODE(stroke_init());
3848 #endif /* MOUSE_DROPPINGS */
3853 /* handle a single X event */
3854 void dispatch_event(XEvent
*e
)
3856 Window w
= e
->xany
.window
;
3859 DBUG("dispatch_event", "Routine Entered");
3868 if (e
->xbutton
.subwindow
!= None
)
3870 w
= e
->xbutton
.subwindow
;
3873 w
= e
->xmaprequest
.window
;
3879 if (w
== Scr
.Root
||
3880 XFindContext(dpy
, w
, FvwmContext
, (caddr_t
*)&fw
) == XCNOENT
)
3884 last_event_type
= e
->type
;
3885 if (EventHandlerJumpTable
[e
->type
])
3888 exec_context_changes_t ecc
;
3891 ecc
.type
= EXCT_EVENT
;
3893 ecc
.w
.wcontext
= GetContext(&fw
, fw
, e
, &dummyw
);
3896 ea
.exc
= exc_create_context(
3897 &ecc
, ECC_TYPE
| ECC_ETRIGGER
| ECC_FW
| ECC_W
|
3899 (*EventHandlerJumpTable
[e
->type
])(&ea
);
3900 exc_destroy_context(ea
.exc
);
3904 /* If we're using the C version of alloca, see if anything needs to be
3909 DBUG("dispatch_event", "Leaving Routine");
3914 /* ewmh configure request */
3915 void events_handle_configure_request(
3916 XConfigureRequestEvent cre
, FvwmWindow
*fw
, Bool force
)
3918 __handle_configure_request(cre
, NULL
, fw
, force
);
3921 void HandleEvents(void)
3925 DBUG("HandleEvents", "Routine Entered");
3926 STROKE_CODE(send_motion
= False
);
3927 while (!isTerminated
)
3929 last_event_type
= 0;
3930 if (Scr
.flags
.is_window_scheduled_for_destroy
)
3932 destroy_scheduled_windows();
3934 if (Scr
.flags
.do_need_window_update
)
3936 flush_window_updates();
3938 if (My_XNextEvent(dpy
, &ev
))
3940 dispatch_event(&ev
);
3942 if (Scr
.flags
.do_need_style_list_update
)
3944 simplify_style_list();
3953 * Waits for next X or module event, fires off startup routines when startup
3954 * modules have finished or after a timeout if the user has specified a
3955 * command line module that doesn't quit or gets stuck.
3958 int My_XNextEvent(Display
*dpy
, XEvent
*event
)
3960 fd_set in_fdset
, out_fdset
;
3963 fmodule_input
*input
;
3964 static struct timeval timeout
;
3965 static struct timeval
*timeoutP
= &timeout
;
3967 DBUG("My_XNextEvent", "Routine Entered");
3969 /* include this next bit if HandleModuleInput() gets called anywhere
3970 * else with queueing turned on. Because this routine is the only
3971 * place that queuing is on _and_ ExecuteCommandQueue is always called
3972 * immediately after it is impossible for there to be anything in the
3973 * queue at this point */
3975 /* execute any commands queued up */
3976 DBUG("My_XNextEvent", "executing module comand queue");
3977 ExecuteCommandQueue();
3980 /* check for any X events already queued up.
3981 * Side effect: this does an XFlush if no events are queued
3982 * Make sure nothing between here and the select causes further
3983 * X requests to be sent or the select may block even though
3984 * there are events in the queue */
3988 "My_XNextEvent", "taking care of queued up events"
3989 " & returning (1)");
3990 FNextEvent(dpy
, event
);
3994 /* The SIGCHLD signal is sent every time one of our child processes
3995 * dies, and the SIGCHLD handler now reaps them automatically. We
3996 * should therefore never see a zombie */
3998 DBUG("My_XNextEvent", "no X events waiting - about to reap children");
3999 /* Zap all those zombies! */
4000 /* If we get to here, then there are no X events waiting to be
4001 * processed. Just take a moment to check for dead children. */
4005 /* check for termination of all startup modules */
4008 module
= module_get_next(NULL
);
4009 for (; module
!= NULL
; module
= module_get_next(module
))
4011 if (MOD_IS_CMDLINE(module
) == 1)
4021 "Starting up after command lines modules");
4022 /* set an infinite timeout to stop ticking */
4024 /* This may cause X requests to be sent */
4027 return 0; /* so return without select()ing */
4031 /* Some signals can interrupt us while we wait for any action
4032 * on our descriptors. While some of these signals may be asking
4033 * fvwm to die, some might be harmless. Harmless interruptions
4034 * mean we have to start waiting all over again ... */
4038 Bool is_waiting_for_scheduled_command
= False
;
4039 static struct timeval
*old_timeoutP
= NULL
;
4041 /* The timeouts become undefined whenever the select returns,
4042 * and so we have to reinitialise them */
4043 ms
= squeue_get_next_ms();
4046 /* run scheduled commands */
4048 ms
= squeue_get_next_ms();
4049 /* should not happen anyway.
4050 * get_next_schedule_queue_ms() can't return 0 after a
4051 * call to execute_schedule_queue(). */
4059 timeout
.tv_sec
= 42;
4060 timeout
.tv_usec
= 0;
4064 /* scheduled commands are pending - don't wait too
4066 timeout
.tv_sec
= ms
/ 1000;
4067 timeout
.tv_usec
= 1000 * (ms
% 1000);
4068 old_timeoutP
= timeoutP
;
4069 timeoutP
= &timeout
;
4070 is_waiting_for_scheduled_command
= True
;
4074 FD_ZERO(&out_fdset
);
4075 FD_SET(x_fd
, &in_fdset
);
4077 /* nothing is done here if fvwm was compiled without session
4081 FD_SET(sm_fd
, &in_fdset
);
4084 module
= module_get_next(NULL
);
4085 for (; module
!= NULL
; module
= module_get_next(module
))
4087 FD_SET(MOD_READFD(module
), &in_fdset
);
4089 if (!FQUEUE_IS_EMPTY(&MOD_PIPEQUEUE(module
)))
4091 FD_SET(MOD_WRITEFD(module
), &out_fdset
);
4095 DBUG("My_XNextEvent", "waiting for module input/output");
4096 num_fd
= fvwmSelect(
4097 fvwmlib_max_fd
, &in_fdset
, &out_fdset
, 0, timeoutP
);
4098 if (is_waiting_for_scheduled_command
)
4100 timeoutP
= old_timeoutP
;
4103 /* Express route out of FVWM ... */
4108 } while (num_fd
< 0);
4112 /* Check for module input. */
4113 module
= module_get_next(NULL
);
4114 for (; module
!= NULL
; module
= module_get_next(module
))
4116 if (FD_ISSET(MOD_READFD(module
), &in_fdset
))
4118 input
= module_receive(module
);
4119 /* enqueue the received command */
4120 module_input_enqueue(input
);
4123 MOD_WRITEFD(module
) >= 0 &&
4124 FD_ISSET(MOD_WRITEFD(module
), &out_fdset
))
4126 DBUG("My_XNextEvent",
4127 "calling FlushMessageQueue");
4128 FlushMessageQueue(module
);
4132 /* cleanup dead modules */
4135 /* execute any commands queued up */
4136 DBUG("My_XNextEvent", "executing module comand queue");
4137 ExecuteCommandQueue();
4139 /* nothing is done here if fvwm was compiled without session
4141 if ((sm_fd
>= 0) && (FD_ISSET(sm_fd
, &in_fdset
)))
4149 /* select has timed out, things must have calmed down so let's
4153 fvwm_msg(ERR
, "My_XNextEvent",
4154 "Some command line modules have not quit, "
4155 "Starting up after timeout.\n");
4157 timeoutP
= NULL
; /* set an infinite timeout to stop
4159 reset_style_changes();
4160 Scr
.flags
.do_need_window_update
= 0;
4162 /* run scheduled commands if necessary */
4166 /* check for X events again, rather than return 0 and get called again
4170 DBUG("My_XNextEvent",
4171 "taking care of queued up events & returning (2)");
4172 FNextEvent(dpy
,event
);
4176 DBUG("My_XNextEvent", "leaving My_XNextEvent");
4183 * Find the Fvwm context for the event.
4186 int GetContext(FvwmWindow
**ret_fw
, FvwmWindow
*t
, const XEvent
*e
, Window
*w
)
4193 Bool is_key_event
= False
;
4195 win
= e
->xany
.window
;
4196 context
= C_NO_CONTEXT
;
4203 subw
= e
->xkey
.subwindow
;
4204 if (win
== Scr
.Root
&& subw
!= None
)
4206 /* Translate root coordinates into subwindow
4207 * coordinates. Necessary for key bindings that work
4208 * over unfocused windows. */
4210 XTranslateCoordinates(
4211 dpy
, Scr
.Root
, subw
, x
, y
, &x
, &y
, &subw
);
4212 XFindContext(dpy
, win
, FvwmContext
, (caddr_t
*) &t
);
4214 is_key_event
= True
;
4222 subw
= e
->xbutton
.subwindow
;
4224 if (t
&& win
== FW_W_FRAME(t
) && subw
!= None
)
4226 /* Translate frame coordinates into subwindow
4229 XTranslateCoordinates(
4230 dpy
, FW_W_FRAME(t
), subw
, x
, y
, &x
, &y
, &subw
);
4231 if (win
== FW_W_PARENT(t
))
4234 XTranslateCoordinates(
4235 dpy
, FW_W_PARENT(t
), subw
, x
, y
, &x
,
4241 XFindContext(dpy
, win
, FvwmContext
, (caddr_t
*)&t
);
4253 if (*w
== Scr
.NoFocusWin
)
4259 if (win
== FW_W_PARENT(t
))
4268 context
= frame_window_id_to_context(t
, *w
, &Button
);
4275 * Removes expose events for a specific window from the queue
4278 int flush_expose(Window w
)
4283 while (FCheckTypedWindowEvent(dpy
, w
, Expose
, &dummy
))
4291 /* same as above, but merges the expose rectangles into a single big one */
4292 int flush_accumulate_expose(Window w
, XEvent
*e
)
4296 int x1
= e
->xexpose
.x
;
4297 int y1
= e
->xexpose
.y
;
4298 int x2
= x1
+ e
->xexpose
.width
;
4299 int y2
= y1
+ e
->xexpose
.height
;
4301 while (FCheckTypedWindowEvent(dpy
, w
, Expose
, &dummy
))
4303 x1
= min(x1
, dummy
.xexpose
.x
);
4304 y1
= min(y1
, dummy
.xexpose
.y
);
4305 x2
= max(x2
, dummy
.xexpose
.x
+ dummy
.xexpose
.width
);
4306 y2
= max(y2
, dummy
.xexpose
.y
+ dummy
.xexpose
.height
);
4311 e
->xexpose
.width
= x2
- x1
;
4312 e
->xexpose
.height
= y2
- y1
;
4319 * Removes all expose events from the queue and does the necessary redraws
4322 void handle_all_expose(void)
4327 saved_event
= fev_save_event();
4329 while (FCheckMaskEvent(dpy
, ExposureMask
, &evdummy
))
4331 dispatch_event(&evdummy
);
4333 fev_restore_event(saved_event
);
4338 /* CoerceEnterNotifyOnCurrentWindow()
4339 * Pretends to get a HandleEnterNotify on the window that the pointer
4340 * currently is in so that the focus gets set correctly from the beginning.
4341 * Note that this presently only works if the current window is not
4342 * click_to_focus; I think that that behaviour is correct and desirable.
4344 void CoerceEnterNotifyOnCurrentWindow(void)
4350 exec_context_changes_t ecc
;
4355 dpy
, Scr
.Root
, &root
, &child
, &e
.xcrossing
.x_root
,
4356 &e
.xcrossing
.y_root
, &e
.xcrossing
.x
, &e
.xcrossing
.y
,
4358 if (f
== False
|| child
== None
)
4362 e
.xcrossing
.type
= EnterNotify
;
4363 e
.xcrossing
.window
= child
;
4364 e
.xcrossing
.subwindow
= None
;
4365 e
.xcrossing
.mode
= NotifyNormal
;
4366 e
.xcrossing
.detail
= NotifyAncestor
;
4367 e
.xcrossing
.same_screen
= True
;
4368 if (XFindContext(dpy
, child
, FvwmContext
, (caddr_t
*)&fw
) == XCNOENT
)
4374 XTranslateCoordinates(
4375 dpy
, Scr
.Root
, child
, e
.xcrossing
.x_root
,
4376 e
.xcrossing
.y_root
, &JunkX
, &JunkY
, &child
);
4377 if (child
== FW_W_PARENT(fw
))
4383 e
.xany
.window
= child
;
4386 e
.xcrossing
.focus
= (fw
== get_focus_window()) ? True
: False
;
4387 ecc
.type
= EXCT_NULL
;
4388 ecc
.x
.etrigger
= &e
;
4389 ea
.exc
= exc_create_context(&ecc
, ECC_TYPE
| ECC_ETRIGGER
);
4390 HandleEnterNotify(&ea
);
4391 exc_destroy_context(ea
.exc
);
4396 /* This function discards all queued up ButtonPress, ButtonRelease and
4397 * ButtonMotion events. */
4398 int discard_events(long event_mask
)
4404 for (count
= 0; FCheckMaskEvent(dpy
, event_mask
, &e
); count
++)
4412 /* This function discards all queued up ButtonPress, ButtonRelease and
4413 * ButtonMotion events. */
4414 int discard_window_events(Window w
, long event_mask
)
4420 for (count
= 0; FCheckWindowEvent(dpy
, w
, event_mask
, &e
); count
++)
4428 /* Similar function for certain types of PropertyNotify. */
4429 int flush_property_notify(Atom atom
, Window w
)
4433 test_typed_window_event_args args
;
4437 args
.event_type
= PropertyNotify
;
4440 dpy
, &e
, test_typed_window_event
, (XPointer
)&args
);
4445 if (e
.xproperty
.atom
!= atom
)
4449 /* remove the event from the queue */
4451 dpy
, &e
, test_typed_window_event
, (XPointer
)&args
);
4457 /* Wait for all mouse buttons to be released
4458 * This can ease some confusion on the part of the user sometimes
4460 * Discard superflous button events during this wait period. */
4461 void WaitForButtonsUp(Bool do_handle_expose
)
4465 long evmask
= ButtonPressMask
|ButtonReleaseMask
|ButtonMotionMask
|
4466 KeyPressMask
|KeyReleaseMask
;
4468 int use_wait_cursor
;
4471 if (FQueryPointer(dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
, &JunkX
, &JunkY
,
4472 &JunkX
, &JunkY
, &mask
) == False
)
4474 /* pointer is on a different screen - that's okay here */
4476 mask
&= DEFAULT_ALL_BUTTONS_MASK
;
4481 if (do_handle_expose
)
4483 evmask
|= ExposureMask
;
4485 GrabEm(None
, GRAB_NORMAL
);
4486 for (count
= 0, use_wait_cursor
= 0; mask
!= 0; count
++)
4488 /* handle expose events */
4489 XAllowEvents(dpy
, SyncPointer
, CurrentTime
);
4490 if (FCheckMaskEvent(dpy
, evmask
, &e
))
4495 if (e
.xbutton
.button
<=
4496 NUMBER_OF_MOUSE_BUTTONS
)
4498 bmask
= (Button1Mask
<<
4499 (e
.xbutton
.button
- 1));
4500 mask
= e
.xbutton
.state
& ~bmask
;
4513 dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
,
4514 &JunkX
, &JunkY
, &JunkX
, &JunkY
, &mask
) ==
4517 /* pointer is on a different screen - that's
4520 mask
&= DEFAULT_ALL_BUTTONS_MASK
;
4523 if (use_wait_cursor
== 0 && count
== 20)
4525 GrabEm(CRS_WAIT
, GRAB_NORMAL
);
4526 use_wait_cursor
= 1;
4529 UngrabEm(GRAB_NORMAL
);
4530 if (use_wait_cursor
)
4532 UngrabEm(GRAB_NORMAL
);
4539 void sync_server(int toggle
)
4541 static Bool synced
= False
;
4545 toggle
= (synced
== False
);
4555 XSynchronize(dpy
, synced
);
4561 Bool
is_resizing_event_pending(
4565 check_if_event_args args
;
4568 args
.do_return_true
= False
;
4569 args
.do_return_true_cr
= False
;
4570 args
.cr_value_mask
= 0;
4571 args
.ret_does_match
= False
;
4573 FCheckIfEvent(dpy
, &e
, test_resizing_event
, (XPointer
)&args
);
4575 return args
.ret_does_match
;
4578 /* ---------------------------- builtin commands --------------------------- */
4580 void CMD_XSynchronize(F_CMD_ARGS
)
4584 toggle
= ParseToggleArgument(action
, NULL
, -1, 0);
4585 sync_server(toggle
);
4590 void CMD_XSync(F_CMD_ARGS
)