Applied some patches from Balaton Zoltan <balaton@eik.bme.hu>
[wmaker-crm.git] / src / event.c
blob85046d499519f484ff51be3f227a874a78cd41fd
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,
20 * USA.
24 #include "wconfig.h"
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <string.h>
34 #include <X11/Xlib.h>
35 #include <X11/Xutil.h>
36 #ifdef SHAPE
37 # include <X11/extensions/shape.h>
38 #endif
39 #ifdef XDND
40 #include "xdnd.h"
41 #endif
43 #ifdef KEEP_XKB_LOCK_STATUS
44 #include <X11/XKBlib.h>
45 #endif /* KEEP_XKB_LOCK_STATUS */
47 #include "WindowMaker.h"
48 #include "window.h"
49 #include "actions.h"
50 #include "client.h"
51 #include "funcs.h"
52 #include "keybind.h"
53 #include "application.h"
54 #include "stacking.h"
55 #include "defaults.h"
56 #include "workspace.h"
57 #include "dock.h"
58 #include "framewin.h"
59 #include "properties.h"
60 #include "balloon.h"
61 #include "xinerama.h"
63 #ifdef NETWM_HINTS
64 # include "wmspec.h"
65 #endif
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;
93 #ifdef SHAPE
94 extern Bool wShapeSupported;
95 extern int wShapeEventBase;
96 #endif
98 #ifdef KEEP_XKB_LOCK_STATUS
99 extern int wXkbEventBase;
100 #endif
102 /* special flags */
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();
129 #ifdef SHAPE
130 static void handleShapeNotify();
131 #endif
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 {
141 pid_t pid;
142 unsigned char exit_status;
143 } DeadProcesses;
145 /* stack of dead processes */
146 static DeadProcesses deadProcesses[MAX_DEAD_PROCESSES];
147 static int deadProcessPtr=0;
150 typedef struct DeathHandler {
151 WDeathHandler *callback;
152 pid_t pid;
153 void *client_data;
154 } DeathHandler;
156 static WMArray *deathHandlers=NULL;
160 WMagicNumber
161 wAddDeathHandler(pid_t pid, WDeathHandler *callback, void *cdata)
163 DeathHandler *handler;
165 handler = malloc(sizeof(DeathHandler));
166 if (!handler)
167 return 0;
169 handler->pid = pid;
170 handler->callback = callback;
171 handler->client_data = cdata;
173 if (!deathHandlers)
174 deathHandlers = WMCreateArrayWithDestructor(8, wfree);
176 WMAddToArray(deathHandlers, handler);
178 return handler;
183 void
184 wDeleteDeathHandler(WMagicNumber id)
186 DeathHandler *handler=(DeathHandler*)id;
188 if (!handler || !deathHandlers)
189 return;
191 /* array destructor will call wfree(handler) */
192 WMRemoveFromArray(deathHandlers, handler);
196 void
197 DispatchEvent(XEvent *event)
199 if (deathHandlers)
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
208 * recursive loop.
210 Shutdown(WSExitMode);
212 } else if (WCHECK_STATE(WSTATE_NEED_RESTART)) {
213 WCHANGE_STATE(WSTATE_RESTARTING);
215 Shutdown(WSRestartPreparationMode);
216 /* received SIGHUP */
217 Restart(NULL, True);
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
224 * the stuff above */
225 if (!event)
226 return;
228 saveTimestamp(event);
229 switch (event->type) {
230 case MapRequest:
231 handleMapRequest(event);
232 break;
234 case KeyPress:
235 handleKeyPress(event);
236 break;
238 case MotionNotify:
239 handleMotionNotify(event);
240 break;
242 case ConfigureRequest:
243 handleConfigureRequest(event);
244 break;
246 case DestroyNotify:
247 handleDestroyNotify(event);
248 break;
250 case MapNotify:
251 handleMapNotify(event);
252 break;
254 case UnmapNotify:
255 handleUnmapNotify(event);
256 break;
258 case ButtonPress:
259 handleButtonPress(event);
260 break;
262 case Expose:
263 handleExpose(event);
264 break;
266 case PropertyNotify:
267 handlePropertyNotify(event);
268 break;
270 case EnterNotify:
271 handleEnterNotify(event);
272 break;
274 case LeaveNotify:
275 handleLeaveNotify(event);
276 break;
278 case ClientMessage:
279 handleClientMessage(event);
280 break;
282 case ColormapNotify:
283 handleColormapNotify(event);
284 break;
286 case MappingNotify:
287 if (event->xmapping.request == MappingKeyboard
288 || event->xmapping.request == MappingModifier)
289 XRefreshKeyboardMapping(&event->xmapping);
290 break;
292 case FocusIn:
293 handleFocusIn(event);
294 break;
296 case VisibilityNotify:
297 handleVisibilityNotify(event);
298 break;
299 default:
300 handleExtensions(event);
301 break;
307 *----------------------------------------------------------------------
308 * EventLoop-
309 * Processes X and internal events indefinitely.
311 * Returns:
312 * Never returns
314 * Side effects:
315 * The LastTimestamp global variable is updated.
316 *----------------------------------------------------------------------
318 void
319 EventLoop()
321 XEvent event;
323 for(;;) {
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.
336 * Returns:
337 * After the pending events that were present at the function call
338 * are processed.
340 * Side effects:
341 * Many -- whatever handling events may involve.
343 *----------------------------------------------------------------------
345 void
346 ProcessPendingEvents()
348 XEvent event;
349 int count;
351 XSync(dpy, False);
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);
359 count--;
364 Bool
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;
376 return True;
378 return False;
382 void
383 NotifyDeadProcess(pid_t pid, unsigned char status)
385 if (deadProcessPtr>=MAX_DEAD_PROCESSES-1) {
386 wwarning("stack overflow: too many dead processes");
387 return;
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;
393 deadProcessPtr++;
397 static void
398 handleDeadProcess(void *foo)
400 DeathHandler *tmp;
401 int i;
403 for (i=0; i<deadProcessPtr; i++) {
404 wWindowDeleteSavedStatesForPID(deadProcesses[i].pid);
407 if (!deathHandlers) {
408 deadProcessPtr=0;
409 return;
412 /* get the pids on the queue and call handlers */
413 while (deadProcessPtr>0) {
414 deadProcessPtr--;
416 for (i = WMGetArrayItemCount(deathHandlers)-1; i >= 0; i--) {
417 tmp = WMGetFromArray(deathHandlers, i);
418 if (!tmp)
419 continue;
421 if (tmp->pid == deadProcesses[deadProcessPtr].pid) {
422 (*tmp->callback)(tmp->pid,
423 deadProcesses[deadProcessPtr].exit_status,
424 tmp->client_data);
425 wDeleteDeathHandler(tmp);
432 static void
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) {
441 case ButtonRelease:
442 case ButtonPress:
443 LastTimestamp = event->xbutton.time;
444 break;
445 case KeyPress:
446 case KeyRelease:
447 LastTimestamp = event->xkey.time;
448 break;
449 case MotionNotify:
450 LastTimestamp = event->xmotion.time;
451 break;
452 case PropertyNotify:
453 LastTimestamp = event->xproperty.time;
454 break;
455 case EnterNotify:
456 case LeaveNotify:
457 LastTimestamp = event->xcrossing.time;
458 break;
459 case SelectionClear:
460 LastTimestamp = event->xselectionclear.time;
461 break;
462 case SelectionRequest:
463 LastTimestamp = event->xselectionrequest.time;
464 break;
465 case SelectionNotify:
466 LastTimestamp = event->xselection.time;
467 #ifdef XDND
468 wXDNDProcessSelection(event);
469 #endif
470 break;
475 static int
476 matchWindow(void *item, void *cdata)
478 return (((WFakeGroupLeader*)item)->origLeader == (Window)cdata);
482 static void
483 handleExtensions(XEvent *event)
485 #ifdef KEEP_XKB_LOCK_STATUS
486 XkbEvent *xkbevent;
487 xkbevent = (XkbEvent *)event;
488 #endif /*KEEP_XKB_LOCK_STATUS*/
489 #ifdef SHAPE
490 if (wShapeSupported && event->type == (wShapeEventBase+ShapeNotify)) {
491 handleShapeNotify(event);
493 #endif
494 #ifdef KEEP_XKB_LOCK_STATUS
495 if (wPreferences.modelock && (xkbevent->type == wXkbEventBase)){
496 handleXkbIndicatorStateNotify(event);
498 #endif /*KEEP_XKB_LOCK_STATUS*/
502 static void
503 handleMapRequest(XEvent *ev)
505 WWindow *wwin;
506 WScreen *scr = NULL;
507 Window window = ev->xmaprequest.window;
509 #ifdef DEBUG
510 printf("got map request for %x\n", (unsigned)window);
511 #endif
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 */
522 if (wapp) {
523 wWorkspaceChange(wwin->screen_ptr, wapp->last_workspace);
525 wUnhideApplication(wapp, False, False);
527 return;
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);
543 else
544 wDockTrackWindowLaunch(scr->last_dock, window);
547 if (wwin) {
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;
555 wShadeWindow(wwin);
557 if (wwin->flags.miniaturized) {
558 wwin->flags.miniaturized = 0;
559 wwin->flags.skip_next_animation = 1;
560 wIconifyWindow(wwin);
562 if (wwin->flags.fullscreen) {
563 wwin->flags.fullscreen = 0;
564 wFullscreenWindow(wwin);
566 if (wwin->flags.hidden) {
567 WApplication *wapp = wApplicationOf(wwin->main_window);
569 wwin->flags.hidden = 0;
570 wwin->flags.skip_next_animation = 1;
571 if (wapp) {
572 wHideApplication(wapp);
579 static void
580 handleDestroyNotify(XEvent *event)
582 WWindow *wwin;
583 WApplication *app;
584 Window window = event->xdestroywindow.window;
585 WScreen *scr = wScreenForRootWindow(event->xdestroywindow.event);
586 int index;
588 #ifdef DEBUG
589 printf("got destroy notify\n");
590 #endif
591 wwin = wWindowFor(window);
592 if (wwin) {
593 wUnmanageWindow(wwin, False, True);
596 if (scr != NULL) {
597 while ((index = WMFindInArray(scr->fakeGroupLeaders, matchWindow,
598 (void*)window)) != WANotFound) {
599 WFakeGroupLeader *fPtr;
601 fPtr = WMGetFromArray(scr->fakeGroupLeaders, index);
602 if (fPtr->retainCount > 0) {
603 fPtr->retainCount--;
604 if (fPtr->retainCount==0 && fPtr->leader!=None) {
605 XDestroyWindow(dpy, fPtr->leader);
606 fPtr->leader = None;
607 XFlush(dpy);
610 fPtr->origLeader = None;
614 app = wApplicationOf(window);
615 if (app) {
616 if (window == app->main_window) {
617 app->refcount = 0;
618 wwin = app->main_window_desc->screen_ptr->focused_window;
619 while (wwin) {
620 if (wwin->main_window == window) {
621 wwin->main_window = None;
623 wwin = wwin->prev;
626 wApplicationDestroy(app);
632 static void
633 handleExpose(XEvent *event)
635 WObjDescriptor *desc;
636 XEvent ev;
638 #ifdef DEBUG
639 printf("got expose\n");
640 #endif
641 while (XCheckTypedWindowEvent(dpy, event->xexpose.window, Expose, &ev));
643 if (XFindContext(dpy, event->xexpose.window, wWinContext,
644 (XPointer *)&desc)==XCNOENT) {
645 return;
648 if (desc->handle_expose) {
649 (*desc->handle_expose)(desc, event);
653 static void
654 executeButtonAction(WScreen *scr, XEvent *event, int action)
656 switch(action) {
657 case WA_SELECT_WINDOWS:
658 wUnselectWindows(scr);
659 wSelectWindows(scr, event);
660 break;
661 case WA_OPEN_APPMENU:
662 OpenRootMenu(scr, event->xbutton.x_root, event->xbutton.y_root, False);
663 /* ugly hack */
664 if (scr->root_menu) {
665 if (scr->root_menu->brother->flags.mapped)
666 event->xbutton.window = scr->root_menu->brother->frame->core->window;
667 else
668 event->xbutton.window = scr->root_menu->frame->core->window;
670 break;
671 case WA_OPEN_WINLISTMENU:
672 OpenSwitchMenu(scr, event->xbutton.x_root, event->xbutton.y_root, False);
673 if (scr->switch_menu) {
674 if (scr->switch_menu->brother->flags.mapped)
675 event->xbutton.window = scr->switch_menu->brother->frame->core->window;
676 else
677 event->xbutton.window = scr->switch_menu->frame->core->window;
679 break;
680 default:
681 break;
686 /* bindable */
687 static void
688 handleButtonPress(XEvent *event)
690 WObjDescriptor *desc;
691 WScreen *scr;
693 #ifdef DEBUG
694 printf("got button press\n");
695 #endif
696 scr = wScreenForRootWindow(event->xbutton.root);
698 #ifdef BALLOON_TEXT
699 wBalloonHide(scr);
700 #endif
703 #ifndef LITE
704 if (event->xbutton.window==scr->root_win) {
705 if (event->xbutton.button==Button1 &&
706 wPreferences.mouse_button1!=WA_NONE) {
707 executeButtonAction(scr, event, wPreferences.mouse_button1);
708 } else if (event->xbutton.button==Button2 &&
709 wPreferences.mouse_button2!=WA_NONE) {
710 executeButtonAction(scr, event, wPreferences.mouse_button2);
711 } else if (event->xbutton.button==Button3 &&
712 wPreferences.mouse_button3!=WA_NONE) {
713 executeButtonAction(scr, event, wPreferences.mouse_button3);
714 } else if (event->xbutton.button==Button4 &&
715 wPreferences.mouse_wheel!=WA_NONE) {
716 wWorkspaceRelativeChange(scr, 1);
717 } else if (event->xbutton.button==Button5 &&
718 wPreferences.mouse_wheel!=WA_NONE) {
719 wWorkspaceRelativeChange(scr, -1);
722 #endif /* !LITE */
724 desc = NULL;
725 if (XFindContext(dpy, event->xbutton.subwindow, wWinContext,
726 (XPointer *)&desc)==XCNOENT) {
727 if (XFindContext(dpy, event->xbutton.window, wWinContext,
728 (XPointer *)&desc)==XCNOENT) {
729 return;
733 if (desc->parent_type == WCLASS_WINDOW) {
734 XSync(dpy, 0);
736 if (event->xbutton.state & MOD_MASK) {
737 XAllowEvents(dpy, AsyncPointer, CurrentTime);
740 /* if (wPreferences.focus_mode == WKF_CLICK) {*/
741 if (wPreferences.ignore_focus_click) {
742 XAllowEvents(dpy, AsyncPointer, CurrentTime);
744 XAllowEvents(dpy, ReplayPointer, CurrentTime);
745 /* }*/
746 XSync(dpy, 0);
747 } else if (desc->parent_type == WCLASS_APPICON
748 || desc->parent_type == WCLASS_MINIWINDOW
749 || desc->parent_type == WCLASS_DOCK_ICON) {
750 if (event->xbutton.state & MOD_MASK) {
751 XSync(dpy, 0);
752 XAllowEvents(dpy, AsyncPointer, CurrentTime);
753 XSync(dpy, 0);
757 if (desc->handle_mousedown!=NULL) {
758 (*desc->handle_mousedown)(desc, event);
761 /* save double-click information */
762 if (scr->flags.next_click_is_not_double) {
763 scr->flags.next_click_is_not_double = 0;
764 } else {
765 scr->last_click_time = event->xbutton.time;
766 scr->last_click_button = event->xbutton.button;
767 scr->last_click_window = event->xbutton.window;
772 static void
773 handleMapNotify(XEvent *event)
775 WWindow *wwin;
776 #ifdef DEBUG
777 printf("got map\n");
778 #endif
779 wwin = wWindowFor(event->xmap.event);
780 if (wwin && wwin->client_win == event->xmap.event) {
781 if (wwin->flags.miniaturized) {
782 wDeiconifyWindow(wwin);
783 } else {
784 XGrabServer(dpy);
785 wWindowMap(wwin);
786 wClientSetState(wwin, NormalState, None);
787 XUngrabServer(dpy);
793 static void
794 handleUnmapNotify(XEvent *event)
796 WWindow *wwin;
797 XEvent ev;
798 Bool withdraw = False;
799 #ifdef DEBUG
800 printf("got unmap\n");
801 #endif
802 /* only process windows with StructureNotify selected
803 * (ignore SubstructureNotify) */
804 wwin = wWindowFor(event->xunmap.window);
805 if (!wwin)
806 return;
808 /* whether the event is a Withdrawal request */
809 if (event->xunmap.event == wwin->screen_ptr->root_win
810 && event->xunmap.send_event)
811 withdraw = True;
813 if (wwin->client_win != event->xunmap.event && !withdraw)
814 return;
816 if (!wwin->flags.mapped && !withdraw
817 && wwin->frame->workspace == wwin->screen_ptr->current_workspace
818 && !wwin->flags.miniaturized && !wwin->flags.hidden)
819 return;
821 XGrabServer(dpy);
822 XUnmapWindow(dpy, wwin->frame->core->window);
823 wwin->flags.mapped = 0;
824 XSync(dpy, 0);
825 /* check if the window was destroyed */
826 if (XCheckTypedWindowEvent(dpy, wwin->client_win, DestroyNotify,&ev)) {
827 DispatchEvent(&ev);
828 } else {
829 Bool reparented = False;
831 if (XCheckTypedWindowEvent(dpy, wwin->client_win, ReparentNotify, &ev))
832 reparented = True;
834 /* withdraw window */
835 wwin->flags.mapped = 0;
836 if (!reparented)
837 wClientSetState(wwin, WithdrawnState, None);
839 /* if the window was reparented, do not reparent it back to the
840 * root window */
841 wUnmanageWindow(wwin, !reparented, False);
843 XUngrabServer(dpy);
847 static void
848 handleConfigureRequest(XEvent *event)
850 WWindow *wwin;
851 #ifdef DEBUG
852 printf("got configure request\n");
853 #endif
854 if (!(wwin=wWindowFor(event->xconfigurerequest.window))) {
856 * Configure request for unmapped window
858 wClientConfigure(NULL, &(event->xconfigurerequest));
859 } else {
860 wClientConfigure(wwin, &(event->xconfigurerequest));
865 static void
866 handlePropertyNotify(XEvent *event)
868 WWindow *wwin;
869 WApplication *wapp;
870 Window jr;
871 int ji;
872 unsigned int ju;
873 WScreen *scr;
874 #ifdef DEBUG
875 printf("got property notify\n");
876 #endif
877 if ((wwin=wWindowFor(event->xproperty.window))) {
878 if (!XGetGeometry(dpy, wwin->client_win, &jr, &ji, &ji,
879 &ju, &ju, &ju, &ju)) {
880 return;
882 wClientCheckProperty(wwin, &event->xproperty);
884 wapp = wApplicationOf(event->xproperty.window);
885 if (wapp) {
886 wClientCheckProperty(wapp->main_window_desc, &event->xproperty);
889 scr = wScreenForWindow(event->xproperty.window);
893 static void
894 handleClientMessage(XEvent *event)
896 WWindow *wwin;
897 WObjDescriptor *desc;
898 #ifdef DEBUG
899 printf("got client message\n");
900 #endif
901 /* handle transition from Normal to Iconic state */
902 if (event->xclient.message_type == _XA_WM_CHANGE_STATE
903 && event->xclient.format == 32
904 && event->xclient.data.l[0] == IconicState) {
906 wwin = wWindowFor(event->xclient.window);
907 if (!wwin) return;
908 if (!wwin->flags.miniaturized)
909 wIconifyWindow(wwin);
910 } else if (event->xclient.message_type == _XA_WM_COLORMAP_NOTIFY
911 && event->xclient.format == 32) {
912 WScreen *scr = wScreenSearchForRootWindow(event->xclient.window);
914 if (!scr)
915 return;
917 if (event->xclient.data.l[1] == 1) { /* starting */
918 wColormapAllowClientInstallation(scr, True);
919 } else { /* stopping */
920 wColormapAllowClientInstallation(scr, False);
922 } else if (event->xclient.message_type == _XA_WINDOWMAKER_COMMAND) {
924 wDefaultsCheckDomains("bla");
926 } else if (event->xclient.message_type == _XA_WINDOWMAKER_WM_FUNCTION) {
927 WApplication *wapp;
928 int done=0;
929 wapp = wApplicationOf(event->xclient.window);
930 if (wapp) {
931 switch (event->xclient.data.l[0]) {
932 case WMFHideOtherApplications:
933 wHideOtherApplications(wapp->main_window_desc);
934 done = 1;
935 break;
937 case WMFHideApplication:
938 wHideApplication(wapp);
939 done = 1;
940 break;
943 if (!done) {
944 wwin = wWindowFor(event->xclient.window);
945 if (wwin) {
946 switch (event->xclient.data.l[0]) {
947 case WMFHideOtherApplications:
948 wHideOtherApplications(wwin);
949 break;
951 case WMFHideApplication:
952 wHideApplication(wApplicationOf(wwin->main_window));
953 break;
957 } else if (event->xclient.message_type == _XA_GNUSTEP_WM_ATTR) {
958 wwin = wWindowFor(event->xclient.window);
959 if (!wwin) return;
960 switch (event->xclient.data.l[0]) {
961 case GSWindowLevelAttr:
963 int level = (int)event->xclient.data.l[1];
965 if (WINDOW_LEVEL(wwin) != level) {
966 ChangeStackingLevel(wwin->frame->core, level);
969 break;
971 } else if (event->xclient.message_type == _XA_GNUSTEP_TITLEBAR_STATE) {
972 wwin = wWindowFor(event->xclient.window);
973 if (!wwin) return;
974 switch (event->xclient.data.l[0]) {
975 case WMTitleBarNormal:
976 wFrameWindowChangeState(wwin->frame, WS_UNFOCUSED);
977 break;
978 case WMTitleBarMain:
979 wFrameWindowChangeState(wwin->frame, WS_PFOCUSED);
980 break;
981 case WMTitleBarKey:
982 wFrameWindowChangeState(wwin->frame, WS_FOCUSED);
983 break;
985 #ifdef NETWM_HINTS
986 } else if (wNETWMProcessClientMessage(&event->xclient)) {
987 /* do nothing */
988 #endif
989 #ifdef XDND
990 } else if (wXDNDProcessClientMessage(&event->xclient)) {
991 /* do nothing */
992 #endif /* XDND */
993 } else {
995 * Non-standard thing, but needed by OffiX DND.
996 * For when the icon frame gets a ClientMessage
997 * that should have gone to the icon_window.
999 if (XFindContext(dpy, event->xbutton.window, wWinContext,
1000 (XPointer *)&desc)!=XCNOENT) {
1001 struct WIcon *icon=NULL;
1003 if (desc->parent_type == WCLASS_MINIWINDOW) {
1004 icon = (WIcon*)desc->parent;
1005 } else if (desc->parent_type == WCLASS_DOCK_ICON
1006 || desc->parent_type == WCLASS_APPICON) {
1007 icon = ((WAppIcon*)desc->parent)->icon;
1009 if (icon && (wwin=icon->owner)) {
1010 if (wwin->client_win!=event->xclient.window) {
1011 event->xclient.window = wwin->client_win;
1012 XSendEvent(dpy, wwin->client_win, False, NoEventMask,
1013 event);
1021 static void
1022 raiseWindow(WScreen *scr)
1024 WWindow *wwin;
1026 scr->autoRaiseTimer = NULL;
1028 wwin = wWindowFor(scr->autoRaiseWindow);
1029 if (!wwin)
1030 return;
1032 if (!wwin->flags.destroyed && wwin->flags.focused) {
1033 wRaiseFrame(wwin->frame->core);
1034 /* this is needed or a race condition will occur */
1035 XSync(dpy, False);
1040 static void
1041 handleEnterNotify(XEvent *event)
1043 WWindow *wwin;
1044 WObjDescriptor *desc = NULL;
1045 #ifdef VIRTUAL_DESKTOP
1046 void (*vdHandler)(XEvent * event);
1047 #endif
1048 XEvent ev;
1049 WScreen *scr = wScreenForRootWindow(event->xcrossing.root);
1050 #ifdef DEBUG
1051 printf("got enter notify\n");
1052 #endif
1054 #ifdef VIRTUAL_DESKTOP
1055 if (XFindContext(dpy, event->xcrossing.window, wVEdgeContext,
1056 (XPointer *)&vdHandler)!=XCNOENT) {
1057 (*vdHandler)(event);
1059 #endif
1061 if (XCheckTypedWindowEvent(dpy, event->xcrossing.window, LeaveNotify,
1062 &ev)) {
1063 /* already left the window... */
1064 saveTimestamp(&ev);
1065 if (ev.xcrossing.mode==event->xcrossing.mode
1066 && ev.xcrossing.detail==event->xcrossing.detail) {
1067 return;
1071 if (XFindContext(dpy, event->xcrossing.window, wWinContext,
1072 (XPointer *)&desc)!=XCNOENT) {
1073 if(desc->handle_enternotify)
1074 (*desc->handle_enternotify)(desc, event);
1077 /* enter to window */
1078 wwin = wWindowFor(event->xcrossing.window);
1079 if (!wwin) {
1080 if (wPreferences.colormap_mode==WCM_POINTER) {
1081 wColormapInstallForWindow(scr, NULL);
1083 if (scr->autoRaiseTimer
1084 && event->xcrossing.root==event->xcrossing.window) {
1085 WMDeleteTimerHandler(scr->autoRaiseTimer);
1086 scr->autoRaiseTimer = NULL;
1088 } else {
1089 /* set auto raise timer even if in focus-follows-mouse mode
1090 * and the event is for the frame window, even if the window
1091 * has focus already. useful if you move the pointer from a focused
1092 * window to the root window and back pretty fast
1094 * set focus if in focus-follows-mouse mode and the event
1095 * is for the frame window and window doesn't have focus yet */
1096 if (wPreferences.focus_mode==WKF_SLOPPY
1097 && wwin->frame->core->window==event->xcrossing.window
1098 && !scr->flags.doing_alt_tab) {
1100 if (!wwin->flags.focused && !WFLAGP(wwin, no_focusable))
1101 wSetFocusTo(scr, wwin);
1103 if (scr->autoRaiseTimer)
1104 WMDeleteTimerHandler(scr->autoRaiseTimer);
1105 scr->autoRaiseTimer = NULL;
1107 if (wPreferences.raise_delay && !WFLAGP(wwin, no_focusable)) {
1108 scr->autoRaiseWindow = wwin->frame->core->window;
1109 scr->autoRaiseTimer
1110 = WMAddTimerHandler(wPreferences.raise_delay,
1111 (WMCallback*)raiseWindow, scr);
1114 /* Install colormap for window, if the colormap installation mode
1115 * is colormap_follows_mouse */
1116 if (wPreferences.colormap_mode==WCM_POINTER) {
1117 if (wwin->client_win==event->xcrossing.window)
1118 wColormapInstallForWindow(scr, wwin);
1119 else
1120 wColormapInstallForWindow(scr, NULL);
1124 /* a little kluge to hide the clip balloon */
1125 if (!wPreferences.flags.noclip && scr->flags.clip_balloon_mapped) {
1126 if (!desc) {
1127 XUnmapWindow(dpy, scr->clip_balloon);
1128 scr->flags.clip_balloon_mapped = 0;
1129 } else {
1130 if (desc->parent_type!=WCLASS_DOCK_ICON
1131 || scr->clip_icon != desc->parent) {
1132 XUnmapWindow(dpy, scr->clip_balloon);
1133 scr->flags.clip_balloon_mapped = 0;
1138 if (event->xcrossing.window == event->xcrossing.root
1139 && event->xcrossing.detail == NotifyNormal
1140 && event->xcrossing.detail != NotifyInferior
1141 && wPreferences.focus_mode != WKF_CLICK) {
1143 wSetFocusTo(scr, scr->focused_window);
1146 #ifdef BALLOON_TEXT
1147 wBalloonEnteredObject(scr, desc);
1148 #endif
1152 static void
1153 handleLeaveNotify(XEvent *event)
1155 WObjDescriptor *desc = NULL;
1157 if (XFindContext(dpy, event->xcrossing.window, wWinContext,
1158 (XPointer *)&desc)!=XCNOENT) {
1159 if(desc->handle_leavenotify)
1160 (*desc->handle_leavenotify)(desc, event);
1165 #ifdef SHAPE
1166 static void
1167 handleShapeNotify(XEvent *event)
1169 XShapeEvent *shev = (XShapeEvent*)event;
1170 WWindow *wwin;
1171 XEvent ev;
1172 #ifdef DEBUG
1173 printf("got shape notify\n");
1174 #endif
1175 while (XCheckTypedWindowEvent(dpy, shev->window, event->type, &ev)) {
1176 XShapeEvent *sev = (XShapeEvent*)&ev;
1178 if (sev->kind == ShapeBounding) {
1179 if (sev->shaped == shev->shaped) {
1180 *shev = *sev;
1181 } else {
1182 XPutBackEvent(dpy, &ev);
1183 break;
1188 wwin = wWindowFor(shev->window);
1189 if (!wwin || shev->kind != ShapeBounding)
1190 return;
1192 if (!shev->shaped && wwin->flags.shaped) {
1194 wwin->flags.shaped = 0;
1195 wWindowClearShape(wwin);
1197 } else if (shev->shaped) {
1199 wwin->flags.shaped = 1;
1200 wWindowSetShape(wwin);
1203 #endif /* SHAPE */
1205 #ifdef KEEP_XKB_LOCK_STATUS
1206 /* please help ]d if you know what to do */
1207 handleXkbIndicatorStateNotify(XEvent *event)
1209 WWindow *wwin;
1210 WScreen *scr;
1211 XkbStateRec staterec;
1212 int i;
1214 for (i=0; i<wScreenCount; i++) {
1215 scr = wScreenWithNumber(i);
1216 wwin = scr->focused_window;
1217 if (wwin && wwin->flags.focused) {
1218 XkbGetState(dpy,XkbUseCoreKbd,&staterec);
1219 if (wwin->frame->languagemode != staterec.group) {
1220 wwin->frame->last_languagemode = wwin->frame->languagemode;
1221 wwin->frame->languagemode = staterec.group;
1223 #ifdef XKB_BUTTON_HINT
1224 if (wwin->frame->titlebar) {
1225 wFrameWindowPaint(wwin->frame);
1227 #endif
1231 #endif /*KEEP_XKB_LOCK_STATUS*/
1233 static void
1234 handleColormapNotify(XEvent *event)
1236 WWindow *wwin;
1237 WScreen *scr;
1238 Bool reinstall = False;
1240 wwin = wWindowFor(event->xcolormap.window);
1241 if (!wwin)
1242 return;
1244 scr = wwin->screen_ptr;
1246 do {
1247 if (wwin) {
1248 if (event->xcolormap.new) {
1249 XWindowAttributes attr;
1251 XGetWindowAttributes(dpy, wwin->client_win, &attr);
1253 if (wwin == scr->cmap_window && wwin->cmap_window_no == 0)
1254 scr->current_colormap = attr.colormap;
1256 reinstall = True;
1257 } else if (event->xcolormap.state == ColormapUninstalled &&
1258 scr->current_colormap == event->xcolormap.colormap) {
1260 /* some bastard app (like XV) removed our colormap */
1262 * can't enforce or things like xscreensaver wont work
1263 * reinstall = True;
1265 } else if (event->xcolormap.state == ColormapInstalled &&
1266 scr->current_colormap == event->xcolormap.colormap) {
1268 /* someone has put our colormap back */
1269 reinstall = False;
1272 } while (XCheckTypedEvent(dpy, ColormapNotify, event)
1273 && ((wwin = wWindowFor(event->xcolormap.window)) || 1));
1275 if (reinstall && scr->current_colormap!=None) {
1276 if (!scr->flags.colormap_stuff_blocked)
1277 XInstallColormap(dpy, scr->current_colormap);
1283 static void
1284 handleFocusIn(XEvent *event)
1286 WWindow *wwin;
1289 * For applications that like stealing the focus.
1291 while (XCheckTypedEvent(dpy, FocusIn, event));
1292 saveTimestamp(event);
1293 if (event->xfocus.mode == NotifyUngrab
1294 || event->xfocus.mode == NotifyGrab
1295 || event->xfocus.detail > NotifyNonlinearVirtual) {
1296 return;
1299 wwin = wWindowFor(event->xfocus.window);
1300 if (wwin && !wwin->flags.focused) {
1301 if (wwin->flags.mapped)
1302 wSetFocusTo(wwin->screen_ptr, wwin);
1303 else
1304 wSetFocusTo(wwin->screen_ptr, NULL);
1305 } else if (!wwin) {
1306 WScreen *scr = wScreenForWindow(event->xfocus.window);
1307 if (scr)
1308 wSetFocusTo(scr, NULL);
1313 static WWindow*
1314 windowUnderPointer(WScreen *scr)
1316 unsigned int mask;
1317 int foo;
1318 Window bar, win;
1320 if (XQueryPointer(dpy, scr->root_win, &bar, &win, &foo, &foo, &foo, &foo,
1321 &mask))
1322 return wWindowFor(win);
1323 return NULL;
1327 static int CheckFullScreenWindowFocused(WScreen *scr)
1329 if (scr->focused_window && scr->focused_window->flags.fullscreen)
1330 return 1;
1331 else
1332 return 0;
1336 static void
1337 handleKeyPress(XEvent *event)
1339 WScreen *scr = wScreenForRootWindow(event->xkey.root);
1340 WWindow *wwin = scr->focused_window;
1341 int i;
1342 int modifiers;
1343 int command=-1, index;
1344 #ifdef KEEP_XKB_LOCK_STATUS
1345 XkbStateRec staterec;
1346 #endif /*KEEP_XKB_LOCK_STATUS*/
1348 /* ignore CapsLock */
1349 modifiers = event->xkey.state & ValidModMask;
1351 for (i=0; i<WKBD_LAST; i++) {
1352 if (wKeyBindings[i].keycode==0)
1353 continue;
1355 if (wKeyBindings[i].keycode==event->xkey.keycode
1356 && (/*wKeyBindings[i].modifier==0
1357 ||*/ wKeyBindings[i].modifier==modifiers)) {
1358 command = i;
1359 break;
1364 if (command < 0) {
1365 #ifdef LITE
1367 #if 0
1369 #endif
1370 #else
1371 if (!wRootMenuPerformShortcut(event)) {
1372 #endif
1373 static int dontLoop = 0;
1375 if (dontLoop > 10) {
1376 wwarning("problem with key event processing code");
1377 return;
1379 dontLoop++;
1380 /* if the focused window is an internal window, try redispatching
1381 * the event to the managed window, as it can be a WINGs window */
1382 if (wwin && wwin->flags.internal_window
1383 && wwin->client_leader!=None) {
1384 /* client_leader contains the WINGs toplevel */
1385 event->xany.window = wwin->client_leader;
1386 WMHandleEvent(event);
1388 dontLoop--;
1390 return;
1393 #define ISMAPPED(w) ((w) && !(w)->flags.miniaturized && ((w)->flags.mapped || (w)->flags.shaded))
1394 #define ISFOCUSED(w) ((w) && (w)->flags.focused)
1396 switch (command) {
1397 #ifndef LITE
1398 case WKBD_ROOTMENU:
1399 /*OpenRootMenu(scr, event->xkey.x_root, event->xkey.y_root, True);*/
1400 if (!CheckFullScreenWindowFocused(scr)) {
1401 WMRect rect = wGetRectForHead(scr, wGetHeadForPointerLocation(scr));
1402 OpenRootMenu(scr, rect.pos.x + rect.size.width/2, rect.pos.y + rect.size.height/2, True);
1404 break;
1405 case WKBD_WINDOWLIST:
1406 if (!CheckFullScreenWindowFocused(scr)) {
1407 WMRect rect = wGetRectForHead(scr, wGetHeadForPointerLocation(scr));
1408 OpenSwitchMenu(scr, rect.pos.x + rect.size.width/2, rect.pos.y + rect.size.height/2, True);
1410 break;
1411 #endif /* !LITE */
1412 case WKBD_WINDOWMENU:
1413 if (ISMAPPED(wwin) && ISFOCUSED(wwin))
1414 OpenWindowMenu(wwin, wwin->frame_x,
1415 wwin->frame_y+wwin->frame->top_width, True);
1416 break;
1417 case WKBD_MINIATURIZE:
1418 if (ISMAPPED(wwin) && ISFOCUSED(wwin)
1419 && !WFLAGP(wwin, no_miniaturizable)) {
1420 CloseWindowMenu(scr);
1422 if (wwin->protocols.MINIATURIZE_WINDOW)
1423 wClientSendProtocol(wwin, _XA_GNUSTEP_WM_MINIATURIZE_WINDOW,
1424 event->xbutton.time);
1425 else {
1426 wIconifyWindow(wwin);
1429 break;
1430 case WKBD_HIDE:
1431 if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1432 WApplication *wapp = wApplicationOf(wwin->main_window);
1433 CloseWindowMenu(scr);
1435 if (wapp && !WFLAGP(wapp->main_window_desc, no_appicon)) {
1436 wHideApplication(wapp);
1439 break;
1440 case WKBD_HIDE_OTHERS:
1441 if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1442 CloseWindowMenu(scr);
1444 wHideOtherApplications(wwin);
1446 break;
1447 case WKBD_MAXIMIZE:
1448 if (ISMAPPED(wwin) && ISFOCUSED(wwin) && IS_RESIZABLE(wwin)) {
1449 int newdir = (MAX_VERTICAL|MAX_HORIZONTAL);
1451 CloseWindowMenu(scr);
1453 if (wwin->flags.maximized == newdir) {
1454 wUnmaximizeWindow(wwin);
1455 } else {
1456 wMaximizeWindow(wwin, newdir|MAX_KEYBOARD);
1459 break;
1460 case WKBD_VMAXIMIZE:
1461 if (ISMAPPED(wwin) && ISFOCUSED(wwin) && IS_RESIZABLE(wwin)) {
1462 int newdir = (MAX_VERTICAL ^ wwin->flags.maximized);
1464 CloseWindowMenu(scr);
1466 if (newdir) {
1467 wMaximizeWindow(wwin, newdir|MAX_KEYBOARD);
1468 } else {
1469 wUnmaximizeWindow(wwin);
1472 break;
1473 case WKBD_HMAXIMIZE:
1474 if (ISMAPPED(wwin) && ISFOCUSED(wwin) && IS_RESIZABLE(wwin)) {
1475 int newdir = (MAX_HORIZONTAL ^ wwin->flags.maximized);
1477 CloseWindowMenu(scr);
1479 if (newdir) {
1480 wMaximizeWindow(wwin, newdir|MAX_KEYBOARD);
1481 } else {
1482 wUnmaximizeWindow(wwin);
1485 break;
1486 case WKBD_RAISE:
1487 if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1488 CloseWindowMenu(scr);
1490 wRaiseFrame(wwin->frame->core);
1492 break;
1493 case WKBD_LOWER:
1494 if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1495 CloseWindowMenu(scr);
1497 wLowerFrame(wwin->frame->core);
1499 break;
1500 case WKBD_RAISELOWER:
1501 /* raise or lower the window under the pointer, not the
1502 * focused one
1504 wwin = windowUnderPointer(scr);
1505 if (wwin)
1506 wRaiseLowerFrame(wwin->frame->core);
1507 break;
1508 case WKBD_SHADE:
1509 if (ISMAPPED(wwin) && ISFOCUSED(wwin) && !WFLAGP(wwin, no_shadeable)) {
1510 if (wwin->flags.shaded)
1511 wUnshadeWindow(wwin);
1512 else
1513 wShadeWindow(wwin);
1515 break;
1516 case WKBD_MOVERESIZE:
1517 if (ISMAPPED(wwin) && ISFOCUSED(wwin) &&
1518 (IS_RESIZABLE(wwin) || IS_MOVABLE(wwin))) {
1519 CloseWindowMenu(scr);
1521 wKeyboardMoveResizeWindow(wwin);
1523 break;
1524 case WKBD_CLOSE:
1525 if (ISMAPPED(wwin) && ISFOCUSED(wwin) && !WFLAGP(wwin, no_closable)) {
1526 CloseWindowMenu(scr);
1527 if (wwin->protocols.DELETE_WINDOW)
1528 wClientSendProtocol(wwin, _XA_WM_DELETE_WINDOW,
1529 event->xkey.time);
1531 break;
1532 case WKBD_SELECT:
1533 if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1534 wSelectWindow(wwin, !wwin->flags.selected);
1536 break;
1537 case WKBD_FOCUSNEXT:
1538 StartWindozeCycle(wwin, event, True);
1539 break;
1541 case WKBD_FOCUSPREV:
1542 StartWindozeCycle(wwin, event, False);
1543 break;
1545 #if (defined(__STDC__) && !defined(UNIXCPP)) || defined(ANSICPP)
1546 #define GOTOWORKS(wk) case WKBD_WORKSPACE##wk:\
1547 i = (scr->current_workspace/10)*10 + wk - 1;\
1548 if (wPreferences.ws_advance || i<scr->workspace_count)\
1549 wWorkspaceChange(scr, i);\
1550 break
1551 #else
1552 #define GOTOWORKS(wk) case WKBD_WORKSPACE/**/wk:\
1553 i = (scr->current_workspace/10)*10 + wk - 1;\
1554 if (wPreferences.ws_advance || i<scr->workspace_count)\
1555 wWorkspaceChange(scr, i);\
1556 break
1557 #endif
1558 GOTOWORKS(1);
1559 GOTOWORKS(2);
1560 GOTOWORKS(3);
1561 GOTOWORKS(4);
1562 GOTOWORKS(5);
1563 GOTOWORKS(6);
1564 GOTOWORKS(7);
1565 GOTOWORKS(8);
1566 GOTOWORKS(9);
1567 GOTOWORKS(10);
1568 #undef GOTOWORKS
1569 case WKBD_NEXTWORKSPACE:
1570 wWorkspaceRelativeChange(scr, 1);
1571 break;
1572 case WKBD_PREVWORKSPACE:
1573 wWorkspaceRelativeChange(scr, -1);
1574 break;
1575 case WKBD_WINDOW1:
1576 case WKBD_WINDOW2:
1577 case WKBD_WINDOW3:
1578 case WKBD_WINDOW4:
1579 case WKBD_WINDOW5:
1580 case WKBD_WINDOW6:
1581 case WKBD_WINDOW7:
1582 case WKBD_WINDOW8:
1583 case WKBD_WINDOW9:
1584 case WKBD_WINDOW10:
1586 index = command-WKBD_WINDOW1;
1588 if (scr->shortcutWindows[index]) {
1589 WMArray *list = scr->shortcutWindows[index];
1590 int cw;
1591 int count = WMGetArrayItemCount(list);
1592 WWindow *twin;
1593 WMArrayIterator iter;
1594 WWindow *wwin;
1596 wUnselectWindows(scr);
1597 cw = scr->current_workspace;
1599 WM_ETARETI_ARRAY(list, wwin, iter) {
1600 if (count > 1)
1601 wWindowChangeWorkspace(wwin, cw);
1603 wMakeWindowVisible(wwin);
1605 if (count > 1)
1606 wSelectWindow(wwin, True);
1609 /* rotate the order of windows, to create a cycling effect */
1610 twin = WMGetFromArray(list, 0);
1611 WMDeleteFromArray(list, 0);
1612 WMAddToArray(list, twin);
1614 } else if (wwin && ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1615 if (scr->shortcutWindows[index]) {
1616 WMFreeArray(scr->shortcutWindows[index]);
1617 scr->shortcutWindows[index] = NULL;
1620 if (wwin->flags.selected && scr->selected_windows) {
1621 scr->shortcutWindows[index] =
1622 WMDuplicateArray(scr->selected_windows);
1623 /*WMRemoveFromArray(scr->shortcutWindows[index], wwin);
1624 WMInsertInArray(scr->shortcutWindows[index], 0, wwin);*/
1625 } else {
1626 scr->shortcutWindows[index] = WMCreateArray(4);
1627 WMAddToArray(scr->shortcutWindows[index], wwin);
1630 wSelectWindow(wwin, !wwin->flags.selected);
1631 XFlush(dpy);
1632 wusleep(3000);
1633 wSelectWindow(wwin, !wwin->flags.selected);
1634 XFlush(dpy);
1636 } else if (scr->selected_windows
1637 && WMGetArrayItemCount(scr->selected_windows)) {
1639 if (wwin->flags.selected && scr->selected_windows) {
1640 if (scr->shortcutWindows[index]) {
1641 WMFreeArray(scr->shortcutWindows[index]);
1643 scr->shortcutWindows[index] =
1644 WMDuplicateArray(scr->selected_windows);
1648 break;
1650 case WKBD_SWITCH_SCREEN:
1651 if (wScreenCount > 1) {
1652 WScreen *scr2;
1653 int i;
1655 /* find index of this screen */
1656 for (i = 0; i < wScreenCount; i++) {
1657 if (wScreenWithNumber(i) == scr)
1658 break;
1660 i++;
1661 if (i >= wScreenCount) {
1662 i = 0;
1664 scr2 = wScreenWithNumber(i);
1666 if (scr2) {
1667 XWarpPointer(dpy, scr->root_win, scr2->root_win, 0, 0, 0, 0,
1668 scr2->scr_width/2, scr2->scr_height/2);
1671 break;
1673 case WKBD_NEXTWSLAYER:
1674 case WKBD_PREVWSLAYER:
1676 int row, column;
1678 row = scr->current_workspace/10;
1679 column = scr->current_workspace%10;
1681 if (command==WKBD_NEXTWSLAYER) {
1682 if ((row+1)*10 < scr->workspace_count)
1683 wWorkspaceChange(scr, column+(row+1)*10);
1684 } else {
1685 if (row > 0)
1686 wWorkspaceChange(scr, column+(row-1)*10);
1689 break;
1690 case WKBD_CLIPLOWER:
1691 if (!wPreferences.flags.noclip)
1692 wDockLower(scr->workspaces[scr->current_workspace]->clip);
1693 break;
1694 case WKBD_CLIPRAISE:
1695 if (!wPreferences.flags.noclip)
1696 wDockRaise(scr->workspaces[scr->current_workspace]->clip);
1697 break;
1698 case WKBD_CLIPRAISELOWER:
1699 if (!wPreferences.flags.noclip)
1700 wDockRaiseLower(scr->workspaces[scr->current_workspace]->clip);
1701 break;
1702 #ifdef KEEP_XKB_LOCK_STATUS
1703 case WKBD_TOGGLE:
1704 if(wPreferences.modelock) {
1705 /*toggle*/
1706 wwin = scr->focused_window;
1708 if (wwin && wwin->flags.mapped
1709 && wwin->frame->workspace == wwin->screen_ptr->current_workspace
1710 && !wwin->flags.miniaturized && !wwin->flags.hidden) {
1711 XkbGetState(dpy,XkbUseCoreKbd,&staterec);
1713 wwin->frame->languagemode = wwin->frame->last_languagemode;
1714 wwin->frame->last_languagemode = staterec.group;
1715 XkbLockGroup(dpy,XkbUseCoreKbd, wwin->frame->languagemode);
1719 break;
1720 #endif /* KEEP_XKB_LOCK_STATUS */
1721 #ifdef VIRTUAL_DESKTOP
1722 case WKBD_VDESK_LEFT:
1723 wWorkspaceKeyboardMoveDesktop(scr, VEC_LEFT);
1724 break;
1726 case WKBD_VDESK_RIGHT:
1727 wWorkspaceKeyboardMoveDesktop(scr, VEC_RIGHT);
1728 break;
1730 case WKBD_VDESK_UP:
1731 wWorkspaceKeyboardMoveDesktop(scr, VEC_UP);
1732 break;
1734 case WKBD_VDESK_DOWN:
1735 wWorkspaceKeyboardMoveDesktop(scr, VEC_DOWN);
1736 break;
1737 #endif
1743 static void
1744 handleMotionNotify(XEvent *event)
1746 WScreen *scr = wScreenForRootWindow(event->xmotion.root);
1748 if (wPreferences.scrollable_menus) {
1749 WMPoint p = wmkpoint(event->xmotion.x_root, event->xmotion.y_root);
1750 WMRect rect = wGetRectForHead(scr, wGetHeadForPoint(scr, p));
1752 if (scr->flags.jump_back_pending ||
1753 p.x <= (rect.pos.x + 1) ||
1754 p.x >= (rect.pos.x + rect.size.width - 2) ||
1755 p.y <= (rect.pos.y + 1) ||
1756 p.y >= (rect.pos.y + rect.size.height - 2)) {
1757 WMenu *menu;
1758 #ifdef DEBUG
1759 printf("pointer at screen edge\n");
1760 #endif
1761 menu = wMenuUnderPointer(scr);
1762 if (menu!=NULL)
1763 wMenuScroll(menu, event);
1769 static void
1770 handleVisibilityNotify(XEvent *event)
1772 WWindow *wwin;
1774 wwin = wWindowFor(event->xvisibility.window);
1775 if (!wwin)
1776 return;
1777 wwin->flags.obscured =
1778 (event->xvisibility.state == VisibilityFullyObscured);