1 /* event.c- event loop and handling
3 * Window Maker window manager
5 * Copyright (c) 1997, 1998 Alfredo K. Kojima
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
33 #include <X11/Xutil.h>
35 #include <X11/extensions/shape.h>
41 #ifdef KEEP_XKB_LOCK_STATUS
42 #include <X11/XKBlib.h>
43 #endif /* KEEP_XKB_LOCK_STATUS */
45 #include "WindowMaker.h"
51 #include "application.h"
54 #include "workspace.h"
57 #include "properties.h"
66 /******** Global Variables **********/
67 extern XContext wWinContext
;
69 extern Cursor wCursor
[WCUR_LAST
];
71 extern WShortKey wKeyBindings
[WKBD_LAST
];
72 extern int wScreenCount
;
73 extern Time LastTimestamp
;
74 extern Time LastFocusChange
;
76 extern WPreferences wPreferences
;
78 #define MOD_MASK wPreferences.modifier_mask
80 extern Atom _XA_WM_COLORMAP_NOTIFY
;
82 extern Atom _XA_WM_CHANGE_STATE
;
83 extern Atom _XA_WM_DELETE_WINDOW
;
84 extern Atom _XA_GNUSTEP_WM_MINIATURIZE_WINDOW
;
85 extern Atom _XA_WINDOWMAKER_WM_FUNCTION
;
88 extern Atom _XA_DND_PROTOCOL
;
93 extern Bool wShapeSupported
;
94 extern int wShapeEventBase
;
98 extern char WProgramState
;
99 extern char WDelayedActionSet
;
102 /************ Local stuff ***********/
105 static void saveTimestamp(XEvent
*event
);
106 static void handleColormapNotify();
107 static void handleMapNotify(), handleUnmapNotify();
108 static void handleButtonPress(), handleExpose();
109 static void handleDestroyNotify();
110 static void handleConfigureRequest();
111 static void handleMapRequest();
112 static void handlePropertyNotify();
113 static void handleEnterNotify();
114 static void handleLeaveNotify();
115 static void handleExtensions();
116 static void handleClientMessage();
117 static void handleKeyPress();
118 static void handleFocusIn();
119 static void handleMotionNotify();
120 static void handleVisibilityNotify();
124 static void handleShapeNotify();
127 /* called from the signal handler */
128 void NotifyDeadProcess(pid_t pid
, unsigned char status
);
130 /* real dead process handler */
131 static void handleDeadProcess(void *foo
);
134 typedef struct DeadProcesses
{
136 unsigned char exit_status
;
139 /* stack of dead processes */
140 static DeadProcesses deadProcesses
[MAX_DEAD_PROCESSES
];
141 static int deadProcessPtr
=0;
144 typedef struct DeathHandler
{
145 WDeathHandler
*callback
;
147 struct DeathHandler
*next
;
151 static DeathHandler
*deathHandler
=NULL
;
156 wAddDeathHandler(pid_t pid
, WDeathHandler
*callback
, void *cdata
)
158 DeathHandler
*handler
;
160 handler
= malloc(sizeof(DeathHandler
));
165 handler
->callback
= callback
;
166 handler
->client_data
= cdata
;
168 handler
->next
= deathHandler
;
170 deathHandler
= handler
;
178 wDeleteDeathHandler(WMagicNumber id
)
180 DeathHandler
*tmp
, *handler
=(DeathHandler
*)id
;
182 if (!handler
|| !deathHandler
)
187 deathHandler
= handler
->next
;
191 if (tmp
->next
==handler
) {
192 tmp
->next
=handler
->next
;
203 DispatchEvent(XEvent
*event
)
206 handleDeadProcess(NULL
);
208 if (WProgramState
==WSTATE_NEED_EXIT
) {
209 WProgramState
= WSTATE_EXITING
;
210 /* received SIGTERM */
212 * WMHandleEvent() can't be called from anything
213 * executed inside here, or we can get in a infinite
216 Shutdown(WSExitMode
);
218 } else if (WProgramState
== WSTATE_NEED_RESTART
) {
219 WProgramState
= WSTATE_RESTARTING
;
221 Shutdown(WSRestartPreparationMode
);
222 /* received SIGHUP */
226 /* for the case that all that is wanted to be dispatched is
231 saveTimestamp(event
);
232 switch (event
->type
) {
234 handleMapRequest(event
);
238 handleKeyPress(event
);
242 handleMotionNotify(event
);
245 case ConfigureRequest
:
246 handleConfigureRequest(event
);
250 handleDestroyNotify(event
);
254 handleMapNotify(event
);
258 handleUnmapNotify(event
);
262 handleButtonPress(event
);
270 handlePropertyNotify(event
);
274 handleEnterNotify(event
);
278 handleLeaveNotify(event
);
282 handleClientMessage(event
);
286 handleColormapNotify(event
);
290 if (event
->xmapping
.request
== MappingKeyboard
291 || event
->xmapping
.request
== MappingModifier
)
292 XRefreshKeyboardMapping(&event
->xmapping
);
296 handleFocusIn(event
);
299 case VisibilityNotify
:
300 handleVisibilityNotify(event
);
304 handleExtensions(event
);
311 *----------------------------------------------------------------------
313 * Processes X and internal events indefinitely.
319 * The LastTimestamp global variable is updated.
320 *----------------------------------------------------------------------
328 WMNextEvent(dpy
, &event
);
329 WMHandleEvent(&event
);
336 IsDoubleClick(WScreen
*scr
, XEvent
*event
)
338 if ((scr
->last_click_time
>0) &&
339 (event
->xbutton
.time
-scr
->last_click_time
<=wPreferences
.dblclick_time
)
340 && (event
->xbutton
.button
== scr
->last_click_button
)
341 && (event
->xbutton
.window
== scr
->last_click_window
)) {
343 scr
->flags
.next_click_is_not_double
= 1;
344 scr
->last_click_time
= 0;
345 scr
->last_click_window
= event
->xbutton
.window
;
354 NotifyDeadProcess(pid_t pid
, unsigned char status
)
356 if (deadProcessPtr
>=MAX_DEAD_PROCESSES
-1) {
357 wwarning(_("stack overflow: too many dead processes"));
360 /* stack the process to be handled later,
361 * as this is called from the signal handler */
362 deadProcesses
[deadProcessPtr
].pid
= pid
;
363 deadProcesses
[deadProcessPtr
].exit_status
= status
;
369 handleDeadProcess(void *foo
)
374 for (i
=0; i
<deadProcessPtr
; i
++) {
375 wWindowDeleteSavedStatesForPID(deadProcesses
[i
].pid
);
383 /* get the pids on the queue and call handlers */
384 while (deadProcessPtr
>0) {
393 if (tmp
->pid
== deadProcesses
[deadProcessPtr
].pid
) {
394 (*tmp
->callback
)(tmp
->pid
,
395 deadProcesses
[deadProcessPtr
].exit_status
,
397 wDeleteDeathHandler(tmp
);
406 saveTimestamp(XEvent
*event
)
408 LastTimestamp
= CurrentTime
;
410 switch (event
->type
) {
413 LastTimestamp
= event
->xbutton
.time
;
417 LastTimestamp
= event
->xkey
.time
;
420 LastTimestamp
= event
->xmotion
.time
;
423 LastTimestamp
= event
->xproperty
.time
;
427 LastTimestamp
= event
->xcrossing
.time
;
430 LastTimestamp
= event
->xselectionclear
.time
;
432 case SelectionRequest
:
433 LastTimestamp
= event
->xselectionrequest
.time
;
435 case SelectionNotify
:
436 LastTimestamp
= event
->xselection
.time
;
443 handleExtensions(XEvent
*event
)
446 if (wShapeSupported
&& event
->type
== (wShapeEventBase
+ShapeNotify
)) {
447 handleShapeNotify(event
);
454 handleMapRequest(XEvent
*ev
)
458 Window window
= ev
->xmaprequest
.window
;
461 printf("got map request for %x\n", (unsigned)window
);
464 if ((wwin
= wWindowFor(window
))) {
465 if (wwin
->flags
.shaded
) {
466 wUnshadeWindow(wwin
);
468 /* deiconify window */
469 if (wwin
->flags
.miniaturized
) {
470 wDeiconifyWindow(wwin
);
471 } else if (wwin
->flags
.hidden
) {
472 WApplication
*wapp
= wApplicationOf(wwin
->main_window
);
473 /* go to the last workspace that the user worked on the app */
474 #ifndef REDUCE_APPICONS
475 /* This severely breaks REDUCE_APPICONS. last_workspace is a neat
476 * concept but it needs to be reworked to handle REDUCE_APPICONS -cls
479 wWorkspaceChange(wwin
->screen_ptr
, wapp
->last_workspace
);
482 wUnhideApplication(wapp
, False
, False
);
487 scr
= wScreenForRootWindow(ev
->xmaprequest
.parent
);
489 wwin
= wManageWindow(scr
, window
);
492 * This is to let the Dock know that the application it launched
493 * has already been mapped (eg: it has finished launching).
494 * It is not necessary for normally docked apps, but is needed for
495 * apps that were forcedly docked (like with dockit).
497 if (scr
->last_dock
) {
498 if (wwin
&& wwin
->main_window
!=None
&& wwin
->main_window
!=window
)
499 wDockTrackWindowLaunch(scr
->last_dock
, wwin
->main_window
);
501 wDockTrackWindowLaunch(scr
->last_dock
, window
);
507 if (wwin
->wm_hints
&& (wwin
->wm_hints
->flags
& StateHint
))
508 state
= wwin
->wm_hints
->initial_state
;
512 if (state
== IconicState
)
513 wwin
->flags
.miniaturized
= 1;
515 if (state
== WithdrawnState
) {
516 wwin
->flags
.mapped
= 0;
517 wClientSetState(wwin
, WithdrawnState
, None
);
518 wUnmanageWindow(wwin
, True
, False
);
520 wClientSetState(wwin
, NormalState
, None
);
521 if (wwin
->flags
.maximized
) {
522 wMaximizeWindow(wwin
, wwin
->flags
.maximized
);
524 if (wwin
->flags
.shaded
) {
525 wwin
->flags
.shaded
= 0;
526 wwin
->flags
.skip_next_animation
= 1;
529 if (wwin
->flags
.miniaturized
) {
530 wwin
->flags
.miniaturized
= 0;
531 wwin
->flags
.skip_next_animation
= 1;
532 wIconifyWindow(wwin
);
534 if (wwin
->flags
.hidden
) {
535 WApplication
*wapp
= wApplicationOf(wwin
->main_window
);
537 wwin
->flags
.hidden
= 0;
538 wwin
->flags
.skip_next_animation
= 1;
540 wHideApplication(wapp
);
549 handleDestroyNotify(XEvent
*event
)
553 Window window
= event
->xdestroywindow
.window
;
556 puts("got destroy notify");
559 wwin
= wWindowFor(window
);
561 wUnmanageWindow(wwin
, False
, True
);
564 app
= wApplicationOf(window
);
566 if (window
== app
->main_window
) {
568 wwin
= app
->main_window_desc
->screen_ptr
->focused_window
;
570 if (wwin
->main_window
== window
) {
571 wwin
->main_window
= None
;
576 wApplicationDestroy(app
);
580 wKWMCheckDestroy(&event
->xdestroywindow
);
587 handleExpose(XEvent
*event
)
589 WObjDescriptor
*desc
;
596 while (XCheckTypedWindowEvent(dpy
, event
->xexpose
.window
, Expose
, &ev
));
598 if (XFindContext(dpy
, event
->xexpose
.window
, wWinContext
,
599 (XPointer
*)&desc
)==XCNOENT
) {
603 if (desc
->handle_expose
) {
604 (*desc
->handle_expose
)(desc
, event
);
611 handleButtonPress(XEvent
*event
)
613 WObjDescriptor
*desc
;
617 puts("got button press");
620 scr
= wScreenForRootWindow(event
->xbutton
.root
);
628 if (event
->xbutton
.window
==scr
->root_win
) {
631 if (wGNOMEProxyizeButtonEvent(scr
, event
))
635 if (event
->xbutton
.button
==wPreferences
.menu_button
) {
636 OpenRootMenu(scr
, event
->xbutton
.x_root
,
637 event
->xbutton
.y_root
, False
);
639 if (scr
->root_menu
) {
640 if (scr
->root_menu
->brother
->flags
.mapped
)
641 event
->xbutton
.window
= scr
->root_menu
->brother
->frame
->core
->window
;
643 event
->xbutton
.window
= scr
->root_menu
->frame
->core
->window
;
645 } else if (event
->xbutton
.button
==wPreferences
.windowl_button
) {
646 OpenSwitchMenu(scr
, event
->xbutton
.x_root
,
647 event
->xbutton
.y_root
, False
);
648 if (scr
->switch_menu
) {
649 if (scr
->switch_menu
->brother
->flags
.mapped
)
650 event
->xbutton
.window
= scr
->switch_menu
->brother
->frame
->core
->window
;
652 event
->xbutton
.window
= scr
->switch_menu
->frame
->core
->window
;
654 } else if (event
->xbutton
.button
==wPreferences
.select_button
) {
655 wUnselectWindows(scr
);
656 wSelectWindows(scr
, event
);
658 #ifdef MOUSE_WS_SWITCH
659 else if (event
->xbutton
.button
==Button4
) {
661 wWorkspaceRelativeChange(scr
, -1);
663 } else if (event
->xbutton
.button
==Button5
) {
665 wWorkspaceRelativeChange(scr
, 1);
668 #endif /* MOUSE_WS_SWITCH */
672 if (XFindContext(dpy
, event
->xbutton
.subwindow
, wWinContext
,
673 (XPointer
*)&desc
)==XCNOENT
) {
674 if (XFindContext(dpy
, event
->xbutton
.window
, wWinContext
,
675 (XPointer
*)&desc
)==XCNOENT
) {
680 if (desc
->handle_mousedown
!=NULL
) {
681 (*desc
->handle_mousedown
)(desc
, event
);
684 if (desc
->parent_type
== WCLASS_WINDOW
) {
687 if (event
->xbutton
.state
& MOD_MASK
) {
688 XAllowEvents(dpy
, AsyncPointer
, CurrentTime
);
691 if (wPreferences
.focus_mode
== WKF_CLICK
) {
692 if (wPreferences
.ignore_focus_click
) {
693 XAllowEvents(dpy
, AsyncPointer
, CurrentTime
);
695 XAllowEvents(dpy
, ReplayPointer
, CurrentTime
);
698 } else if (desc
->parent_type
== WCLASS_APPICON
699 || desc
->parent_type
== WCLASS_MINIWINDOW
700 || desc
->parent_type
== WCLASS_DOCK_ICON
) {
701 if (event
->xbutton
.state
& MOD_MASK
) {
703 XAllowEvents(dpy
, AsyncPointer
, CurrentTime
);
708 /* save double-click information */
709 if (scr
->flags
.next_click_is_not_double
) {
710 scr
->flags
.next_click_is_not_double
= 0;
712 scr
->last_click_time
= event
->xbutton
.time
;
713 scr
->last_click_button
= event
->xbutton
.button
;
714 scr
->last_click_window
= event
->xbutton
.window
;
720 handleMapNotify(XEvent
*event
)
728 wwin
= wWindowFor(event
->xmap
.event
);
729 if (wwin
&& wwin
->client_win
== event
->xmap
.event
) {
730 if (wwin
->flags
.miniaturized
) {
731 wDeiconifyWindow(wwin
);
735 wClientSetState(wwin
, NormalState
, None
);
743 handleUnmapNotify(XEvent
*event
)
747 Bool withdraw
= False
;
753 /* only process windows with StructureNotify selected
754 * (ignore SubstructureNotify) */
755 wwin
= wWindowFor(event
->xunmap
.window
);
759 /* whether the event is a Withdrawal request */
760 if (event
->xunmap
.event
== wwin
->screen_ptr
->root_win
761 && event
->xunmap
.send_event
)
764 if (wwin
->client_win
!= event
->xunmap
.event
&& !withdraw
)
767 if (!wwin
->flags
.mapped
&& !withdraw
768 && wwin
->frame
->workspace
== wwin
->screen_ptr
->current_workspace
769 && !wwin
->flags
.miniaturized
&& !wwin
->flags
.hidden
)
773 XUnmapWindow(dpy
, wwin
->frame
->core
->window
);
774 wwin
->flags
.mapped
= 0;
776 /* check if the window was destroyed */
777 if (XCheckTypedWindowEvent(dpy
, wwin
->client_win
, DestroyNotify
,&ev
)) {
780 Bool reparented
= False
;
782 if (XCheckTypedWindowEvent(dpy
, wwin
->client_win
, ReparentNotify
, &ev
))
785 /* withdraw window */
786 wwin
->flags
.mapped
= 0;
788 wClientSetState(wwin
, WithdrawnState
, None
);
790 /* if the window was reparented, do not reparent it back to the
792 wUnmanageWindow(wwin
, !reparented
, False
);
799 handleConfigureRequest(XEvent
*event
)
804 puts("got configure request");
806 if (!(wwin
=wWindowFor(event
->xconfigurerequest
.window
))) {
808 * Configure request for unmapped window
810 wClientConfigure(NULL
, &(event
->xconfigurerequest
));
812 wClientConfigure(wwin
, &(event
->xconfigurerequest
));
818 handlePropertyNotify(XEvent
*event
)
828 puts("got property notify");
830 if ((wwin
=wWindowFor(event
->xproperty
.window
))) {
831 if (!XGetGeometry(dpy
, wwin
->client_win
, &jr
, &ji
, &ji
,
832 &ju
, &ju
, &ju
, &ju
)) {
835 wClientCheckProperty(wwin
, &event
->xproperty
);
837 wapp
= wApplicationOf(event
->xproperty
.window
);
839 wClientCheckProperty(wapp
->main_window_desc
, &event
->xproperty
);
842 scr
= wScreenForWindow(event
->xproperty
.window
);
843 if (scr
&& scr
->root_win
== event
->xproperty
.window
) {
845 wKWMCheckRootHintChange(scr
, &event
->xproperty
);
852 handleClientMessage(XEvent
*event
)
855 WObjDescriptor
*desc
;
858 puts("got client message");
860 /* handle transition from Normal to Iconic state */
861 if (event
->xclient
.message_type
== _XA_WM_CHANGE_STATE
862 && event
->xclient
.format
== 32
863 && event
->xclient
.data
.l
[0] == IconicState
) {
865 wwin
= wWindowFor(event
->xclient
.window
);
867 if (!wwin
->flags
.miniaturized
)
868 wIconifyWindow(wwin
);
869 } else if (event
->xclient
.message_type
== _XA_WM_COLORMAP_NOTIFY
870 && event
->xclient
.format
== 32) {
871 WScreen
*scr
= wScreenSearchForRootWindow(event
->xclient
.window
);
876 if (event
->xclient
.data
.l
[1] == 1) { /* starting */
877 wColormapAllowClientInstallation(scr
, True
);
878 } else { /* stopping */
879 wColormapAllowClientInstallation(scr
, False
);
881 } else if (event
->xclient
.message_type
== _XA_WINDOWMAKER_WM_FUNCTION
) {
884 wapp
= wApplicationOf(event
->xclient
.window
);
886 switch (event
->xclient
.data
.l
[0]) {
887 case WMFHideOtherApplications
:
888 wHideOtherApplications(wapp
->main_window_desc
);
892 case WMFHideApplication
:
893 wHideApplication(wapp
);
899 wwin
= wWindowFor(event
->xclient
.window
);
901 switch (event
->xclient
.data
.l
[0]) {
902 case WMFHideOtherApplications
:
903 wHideOtherApplications(wwin
);
906 case WMFHideApplication
:
907 wHideApplication(wApplicationOf(wwin
->main_window
));
913 } else if (wGNOMEProcessClientMessage(&event
->xclient
)) {
915 #endif /* GNOME_STUFF */
917 } else if (wKWMProcessClientMessage(&event
->xclient
)) {
919 #endif /* KWM_HINTS */
921 } else if (wXDEProcessClientMessage(&event
->xclient
)) {
925 } else if (event
->xclient
.message_type
==_XA_DND_PROTOCOL
) {
926 WScreen
*scr
= wScreenForWindow(event
->xclient
.window
);
927 if (scr
&& wDockReceiveDNDDrop(scr
,event
))
928 goto redirect_message
;
929 #endif /* OFFIX_DND */
935 * Non-standard thing, but needed by OffiX DND.
936 * For when the icon frame gets a ClientMessage
937 * that should have gone to the icon_window.
939 if (XFindContext(dpy
, event
->xbutton
.window
, wWinContext
,
940 (XPointer
*)&desc
)!=XCNOENT
) {
941 struct WIcon
*icon
=NULL
;
943 if (desc
->parent_type
== WCLASS_MINIWINDOW
) {
944 icon
= (WIcon
*)desc
->parent
;
945 } else if (desc
->parent_type
== WCLASS_DOCK_ICON
946 || desc
->parent_type
== WCLASS_APPICON
) {
947 icon
= ((WAppIcon
*)desc
->parent
)->icon
;
949 if (icon
&& (wwin
=icon
->owner
)) {
950 if (wwin
->client_win
!=event
->xclient
.window
) {
951 event
->xclient
.window
= wwin
->client_win
;
952 XSendEvent(dpy
, wwin
->client_win
, False
, NoEventMask
,
962 raiseWindow(WScreen
*scr
)
966 scr
->autoRaiseTimer
= NULL
;
968 wwin
= wWindowFor(scr
->autoRaiseWindow
);
972 if (!wwin
->flags
.destroyed
) {
973 wRaiseFrame(wwin
->frame
->core
);
974 /* this is needed or a race condition will occur */
981 handleEnterNotify(XEvent
*event
)
984 WObjDescriptor
*desc
= NULL
;
986 WScreen
*scr
= wScreenForRootWindow(event
->xcrossing
.root
);
990 puts("got enter notify");
993 if (XCheckTypedWindowEvent(dpy
, event
->xcrossing
.window
, LeaveNotify
,
995 /* already left the window... */
997 if (ev
.xcrossing
.mode
==event
->xcrossing
.mode
998 && ev
.xcrossing
.detail
==event
->xcrossing
.detail
) {
1003 if (XFindContext(dpy
, event
->xcrossing
.window
, wWinContext
,
1004 (XPointer
*)&desc
)!=XCNOENT
) {
1005 if(desc
->handle_enternotify
)
1006 (*desc
->handle_enternotify
)(desc
, event
);
1009 /* enter to window */
1010 wwin
= wWindowFor(event
->xcrossing
.window
);
1012 if (wPreferences
.focus_mode
==WKF_POINTER
1013 && event
->xcrossing
.window
==event
->xcrossing
.root
) {
1014 wSetFocusTo(scr
, NULL
);
1016 if (wPreferences
.colormap_mode
==WKF_POINTER
) {
1017 wColormapInstallForWindow(scr
, NULL
);
1019 if (scr
->autoRaiseTimer
1020 && event
->xcrossing
.root
==event
->xcrossing
.window
) {
1021 WMDeleteTimerHandler(scr
->autoRaiseTimer
);
1022 scr
->autoRaiseTimer
= NULL
;
1025 /* set auto raise timer even if in focus-follows-mouse mode
1026 * and the event is for the frame window, even if the window
1027 * has focus already. useful if you move the pointer from a focused
1028 * window to the root window and back pretty fast
1030 * set focus if in focus-follows-mouse mode and the event
1031 * is for the frame window and window doesn't have focus yet */
1032 if ((wPreferences
.focus_mode
==WKF_POINTER
1033 || wPreferences
.focus_mode
==WKF_SLOPPY
)
1034 && wwin
->frame
->core
->window
==event
->xcrossing
.window
1035 && !scr
->flags
.doing_alt_tab
) {
1037 if (!wwin
->flags
.focused
)
1038 wSetFocusTo(scr
, wwin
);
1040 if (scr
->autoRaiseTimer
)
1041 WMDeleteTimerHandler(scr
->autoRaiseTimer
);
1042 scr
->autoRaiseTimer
= NULL
;
1044 if (wPreferences
.raise_delay
&& !WFLAGP(wwin
, no_focusable
)) {
1045 scr
->autoRaiseWindow
= wwin
->frame
->core
->window
;
1047 = WMAddTimerHandler(wPreferences
.raise_delay
,
1048 (WMCallback
*)raiseWindow
, scr
);
1051 /* Install colormap for window, if the colormap installation mode
1052 * is colormap_follows_mouse */
1053 if (wPreferences
.colormap_mode
==WKF_POINTER
) {
1054 if (wwin
->client_win
==event
->xcrossing
.window
)
1055 wColormapInstallForWindow(scr
, wwin
);
1057 wColormapInstallForWindow(scr
, NULL
);
1061 /* a little kluge to hide the clip balloon */
1062 if (!wPreferences
.flags
.noclip
&& scr
->flags
.clip_balloon_mapped
) {
1064 XUnmapWindow(dpy
, scr
->clip_balloon
);
1065 scr
->flags
.clip_balloon_mapped
= 0;
1067 if (desc
->parent_type
!=WCLASS_DOCK_ICON
1068 || scr
->clip_icon
!= desc
->parent
) {
1069 XUnmapWindow(dpy
, scr
->clip_balloon
);
1070 scr
->flags
.clip_balloon_mapped
= 0;
1075 if (event
->xcrossing
.window
== event
->xcrossing
.root
1076 && event
->xcrossing
.detail
== NotifyNormal
1077 && event
->xcrossing
.detail
!= NotifyInferior
1078 && wPreferences
.focus_mode
!= WKF_CLICK
) {
1080 wSetFocusTo(scr
, scr
->focused_window
);
1084 wBalloonEnteredObject(scr
, desc
);
1090 handleLeaveNotify(XEvent
*event
)
1092 WObjDescriptor
*desc
= NULL
;
1094 if (XFindContext(dpy
, event
->xcrossing
.window
, wWinContext
,
1095 (XPointer
*)&desc
)!=XCNOENT
) {
1096 if(desc
->handle_leavenotify
)
1097 (*desc
->handle_leavenotify
)(desc
, event
);
1099 if (event
->xcrossing
.window
== event
->xcrossing
.root
1100 && event
->xcrossing
.mode
== NotifyNormal
1101 && event
->xcrossing
.detail
!= NotifyInferior
1102 && wPreferences
.focus_mode
!= WKF_CLICK
) {
1104 WScreen
*scr
= wScreenForRootWindow(event
->xcrossing
.root
);
1106 wSetFocusTo(scr
, NULL
);
1113 handleShapeNotify(XEvent
*event
)
1115 XShapeEvent
*shev
= (XShapeEvent
*)event
;
1120 puts("got shape notify");
1123 while (XCheckTypedWindowEvent(dpy
, shev
->window
, event
->type
, &ev
)) {
1124 XShapeEvent
*sev
= (XShapeEvent
*)&ev
;
1126 if (sev
->kind
== ShapeBounding
) {
1127 if (sev
->shaped
== shev
->shaped
) {
1130 XPutBackEvent(dpy
, &ev
);
1136 wwin
= wWindowFor(shev
->window
);
1137 if (!wwin
|| shev
->kind
!= ShapeBounding
)
1140 if (!shev
->shaped
&& wwin
->flags
.shaped
) {
1142 wwin
->flags
.shaped
= 0;
1143 wWindowClearShape(wwin
);
1145 } else if (shev
->shaped
) {
1147 wwin
->flags
.shaped
= 1;
1148 wWindowSetShape(wwin
);
1155 handleColormapNotify(XEvent
*event
)
1159 Bool reinstall
= False
;
1161 wwin
= wWindowFor(event
->xcolormap
.window
);
1165 scr
= wwin
->screen_ptr
;
1169 if (event
->xcolormap
.new) {
1170 XWindowAttributes attr
;
1172 XGetWindowAttributes(dpy
, wwin
->client_win
, &attr
);
1174 if (wwin
== scr
->cmap_window
&& wwin
->cmap_window_no
== 0)
1175 scr
->current_colormap
= attr
.colormap
;
1178 } else if (event
->xcolormap
.state
== ColormapUninstalled
&&
1179 scr
->current_colormap
== event
->xcolormap
.colormap
) {
1181 /* some bastard app (like XV) removed our colormap */
1183 * can't enforce or things like xscreensaver wont work
1186 } else if (event
->xcolormap
.state
== ColormapInstalled
&&
1187 scr
->current_colormap
== event
->xcolormap
.colormap
) {
1189 /* someone has put our colormap back */
1193 } while (XCheckTypedEvent(dpy
, ColormapNotify
, event
)
1194 && ((wwin
= wWindowFor(event
->xcolormap
.window
)) || 1));
1196 if (reinstall
&& scr
->current_colormap
!=None
) {
1197 if (!scr
->flags
.colormap_stuff_blocked
)
1198 XInstallColormap(dpy
, scr
->current_colormap
);
1205 handleFocusIn(XEvent
*event
)
1210 * For applications that like stealing the focus.
1212 while (XCheckTypedEvent(dpy
, FocusIn
, event
));
1213 saveTimestamp(event
);
1214 if (event
->xfocus
.mode
== NotifyUngrab
1215 || event
->xfocus
.mode
== NotifyGrab
1216 || event
->xfocus
.detail
> NotifyNonlinearVirtual
) {
1220 wwin
= wWindowFor(event
->xfocus
.window
);
1221 if (wwin
&& !wwin
->flags
.focused
) {
1222 if (wwin
->flags
.mapped
)
1223 wSetFocusTo(wwin
->screen_ptr
, wwin
);
1225 wSetFocusTo(wwin
->screen_ptr
, NULL
);
1227 WScreen
*scr
= wScreenForWindow(event
->xfocus
.window
);
1229 wSetFocusTo(scr
, NULL
);
1235 windowUnderPointer(WScreen
*scr
)
1241 if (XQueryPointer(dpy
, scr
->root_win
, &bar
, &win
, &foo
, &foo
, &foo
, &foo
,
1243 return wWindowFor(win
);
1247 #ifdef WEENDOZE_CYCLE
1250 nextToFocusAfter(WWindow
*wwin
)
1252 WWindow
*tmp
= wwin
->next
;
1255 if (wWindowCanReceiveFocus(tmp
) && !WFLAGP(tmp
, skip_window_list
)) {
1263 /* start over from the beginning of the list */
1267 while (tmp
&& tmp
!= wwin
) {
1268 if (wWindowCanReceiveFocus(tmp
) && !WFLAGP(tmp
, skip_window_list
)) {
1280 nextToFocusBefore(WWindow
*wwin
)
1282 WWindow
*tmp
= wwin
->prev
;
1285 if (wWindowCanReceiveFocus(tmp
) && !WFLAGP(tmp
, skip_window_list
)) {
1292 /* start over from the beginning of the list */
1297 while (tmp
&& tmp
!= wwin
) {
1298 if (wWindowCanReceiveFocus(tmp
) && !WFLAGP(tmp
, skip_window_list
)) {
1309 doWindozeCycle(WWindow
*wwin
, XEvent
*event
, Bool next
)
1311 WScreen
*scr
= wScreenForRootWindow(event
->xkey
.root
);
1313 WWindow
*newFocused
;
1314 WWindow
*oldFocused
;
1316 XModifierKeymap
*keymap
;
1322 keymap
= XGetModifierMapping(dpy
);
1325 XGrabKeyboard(dpy
, scr
->root_win
, False
, GrabModeAsync
, GrabModeAsync
,
1329 newFocused
= nextToFocusAfter(wwin
);
1331 newFocused
= nextToFocusBefore(wwin
);
1334 scr
->flags
.doing_alt_tab
= 1;
1336 wWindowFocus(newFocused
, scr
->focused_window
);
1337 oldFocused
= newFocused
;
1339 OpenSwitchMenu(scr
, scr
->scr_width
/2, scr
->scr_height
/2, False
);
1344 WMMaskEvent(dpy
,KeyPressMask
|KeyReleaseMask
|ExposureMask
, &ev
);
1345 /* WMNextEvent(dpy, &ev);*/
1346 if (ev
.type
!= KeyRelease
&& ev
.type
!= KeyPress
) {
1351 /* ignore CapsLock */
1352 modifiers
= ev
.xkey
.state
& ValidModMask
;
1354 if (ev
.type
== KeyPress
1355 && wKeyBindings
[WKBD_FOCUSNEXT
].keycode
== ev
.xkey
.keycode
1356 && wKeyBindings
[WKBD_FOCUSNEXT
].modifier
== modifiers
) {
1358 UpdateSwitchMenu(scr
, newFocused
, ACTION_CHANGE_STATE
);
1359 newFocused
= nextToFocusAfter(newFocused
);
1360 wWindowFocus(newFocused
, oldFocused
);
1361 oldFocused
= newFocused
;
1362 UpdateSwitchMenu(scr
, newFocused
, ACTION_CHANGE_STATE
);
1364 } else if (ev
.type
== KeyPress
1365 && wKeyBindings
[WKBD_FOCUSPREV
].keycode
== ev
.xkey
.keycode
1366 && wKeyBindings
[WKBD_FOCUSPREV
].modifier
== modifiers
) {
1368 UpdateSwitchMenu(scr
, newFocused
, ACTION_CHANGE_STATE
);
1369 newFocused
= nextToFocusBefore(newFocused
);
1370 wWindowFocus(newFocused
, oldFocused
);
1371 oldFocused
= newFocused
;
1372 UpdateSwitchMenu(scr
, newFocused
, ACTION_CHANGE_STATE
);
1374 if (ev
.type
== KeyRelease
) {
1377 for (i
= 0; i
<= 8 * keymap
->max_keypermod
; i
++) {
1378 if (keymap
->modifiermap
[i
] == ev
.xkey
.keycode
&&
1379 wKeyBindings
[WKBD_FOCUSNEXT
].modifier
1380 & 1<<(i
/keymap
->max_keypermod
)) {
1390 XUngrabKeyboard(dpy
, CurrentTime
);
1391 wSetFocusTo(scr
, newFocused
);
1392 scr
->flags
.doing_alt_tab
= 0;
1393 OpenSwitchMenu(scr
, scr
->scr_width
/2, scr
->scr_height
/2, False
);
1397 #endif /* WEENDOZE_CYCLE */
1403 handleKeyPress(XEvent
*event
)
1405 WScreen
*scr
= wScreenForRootWindow(event
->xkey
.root
);
1406 WWindow
*wwin
= scr
->focused_window
;
1410 #ifdef KEEP_XKB_LOCK_STATUS
1411 XkbStateRec staterec
;
1412 #endif /*KEEP_XKB_LOCK_STATUS*/
1414 /* ignore CapsLock */
1415 modifiers
= event
->xkey
.state
& ValidModMask
;
1417 for (i
=0; i
<WKBD_LAST
; i
++) {
1418 if (wKeyBindings
[i
].keycode
==0)
1421 if (wKeyBindings
[i
].keycode
==event
->xkey
.keycode
1422 && (/*wKeyBindings[i].modifier==0
1423 ||*/ wKeyBindings
[i
].modifier
==modifiers
)) {
1436 if (!wRootMenuPerformShortcut(event
)) {
1438 static int dontLoop
= 0;
1440 if (dontLoop
> 10) {
1441 wwarning("problem with key event processing code");
1445 /* if the focused window is an internal window, try redispatching
1446 * the event to the managed window, as it can be a WINGs window */
1447 if (wwin
&& wwin
->flags
.internal_window
1448 && wwin
->client_leader
!=None
) {
1449 /* client_leader contains the WINGs toplevel */
1450 event
->xany
.window
= wwin
->client_leader
;
1451 WMHandleEvent(event
);
1458 #define ISMAPPED(w) ((w) && !(w)->flags.miniaturized && ((w)->flags.mapped || (w)->flags.shaded))
1459 #define ISFOCUSED(w) ((w) && (w)->flags.focused)
1464 OpenRootMenu(scr
, event
->xkey
.x_root
, event
->xkey
.y_root
, True
);
1466 case WKBD_WINDOWLIST
:
1467 OpenSwitchMenu(scr
, event
->xkey
.x_root
, event
->xkey
.y_root
, True
);
1470 case WKBD_WINDOWMENU
:
1471 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
))
1472 OpenWindowMenu(wwin
, wwin
->frame_x
,
1473 wwin
->frame_y
+wwin
->frame
->top_width
, True
);
1475 case WKBD_MINIATURIZE
:
1476 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)
1477 && !WFLAGP(wwin
, no_miniaturizable
)) {
1478 CloseWindowMenu(scr
);
1480 if (wwin
->protocols
.MINIATURIZE_WINDOW
)
1481 wClientSendProtocol(wwin
, _XA_GNUSTEP_WM_MINIATURIZE_WINDOW
,
1482 event
->xbutton
.time
);
1484 wIconifyWindow(wwin
);
1489 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1490 WApplication
*wapp
= wApplicationOf(wwin
->main_window
);
1491 CloseWindowMenu(scr
);
1493 if (wapp
&& !WFLAGP(wapp
->main_window_desc
, no_appicon
)) {
1494 wHideApplication(wapp
);
1499 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
) && !WFLAGP(wwin
, no_resizable
)) {
1500 CloseWindowMenu(scr
);
1502 if (wwin
->flags
.maximized
) {
1503 wUnmaximizeWindow(wwin
);
1505 wMaximizeWindow(wwin
, MAX_VERTICAL
|MAX_HORIZONTAL
);
1509 case WKBD_VMAXIMIZE
:
1510 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
) && !WFLAGP(wwin
, no_resizable
)) {
1511 CloseWindowMenu(scr
);
1513 if (wwin
->flags
.maximized
) {
1514 wUnmaximizeWindow(wwin
);
1516 wMaximizeWindow(wwin
, MAX_VERTICAL
);
1521 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1522 CloseWindowMenu(scr
);
1524 wRaiseFrame(wwin
->frame
->core
);
1528 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1529 CloseWindowMenu(scr
);
1531 wLowerFrame(wwin
->frame
->core
);
1534 case WKBD_RAISELOWER
:
1535 /* raise or lower the window under the pointer, not the
1538 wwin
= windowUnderPointer(scr
);
1540 wRaiseLowerFrame(wwin
->frame
->core
);
1543 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
) && !WFLAGP(wwin
, no_shadeable
)) {
1544 if (wwin
->flags
.shaded
)
1545 wUnshadeWindow(wwin
);
1550 case WKBD_MOVERESIZE
:
1551 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1552 CloseWindowMenu(scr
);
1554 wKeyboardMoveResizeWindow(wwin
);
1558 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
) && !WFLAGP(wwin
, no_closable
)) {
1559 CloseWindowMenu(scr
);
1560 if (wwin
->protocols
.DELETE_WINDOW
)
1561 wClientSendProtocol(wwin
, _XA_WM_DELETE_WINDOW
,
1566 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1567 wSelectWindow(wwin
, !wwin
->flags
.selected
);
1570 case WKBD_FOCUSNEXT
:
1571 #ifdef WEENDOZE_CYCLE
1572 if (wPreferences
.windoze_cycling
) {
1573 doWindozeCycle(wwin
, event
, True
);
1575 #endif /* WEENDOZE_CYCLE */
1577 wwin
= NextFocusWindow(scr
);
1579 wSetFocusTo(scr
, wwin
);
1580 if (wPreferences
.circ_raise
)
1581 wRaiseFrame(wwin
->frame
->core
);
1586 case WKBD_FOCUSPREV
:
1587 #ifdef WEENDOZE_CYCLE
1588 if (wPreferences
.windoze_cycling
) {
1589 doWindozeCycle(wwin
, event
, False
);
1591 #endif /* WEENDOZE_CYCLE */
1593 wwin
= PrevFocusWindow(scr
);
1595 wSetFocusTo(scr
, wwin
);
1596 if (wPreferences
.circ_raise
)
1597 wRaiseFrame(wwin
->frame
->core
);
1602 #if (defined(__STDC__) && !defined(UNIXCPP)) || defined(ANSICPP)
1603 #define GOTOWORKS(wk) case WKBD_WORKSPACE##wk:\
1604 i = (scr->current_workspace/10)*10 + wk - 1;\
1605 if (wPreferences.ws_advance || i<scr->workspace_count)\
1606 wWorkspaceChange(scr, i);\
1609 #define GOTOWORKS(wk) case WKBD_WORKSPACE/**/wk:\
1610 i = (scr->current_workspace/10)*10 + wk - 1;\
1611 if (wPreferences.ws_advance || i<scr->workspace_count)\
1612 wWorkspaceChange(scr, i);\
1626 case WKBD_NEXTWORKSPACE
:
1627 wWorkspaceRelativeChange(scr
, 1);
1629 case WKBD_PREVWORKSPACE
:
1630 wWorkspaceRelativeChange(scr
, -1);
1636 #ifdef EXTEND_WINDOWSHORTCUT
1644 if (scr
->shortcutWindow
[command
-WKBD_WINDOW1
]) {
1645 wMakeWindowVisible(scr
->shortcutWindow
[command
-WKBD_WINDOW1
]);
1646 } else if (wwin
&& ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1647 scr
->shortcutWindow
[command
-WKBD_WINDOW1
] = wwin
;
1648 wSelectWindow(wwin
, !wwin
->flags
.selected
);
1651 wSelectWindow(wwin
, !wwin
->flags
.selected
);
1655 case WKBD_NEXTWSLAYER
:
1656 case WKBD_PREVWSLAYER
:
1660 row
= scr
->current_workspace
/10;
1661 column
= scr
->current_workspace
%10;
1663 if (command
==WKBD_NEXTWSLAYER
) {
1664 if ((row
+1)*10 < scr
->workspace_count
)
1665 wWorkspaceChange(scr
, column
+(row
+1)*10);
1668 wWorkspaceChange(scr
, column
+(row
-1)*10);
1672 case WKBD_CLIPLOWER
:
1673 if (!wPreferences
.flags
.noclip
)
1674 wDockLower(scr
->workspaces
[scr
->current_workspace
]->clip
);
1676 case WKBD_CLIPRAISE
:
1677 if (!wPreferences
.flags
.noclip
)
1678 wDockRaise(scr
->workspaces
[scr
->current_workspace
]->clip
);
1680 case WKBD_CLIPRAISELOWER
:
1681 if (!wPreferences
.flags
.noclip
)
1682 wDockRaiseLower(scr
->workspaces
[scr
->current_workspace
]->clip
);
1684 #ifdef KEEP_XKB_LOCK_STATUS
1686 if(wPreferences
.modelock
){
1687 XkbGetState(dpy
,XkbUseCoreKbd
,&staterec
);
1689 XkbLockGroup(dpy
,XkbUseCoreKbd
,
1690 wwin
->languagemode
=staterec
.compat_state
&32?0:1);
1693 #endif /* KEEP_XKB_LOCK_STATUS */
1700 handleMotionNotify(XEvent
*event
)
1703 WScreen
*scr
= wScreenForRootWindow(event
->xmotion
.root
);
1705 if (wPreferences
.scrollable_menus
) {
1706 if (event
->xmotion
.x_root
<= 1 ||
1707 event
->xmotion
.x_root
>= (scr
->scr_width
- 2) ||
1708 event
->xmotion
.y_root
<= 1 ||
1709 event
->xmotion
.y_root
>= (scr
->scr_height
- 2)) {
1712 puts("pointer at screen edge");
1715 menu
= wMenuUnderPointer(scr
);
1717 wMenuScroll(menu
, event
);
1724 handleVisibilityNotify(XEvent
*event
)
1728 wwin
= wWindowFor(event
->xvisibility
.window
);
1731 wwin
->flags
.obscured
=
1732 (event
->xvisibility
.state
== VisibilityFullyObscured
);