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
);
227 RestoreDesktop(NULL
);
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
);
241 RestoreDesktop(NULL
);
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
.subwindow
== 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
);
658 #ifdef MOUSE_WS_SWITCH
659 else if (event
->xbutton
.button
==Button4
) {
661 if (scr
->current_workspace
> 0)
662 wWorkspaceChange(scr
, scr
->current_workspace
-1);
664 } else if (event
->xbutton
.button
==Button5
) {
666 if (scr
->current_workspace
< scr
->workspace_count
-1)
667 wWorkspaceChange(scr
, scr
->current_workspace
+1);
670 #endif /* MOUSE_WS_SWITCH */
673 if (XFindContext(dpy
, event
->xbutton
.subwindow
, wWinContext
,
674 (XPointer
*)&desc
)==XCNOENT
) {
675 if (XFindContext(dpy
, event
->xbutton
.window
, wWinContext
,
676 (XPointer
*)&desc
)==XCNOENT
) {
681 if (desc
->parent_type
== WCLASS_WINDOW
) {
684 if (event
->xbutton
.state
& MOD_MASK
) {
685 XAllowEvents(dpy
, AsyncPointer
, CurrentTime
);
688 if (wPreferences
.focus_mode
== WKF_CLICK
) {
689 if (wPreferences
.ignore_focus_click
) {
690 XAllowEvents(dpy
, AsyncPointer
, CurrentTime
);
692 XAllowEvents(dpy
, ReplayPointer
, CurrentTime
);
695 } else if (desc
->parent_type
== WCLASS_APPICON
696 || desc
->parent_type
== WCLASS_MINIWINDOW
697 || desc
->parent_type
== WCLASS_DOCK_ICON
) {
698 if (event
->xbutton
.state
& MOD_MASK
) {
700 XAllowEvents(dpy
, AsyncPointer
, CurrentTime
);
705 if (desc
->handle_mousedown
!=NULL
) {
706 (*desc
->handle_mousedown
)(desc
, event
);
709 /* save double-click information */
710 if (scr
->flags
.next_click_is_not_double
) {
711 scr
->flags
.next_click_is_not_double
= 0;
713 scr
->last_click_time
= event
->xbutton
.time
;
714 scr
->last_click_button
= event
->xbutton
.button
;
715 scr
->last_click_window
= event
->xbutton
.subwindow
;
721 handleMapNotify(Window window
)
728 wwin
= wWindowFor(window
);
729 if (wwin
&& wwin
->client_win
==window
) {
730 if (wwin
->flags
.ignore_next_unmap
) {
731 wwin
->flags
.ignore_next_unmap
=0;
734 if (wwin
->flags
.miniaturized
) {
735 wDeiconifyWindow(wwin
);
739 XMapWindow(dpy
, wwin
->client_win
);
740 XMapWindow(dpy
, wwin
->frame
->core
->window
);
741 wwin
->flags
.mapped
=1;
742 wClientSetState(wwin
, NormalState
, None
);
750 handleUnmapNotify(XEvent
*event
)
758 wwin
= wWindowFor(event
->xunmap
.window
);
759 if (!wwin
|| wwin
->client_win
!=event
->xunmap
.window
)
762 if (!wwin
->flags
.mapped
763 && wwin
->frame
->workspace
==wwin
->screen_ptr
->current_workspace
764 && !wwin
->flags
.miniaturized
&& !wwin
->flags
.hidden
)
767 if (wwin
->flags
.ignore_next_unmap
) {
771 XUnmapWindow(dpy
, wwin
->frame
->core
->window
);
772 wwin
->flags
.mapped
= 0;
774 /* check if the window was destroyed */
775 if (XCheckTypedWindowEvent(dpy
, wwin
->client_win
, DestroyNotify
,&ev
)) {
778 Bool reparented
= False
;
780 if (XCheckTypedWindowEvent(dpy
, wwin
->client_win
, ReparentNotify
, &ev
))
783 /* withdraw window */
784 wwin
->flags
.mapped
= 0;
786 wClientSetState(wwin
, WithdrawnState
, None
);
788 /* if the window was reparented, do not reparent it back to the
790 wUnmanageWindow(wwin
, !reparented
);
797 handleConfigureRequest(XEvent
*event
)
802 puts("got configure request");
804 if (!(wwin
=wWindowFor(event
->xconfigurerequest
.window
))) {
806 * Configure request for unmapped window
808 wClientConfigure(NULL
, &(event
->xconfigurerequest
));
810 wClientConfigure(wwin
, &(event
->xconfigurerequest
));
816 handlePropertyNotify(XEvent
*event
)
825 puts("got property notify");
827 if ((wwin
=wWindowFor(event
->xproperty
.window
))) {
828 if (!XGetGeometry(dpy
, wwin
->client_win
, &jr
, &ji
, &ji
,
829 &ju
, &ju
, &ju
, &ju
)) {
832 wClientCheckProperty(wwin
, &event
->xproperty
);
834 wapp
= wApplicationOf(event
->xproperty
.window
);
836 wClientCheckProperty(wapp
->main_window_desc
, &event
->xproperty
);
842 handleClientMessage(XEvent
*event
)
845 WObjDescriptor
*desc
;
848 puts("got client message");
850 /* handle transition from Normal to Iconic state */
851 if (event
->xclient
.message_type
== _XA_WM_CHANGE_STATE
852 && event
->xclient
.format
== 32
853 && event
->xclient
.data
.l
[0] == IconicState
) {
855 wwin
= wWindowFor(event
->xclient
.window
);
857 if (!wwin
->flags
.miniaturized
)
858 wIconifyWindow(wwin
);
859 } else if (event
->xclient
.message_type
== _XA_WM_COLORMAP_NOTIFY
860 && event
->xclient
.format
== 32) {
861 WScreen
*scr
= wScreenForRootWindow(event
->xclient
.window
);
866 if (event
->xclient
.data
.l
[1] == 1) { /* starting */
867 wColormapAllowClientInstallation(scr
, True
);
868 } else { /* stopping */
869 wColormapAllowClientInstallation(scr
, False
);
871 } else if (event
->xclient
.message_type
== _XA_WINDOWMAKER_WM_FUNCTION
) {
874 wapp
= wApplicationOf(event
->xclient
.window
);
876 switch (event
->xclient
.data
.l
[0]) {
877 case WMFHideOtherApplications
:
878 wHideOtherApplications(wapp
->main_window_desc
);
882 case WMFHideApplication
:
883 wHideApplication(wapp
);
889 wwin
= wWindowFor(event
->xclient
.window
);
891 switch (event
->xclient
.data
.l
[0]) {
892 case WMFHideOtherApplications
:
893 wHideOtherApplications(wwin
);
896 case WMFHideApplication
:
897 wHideApplication(wApplicationOf(wwin
->main_window
));
903 } else if (event
->xclient
.message_type
==_XA_XDE_DATA_AVAILABLE
) {
905 WScreen
*scr
= wScreenForWindow(event
->xclient
.window
);
909 char * tmpstr
, * runstr
, * freestr
, * tofreestr
;
911 gdkev
.dropdataavailable
.u
.allflags
= event
->xclient
.data
.l
[1];
912 gdkev
.dropdataavailable
.timestamp
= event
->xclient
.data
.l
[4];
914 if(gdkev
.dropdataavailable
.u
.flags
.isdrop
){
915 gdkev
.dropdataavailable
.type
= GDK_DROP_DATA_AVAIL
;
916 gdkev
.dropdataavailable
.requestor
= event
->xclient
.data
.l
[0];
917 XGetWindowProperty(dpy
,gdkev
.dropdataavailable
.requestor
,
918 event
->xclient
.data
.l
[2],
920 0, XA_PRIMARY
, &tmpatom
,
922 &gdkev
.dropdataavailable
.data_numbytes
,
925 datalenght
=gdkev
.dropdataavailable
.data_numbytes
-1;
928 for(;datalenght
>0;datalenght
-=(strlen(tmpstr
)+1),tmpstr
=&tmpstr
[strlen(tmpstr
)+1]){
929 freestr
=runstr
;runstr
=wstrappend(runstr
,tmpstr
);free(freestr
);
930 freestr
=runstr
;runstr
=wstrappend(runstr
," ");free(freestr
);
933 scr
->xdestring
=runstr
;
934 /* no need to redirect ? */
935 wDockReceiveDNDDrop(scr
,event
);
940 } else if (event
->xclient
.message_type
==_XA_XDE_LEAVE
) {
942 } else if (event
->xclient
.message_type
==_XA_XDE_ENTER
) {
946 gdkev
.dropenter
.u
.allflags
=event
->xclient
.data
.l
[1];
947 printf("from win %x\n",event
->xclient
.data
.l
[0]);
948 printf("to win %x\n",event
->xclient
.window
);
949 printf("enter %x\n",event
->xclient
.data
.l
[1]);
950 printf("v %x ",event
->xclient
.data
.l
[2]);
951 printf("%x ",event
->xclient
.data
.l
[3]);
952 printf("%x\n",event
->xclient
.data
.l
[4]);
954 if(event
->xclient
.data
.l
[2]==_XDE_FILETYPE
||
955 event
->xclient
.data
.l
[3]==_XDE_FILETYPE
||
956 event
->xclient
.data
.l
[4]==_XDE_FILETYPE
||
957 event
->xclient
.data
.l
[2]==_XDE_URLTYPE
||
958 event
->xclient
.data
.l
[3]==_XDE_URLTYPE
||
959 event
->xclient
.data
.l
[4]==_XDE_URLTYPE
)
960 if(gdkev
.dropenter
.u
.flags
.sendreply
){
962 replyev
.xclient
.type
= ClientMessage
;
963 replyev
.xclient
.window
= event
->xclient
.data
.l
[0];
964 replyev
.xclient
.format
= 32;
965 replyev
.xclient
.message_type
= _XA_XDE_REQUEST
;
966 replyev
.xclient
.data
.l
[0] = event
->xclient
.window
;
968 gdkev
.dragrequest
.u
.allflags
= 0;
969 gdkev
.dragrequest
.u
.flags
.protocol_version
= 0;
970 gdkev
.dragrequest
.u
.flags
.willaccept
= 1;
971 gdkev
.dragrequest
.u
.flags
.delete_data
= 0;
973 replyev
.xclient
.data
.l
[1] = gdkev
.dragrequest
.u
.allflags
;
974 replyev
.xclient
.data
.l
[2] = replyev
.xclient
.data
.l
[3] = 0;
975 replyev
.xclient
.data
.l
[4] = event
->xclient
.data
.l
[2];
976 XSendEvent(dpy
, replyev
.xclient
.window
, 0, NoEventMask
, &replyev
);
981 } else if (event
->xclient
.message_type
==_XA_DND_PROTOCOL
) {
982 WScreen
*scr
= wScreenForWindow(event
->xclient
.window
);
983 if (scr
&& wDockReceiveDNDDrop(scr
,event
))
984 goto redirect_message
;
985 #endif /* OFFIX_DND */
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
) {
1029 wRaiseFrame(wwin
->frame
->core
);
1030 /* this is needed or a race condition will occur */
1037 handleEnterNotify(XEvent
*event
)
1040 WObjDescriptor
*desc
= NULL
;
1042 WScreen
*scr
= wScreenForRootWindow(event
->xcrossing
.root
);
1046 puts("got enter notify");
1049 if (XCheckTypedWindowEvent(dpy
, event
->xcrossing
.window
, LeaveNotify
,
1051 /* already left the window... */
1053 if (ev
.xcrossing
.mode
==event
->xcrossing
.mode
1054 && ev
.xcrossing
.detail
==event
->xcrossing
.detail
) {
1059 if (XFindContext(dpy
, event
->xcrossing
.window
, wWinContext
,
1060 (XPointer
*)&desc
)!=XCNOENT
) {
1061 if(desc
->handle_enternotify
)
1062 (*desc
->handle_enternotify
)(desc
, event
);
1065 /* enter to window */
1066 wwin
= wWindowFor(event
->xcrossing
.window
);
1068 if (wPreferences
.focus_mode
==WKF_POINTER
1069 && event
->xcrossing
.window
==event
->xcrossing
.root
) {
1070 wSetFocusTo(scr
, NULL
);
1072 if (wPreferences
.colormap_mode
==WKF_POINTER
) {
1073 wColormapInstallForWindow(scr
, NULL
);
1075 if (scr
->autoRaiseTimer
1076 && event
->xcrossing
.root
==event
->xcrossing
.window
) {
1077 WMDeleteTimerHandler(scr
->autoRaiseTimer
);
1078 scr
->autoRaiseTimer
= NULL
;
1081 /* set focus if in focus-follows-mouse mode and the event
1082 * is for the frame window and window doesn't have focus yet */
1083 if ((wPreferences
.focus_mode
==WKF_POINTER
1084 || wPreferences
.focus_mode
==WKF_SLOPPY
)
1085 && wwin
->frame
->core
->window
==event
->xcrossing
.window
1086 && !wwin
->flags
.focused
) {
1087 wSetFocusTo(scr
, wwin
);
1089 if (scr
->autoRaiseTimer
)
1090 WMDeleteTimerHandler(scr
->autoRaiseTimer
);
1091 scr
->autoRaiseTimer
= NULL
;
1093 if (wPreferences
.raise_delay
&& !wwin
->window_flags
.no_focusable
) {
1094 scr
->autoRaiseWindow
= wwin
->frame
->core
->window
;
1096 = WMAddTimerHandler(wPreferences
.raise_delay
,
1097 (WMCallback
*)raiseWindow
, scr
);
1100 /* Install colormap for window, if the colormap installation mode
1101 * is colormap_follows_mouse */
1102 if (wPreferences
.colormap_mode
==WKF_POINTER
) {
1103 if (wwin
->client_win
==event
->xcrossing
.window
)
1104 wColormapInstallForWindow(scr
, wwin
);
1106 wColormapInstallForWindow(scr
, NULL
);
1110 /* a little kluge to hide the clip balloon */
1111 if (!wPreferences
.flags
.noclip
&& scr
->flags
.clip_balloon_mapped
) {
1113 XUnmapWindow(dpy
, scr
->clip_balloon
);
1114 scr
->flags
.clip_balloon_mapped
= 0;
1116 if (desc
->parent_type
!=WCLASS_DOCK_ICON
1117 || scr
->clip_icon
!= desc
->parent
) {
1118 XUnmapWindow(dpy
, scr
->clip_balloon
);
1119 scr
->flags
.clip_balloon_mapped
= 0;
1124 if (event
->xcrossing
.window
== event
->xcrossing
.root
1125 && event
->xcrossing
.detail
== NotifyNormal
1126 && event
->xcrossing
.detail
!= NotifyInferior
1127 && wPreferences
.focus_mode
!= WKF_CLICK
) {
1129 wSetFocusTo(scr
, scr
->focused_window
);
1133 wBalloonEnteredObject(scr
, desc
);
1139 handleLeaveNotify(XEvent
*event
)
1141 WObjDescriptor
*desc
= NULL
;
1143 if (XFindContext(dpy
, event
->xcrossing
.window
, wWinContext
,
1144 (XPointer
*)&desc
)!=XCNOENT
) {
1145 if(desc
->handle_leavenotify
)
1146 (*desc
->handle_leavenotify
)(desc
, event
);
1148 if (event
->xcrossing
.window
== event
->xcrossing
.root
1149 && event
->xcrossing
.mode
== NotifyNormal
1150 && event
->xcrossing
.detail
!= NotifyInferior
1151 && wPreferences
.focus_mode
!= WKF_CLICK
) {
1153 WScreen
*scr
= wScreenForRootWindow(event
->xcrossing
.root
);
1155 wSetFocusTo(scr
, NULL
);
1162 handleShapeNotify(XEvent
*event
)
1164 XShapeEvent
*shev
= (XShapeEvent
*)event
;
1169 puts("got shape notify");
1172 while (XCheckTypedWindowEvent(dpy
, shev
->window
, event
->type
, &ev
)) {
1173 XShapeEvent
*sev
= (XShapeEvent
*)&ev
;
1175 if (sev
->kind
== ShapeBounding
) {
1176 if (sev
->shaped
== shev
->shaped
) {
1179 XPutBackEvent(dpy
, &ev
);
1185 wwin
= wWindowFor(shev
->window
);
1186 if (!wwin
|| shev
->kind
!= ShapeBounding
)
1189 if (!shev
->shaped
&& wwin
->flags
.shaped
) {
1191 wwin
->flags
.shaped
= 0;
1192 wWindowClearShape(wwin
);
1194 } else if (shev
->shaped
) {
1196 wwin
->flags
.shaped
= 1;
1197 wWindowSetShape(wwin
);
1204 handleColormapNotify(XEvent
*event
)
1208 Bool reinstall
= False
;
1210 wwin
= wWindowFor(event
->xcolormap
.window
);
1214 scr
= wwin
->screen_ptr
;
1218 if (event
->xcolormap
.new) {
1219 XWindowAttributes attr
;
1221 XGetWindowAttributes(dpy
, wwin
->client_win
, &attr
);
1223 if (wwin
== scr
->cmap_window
&& wwin
->cmap_window_no
== 0)
1224 scr
->current_colormap
= attr
.colormap
;
1227 } else if (event
->xcolormap
.state
== ColormapUninstalled
&&
1228 scr
->current_colormap
== event
->xcolormap
.colormap
) {
1230 /* some bastard app (like XV) removed our colormap */
1232 * can't enforce or things like xscreensaver wont work
1235 } else if (event
->xcolormap
.state
== ColormapInstalled
&&
1236 scr
->current_colormap
== event
->xcolormap
.colormap
) {
1238 /* someone has put our colormap back */
1242 } while (XCheckTypedEvent(dpy
, ColormapNotify
, event
)
1243 && ((wwin
= wWindowFor(event
->xcolormap
.window
)) || 1));
1245 if (reinstall
&& scr
->current_colormap
!=None
) {
1246 if (!scr
->flags
.colormap_stuff_blocked
)
1247 XInstallColormap(dpy
, scr
->current_colormap
);
1254 handleFocusIn(XEvent
*event
)
1259 * For applications that like stealing the focus.
1261 while (XCheckTypedEvent(dpy
, FocusIn
, event
));
1262 saveTimestamp(event
);
1263 if (event
->xfocus
.mode
== NotifyUngrab
1264 || event
->xfocus
.mode
== NotifyGrab
1265 || event
->xfocus
.detail
> NotifyNonlinearVirtual
) {
1269 wwin
= wWindowFor(event
->xfocus
.window
);
1270 if (wwin
&& !wwin
->flags
.focused
) {
1271 if (wwin
->flags
.mapped
)
1272 wSetFocusTo(wwin
->screen_ptr
, wwin
);
1274 wSetFocusTo(wwin
->screen_ptr
, NULL
);
1276 WScreen
*scr
= wScreenForWindow(event
->xfocus
.window
);
1278 wSetFocusTo(scr
, NULL
);
1284 windowUnderPointer(WScreen
*scr
)
1290 if (XQueryPointer(dpy
, scr
->root_win
, &bar
, &win
, &foo
, &foo
, &foo
, &foo
,
1292 return wWindowFor(win
);
1297 handleKeyPress(XEvent
*event
)
1299 WScreen
*scr
= wScreenForRootWindow(event
->xkey
.root
);
1300 WWindow
*wwin
= scr
->focused_window
;
1304 #ifdef KEEP_XKB_LOCK_STATUS
1305 XkbStateRec staterec
;
1306 #endif /*KEEP_XKB_LOCK_STATUS*/
1308 /* ignore CapsLock */
1309 modifiers
= event
->xkey
.state
& ValidModMask
;
1311 for (i
=0; i
<WKBD_LAST
; i
++) {
1312 if (wKeyBindings
[i
].keycode
==0)
1315 if (wKeyBindings
[i
].keycode
==event
->xkey
.keycode
1316 && (/*wKeyBindings[i].modifier==0
1317 ||*/ wKeyBindings
[i
].modifier
==modifiers
)) {
1324 if (!wRootMenuPerformShortcut(event
)) {
1325 static int dontLoop
= 0;
1327 if (dontLoop
> 10) {
1328 wwarning("problem with key event processing code");
1332 /* if the focused window is an internal window, try redispatching
1333 * the event to the managed window, as it can be a WINGs window */
1334 if (wwin
&& wwin
->flags
.internal_window
1335 && wwin
->client_leader
!=None
) {
1336 /* client_leader contains the WINGs toplevel */
1337 event
->xany
.window
= wwin
->client_leader
;
1338 WMHandleEvent(event
);
1345 #define ISMAPPED(w) ((w) && !(w)->flags.miniaturized && ((w)->flags.mapped || (w)->flags.shaded))
1346 #define ISFOCUSED(w) ((w) && (w)->flags.focused)
1350 OpenRootMenu(scr
, event
->xkey
.x_root
, event
->xkey
.y_root
, True
);
1352 case WKBD_WINDOWMENU
:
1353 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
))
1354 OpenWindowMenu(wwin
, wwin
->frame_x
,
1355 wwin
->frame_y
+wwin
->frame
->top_width
, True
);
1357 case WKBD_WINDOWLIST
:
1358 OpenSwitchMenu(scr
, event
->xkey
.x_root
, event
->xkey
.y_root
, True
);
1360 case WKBD_MINIATURIZE
:
1361 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1362 CloseWindowMenu(scr
);
1364 if (wwin
->protocols
.MINIATURIZE_WINDOW
)
1365 wClientSendProtocol(wwin
, _XA_GNUSTEP_WM_MINIATURIZE_WINDOW
,
1366 event
->xbutton
.time
);
1368 if (!wwin
->window_flags
.no_miniaturizable
)
1369 wIconifyWindow(wwin
);
1374 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1375 WApplication
*wapp
= wApplicationOf(wwin
->main_window
);
1376 CloseWindowMenu(scr
);
1378 if (wapp
&& !wapp
->main_window_desc
->window_flags
.no_appicon
) {
1379 wHideApplication(wapp
);
1384 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)
1385 && !wwin
->window_flags
.no_resizable
) {
1386 CloseWindowMenu(scr
);
1388 if (wwin
->flags
.maximized
) {
1389 wUnmaximizeWindow(wwin
);
1391 wMaximizeWindow(wwin
, MAX_VERTICAL
|MAX_HORIZONTAL
);
1395 case WKBD_VMAXIMIZE
:
1396 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)
1397 && !wwin
->window_flags
.no_resizable
) {
1398 CloseWindowMenu(scr
);
1400 if (wwin
->flags
.maximized
) {
1401 wUnmaximizeWindow(wwin
);
1403 wMaximizeWindow(wwin
, MAX_VERTICAL
);
1408 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1409 CloseWindowMenu(scr
);
1411 wRaiseFrame(wwin
->frame
->core
);
1415 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1416 CloseWindowMenu(scr
);
1418 wLowerFrame(wwin
->frame
->core
);
1421 case WKBD_RAISELOWER
:
1422 /* raise or lower the window under the pointer, not the
1425 wwin
= windowUnderPointer(scr
);
1427 wRaiseLowerFrame(wwin
->frame
->core
);
1430 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)
1431 && !wwin
->window_flags
.no_shadeable
) {
1432 if (wwin
->flags
.shaded
)
1433 wUnshadeWindow(wwin
);
1439 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)
1440 && !wwin
->window_flags
.no_closable
) {
1441 CloseWindowMenu(scr
);
1442 if (wwin
->protocols
.DELETE_WINDOW
)
1443 wClientSendProtocol(wwin
, _XA_WM_DELETE_WINDOW
,
1448 if (ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1449 wSelectWindow(wwin
, !wwin
->flags
.selected
);
1452 case WKBD_FOCUSNEXT
:
1453 wwin
= NextFocusWindow(scr
);
1455 wSetFocusTo(scr
, wwin
);
1456 if (wPreferences
.circ_raise
)
1457 wRaiseFrame(wwin
->frame
->core
);
1460 case WKBD_FOCUSPREV
:
1461 wwin
= PrevFocusWindow(scr
);
1463 wSetFocusTo(scr
, wwin
);
1464 if (wPreferences
.circ_raise
)
1465 wRaiseFrame(wwin
->frame
->core
);
1468 #if (defined(__STDC__) && !defined(UNIXCPP)) || defined(ANSICPP)
1469 #define GOTOWORKS(wk) case WKBD_WORKSPACE##wk:\
1470 i = (scr->current_workspace/10)*10 + wk - 1;\
1471 if (wPreferences.ws_advance || i<scr->workspace_count)\
1472 wWorkspaceChange(scr, i);\
1475 #define GOTOWORKS(wk) case WKBD_WORKSPACE/**/wk:\
1476 i = (scr->current_workspace/10)*10 + wk - 1;\
1477 if (wPreferences.ws_advance || i<scr->workspace_count)\
1478 wWorkspaceChange(scr, i);\
1492 case WKBD_NEXTWORKSPACE
:
1493 if (scr
->current_workspace
< scr
->workspace_count
-1)
1494 wWorkspaceChange(scr
, scr
->current_workspace
+1);
1495 else if (scr
->current_workspace
== scr
->workspace_count
-1) {
1496 if (wPreferences
.ws_advance
&&
1497 scr
->current_workspace
< MAX_WORKSPACES
-1)
1498 wWorkspaceChange(scr
, scr
->current_workspace
+1);
1499 else if (wPreferences
.ws_cycle
)
1500 wWorkspaceChange(scr
, 0);
1503 case WKBD_PREVWORKSPACE
:
1504 if (scr
->current_workspace
> 0)
1505 wWorkspaceChange(scr
, scr
->current_workspace
-1);
1506 else if (scr
->current_workspace
==0 && wPreferences
.ws_cycle
)
1507 wWorkspaceChange(scr
, scr
->workspace_count
-1);
1513 if (scr
->shortcutWindow
[command
-WKBD_WINDOW1
]) {
1514 wMakeWindowVisible(scr
->shortcutWindow
[command
-WKBD_WINDOW1
]);
1515 } else if (wwin
&& ISMAPPED(wwin
) && ISFOCUSED(wwin
)) {
1516 scr
->shortcutWindow
[command
-WKBD_WINDOW1
] = wwin
;
1517 wSelectWindow(wwin
, !wwin
->flags
.selected
);
1520 wSelectWindow(wwin
, !wwin
->flags
.selected
);
1524 case WKBD_NEXTWSLAYER
:
1525 case WKBD_PREVWSLAYER
:
1529 row
= scr
->current_workspace
/10;
1530 column
= scr
->current_workspace
%10;
1532 if (command
==WKBD_NEXTWSLAYER
) {
1533 if ((row
+1)*10 < scr
->workspace_count
)
1534 wWorkspaceChange(scr
, column
+(row
+1)*10);
1537 wWorkspaceChange(scr
, column
+(row
-1)*10);
1541 case WKBD_CLIPLOWER
:
1542 if (!wPreferences
.flags
.noclip
)
1543 wDockLower(scr
->workspaces
[scr
->current_workspace
]->clip
);
1545 case WKBD_CLIPRAISE
:
1546 if (!wPreferences
.flags
.noclip
)
1547 wDockRaise(scr
->workspaces
[scr
->current_workspace
]->clip
);
1549 case WKBD_CLIPRAISELOWER
:
1550 if (!wPreferences
.flags
.noclip
)
1551 wDockRaiseLower(scr
->workspaces
[scr
->current_workspace
]->clip
);
1553 #ifdef KEEP_XKB_LOCK_STATUS
1555 if(wPreferences
.modelock
){
1556 XkbGetState(dpy
,XkbUseCoreKbd
,&staterec
);
1558 XkbLockGroup(dpy
,XkbUseCoreKbd
,
1559 wwin
->languagemode
=staterec
.compat_state
&32?0:1);
1562 #endif /* KEEP_XKB_LOCK_STATUS */
1569 handleMotionNotify(XEvent
*event
)
1572 WScreen
*scr
= wScreenForRootWindow(event
->xmotion
.root
);
1574 if (wPreferences
.scrollable_menus
) {
1575 if (event
->xmotion
.x_root
<= 1 ||
1576 event
->xmotion
.x_root
>= (scr
->scr_width
- 2) ||
1577 event
->xmotion
.y_root
<= 1 ||
1578 event
->xmotion
.y_root
>= (scr
->scr_height
- 2)) {
1581 puts("pointer at screen edge");
1584 menu
= wMenuUnderPointer(scr
);
1586 wMenuScroll(menu
, event
);