1 /* event.c- event loop and handling
3 * Window Maker window manager
5 * Copyright (c) 1997, 1998 Alfredo K. Kojima
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
33 #include <X11/Xutil.h>
35 #include <X11/extensions/shape.h>
38 #include <X11/Xatom.h>
42 #ifdef KEEP_XKB_LOCK_STATUS
43 #include <X11/XKBlib.h>
44 #endif /* KEEP_XKB_LOCK_STATUS */
46 #include "WindowMaker.h"
52 #include "application.h"
55 #include "workspace.h"
58 #include "properties.h"
62 /******** Global Variables **********/
63 extern XContext wWinContext
;
65 extern Cursor wCursor
[WCUR_LAST
];
67 extern WShortKey wKeyBindings
[WKBD_LAST
];
68 extern int wScreenCount
;
69 extern Time LastTimestamp
;
70 extern Time LastFocusChange
;
72 extern WPreferences wPreferences
;
74 #define MOD_MASK wPreferences.modifier_mask
76 extern Atom _XA_WM_COLORMAP_NOTIFY
;
78 extern Atom _XA_WM_CHANGE_STATE
;
79 extern Atom _XA_WM_DELETE_WINDOW
;
80 extern Atom _XA_GNUSTEP_WM_MINIATURIZE_WINDOW
;
81 extern Atom _XA_WINDOWMAKER_WM_FUNCTION
;
84 extern Atom _XA_DND_PROTOCOL
;
87 extern Atom _XA_XDE_REQUEST
;
88 extern Atom _XA_XDE_ENTER
;
89 extern Atom _XA_XDE_LEAVE
;
90 extern Atom _XA_XDE_DATA_AVAILABLE
;
91 extern Atom _XDE_FILETYPE
;
92 extern Atom _XDE_URLTYPE
;
97 extern Bool wShapeSupported
;
98 extern int wShapeEventBase
;
102 extern char WProgramState
;
103 extern char WDelayedActionSet
;
106 /************ Local stuff ***********/
109 static void saveTimestamp(XEvent
*event
);
110 static void handleColormapNotify();
111 static void handleMapNotify(), handleUnmapNotify();
112 static void handleButtonPress(), handleExpose();
113 static void handleDestroyNotify();
114 static void handleConfigureRequest();
115 static void handleMapRequest();
116 static void handlePropertyNotify();
117 static void handleEnterNotify();
118 static void handleLeaveNotify();
119 static void handleExtensions();
120 static void handleClientMessage();
121 static void handleKeyPress();
122 static void handleFocusIn();
123 static void handleMotionNotify();
126 static void handleShapeNotify();
129 /* called from the signal handler */
130 void NotifyDeadProcess(pid_t pid
, unsigned char status
);
132 /* real dead process handler */
133 static void handleDeadProcess(void *foo
);
136 typedef struct DeadProcesses
{
138 unsigned char exit_status
;
141 /* stack of dead processes */
142 static DeadProcesses deadProcesses
[MAX_DEAD_PROCESSES
];
143 static int deadProcessPtr
=0;
146 typedef struct DeathHandler
{
147 WDeathHandler
*callback
;
149 struct DeathHandler
*next
;
153 static DeathHandler
*deathHandler
=NULL
;
158 wAddDeathHandler(pid_t pid
, WDeathHandler
*callback
, void *cdata
)
160 DeathHandler
*handler
;
162 handler
= malloc(sizeof(DeathHandler
));
167 handler
->callback
= callback
;
168 handler
->client_data
= cdata
;
170 handler
->next
= deathHandler
;
172 deathHandler
= handler
;
180 wDeleteDeathHandler(WMagicNumber id
)
182 DeathHandler
*tmp
, *handler
=(DeathHandler
*)id
;
184 if (!handler
|| !deathHandler
)
189 deathHandler
= handler
->next
;
193 if (tmp
->next
==handler
) {
194 tmp
->next
=handler
->next
;
205 DispatchEvent(XEvent
*event
)
210 handleDeadProcess(NULL
);
212 if (WProgramState
==WSTATE_NEED_EXIT
) {
213 WProgramState
= WSTATE_EXITING
;
216 * WMHandleEvent() can't be called from anything
217 * executed inside here, or we can get in a infinite
220 for (i
=0; i
<wScreenCount
; i
++) {
222 scr
= wScreenWithNumber(i
);
224 wScreenSaveState(scr
);
229 /* received SIGTERM */
231 } else if (WProgramState
== WSTATE_NEED_RESTART
) {
232 WProgramState
= WSTATE_RESTARTING
;
234 for (i
=0; i
<wScreenCount
; i
++) {
236 scr
= wScreenWithNumber(i
);
238 wScreenSaveState(scr
);
242 /* received SIGHUP */
246 /* for the case that all that is wanted to be dispatched is
251 saveTimestamp(event
);
252 switch (event
->type
) {
254 handleMapRequest(event
);
258 handleKeyPress(event
);
262 handleMotionNotify(event
);
265 case ConfigureRequest
:
266 handleConfigureRequest(event
);
270 handleDestroyNotify(event
->xdestroywindow
.window
);
274 handleMapNotify(event
->xmap
.window
);
278 handleUnmapNotify(event
);
282 handleButtonPress(event
);
290 handlePropertyNotify(event
);
294 handleEnterNotify(event
);
298 handleLeaveNotify(event
);
302 handleClientMessage(event
);
306 handleColormapNotify(event
);
310 if (event
->xmapping
.request
== MappingKeyboard
311 || event
->xmapping
.request
== MappingModifier
)
312 XRefreshKeyboardMapping(&event
->xmapping
);
316 handleFocusIn(event
);
320 handleExtensions(event
);
326 *----------------------------------------------------------------------
328 * Processes X and internal events indefinitely.
334 * The LastTimestamp global variable is updated.
335 *----------------------------------------------------------------------
343 WMNextEvent(dpy
, &event
);
344 WMHandleEvent(&event
);
351 IsDoubleClick(WScreen
*scr
, XEvent
*event
)
353 if ((scr
->last_click_time
>0) &&
354 (event
->xbutton
.time
-scr
->last_click_time
<=wPreferences
.dblclick_time
)
355 && (event
->xbutton
.button
== scr
->last_click_button
)
356 && (event
->xbutton
.window
== scr
->last_click_window
)) {
358 scr
->flags
.next_click_is_not_double
= 1;
359 scr
->last_click_time
= 0;
360 scr
->last_click_window
= None
;
369 NotifyDeadProcess(pid_t pid
, unsigned char status
)
371 if (deadProcessPtr
>=MAX_DEAD_PROCESSES
-1) {
372 wwarning(_("stack overflow: too many dead processes"));
375 /* stack the process to be handled later,
376 * as this is called from the signal handler */
377 deadProcesses
[deadProcessPtr
].pid
= pid
;
378 deadProcesses
[deadProcessPtr
].exit_status
= status
;
384 handleDeadProcess(void *foo
)
389 for (i
=0; i
<deadProcessPtr
; i
++) {
390 wWindowDeleteSavedStatesForPID(deadProcesses
[i
].pid
);
398 /* get the pids on the queue and call handlers */
399 while (deadProcessPtr
>0) {
408 if (tmp
->pid
== deadProcesses
[deadProcessPtr
].pid
) {
409 (*tmp
->callback
)(tmp
->pid
,
410 deadProcesses
[deadProcessPtr
].exit_status
,
412 wDeleteDeathHandler(tmp
);
421 saveTimestamp(XEvent
*event
)
423 LastTimestamp
= CurrentTime
;
425 switch (event
->type
) {
428 LastTimestamp
= event
->xbutton
.time
;
432 LastTimestamp
= event
->xkey
.time
;
435 LastTimestamp
= event
->xmotion
.time
;
438 LastTimestamp
= event
->xproperty
.time
;
442 LastTimestamp
= event
->xcrossing
.time
;
445 LastTimestamp
= event
->xselectionclear
.time
;
447 case SelectionRequest
:
448 LastTimestamp
= event
->xselectionrequest
.time
;
450 case SelectionNotify
:
451 LastTimestamp
= event
->xselection
.time
;
458 handleExtensions(XEvent
*event
)
461 if (wShapeSupported
&& event
->type
== (wShapeEventBase
+ShapeNotify
)) {
462 handleShapeNotify(event
);
468 handleMapRequest(XEvent
*ev
)
472 Window window
= ev
->xmaprequest
.window
;
475 printf("got map request for %x\n", (unsigned)window
);
478 if ((wwin
=wWindowFor(window
))) {
479 /* deiconify window */
480 if (wwin
->flags
.shaded
)
481 wUnshadeWindow(wwin
);
482 if (wwin
->flags
.miniaturized
) {
483 wDeiconifyWindow(wwin
);
484 } else if (wwin
->flags
.hidden
) {
485 WApplication
*wapp
= wApplicationOf(wwin
->main_window
);
486 /* go to the last workspace that the user worked on the app */
487 #ifndef REDUCE_APPICONS
488 /* This severely breaks REDUCE_APPICONS. last_workspace is a neat
489 * concept but it needs to be reworked to handle REDUCE_APPICONS -cls
492 wWorkspaceChange(wwin
->screen_ptr
, wapp
->last_workspace
);
495 wUnhideApplication(wapp
, False
, False
);
500 scr
= wScreenForRootWindow(ev
->xmaprequest
.parent
);
502 wwin
= wManageWindow(scr
, window
);
505 * This is to let the Dock know that the application it launched
506 * has already been mapped (eg: it has finished launching).
507 * It is not necessary for normally docked apps, but is needed for
508 * apps that were forcedly docked (like with dockit).
510 if (scr
->last_dock
) {
511 if (wwin
&& wwin
->main_window
!=None
&& wwin
->main_window
!=window
)
512 wDockTrackWindowLaunch(scr
->last_dock
, wwin
->main_window
);
514 wDockTrackWindowLaunch(scr
->last_dock
, window
);
520 if (wwin
->wm_hints
&& (wwin
->wm_hints
->flags
& StateHint
))
521 state
= wwin
->wm_hints
->initial_state
;
525 if (state
==IconicState
)
526 wwin
->flags
.miniaturized
= 1;
528 if (state
==WithdrawnState
) {
529 wwin
->flags
.mapped
= 0;
530 wClientSetState(wwin
, WithdrawnState
, None
);
531 wUnmanageWindow(wwin
, True
);
533 wClientSetState(wwin
, NormalState
, None
);
534 if (wwin
->flags
.shaded
) {
535 wwin
->flags
.shaded
= 0;
536 wwin
->flags
.skip_next_animation
= 1;
537 wwin
->flags
.ignore_next_unmap
= 1; /* ??? */
540 if (wwin
->flags
.miniaturized
) {
541 wwin
->flags
.miniaturized
= 0;
542 wwin
->flags
.hidden
= 0;
543 wwin
->flags
.skip_next_animation
= 1;
544 wwin
->flags
.ignore_next_unmap
= 1;
545 wIconifyWindow(wwin
);
546 } else if (wwin
->flags
.hidden
) {
547 WApplication
*wapp
= wApplicationOf(wwin
->main_window
);
548 wwin
->flags
.hidden
= 0;
549 wwin
->flags
.skip_next_animation
= 1;
551 wHideApplication(wapp
);
553 wwin
->flags
.ignore_next_unmap
= 1;
561 handleDestroyNotify(Window window
)
566 puts("got destroy notify");
569 wwin
= wWindowFor(window
);
571 wUnmanageWindow(wwin
, False
);
574 app
= wApplicationOf(window
);
576 if (window
== app
->main_window
) {
578 wwin
= app
->main_window_desc
->screen_ptr
->focused_window
;
580 if (wwin
->main_window
== window
) {
581 wwin
->main_window
= None
;
586 wApplicationDestroy(app
);
593 handleExpose(XEvent
*event
)
595 WObjDescriptor
*desc
;
600 if (event
->xexpose
.count
!=0) {
604 if (XFindContext(dpy
, event
->xexpose
.window
, wWinContext
,
605 (XPointer
*)&desc
)==XCNOENT
) {
609 if (desc
->handle_expose
) {
610 (*desc
->handle_expose
)(desc
, event
);
617 handleButtonPress(XEvent
*event
)
619 WObjDescriptor
*desc
;
623 puts("got button press");
626 scr
= wScreenForRootWindow(event
->xbutton
.root
);
632 if (event
->xbutton
.window
==scr
->root_win
) {
633 if (event
->xbutton
.button
==wPreferences
.menu_button
) {
634 OpenRootMenu(scr
, event
->xbutton
.x_root
,
635 event
->xbutton
.y_root
, False
);
637 if (scr
->root_menu
) {
638 if (scr
->root_menu
->brother
->flags
.mapped
)
639 event
->xbutton
.window
= scr
->root_menu
->brother
->frame
->core
->window
;
641 event
->xbutton
.window
= scr
->root_menu
->frame
->core
->window
;
643 } else if (event
->xbutton
.button
==wPreferences
.windowl_button
) {
645 OpenSwitchMenu(scr
, event
->xbutton
.x_root
,
646 event
->xbutton
.y_root
, False
);
647 if (scr
->switch_menu
) {
648 if (scr
->switch_menu
->brother
->flags
.mapped
)
649 event
->xbutton
.window
= scr
->switch_menu
->brother
->frame
->core
->window
;
651 event
->xbutton
.window
= scr
->switch_menu
->frame
->core
->window
;
653 } else if (event
->xbutton
.button
==wPreferences
.select_button
) {
655 wUnselectWindows(scr
);
656 wSelectWindows(scr
, event
);
661 if (XFindContext(dpy
, event
->xbutton
.window
, wWinContext
,
662 (XPointer
*)&desc
)==XCNOENT
) {
666 if (desc
->parent_type
== WCLASS_WINDOW
) {
669 if (event
->xbutton
.state
& MOD_MASK
) {
670 XAllowEvents(dpy
, AsyncPointer
, CurrentTime
);
673 if (wPreferences
.focus_mode
== WKF_CLICK
) {
674 if (wPreferences
.ignore_focus_click
) {
675 XAllowEvents(dpy
, AsyncPointer
, CurrentTime
);
677 XAllowEvents(dpy
, ReplayPointer
, CurrentTime
);
680 } else if (desc
->parent_type
== WCLASS_APPICON
681 || desc
->parent_type
== WCLASS_MINIWINDOW
682 || desc
->parent_type
== WCLASS_DOCK_ICON
) {
683 if (event
->xbutton
.state
& MOD_MASK
) {
685 XAllowEvents(dpy
, AsyncPointer
, CurrentTime
);
690 if (desc
->handle_mousedown
!=NULL
) {
691 (*desc
->handle_mousedown
)(desc
, event
);
694 /* save double-click information */
695 if (scr
->flags
.next_click_is_not_double
) {
696 scr
->flags
.next_click_is_not_double
= 0;
698 scr
->last_click_time
= event
->xbutton
.time
;
699 scr
->last_click_button
= event
->xbutton
.button
;
700 scr
->last_click_window
= event
->xbutton
.window
;
706 handleMapNotify(Window window
)
713 wwin
= wWindowFor(window
);
714 if (wwin
&& wwin
->client_win
==window
) {
715 if (wwin
->flags
.ignore_next_unmap
) {
716 wwin
->flags
.ignore_next_unmap
=0;
719 if (wwin
->flags
.miniaturized
) {
720 wDeiconifyWindow(wwin
);
724 XMapWindow(dpy
, wwin
->client_win
);
725 XMapWindow(dpy
, wwin
->frame
->core
->window
);
726 wwin
->flags
.mapped
=1;
727 wClientSetState(wwin
, NormalState
, None
);
735 handleUnmapNotify(XEvent
*event
)
743 wwin
= wWindowFor(event
->xunmap
.window
);
744 if (!wwin
|| wwin
->client_win
!=event
->xunmap
.window
)
747 if (!wwin
->flags
.mapped
748 && wwin
->frame
->workspace
==wwin
->screen_ptr
->current_workspace
749 && !wwin
->flags
.miniaturized
&& !wwin
->flags
.hidden
)
752 if (wwin
->flags
.ignore_next_unmap
) {
756 XUnmapWindow(dpy
, wwin
->frame
->core
->window
);
757 wwin
->flags
.mapped
= 0;
759 /* check if the window was destroyed */
760 if (XCheckTypedWindowEvent(dpy
, wwin
->client_win
, DestroyNotify
,&ev
)) {
763 Bool reparented
= False
;
765 if (XCheckTypedWindowEvent(dpy
, wwin
->client_win
, ReparentNotify
, &ev
))
768 /* withdraw window */
769 wwin
->flags
.mapped
= 0;
771 wClientSetState(wwin
, WithdrawnState
, None
);
773 /* if the window was reparented, do not reparent it back to the
775 wUnmanageWindow(wwin
, !reparented
);
782 handleConfigureRequest(XEvent
*event
)
787 puts("got configure request");
789 if (!(wwin
=wWindowFor(event
->xconfigurerequest
.window
))) {
791 * Configure request for unmapped window
793 wClientConfigure(NULL
, &(event
->xconfigurerequest
));
795 wClientConfigure(wwin
, &(event
->xconfigurerequest
));
801 handlePropertyNotify(XEvent
*event
)
810 puts("got property notify");
812 if ((wwin
=wWindowFor(event
->xproperty
.window
))) {
813 if (!XGetGeometry(dpy
, wwin
->client_win
, &jr
, &ji
, &ji
,
814 &ju
, &ju
, &ju
, &ju
)) {
817 wClientCheckProperty(wwin
, &event
->xproperty
);
819 wapp
= wApplicationOf(event
->xproperty
.window
);
821 wClientCheckProperty(wapp
->main_window_desc
, &event
->xproperty
);
827 handleClientMessage(XEvent
*event
)
830 WObjDescriptor
*desc
;
833 puts("got client message");
835 /* handle transition from Normal to Iconic state */
836 if (event
->xclient
.message_type
== _XA_WM_CHANGE_STATE
837 && event
->xclient
.format
== 32
838 && event
->xclient
.data
.l
[0] == IconicState
) {
840 wwin
= wWindowFor(event
->xclient
.window
);
842 if (!wwin
->flags
.miniaturized
)
843 wIconifyWindow(wwin
);
844 } else if (event
->xclient
.message_type
== _XA_WM_COLORMAP_NOTIFY
845 && event
->xclient
.format
== 32) {
846 WScreen
*scr
= wScreenForRootWindow(event
->xclient
.window
);
851 if (event
->xclient
.data
.l
[1] == 1) { /* starting */
852 wColormapAllowClientInstallation(scr
, True
);
853 } else { /* stopping */
854 wColormapAllowClientInstallation(scr
, False
);
856 } else if (event
->xclient
.message_type
== _XA_WINDOWMAKER_WM_FUNCTION
) {
859 wapp
= wApplicationOf(event
->xclient
.window
);
861 switch (event
->xclient
.data
.l
[0]) {
862 case WMFHideOtherApplications
:
863 wHideOtherApplications(wapp
->main_window_desc
);
867 case WMFHideApplication
:
868 wHideApplication(wapp
);
874 wwin
= wWindowFor(event
->xclient
.window
);
876 switch (event
->xclient
.data
.l
[0]) {
877 case WMFHideOtherApplications
:
878 wHideOtherApplications(wwin
);
881 case WMFHideApplication
:
882 wHideApplication(wApplicationOf(wwin
->main_window
));
888 } else if (event
->xclient
.message_type
==_XA_XDE_DATA_AVAILABLE
) {
890 WScreen
*scr
= wScreenForWindow(event
->xclient
.window
);
894 char * tmpstr
, * runstr
, * freestr
, * tofreestr
;
896 gdkev
.dropdataavailable
.u
.allflags
= event
->xclient
.data
.l
[1];
897 gdkev
.dropdataavailable
.timestamp
= event
->xclient
.data
.l
[4];
899 if(gdkev
.dropdataavailable
.u
.flags
.isdrop
){
900 gdkev
.dropdataavailable
.type
= GDK_DROP_DATA_AVAIL
;
901 gdkev
.dropdataavailable
.requestor
= event
->xclient
.data
.l
[0];
902 XGetWindowProperty(dpy
,gdkev
.dropdataavailable
.requestor
,
903 event
->xclient
.data
.l
[2],
905 0, XA_PRIMARY
, &tmpatom
,
907 &gdkev
.dropdataavailable
.data_numbytes
,
910 datalenght
=gdkev
.dropdataavailable
.data_numbytes
-1;
913 for(;datalenght
>0;datalenght
-=(strlen(tmpstr
)+1),tmpstr
=&tmpstr
[strlen(tmpstr
)+1]){
914 freestr
=runstr
;runstr
=wstrappend(runstr
,tmpstr
);free(freestr
);
915 freestr
=runstr
;runstr
=wstrappend(runstr
," ");free(freestr
);
918 scr
->xdestring
=runstr
;
919 /* no need to redirect ? */
920 wDockReceiveDNDDrop(scr
,event
);
925 } else if (event
->xclient
.message_type
==_XA_XDE_LEAVE
) {
927 } else if (event
->xclient
.message_type
==_XA_XDE_ENTER
) {
931 gdkev
.dropenter
.u
.allflags
=event
->xclient
.data
.l
[1];
932 printf("from win %x\n",event
->xclient
.data
.l
[0]);
933 printf("to win %x\n",event
->xclient
.window
);
934 printf("enter %x\n",event
->xclient
.data
.l
[1]);
935 printf("v %x ",event
->xclient
.data
.l
[2]);
936 printf("%x ",event
->xclient
.data
.l
[3]);
937 printf("%x\n",event
->xclient
.data
.l
[4]);
939 if(event
->xclient
.data
.l
[2]==_XDE_FILETYPE
||
940 event
->xclient
.data
.l
[3]==_XDE_FILETYPE
||
941 event
->xclient
.data
.l
[4]==_XDE_FILETYPE
||
942 event
->xclient
.data
.l
[2]==_XDE_URLTYPE
||
943 event
->xclient
.data
.l
[3]==_XDE_URLTYPE
||
944 event
->xclient
.data
.l
[4]==_XDE_URLTYPE
)
945 if(gdkev
.dropenter
.u
.flags
.sendreply
){
947 replyev
.xclient
.type
= ClientMessage
;
948 replyev
.xclient
.window
= event
->xclient
.data
.l
[0];
949 replyev
.xclient
.format
= 32;
950 replyev
.xclient
.message_type
= _XA_XDE_REQUEST
;
951 replyev
.xclient
.data
.l
[0] = event
->xclient
.window
;
953 gdkev
.dragrequest
.u
.allflags
= 0;
954 gdkev
.dragrequest
.u
.flags
.protocol_version
= 0;
955 gdkev
.dragrequest
.u
.flags
.willaccept
= 1;
956 gdkev
.dragrequest
.u
.flags
.delete_data
= 0;
958 replyev
.xclient
.data
.l
[1] = gdkev
.dragrequest
.u
.allflags
;
959 replyev
.xclient
.data
.l
[2] = replyev
.xclient
.data
.l
[3] = 0;
960 replyev
.xclient
.data
.l
[4] = event
->xclient
.data
.l
[2];
961 XSendEvent(dpy
, replyev
.xclient
.window
, 0, NoEventMask
, &replyev
);
966 } else if (event
->xclient
.message_type
==_XA_DND_PROTOCOL
) {
967 WScreen
*scr
= wScreenForWindow(event
->xclient
.window
);
968 if (scr
&& wDockReceiveDNDDrop(scr
,event
))
969 goto redirect_message
;
970 #endif /* OFFIX_DND */
976 * Non-standard thing, but needed by OffiX DND.
977 * For when the icon frame gets a ClientMessage
978 * that should have gone to the icon_window.
980 if (XFindContext(dpy
, event
->xbutton
.window
, wWinContext
,
981 (XPointer
*)&desc
)!=XCNOENT
) {
982 struct WIcon
*icon
=NULL
;
984 if (desc
->parent_type
== WCLASS_MINIWINDOW
) {
985 icon
= (WIcon
*)desc
->parent
;
986 } else if (desc
->parent_type
== WCLASS_DOCK_ICON
987 || desc
->parent_type
== WCLASS_APPICON
) {
988 icon
= ((WAppIcon
*)desc
->parent
)->icon
;
990 if (icon
&& (wwin
=icon
->owner
)) {
991 if (wwin
->client_win
!=event
->xclient
.window
) {
992 event
->xclient
.window
= wwin
->client_win
;
993 XSendEvent(dpy
, wwin
->client_win
, False
, NoEventMask
,
1003 raiseWindow(WScreen
*scr
)
1007 scr
->autoRaiseTimer
= NULL
;
1009 wwin
= wWindowFor(scr
->autoRaiseWindow
);
1013 if (!wwin
->flags
.destroyed
) {
1014 wRaiseFrame(wwin
->frame
->core
);
1015 /* this is needed or a race condition will occur */
1022 handleEnterNotify(XEvent
*event
)
1025 WObjDescriptor
*desc
= NULL
;
1027 WScreen
*scr
= wScreenForRootWindow(event
->xcrossing
.root
);
1031 puts("got enter notify");
1034 if (XCheckTypedWindowEvent(dpy
, event
->xcrossing
.window
, LeaveNotify
,
1036 /* already left the window... */
1038 if (ev
.xcrossing
.mode
==event
->xcrossing
.mode
1039 && ev
.xcrossing
.detail
==event
->xcrossing
.detail
) {
1044 if (XFindContext(dpy
, event
->xcrossing
.window
, wWinContext
,
1045 (XPointer
*)&desc
)!=XCNOENT
) {
1046 if(desc
->handle_enternotify
)
1047 (*desc
->handle_enternotify
)(desc
, event
);
1050 /* enter to window */
1051 wwin
= wWindowFor(event
->xcrossing
.window
);
1053 if (wPreferences
.focus_mode
==WKF_POINTER
1054 && event
->xcrossing
.window
==event
->xcrossing
.root
) {
1055 wSetFocusTo(scr
, NULL
);
1057 if (wPreferences
.colormap_mode
==WKF_POINTER
) {
1058 wColormapInstallForWindow(scr
, NULL
);
1060 if (scr
->autoRaiseTimer
1061 && event
->xcrossing
.root
==event
->xcrossing
.window
) {
1062 WMDeleteTimerHandler(scr
->autoRaiseTimer
);
1063 scr
->autoRaiseTimer
= NULL
;
1066 /* set focus if in focus-follows-mouse mode and the event
1067 * is for the frame window and window doesn't have focus yet */
1068 if ((wPreferences
.focus_mode
==WKF_POINTER
1069 || wPreferences
.focus_mode
==WKF_SLOPPY
)
1070 && wwin
->frame
->core
->window
==event
->xcrossing
.window
1071 && !wwin
->flags
.focused
) {
1072 wSetFocusTo(scr
, wwin
);
1074 if (scr
->autoRaiseTimer
)
1075 WMDeleteTimerHandler(scr
->autoRaiseTimer
);
1076 scr
->autoRaiseTimer
= NULL
;
1078 if (wPreferences
.raise_delay
&& !wwin
->window_flags
.no_focusable
) {
1079 scr
->autoRaiseWindow
= wwin
->frame
->core
->window
;
1081 = WMAddTimerHandler(wPreferences
.raise_delay
,
1082 (WMCallback
*)raiseWindow
, scr
);
1085 /* Install colormap for window, if the colormap installation mode
1086 * is colormap_follows_mouse */
1087 if (wPreferences
.colormap_mode
==WKF_POINTER
) {
1088 if (wwin
->client_win
==event
->xcrossing
.window
)
1089 wColormapInstallForWindow(scr
, wwin
);
1091 wColormapInstallForWindow(scr
, NULL
);
1095 /* a little kluge to hide the clip balloon */
1096 if (!wPreferences
.flags
.noclip
&& scr
->flags
.clip_balloon_mapped
) {
1098 XUnmapWindow(dpy
, scr
->clip_balloon
);
1099 scr
->flags
.clip_balloon_mapped
= 0;
1101 if (desc
->parent_type
!=WCLASS_DOCK_ICON
1102 || scr
->clip_icon
!= desc
->parent
) {
1103 XUnmapWindow(dpy
, scr
->clip_balloon
);
1104 scr
->flags
.clip_balloon_mapped
= 0;
1109 if (event
->xcrossing
.window
== event
->xcrossing
.root
1110 && event
->xcrossing
.detail
== NotifyNormal
1111 && event
->xcrossing
.detail
!= NotifyInferior
1112 && wPreferences
.focus_mode
!= WKF_CLICK
) {
1114 wSetFocusTo(scr
, scr
->focused_window
);
1118 wBalloonEnteredObject(scr
, desc
);
1124 handleLeaveNotify(XEvent
*event
)
1126 WObjDescriptor
*desc
= NULL
;
1128 if (XFindContext(dpy
, event
->xcrossing
.window
, wWinContext
,
1129 (XPointer
*)&desc
)!=XCNOENT
) {
1130 if(desc
->handle_leavenotify
)
1131 (*desc
->handle_leavenotify
)(desc
, event
);
1133 if (event
->xcrossing
.window
== event
->xcrossing
.root
1134 && event
->xcrossing
.mode
== NotifyNormal
1135 && event
->xcrossing
.detail
!= NotifyInferior
1136 && wPreferences
.focus_mode
!= WKF_CLICK
) {
1138 WScreen
*scr
= wScreenForRootWindow(event
->xcrossing
.root
);
1140 wSetFocusTo(scr
, NULL
);
1147 handleShapeNotify(XEvent
*event
)
1149 XShapeEvent
*shev
= (XShapeEvent
*)event
;
1154 puts("got shape notify");
1157 while (XCheckTypedWindowEvent(dpy
, shev
->window
, event
->type
, &ev
)) {
1158 XShapeEvent
*sev
= (XShapeEvent
*)&ev
;
1160 if (sev
->kind
== ShapeBounding
) {
1161 if (sev
->shaped
== shev
->shaped
) {
1164 XPutBackEvent(dpy
, &ev
);
1170 wwin
= wWindowFor(shev
->window
);
1171 if (!wwin
|| shev
->kind
!= ShapeBounding
)
1174 if (!shev
->shaped
&& wwin
->flags
.shaped
) {
1176 wwin
->flags
.shaped
= 0;
1177 wWindowClearShape(wwin
);
1179 } else if (shev
->shaped
) {
1181 wwin
->flags
.shaped
= 1;
1182 wWindowSetShape(wwin
);
1189 handleColormapNotify(XEvent
*event
)
1193 Bool reinstall
= False
;
1195 wwin
= wWindowFor(event
->xcolormap
.window
);
1199 scr
= wwin
->screen_ptr
;
1203 if (event
->xcolormap
.new) {
1204 XWindowAttributes attr
;
1206 XGetWindowAttributes(dpy
, wwin
->client_win
, &attr
);
1208 if (wwin
== scr
->cmap_window
&& wwin
->cmap_window_no
== 0)
1209 scr
->current_colormap
= attr
.colormap
;
1212 } else if (event
->xcolormap
.state
== ColormapUninstalled
&&
1213 scr
->current_colormap
== event
->xcolormap
.colormap
) {
1215 /* some bastard app (like XV) removed our colormap */
1217 } else if (event
->xcolormap
.state
== ColormapInstalled
&&
1218 scr
->current_colormap
== event
->xcolormap
.colormap
) {
1220 /* someone has put our colormap back */
1224 } while (XCheckTypedEvent(dpy
, ColormapNotify
, event
)
1225 && ((wwin
= wWindowFor(event
->xcolormap
.window
)) || 1));
1227 if (reinstall
&& scr
->current_colormap
!=None
) {
1228 if (!scr
->flags
.colormap_stuff_blocked
)
1229 XInstallColormap(dpy
, scr
->current_colormap
);
1236 handleFocusIn(XEvent
*event
)
1241 * For applications that like stealing the focus.
1243 while (XCheckTypedEvent(dpy
, FocusIn
, event
));
1244 saveTimestamp(event
);
1245 if (event
->xfocus
.mode
== NotifyUngrab
1246 || event
->xfocus
.mode
== NotifyGrab
1247 || event
->xfocus
.detail
> NotifyNonlinearVirtual
) {
1251 wwin
= wWindowFor(event
->xfocus
.window
);
1252 if (wwin
&& !wwin
->flags
.focused
) {
1253 if (wwin
->flags
.mapped
)
1254 wSetFocusTo(wwin
->screen_ptr
, wwin
);
1256 wSetFocusTo(wwin
->screen_ptr
, NULL
);
1258 WScreen
*scr
= wScreenForWindow(event
->xfocus
.window
);
1260 wSetFocusTo(scr
, NULL
);
1266 windowUnderPointer(WScreen
*scr
)
1272 if (XQueryPointer(dpy
, scr
->root_win
, &bar
, &win
, &foo
, &foo
, &foo
, &foo
,
1274 return wWindowFor(win
);
1279 handleKeyPress(XEvent
*event
)
1281 WScreen
*scr
= wScreenForRootWindow(event
->xkey
.root
);
1282 WWindow
*wwin
= scr
->focused_window
;
1286 #ifdef KEEP_XKB_LOCK_STATUS
1287 XkbStateRec staterec
;
1288 #endif /*KEEP_XKB_LOCK_STATUS*/
1290 /* ignore CapsLock */
1291 modifiers
= event
->xkey
.state
& ValidModMask
;
1293 for (i
=0; i
<WKBD_LAST
; i
++) {
1294 if (wKeyBindings
[i
].keycode
==0)
1297 if (wKeyBindings
[i
].keycode
==event
->xkey
.keycode
1298 && (/*wKeyBindings[i].modifier==0
1299 ||*/ wKeyBindings
[i
].modifier
==modifiers
)) {
1306 if (!wRootMenuPerformShortcut(event
)) {
1307 static int dontLoop
= 0;
1309 if (dontLoop
> 10) {
1310 wwarning("problem with key event processing code");
1314 /* if the focused window is an internal window, try redispatching
1315 * the event to the managed window, as it can be a WINGs window */
1316 if (wwin
&& wwin
->flags
.internal_window
1317 && wwin
->client_leader
!=None
) {
1318 /* client_leader contains the WINGs toplevel */
1319 event
->xany
.window
= wwin
->client_leader
;
1320 WMHandleEvent(event
);
1327 #define ISMAPPED(w) ((w) && !(w)->flags.miniaturized && ((w)->flags.mapped || (w)->flags.shaded))
1328 #define ISFOCUSED(w) ((w) && (w)->flags.focused)
1332 OpenRootMenu(scr
, event
->xkey
.x_root
, event
->xkey
.y_root
, True
);
1334 case WKBD_WINDOWMENU
:
1335 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
))
1336 OpenWindowMenu(wwin
, wwin
->frame_x
,
1337 wwin
->frame_y
+wwin
->frame
->top_width
, True
);
1339 case WKBD_WINDOWLIST
:
1340 OpenSwitchMenu(scr
, event
->xkey
.x_root
, event
->xkey
.y_root
, True
);
1342 case WKBD_MINIATURIZE
:
1343 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1344 CloseWindowMenu(scr
);
1346 if (wwin
->protocols
.MINIATURIZE_WINDOW
)
1347 wClientSendProtocol(wwin
, _XA_GNUSTEP_WM_MINIATURIZE_WINDOW
,
1348 event
->xbutton
.time
);
1350 if (!wwin
->window_flags
.no_miniaturizable
)
1351 wIconifyWindow(wwin
);
1356 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1357 WApplication
*wapp
= wApplicationOf(wwin
->main_window
);
1358 CloseWindowMenu(scr
);
1360 if (wapp
&& !wapp
->main_window_desc
->window_flags
.no_appicon
) {
1361 wHideApplication(wapp
);
1366 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)
1367 && !wwin
->window_flags
.no_resizable
) {
1368 CloseWindowMenu(scr
);
1370 if (wwin
->flags
.maximized
) {
1371 wUnmaximizeWindow(wwin
);
1373 wMaximizeWindow(wwin
, MAX_VERTICAL
|MAX_HORIZONTAL
);
1377 case WKBD_VMAXIMIZE
:
1378 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)
1379 && !wwin
->window_flags
.no_resizable
) {
1380 CloseWindowMenu(scr
);
1382 if (wwin
->flags
.maximized
) {
1383 wUnmaximizeWindow(wwin
);
1385 wMaximizeWindow(wwin
, MAX_VERTICAL
);
1390 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1391 CloseWindowMenu(scr
);
1393 wRaiseFrame(wwin
->frame
->core
);
1397 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1398 CloseWindowMenu(scr
);
1400 wLowerFrame(wwin
->frame
->core
);
1403 case WKBD_RAISELOWER
:
1404 /* raise or lower the window under the pointer, not the
1407 wwin
= windowUnderPointer(scr
);
1409 wRaiseLowerFrame(wwin
->frame
->core
);
1412 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)
1413 && !wwin
->window_flags
.no_shadeable
) {
1414 if (wwin
->flags
.shaded
)
1415 wUnshadeWindow(wwin
);
1421 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)
1422 && !wwin
->window_flags
.no_closable
) {
1423 CloseWindowMenu(scr
);
1424 if (wwin
->protocols
.DELETE_WINDOW
)
1425 wClientSendProtocol(wwin
, _XA_WM_DELETE_WINDOW
,
1430 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1431 wSelectWindow(wwin
, !wwin
->flags
.selected
);
1434 case WKBD_FOCUSNEXT
:
1435 wwin
= NextFocusWindow(scr
);
1437 wSetFocusTo(scr
, wwin
);
1438 if (wPreferences
.circ_raise
)
1439 wRaiseFrame(wwin
->frame
->core
);
1442 case WKBD_FOCUSPREV
:
1443 wwin
= PrevFocusWindow(scr
);
1445 wSetFocusTo(scr
, wwin
);
1446 if (wPreferences
.circ_raise
)
1447 wRaiseFrame(wwin
->frame
->core
);
1450 #if (defined(__STDC__) && !defined(UNIXCPP)) || defined(ANSICPP)
1451 #define GOTOWORKS(wk) case WKBD_WORKSPACE##wk:\
1452 i = (scr->current_workspace/10)*10 + wk - 1;\
1453 if (wPreferences.ws_advance || i<scr->workspace_count)\
1454 wWorkspaceChange(scr, i);\
1457 #define GOTOWORKS(wk) case WKBD_WORKSPACE/**/wk:\
1458 i = (scr->current_workspace/10)*10 + wk - 1;\
1459 if (wPreferences.ws_advance || i<scr->workspace_count)\
1460 wWorkspaceChange(scr, i);\
1474 case WKBD_NEXTWORKSPACE
:
1475 if (scr
->current_workspace
< scr
->workspace_count
-1)
1476 wWorkspaceChange(scr
, scr
->current_workspace
+1);
1477 else if (scr
->current_workspace
== scr
->workspace_count
-1) {
1478 if (wPreferences
.ws_advance
&&
1479 scr
->current_workspace
< MAX_WORKSPACES
-1)
1480 wWorkspaceChange(scr
, scr
->current_workspace
+1);
1481 else if (wPreferences
.ws_cycle
)
1482 wWorkspaceChange(scr
, 0);
1485 case WKBD_PREVWORKSPACE
:
1486 if (scr
->current_workspace
> 0)
1487 wWorkspaceChange(scr
, scr
->current_workspace
-1);
1488 else if (scr
->current_workspace
==0 && wPreferences
.ws_cycle
)
1489 wWorkspaceChange(scr
, scr
->workspace_count
-1);
1495 if (scr
->shortcutWindow
[command
-WKBD_WINDOW1
]) {
1496 wMakeWindowVisible(scr
->shortcutWindow
[command
-WKBD_WINDOW1
]);
1497 } else if (wwin
&& ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1498 scr
->shortcutWindow
[command
-WKBD_WINDOW1
] = wwin
;
1499 wSelectWindow(wwin
, !wwin
->flags
.selected
);
1502 wSelectWindow(wwin
, !wwin
->flags
.selected
);
1506 case WKBD_NEXTWSLAYER
:
1507 case WKBD_PREVWSLAYER
:
1511 row
= scr
->current_workspace
/10;
1512 column
= scr
->current_workspace
%10;
1514 if (command
==WKBD_NEXTWSLAYER
) {
1515 if ((row
+1)*10 < scr
->workspace_count
)
1516 wWorkspaceChange(scr
, column
+(row
+1)*10);
1519 wWorkspaceChange(scr
, column
+(row
-1)*10);
1523 case WKBD_CLIPLOWER
:
1524 if (!wPreferences
.flags
.noclip
)
1525 wDockLower(scr
->workspaces
[scr
->current_workspace
]->clip
);
1527 case WKBD_CLIPRAISE
:
1528 if (!wPreferences
.flags
.noclip
)
1529 wDockRaise(scr
->workspaces
[scr
->current_workspace
]->clip
);
1531 case WKBD_CLIPRAISELOWER
:
1532 if (!wPreferences
.flags
.noclip
)
1533 wDockRaiseLower(scr
->workspaces
[scr
->current_workspace
]->clip
);
1535 #ifdef KEEP_XKB_LOCK_STATUS
1537 if(wPreferences
.modelock
){
1538 XkbGetState(dpy
,XkbUseCoreKbd
,&staterec
);
1540 XkbLockGroup(dpy
,XkbUseCoreKbd
,
1541 wwin
->languagemode
=staterec
.compat_state
&32?0:1);
1544 #endif /* KEEP_XKB_LOCK_STATUS */
1551 handleMotionNotify(XEvent
*event
)
1554 WScreen
*scr
= wScreenForRootWindow(event
->xmotion
.root
);
1556 if (wPreferences
.scrollable_menus
) {
1557 if (event
->xmotion
.x_root
<= 1 ||
1558 event
->xmotion
.x_root
>= (scr
->scr_width
- 2) ||
1559 event
->xmotion
.y_root
<= 1 ||
1560 event
->xmotion
.y_root
>= (scr
->scr_height
- 2)) {
1563 puts("pointer at screen edge");
1566 menu
= wMenuUnderPointer(scr
);
1568 wMenuScroll(menu
, event
);