1 /* event.c- event loop and handling
3 * WindowMaker 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>
38 #include "WindowMaker.h"
44 #include "application.h"
47 #include "workspace.h"
50 #include "properties.h"
54 /******** Global Variables **********/
55 extern XContext wWinContext
;
57 extern Cursor wCursor
[WCUR_LAST
];
59 extern WShortKey wKeyBindings
[WKBD_LAST
];
60 extern int wScreenCount
;
61 extern Time LastTimestamp
;
62 extern Time LastFocusChange
;
64 extern WPreferences wPreferences
;
66 #define MOD_MASK wPreferences.modifier_mask
68 extern Atom _XA_WM_CHANGE_STATE
;
69 extern Atom _XA_WM_DELETE_WINDOW
;
70 extern Atom _XA_WINDOWMAKER_WM_MINIATURIZE_WINDOW
;
71 extern Atom _XA_WINDOWMAKER_WM_FUNCTION
;
74 extern Atom _XA_DND_PROTOCOL
;
78 extern int ShapeEventBase
;
82 extern char WRestartASAP
;
83 extern char WExitASAP
;
84 extern char WDelayedActionSet
;
87 /************ Local stuff ***********/
90 static void saveTimestamp(XEvent
*event
);
91 static void handleColormapNotify();
92 static void handleMapNotify(), handleUnmapNotify();
93 static void handleButtonPress(), handleExpose();
94 static void handleDestroyNotify();
95 static void handleConfigureRequest();
96 static void handleMapRequest();
97 static void handlePropertyNotify();
98 static void handleEnterNotify();
99 static void handleLeaveNotify();
100 static void handleExtensions();
101 static void handleClientMessage();
102 static void handleKeyPress();
103 static void handleFocusIn();
104 static void handleMotionNotify();
106 static void handleShapeNotify();
109 /* called from the signal handler */
110 void NotifyDeadProcess(pid_t pid
, unsigned char status
);
112 /* real dead process handler */
113 static void handleDeadProcess(void *foo
);
116 typedef struct DeadProcesses
{
118 unsigned char exit_status
;
121 /* stack of dead processes */
122 static DeadProcesses deadProcesses
[MAX_DEAD_PROCESSES
];
123 static int deadProcessPtr
=0;
126 typedef struct DeathHandler
{
127 WDeathHandler
*callback
;
129 struct DeathHandler
*next
;
133 static DeathHandler
*deathHandler
=NULL
;
135 static WWindowState
*windowState
=NULL
;
141 wAddWindowSavedState(char *instance
, char *class, char *command
,
142 pid_t pid
, WSavedState
*state
)
144 WWindowState
*wstate
;
146 wstate
= malloc(sizeof(WWindowState
));
150 memset(wstate
, 0, sizeof(WWindowState
));
153 wstate
->instance
= wstrdup(instance
);
155 wstate
->class = wstrdup(class);
157 wstate
->command
= wstrdup(command
);
158 wstate
->state
= state
;
160 wstate
->next
= windowState
;
161 windowState
= wstate
;
164 printf("Added WindowState with ID %p, for %s.%s : \"%s\"\n", wstate
, instance
,
172 #define SAME(x, y) (((x) && (y) && !strcmp((x), (y))) || (!(x) && !(y)))
176 wGetWindowSavedState(Window win
)
178 char *instance
, *class, *command
=NULL
;
179 WWindowState
*wstate
= windowState
;
186 if (XGetCommand(dpy
, win
, &argv
, &argc
) && argc
>0) {
187 command
= FlattenStringList(argv
, argc
);
188 XFreeStringList(argv
);
193 if (PropGetWMClass(win
, &class, &instance
)) {
195 if (SAME(instance
, wstate
->instance
) &&
196 SAME(class, wstate
->class) &&
197 SAME(command
, wstate
->command
)) {
200 wstate
= wstate
->next
;
207 printf("Read WindowState with ID %p, for %s.%s : \"%s\"\n", wstate
, instance
,
211 if (command
) free(command
);
212 if (instance
) XFree(instance
);
213 if (class) XFree(class);
220 wDeleteWindowSavedState(WMagicNumber id
)
222 WWindowState
*tmp
, *wstate
=(WWindowState
*)id
;
224 if (!wstate
|| !windowState
)
229 windowState
= wstate
->next
;
231 printf("Deleted WindowState with ID %p, for %s.%s : \"%s\"\n",
232 wstate
, wstate
->instance
, wstate
->class, wstate
->command
);
234 if (wstate
->instance
) free(wstate
->instance
);
235 if (wstate
->class) free(wstate
->class);
236 if (wstate
->command
) free(wstate
->command
);
241 if (tmp
->next
==wstate
) {
242 tmp
->next
=wstate
->next
;
244 printf("Deleted WindowState with ID %p, for %s.%s : \"%s\"\n",
245 wstate
, wstate
->instance
, wstate
->class, wstate
->command
);
247 if (wstate
->instance
) free(wstate
->instance
);
248 if (wstate
->class) free(wstate
->class);
249 if (wstate
->command
) free(wstate
->command
);
261 wAddDeathHandler(pid_t pid
, WDeathHandler
*callback
, void *cdata
)
263 DeathHandler
*handler
;
265 handler
= malloc(sizeof(DeathHandler
));
270 handler
->callback
= callback
;
271 handler
->client_data
= cdata
;
273 handler
->next
= deathHandler
;
275 deathHandler
= handler
;
283 wDeleteDeathHandler(WMagicNumber id
)
285 DeathHandler
*tmp
, *handler
=(DeathHandler
*)id
;
287 if (!handler
|| !deathHandler
)
292 deathHandler
= handler
->next
;
296 if (tmp
->next
==handler
) {
297 tmp
->next
=handler
->next
;
308 DispatchEvent(XEvent
*event
)
313 handleDeadProcess(NULL
);
319 * WMHandleEvent() can't be called from anything
320 * executed inside here, or we can get in a infinite
323 for (i
=0; i
<wScreenCount
; i
++) {
325 scr
= wScreenWithNumber(i
);
327 wScreenSaveState(scr
);
332 /* received SIGTERM */
334 } else if (WRestartASAP
) {
337 for (i
=0; i
<wScreenCount
; i
++) {
339 scr
= wScreenWithNumber(i
);
341 wScreenSaveState(scr
);
345 /* received SIGHUP */
349 /* for the case that all that is wanted to be dispatched is
354 saveTimestamp(event
);
355 switch (event
->type
) {
357 handleMapRequest(event
);
361 handleKeyPress(event
);
365 handleMotionNotify(event
);
368 case ConfigureRequest
:
369 handleConfigureRequest(event
);
373 handleDestroyNotify(event
->xdestroywindow
.window
);
377 handleMapNotify(event
->xmap
.window
);
381 handleUnmapNotify(event
);
385 handleButtonPress(event
);
393 handlePropertyNotify(event
);
397 handleEnterNotify(event
);
401 handleLeaveNotify(event
);
405 handleClientMessage(event
);
409 handleColormapNotify(event
);
413 if (event
->xmapping
.request
== MappingKeyboard
414 || event
->xmapping
.request
== MappingModifier
)
415 XRefreshKeyboardMapping(&event
->xmapping
);
419 handleFocusIn(event
);
423 handleExtensions(event
);
429 *----------------------------------------------------------------------
431 * Processes X and internal events indefinitely.
437 * The LastTimestamp global variable is updated.
438 *----------------------------------------------------------------------
446 WMNextEvent(dpy
, &event
);
447 WMHandleEvent(&event
);
454 IsDoubleClick(WScreen
*scr
, XEvent
*event
)
456 if ((scr
->last_click_time
>0) &&
457 (event
->xbutton
.time
-scr
->last_click_time
<=wPreferences
.dblclick_time
)
458 && (event
->xbutton
.button
== scr
->last_click_button
)
459 && (event
->xbutton
.window
== scr
->last_click_window
)) {
461 scr
->flags
.next_click_is_not_double
= 1;
462 scr
->last_click_time
= 0;
463 scr
->last_click_window
= None
;
472 NotifyDeadProcess(pid_t pid
, unsigned char status
)
474 if (deadProcessPtr
>=MAX_DEAD_PROCESSES
-1) {
475 wwarning(_("stack overflow: too many dead processes"));
478 /* stack the process to be handled later,
479 * as this is called from the signal handler */
480 deadProcesses
[deadProcessPtr
].pid
= pid
;
481 deadProcesses
[deadProcessPtr
].exit_status
= status
;
487 handleDeadProcess(void *foo
)
492 int tmpPtr
= deadProcessPtr
;
504 if (wins
->pid
== deadProcesses
[tmpPtr
].pid
) {
505 wDeleteWindowSavedState(wins
);
517 /* get the pids on the queue and call handlers */
518 while (deadProcessPtr
>0) {
527 if (tmp
->pid
== deadProcesses
[deadProcessPtr
].pid
) {
528 (*tmp
->callback
)(tmp
->pid
,
529 deadProcesses
[deadProcessPtr
].exit_status
,
531 wDeleteDeathHandler(tmp
);
540 saveTimestamp(XEvent
*event
)
542 LastTimestamp
= CurrentTime
;
544 switch (event
->type
) {
547 LastTimestamp
= event
->xbutton
.time
;
551 LastTimestamp
= event
->xkey
.time
;
554 LastTimestamp
= event
->xmotion
.time
;
557 LastTimestamp
= event
->xproperty
.time
;
561 LastTimestamp
= event
->xcrossing
.time
;
564 LastTimestamp
= event
->xselectionclear
.time
;
566 case SelectionRequest
:
567 LastTimestamp
= event
->xselectionrequest
.time
;
569 case SelectionNotify
:
570 LastTimestamp
= event
->xselection
.time
;
577 handleExtensions(XEvent
*event
)
580 if (event
->type
== (ShapeEventBase
+ShapeNotify
)) {
581 handleShapeNotify(event
);
587 handleMapRequest(XEvent
*ev
)
591 Window window
= ev
->xmaprequest
.window
;
594 printf("got map request for %x\n", (unsigned)window
);
597 if ((wwin
=wWindowFor(window
))) {
598 /* deiconify window */
599 if (wwin
->flags
.shaded
)
600 wUnshadeWindow(wwin
);
601 if (wwin
->flags
.miniaturized
) {
602 wDeiconifyWindow(wwin
);
603 } else if (wwin
->flags
.hidden
) {
604 WApplication
*wapp
= wApplicationOf(wwin
->main_window
);
605 /* go to the last workspace that the user worked on the app */
606 #ifndef REDUCE_APPICONS
607 /* This severely breaks REDUCE_APPICONS. last_workspace is a neat
608 * concept but it needs to be reworked to handle REDUCE_APPICONS -cls
611 wWorkspaceChange(wwin
->screen_ptr
, wapp
->last_workspace
);
614 wUnhideApplication(wapp
, False
, False
);
619 scr
= wScreenForRootWindow(ev
->xmaprequest
.parent
);
621 wwin
= wManageWindow(scr
, window
);
624 * This is to let the Dock know that the application it launched
625 * has already been mapped (eg: it has finished launching).
626 * It is not necessary for normally docked apps, but is needed for
627 * apps that were forcedly docked (like with dockit).
629 if (scr
->last_dock
) {
630 if (wwin
&& wwin
->main_window
!=None
&& wwin
->main_window
!=window
)
631 wDockTrackWindowLaunch(scr
->last_dock
, wwin
->main_window
);
633 wDockTrackWindowLaunch(scr
->last_dock
, window
);
639 if (wwin
->wm_hints
&& (wwin
->wm_hints
->flags
& StateHint
))
640 state
= wwin
->wm_hints
->initial_state
;
644 if (state
==IconicState
)
645 wwin
->flags
.miniaturized
= 1;
647 if (state
==WithdrawnState
) {
648 wwin
->flags
.mapped
= 0;
649 wClientSetState(wwin
, WithdrawnState
, None
);
650 XSelectInput(dpy
, wwin
->client_win
, NoEventMask
);
651 XRemoveFromSaveSet(dpy
, wwin
->client_win
);
652 wUnmanageWindow(wwin
, True
);
654 wClientSetState(wwin
, NormalState
, None
);
655 if (wwin
->flags
.shaded
) {
656 wwin
->flags
.shaded
= 0;
657 wwin
->flags
.skip_next_animation
= 1;
658 wwin
->flags
.ignore_next_unmap
= 1; /* ??? */
661 if (wwin
->flags
.miniaturized
) {
662 wwin
->flags
.miniaturized
= 0;
663 wwin
->flags
.hidden
= 0;
664 wwin
->flags
.skip_next_animation
= 1;
665 wwin
->flags
.ignore_next_unmap
= 1;
666 wIconifyWindow(wwin
);
667 } else if (wwin
->flags
.hidden
) {
668 WApplication
*wapp
= wApplicationOf(wwin
->main_window
);
669 wwin
->flags
.hidden
= 0;
670 wwin
->flags
.skip_next_animation
= 1;
672 wHideApplication(wapp
);
674 wwin
->flags
.ignore_next_unmap
= 1;
680 wwin
->flags
.mapped
= 0;
681 wClientSetState(wwin
, WithdrawnState
, None
);
682 XSelectInput(dpy
, wwin
->client_win
, NoEventMask
);
683 XRemoveFromSaveSet(dpy
, wwin
->client_win
);
684 wUnmanageWindow(wwin
, True
);
688 if (!wwin
->flags
.miniaturized
) {
689 wwin
->flags
.ignore_next_unmap
=1;
690 wwin
->flags
.skip_next_animation
=1;
691 wIconifyWindow(wwin
);
699 wClientSetState(wwin
, NormalState
, None
);
708 handleDestroyNotify(Window window
)
713 puts("got destroy notify");
716 wwin
= wWindowFor(window
);
718 wUnmanageWindow(wwin
, False
);
721 app
= wApplicationOf(window
);
723 if (window
== app
->main_window
) {
725 wwin
= app
->main_window_desc
->screen_ptr
->focused_window
;
727 if (wwin
->main_window
== window
) {
728 wwin
->main_window
= None
;
733 wApplicationDestroy(app
);
740 handleExpose(XEvent
*event
)
742 WObjDescriptor
*desc
;
747 if (event
->xexpose
.count
!=0) {
751 if (XFindContext(dpy
, event
->xexpose
.window
, wWinContext
,
752 (XPointer
*)&desc
)==XCNOENT
) {
756 if (desc
->handle_expose
) {
757 (*desc
->handle_expose
)(desc
, event
);
764 handleButtonPress(XEvent
*event
)
766 WObjDescriptor
*desc
;
770 puts("got button press");
773 scr
= wScreenForRootWindow(event
->xbutton
.root
);
779 if (event
->xbutton
.window
==scr
->root_win
) {
780 if (event
->xbutton
.button
==wPreferences
.menu_button
) {
781 OpenRootMenu(scr
, event
->xbutton
.x_root
,
782 event
->xbutton
.y_root
, False
);
784 if (scr
->root_menu
) {
785 if (scr
->root_menu
->brother
->flags
.mapped
)
786 event
->xbutton
.window
= scr
->root_menu
->brother
->frame
->core
->window
;
788 event
->xbutton
.window
= scr
->root_menu
->frame
->core
->window
;
790 } else if (event
->xbutton
.button
==wPreferences
.windowl_button
) {
792 OpenSwitchMenu(scr
, event
->xbutton
.x_root
,
793 event
->xbutton
.y_root
, False
);
794 if (scr
->switch_menu
) {
795 if (scr
->switch_menu
->brother
->flags
.mapped
)
796 event
->xbutton
.window
= scr
->switch_menu
->brother
->frame
->core
->window
;
798 event
->xbutton
.window
= scr
->switch_menu
->frame
->core
->window
;
800 } else if (event
->xbutton
.button
==wPreferences
.select_button
) {
803 wSelectWindows(scr
, event
);
808 if (XFindContext(dpy
, event
->xbutton
.window
, wWinContext
,
809 (XPointer
*)&desc
)==XCNOENT
) {
813 if (desc
->parent_type
== WCLASS_WINDOW
) {
816 if (event
->xbutton
.state
& MOD_MASK
) {
817 XAllowEvents(dpy
, AsyncPointer
, CurrentTime
);
820 if (wPreferences
.focus_mode
== WKF_CLICK
) {
821 if (wPreferences
.ignore_focus_click
) {
822 XAllowEvents(dpy
, AsyncPointer
, CurrentTime
);
824 XAllowEvents(dpy
, ReplayPointer
, CurrentTime
);
827 } else if (desc
->parent_type
== WCLASS_APPICON
828 || desc
->parent_type
== WCLASS_MINIWINDOW
829 || desc
->parent_type
== WCLASS_DOCK_ICON
) {
830 if (event
->xbutton
.state
& MOD_MASK
) {
832 XAllowEvents(dpy
, AsyncPointer
, CurrentTime
);
837 if (desc
->handle_mousedown
!=NULL
) {
838 (*desc
->handle_mousedown
)(desc
, event
);
841 /* save double-click information */
842 if (scr
->flags
.next_click_is_not_double
) {
843 scr
->flags
.next_click_is_not_double
= 0;
845 scr
->last_click_time
= event
->xbutton
.time
;
846 scr
->last_click_button
= event
->xbutton
.button
;
847 scr
->last_click_window
= event
->xbutton
.window
;
853 handleMapNotify(Window window
)
860 wwin
= wWindowFor(window
);
861 if (wwin
&& wwin
->client_win
==window
) {
862 if (wwin
->flags
.ignore_next_unmap
) {
863 wwin
->flags
.ignore_next_unmap
=0;
866 if (wwin
->flags
.miniaturized
) {
867 wDeiconifyWindow(wwin
);
871 XMapWindow(dpy
, wwin
->client_win
);
872 XMapWindow(dpy
, wwin
->frame
->core
->window
);
873 wwin
->flags
.mapped
=1;
874 wClientSetState(wwin
, NormalState
, None
);
882 handleUnmapNotify(XEvent
*event
)
890 wwin
= wWindowFor(event
->xunmap
.window
);
891 if (!wwin
|| wwin
->client_win
!=event
->xunmap
.window
)
894 if (!wwin
->flags
.mapped
895 && wwin
->frame
->workspace
==wwin
->screen_ptr
->current_workspace
896 && !wwin
->flags
.miniaturized
&& !wwin
->flags
.hidden
)
899 if (wwin
->flags
.ignore_next_unmap
) {
903 XUnmapWindow(dpy
, wwin
->frame
->core
->window
);
904 wwin
->flags
.mapped
= 0;
906 /* check if the window was destroyed */
907 if (XCheckTypedWindowEvent(dpy
, wwin
->client_win
, DestroyNotify
,&ev
)) {
910 /* withdraw window */
911 wwin
->flags
.mapped
= 0;
912 XSelectInput(dpy
, wwin
->client_win
, NoEventMask
);
913 XRemoveFromSaveSet(dpy
, wwin
->client_win
);
914 wClientSetState(wwin
, WithdrawnState
, None
);
915 wUnmanageWindow(wwin
, True
);
922 handleConfigureRequest(XEvent
*event
)
927 puts("got configure request");
929 if (!(wwin
=wWindowFor(event
->xconfigurerequest
.window
))) {
931 * Configure request for unmapped window
933 wClientConfigure(NULL
, &(event
->xconfigurerequest
));
935 wClientConfigure(wwin
, &(event
->xconfigurerequest
));
941 handlePropertyNotify(XEvent
*event
)
950 puts("got property notify");
952 if ((wwin
=wWindowFor(event
->xproperty
.window
))) {
953 if (!XGetGeometry(dpy
, wwin
->client_win
, &jr
, &ji
, &ji
,
954 &ju
, &ju
, &ju
, &ju
)) {
957 wClientCheckProperty(wwin
, &event
->xproperty
);
959 wapp
= wApplicationOf(event
->xproperty
.window
);
961 wClientCheckProperty(wapp
->main_window_desc
, &event
->xproperty
);
967 handleClientMessage(XEvent
*event
)
970 WObjDescriptor
*desc
;
973 puts("got client message");
975 /* handle transition from Normal to Iconic state */
976 if (event
->xclient
.message_type
== _XA_WM_CHANGE_STATE
977 && event
->xclient
.format
== 32
978 && event
->xclient
.data
.l
[0] == IconicState
) {
980 wwin
= wWindowFor(event
->xclient
.window
);
982 if (!wwin
->flags
.miniaturized
)
983 wIconifyWindow(wwin
);
984 } else if (event
->xclient
.message_type
== _XA_WINDOWMAKER_WM_FUNCTION
) {
987 wapp
= wApplicationOf(event
->xclient
.window
);
989 switch (event
->xclient
.data
.l
[0]) {
990 case WMFHideOtherApplications
:
991 wHideOtherApplications(wapp
->main_window_desc
);
995 case WMFHideApplication
:
996 wHideApplication(wapp
);
1002 wwin
= wWindowFor(event
->xclient
.window
);
1004 switch (event
->xclient
.data
.l
[0]) {
1005 case WMFHideOtherApplications
:
1006 wHideOtherApplications(wwin
);
1009 case WMFHideApplication
:
1010 wHideApplication(wApplicationOf(wwin
->main_window
));
1016 } else if (event
->xclient
.message_type
==_XA_DND_PROTOCOL
) {
1017 if (wDockReceiveDNDDrop(wScreenForWindow(event
->xclient
.window
),event
))
1018 goto redirect_message
;
1019 #endif /* OFFIX_DND */
1025 * Non-standard thing, but needed by OffiX DND.
1026 * For when the icon frame gets a ClientMessage
1027 * that should have gone to the icon_window.
1029 if (XFindContext(dpy
, event
->xbutton
.window
, wWinContext
,
1030 (XPointer
*)&desc
)!=XCNOENT
) {
1031 struct WIcon
*icon
=NULL
;
1033 if (desc
->parent_type
== WCLASS_MINIWINDOW
) {
1034 icon
= (WIcon
*)desc
->parent
;
1035 } else if (desc
->parent_type
== WCLASS_DOCK_ICON
1036 || desc
->parent_type
== WCLASS_APPICON
) {
1037 icon
= ((WAppIcon
*)desc
->parent
)->icon
;
1039 if (icon
&& (wwin
=icon
->owner
)) {
1040 if (wwin
->client_win
!=event
->xclient
.window
) {
1041 event
->xclient
.window
= wwin
->client_win
;
1042 XSendEvent(dpy
, wwin
->client_win
, False
, NoEventMask
,
1052 raiseWindow(WScreen
*scr
)
1056 scr
->autoRaiseTimer
= NULL
;
1058 wwin
= wWindowFor(scr
->autoRaiseWindow
);
1062 if (!wwin
->flags
.destroyed
) {
1063 wRaiseFrame(wwin
->frame
->core
);
1064 /* this is needed or a race condition will occur */
1071 handleEnterNotify(XEvent
*event
)
1074 WObjDescriptor
*desc
= NULL
;
1076 WScreen
*scr
= wScreenForRootWindow(event
->xcrossing
.root
);
1080 puts("got enter notify");
1083 if (XCheckTypedWindowEvent(dpy
, event
->xcrossing
.window
, LeaveNotify
,
1085 /* already left the window... */
1087 if (ev
.xcrossing
.mode
==event
->xcrossing
.mode
1088 && ev
.xcrossing
.detail
==event
->xcrossing
.detail
) {
1093 if (XFindContext(dpy
, event
->xcrossing
.window
, wWinContext
,
1094 (XPointer
*)&desc
)!=XCNOENT
) {
1095 if(desc
->handle_enternotify
)
1096 (*desc
->handle_enternotify
)(desc
, event
);
1099 /* enter to window */
1100 wwin
= wWindowFor(event
->xcrossing
.window
);
1102 if (wPreferences
.focus_mode
==WKF_POINTER
1103 && event
->xcrossing
.window
==event
->xcrossing
.root
) {
1104 wSetFocusTo(scr
, NULL
);
1106 if (wPreferences
.colormap_mode
==WKF_POINTER
) {
1107 wColormapInstallForWindow(scr
, NULL
);
1109 if (scr
->autoRaiseTimer
1110 && event
->xcrossing
.root
==event
->xcrossing
.window
) {
1111 WMDeleteTimerHandler(scr
->autoRaiseTimer
);
1112 scr
->autoRaiseTimer
= NULL
;
1115 /* set focus if in focus-follows-mouse mode and the event
1116 * is for the frame window and window doesn't have focus yet */
1117 if ((wPreferences
.focus_mode
==WKF_POINTER
1118 || wPreferences
.focus_mode
==WKF_SLOPPY
)
1119 && wwin
->frame
->core
->window
==event
->xcrossing
.window
1120 && !wwin
->flags
.focused
) {
1121 wSetFocusTo(scr
, wwin
);
1123 if (scr
->autoRaiseTimer
)
1124 WMDeleteTimerHandler(scr
->autoRaiseTimer
);
1125 scr
->autoRaiseTimer
= NULL
;
1127 if (wPreferences
.raise_delay
&& !wwin
->window_flags
.no_focusable
) {
1128 scr
->autoRaiseWindow
= wwin
->frame
->core
->window
;
1130 = WMAddTimerHandler(wPreferences
.raise_delay
,
1131 (WMCallback
*)raiseWindow
, scr
);
1134 /* Install colormap for window, if the colormap installation mode
1135 * is colormap_follows_mouse */
1136 if (wPreferences
.colormap_mode
==WKF_POINTER
) {
1137 if (wwin
->client_win
==event
->xcrossing
.window
)
1138 wColormapInstallForWindow(scr
, wwin
);
1140 wColormapInstallForWindow(scr
, NULL
);
1144 /* a little kluge to hide the clip balloon */
1145 if (!wPreferences
.flags
.noclip
&& scr
->flags
.clip_balloon_mapped
) {
1147 XUnmapWindow(dpy
, scr
->clip_balloon
);
1148 scr
->flags
.clip_balloon_mapped
= 0;
1150 if (desc
->parent_type
!=WCLASS_DOCK_ICON
1151 || scr
->clip_icon
!= desc
->parent
) {
1152 XUnmapWindow(dpy
, scr
->clip_balloon
);
1153 scr
->flags
.clip_balloon_mapped
= 0;
1158 if (event
->xcrossing
.window
== event
->xcrossing
.root
1159 && event
->xcrossing
.detail
== NotifyNormal
1160 && event
->xcrossing
.detail
!= NotifyInferior
1161 && wPreferences
.focus_mode
!= WKF_CLICK
) {
1163 wSetFocusTo(scr
, scr
->focused_window
);
1167 wBalloonEnteredObject(scr
, desc
);
1173 handleLeaveNotify(XEvent
*event
)
1175 WObjDescriptor
*desc
= NULL
;
1177 if (XFindContext(dpy
, event
->xcrossing
.window
, wWinContext
,
1178 (XPointer
*)&desc
)!=XCNOENT
) {
1179 if(desc
->handle_leavenotify
)
1180 (*desc
->handle_leavenotify
)(desc
, event
);
1182 if (event
->xcrossing
.window
== event
->xcrossing
.root
1183 && event
->xcrossing
.mode
== NotifyNormal
1184 && event
->xcrossing
.detail
!= NotifyInferior
1185 && wPreferences
.focus_mode
!= WKF_CLICK
) {
1187 WScreen
*scr
= wScreenForRootWindow(event
->xcrossing
.root
);
1189 wSetFocusTo(scr
, NULL
);
1196 handleShapeNotify(XEvent
*event
)
1198 XShapeEvent
*shev
= (XShapeEvent
*)event
;
1200 puts("got shape notify");
1202 puts("got shape notify");
1204 wwin
= wWindowFor(event
->xany
.window
);
1205 if (!wwin
|| shev
->kind
!= ShapeBounding
)
1208 wwin
->flags
.shaped
= shev
->shaped
;
1209 wWindowSetShape(wwin
);
1215 handleColormapNotify(XEvent
*event
)
1219 Bool reinstall
= False
;
1221 wwin
= wWindowFor(event
->xcolormap
.window
);
1225 scr
= wwin
->screen_ptr
;
1229 if (event
->xcolormap
.new) {
1230 XWindowAttributes attr
;
1232 XGetWindowAttributes(dpy
, wwin
->client_win
, &attr
);
1234 if (wwin
== scr
->cmap_window
&& wwin
->cmap_window_no
== 0)
1235 scr
->current_colormap
= attr
.colormap
;
1238 } else if (event
->xcolormap
.state
== ColormapUninstalled
&&
1239 scr
->current_colormap
== event
->xcolormap
.colormap
) {
1241 /* some bastard app (like XV) removed our colormap */
1243 } else if (event
->xcolormap
.state
== ColormapInstalled
&&
1244 scr
->current_colormap
== event
->xcolormap
.colormap
) {
1246 /* someone has put our colormap back */
1250 } while (XCheckTypedEvent(dpy
, ColormapNotify
, event
)
1251 && ((wwin
= wWindowFor(event
->xcolormap
.window
)) || 1));
1253 if (reinstall
&& scr
->current_colormap
!=None
) {
1255 XInstallColormap(dpy
, scr
->current_colormap
);
1262 handleFocusIn(XEvent
*event
)
1266 if (event
->xfocus
.mode
== NotifyUngrab
) {
1270 * For applications that like stealing the focus.
1272 while (XCheckTypedEvent(dpy
, FocusIn
, event
));
1273 saveTimestamp(event
);
1274 if (event
->xfocus
.mode
== NotifyUngrab
) {
1278 wwin
= wWindowFor(event
->xfocus
.window
);
1279 if (wwin
&& !wwin
->flags
.focused
) {
1280 if (wwin
->flags
.mapped
)
1281 wSetFocusTo(wwin
->screen_ptr
, wwin
);
1283 wSetFocusTo(wwin
->screen_ptr
, NULL
);
1285 wSetFocusTo(wScreenForWindow(event
->xfocus
.window
), NULL
);
1291 windowUnderPointer(WScreen
*scr
)
1297 if (XQueryPointer(dpy
, scr
->root_win
, &bar
, &win
, &foo
, &foo
, &foo
, &foo
,
1299 return wWindowFor(win
);
1304 handleKeyPress(XEvent
*event
)
1306 WScreen
*scr
= wScreenForRootWindow(event
->xkey
.root
);
1307 WWindow
*wwin
= scr
->focused_window
;
1312 /* ignore CapsLock */
1313 modifiers
= event
->xkey
.state
& ValidModMask
;
1315 for (i
=0; i
<WKBD_LAST
; i
++) {
1316 if (wKeyBindings
[i
].keycode
==0)
1319 if (wKeyBindings
[i
].keycode
==event
->xkey
.keycode
1320 && (/*wKeyBindings[i].modifier==0
1321 ||*/ wKeyBindings
[i
].modifier
==modifiers
)) {
1328 if (!wRootMenuPerformShortcut(event
)) {
1329 static int dontLoop
= 0;
1331 if (dontLoop
> 10) {
1332 wwarning("problem with key event processing code");
1336 /* if the focused window is an internal window, try redispatching
1337 * the event to the managed window, as it can be a WINGs window */
1338 if (wwin
&& wwin
->flags
.internal_window
1339 && wwin
->client_leader
!=None
) {
1340 /* client_leader contains the WINGs toplevel */
1341 event
->xany
.window
= wwin
->client_leader
;
1342 WMHandleEvent(event
);
1349 #define ISMAPPED(w) ((w) && !(w)->flags.miniaturized && ((w)->flags.mapped || (w)->flags.shaded))
1350 #define ISFOCUSED(w) ((w) && (w)->flags.focused)
1354 OpenRootMenu(scr
, event
->xkey
.x_root
, event
->xkey
.y_root
, True
);
1356 case WKBD_WINDOWMENU
:
1357 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
))
1358 OpenWindowMenu(wwin
, wwin
->frame_x
,
1359 wwin
->frame_y
+wwin
->frame
->top_width
, True
);
1361 case WKBD_WINDOWLIST
:
1362 OpenSwitchMenu(scr
, event
->xkey
.x_root
, event
->xkey
.y_root
, True
);
1364 case WKBD_MINIATURIZE
:
1365 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1366 CloseWindowMenu(scr
);
1368 if (wwin
->protocols
.MINIATURIZE_WINDOW
)
1369 wClientSendProtocol(wwin
, _XA_WINDOWMAKER_WM_MINIATURIZE_WINDOW
,
1370 event
->xbutton
.time
);
1372 if (!wwin
->window_flags
.no_miniaturizable
)
1373 wIconifyWindow(wwin
);
1378 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1379 WApplication
*wapp
= wApplicationOf(wwin
->main_window
);
1380 CloseWindowMenu(scr
);
1382 if (wapp
&& !wapp
->main_window_desc
->window_flags
.no_appicon
) {
1383 wHideApplication(wapp
);
1388 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)
1389 && !wwin
->window_flags
.no_resizable
) {
1390 CloseWindowMenu(scr
);
1392 if (wwin
->flags
.maximized
) {
1393 wUnmaximizeWindow(wwin
);
1395 wMaximizeWindow(wwin
, MAX_VERTICAL
|MAX_HORIZONTAL
);
1399 case WKBD_VMAXIMIZE
:
1400 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)
1401 && !wwin
->window_flags
.no_resizable
) {
1402 CloseWindowMenu(scr
);
1404 if (wwin
->flags
.maximized
) {
1405 wUnmaximizeWindow(wwin
);
1407 wMaximizeWindow(wwin
, MAX_VERTICAL
);
1412 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1413 CloseWindowMenu(scr
);
1415 wRaiseFrame(wwin
->frame
->core
);
1419 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1420 CloseWindowMenu(scr
);
1422 wLowerFrame(wwin
->frame
->core
);
1425 case WKBD_RAISELOWER
:
1426 /* raise or lower the window under the pointer, not the
1429 wwin
= windowUnderPointer(scr
);
1431 wRaiseLowerFrame(wwin
->frame
->core
);
1434 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)
1435 && !wwin
->window_flags
.no_shadeable
) {
1436 if (wwin
->flags
.shaded
)
1437 wUnshadeWindow(wwin
);
1443 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)
1444 && !wwin
->window_flags
.no_closable
) {
1445 CloseWindowMenu(scr
);
1446 if (wwin
->protocols
.DELETE_WINDOW
)
1447 wClientSendProtocol(wwin
, _XA_WM_DELETE_WINDOW
,
1452 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1453 wSelectWindow(wwin
);
1456 case WKBD_FOCUSNEXT
:
1457 wwin
= NextFocusWindow(scr
);
1459 wSetFocusTo(scr
, wwin
);
1460 if (wPreferences
.circ_raise
)
1461 wRaiseFrame(wwin
->frame
->core
);
1464 case WKBD_FOCUSPREV
:
1465 wwin
= PrevFocusWindow(scr
);
1467 wSetFocusTo(scr
, wwin
);
1468 if (wPreferences
.circ_raise
)
1469 wRaiseFrame(wwin
->frame
->core
);
1472 case WKBD_WORKSPACE1
:
1473 wWorkspaceChange(scr
, 0);
1475 case WKBD_WORKSPACE2
:
1476 wWorkspaceChange(scr
, 1);
1478 case WKBD_WORKSPACE3
:
1479 wWorkspaceChange(scr
, 2);
1481 case WKBD_WORKSPACE4
:
1482 wWorkspaceChange(scr
, 3);
1484 case WKBD_WORKSPACE5
:
1485 wWorkspaceChange(scr
, 4);
1487 case WKBD_WORKSPACE6
:
1488 wWorkspaceChange(scr
, 5);
1490 case WKBD_WORKSPACE7
:
1491 wWorkspaceChange(scr
, 6);
1493 case WKBD_WORKSPACE8
:
1494 wWorkspaceChange(scr
, 7);
1496 case WKBD_WORKSPACE9
:
1497 wWorkspaceChange(scr
, 8);
1499 case WKBD_WORKSPACE10
:
1500 wWorkspaceChange(scr
, 9);
1502 case WKBD_NEXTWORKSPACE
:
1503 if (scr
->current_workspace
< scr
->workspace_count
-1)
1504 wWorkspaceChange(scr
, scr
->current_workspace
+1);
1505 else if (scr
->current_workspace
== scr
->workspace_count
-1) {
1506 if (wPreferences
.ws_advance
&&
1507 scr
->current_workspace
< MAX_WORKSPACES
-1)
1508 wWorkspaceChange(scr
, scr
->current_workspace
+1);
1509 else if (wPreferences
.ws_cycle
)
1510 wWorkspaceChange(scr
, 0);
1513 case WKBD_PREVWORKSPACE
:
1514 if (scr
->current_workspace
> 0)
1515 wWorkspaceChange(scr
, scr
->current_workspace
-1);
1516 else if (scr
->current_workspace
==0 && wPreferences
.ws_cycle
)
1517 wWorkspaceChange(scr
, scr
->workspace_count
-1);
1520 case WKBD_NEXTWSLAYER
:
1521 case WKBD_PREVWSLAYER
:
1525 row
= scr
->current_workspace
/10;
1526 column
= scr
->current_workspace
%10;
1528 if (command
==WKBD_NEXTWSLAYER
) {
1529 if ((row
+1)*10 < scr
->workspace_count
)
1530 wWorkspaceChange(scr
, column
+(row
+1)*10);
1533 wWorkspaceChange(scr
, column
+(row
-1)*10);
1537 case WKBD_CLIPLOWER
:
1538 if (!wPreferences
.flags
.noclip
)
1539 wDockLower(scr
->workspaces
[scr
->current_workspace
]->clip
);
1541 case WKBD_CLIPRAISE
:
1542 if (!wPreferences
.flags
.noclip
)
1543 wDockRaise(scr
->workspaces
[scr
->current_workspace
]->clip
);
1545 case WKBD_CLIPRAISELOWER
:
1546 if (!wPreferences
.flags
.noclip
)
1547 wDockRaiseLower(scr
->workspaces
[scr
->current_workspace
]->clip
);
1554 handleMotionNotify(XEvent
*event
)
1557 WScreen
*scr
= wScreenForRootWindow(event
->xmotion
.root
);
1559 if (wPreferences
.scrollable_menus
) {
1560 if (event
->xmotion
.x_root
<= 1 ||
1561 event
->xmotion
.x_root
>= (scr
->scr_width
- 2) ||
1562 event
->xmotion
.y_root
<= 1 ||
1563 event
->xmotion
.y_root
>= (scr
->scr_height
- 2)) {
1566 puts("pointer at screen edge");
1569 menu
= wMenuUnderPointer(scr
);
1571 wMenuScroll(menu
, event
);