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>
43 #include "WindowMaker.h"
49 #include "application.h"
52 #include "workspace.h"
55 #include "properties.h"
59 /******** Global Variables **********/
60 extern XContext wWinContext
;
62 extern Cursor wCursor
[WCUR_LAST
];
64 extern WShortKey wKeyBindings
[WKBD_LAST
];
65 extern int wScreenCount
;
66 extern Time LastTimestamp
;
67 extern Time LastFocusChange
;
69 extern WPreferences wPreferences
;
71 #define MOD_MASK wPreferences.modifier_mask
73 extern Atom _XA_WM_CHANGE_STATE
;
74 extern Atom _XA_WM_DELETE_WINDOW
;
75 extern Atom _XA_GNUSTEP_WM_MINIATURIZE_WINDOW
;
76 extern Atom _XA_WINDOWMAKER_WM_FUNCTION
;
79 extern Atom _XA_DND_PROTOCOL
;
82 extern Atom _XA_XDE_REQUEST
;
83 extern Atom _XA_XDE_ENTER
;
84 extern Atom _XA_XDE_LEAVE
;
85 extern Atom _XA_XDE_DATA_AVAILABLE
;
86 extern Atom _XDE_FILETYPE
;
87 extern Atom _XDE_URLTYPE
;
92 extern Bool wShapeSupported
;
93 extern int wShapeEventBase
;
97 extern char WProgramState
;
98 extern char WDelayedActionSet
;
101 /************ Local stuff ***********/
104 static void saveTimestamp(XEvent
*event
);
105 static void handleColormapNotify();
106 static void handleMapNotify(), handleUnmapNotify();
107 static void handleButtonPress(), handleExpose();
108 static void handleDestroyNotify();
109 static void handleConfigureRequest();
110 static void handleMapRequest();
111 static void handlePropertyNotify();
112 static void handleEnterNotify();
113 static void handleLeaveNotify();
114 static void handleExtensions();
115 static void handleClientMessage();
116 static void handleKeyPress();
117 static void handleFocusIn();
118 static void handleMotionNotify();
120 static void handleShapeNotify();
123 /* called from the signal handler */
124 void NotifyDeadProcess(pid_t pid
, unsigned char status
);
126 /* real dead process handler */
127 static void handleDeadProcess(void *foo
);
130 typedef struct DeadProcesses
{
132 unsigned char exit_status
;
135 /* stack of dead processes */
136 static DeadProcesses deadProcesses
[MAX_DEAD_PROCESSES
];
137 static int deadProcessPtr
=0;
140 typedef struct DeathHandler
{
141 WDeathHandler
*callback
;
143 struct DeathHandler
*next
;
147 static DeathHandler
*deathHandler
=NULL
;
152 wAddDeathHandler(pid_t pid
, WDeathHandler
*callback
, void *cdata
)
154 DeathHandler
*handler
;
156 handler
= malloc(sizeof(DeathHandler
));
161 handler
->callback
= callback
;
162 handler
->client_data
= cdata
;
164 handler
->next
= deathHandler
;
166 deathHandler
= handler
;
174 wDeleteDeathHandler(WDeathHandlerID id
)
176 DeathHandler
*tmp
, *handler
=(DeathHandler
*)id
;
178 if (!handler
|| !deathHandler
)
183 deathHandler
= handler
->next
;
187 if (tmp
->next
==handler
) {
188 tmp
->next
=handler
->next
;
199 DispatchEvent(XEvent
*event
)
204 handleDeadProcess(NULL
);
206 if (WProgramState
==WSTATE_NEED_EXIT
) {
207 WProgramState
= WSTATE_EXITING
;
210 * WMHandleEvent() can't be called from anything
211 * executed inside here, or we can get in a infinite
214 for (i
=0; i
<wScreenCount
; i
++) {
216 scr
= wScreenWithNumber(i
);
218 wScreenSaveState(scr
);
223 /* received SIGTERM */
225 } else if (WProgramState
== WSTATE_NEED_RESTART
) {
226 WProgramState
= WSTATE_RESTARTING
;
228 for (i
=0; i
<wScreenCount
; i
++) {
230 scr
= wScreenWithNumber(i
);
232 wScreenSaveState(scr
);
236 /* received SIGHUP */
240 /* for the case that all that is wanted to be dispatched is
245 saveTimestamp(event
);
246 switch (event
->type
) {
248 handleMapRequest(event
);
252 handleKeyPress(event
);
256 handleMotionNotify(event
);
259 case ConfigureRequest
:
260 handleConfigureRequest(event
);
264 handleDestroyNotify(event
->xdestroywindow
.window
);
268 handleMapNotify(event
->xmap
.window
);
272 handleUnmapNotify(event
);
276 handleButtonPress(event
);
284 handlePropertyNotify(event
);
288 handleEnterNotify(event
);
292 handleLeaveNotify(event
);
296 handleClientMessage(event
);
300 handleColormapNotify(event
);
304 if (event
->xmapping
.request
== MappingKeyboard
305 || event
->xmapping
.request
== MappingModifier
)
306 XRefreshKeyboardMapping(&event
->xmapping
);
310 handleFocusIn(event
);
314 handleExtensions(event
);
320 *----------------------------------------------------------------------
322 * Processes X and internal events indefinitely.
328 * The LastTimestamp global variable is updated.
329 *----------------------------------------------------------------------
337 WMNextEvent(dpy
, &event
);
338 WMHandleEvent(&event
);
345 IsDoubleClick(WScreen
*scr
, XEvent
*event
)
347 if ((scr
->last_click_time
>0) &&
348 (event
->xbutton
.time
-scr
->last_click_time
<=wPreferences
.dblclick_time
)
349 && (event
->xbutton
.button
== scr
->last_click_button
)
350 && (event
->xbutton
.window
== scr
->last_click_window
)) {
352 scr
->flags
.next_click_is_not_double
= 1;
353 scr
->last_click_time
= 0;
354 scr
->last_click_window
= None
;
363 NotifyDeadProcess(pid_t pid
, unsigned char status
)
365 if (deadProcessPtr
>=MAX_DEAD_PROCESSES
-1) {
366 wwarning(_("stack overflow: too many dead processes"));
369 /* stack the process to be handled later,
370 * as this is called from the signal handler */
371 deadProcesses
[deadProcessPtr
].pid
= pid
;
372 deadProcesses
[deadProcessPtr
].exit_status
= status
;
378 handleDeadProcess(void *foo
)
383 for (i
=0; i
<deadProcessPtr
; i
++) {
384 wWindowDeleteSavedStatesForPID(deadProcesses
[i
].pid
);
392 /* get the pids on the queue and call handlers */
393 while (deadProcessPtr
>0) {
402 if (tmp
->pid
== deadProcesses
[deadProcessPtr
].pid
) {
403 (*tmp
->callback
)(tmp
->pid
,
404 deadProcesses
[deadProcessPtr
].exit_status
,
406 wDeleteDeathHandler(tmp
);
415 saveTimestamp(XEvent
*event
)
417 LastTimestamp
= CurrentTime
;
419 switch (event
->type
) {
422 LastTimestamp
= event
->xbutton
.time
;
426 LastTimestamp
= event
->xkey
.time
;
429 LastTimestamp
= event
->xmotion
.time
;
432 LastTimestamp
= event
->xproperty
.time
;
436 LastTimestamp
= event
->xcrossing
.time
;
439 LastTimestamp
= event
->xselectionclear
.time
;
441 case SelectionRequest
:
442 LastTimestamp
= event
->xselectionrequest
.time
;
444 case SelectionNotify
:
445 LastTimestamp
= event
->xselection
.time
;
452 handleExtensions(XEvent
*event
)
455 if (wShapeSupported
&& event
->type
== (wShapeEventBase
+ShapeNotify
)) {
456 handleShapeNotify(event
);
462 handleMapRequest(XEvent
*ev
)
466 Window window
= ev
->xmaprequest
.window
;
469 printf("got map request for %x\n", (unsigned)window
);
472 if ((wwin
=wWindowFor(window
))) {
473 /* deiconify window */
474 if (wwin
->flags
.shaded
)
475 wUnshadeWindow(wwin
);
476 if (wwin
->flags
.miniaturized
) {
477 wDeiconifyWindow(wwin
);
478 } else if (wwin
->flags
.hidden
) {
479 WApplication
*wapp
= wApplicationOf(wwin
->main_window
);
480 /* go to the last workspace that the user worked on the app */
481 #ifndef REDUCE_APPICONS
482 /* This severely breaks REDUCE_APPICONS. last_workspace is a neat
483 * concept but it needs to be reworked to handle REDUCE_APPICONS -cls
486 wWorkspaceChange(wwin
->screen_ptr
, wapp
->last_workspace
);
489 wUnhideApplication(wapp
, False
, False
);
494 scr
= wScreenForRootWindow(ev
->xmaprequest
.parent
);
496 wwin
= wManageWindow(scr
, window
);
499 * This is to let the Dock know that the application it launched
500 * has already been mapped (eg: it has finished launching).
501 * It is not necessary for normally docked apps, but is needed for
502 * apps that were forcedly docked (like with dockit).
504 if (scr
->last_dock
) {
505 if (wwin
&& wwin
->main_window
!=None
&& wwin
->main_window
!=window
)
506 wDockTrackWindowLaunch(scr
->last_dock
, wwin
->main_window
);
508 wDockTrackWindowLaunch(scr
->last_dock
, window
);
514 if (wwin
->wm_hints
&& (wwin
->wm_hints
->flags
& StateHint
))
515 state
= wwin
->wm_hints
->initial_state
;
519 if (state
==IconicState
)
520 wwin
->flags
.miniaturized
= 1;
522 if (state
==WithdrawnState
) {
523 wwin
->flags
.mapped
= 0;
524 wClientSetState(wwin
, WithdrawnState
, None
);
525 XSelectInput(dpy
, wwin
->client_win
, NoEventMask
);
526 XRemoveFromSaveSet(dpy
, wwin
->client_win
);
527 wUnmanageWindow(wwin
, True
);
529 wClientSetState(wwin
, NormalState
, None
);
530 if (wwin
->flags
.shaded
) {
531 wwin
->flags
.shaded
= 0;
532 wwin
->flags
.skip_next_animation
= 1;
533 wwin
->flags
.ignore_next_unmap
= 1; /* ??? */
536 if (wwin
->flags
.miniaturized
) {
537 wwin
->flags
.miniaturized
= 0;
538 wwin
->flags
.hidden
= 0;
539 wwin
->flags
.skip_next_animation
= 1;
540 wwin
->flags
.ignore_next_unmap
= 1;
541 wIconifyWindow(wwin
);
542 } else if (wwin
->flags
.hidden
) {
543 WApplication
*wapp
= wApplicationOf(wwin
->main_window
);
544 wwin
->flags
.hidden
= 0;
545 wwin
->flags
.skip_next_animation
= 1;
547 wHideApplication(wapp
);
549 wwin
->flags
.ignore_next_unmap
= 1;
555 wwin
->flags
.mapped
= 0;
556 wClientSetState(wwin
, WithdrawnState
, None
);
557 XSelectInput(dpy
, wwin
->client_win
, NoEventMask
);
558 XRemoveFromSaveSet(dpy
, wwin
->client_win
);
559 wUnmanageWindow(wwin
, True
);
563 if (!wwin
->flags
.miniaturized
) {
564 wwin
->flags
.ignore_next_unmap
=1;
565 wwin
->flags
.skip_next_animation
=1;
566 wIconifyWindow(wwin
);
574 wClientSetState(wwin
, NormalState
, None
);
583 handleDestroyNotify(Window window
)
588 puts("got destroy notify");
591 wwin
= wWindowFor(window
);
593 wUnmanageWindow(wwin
, False
);
596 app
= wApplicationOf(window
);
598 if (window
== app
->main_window
) {
600 wwin
= app
->main_window_desc
->screen_ptr
->focused_window
;
602 if (wwin
->main_window
== window
) {
603 wwin
->main_window
= None
;
608 wApplicationDestroy(app
);
615 handleExpose(XEvent
*event
)
617 WObjDescriptor
*desc
;
622 if (event
->xexpose
.count
!=0) {
626 if (XFindContext(dpy
, event
->xexpose
.window
, wWinContext
,
627 (XPointer
*)&desc
)==XCNOENT
) {
631 if (desc
->handle_expose
) {
632 (*desc
->handle_expose
)(desc
, event
);
639 handleButtonPress(XEvent
*event
)
641 WObjDescriptor
*desc
;
645 puts("got button press");
648 scr
= wScreenForRootWindow(event
->xbutton
.root
);
654 if (event
->xbutton
.window
==scr
->root_win
) {
655 if (event
->xbutton
.button
==wPreferences
.menu_button
) {
656 OpenRootMenu(scr
, event
->xbutton
.x_root
,
657 event
->xbutton
.y_root
, False
);
659 if (scr
->root_menu
) {
660 if (scr
->root_menu
->brother
->flags
.mapped
)
661 event
->xbutton
.window
= scr
->root_menu
->brother
->frame
->core
->window
;
663 event
->xbutton
.window
= scr
->root_menu
->frame
->core
->window
;
665 } else if (event
->xbutton
.button
==wPreferences
.windowl_button
) {
667 OpenSwitchMenu(scr
, event
->xbutton
.x_root
,
668 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
;
675 } else if (event
->xbutton
.button
==wPreferences
.select_button
) {
678 wSelectWindows(scr
, event
);
683 if (XFindContext(dpy
, event
->xbutton
.window
, wWinContext
,
684 (XPointer
*)&desc
)==XCNOENT
) {
688 if (desc
->parent_type
== WCLASS_WINDOW
) {
691 if (event
->xbutton
.state
& MOD_MASK
) {
692 XAllowEvents(dpy
, AsyncPointer
, CurrentTime
);
695 if (wPreferences
.focus_mode
== WKF_CLICK
) {
696 if (wPreferences
.ignore_focus_click
) {
697 XAllowEvents(dpy
, AsyncPointer
, CurrentTime
);
699 XAllowEvents(dpy
, ReplayPointer
, CurrentTime
);
702 } else if (desc
->parent_type
== WCLASS_APPICON
703 || desc
->parent_type
== WCLASS_MINIWINDOW
704 || desc
->parent_type
== WCLASS_DOCK_ICON
) {
705 if (event
->xbutton
.state
& MOD_MASK
) {
707 XAllowEvents(dpy
, AsyncPointer
, CurrentTime
);
712 if (desc
->handle_mousedown
!=NULL
) {
713 (*desc
->handle_mousedown
)(desc
, event
);
716 /* save double-click information */
717 if (scr
->flags
.next_click_is_not_double
) {
718 scr
->flags
.next_click_is_not_double
= 0;
720 scr
->last_click_time
= event
->xbutton
.time
;
721 scr
->last_click_button
= event
->xbutton
.button
;
722 scr
->last_click_window
= event
->xbutton
.window
;
728 handleMapNotify(Window window
)
735 wwin
= wWindowFor(window
);
736 if (wwin
&& wwin
->client_win
==window
) {
737 if (wwin
->flags
.ignore_next_unmap
) {
738 wwin
->flags
.ignore_next_unmap
=0;
741 if (wwin
->flags
.miniaturized
) {
742 wDeiconifyWindow(wwin
);
746 XMapWindow(dpy
, wwin
->client_win
);
747 XMapWindow(dpy
, wwin
->frame
->core
->window
);
748 wwin
->flags
.mapped
=1;
749 wClientSetState(wwin
, NormalState
, None
);
757 handleUnmapNotify(XEvent
*event
)
765 wwin
= wWindowFor(event
->xunmap
.window
);
766 if (!wwin
|| wwin
->client_win
!=event
->xunmap
.window
)
769 if (!wwin
->flags
.mapped
770 && wwin
->frame
->workspace
==wwin
->screen_ptr
->current_workspace
771 && !wwin
->flags
.miniaturized
&& !wwin
->flags
.hidden
)
774 if (wwin
->flags
.ignore_next_unmap
) {
778 XUnmapWindow(dpy
, wwin
->frame
->core
->window
);
779 wwin
->flags
.mapped
= 0;
781 /* check if the window was destroyed */
782 if (XCheckTypedWindowEvent(dpy
, wwin
->client_win
, DestroyNotify
,&ev
)) {
785 /* withdraw window */
786 wwin
->flags
.mapped
= 0;
787 XSelectInput(dpy
, wwin
->client_win
, NoEventMask
);
788 XRemoveFromSaveSet(dpy
, wwin
->client_win
);
789 wClientSetState(wwin
, WithdrawnState
, None
);
790 wUnmanageWindow(wwin
, True
);
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_WINDOWMAKER_WM_FUNCTION
) {
862 wapp
= wApplicationOf(event
->xclient
.window
);
864 switch (event
->xclient
.data
.l
[0]) {
865 case WMFHideOtherApplications
:
866 wHideOtherApplications(wapp
->main_window_desc
);
870 case WMFHideApplication
:
871 wHideApplication(wapp
);
877 wwin
= wWindowFor(event
->xclient
.window
);
879 switch (event
->xclient
.data
.l
[0]) {
880 case WMFHideOtherApplications
:
881 wHideOtherApplications(wwin
);
884 case WMFHideApplication
:
885 wHideApplication(wApplicationOf(wwin
->main_window
));
891 } else if (event
->xclient
.message_type
==_XA_XDE_DATA_AVAILABLE
) {
893 WScreen
*scr
= wScreenForWindow(event
->xclient
.window
);
897 char * tmpstr
, * runstr
, * freestr
, * tofreestr
;
899 gdkev
.dropdataavailable
.u
.allflags
= event
->xclient
.data
.l
[1];
900 gdkev
.dropdataavailable
.timestamp
= event
->xclient
.data
.l
[4];
902 if(gdkev
.dropdataavailable
.u
.flags
.isdrop
){
903 gdkev
.dropdataavailable
.type
= GDK_DROP_DATA_AVAIL
;
904 gdkev
.dropdataavailable
.requestor
= event
->xclient
.data
.l
[0];
905 XGetWindowProperty(dpy
,gdkev
.dropdataavailable
.requestor
,
906 event
->xclient
.data
.l
[2],
908 0, XA_PRIMARY
, &tmpatom
,
910 &gdkev
.dropdataavailable
.data_numbytes
,
913 datalenght
=gdkev
.dropdataavailable
.data_numbytes
-1;
916 for(;datalenght
>0;datalenght
-=(strlen(tmpstr
)+1),tmpstr
=&tmpstr
[strlen(tmpstr
)+1]){
917 freestr
=runstr
;runstr
=wstrappend(runstr
,tmpstr
);free(freestr
);
918 freestr
=runstr
;runstr
=wstrappend(runstr
," ");free(freestr
);
921 scr
->xdestring
=runstr
;
922 /* no need to redirect ? */
923 wDockReceiveDNDDrop(scr
,event
);
928 } else if (event
->xclient
.message_type
==_XA_XDE_LEAVE
) {
930 } else if (event
->xclient
.message_type
==_XA_XDE_ENTER
) {
934 gdkev
.dropenter
.u
.allflags
=event
->xclient
.data
.l
[1];
935 printf("from win %x\n",event
->xclient
.data
.l
[0]);
936 printf("to win %x\n",event
->xclient
.window
);
937 printf("enter %x\n",event
->xclient
.data
.l
[1]);
938 printf("v %x ",event
->xclient
.data
.l
[2]);
939 printf("%x ",event
->xclient
.data
.l
[3]);
940 printf("%x\n",event
->xclient
.data
.l
[4]);
942 if(event
->xclient
.data
.l
[2]==_XDE_FILETYPE
||
943 event
->xclient
.data
.l
[3]==_XDE_FILETYPE
||
944 event
->xclient
.data
.l
[4]==_XDE_FILETYPE
||
945 event
->xclient
.data
.l
[2]==_XDE_URLTYPE
||
946 event
->xclient
.data
.l
[3]==_XDE_URLTYPE
||
947 event
->xclient
.data
.l
[4]==_XDE_URLTYPE
)
948 if(gdkev
.dropenter
.u
.flags
.sendreply
){
950 replyev
.xclient
.type
= ClientMessage
;
951 replyev
.xclient
.window
= event
->xclient
.data
.l
[0];
952 replyev
.xclient
.format
= 32;
953 replyev
.xclient
.message_type
= _XA_XDE_REQUEST
;
954 replyev
.xclient
.data
.l
[0] = event
->xclient
.window
;
956 gdkev
.dragrequest
.u
.allflags
= 0;
957 gdkev
.dragrequest
.u
.flags
.protocol_version
= 0;
958 gdkev
.dragrequest
.u
.flags
.willaccept
= 1;
959 gdkev
.dragrequest
.u
.flags
.delete_data
= 0;
961 replyev
.xclient
.data
.l
[1] = gdkev
.dragrequest
.u
.allflags
;
962 replyev
.xclient
.data
.l
[2] = replyev
.xclient
.data
.l
[3] = 0;
963 replyev
.xclient
.data
.l
[4] = event
->xclient
.data
.l
[2];
964 XSendEvent(dpy
, replyev
.xclient
.window
, 0, NoEventMask
, &replyev
);
969 } else if (event
->xclient
.message_type
==_XA_DND_PROTOCOL
) {
970 WScreen
*scr
= wScreenForWindow(event
->xclient
.window
);
971 if (scr
&& wDockReceiveDNDDrop(scr
,event
))
972 goto redirect_message
;
973 #endif /* OFFIX_DND */
979 * Non-standard thing, but needed by OffiX DND.
980 * For when the icon frame gets a ClientMessage
981 * that should have gone to the icon_window.
983 if (XFindContext(dpy
, event
->xbutton
.window
, wWinContext
,
984 (XPointer
*)&desc
)!=XCNOENT
) {
985 struct WIcon
*icon
=NULL
;
987 if (desc
->parent_type
== WCLASS_MINIWINDOW
) {
988 icon
= (WIcon
*)desc
->parent
;
989 } else if (desc
->parent_type
== WCLASS_DOCK_ICON
990 || desc
->parent_type
== WCLASS_APPICON
) {
991 icon
= ((WAppIcon
*)desc
->parent
)->icon
;
993 if (icon
&& (wwin
=icon
->owner
)) {
994 if (wwin
->client_win
!=event
->xclient
.window
) {
995 event
->xclient
.window
= wwin
->client_win
;
996 XSendEvent(dpy
, wwin
->client_win
, False
, NoEventMask
,
1006 raiseWindow(WScreen
*scr
)
1010 scr
->autoRaiseTimer
= NULL
;
1012 wwin
= wWindowFor(scr
->autoRaiseWindow
);
1016 if (!wwin
->flags
.destroyed
) {
1017 wRaiseFrame(wwin
->frame
->core
);
1018 /* this is needed or a race condition will occur */
1025 handleEnterNotify(XEvent
*event
)
1028 WObjDescriptor
*desc
= NULL
;
1030 WScreen
*scr
= wScreenForRootWindow(event
->xcrossing
.root
);
1034 puts("got enter notify");
1037 if (XCheckTypedWindowEvent(dpy
, event
->xcrossing
.window
, LeaveNotify
,
1039 /* already left the window... */
1041 if (ev
.xcrossing
.mode
==event
->xcrossing
.mode
1042 && ev
.xcrossing
.detail
==event
->xcrossing
.detail
) {
1047 if (XFindContext(dpy
, event
->xcrossing
.window
, wWinContext
,
1048 (XPointer
*)&desc
)!=XCNOENT
) {
1049 if(desc
->handle_enternotify
)
1050 (*desc
->handle_enternotify
)(desc
, event
);
1053 /* enter to window */
1054 wwin
= wWindowFor(event
->xcrossing
.window
);
1056 if (wPreferences
.focus_mode
==WKF_POINTER
1057 && event
->xcrossing
.window
==event
->xcrossing
.root
) {
1058 wSetFocusTo(scr
, NULL
);
1060 if (wPreferences
.colormap_mode
==WKF_POINTER
) {
1061 wColormapInstallForWindow(scr
, NULL
);
1063 if (scr
->autoRaiseTimer
1064 && event
->xcrossing
.root
==event
->xcrossing
.window
) {
1065 WMDeleteTimerHandler(scr
->autoRaiseTimer
);
1066 scr
->autoRaiseTimer
= NULL
;
1069 /* set focus if in focus-follows-mouse mode and the event
1070 * is for the frame window and window doesn't have focus yet */
1071 if ((wPreferences
.focus_mode
==WKF_POINTER
1072 || wPreferences
.focus_mode
==WKF_SLOPPY
)
1073 && wwin
->frame
->core
->window
==event
->xcrossing
.window
1074 && !wwin
->flags
.focused
) {
1075 wSetFocusTo(scr
, wwin
);
1077 if (scr
->autoRaiseTimer
)
1078 WMDeleteTimerHandler(scr
->autoRaiseTimer
);
1079 scr
->autoRaiseTimer
= NULL
;
1081 if (wPreferences
.raise_delay
&& !wwin
->window_flags
.no_focusable
) {
1082 scr
->autoRaiseWindow
= wwin
->frame
->core
->window
;
1084 = WMAddTimerHandler(wPreferences
.raise_delay
,
1085 (WMCallback
*)raiseWindow
, scr
);
1088 /* Install colormap for window, if the colormap installation mode
1089 * is colormap_follows_mouse */
1090 if (wPreferences
.colormap_mode
==WKF_POINTER
) {
1091 if (wwin
->client_win
==event
->xcrossing
.window
)
1092 wColormapInstallForWindow(scr
, wwin
);
1094 wColormapInstallForWindow(scr
, NULL
);
1098 /* a little kluge to hide the clip balloon */
1099 if (!wPreferences
.flags
.noclip
&& scr
->flags
.clip_balloon_mapped
) {
1101 XUnmapWindow(dpy
, scr
->clip_balloon
);
1102 scr
->flags
.clip_balloon_mapped
= 0;
1104 if (desc
->parent_type
!=WCLASS_DOCK_ICON
1105 || scr
->clip_icon
!= desc
->parent
) {
1106 XUnmapWindow(dpy
, scr
->clip_balloon
);
1107 scr
->flags
.clip_balloon_mapped
= 0;
1112 if (event
->xcrossing
.window
== event
->xcrossing
.root
1113 && event
->xcrossing
.detail
== NotifyNormal
1114 && event
->xcrossing
.detail
!= NotifyInferior
1115 && wPreferences
.focus_mode
!= WKF_CLICK
) {
1117 wSetFocusTo(scr
, scr
->focused_window
);
1121 wBalloonEnteredObject(scr
, desc
);
1127 handleLeaveNotify(XEvent
*event
)
1129 WObjDescriptor
*desc
= NULL
;
1131 if (XFindContext(dpy
, event
->xcrossing
.window
, wWinContext
,
1132 (XPointer
*)&desc
)!=XCNOENT
) {
1133 if(desc
->handle_leavenotify
)
1134 (*desc
->handle_leavenotify
)(desc
, event
);
1136 if (event
->xcrossing
.window
== event
->xcrossing
.root
1137 && event
->xcrossing
.mode
== NotifyNormal
1138 && event
->xcrossing
.detail
!= NotifyInferior
1139 && wPreferences
.focus_mode
!= WKF_CLICK
) {
1141 WScreen
*scr
= wScreenForRootWindow(event
->xcrossing
.root
);
1143 wSetFocusTo(scr
, NULL
);
1150 handleShapeNotify(XEvent
*event
)
1152 XShapeEvent
*shev
= (XShapeEvent
*)event
;
1157 puts("got shape notify");
1160 while (XCheckTypedWindowEvent(dpy
, shev
->window
, event
->type
, &ev
)) {
1161 XShapeEvent
*sev
= (XShapeEvent
*)&ev
;
1163 if (sev
->kind
== ShapeBounding
) {
1164 if (sev
->shaped
== shev
->shaped
) {
1167 XPutBackEvent(dpy
, &ev
);
1173 wwin
= wWindowFor(shev
->window
);
1174 if (!wwin
|| shev
->kind
!= ShapeBounding
)
1177 if (!shev
->shaped
&& wwin
->flags
.shaped
) {
1179 wwin
->flags
.shaped
= 0;
1180 wWindowClearShape(wwin
);
1182 } else if (shev
->shaped
) {
1184 wwin
->flags
.shaped
= 1;
1185 wWindowSetShape(wwin
);
1192 handleColormapNotify(XEvent
*event
)
1196 Bool reinstall
= False
;
1198 wwin
= wWindowFor(event
->xcolormap
.window
);
1202 scr
= wwin
->screen_ptr
;
1206 if (event
->xcolormap
.new) {
1207 XWindowAttributes attr
;
1209 XGetWindowAttributes(dpy
, wwin
->client_win
, &attr
);
1211 if (wwin
== scr
->cmap_window
&& wwin
->cmap_window_no
== 0)
1212 scr
->current_colormap
= attr
.colormap
;
1215 } else if (event
->xcolormap
.state
== ColormapUninstalled
&&
1216 scr
->current_colormap
== event
->xcolormap
.colormap
) {
1218 /* some bastard app (like XV) removed our colormap */
1220 } else if (event
->xcolormap
.state
== ColormapInstalled
&&
1221 scr
->current_colormap
== event
->xcolormap
.colormap
) {
1223 /* someone has put our colormap back */
1227 } while (XCheckTypedEvent(dpy
, ColormapNotify
, event
)
1228 && ((wwin
= wWindowFor(event
->xcolormap
.window
)) || 1));
1230 if (reinstall
&& scr
->current_colormap
!=None
) {
1232 XInstallColormap(dpy
, scr
->current_colormap
);
1239 handleFocusIn(XEvent
*event
)
1244 * For applications that like stealing the focus.
1246 while (XCheckTypedEvent(dpy
, FocusIn
, event
));
1247 saveTimestamp(event
);
1248 if (event
->xfocus
.mode
== NotifyUngrab
1249 || event
->xfocus
.mode
== NotifyGrab
1250 || event
->xfocus
.detail
> NotifyNonlinearVirtual
) {
1254 wwin
= wWindowFor(event
->xfocus
.window
);
1255 if (wwin
&& !wwin
->flags
.focused
) {
1256 if (wwin
->flags
.mapped
)
1257 wSetFocusTo(wwin
->screen_ptr
, wwin
);
1259 wSetFocusTo(wwin
->screen_ptr
, NULL
);
1261 WScreen
*scr
= wScreenForWindow(event
->xfocus
.window
);
1263 wSetFocusTo(scr
, NULL
);
1269 windowUnderPointer(WScreen
*scr
)
1275 if (XQueryPointer(dpy
, scr
->root_win
, &bar
, &win
, &foo
, &foo
, &foo
, &foo
,
1277 return wWindowFor(win
);
1282 handleKeyPress(XEvent
*event
)
1284 WScreen
*scr
= wScreenForRootWindow(event
->xkey
.root
);
1285 WWindow
*wwin
= scr
->focused_window
;
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
);
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);
1492 case WKBD_NEXTWSLAYER
:
1493 case WKBD_PREVWSLAYER
:
1497 row
= scr
->current_workspace
/10;
1498 column
= scr
->current_workspace
%10;
1500 if (command
==WKBD_NEXTWSLAYER
) {
1501 if ((row
+1)*10 < scr
->workspace_count
)
1502 wWorkspaceChange(scr
, column
+(row
+1)*10);
1505 wWorkspaceChange(scr
, column
+(row
-1)*10);
1509 case WKBD_CLIPLOWER
:
1510 if (!wPreferences
.flags
.noclip
)
1511 wDockLower(scr
->workspaces
[scr
->current_workspace
]->clip
);
1513 case WKBD_CLIPRAISE
:
1514 if (!wPreferences
.flags
.noclip
)
1515 wDockRaise(scr
->workspaces
[scr
->current_workspace
]->clip
);
1517 case WKBD_CLIPRAISELOWER
:
1518 if (!wPreferences
.flags
.noclip
)
1519 wDockRaiseLower(scr
->workspaces
[scr
->current_workspace
]->clip
);
1526 handleMotionNotify(XEvent
*event
)
1529 WScreen
*scr
= wScreenForRootWindow(event
->xmotion
.root
);
1531 if (wPreferences
.scrollable_menus
) {
1532 if (event
->xmotion
.x_root
<= 1 ||
1533 event
->xmotion
.x_root
>= (scr
->scr_width
- 2) ||
1534 event
->xmotion
.y_root
<= 1 ||
1535 event
->xmotion
.y_root
>= (scr
->scr_height
- 2)) {
1538 puts("pointer at screen edge");
1541 menu
= wMenuUnderPointer(scr
);
1543 wMenuScroll(menu
, event
);