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
.hidden
) {
563 WApplication
*wapp
= wApplicationOf(wwin
->main_window
);
565 wwin
->flags
.hidden
= 0;
566 wwin
->flags
.skip_next_animation
= 1;
568 wHideApplication(wapp
);
576 handleDestroyNotify(XEvent
*event
)
580 Window window
= event
->xdestroywindow
.window
;
581 WScreen
*scr
= wScreenForRootWindow(event
->xdestroywindow
.event
);
585 printf("got destroy notify\n");
587 wwin
= wWindowFor(window
);
589 wUnmanageWindow(wwin
, False
, True
);
593 while ((index
= WMFindInArray(scr
->fakeGroupLeaders
, matchWindow
,
594 (void*)window
)) != WANotFound
) {
595 WFakeGroupLeader
*fPtr
;
597 fPtr
= WMGetFromArray(scr
->fakeGroupLeaders
, index
);
598 if (fPtr
->retainCount
> 0) {
600 if (fPtr
->retainCount
==0 && fPtr
->leader
!=None
) {
601 XDestroyWindow(dpy
, fPtr
->leader
);
606 fPtr
->origLeader
= None
;
610 app
= wApplicationOf(window
);
612 if (window
== app
->main_window
) {
614 wwin
= app
->main_window_desc
->screen_ptr
->focused_window
;
616 if (wwin
->main_window
== window
) {
617 wwin
->main_window
= None
;
622 wApplicationDestroy(app
);
629 handleExpose(XEvent
*event
)
631 WObjDescriptor
*desc
;
635 printf("got expose\n");
637 while (XCheckTypedWindowEvent(dpy
, event
->xexpose
.window
, Expose
, &ev
));
639 if (XFindContext(dpy
, event
->xexpose
.window
, wWinContext
,
640 (XPointer
*)&desc
)==XCNOENT
) {
644 if (desc
->handle_expose
) {
645 (*desc
->handle_expose
)(desc
, event
);
650 executeButtonAction(WScreen
*scr
, XEvent
*event
, int action
)
653 case WA_SELECT_WINDOWS
:
654 wUnselectWindows(scr
);
655 wSelectWindows(scr
, event
);
657 case WA_OPEN_APPMENU
:
658 OpenRootMenu(scr
, event
->xbutton
.x_root
, event
->xbutton
.y_root
, False
);
660 if (scr
->root_menu
) {
661 if (scr
->root_menu
->brother
->flags
.mapped
)
662 event
->xbutton
.window
= scr
->root_menu
->brother
->frame
->core
->window
;
664 event
->xbutton
.window
= scr
->root_menu
->frame
->core
->window
;
667 case WA_OPEN_WINLISTMENU
:
668 OpenSwitchMenu(scr
, event
->xbutton
.x_root
, event
->xbutton
.y_root
, False
);
669 if (scr
->switch_menu
) {
670 if (scr
->switch_menu
->brother
->flags
.mapped
)
671 event
->xbutton
.window
= scr
->switch_menu
->brother
->frame
->core
->window
;
673 event
->xbutton
.window
= scr
->switch_menu
->frame
->core
->window
;
684 handleButtonPress(XEvent
*event
)
686 WObjDescriptor
*desc
;
690 printf("got button press\n");
692 scr
= wScreenForRootWindow(event
->xbutton
.root
);
700 if (event
->xbutton
.window
==scr
->root_win
) {
701 if (event
->xbutton
.button
==Button1
&&
702 wPreferences
.mouse_button1
!=WA_NONE
) {
703 executeButtonAction(scr
, event
, wPreferences
.mouse_button1
);
704 } else if (event
->xbutton
.button
==Button2
&&
705 wPreferences
.mouse_button2
!=WA_NONE
) {
706 executeButtonAction(scr
, event
, wPreferences
.mouse_button2
);
707 } else if (event
->xbutton
.button
==Button3
&&
708 wPreferences
.mouse_button3
!=WA_NONE
) {
709 executeButtonAction(scr
, event
, wPreferences
.mouse_button3
);
710 } else if (event
->xbutton
.button
==Button4
&&
711 wPreferences
.mouse_wheel
!=WA_NONE
) {
712 wWorkspaceRelativeChange(scr
, 1);
713 } else if (event
->xbutton
.button
==Button5
&&
714 wPreferences
.mouse_wheel
!=WA_NONE
) {
715 wWorkspaceRelativeChange(scr
, -1);
721 if (XFindContext(dpy
, event
->xbutton
.subwindow
, wWinContext
,
722 (XPointer
*)&desc
)==XCNOENT
) {
723 if (XFindContext(dpy
, event
->xbutton
.window
, wWinContext
,
724 (XPointer
*)&desc
)==XCNOENT
) {
729 if (desc
->parent_type
== WCLASS_WINDOW
) {
732 if (event
->xbutton
.state
& MOD_MASK
) {
733 XAllowEvents(dpy
, AsyncPointer
, CurrentTime
);
736 /* if (wPreferences.focus_mode == WKF_CLICK) {*/
737 if (wPreferences
.ignore_focus_click
) {
738 XAllowEvents(dpy
, AsyncPointer
, CurrentTime
);
740 XAllowEvents(dpy
, ReplayPointer
, CurrentTime
);
743 } else if (desc
->parent_type
== WCLASS_APPICON
744 || desc
->parent_type
== WCLASS_MINIWINDOW
745 || desc
->parent_type
== WCLASS_DOCK_ICON
) {
746 if (event
->xbutton
.state
& MOD_MASK
) {
748 XAllowEvents(dpy
, AsyncPointer
, CurrentTime
);
753 if (desc
->handle_mousedown
!=NULL
) {
754 (*desc
->handle_mousedown
)(desc
, event
);
757 /* save double-click information */
758 if (scr
->flags
.next_click_is_not_double
) {
759 scr
->flags
.next_click_is_not_double
= 0;
761 scr
->last_click_time
= event
->xbutton
.time
;
762 scr
->last_click_button
= event
->xbutton
.button
;
763 scr
->last_click_window
= event
->xbutton
.window
;
769 handleMapNotify(XEvent
*event
)
775 wwin
= wWindowFor(event
->xmap
.event
);
776 if (wwin
&& wwin
->client_win
== event
->xmap
.event
) {
777 if (wwin
->flags
.miniaturized
) {
778 wDeiconifyWindow(wwin
);
782 wClientSetState(wwin
, NormalState
, None
);
790 handleUnmapNotify(XEvent
*event
)
794 Bool withdraw
= False
;
796 printf("got unmap\n");
798 /* only process windows with StructureNotify selected
799 * (ignore SubstructureNotify) */
800 wwin
= wWindowFor(event
->xunmap
.window
);
804 /* whether the event is a Withdrawal request */
805 if (event
->xunmap
.event
== wwin
->screen_ptr
->root_win
806 && event
->xunmap
.send_event
)
809 if (wwin
->client_win
!= event
->xunmap
.event
&& !withdraw
)
812 if (!wwin
->flags
.mapped
&& !withdraw
813 && wwin
->frame
->workspace
== wwin
->screen_ptr
->current_workspace
814 && !wwin
->flags
.miniaturized
&& !wwin
->flags
.hidden
)
818 XUnmapWindow(dpy
, wwin
->frame
->core
->window
);
819 wwin
->flags
.mapped
= 0;
821 /* check if the window was destroyed */
822 if (XCheckTypedWindowEvent(dpy
, wwin
->client_win
, DestroyNotify
,&ev
)) {
825 Bool reparented
= False
;
827 if (XCheckTypedWindowEvent(dpy
, wwin
->client_win
, ReparentNotify
, &ev
))
830 /* withdraw window */
831 wwin
->flags
.mapped
= 0;
833 wClientSetState(wwin
, WithdrawnState
, None
);
835 /* if the window was reparented, do not reparent it back to the
837 wUnmanageWindow(wwin
, !reparented
, False
);
844 handleConfigureRequest(XEvent
*event
)
848 printf("got configure request\n");
850 if (!(wwin
=wWindowFor(event
->xconfigurerequest
.window
))) {
852 * Configure request for unmapped window
854 wClientConfigure(NULL
, &(event
->xconfigurerequest
));
856 wClientConfigure(wwin
, &(event
->xconfigurerequest
));
862 handlePropertyNotify(XEvent
*event
)
871 printf("got property notify\n");
873 if ((wwin
=wWindowFor(event
->xproperty
.window
))) {
874 if (!XGetGeometry(dpy
, wwin
->client_win
, &jr
, &ji
, &ji
,
875 &ju
, &ju
, &ju
, &ju
)) {
878 wClientCheckProperty(wwin
, &event
->xproperty
);
880 wapp
= wApplicationOf(event
->xproperty
.window
);
882 wClientCheckProperty(wapp
->main_window_desc
, &event
->xproperty
);
885 scr
= wScreenForWindow(event
->xproperty
.window
);
890 handleClientMessage(XEvent
*event
)
893 WObjDescriptor
*desc
;
895 printf("got client message\n");
897 /* handle transition from Normal to Iconic state */
898 if (event
->xclient
.message_type
== _XA_WM_CHANGE_STATE
899 && event
->xclient
.format
== 32
900 && event
->xclient
.data
.l
[0] == IconicState
) {
902 wwin
= wWindowFor(event
->xclient
.window
);
904 if (!wwin
->flags
.miniaturized
)
905 wIconifyWindow(wwin
);
906 } else if (event
->xclient
.message_type
== _XA_WM_COLORMAP_NOTIFY
907 && event
->xclient
.format
== 32) {
908 WScreen
*scr
= wScreenSearchForRootWindow(event
->xclient
.window
);
913 if (event
->xclient
.data
.l
[1] == 1) { /* starting */
914 wColormapAllowClientInstallation(scr
, True
);
915 } else { /* stopping */
916 wColormapAllowClientInstallation(scr
, False
);
918 } else if (event
->xclient
.message_type
== _XA_WINDOWMAKER_COMMAND
) {
920 wDefaultsCheckDomains("bla");
922 } else if (event
->xclient
.message_type
== _XA_WINDOWMAKER_WM_FUNCTION
) {
925 wapp
= wApplicationOf(event
->xclient
.window
);
927 switch (event
->xclient
.data
.l
[0]) {
928 case WMFHideOtherApplications
:
929 wHideOtherApplications(wapp
->main_window_desc
);
933 case WMFHideApplication
:
934 wHideApplication(wapp
);
940 wwin
= wWindowFor(event
->xclient
.window
);
942 switch (event
->xclient
.data
.l
[0]) {
943 case WMFHideOtherApplications
:
944 wHideOtherApplications(wwin
);
947 case WMFHideApplication
:
948 wHideApplication(wApplicationOf(wwin
->main_window
));
953 } else if (event
->xclient
.message_type
== _XA_GNUSTEP_WM_ATTR
) {
954 wwin
= wWindowFor(event
->xclient
.window
);
956 switch (event
->xclient
.data
.l
[0]) {
957 case GSWindowLevelAttr
:
959 int level
= (int)event
->xclient
.data
.l
[1];
961 if (WINDOW_LEVEL(wwin
) != level
) {
962 ChangeStackingLevel(wwin
->frame
->core
, level
);
967 } else if (event
->xclient
.message_type
== _XA_GNUSTEP_TITLEBAR_STATE
) {
968 wwin
= wWindowFor(event
->xclient
.window
);
970 switch (event
->xclient
.data
.l
[0]) {
971 case WMTitleBarNormal
:
972 wFrameWindowChangeState(wwin
->frame
, WS_UNFOCUSED
);
975 wFrameWindowChangeState(wwin
->frame
, WS_PFOCUSED
);
978 wFrameWindowChangeState(wwin
->frame
, WS_FOCUSED
);
982 } else if (wNETWMProcessClientMessage(&event
->xclient
)) {
986 } else if (wXDNDProcessClientMessage(&event
->xclient
)) {
991 * Non-standard thing, but needed by OffiX DND.
992 * For when the icon frame gets a ClientMessage
993 * that should have gone to the icon_window.
995 if (XFindContext(dpy
, event
->xbutton
.window
, wWinContext
,
996 (XPointer
*)&desc
)!=XCNOENT
) {
997 struct WIcon
*icon
=NULL
;
999 if (desc
->parent_type
== WCLASS_MINIWINDOW
) {
1000 icon
= (WIcon
*)desc
->parent
;
1001 } else if (desc
->parent_type
== WCLASS_DOCK_ICON
1002 || desc
->parent_type
== WCLASS_APPICON
) {
1003 icon
= ((WAppIcon
*)desc
->parent
)->icon
;
1005 if (icon
&& (wwin
=icon
->owner
)) {
1006 if (wwin
->client_win
!=event
->xclient
.window
) {
1007 event
->xclient
.window
= wwin
->client_win
;
1008 XSendEvent(dpy
, wwin
->client_win
, False
, NoEventMask
,
1018 raiseWindow(WScreen
*scr
)
1022 scr
->autoRaiseTimer
= NULL
;
1024 wwin
= wWindowFor(scr
->autoRaiseWindow
);
1028 if (!wwin
->flags
.destroyed
&& wwin
->flags
.focused
) {
1029 wRaiseFrame(wwin
->frame
->core
);
1030 /* this is needed or a race condition will occur */
1037 handleEnterNotify(XEvent
*event
)
1040 WObjDescriptor
*desc
= NULL
;
1041 #ifdef VIRTUAL_DESKTOP
1042 void (*vdHandler
)(XEvent
* event
);
1045 WScreen
*scr
= wScreenForRootWindow(event
->xcrossing
.root
);
1047 printf("got enter notify\n");
1050 #ifdef VIRTUAL_DESKTOP
1051 if (XFindContext(dpy
, event
->xcrossing
.window
, wVEdgeContext
,
1052 (XPointer
*)&vdHandler
)!=XCNOENT
) {
1053 (*vdHandler
)( event
);
1057 if (XCheckTypedWindowEvent(dpy
, event
->xcrossing
.window
, LeaveNotify
,
1059 /* already left the window... */
1061 if (ev
.xcrossing
.mode
==event
->xcrossing
.mode
1062 && ev
.xcrossing
.detail
==event
->xcrossing
.detail
) {
1067 if (XFindContext(dpy
, event
->xcrossing
.window
, wWinContext
,
1068 (XPointer
*)&desc
)!=XCNOENT
) {
1069 if(desc
->handle_enternotify
)
1070 (*desc
->handle_enternotify
)(desc
, event
);
1073 /* enter to window */
1074 wwin
= wWindowFor(event
->xcrossing
.window
);
1076 if (wPreferences
.colormap_mode
==WCM_POINTER
) {
1077 wColormapInstallForWindow(scr
, NULL
);
1079 if (scr
->autoRaiseTimer
1080 && event
->xcrossing
.root
==event
->xcrossing
.window
) {
1081 WMDeleteTimerHandler(scr
->autoRaiseTimer
);
1082 scr
->autoRaiseTimer
= NULL
;
1085 /* set auto raise timer even if in focus-follows-mouse mode
1086 * and the event is for the frame window, even if the window
1087 * has focus already. useful if you move the pointer from a focused
1088 * window to the root window and back pretty fast
1090 * set focus if in focus-follows-mouse mode and the event
1091 * is for the frame window and window doesn't have focus yet */
1092 if (wPreferences
.focus_mode
==WKF_SLOPPY
1093 && wwin
->frame
->core
->window
==event
->xcrossing
.window
1094 && !scr
->flags
.doing_alt_tab
) {
1096 if (!wwin
->flags
.focused
&& !WFLAGP(wwin
, no_focusable
))
1097 wSetFocusTo(scr
, wwin
);
1099 if (scr
->autoRaiseTimer
)
1100 WMDeleteTimerHandler(scr
->autoRaiseTimer
);
1101 scr
->autoRaiseTimer
= NULL
;
1103 if (wPreferences
.raise_delay
&& !WFLAGP(wwin
, no_focusable
)) {
1104 scr
->autoRaiseWindow
= wwin
->frame
->core
->window
;
1106 = WMAddTimerHandler(wPreferences
.raise_delay
,
1107 (WMCallback
*)raiseWindow
, scr
);
1110 /* Install colormap for window, if the colormap installation mode
1111 * is colormap_follows_mouse */
1112 if (wPreferences
.colormap_mode
==WCM_POINTER
) {
1113 if (wwin
->client_win
==event
->xcrossing
.window
)
1114 wColormapInstallForWindow(scr
, wwin
);
1116 wColormapInstallForWindow(scr
, NULL
);
1120 /* a little kluge to hide the clip balloon */
1121 if (!wPreferences
.flags
.noclip
&& scr
->flags
.clip_balloon_mapped
) {
1123 XUnmapWindow(dpy
, scr
->clip_balloon
);
1124 scr
->flags
.clip_balloon_mapped
= 0;
1126 if (desc
->parent_type
!=WCLASS_DOCK_ICON
1127 || scr
->clip_icon
!= desc
->parent
) {
1128 XUnmapWindow(dpy
, scr
->clip_balloon
);
1129 scr
->flags
.clip_balloon_mapped
= 0;
1134 if (event
->xcrossing
.window
== event
->xcrossing
.root
1135 && event
->xcrossing
.detail
== NotifyNormal
1136 && event
->xcrossing
.detail
!= NotifyInferior
1137 && wPreferences
.focus_mode
!= WKF_CLICK
) {
1139 wSetFocusTo(scr
, scr
->focused_window
);
1143 wBalloonEnteredObject(scr
, desc
);
1149 handleLeaveNotify(XEvent
*event
)
1151 WObjDescriptor
*desc
= NULL
;
1153 if (XFindContext(dpy
, event
->xcrossing
.window
, wWinContext
,
1154 (XPointer
*)&desc
)!=XCNOENT
) {
1155 if(desc
->handle_leavenotify
)
1156 (*desc
->handle_leavenotify
)(desc
, event
);
1163 handleShapeNotify(XEvent
*event
)
1165 XShapeEvent
*shev
= (XShapeEvent
*)event
;
1169 printf("got shape notify\n");
1171 while (XCheckTypedWindowEvent(dpy
, shev
->window
, event
->type
, &ev
)) {
1172 XShapeEvent
*sev
= (XShapeEvent
*)&ev
;
1174 if (sev
->kind
== ShapeBounding
) {
1175 if (sev
->shaped
== shev
->shaped
) {
1178 XPutBackEvent(dpy
, &ev
);
1184 wwin
= wWindowFor(shev
->window
);
1185 if (!wwin
|| shev
->kind
!= ShapeBounding
)
1188 if (!shev
->shaped
&& wwin
->flags
.shaped
) {
1190 wwin
->flags
.shaped
= 0;
1191 wWindowClearShape(wwin
);
1193 } else if (shev
->shaped
) {
1195 wwin
->flags
.shaped
= 1;
1196 wWindowSetShape(wwin
);
1201 #ifdef KEEP_XKB_LOCK_STATUS
1202 /* please help ]d if you know what to do */
1203 handleXkbIndicatorStateNotify(XEvent
*event
)
1207 XkbStateRec staterec
;
1210 for (i
=0; i
<wScreenCount
; i
++) {
1211 scr
= wScreenWithNumber(i
);
1212 wwin
= scr
->focused_window
;
1213 if (wwin
&& wwin
->flags
.focused
) {
1214 XkbGetState(dpy
,XkbUseCoreKbd
,&staterec
);
1215 if (wwin
->frame
->languagemode
!= staterec
.group
) {
1216 wwin
->frame
->last_languagemode
= wwin
->frame
->languagemode
;
1217 wwin
->frame
->languagemode
= staterec
.group
;
1219 #ifdef XKB_BUTTON_HINT
1220 if (wwin
->frame
->titlebar
) {
1221 wFrameWindowPaint(wwin
->frame
);
1227 #endif /*KEEP_XKB_LOCK_STATUS*/
1230 handleColormapNotify(XEvent
*event
)
1234 Bool reinstall
= False
;
1236 wwin
= wWindowFor(event
->xcolormap
.window
);
1240 scr
= wwin
->screen_ptr
;
1244 if (event
->xcolormap
.new) {
1245 XWindowAttributes attr
;
1247 XGetWindowAttributes(dpy
, wwin
->client_win
, &attr
);
1249 if (wwin
== scr
->cmap_window
&& wwin
->cmap_window_no
== 0)
1250 scr
->current_colormap
= attr
.colormap
;
1253 } else if (event
->xcolormap
.state
== ColormapUninstalled
&&
1254 scr
->current_colormap
== event
->xcolormap
.colormap
) {
1256 /* some bastard app (like XV) removed our colormap */
1258 * can't enforce or things like xscreensaver wont work
1261 } else if (event
->xcolormap
.state
== ColormapInstalled
&&
1262 scr
->current_colormap
== event
->xcolormap
.colormap
) {
1264 /* someone has put our colormap back */
1268 } while (XCheckTypedEvent(dpy
, ColormapNotify
, event
)
1269 && ((wwin
= wWindowFor(event
->xcolormap
.window
)) || 1));
1271 if (reinstall
&& scr
->current_colormap
!=None
) {
1272 if (!scr
->flags
.colormap_stuff_blocked
)
1273 XInstallColormap(dpy
, scr
->current_colormap
);
1280 handleFocusIn(XEvent
*event
)
1285 * For applications that like stealing the focus.
1287 while (XCheckTypedEvent(dpy
, FocusIn
, event
));
1288 saveTimestamp(event
);
1289 if (event
->xfocus
.mode
== NotifyUngrab
1290 || event
->xfocus
.mode
== NotifyGrab
1291 || event
->xfocus
.detail
> NotifyNonlinearVirtual
) {
1295 wwin
= wWindowFor(event
->xfocus
.window
);
1296 if (wwin
&& !wwin
->flags
.focused
) {
1297 if (wwin
->flags
.mapped
)
1298 wSetFocusTo(wwin
->screen_ptr
, wwin
);
1300 wSetFocusTo(wwin
->screen_ptr
, NULL
);
1302 WScreen
*scr
= wScreenForWindow(event
->xfocus
.window
);
1304 wSetFocusTo(scr
, NULL
);
1310 windowUnderPointer(WScreen
*scr
)
1316 if (XQueryPointer(dpy
, scr
->root_win
, &bar
, &win
, &foo
, &foo
, &foo
, &foo
,
1318 return wWindowFor(win
);
1323 static int CheckFullScreenWindowFocused(WScreen
*scr
)
1325 if (scr
->focused_window
&& scr
->focused_window
->flags
.fullscreen
)
1333 handleKeyPress(XEvent
*event
)
1335 WScreen
*scr
= wScreenForRootWindow(event
->xkey
.root
);
1336 WWindow
*wwin
= scr
->focused_window
;
1339 int command
=-1, index
;
1340 #ifdef KEEP_XKB_LOCK_STATUS
1341 XkbStateRec staterec
;
1342 #endif /*KEEP_XKB_LOCK_STATUS*/
1344 /* ignore CapsLock */
1345 modifiers
= event
->xkey
.state
& ValidModMask
;
1347 for (i
=0; i
<WKBD_LAST
; i
++) {
1348 if (wKeyBindings
[i
].keycode
==0)
1351 if (wKeyBindings
[i
].keycode
==event
->xkey
.keycode
1352 && (/*wKeyBindings[i].modifier==0
1353 ||*/ wKeyBindings
[i
].modifier
==modifiers
)) {
1367 if (!wRootMenuPerformShortcut(event
)) {
1369 static int dontLoop
= 0;
1371 if (dontLoop
> 10) {
1372 wwarning("problem with key event processing code");
1376 /* if the focused window is an internal window, try redispatching
1377 * the event to the managed window, as it can be a WINGs window */
1378 if (wwin
&& wwin
->flags
.internal_window
1379 && wwin
->client_leader
!=None
) {
1380 /* client_leader contains the WINGs toplevel */
1381 event
->xany
.window
= wwin
->client_leader
;
1382 WMHandleEvent(event
);
1389 #define ISMAPPED(w) ((w) && !(w)->flags.miniaturized && ((w)->flags.mapped || (w)->flags.shaded))
1390 #define ISFOCUSED(w) ((w) && (w)->flags.focused)
1395 /*OpenRootMenu(scr, event->xkey.x_root, event->xkey.y_root, True);*/
1396 if (!CheckFullScreenWindowFocused(scr
)) {
1397 WMRect rect
= wGetRectForHead(scr
, wGetHeadForPointerLocation(scr
));
1398 OpenRootMenu(scr
, rect
.pos
.x
+ rect
.size
.width
/2, rect
.pos
.y
+ rect
.size
.height
/2, True
);
1401 case WKBD_WINDOWLIST
:
1402 if (!CheckFullScreenWindowFocused(scr
)) {
1403 WMRect rect
= wGetRectForHead(scr
, wGetHeadForPointerLocation(scr
));
1404 OpenSwitchMenu(scr
, rect
.pos
.x
+ rect
.size
.width
/2, rect
.pos
.y
+ rect
.size
.height
/2, True
);
1408 case WKBD_WINDOWMENU
:
1409 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
))
1410 OpenWindowMenu(wwin
, wwin
->frame_x
,
1411 wwin
->frame_y
+wwin
->frame
->top_width
, True
);
1413 case WKBD_MINIATURIZE
:
1414 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)
1415 && !WFLAGP(wwin
, no_miniaturizable
)) {
1416 CloseWindowMenu(scr
);
1418 if (wwin
->protocols
.MINIATURIZE_WINDOW
)
1419 wClientSendProtocol(wwin
, _XA_GNUSTEP_WM_MINIATURIZE_WINDOW
,
1420 event
->xbutton
.time
);
1422 wIconifyWindow(wwin
);
1427 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1428 WApplication
*wapp
= wApplicationOf(wwin
->main_window
);
1429 CloseWindowMenu(scr
);
1431 if (wapp
&& !WFLAGP(wapp
->main_window_desc
, no_appicon
)) {
1432 wHideApplication(wapp
);
1436 case WKBD_HIDE_OTHERS
:
1437 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1438 CloseWindowMenu(scr
);
1440 wHideOtherApplications(wwin
);
1444 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
) && IS_RESIZABLE(wwin
)) {
1445 int newdir
= (MAX_VERTICAL
|MAX_HORIZONTAL
);
1447 CloseWindowMenu(scr
);
1449 if (wwin
->flags
.maximized
== newdir
) {
1450 wUnmaximizeWindow(wwin
);
1452 wMaximizeWindow(wwin
, newdir
|MAX_KEYBOARD
);
1456 case WKBD_VMAXIMIZE
:
1457 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
) && IS_RESIZABLE(wwin
)) {
1458 int newdir
= (MAX_VERTICAL
^ wwin
->flags
.maximized
);
1460 CloseWindowMenu(scr
);
1463 wMaximizeWindow(wwin
, newdir
|MAX_KEYBOARD
);
1465 wUnmaximizeWindow(wwin
);
1469 case WKBD_HMAXIMIZE
:
1470 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
) && IS_RESIZABLE(wwin
)) {
1471 int newdir
= (MAX_HORIZONTAL
^ wwin
->flags
.maximized
);
1473 CloseWindowMenu(scr
);
1476 wMaximizeWindow(wwin
, newdir
|MAX_KEYBOARD
);
1478 wUnmaximizeWindow(wwin
);
1483 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1484 CloseWindowMenu(scr
);
1486 wRaiseFrame(wwin
->frame
->core
);
1490 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1491 CloseWindowMenu(scr
);
1493 wLowerFrame(wwin
->frame
->core
);
1496 case WKBD_RAISELOWER
:
1497 /* raise or lower the window under the pointer, not the
1500 wwin
= windowUnderPointer(scr
);
1502 wRaiseLowerFrame(wwin
->frame
->core
);
1505 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
) && !WFLAGP(wwin
, no_shadeable
)) {
1506 if (wwin
->flags
.shaded
)
1507 wUnshadeWindow(wwin
);
1512 case WKBD_MOVERESIZE
:
1513 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
) &&
1514 (IS_RESIZABLE(wwin
) || IS_MOVABLE(wwin
))) {
1515 CloseWindowMenu(scr
);
1517 wKeyboardMoveResizeWindow(wwin
);
1521 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
) && !WFLAGP(wwin
, no_closable
)) {
1522 CloseWindowMenu(scr
);
1523 if (wwin
->protocols
.DELETE_WINDOW
)
1524 wClientSendProtocol(wwin
, _XA_WM_DELETE_WINDOW
,
1529 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1530 wSelectWindow(wwin
, !wwin
->flags
.selected
);
1533 case WKBD_FOCUSNEXT
:
1534 StartWindozeCycle(wwin
, event
, True
);
1537 case WKBD_FOCUSPREV
:
1538 StartWindozeCycle(wwin
, event
, False
);
1541 #if (defined(__STDC__) && !defined(UNIXCPP)) || defined(ANSICPP)
1542 #define GOTOWORKS(wk) case WKBD_WORKSPACE##wk:\
1543 i = (scr->current_workspace/10)*10 + wk - 1;\
1544 if (wPreferences.ws_advance || i<scr->workspace_count)\
1545 wWorkspaceChange(scr, i);\
1548 #define GOTOWORKS(wk) case WKBD_WORKSPACE/**/wk:\
1549 i = (scr->current_workspace/10)*10 + wk - 1;\
1550 if (wPreferences.ws_advance || i<scr->workspace_count)\
1551 wWorkspaceChange(scr, i);\
1565 case WKBD_NEXTWORKSPACE
:
1566 wWorkspaceRelativeChange(scr
, 1);
1568 case WKBD_PREVWORKSPACE
:
1569 wWorkspaceRelativeChange(scr
, -1);
1582 index
= command
-WKBD_WINDOW1
;
1584 if (scr
->shortcutWindows
[index
]) {
1585 WMArray
*list
= scr
->shortcutWindows
[index
];
1587 int count
= WMGetArrayItemCount(list
);
1589 WMArrayIterator iter
;
1592 wUnselectWindows(scr
);
1593 cw
= scr
->current_workspace
;
1595 WM_ETARETI_ARRAY(list
, wwin
, iter
) {
1597 wWindowChangeWorkspace(wwin
, cw
);
1599 wMakeWindowVisible(wwin
);
1602 wSelectWindow(wwin
, True
);
1605 /* rotate the order of windows, to create a cycling effect */
1606 twin
= WMGetFromArray(list
, 0);
1607 WMDeleteFromArray(list
, 0);
1608 WMAddToArray(list
, twin
);
1610 } else if (wwin
&& ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1611 if (scr
->shortcutWindows
[index
]) {
1612 WMFreeArray(scr
->shortcutWindows
[index
]);
1613 scr
->shortcutWindows
[index
] = NULL
;
1616 if (wwin
->flags
.selected
&& scr
->selected_windows
) {
1617 scr
->shortcutWindows
[index
] =
1618 WMDuplicateArray(scr
->selected_windows
);
1619 /*WMRemoveFromArray(scr->shortcutWindows[index], wwin);
1620 WMInsertInArray(scr->shortcutWindows[index], 0, wwin);*/
1622 scr
->shortcutWindows
[index
] = WMCreateArray(4);
1623 WMAddToArray(scr
->shortcutWindows
[index
], wwin
);
1626 wSelectWindow(wwin
, !wwin
->flags
.selected
);
1629 wSelectWindow(wwin
, !wwin
->flags
.selected
);
1632 } else if (scr
->selected_windows
1633 && WMGetArrayItemCount(scr
->selected_windows
)) {
1635 if (wwin
->flags
.selected
&& scr
->selected_windows
) {
1636 if (scr
->shortcutWindows
[index
]) {
1637 WMFreeArray(scr
->shortcutWindows
[index
]);
1639 scr
->shortcutWindows
[index
] =
1640 WMDuplicateArray(scr
->selected_windows
);
1646 case WKBD_SWITCH_SCREEN
:
1647 if (wScreenCount
> 1) {
1651 /* find index of this screen */
1652 for (i
= 0; i
< wScreenCount
; i
++) {
1653 if (wScreenWithNumber(i
) == scr
)
1657 if (i
>= wScreenCount
) {
1660 scr2
= wScreenWithNumber(i
);
1663 XWarpPointer(dpy
, scr
->root_win
, scr2
->root_win
, 0, 0, 0, 0,
1664 scr2
->scr_width
/2, scr2
->scr_height
/2);
1669 case WKBD_NEXTWSLAYER
:
1670 case WKBD_PREVWSLAYER
:
1674 row
= scr
->current_workspace
/10;
1675 column
= scr
->current_workspace
%10;
1677 if (command
==WKBD_NEXTWSLAYER
) {
1678 if ((row
+1)*10 < scr
->workspace_count
)
1679 wWorkspaceChange(scr
, column
+(row
+1)*10);
1682 wWorkspaceChange(scr
, column
+(row
-1)*10);
1686 case WKBD_CLIPLOWER
:
1687 if (!wPreferences
.flags
.noclip
)
1688 wDockLower(scr
->workspaces
[scr
->current_workspace
]->clip
);
1690 case WKBD_CLIPRAISE
:
1691 if (!wPreferences
.flags
.noclip
)
1692 wDockRaise(scr
->workspaces
[scr
->current_workspace
]->clip
);
1694 case WKBD_CLIPRAISELOWER
:
1695 if (!wPreferences
.flags
.noclip
)
1696 wDockRaiseLower(scr
->workspaces
[scr
->current_workspace
]->clip
);
1698 #ifdef KEEP_XKB_LOCK_STATUS
1700 if(wPreferences
.modelock
) {
1702 wwin
= scr
->focused_window
;
1704 if (wwin
&& wwin
->flags
.mapped
1705 && wwin
->frame
->workspace
== wwin
->screen_ptr
->current_workspace
1706 && !wwin
->flags
.miniaturized
&& !wwin
->flags
.hidden
) {
1707 XkbGetState(dpy
,XkbUseCoreKbd
,&staterec
);
1709 wwin
->frame
->languagemode
= wwin
->frame
->last_languagemode
;
1710 wwin
->frame
->last_languagemode
= staterec
.group
;
1711 XkbLockGroup(dpy
,XkbUseCoreKbd
, wwin
->frame
->languagemode
);
1716 #endif /* KEEP_XKB_LOCK_STATUS */
1717 #ifdef VIRTUAL_DESKTOP
1718 case WKBD_VDESK_LEFT
:
1719 wWorkspaceKeyboardMoveDesktop(scr
, VEC_LEFT
);
1722 case WKBD_VDESK_RIGHT
:
1723 wWorkspaceKeyboardMoveDesktop(scr
, VEC_RIGHT
);
1727 wWorkspaceKeyboardMoveDesktop(scr
, VEC_UP
);
1730 case WKBD_VDESK_DOWN
:
1731 wWorkspaceKeyboardMoveDesktop(scr
, VEC_DOWN
);
1740 handleMotionNotify(XEvent
*event
)
1742 WScreen
*scr
= wScreenForRootWindow(event
->xmotion
.root
);
1744 if (wPreferences
.scrollable_menus
) {
1745 WMPoint p
= wmkpoint(event
->xmotion
.x_root
, event
->xmotion
.y_root
);
1746 WMRect rect
= wGetRectForHead(scr
, wGetHeadForPoint(scr
, p
));
1748 if (scr
->flags
.jump_back_pending
||
1749 p
.x
<= (rect
.pos
.x
+ 1) ||
1750 p
.x
>= (rect
.pos
.x
+ rect
.size
.width
- 2) ||
1751 p
.y
<= (rect
.pos
.y
+ 1) ||
1752 p
.y
>= (rect
.pos
.y
+ rect
.size
.height
- 2)) {
1755 printf("pointer at screen edge\n");
1757 menu
= wMenuUnderPointer(scr
);
1759 wMenuScroll(menu
, event
);
1766 handleVisibilityNotify(XEvent
*event
)
1770 wwin
= wWindowFor(event
->xvisibility
.window
);
1773 wwin
->flags
.obscured
=
1774 (event
->xvisibility
.state
== VisibilityFullyObscured
);