1 /* event.c- event loop and handling
3 * Window Maker window manager
5 * Copyright (c) 1997-2003 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,
35 #include <X11/Xutil.h>
37 # include <X11/extensions/shape.h>
43 #ifdef KEEP_XKB_LOCK_STATUS
44 #include <X11/XKBlib.h>
45 #endif /* KEEP_XKB_LOCK_STATUS */
47 #include "WindowMaker.h"
53 #include "application.h"
56 #include "workspace.h"
59 #include "properties.h"
67 /******** Global Variables **********/
68 extern XContext wWinContext
;
69 extern XContext wVEdgeContext
;
71 extern Cursor wCursor
[WCUR_LAST
];
73 extern WShortKey wKeyBindings
[WKBD_LAST
];
74 extern int wScreenCount
;
75 extern Time LastTimestamp
;
76 extern Time LastFocusChange
;
78 extern WPreferences wPreferences
;
80 #define MOD_MASK wPreferences.modifier_mask
82 extern Atom _XA_WM_COLORMAP_NOTIFY
;
84 extern Atom _XA_WM_CHANGE_STATE
;
85 extern Atom _XA_WM_DELETE_WINDOW
;
86 extern Atom _XA_GNUSTEP_WM_ATTR
;
87 extern Atom _XA_GNUSTEP_WM_MINIATURIZE_WINDOW
;
88 extern Atom _XA_GNUSTEP_TITLEBAR_STATE
;
89 extern Atom _XA_WINDOWMAKER_WM_FUNCTION
;
90 extern Atom _XA_WINDOWMAKER_COMMAND
;
94 extern Bool wShapeSupported
;
95 extern int wShapeEventBase
;
98 #ifdef KEEP_XKB_LOCK_STATUS
99 extern int wXkbEventBase
;
103 extern char WDelayedActionSet
;
106 /************ Local stuff ***********/
109 static void saveTimestamp(XEvent
*event
);
110 static void handleColormapNotify();
111 static void handleMapNotify();
112 static void handleUnmapNotify();
113 static void handleButtonPress();
114 static void handleExpose();
115 static void handleDestroyNotify();
116 static void handleConfigureRequest();
117 static void handleMapRequest();
118 static void handlePropertyNotify();
119 static void handleEnterNotify();
120 static void handleLeaveNotify();
121 static void handleExtensions();
122 static void handleClientMessage();
123 static void handleKeyPress();
124 static void handleFocusIn();
125 static void handleMotionNotify();
126 static void handleVisibilityNotify();
130 static void handleShapeNotify();
133 /* called from the signal handler */
134 void NotifyDeadProcess(pid_t pid
, unsigned char status
);
136 /* real dead process handler */
137 static void handleDeadProcess(void *foo
);
140 typedef struct DeadProcesses
{
142 unsigned char exit_status
;
145 /* stack of dead processes */
146 static DeadProcesses deadProcesses
[MAX_DEAD_PROCESSES
];
147 static int deadProcessPtr
=0;
150 typedef struct DeathHandler
{
151 WDeathHandler
*callback
;
156 static WMArray
*deathHandlers
=NULL
;
161 wAddDeathHandler(pid_t pid
, WDeathHandler
*callback
, void *cdata
)
163 DeathHandler
*handler
;
165 handler
= malloc(sizeof(DeathHandler
));
170 handler
->callback
= callback
;
171 handler
->client_data
= cdata
;
174 deathHandlers
= WMCreateArrayWithDestructor(8, wfree
);
176 WMAddToArray(deathHandlers
, handler
);
184 wDeleteDeathHandler(WMagicNumber id
)
186 DeathHandler
*handler
=(DeathHandler
*)id
;
188 if (!handler
|| !deathHandlers
)
191 /* array destructor will call wfree(handler) */
192 WMRemoveFromArray(deathHandlers
, handler
);
197 DispatchEvent(XEvent
*event
)
200 handleDeadProcess(NULL
);
202 if (WCHECK_STATE(WSTATE_NEED_EXIT
)) {
203 WCHANGE_STATE(WSTATE_EXITING
);
204 /* received SIGTERM */
206 * WMHandleEvent() can't be called from anything
207 * executed inside here, or we can get in a infinite
210 Shutdown(WSExitMode
);
212 } else if (WCHECK_STATE(WSTATE_NEED_RESTART
)) {
213 WCHANGE_STATE(WSTATE_RESTARTING
);
215 Shutdown(WSRestartPreparationMode
);
216 /* received SIGHUP */
218 } else if (WCHECK_STATE(WSTATE_NEED_REREAD
)) {
219 WCHANGE_STATE(WSTATE_NORMAL
);
220 wDefaultsCheckDomains("bla");
223 /* for the case that all that is wanted to be dispatched is
228 saveTimestamp(event
);
229 switch (event
->type
) {
231 handleMapRequest(event
);
235 handleKeyPress(event
);
239 handleMotionNotify(event
);
242 case ConfigureRequest
:
243 handleConfigureRequest(event
);
247 handleDestroyNotify(event
);
251 handleMapNotify(event
);
255 handleUnmapNotify(event
);
259 handleButtonPress(event
);
267 handlePropertyNotify(event
);
271 handleEnterNotify(event
);
275 handleLeaveNotify(event
);
279 handleClientMessage(event
);
283 handleColormapNotify(event
);
287 if (event
->xmapping
.request
== MappingKeyboard
288 || event
->xmapping
.request
== MappingModifier
)
289 XRefreshKeyboardMapping(&event
->xmapping
);
293 handleFocusIn(event
);
296 case VisibilityNotify
:
297 handleVisibilityNotify(event
);
300 handleExtensions(event
);
307 *----------------------------------------------------------------------
309 * Processes X and internal events indefinitely.
315 * The LastTimestamp global variable is updated.
316 *----------------------------------------------------------------------
324 WMNextEvent(dpy
, &event
);
325 WMHandleEvent(&event
);
331 *----------------------------------------------------------------------
332 * ProcessPendingEvents --
333 * Processes the events that are currently pending (at the time
334 * this function is called) in the display's queue.
337 * After the pending events that were present at the function call
341 * Many -- whatever handling events may involve.
343 *----------------------------------------------------------------------
346 ProcessPendingEvents()
353 /* Take a snapshot of the event count in the queue */
354 count
= XPending(dpy
);
356 while (count
>0 && XPending(dpy
)) {
357 WMNextEvent(dpy
, &event
);
358 WMHandleEvent(&event
);
365 IsDoubleClick(WScreen
*scr
, XEvent
*event
)
367 if ((scr
->last_click_time
>0) &&
368 (event
->xbutton
.time
-scr
->last_click_time
<=wPreferences
.dblclick_time
)
369 && (event
->xbutton
.button
== scr
->last_click_button
)
370 && (event
->xbutton
.window
== scr
->last_click_window
)) {
372 scr
->flags
.next_click_is_not_double
= 1;
373 scr
->last_click_time
= 0;
374 scr
->last_click_window
= event
->xbutton
.window
;
383 NotifyDeadProcess(pid_t pid
, unsigned char status
)
385 if (deadProcessPtr
>=MAX_DEAD_PROCESSES
-1) {
386 wwarning("stack overflow: too many dead processes");
389 /* stack the process to be handled later,
390 * as this is called from the signal handler */
391 deadProcesses
[deadProcessPtr
].pid
= pid
;
392 deadProcesses
[deadProcessPtr
].exit_status
= status
;
398 handleDeadProcess(void *foo
)
403 for (i
=0; i
<deadProcessPtr
; i
++) {
404 wWindowDeleteSavedStatesForPID(deadProcesses
[i
].pid
);
407 if (!deathHandlers
) {
412 /* get the pids on the queue and call handlers */
413 while (deadProcessPtr
>0) {
416 for (i
= WMGetArrayItemCount(deathHandlers
)-1; i
>= 0; i
--) {
417 tmp
= WMGetFromArray(deathHandlers
, i
);
421 if (tmp
->pid
== deadProcesses
[deadProcessPtr
].pid
) {
422 (*tmp
->callback
)(tmp
->pid
,
423 deadProcesses
[deadProcessPtr
].exit_status
,
425 wDeleteDeathHandler(tmp
);
433 saveTimestamp(XEvent
*event
)
436 * Never save CurrentTime as LastTimestamp because CurrentTime
437 * it's not a real timestamp (it's the 0L constant)
440 switch (event
->type
) {
443 LastTimestamp
= event
->xbutton
.time
;
447 LastTimestamp
= event
->xkey
.time
;
450 LastTimestamp
= event
->xmotion
.time
;
453 LastTimestamp
= event
->xproperty
.time
;
457 LastTimestamp
= event
->xcrossing
.time
;
460 LastTimestamp
= event
->xselectionclear
.time
;
462 case SelectionRequest
:
463 LastTimestamp
= event
->xselectionrequest
.time
;
465 case SelectionNotify
:
466 LastTimestamp
= event
->xselection
.time
;
468 wXDNDProcessSelection(event
);
476 matchWindow(void *item
, void *cdata
)
478 return (((WFakeGroupLeader
*)item
)->origLeader
== (Window
)cdata
);
483 handleExtensions(XEvent
*event
)
485 #ifdef KEEP_XKB_LOCK_STATUS
487 xkbevent
= (XkbEvent
*)event
;
488 #endif /*KEEP_XKB_LOCK_STATUS*/
490 if (wShapeSupported
&& event
->type
== (wShapeEventBase
+ShapeNotify
)) {
491 handleShapeNotify(event
);
494 #ifdef KEEP_XKB_LOCK_STATUS
495 if (wPreferences
.modelock
&& (xkbevent
->type
== wXkbEventBase
)){
496 handleXkbIndicatorStateNotify(event
);
498 #endif /*KEEP_XKB_LOCK_STATUS*/
503 handleMapRequest(XEvent
*ev
)
507 Window window
= ev
->xmaprequest
.window
;
510 printf("got map request for %x\n", (unsigned)window
);
512 if ((wwin
= wWindowFor(window
))) {
513 if (wwin
->flags
.shaded
) {
514 wUnshadeWindow(wwin
);
516 /* deiconify window */
517 if (wwin
->flags
.miniaturized
) {
518 wDeiconifyWindow(wwin
);
519 } else if (wwin
->flags
.hidden
) {
520 WApplication
*wapp
= wApplicationOf(wwin
->main_window
);
521 /* go to the last workspace that the user worked on the app */
523 wWorkspaceChange(wwin
->screen_ptr
, wapp
->last_workspace
);
525 wUnhideApplication(wapp
, False
, False
);
530 scr
= wScreenForRootWindow(ev
->xmaprequest
.parent
);
532 wwin
= wManageWindow(scr
, window
);
535 * This is to let the Dock know that the application it launched
536 * has already been mapped (eg: it has finished launching).
537 * It is not necessary for normally docked apps, but is needed for
538 * apps that were forcedly docked (like with dockit).
540 if (scr
->last_dock
) {
541 if (wwin
&& wwin
->main_window
!=None
&& wwin
->main_window
!=window
)
542 wDockTrackWindowLaunch(scr
->last_dock
, wwin
->main_window
);
544 wDockTrackWindowLaunch(scr
->last_dock
, window
);
548 wClientSetState(wwin
, NormalState
, None
);
549 if (wwin
->flags
.maximized
) {
550 wMaximizeWindow(wwin
, wwin
->flags
.maximized
);
552 if (wwin
->flags
.shaded
) {
553 wwin
->flags
.shaded
= 0;
554 wwin
->flags
.skip_next_animation
= 1;
557 if (wwin
->flags
.miniaturized
) {
558 wwin
->flags
.miniaturized
= 0;
559 wwin
->flags
.skip_next_animation
= 1;
560 wIconifyWindow(wwin
);
562 if (wwin
->flags
.fullscreen
) {
563 wwin
->flags
.fullscreen
= 0;
564 wFullscreenWindow(wwin
);
566 if (wwin
->flags
.hidden
) {
567 WApplication
*wapp
= wApplicationOf(wwin
->main_window
);
569 wwin
->flags
.hidden
= 0;
570 wwin
->flags
.skip_next_animation
= 1;
572 wHideApplication(wapp
);
580 handleDestroyNotify(XEvent
*event
)
584 Window window
= event
->xdestroywindow
.window
;
585 WScreen
*scr
= wScreenForRootWindow(event
->xdestroywindow
.event
);
589 printf("got destroy notify\n");
591 wwin
= wWindowFor(window
);
593 wUnmanageWindow(wwin
, False
, True
);
597 while ((index
= WMFindInArray(scr
->fakeGroupLeaders
, matchWindow
,
598 (void*)window
)) != WANotFound
) {
599 WFakeGroupLeader
*fPtr
;
601 fPtr
= WMGetFromArray(scr
->fakeGroupLeaders
, index
);
602 if (fPtr
->retainCount
> 0) {
604 if (fPtr
->retainCount
==0 && fPtr
->leader
!=None
) {
605 XDestroyWindow(dpy
, fPtr
->leader
);
610 fPtr
->origLeader
= None
;
614 app
= wApplicationOf(window
);
616 if (window
== app
->main_window
) {
618 wwin
= app
->main_window_desc
->screen_ptr
->focused_window
;
620 if (wwin
->main_window
== window
) {
621 wwin
->main_window
= None
;
626 wApplicationDestroy(app
);
633 handleExpose(XEvent
*event
)
635 WObjDescriptor
*desc
;
639 printf("got expose\n");
641 while (XCheckTypedWindowEvent(dpy
, event
->xexpose
.window
, Expose
, &ev
));
643 if (XFindContext(dpy
, event
->xexpose
.window
, wWinContext
,
644 (XPointer
*)&desc
)==XCNOENT
) {
648 if (desc
->handle_expose
) {
649 (*desc
->handle_expose
)(desc
, event
);
654 executeButtonAction(WScreen
*scr
, XEvent
*event
, int action
)
657 case WA_SELECT_WINDOWS
:
658 wUnselectWindows(scr
);
659 wSelectWindows(scr
, event
);
661 case WA_OPEN_APPMENU
:
662 OpenRootMenu(scr
, event
->xbutton
.x_root
, event
->xbutton
.y_root
, False
);
664 if (scr
->root_menu
) {
665 if (scr
->root_menu
->brother
->flags
.mapped
)
666 event
->xbutton
.window
= scr
->root_menu
->brother
->frame
->core
->window
;
668 event
->xbutton
.window
= scr
->root_menu
->frame
->core
->window
;
671 case WA_OPEN_WINLISTMENU
:
672 OpenSwitchMenu(scr
, event
->xbutton
.x_root
, event
->xbutton
.y_root
, False
);
673 if (scr
->switch_menu
) {
674 if (scr
->switch_menu
->brother
->flags
.mapped
)
675 event
->xbutton
.window
= scr
->switch_menu
->brother
->frame
->core
->window
;
677 event
->xbutton
.window
= scr
->switch_menu
->frame
->core
->window
;
688 handleButtonPress(XEvent
*event
)
690 WObjDescriptor
*desc
;
694 printf("got button press\n");
696 scr
= wScreenForRootWindow(event
->xbutton
.root
);
704 if (event
->xbutton
.window
==scr
->root_win
) {
705 if (event
->xbutton
.button
==Button1
&&
706 wPreferences
.mouse_button1
!=WA_NONE
) {
707 executeButtonAction(scr
, event
, wPreferences
.mouse_button1
);
708 } else if (event
->xbutton
.button
==Button2
&&
709 wPreferences
.mouse_button2
!=WA_NONE
) {
710 executeButtonAction(scr
, event
, wPreferences
.mouse_button2
);
711 } else if (event
->xbutton
.button
==Button3
&&
712 wPreferences
.mouse_button3
!=WA_NONE
) {
713 executeButtonAction(scr
, event
, wPreferences
.mouse_button3
);
714 } else if (event
->xbutton
.button
==Button4
&&
715 wPreferences
.mouse_wheel
!=WA_NONE
) {
716 wWorkspaceRelativeChange(scr
, 1);
717 } else if (event
->xbutton
.button
==Button5
&&
718 wPreferences
.mouse_wheel
!=WA_NONE
) {
719 wWorkspaceRelativeChange(scr
, -1);
725 if (XFindContext(dpy
, event
->xbutton
.subwindow
, wWinContext
,
726 (XPointer
*)&desc
)==XCNOENT
) {
727 if (XFindContext(dpy
, event
->xbutton
.window
, wWinContext
,
728 (XPointer
*)&desc
)==XCNOENT
) {
733 if (desc
->parent_type
== WCLASS_WINDOW
) {
736 if (event
->xbutton
.state
& MOD_MASK
) {
737 XAllowEvents(dpy
, AsyncPointer
, CurrentTime
);
740 /* if (wPreferences.focus_mode == WKF_CLICK) {*/
741 if (wPreferences
.ignore_focus_click
) {
742 XAllowEvents(dpy
, AsyncPointer
, CurrentTime
);
744 XAllowEvents(dpy
, ReplayPointer
, CurrentTime
);
747 } else if (desc
->parent_type
== WCLASS_APPICON
748 || desc
->parent_type
== WCLASS_MINIWINDOW
749 || desc
->parent_type
== WCLASS_DOCK_ICON
) {
750 if (event
->xbutton
.state
& MOD_MASK
) {
752 XAllowEvents(dpy
, AsyncPointer
, CurrentTime
);
757 if (desc
->handle_mousedown
!=NULL
) {
758 (*desc
->handle_mousedown
)(desc
, event
);
761 /* save double-click information */
762 if (scr
->flags
.next_click_is_not_double
) {
763 scr
->flags
.next_click_is_not_double
= 0;
765 scr
->last_click_time
= event
->xbutton
.time
;
766 scr
->last_click_button
= event
->xbutton
.button
;
767 scr
->last_click_window
= event
->xbutton
.window
;
773 handleMapNotify(XEvent
*event
)
779 wwin
= wWindowFor(event
->xmap
.event
);
780 if (wwin
&& wwin
->client_win
== event
->xmap
.event
) {
781 if (wwin
->flags
.miniaturized
) {
782 wDeiconifyWindow(wwin
);
786 wClientSetState(wwin
, NormalState
, None
);
794 handleUnmapNotify(XEvent
*event
)
798 Bool withdraw
= False
;
800 printf("got unmap\n");
802 /* only process windows with StructureNotify selected
803 * (ignore SubstructureNotify) */
804 wwin
= wWindowFor(event
->xunmap
.window
);
808 /* whether the event is a Withdrawal request */
809 if (event
->xunmap
.event
== wwin
->screen_ptr
->root_win
810 && event
->xunmap
.send_event
)
813 if (wwin
->client_win
!= event
->xunmap
.event
&& !withdraw
)
816 if (!wwin
->flags
.mapped
&& !withdraw
817 && wwin
->frame
->workspace
== wwin
->screen_ptr
->current_workspace
818 && !wwin
->flags
.miniaturized
&& !wwin
->flags
.hidden
)
822 XUnmapWindow(dpy
, wwin
->frame
->core
->window
);
823 wwin
->flags
.mapped
= 0;
825 /* check if the window was destroyed */
826 if (XCheckTypedWindowEvent(dpy
, wwin
->client_win
, DestroyNotify
,&ev
)) {
829 Bool reparented
= False
;
831 if (XCheckTypedWindowEvent(dpy
, wwin
->client_win
, ReparentNotify
, &ev
))
834 /* withdraw window */
835 wwin
->flags
.mapped
= 0;
837 wClientSetState(wwin
, WithdrawnState
, None
);
839 /* if the window was reparented, do not reparent it back to the
841 wUnmanageWindow(wwin
, !reparented
, False
);
848 handleConfigureRequest(XEvent
*event
)
852 printf("got configure request\n");
854 if (!(wwin
=wWindowFor(event
->xconfigurerequest
.window
))) {
856 * Configure request for unmapped window
858 wClientConfigure(NULL
, &(event
->xconfigurerequest
));
860 wClientConfigure(wwin
, &(event
->xconfigurerequest
));
866 handlePropertyNotify(XEvent
*event
)
875 printf("got property notify\n");
877 if ((wwin
=wWindowFor(event
->xproperty
.window
))) {
878 if (!XGetGeometry(dpy
, wwin
->client_win
, &jr
, &ji
, &ji
,
879 &ju
, &ju
, &ju
, &ju
)) {
882 wClientCheckProperty(wwin
, &event
->xproperty
);
884 wapp
= wApplicationOf(event
->xproperty
.window
);
886 wClientCheckProperty(wapp
->main_window_desc
, &event
->xproperty
);
889 scr
= wScreenForWindow(event
->xproperty
.window
);
894 handleClientMessage(XEvent
*event
)
897 WObjDescriptor
*desc
;
899 printf("got client message\n");
901 /* handle transition from Normal to Iconic state */
902 if (event
->xclient
.message_type
== _XA_WM_CHANGE_STATE
903 && event
->xclient
.format
== 32
904 && event
->xclient
.data
.l
[0] == IconicState
) {
906 wwin
= wWindowFor(event
->xclient
.window
);
908 if (!wwin
->flags
.miniaturized
)
909 wIconifyWindow(wwin
);
910 } else if (event
->xclient
.message_type
== _XA_WM_COLORMAP_NOTIFY
911 && event
->xclient
.format
== 32) {
912 WScreen
*scr
= wScreenSearchForRootWindow(event
->xclient
.window
);
917 if (event
->xclient
.data
.l
[1] == 1) { /* starting */
918 wColormapAllowClientInstallation(scr
, True
);
919 } else { /* stopping */
920 wColormapAllowClientInstallation(scr
, False
);
922 } else if (event
->xclient
.message_type
== _XA_WINDOWMAKER_COMMAND
) {
924 wDefaultsCheckDomains("bla");
926 } else if (event
->xclient
.message_type
== _XA_WINDOWMAKER_WM_FUNCTION
) {
929 wapp
= wApplicationOf(event
->xclient
.window
);
931 switch (event
->xclient
.data
.l
[0]) {
932 case WMFHideOtherApplications
:
933 wHideOtherApplications(wapp
->main_window_desc
);
937 case WMFHideApplication
:
938 wHideApplication(wapp
);
944 wwin
= wWindowFor(event
->xclient
.window
);
946 switch (event
->xclient
.data
.l
[0]) {
947 case WMFHideOtherApplications
:
948 wHideOtherApplications(wwin
);
951 case WMFHideApplication
:
952 wHideApplication(wApplicationOf(wwin
->main_window
));
957 } else if (event
->xclient
.message_type
== _XA_GNUSTEP_WM_ATTR
) {
958 wwin
= wWindowFor(event
->xclient
.window
);
960 switch (event
->xclient
.data
.l
[0]) {
961 case GSWindowLevelAttr
:
963 int level
= (int)event
->xclient
.data
.l
[1];
965 if (WINDOW_LEVEL(wwin
) != level
) {
966 ChangeStackingLevel(wwin
->frame
->core
, level
);
971 } else if (event
->xclient
.message_type
== _XA_GNUSTEP_TITLEBAR_STATE
) {
972 wwin
= wWindowFor(event
->xclient
.window
);
974 switch (event
->xclient
.data
.l
[0]) {
975 case WMTitleBarNormal
:
976 wFrameWindowChangeState(wwin
->frame
, WS_UNFOCUSED
);
979 wFrameWindowChangeState(wwin
->frame
, WS_PFOCUSED
);
982 wFrameWindowChangeState(wwin
->frame
, WS_FOCUSED
);
986 } else if (wNETWMProcessClientMessage(&event
->xclient
)) {
990 } else if (wXDNDProcessClientMessage(&event
->xclient
)) {
995 * Non-standard thing, but needed by OffiX DND.
996 * For when the icon frame gets a ClientMessage
997 * that should have gone to the icon_window.
999 if (XFindContext(dpy
, event
->xbutton
.window
, wWinContext
,
1000 (XPointer
*)&desc
)!=XCNOENT
) {
1001 struct WIcon
*icon
=NULL
;
1003 if (desc
->parent_type
== WCLASS_MINIWINDOW
) {
1004 icon
= (WIcon
*)desc
->parent
;
1005 } else if (desc
->parent_type
== WCLASS_DOCK_ICON
1006 || desc
->parent_type
== WCLASS_APPICON
) {
1007 icon
= ((WAppIcon
*)desc
->parent
)->icon
;
1009 if (icon
&& (wwin
=icon
->owner
)) {
1010 if (wwin
->client_win
!=event
->xclient
.window
) {
1011 event
->xclient
.window
= wwin
->client_win
;
1012 XSendEvent(dpy
, wwin
->client_win
, False
, NoEventMask
,
1022 raiseWindow(WScreen
*scr
)
1026 scr
->autoRaiseTimer
= NULL
;
1028 wwin
= wWindowFor(scr
->autoRaiseWindow
);
1032 if (!wwin
->flags
.destroyed
&& wwin
->flags
.focused
) {
1033 wRaiseFrame(wwin
->frame
->core
);
1034 /* this is needed or a race condition will occur */
1041 handleEnterNotify(XEvent
*event
)
1044 WObjDescriptor
*desc
= NULL
;
1045 #ifdef VIRTUAL_DESKTOP
1046 void (*vdHandler
)(XEvent
* event
);
1049 WScreen
*scr
= wScreenForRootWindow(event
->xcrossing
.root
);
1051 printf("got enter notify\n");
1054 #ifdef VIRTUAL_DESKTOP
1055 if (XFindContext(dpy
, event
->xcrossing
.window
, wVEdgeContext
,
1056 (XPointer
*)&vdHandler
)!=XCNOENT
) {
1057 (*vdHandler
)(event
);
1061 if (XCheckTypedWindowEvent(dpy
, event
->xcrossing
.window
, LeaveNotify
,
1063 /* already left the window... */
1065 if (ev
.xcrossing
.mode
==event
->xcrossing
.mode
1066 && ev
.xcrossing
.detail
==event
->xcrossing
.detail
) {
1071 if (XFindContext(dpy
, event
->xcrossing
.window
, wWinContext
,
1072 (XPointer
*)&desc
)!=XCNOENT
) {
1073 if(desc
->handle_enternotify
)
1074 (*desc
->handle_enternotify
)(desc
, event
);
1077 /* enter to window */
1078 wwin
= wWindowFor(event
->xcrossing
.window
);
1080 if (wPreferences
.colormap_mode
==WCM_POINTER
) {
1081 wColormapInstallForWindow(scr
, NULL
);
1083 if (scr
->autoRaiseTimer
1084 && event
->xcrossing
.root
==event
->xcrossing
.window
) {
1085 WMDeleteTimerHandler(scr
->autoRaiseTimer
);
1086 scr
->autoRaiseTimer
= NULL
;
1089 /* set auto raise timer even if in focus-follows-mouse mode
1090 * and the event is for the frame window, even if the window
1091 * has focus already. useful if you move the pointer from a focused
1092 * window to the root window and back pretty fast
1094 * set focus if in focus-follows-mouse mode and the event
1095 * is for the frame window and window doesn't have focus yet */
1096 if (wPreferences
.focus_mode
==WKF_SLOPPY
1097 && wwin
->frame
->core
->window
==event
->xcrossing
.window
1098 && !scr
->flags
.doing_alt_tab
) {
1100 if (!wwin
->flags
.focused
&& !WFLAGP(wwin
, no_focusable
))
1101 wSetFocusTo(scr
, wwin
);
1103 if (scr
->autoRaiseTimer
)
1104 WMDeleteTimerHandler(scr
->autoRaiseTimer
);
1105 scr
->autoRaiseTimer
= NULL
;
1107 if (wPreferences
.raise_delay
&& !WFLAGP(wwin
, no_focusable
)) {
1108 scr
->autoRaiseWindow
= wwin
->frame
->core
->window
;
1110 = WMAddTimerHandler(wPreferences
.raise_delay
,
1111 (WMCallback
*)raiseWindow
, scr
);
1114 /* Install colormap for window, if the colormap installation mode
1115 * is colormap_follows_mouse */
1116 if (wPreferences
.colormap_mode
==WCM_POINTER
) {
1117 if (wwin
->client_win
==event
->xcrossing
.window
)
1118 wColormapInstallForWindow(scr
, wwin
);
1120 wColormapInstallForWindow(scr
, NULL
);
1124 /* a little kluge to hide the clip balloon */
1125 if (!wPreferences
.flags
.noclip
&& scr
->flags
.clip_balloon_mapped
) {
1127 XUnmapWindow(dpy
, scr
->clip_balloon
);
1128 scr
->flags
.clip_balloon_mapped
= 0;
1130 if (desc
->parent_type
!=WCLASS_DOCK_ICON
1131 || scr
->clip_icon
!= desc
->parent
) {
1132 XUnmapWindow(dpy
, scr
->clip_balloon
);
1133 scr
->flags
.clip_balloon_mapped
= 0;
1138 if (event
->xcrossing
.window
== event
->xcrossing
.root
1139 && event
->xcrossing
.detail
== NotifyNormal
1140 && event
->xcrossing
.detail
!= NotifyInferior
1141 && wPreferences
.focus_mode
!= WKF_CLICK
) {
1143 wSetFocusTo(scr
, scr
->focused_window
);
1147 wBalloonEnteredObject(scr
, desc
);
1153 handleLeaveNotify(XEvent
*event
)
1155 WObjDescriptor
*desc
= NULL
;
1157 if (XFindContext(dpy
, event
->xcrossing
.window
, wWinContext
,
1158 (XPointer
*)&desc
)!=XCNOENT
) {
1159 if(desc
->handle_leavenotify
)
1160 (*desc
->handle_leavenotify
)(desc
, event
);
1167 handleShapeNotify(XEvent
*event
)
1169 XShapeEvent
*shev
= (XShapeEvent
*)event
;
1173 printf("got shape notify\n");
1175 while (XCheckTypedWindowEvent(dpy
, shev
->window
, event
->type
, &ev
)) {
1176 XShapeEvent
*sev
= (XShapeEvent
*)&ev
;
1178 if (sev
->kind
== ShapeBounding
) {
1179 if (sev
->shaped
== shev
->shaped
) {
1182 XPutBackEvent(dpy
, &ev
);
1188 wwin
= wWindowFor(shev
->window
);
1189 if (!wwin
|| shev
->kind
!= ShapeBounding
)
1192 if (!shev
->shaped
&& wwin
->flags
.shaped
) {
1194 wwin
->flags
.shaped
= 0;
1195 wWindowClearShape(wwin
);
1197 } else if (shev
->shaped
) {
1199 wwin
->flags
.shaped
= 1;
1200 wWindowSetShape(wwin
);
1205 #ifdef KEEP_XKB_LOCK_STATUS
1206 /* please help ]d if you know what to do */
1207 handleXkbIndicatorStateNotify(XEvent
*event
)
1211 XkbStateRec staterec
;
1214 for (i
=0; i
<wScreenCount
; i
++) {
1215 scr
= wScreenWithNumber(i
);
1216 wwin
= scr
->focused_window
;
1217 if (wwin
&& wwin
->flags
.focused
) {
1218 XkbGetState(dpy
,XkbUseCoreKbd
,&staterec
);
1219 if (wwin
->frame
->languagemode
!= staterec
.group
) {
1220 wwin
->frame
->last_languagemode
= wwin
->frame
->languagemode
;
1221 wwin
->frame
->languagemode
= staterec
.group
;
1223 #ifdef XKB_BUTTON_HINT
1224 if (wwin
->frame
->titlebar
) {
1225 wFrameWindowPaint(wwin
->frame
);
1231 #endif /*KEEP_XKB_LOCK_STATUS*/
1234 handleColormapNotify(XEvent
*event
)
1238 Bool reinstall
= False
;
1240 wwin
= wWindowFor(event
->xcolormap
.window
);
1244 scr
= wwin
->screen_ptr
;
1248 if (event
->xcolormap
.new) {
1249 XWindowAttributes attr
;
1251 XGetWindowAttributes(dpy
, wwin
->client_win
, &attr
);
1253 if (wwin
== scr
->cmap_window
&& wwin
->cmap_window_no
== 0)
1254 scr
->current_colormap
= attr
.colormap
;
1257 } else if (event
->xcolormap
.state
== ColormapUninstalled
&&
1258 scr
->current_colormap
== event
->xcolormap
.colormap
) {
1260 /* some bastard app (like XV) removed our colormap */
1262 * can't enforce or things like xscreensaver wont work
1265 } else if (event
->xcolormap
.state
== ColormapInstalled
&&
1266 scr
->current_colormap
== event
->xcolormap
.colormap
) {
1268 /* someone has put our colormap back */
1272 } while (XCheckTypedEvent(dpy
, ColormapNotify
, event
)
1273 && ((wwin
= wWindowFor(event
->xcolormap
.window
)) || 1));
1275 if (reinstall
&& scr
->current_colormap
!=None
) {
1276 if (!scr
->flags
.colormap_stuff_blocked
)
1277 XInstallColormap(dpy
, scr
->current_colormap
);
1284 handleFocusIn(XEvent
*event
)
1289 * For applications that like stealing the focus.
1291 while (XCheckTypedEvent(dpy
, FocusIn
, event
));
1292 saveTimestamp(event
);
1293 if (event
->xfocus
.mode
== NotifyUngrab
1294 || event
->xfocus
.mode
== NotifyGrab
1295 || event
->xfocus
.detail
> NotifyNonlinearVirtual
) {
1299 wwin
= wWindowFor(event
->xfocus
.window
);
1300 if (wwin
&& !wwin
->flags
.focused
) {
1301 if (wwin
->flags
.mapped
)
1302 wSetFocusTo(wwin
->screen_ptr
, wwin
);
1304 wSetFocusTo(wwin
->screen_ptr
, NULL
);
1306 WScreen
*scr
= wScreenForWindow(event
->xfocus
.window
);
1308 wSetFocusTo(scr
, NULL
);
1314 windowUnderPointer(WScreen
*scr
)
1320 if (XQueryPointer(dpy
, scr
->root_win
, &bar
, &win
, &foo
, &foo
, &foo
, &foo
,
1322 return wWindowFor(win
);
1327 static int CheckFullScreenWindowFocused(WScreen
*scr
)
1329 if (scr
->focused_window
&& scr
->focused_window
->flags
.fullscreen
)
1337 handleKeyPress(XEvent
*event
)
1339 WScreen
*scr
= wScreenForRootWindow(event
->xkey
.root
);
1340 WWindow
*wwin
= scr
->focused_window
;
1343 int command
=-1, index
;
1344 #ifdef KEEP_XKB_LOCK_STATUS
1345 XkbStateRec staterec
;
1346 #endif /*KEEP_XKB_LOCK_STATUS*/
1348 /* ignore CapsLock */
1349 modifiers
= event
->xkey
.state
& ValidModMask
;
1351 for (i
=0; i
<WKBD_LAST
; i
++) {
1352 if (wKeyBindings
[i
].keycode
==0)
1355 if (wKeyBindings
[i
].keycode
==event
->xkey
.keycode
1356 && (/*wKeyBindings[i].modifier==0
1357 ||*/ wKeyBindings
[i
].modifier
==modifiers
)) {
1371 if (!wRootMenuPerformShortcut(event
)) {
1373 static int dontLoop
= 0;
1375 if (dontLoop
> 10) {
1376 wwarning("problem with key event processing code");
1380 /* if the focused window is an internal window, try redispatching
1381 * the event to the managed window, as it can be a WINGs window */
1382 if (wwin
&& wwin
->flags
.internal_window
1383 && wwin
->client_leader
!=None
) {
1384 /* client_leader contains the WINGs toplevel */
1385 event
->xany
.window
= wwin
->client_leader
;
1386 WMHandleEvent(event
);
1393 #define ISMAPPED(w) ((w) && !(w)->flags.miniaturized && ((w)->flags.mapped || (w)->flags.shaded))
1394 #define ISFOCUSED(w) ((w) && (w)->flags.focused)
1399 /*OpenRootMenu(scr, event->xkey.x_root, event->xkey.y_root, True);*/
1400 if (!CheckFullScreenWindowFocused(scr
)) {
1401 WMRect rect
= wGetRectForHead(scr
, wGetHeadForPointerLocation(scr
));
1402 OpenRootMenu(scr
, rect
.pos
.x
+ rect
.size
.width
/2, rect
.pos
.y
+ rect
.size
.height
/2, True
);
1405 case WKBD_WINDOWLIST
:
1406 if (!CheckFullScreenWindowFocused(scr
)) {
1407 WMRect rect
= wGetRectForHead(scr
, wGetHeadForPointerLocation(scr
));
1408 OpenSwitchMenu(scr
, rect
.pos
.x
+ rect
.size
.width
/2, rect
.pos
.y
+ rect
.size
.height
/2, True
);
1412 case WKBD_WINDOWMENU
:
1413 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
))
1414 OpenWindowMenu(wwin
, wwin
->frame_x
,
1415 wwin
->frame_y
+wwin
->frame
->top_width
, True
);
1417 case WKBD_MINIATURIZE
:
1418 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)
1419 && !WFLAGP(wwin
, no_miniaturizable
)) {
1420 CloseWindowMenu(scr
);
1422 if (wwin
->protocols
.MINIATURIZE_WINDOW
)
1423 wClientSendProtocol(wwin
, _XA_GNUSTEP_WM_MINIATURIZE_WINDOW
,
1424 event
->xbutton
.time
);
1426 wIconifyWindow(wwin
);
1431 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1432 WApplication
*wapp
= wApplicationOf(wwin
->main_window
);
1433 CloseWindowMenu(scr
);
1435 if (wapp
&& !WFLAGP(wapp
->main_window_desc
, no_appicon
)) {
1436 wHideApplication(wapp
);
1440 case WKBD_HIDE_OTHERS
:
1441 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1442 CloseWindowMenu(scr
);
1444 wHideOtherApplications(wwin
);
1448 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
) && IS_RESIZABLE(wwin
)) {
1449 int newdir
= (MAX_VERTICAL
|MAX_HORIZONTAL
);
1451 CloseWindowMenu(scr
);
1453 if (wwin
->flags
.maximized
== newdir
) {
1454 wUnmaximizeWindow(wwin
);
1456 wMaximizeWindow(wwin
, newdir
|MAX_KEYBOARD
);
1460 case WKBD_VMAXIMIZE
:
1461 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
) && IS_RESIZABLE(wwin
)) {
1462 int newdir
= (MAX_VERTICAL
^ wwin
->flags
.maximized
);
1464 CloseWindowMenu(scr
);
1467 wMaximizeWindow(wwin
, newdir
|MAX_KEYBOARD
);
1469 wUnmaximizeWindow(wwin
);
1473 case WKBD_HMAXIMIZE
:
1474 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
) && IS_RESIZABLE(wwin
)) {
1475 int newdir
= (MAX_HORIZONTAL
^ wwin
->flags
.maximized
);
1477 CloseWindowMenu(scr
);
1480 wMaximizeWindow(wwin
, newdir
|MAX_KEYBOARD
);
1482 wUnmaximizeWindow(wwin
);
1487 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1488 CloseWindowMenu(scr
);
1490 wRaiseFrame(wwin
->frame
->core
);
1494 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1495 CloseWindowMenu(scr
);
1497 wLowerFrame(wwin
->frame
->core
);
1500 case WKBD_RAISELOWER
:
1501 /* raise or lower the window under the pointer, not the
1504 wwin
= windowUnderPointer(scr
);
1506 wRaiseLowerFrame(wwin
->frame
->core
);
1509 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
) && !WFLAGP(wwin
, no_shadeable
)) {
1510 if (wwin
->flags
.shaded
)
1511 wUnshadeWindow(wwin
);
1516 case WKBD_MOVERESIZE
:
1517 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
) &&
1518 (IS_RESIZABLE(wwin
) || IS_MOVABLE(wwin
))) {
1519 CloseWindowMenu(scr
);
1521 wKeyboardMoveResizeWindow(wwin
);
1525 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
) && !WFLAGP(wwin
, no_closable
)) {
1526 CloseWindowMenu(scr
);
1527 if (wwin
->protocols
.DELETE_WINDOW
)
1528 wClientSendProtocol(wwin
, _XA_WM_DELETE_WINDOW
,
1533 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1534 wSelectWindow(wwin
, !wwin
->flags
.selected
);
1537 case WKBD_FOCUSNEXT
:
1538 StartWindozeCycle(wwin
, event
, True
);
1541 case WKBD_FOCUSPREV
:
1542 StartWindozeCycle(wwin
, event
, False
);
1545 #if (defined(__STDC__) && !defined(UNIXCPP)) || defined(ANSICPP)
1546 #define GOTOWORKS(wk) case WKBD_WORKSPACE##wk:\
1547 i = (scr->current_workspace/10)*10 + wk - 1;\
1548 if (wPreferences.ws_advance || i<scr->workspace_count)\
1549 wWorkspaceChange(scr, i);\
1552 #define GOTOWORKS(wk) case WKBD_WORKSPACE/**/wk:\
1553 i = (scr->current_workspace/10)*10 + wk - 1;\
1554 if (wPreferences.ws_advance || i<scr->workspace_count)\
1555 wWorkspaceChange(scr, i);\
1569 case WKBD_NEXTWORKSPACE
:
1570 wWorkspaceRelativeChange(scr
, 1);
1572 case WKBD_PREVWORKSPACE
:
1573 wWorkspaceRelativeChange(scr
, -1);
1586 index
= command
-WKBD_WINDOW1
;
1588 if (scr
->shortcutWindows
[index
]) {
1589 WMArray
*list
= scr
->shortcutWindows
[index
];
1591 int count
= WMGetArrayItemCount(list
);
1593 WMArrayIterator iter
;
1596 wUnselectWindows(scr
);
1597 cw
= scr
->current_workspace
;
1599 WM_ETARETI_ARRAY(list
, wwin
, iter
) {
1601 wWindowChangeWorkspace(wwin
, cw
);
1603 wMakeWindowVisible(wwin
);
1606 wSelectWindow(wwin
, True
);
1609 /* rotate the order of windows, to create a cycling effect */
1610 twin
= WMGetFromArray(list
, 0);
1611 WMDeleteFromArray(list
, 0);
1612 WMAddToArray(list
, twin
);
1614 } else if (wwin
&& ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1615 if (scr
->shortcutWindows
[index
]) {
1616 WMFreeArray(scr
->shortcutWindows
[index
]);
1617 scr
->shortcutWindows
[index
] = NULL
;
1620 if (wwin
->flags
.selected
&& scr
->selected_windows
) {
1621 scr
->shortcutWindows
[index
] =
1622 WMDuplicateArray(scr
->selected_windows
);
1623 /*WMRemoveFromArray(scr->shortcutWindows[index], wwin);
1624 WMInsertInArray(scr->shortcutWindows[index], 0, wwin);*/
1626 scr
->shortcutWindows
[index
] = WMCreateArray(4);
1627 WMAddToArray(scr
->shortcutWindows
[index
], wwin
);
1630 wSelectWindow(wwin
, !wwin
->flags
.selected
);
1633 wSelectWindow(wwin
, !wwin
->flags
.selected
);
1636 } else if (scr
->selected_windows
1637 && WMGetArrayItemCount(scr
->selected_windows
)) {
1639 if (wwin
->flags
.selected
&& scr
->selected_windows
) {
1640 if (scr
->shortcutWindows
[index
]) {
1641 WMFreeArray(scr
->shortcutWindows
[index
]);
1643 scr
->shortcutWindows
[index
] =
1644 WMDuplicateArray(scr
->selected_windows
);
1650 case WKBD_SWITCH_SCREEN
:
1651 if (wScreenCount
> 1) {
1655 /* find index of this screen */
1656 for (i
= 0; i
< wScreenCount
; i
++) {
1657 if (wScreenWithNumber(i
) == scr
)
1661 if (i
>= wScreenCount
) {
1664 scr2
= wScreenWithNumber(i
);
1667 XWarpPointer(dpy
, scr
->root_win
, scr2
->root_win
, 0, 0, 0, 0,
1668 scr2
->scr_width
/2, scr2
->scr_height
/2);
1673 case WKBD_NEXTWSLAYER
:
1674 case WKBD_PREVWSLAYER
:
1678 row
= scr
->current_workspace
/10;
1679 column
= scr
->current_workspace
%10;
1681 if (command
==WKBD_NEXTWSLAYER
) {
1682 if ((row
+1)*10 < scr
->workspace_count
)
1683 wWorkspaceChange(scr
, column
+(row
+1)*10);
1686 wWorkspaceChange(scr
, column
+(row
-1)*10);
1690 case WKBD_CLIPLOWER
:
1691 if (!wPreferences
.flags
.noclip
)
1692 wDockLower(scr
->workspaces
[scr
->current_workspace
]->clip
);
1694 case WKBD_CLIPRAISE
:
1695 if (!wPreferences
.flags
.noclip
)
1696 wDockRaise(scr
->workspaces
[scr
->current_workspace
]->clip
);
1698 case WKBD_CLIPRAISELOWER
:
1699 if (!wPreferences
.flags
.noclip
)
1700 wDockRaiseLower(scr
->workspaces
[scr
->current_workspace
]->clip
);
1702 #ifdef KEEP_XKB_LOCK_STATUS
1704 if(wPreferences
.modelock
) {
1706 wwin
= scr
->focused_window
;
1708 if (wwin
&& wwin
->flags
.mapped
1709 && wwin
->frame
->workspace
== wwin
->screen_ptr
->current_workspace
1710 && !wwin
->flags
.miniaturized
&& !wwin
->flags
.hidden
) {
1711 XkbGetState(dpy
,XkbUseCoreKbd
,&staterec
);
1713 wwin
->frame
->languagemode
= wwin
->frame
->last_languagemode
;
1714 wwin
->frame
->last_languagemode
= staterec
.group
;
1715 XkbLockGroup(dpy
,XkbUseCoreKbd
, wwin
->frame
->languagemode
);
1720 #endif /* KEEP_XKB_LOCK_STATUS */
1721 #ifdef VIRTUAL_DESKTOP
1722 case WKBD_VDESK_LEFT
:
1723 wWorkspaceKeyboardMoveDesktop(scr
, VEC_LEFT
);
1726 case WKBD_VDESK_RIGHT
:
1727 wWorkspaceKeyboardMoveDesktop(scr
, VEC_RIGHT
);
1731 wWorkspaceKeyboardMoveDesktop(scr
, VEC_UP
);
1734 case WKBD_VDESK_DOWN
:
1735 wWorkspaceKeyboardMoveDesktop(scr
, VEC_DOWN
);
1744 handleMotionNotify(XEvent
*event
)
1746 WScreen
*scr
= wScreenForRootWindow(event
->xmotion
.root
);
1748 if (wPreferences
.scrollable_menus
) {
1749 WMPoint p
= wmkpoint(event
->xmotion
.x_root
, event
->xmotion
.y_root
);
1750 WMRect rect
= wGetRectForHead(scr
, wGetHeadForPoint(scr
, p
));
1752 if (scr
->flags
.jump_back_pending
||
1753 p
.x
<= (rect
.pos
.x
+ 1) ||
1754 p
.x
>= (rect
.pos
.x
+ rect
.size
.width
- 2) ||
1755 p
.y
<= (rect
.pos
.y
+ 1) ||
1756 p
.y
>= (rect
.pos
.y
+ rect
.size
.height
- 2)) {
1759 printf("pointer at screen edge\n");
1761 menu
= wMenuUnderPointer(scr
);
1763 wMenuScroll(menu
, event
);
1770 handleVisibilityNotify(XEvent
*event
)
1774 wwin
= wWindowFor(event
->xvisibility
.window
);
1777 wwin
->flags
.obscured
=
1778 (event
->xvisibility
.state
== VisibilityFullyObscured
);