1
/* event.c- event loop and handling
3
* Window Maker window manager
5
* Copyright (c) 1997-2003 Alfredo K. Kojima
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 2 of the License, or
10
* (at your option) any later version.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
35
#include <X11/Xutil.h>
37
# include <X11/extensions/shape.h>
43
#ifdef KEEP_XKB_LOCK_STATUS
44
#include <X11/XKBlib.h>
45
#endif /* KEEP_XKB_LOCK_STATUS */
47
#include "WindowMaker.h"
53
#include "application.h"
56
#include "workspace.h"
59
#include "properties.h"
67
/******** Global Variables **********/
68
extern XContext wWinContext;
69
extern XContext wVEdgeContext;
71
extern Cursor wCursor[WCUR_LAST];
73
extern WShortKey wKeyBindings[WKBD_LAST];
74
extern int wScreenCount;
75
extern Time LastTimestamp;
76
extern Time LastFocusChange;
78
extern WPreferences wPreferences;
80
#define MOD_MASK wPreferences.modifier_mask
82
extern Atom _XA_WM_COLORMAP_NOTIFY;
84
extern Atom _XA_WM_CHANGE_STATE;
85
extern Atom _XA_WM_DELETE_WINDOW;
86
extern Atom _XA_GNUSTEP_WM_ATTR;
87
extern Atom _XA_GNUSTEP_WM_MINIATURIZE_WINDOW;
88
extern Atom _XA_GNUSTEP_TITLEBAR_STATE;
89
extern Atom _XA_WINDOWMAKER_WM_FUNCTION;
90
extern Atom _XA_WINDOWMAKER_COMMAND;
94
extern Bool wShapeSupported;
95
extern int wShapeEventBase;
98
#ifdef KEEP_XKB_LOCK_STATUS
99
extern int wXkbEventBase;
103
extern char WDelayedActionSet;
106
/************ Local stuff ***********/
109
static void saveTimestamp(XEvent *event);
110
static void handleColormapNotify();
111
static void handleMapNotify();
112
static void handleUnmapNotify();
113
static void handleButtonPress();
114
static void handleExpose();
115
static void handleDestroyNotify();
116
static void handleConfigureRequest();
117
static void handleMapRequest();
118
static void handlePropertyNotify();
119
static void handleEnterNotify();
120
static void handleLeaveNotify();
121
static void handleExtensions();
122
static void handleClientMessage();
123
static void handleKeyPress();
124
static void handleFocusIn();
125
static void handleMotionNotify();
126
static void handleVisibilityNotify();
130
static void handleShapeNotify();
133
/* called from the signal handler */
134
void NotifyDeadProcess(pid_t pid, unsigned char status);
136
/* real dead process handler */
137
static void handleDeadProcess(void *foo);
140
typedef struct DeadProcesses {
142
unsigned char exit_status;
145
/* stack of dead processes */
146
static DeadProcesses deadProcesses[MAX_DEAD_PROCESSES];
147
static int deadProcessPtr=0;
150
typedef struct DeathHandler {
151
WDeathHandler *callback;
156
static WMArray *deathHandlers=NULL;
161
wAddDeathHandler(pid_t pid, WDeathHandler *callback, void *cdata)
163
DeathHandler *handler;
165
handler = malloc(sizeof(DeathHandler));
170
handler->callback = callback;
171
handler->client_data = cdata;
174
deathHandlers = WMCreateArrayWithDestructor(8, wfree);
176
WMAddToArray(deathHandlers, handler);
184
wDeleteDeathHandler(WMagicNumber id)
186
DeathHandler *handler=(DeathHandler*)id;
188
if (!handler || !deathHandlers)
191
/* array destructor will call wfree(handler) */
192
WMRemoveFromArray(deathHandlers, handler);
197
DispatchEvent(XEvent *event)
200
handleDeadProcess(NULL);
202
if (WCHECK_STATE(WSTATE_NEED_EXIT)) {
203
WCHANGE_STATE(WSTATE_EXITING);
204
/* received SIGTERM */
206
* WMHandleEvent() can't be called from anything
207
* executed inside here, or we can get in a infinite
210
Shutdown(WSExitMode);
212
} else if (WCHECK_STATE(WSTATE_NEED_RESTART)) {
213
WCHANGE_STATE(WSTATE_RESTARTING);
215
Shutdown(WSRestartPreparationMode);
216
/* received SIGHUP */
218
} else if (WCHECK_STATE(WSTATE_NEED_REREAD)) {
219
WCHANGE_STATE(WSTATE_NORMAL);
220
wDefaultsCheckDomains("bla");
223
/* for the case that all that is wanted to be dispatched is
228
saveTimestamp(event);
229
switch (event->type) {
231
handleMapRequest(event);
235
handleKeyPress(event);
239
handleMotionNotify(event);
242
case ConfigureRequest:
243
handleConfigureRequest(event);
247
handleDestroyNotify(event);
251
handleMapNotify(event);
255
handleUnmapNotify(event);
259
handleButtonPress(event);
267
handlePropertyNotify(event);
271
handleEnterNotify(event);
275
handleLeaveNotify(event);
279
handleClientMessage(event);
283
handleColormapNotify(event);
287
if (event->xmapping.request == MappingKeyboard
288
|| event->xmapping.request == MappingModifier)
289
XRefreshKeyboardMapping(&event->xmapping);
293
handleFocusIn(event);
296
case VisibilityNotify:
297
handleVisibilityNotify(event);
300
handleExtensions(event);
307
*----------------------------------------------------------------------
309
* Processes X and internal events indefinitely.
315
* The LastTimestamp global variable is updated.
316
*----------------------------------------------------------------------
324
WMNextEvent(dpy, &event);
325
WMHandleEvent(&event);
331
*----------------------------------------------------------------------
332
* ProcessPendingEvents --
333
* Processes the events that are currently pending (at the time
334
* this function is called) in the display's queue.
337
* After the pending events that were present at the function call
341
* Many -- whatever handling events may involve.
343
*----------------------------------------------------------------------
346
ProcessPendingEvents()
353
/* Take a snapshot of the event count in the queue */
354
count = XPending(dpy);
356
while (count>0 && XPending(dpy)) {
357
WMNextEvent(dpy, &event);
358
WMHandleEvent(&event);
365
IsDoubleClick(WScreen *scr, XEvent *event)
367
if ((scr->last_click_time>0) &&
368
(event->xbutton.time-scr->last_click_time<=wPreferences.dblclick_time)
369
&& (event->xbutton.button == scr->last_click_button)
370
&& (event->xbutton.window == scr->last_click_window)) {
372
scr->flags.next_click_is_not_double = 1;
373
scr->last_click_time = 0;
374
scr->last_click_window = event->xbutton.window;
383
NotifyDeadProcess(pid_t pid, unsigned char status)
385
if (deadProcessPtr>=MAX_DEAD_PROCESSES-1) {
386
wwarning("stack overflow: too many dead processes");
389
/* stack the process to be handled later,
390
* as this is called from the signal handler */
391
deadProcesses[deadProcessPtr].pid = pid;
392
deadProcesses[deadProcessPtr].exit_status = status;
398
handleDeadProcess(void *foo)
403
for (i=0; i<deadProcessPtr; i++) {
404
wWindowDeleteSavedStatesForPID(deadProcesses[i].pid);
407
if (!deathHandlers) {
412
/* get the pids on the queue and call handlers */
413
while (deadProcessPtr>0) {
416
for (i = WMGetArrayItemCount(deathHandlers)-1; i >= 0; i--) {
417
tmp = WMGetFromArray(deathHandlers, i);
421
if (tmp->pid == deadProcesses[deadProcessPtr].pid) {
422
(*tmp->callback)(tmp->pid,
423
deadProcesses[deadProcessPtr].exit_status,
425
wDeleteDeathHandler(tmp);
433
saveTimestamp(XEvent *event)
436
* Never save CurrentTime as LastTimestamp because CurrentTime
437
* it's not a real timestamp (it's the 0L constant)
440
switch (event->type) {
443
LastTimestamp = event->xbutton.time;
447
LastTimestamp = event->xkey.time;
450
LastTimestamp = event->xmotion.time;
453
LastTimestamp = event->xproperty.time;
457
LastTimestamp = event->xcrossing.time;
460
LastTimestamp = event->xselectionclear.time;
462
case SelectionRequest:
463
LastTimestamp = event->xselectionrequest.time;
465
case SelectionNotify:
466
LastTimestamp = event->xselection.time;
468
wXDNDProcessSelection(event);
476
matchWindow(void *item, void *cdata)
478
return (((WFakeGroupLeader*)item)->origLeader == (Window)cdata);
483
handleExtensions(XEvent *event)
485
#ifdef KEEP_XKB_LOCK_STATUS
487
xkbevent = (XkbEvent *)event;
488
#endif /*KEEP_XKB_LOCK_STATUS*/
490
if (wShapeSupported && event->type == (wShapeEventBase+ShapeNotify)) {
491
handleShapeNotify(event);
494
#ifdef KEEP_XKB_LOCK_STATUS
495
if (wPreferences.modelock && (xkbevent->type == wXkbEventBase)){
496
handleXkbIndicatorStateNotify(event);
498
#endif /*KEEP_XKB_LOCK_STATUS*/
503
handleMapRequest(XEvent *ev)
507
Window window = ev->xmaprequest.window;
510
printf("got map request for %x\n", (unsigned)window);
512
if ((wwin = wWindowFor(window))) {
513
if (wwin->flags.shaded) {
514
wUnshadeWindow(wwin);
516
/* deiconify window */
517
if (wwin->flags.miniaturized) {
518
wDeiconifyWindow(wwin);
519
} else if (wwin->flags.hidden) {
520
WApplication *wapp = wApplicationOf(wwin->main_window);
521
/* go to the last workspace that the user worked on the app */
523
wWorkspaceChange(wwin->screen_ptr, wapp->last_workspace);
525
wUnhideApplication(wapp, False, False);
530
scr = wScreenForRootWindow(ev->xmaprequest.parent);
532
wwin = wManageWindow(scr, window);
535
* This is to let the Dock know that the application it launched
536
* has already been mapped (eg: it has finished launching).
537
* It is not necessary for normally docked apps, but is needed for
538
* apps that were forcedly docked (like with dockit).
540
if (scr->last_dock) {
541
if (wwin && wwin->main_window!=None && wwin->main_window!=window)
542
wDockTrackWindowLaunch(scr->last_dock, wwin->main_window);
544
wDockTrackWindowLaunch(scr->last_dock, window);
548
wClientSetState(wwin, NormalState, None);
549
if (wwin->flags.maximized) {
550
wMaximizeWindow(wwin, wwin->flags.maximized);
552
if (wwin->flags.shaded) {
553
wwin->flags.shaded = 0;
554
wwin->flags.skip_next_animation = 1;
557
if (wwin->flags.miniaturized) {
558
wwin->flags.miniaturized = 0;
559
wwin->flags.skip_next_animation = 1;
560
wIconifyWindow(wwin);
562
if (wwin->flags.hidden) {
563
WApplication *wapp = wApplicationOf(wwin->main_window);
565
wwin->flags.hidden = 0;
566
wwin->flags.skip_next_animation = 1;
568
wHideApplication(wapp);
576
handleDestroyNotify(XEvent *event)
580
Window window = event->xdestroywindow.window;
581
WScreen *scr = wScreenForRootWindow(event->xdestroywindow.event);
585
printf("got destroy notify\n");
587
wwin = wWindowFor(window);
589
wUnmanageWindow(wwin, False, True);
593
while ((index = WMFindInArray(scr->fakeGroupLeaders, matchWindow,
594
(void*)window)) != WANotFound) {
595
WFakeGroupLeader *fPtr;
597
fPtr = WMGetFromArray(scr->fakeGroupLeaders, index);
598
if (fPtr->retainCount > 0) {
600
if (fPtr->retainCount==0 && fPtr->leader!=None) {
601
XDestroyWindow(dpy, fPtr->leader);
606
fPtr->origLeader = None;
610
app = wApplicationOf(window);
612
if (window == app->main_window) {
614
wwin = app->main_window_desc->screen_ptr->focused_window;
616
if (wwin->main_window == window) {
617
wwin->main_window = None;
622
wApplicationDestroy(app);
629
handleExpose(XEvent *event)
631
WObjDescriptor *desc;
635
printf("got expose\n");
637
while (XCheckTypedWindowEvent(dpy, event->xexpose.window, Expose, &ev));
639
if (XFindContext(dpy, event->xexpose.window, wWinContext,
640
(XPointer *)&desc)==XCNOENT) {
644
if (desc->handle_expose) {
645
(*desc->handle_expose)(desc, event);
650
executeButtonAction(WScreen *scr, XEvent *event, int action)
653
case WA_SELECT_WINDOWS:
654
wUnselectWindows(scr);
655
wSelectWindows(scr, event);
657
case WA_OPEN_APPMENU:
658
OpenRootMenu(scr, event->xbutton.x_root, event->xbutton.y_root, False);
660
if (scr->root_menu) {
661
if (scr->root_menu->brother->flags.mapped)
662
event->xbutton.window = scr->root_menu->brother->frame->core->window;
664
event->xbutton.window = scr->root_menu->frame->core->window;
667
case WA_OPEN_WINLISTMENU:
668
OpenSwitchMenu(scr, event->xbutton.x_root, event->xbutton.y_root, False);
669
if (scr->switch_menu) {
670
if (scr->switch_menu->brother->flags.mapped)
671
event->xbutton.window = scr->switch_menu->brother->frame->core->window;
673
event->xbutton.window = scr->switch_menu->frame->core->window;
684
handleButtonPress(XEvent *event)
686
WObjDescriptor *desc;
690
printf("got button press\n");
692
scr = wScreenForRootWindow(event->xbutton.root);
700
if (event->xbutton.window==scr->root_win) {
701
if (event->xbutton.button==Button1 &&
702
wPreferences.mouse_button1!=WA_NONE) {
703
executeButtonAction(scr, event, wPreferences.mouse_button1);
704
} else if (event->xbutton.button==Button2 &&
705
wPreferences.mouse_button2!=WA_NONE) {
706
executeButtonAction(scr, event, wPreferences.mouse_button2);
707
} else if (event->xbutton.button==Button3 &&
708
wPreferences.mouse_button3!=WA_NONE) {
709
executeButtonAction(scr, event, wPreferences.mouse_button3);
710
} else if (event->xbutton.button==Button4 &&
711
wPreferences.mouse_wheel!=WA_NONE) {
712
wWorkspaceRelativeChange(scr, 1);
713
} else if (event->xbutton.button==Button5 &&
714
wPreferences.mouse_wheel!=WA_NONE) {
715
wWorkspaceRelativeChange(scr, -1);
721
if (XFindContext(dpy, event->xbutton.subwindow, wWinContext,
722
(XPointer *)&desc)==XCNOENT) {
723
if (XFindContext(dpy, event->xbutton.window, wWinContext,
724
(XPointer *)&desc)==XCNOENT) {
729
if (desc->parent_type == WCLASS_WINDOW) {
732
if (event->xbutton.state & MOD_MASK) {
733
XAllowEvents(dpy, AsyncPointer, CurrentTime);
736
/* if (wPreferences.focus_mode == WKF_CLICK) {*/
737
if (wPreferences.ignore_focus_click) {
738
XAllowEvents(dpy, AsyncPointer, CurrentTime);
740
XAllowEvents(dpy, ReplayPointer, CurrentTime);
743
} else if (desc->parent_type == WCLASS_APPICON
744
|| desc->parent_type == WCLASS_MINIWINDOW
745
|| desc->parent_type == WCLASS_DOCK_ICON) {
746
if (event->xbutton.state & MOD_MASK) {
748
XAllowEvents(dpy, AsyncPointer, CurrentTime);
753
if (desc->handle_mousedown!=NULL) {
754
(*desc->handle_mousedown)(desc, event);
757
/* save double-click information */
758
if (scr->flags.next_click_is_not_double) {
759
scr->flags.next_click_is_not_double = 0;
761
scr->last_click_time = event->xbutton.time;
762
scr->last_click_button = event->xbutton.button;
763
scr->last_click_window = event->xbutton.window;
769
handleMapNotify(XEvent *event)
775
wwin = wWindowFor(event->xmap.event);
776
if (wwin && wwin->client_win == event->xmap.event) {
777
if (wwin->flags.miniaturized) {
778
wDeiconifyWindow(wwin);
782
wClientSetState(wwin, NormalState, None);
790
handleUnmapNotify(XEvent *event)
794
Bool withdraw = False;
796
printf("got unmap\n");
798
/* only process windows with StructureNotify selected
799
* (ignore SubstructureNotify) */
800
wwin = wWindowFor(event->xunmap.window);
804
/* whether the event is a Withdrawal request */
805
if (event->xunmap.event == wwin->screen_ptr->root_win
806
&& event->xunmap.send_event)
809
if (wwin->client_win != event->xunmap.event && !withdraw)
812
if (!wwin->flags.mapped && !withdraw
813
&& wwin->frame->workspace == wwin->screen_ptr->current_workspace
814
&& !wwin->flags.miniaturized && !wwin->flags.hidden)
818
XUnmapWindow(dpy, wwin->frame->core->window);
819
wwin->flags.mapped = 0;
821
/* check if the window was destroyed */
822
if (XCheckTypedWindowEvent(dpy, wwin->client_win, DestroyNotify,&ev)) {
825
Bool reparented = False;
827
if (XCheckTypedWindowEvent(dpy, wwin->client_win, ReparentNotify, &ev))
830
/* withdraw window */
831
wwin->flags.mapped = 0;
833
wClientSetState(wwin, WithdrawnState, None);
835
/* if the window was reparented, do not reparent it back to the
837
wUnmanageWindow(wwin, !reparented, False);
844
handleConfigureRequest(XEvent *event)
848
printf("got configure request\n");
850
if (!(wwin=wWindowFor(event->xconfigurerequest.window))) {
852
* Configure request for unmapped window
854
wClientConfigure(NULL, &(event->xconfigurerequest));
856
wClientConfigure(wwin, &(event->xconfigurerequest));
862
handlePropertyNotify(XEvent *event)
871
printf("got property notify\n");
873
if ((wwin=wWindowFor(event->xproperty.window))) {
874
if (!XGetGeometry(dpy, wwin->client_win, &jr, &ji, &ji,
875
&ju, &ju, &ju, &ju)) {
878
wClientCheckProperty(wwin, &event->xproperty);
880
wapp = wApplicationOf(event->xproperty.window);
882
wClientCheckProperty(wapp->main_window_desc, &event->xproperty);
885
scr = wScreenForWindow(event->xproperty.window);
890
handleClientMessage(XEvent *event)
893
WObjDescriptor *desc;
895
printf("got client message\n");
897
/* handle transition from Normal to Iconic state */
898
if (event->xclient.message_type == _XA_WM_CHANGE_STATE
899
&& event->xclient.format == 32
900
&& event->xclient.data.l[0] == IconicState) {
902
wwin = wWindowFor(event->xclient.window);
904
if (!wwin->flags.miniaturized)
905
wIconifyWindow(wwin);
906
} else if (event->xclient.message_type == _XA_WM_COLORMAP_NOTIFY
907
&& event->xclient.format == 32) {
908
WScreen *scr = wScreenSearchForRootWindow(event->xclient.window);
913
if (event->xclient.data.l[1] == 1) { /* starting */
914
wColormapAllowClientInstallation(scr, True);
915
} else { /* stopping */
916
wColormapAllowClientInstallation(scr, False);
918
} else if (event->xclient.message_type == _XA_WINDOWMAKER_COMMAND) {
920
wDefaultsCheckDomains("bla");
922
} else if (event->xclient.message_type == _XA_WINDOWMAKER_WM_FUNCTION) {
925
wapp = wApplicationOf(event->xclient.window);
927
switch (event->xclient.data.l[0]) {
928
case WMFHideOtherApplications:
929
wHideOtherApplications(wapp->main_window_desc);
933
case WMFHideApplication:
934
wHideApplication(wapp);
940
wwin = wWindowFor(event->xclient.window);
942
switch (event->xclient.data.l[0]) {
943
case WMFHideOtherApplications:
944
wHideOtherApplications(wwin);
947
case WMFHideApplication:
948
wHideApplication(wApplicationOf(wwin->main_window));
953
} else if (event->xclient.message_type == _XA_GNUSTEP_WM_ATTR) {
954
wwin = wWindowFor(event->xclient.window);
956
switch (event->xclient.data.l[0]) {
957
case GSWindowLevelAttr:
959
int level = (int)event->xclient.data.l[1];
961
if (WINDOW_LEVEL(wwin) != level) {
962
ChangeStackingLevel(wwin->frame->core, level);
967
} else if (event->xclient.message_type == _XA_GNUSTEP_TITLEBAR_STATE) {
968
wwin = wWindowFor(event->xclient.window);
970
switch (event->xclient.data.l[0]) {
971
case WMTitleBarNormal:
972
wFrameWindowChangeState(wwin->frame, WS_UNFOCUSED);
975
wFrameWindowChangeState(wwin->frame, WS_PFOCUSED);
978
wFrameWindowChangeState(wwin->frame, WS_FOCUSED);
982
} else if (wNETWMProcessClientMessage(&event->xclient)) {
986
} else if (wXDNDProcessClientMessage(&event->xclient)) {
991
* Non-standard thing, but needed by OffiX DND.
992
* For when the icon frame gets a ClientMessage
993
* that should have gone to the icon_window.
995
if (XFindContext(dpy, event->xbutton.window, wWinContext,
996
(XPointer *)&desc)!=XCNOENT) {
997
struct WIcon *icon=NULL;
999
if (desc->parent_type == WCLASS_MINIWINDOW) {
1000
icon = (WIcon*)desc->parent;
1001
} else if (desc->parent_type == WCLASS_DOCK_ICON
1002
|| desc->parent_type == WCLASS_APPICON) {
1003
icon = ((WAppIcon*)desc->parent)->icon;
1005
if (icon && (wwin=icon->owner)) {
1006
if (wwin->client_win!=event->xclient.window) {
1007
event->xclient.window = wwin->client_win;
1008
XSendEvent(dpy, wwin->client_win, False, NoEventMask,
1018
raiseWindow(WScreen *scr)
1022
scr->autoRaiseTimer = NULL;
1024
wwin = wWindowFor(scr->autoRaiseWindow);
1028
if (!wwin->flags.destroyed && wwin->flags.focused) {
1029
wRaiseFrame(wwin->frame->core);
1030
/* this is needed or a race condition will occur */
1037
handleEnterNotify(XEvent *event)
1040
WObjDescriptor *desc = NULL;
1041
#ifdef VIRTUAL_DESKTOP
1042
void (*vdHandler)(XEvent * event);
1045
WScreen *scr = wScreenForRootWindow(event->xcrossing.root);
1047
printf("got enter notify\n");
1050
#ifdef VIRTUAL_DESKTOP
1051
if (XFindContext(dpy, event->xcrossing.window, wVEdgeContext,
1052
(XPointer *)&vdHandler)!=XCNOENT) {
1053
(*vdHandler)(event);
1057
if (XCheckTypedWindowEvent(dpy, event->xcrossing.window, LeaveNotify,
1059
/* already left the window... */
1061
if (ev.xcrossing.mode==event->xcrossing.mode
1062
&& ev.xcrossing.detail==event->xcrossing.detail) {
1067
if (XFindContext(dpy, event->xcrossing.window, wWinContext,
1068
(XPointer *)&desc)!=XCNOENT) {
1069
if(desc->handle_enternotify)
1070
(*desc->handle_enternotify)(desc, event);
1073
/* enter to window */
1074
wwin = wWindowFor(event->xcrossing.window);
1076
if (wPreferences.colormap_mode==WCM_POINTER) {
1077
wColormapInstallForWindow(scr, NULL);
1079
if (scr->autoRaiseTimer
1080
&& event->xcrossing.root==event->xcrossing.window) {
1081
WMDeleteTimerHandler(scr->autoRaiseTimer);
1082
scr->autoRaiseTimer = NULL;
1085
/* set auto raise timer even if in focus-follows-mouse mode
1086
* and the event is for the frame window, even if the window
1087
* has focus already. useful if you move the pointer from a focused
1088
* window to the root window and back pretty fast
1090
* set focus if in focus-follows-mouse mode and the event
1091
* is for the frame window and window doesn't have focus yet */
1092
if (wPreferences.focus_mode==WKF_SLOPPY
1093
&& wwin->frame->core->window==event->xcrossing.window
1094
&& !scr->flags.doing_alt_tab) {
1096
if (!wwin->flags.focused && !WFLAGP(wwin, no_focusable))
1097
wSetFocusTo(scr, wwin);
1099
if (scr->autoRaiseTimer)
1100
WMDeleteTimerHandler(scr->autoRaiseTimer);
1101
scr->autoRaiseTimer = NULL;
1103
if (wPreferences.raise_delay && !WFLAGP(wwin, no_focusable)) {
1104
scr->autoRaiseWindow = wwin->frame->core->window;
1106
= WMAddTimerHandler(wPreferences.raise_delay,
1107
(WMCallback*)raiseWindow, scr);
1110
/* Install colormap for window, if the colormap installation mode
1111
* is colormap_follows_mouse */
1112
if (wPreferences.colormap_mode==WCM_POINTER) {
1113
if (wwin->client_win==event->xcrossing.window)
1114
wColormapInstallForWindow(scr, wwin);
1116
wColormapInstallForWindow(scr, NULL);
1120
/* a little kluge to hide the clip balloon */
1121
if (!wPreferences.flags.noclip && scr->flags.clip_balloon_mapped) {
1123
XUnmapWindow(dpy, scr->clip_balloon);
1124
scr->flags.clip_balloon_mapped = 0;
1126
if (desc->parent_type!=WCLASS_DOCK_ICON
1127
|| scr->clip_icon != desc->parent) {
1128
XUnmapWindow(dpy, scr->clip_balloon);
1129
scr->flags.clip_balloon_mapped = 0;
1134
if (event->xcrossing.window == event->xcrossing.root
1135
&& event->xcrossing.detail == NotifyNormal
1136
&& event->xcrossing.detail != NotifyInferior
1137
&& wPreferences.focus_mode != WKF_CLICK) {
1139
wSetFocusTo(scr, scr->focused_window);
1143
wBalloonEnteredObject(scr, desc);
1149
handleLeaveNotify(XEvent *event)
1151
WObjDescriptor *desc = NULL;
1153
if (XFindContext(dpy, event->xcrossing.window, wWinContext,
1154
(XPointer *)&desc)!=XCNOENT) {
1155
if(desc->handle_leavenotify)
1156
(*desc->handle_leavenotify)(desc, event);
1163
handleShapeNotify(XEvent *event)
1165
XShapeEvent *shev = (XShapeEvent*)event;
1169
printf("got shape notify\n");
1171
while (XCheckTypedWindowEvent(dpy, shev->window, event->type, &ev)) {
1172
XShapeEvent *sev = (XShapeEvent*)&ev;
1174
if (sev->kind == ShapeBounding) {
1175
if (sev->shaped == shev->shaped) {
1178
XPutBackEvent(dpy, &ev);
1184
wwin = wWindowFor(shev->window);
1185
if (!wwin || shev->kind != ShapeBounding)
1188
if (!shev->shaped && wwin->flags.shaped) {
1190
wwin->flags.shaped = 0;
1191
wWindowClearShape(wwin);
1193
} else if (shev->shaped) {
1195
wwin->flags.shaped = 1;
1196
wWindowSetShape(wwin);
1201
#ifdef KEEP_XKB_LOCK_STATUS
1202
/* please help ]d if you know what to do */
1203
handleXkbIndicatorStateNotify(XEvent *event)
1207
XkbStateRec staterec;
1210
for (i=0; i<wScreenCount; i++) {
1211
scr = wScreenWithNumber(i);
1212
wwin = scr->focused_window;
1213
if (wwin && wwin->flags.focused) {
1214
XkbGetState(dpy,XkbUseCoreKbd,&staterec);
1215
if (wwin->frame->languagemode != staterec.group) {
1216
wwin->frame->last_languagemode = wwin->frame->languagemode;
1217
wwin->frame->languagemode = staterec.group;
1219
#ifdef XKB_BUTTON_HINT
1220
if (wwin->frame->titlebar) {
1221
wFrameWindowPaint(wwin->frame);
1227
#endif /*KEEP_XKB_LOCK_STATUS*/
1230
handleColormapNotify(XEvent *event)
1234
Bool reinstall = False;
1236
wwin = wWindowFor(event->xcolormap.window);
1240
scr = wwin->screen_ptr;
1244
if (event->xcolormap.new) {
1245
XWindowAttributes attr;
1247
XGetWindowAttributes(dpy, wwin->client_win, &attr);
1249
if (wwin == scr->cmap_window && wwin->cmap_window_no == 0)
1250
scr->current_colormap = attr.colormap;
1253
} else if (event->xcolormap.state == ColormapUninstalled &&
1254
scr->current_colormap == event->xcolormap.colormap) {
1256
/* some bastard app (like XV) removed our colormap */
1258
* can't enforce or things like xscreensaver wont work
1261
} else if (event->xcolormap.state == ColormapInstalled &&
1262
scr->current_colormap == event->xcolormap.colormap) {
1264
/* someone has put our colormap back */
1268
} while (XCheckTypedEvent(dpy, ColormapNotify, event)
1269
&& ((wwin = wWindowFor(event->xcolormap.window)) || 1));
1271
if (reinstall && scr->current_colormap!=None) {
1272
if (!scr->flags.colormap_stuff_blocked)
1273
XInstallColormap(dpy, scr->current_colormap);
1280
handleFocusIn(XEvent *event)
1285
* For applications that like stealing the focus.
1287
while (XCheckTypedEvent(dpy, FocusIn, event));
1288
saveTimestamp(event);
1289
if (event->xfocus.mode == NotifyUngrab
1290
|| event->xfocus.mode == NotifyGrab
1291
|| event->xfocus.detail > NotifyNonlinearVirtual) {
1295
wwin = wWindowFor(event->xfocus.window);
1296
if (wwin && !wwin->flags.focused) {
1297
if (wwin->flags.mapped)
1298
wSetFocusTo(wwin->screen_ptr, wwin);
1300
wSetFocusTo(wwin->screen_ptr, NULL);
1302
WScreen *scr = wScreenForWindow(event->xfocus.window);
1304
wSetFocusTo(scr, NULL);
1310
windowUnderPointer(WScreen *scr)
1316
if (XQueryPointer(dpy, scr->root_win, &bar, &win, &foo, &foo, &foo, &foo,
1318
return wWindowFor(win);
1323
static int CheckFullScreenWindowFocused(WScreen *scr)
1325
if (scr->focused_window && scr->focused_window->flags.fullscreen)
1333
handleKeyPress(XEvent *event)
1335
WScreen *scr = wScreenForRootWindow(event->xkey.root);
1336
WWindow *wwin = scr->focused_window;
1339
int command=-1, index;
1340
#ifdef KEEP_XKB_LOCK_STATUS
1341
XkbStateRec staterec;
1342
#endif /*KEEP_XKB_LOCK_STATUS*/
1344
/* ignore CapsLock */
1345
modifiers = event->xkey.state & ValidModMask;
1347
for (i=0; i<WKBD_LAST; i++) {
1348
if (wKeyBindings[i].keycode==0)
1351
if (wKeyBindings[i].keycode==event->xkey.keycode
1352
&& (/*wKeyBindings[i].modifier==0
1353
||*/ wKeyBindings[i].modifier==modifiers)) {
1367
if (!wRootMenuPerformShortcut(event)) {
1369
static int dontLoop = 0;
1371
if (dontLoop > 10) {
1372
wwarning("problem with key event processing code");
1376
/* if the focused window is an internal window, try redispatching
1377
* the event to the managed window, as it can be a WINGs window */
1378
if (wwin && wwin->flags.internal_window
1379
&& wwin->client_leader!=None) {
1380
/* client_leader contains the WINGs toplevel */
1381
event->xany.window = wwin->client_leader;
1382
WMHandleEvent(event);
1389
#define ISMAPPED(w) ((w) && !(w)->flags.miniaturized && ((w)->flags.mapped || (w)->flags.shaded))
1390
#define ISFOCUSED(w) ((w) && (w)->flags.focused)
1395
/*OpenRootMenu(scr, event->xkey.x_root, event->xkey.y_root, True);*/
1396
if (!CheckFullScreenWindowFocused(scr)) {
1397
WMRect rect = wGetRectForHead(scr, wGetHeadForPointerLocation(scr));
1398
OpenRootMenu(scr, rect.pos.x + rect.size.width/2, rect.pos.y + rect.size.height/2, True);
1401
case WKBD_WINDOWLIST:
1402
if (!CheckFullScreenWindowFocused(scr)) {
1403
WMRect rect = wGetRectForHead(scr, wGetHeadForPointerLocation(scr));
1404
OpenSwitchMenu(scr, rect.pos.x + rect.size.width/2, rect.pos.y + rect.size.height/2, True);
1408
case WKBD_WINDOWMENU:
1409
if (ISMAPPED(wwin) && ISFOCUSED(wwin))
1410
OpenWindowMenu(wwin, wwin->frame_x,
1411
wwin->frame_y+wwin->frame->top_width, True);
1413
case WKBD_MINIATURIZE:
1414
if (ISMAPPED(wwin) && ISFOCUSED(wwin)
1415
&& !WFLAGP(wwin, no_miniaturizable)) {
1416
CloseWindowMenu(scr);
1418
if (wwin->protocols.MINIATURIZE_WINDOW)
1419
wClientSendProtocol(wwin, _XA_GNUSTEP_WM_MINIATURIZE_WINDOW,
1420
event->xbutton.time);
1422
wIconifyWindow(wwin);
1427
if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1428
WApplication *wapp = wApplicationOf(wwin->main_window);
1429
CloseWindowMenu(scr);
1431
if (wapp && !WFLAGP(wapp->main_window_desc, no_appicon)) {
1432
wHideApplication(wapp);
1436
case WKBD_HIDE_OTHERS:
1437
if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1438
CloseWindowMenu(scr);
1440
wHideOtherApplications(wwin);
1444
if (ISMAPPED(wwin) && ISFOCUSED(wwin) && IS_RESIZABLE(wwin)) {
1445
int newdir = (MAX_VERTICAL|MAX_HORIZONTAL);
1447
CloseWindowMenu(scr);
1449
if (wwin->flags.maximized == newdir) {
1450
wUnmaximizeWindow(wwin);
1452
wMaximizeWindow(wwin, newdir|MAX_KEYBOARD);
1456
case WKBD_VMAXIMIZE:
1457
if (ISMAPPED(wwin) && ISFOCUSED(wwin) && IS_RESIZABLE(wwin)) {
1458
int newdir = (MAX_VERTICAL ^ wwin->flags.maximized);
1460
CloseWindowMenu(scr);
1463
wMaximizeWindow(wwin, newdir|MAX_KEYBOARD);
1465
wUnmaximizeWindow(wwin);
1469
case WKBD_HMAXIMIZE:
1470
if (ISMAPPED(wwin) && ISFOCUSED(wwin) && IS_RESIZABLE(wwin)) {
1471
int newdir = (MAX_HORIZONTAL ^ wwin->flags.maximized);
1473
CloseWindowMenu(scr);
1476
wMaximizeWindow(wwin, newdir|MAX_KEYBOARD);
1478
wUnmaximizeWindow(wwin);
1483
if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1484
CloseWindowMenu(scr);
1486
wRaiseFrame(wwin->frame->core);
1490
if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1491
CloseWindowMenu(scr);
1493
wLowerFrame(wwin->frame->core);
1496
case WKBD_RAISELOWER:
1497
/* raise or lower the window under the pointer, not the
1500
wwin = windowUnderPointer(scr);
1502
wRaiseLowerFrame(wwin->frame->core);
1505
if (ISMAPPED(wwin) && ISFOCUSED(wwin) && !WFLAGP(wwin, no_shadeable)) {
1506
if (wwin->flags.shaded)
1507
wUnshadeWindow(wwin);
1512
case WKBD_MOVERESIZE:
1513
if (ISMAPPED(wwin) && ISFOCUSED(wwin) &&
1514
(IS_RESIZABLE(wwin) || IS_MOVABLE(wwin))) {
1515
CloseWindowMenu(scr);
1517
wKeyboardMoveResizeWindow(wwin);
1521
if (ISMAPPED(wwin) && ISFOCUSED(wwin) && !WFLAGP(wwin, no_closable)) {
1522
CloseWindowMenu(scr);
1523
if (wwin->protocols.DELETE_WINDOW)
1524
wClientSendProtocol(wwin, _XA_WM_DELETE_WINDOW,
1529
if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1530
wSelectWindow(wwin, !wwin->flags.selected);
1533
case WKBD_FOCUSNEXT:
1534
StartWindozeCycle(wwin, event, True);
1537
case WKBD_FOCUSPREV:
1538
StartWindozeCycle(wwin, event, False);
1541
#if (defined(__STDC__) && !defined(UNIXCPP)) || defined(ANSICPP)
1542
#define GOTOWORKS(wk) case WKBD_WORKSPACE##wk:\
1543
i = (scr->current_workspace/10)*10 + wk - 1;\
1544
if (wPreferences.ws_advance || i<scr->workspace_count)\
1545
wWorkspaceChange(scr, i);\
1548
#define GOTOWORKS(wk) case WKBD_WORKSPACE/**/wk:\
1549
i = (scr->current_workspace/10)*10 + wk - 1;\
1550
if (wPreferences.ws_advance || i<scr->workspace_count)\
1551
wWorkspaceChange(scr, i);\
1565
case WKBD_NEXTWORKSPACE:
1566
wWorkspaceRelativeChange(scr, 1);
1568
case WKBD_PREVWORKSPACE:
1569
wWorkspaceRelativeChange(scr, -1);
1582
index = command-WKBD_WINDOW1;
1584
if (scr->shortcutWindows[index]) {
1585
WMArray *list = scr->shortcutWindows[index];
1587
int count = WMGetArrayItemCount(list);
1589
WMArrayIterator iter;
1592
wUnselectWindows(scr);
1593
cw = scr->current_workspace;
1595
WM_ETARETI_ARRAY(list, wwin, iter) {
1597
wWindowChangeWorkspace(wwin, cw);
1599
wMakeWindowVisible(wwin);
1602
wSelectWindow(wwin, True);
1605
/* rotate the order of windows, to create a cycling effect */
1606
twin = WMGetFromArray(list, 0);
1607
WMDeleteFromArray(list, 0);
1608
WMAddToArray(list, twin);
1610
} else if (wwin && ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1611
if (scr->shortcutWindows[index]) {
1612
WMFreeArray(scr->shortcutWindows[index]);
1613
scr->shortcutWindows[index] = NULL;
1616
if (wwin->flags.selected && scr->selected_windows) {
1617
scr->shortcutWindows[index] =
1618
WMDuplicateArray(scr->selected_windows);
1619
/*WMRemoveFromArray(scr->shortcutWindows[index], wwin);
1620
WMInsertInArray(scr->shortcutWindows[index], 0, wwin);*/
1622
scr->shortcutWindows[index] = WMCreateArray(4);
1623
WMAddToArray(scr->shortcutWindows[index], wwin);
1626
wSelectWindow(wwin, !wwin->flags.selected);
1629
wSelectWindow(wwin, !wwin->flags.selected);
1632
} else if (scr->selected_windows
1633
&& WMGetArrayItemCount(scr->selected_windows)) {
1635
if (wwin->flags.selected && scr->selected_windows) {
1636
if (scr->shortcutWindows[index]) {
1637
WMFreeArray(scr->shortcutWindows[index]);
1639
scr->shortcutWindows[index] =
1640
WMDuplicateArray(scr->selected_windows);
1646
case WKBD_SWITCH_SCREEN:
1647
if (wScreenCount > 1) {
1651
/* find index of this screen */
1652
for (i = 0; i < wScreenCount; i++) {
1653
if (wScreenWithNumber(i) == scr)
1657
if (i >= wScreenCount) {
1660
scr2 = wScreenWithNumber(i);
1663
XWarpPointer(dpy, scr->root_win, scr2->root_win, 0, 0, 0, 0,
1664
scr2->scr_width/2, scr2->scr_height/2);
1669
case WKBD_NEXTWSLAYER:
1670
case WKBD_PREVWSLAYER:
1674
row = scr->current_workspace/10;
1675
column = scr->current_workspace%10;
1677
if (command==WKBD_NEXTWSLAYER) {
1678
if ((row+1)*10 < scr->workspace_count)
1679
wWorkspaceChange(scr, column+(row+1)*10);
1682
wWorkspaceChange(scr, column+(row-1)*10);
1686
case WKBD_CLIPLOWER:
1687
if (!wPreferences.flags.noclip)
1688
wDockLower(scr->workspaces[scr->current_workspace]->clip);
1690
case WKBD_CLIPRAISE:
1691
if (!wPreferences.flags.noclip)
1692
wDockRaise(scr->workspaces[scr->current_workspace]->clip);
1694
case WKBD_CLIPRAISELOWER:
1695
if (!wPreferences.flags.noclip)
1696
wDockRaiseLower(scr->workspaces[scr->current_workspace]->clip);
1698
#ifdef KEEP_XKB_LOCK_STATUS
1700
if(wPreferences.modelock) {
1702
wwin = scr->focused_window;
1704
if (wwin && wwin->flags.mapped
1705
&& wwin->frame->workspace == wwin->screen_ptr->current_workspace
1706
&& !wwin->flags.miniaturized && !wwin->flags.hidden) {
1707
XkbGetState(dpy,XkbUseCoreKbd,&staterec);
1709
wwin->frame->languagemode = wwin->frame->last_languagemode;
1710
wwin->frame->last_languagemode = staterec.group;
1711
XkbLockGroup(dpy,XkbUseCoreKbd, wwin->frame->languagemode);
1716
#endif /* KEEP_XKB_LOCK_STATUS */
1717
#ifdef VIRTUAL_DESKTOP
1718
case WKBD_VDESK_LEFT:
1719
wWorkspaceKeyboardMoveDesktop(scr, VEC_LEFT);
1722
case WKBD_VDESK_RIGHT:
1723
wWorkspaceKeyboardMoveDesktop(scr, VEC_RIGHT);
1727
wWorkspaceKeyboardMoveDesktop(scr, VEC_UP);
1730
case WKBD_VDESK_DOWN:
1731
wWorkspaceKeyboardMoveDesktop(scr, VEC_DOWN);
1740
handleMotionNotify(XEvent *event)
1742
WScreen *scr = wScreenForRootWindow(event->xmotion.root);
1744
if (wPreferences.scrollable_menus) {
1745
WMPoint p = wmkpoint(event->xmotion.x_root, event->xmotion.y_root);
1746
WMRect rect = wGetRectForHead(scr, wGetHeadForPoint(scr, p));
1748
if (scr->flags.jump_back_pending ||
1749
p.x <= (rect.pos.x + 1) ||
1750
p.x >= (rect.pos.x + rect.size.width - 2) ||
1751
p.y <= (rect.pos.y + 1) ||
1752
p.y >= (rect.pos.y + rect.size.height - 2)) {
1755
printf("pointer at screen edge\n");
1757
menu = wMenuUnderPointer(scr);
1759
wMenuScroll(menu, event);
1766
handleVisibilityNotify(XEvent *event)
1770
wwin = wWindowFor(event->xvisibility.window);
1773
wwin->flags.obscured =
1774
(event->xvisibility.state == VisibilityFullyObscured);