- Removed support for legacy systems: OpenLook, KDE-2.x, Gnome-1.x
[wmaker-crm.git] / src / event.c
blobe9f352e80f2b0b181fefa67041eafb63643f4145
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.hidden) {
563 WApplication *wapp = wApplicationOf(wwin->main_window);
565 wwin->flags.hidden = 0;
566 wwin->flags.skip_next_animation = 1;
567 if (wapp) {
568 wHideApplication(wapp);
575 static void
576 handleDestroyNotify(XEvent *event)
578 WWindow *wwin;
579 WApplication *app;
580 Window window = event->xdestroywindow.window;
581 WScreen *scr = wScreenForRootWindow(event->xdestroywindow.event);
582 int index;
584 #ifdef DEBUG
585 printf("got destroy notify\n");
586 #endif
587 wwin = wWindowFor(window);
588 if (wwin) {
589 wUnmanageWindow(wwin, False, True);
592 if (scr != NULL) {
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) {
599 fPtr->retainCount--;
600 if (fPtr->retainCount==0 && fPtr->leader!=None) {
601 XDestroyWindow(dpy, fPtr->leader);
602 fPtr->leader = None;
603 XFlush(dpy);
606 fPtr->origLeader = None;
610 app = wApplicationOf(window);
611 if (app) {
612 if (window == app->main_window) {
613 app->refcount = 0;
614 wwin = app->main_window_desc->screen_ptr->focused_window;
615 while (wwin) {
616 if (wwin->main_window == window) {
617 wwin->main_window = None;
619 wwin = wwin->prev;
622 wApplicationDestroy(app);
628 static void
629 handleExpose(XEvent *event)
631 WObjDescriptor *desc;
632 XEvent ev;
634 #ifdef DEBUG
635 printf("got expose\n");
636 #endif
637 while (XCheckTypedWindowEvent(dpy, event->xexpose.window, Expose, &ev));
639 if (XFindContext(dpy, event->xexpose.window, wWinContext,
640 (XPointer *)&desc)==XCNOENT) {
641 return;
644 if (desc->handle_expose) {
645 (*desc->handle_expose)(desc, event);
649 static void
650 executeButtonAction(WScreen *scr, XEvent *event, int action)
652 switch(action) {
653 case WA_SELECT_WINDOWS:
654 wUnselectWindows(scr);
655 wSelectWindows(scr, event);
656 break;
657 case WA_OPEN_APPMENU:
658 OpenRootMenu(scr, event->xbutton.x_root, event->xbutton.y_root, False);
659 /* ugly hack */
660 if (scr->root_menu) {
661 if (scr->root_menu->brother->flags.mapped)
662 event->xbutton.window = scr->root_menu->brother->frame->core->window;
663 else
664 event->xbutton.window = scr->root_menu->frame->core->window;
666 break;
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;
672 else
673 event->xbutton.window = scr->switch_menu->frame->core->window;
675 break;
676 default:
677 break;
682 /* bindable */
683 static void
684 handleButtonPress(XEvent *event)
686 WObjDescriptor *desc;
687 WScreen *scr;
689 #ifdef DEBUG
690 printf("got button press\n");
691 #endif
692 scr = wScreenForRootWindow(event->xbutton.root);
694 #ifdef BALLOON_TEXT
695 wBalloonHide(scr);
696 #endif
699 #ifndef LITE
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);
718 #endif /* !LITE */
720 desc = NULL;
721 if (XFindContext(dpy, event->xbutton.subwindow, wWinContext,
722 (XPointer *)&desc)==XCNOENT) {
723 if (XFindContext(dpy, event->xbutton.window, wWinContext,
724 (XPointer *)&desc)==XCNOENT) {
725 return;
729 if (desc->parent_type == WCLASS_WINDOW) {
730 XSync(dpy, 0);
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);
741 /* }*/
742 XSync(dpy, 0);
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) {
747 XSync(dpy, 0);
748 XAllowEvents(dpy, AsyncPointer, CurrentTime);
749 XSync(dpy, 0);
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;
760 } else {
761 scr->last_click_time = event->xbutton.time;
762 scr->last_click_button = event->xbutton.button;
763 scr->last_click_window = event->xbutton.window;
768 static void
769 handleMapNotify(XEvent *event)
771 WWindow *wwin;
772 #ifdef DEBUG
773 printf("got map\n");
774 #endif
775 wwin = wWindowFor(event->xmap.event);
776 if (wwin && wwin->client_win == event->xmap.event) {
777 if (wwin->flags.miniaturized) {
778 wDeiconifyWindow(wwin);
779 } else {
780 XGrabServer(dpy);
781 wWindowMap(wwin);
782 wClientSetState(wwin, NormalState, None);
783 XUngrabServer(dpy);
789 static void
790 handleUnmapNotify(XEvent *event)
792 WWindow *wwin;
793 XEvent ev;
794 Bool withdraw = False;
795 #ifdef DEBUG
796 printf("got unmap\n");
797 #endif
798 /* only process windows with StructureNotify selected
799 * (ignore SubstructureNotify) */
800 wwin = wWindowFor(event->xunmap.window);
801 if (!wwin)
802 return;
804 /* whether the event is a Withdrawal request */
805 if (event->xunmap.event == wwin->screen_ptr->root_win
806 && event->xunmap.send_event)
807 withdraw = True;
809 if (wwin->client_win != event->xunmap.event && !withdraw)
810 return;
812 if (!wwin->flags.mapped && !withdraw
813 && wwin->frame->workspace == wwin->screen_ptr->current_workspace
814 && !wwin->flags.miniaturized && !wwin->flags.hidden)
815 return;
817 XGrabServer(dpy);
818 XUnmapWindow(dpy, wwin->frame->core->window);
819 wwin->flags.mapped = 0;
820 XSync(dpy, 0);
821 /* check if the window was destroyed */
822 if (XCheckTypedWindowEvent(dpy, wwin->client_win, DestroyNotify,&ev)) {
823 DispatchEvent(&ev);
824 } else {
825 Bool reparented = False;
827 if (XCheckTypedWindowEvent(dpy, wwin->client_win, ReparentNotify, &ev))
828 reparented = True;
830 /* withdraw window */
831 wwin->flags.mapped = 0;
832 if (!reparented)
833 wClientSetState(wwin, WithdrawnState, None);
835 /* if the window was reparented, do not reparent it back to the
836 * root window */
837 wUnmanageWindow(wwin, !reparented, False);
839 XUngrabServer(dpy);
843 static void
844 handleConfigureRequest(XEvent *event)
846 WWindow *wwin;
847 #ifdef DEBUG
848 printf("got configure request\n");
849 #endif
850 if (!(wwin=wWindowFor(event->xconfigurerequest.window))) {
852 * Configure request for unmapped window
854 wClientConfigure(NULL, &(event->xconfigurerequest));
855 } else {
856 wClientConfigure(wwin, &(event->xconfigurerequest));
861 static void
862 handlePropertyNotify(XEvent *event)
864 WWindow *wwin;
865 WApplication *wapp;
866 Window jr;
867 int ji;
868 unsigned int ju;
869 WScreen *scr;
870 #ifdef DEBUG
871 printf("got property notify\n");
872 #endif
873 if ((wwin=wWindowFor(event->xproperty.window))) {
874 if (!XGetGeometry(dpy, wwin->client_win, &jr, &ji, &ji,
875 &ju, &ju, &ju, &ju)) {
876 return;
878 wClientCheckProperty(wwin, &event->xproperty);
880 wapp = wApplicationOf(event->xproperty.window);
881 if (wapp) {
882 wClientCheckProperty(wapp->main_window_desc, &event->xproperty);
885 scr = wScreenForWindow(event->xproperty.window);
889 static void
890 handleClientMessage(XEvent *event)
892 WWindow *wwin;
893 WObjDescriptor *desc;
894 #ifdef DEBUG
895 printf("got client message\n");
896 #endif
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);
903 if (!wwin) return;
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);
910 if (!scr)
911 return;
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) {
923 WApplication *wapp;
924 int done=0;
925 wapp = wApplicationOf(event->xclient.window);
926 if (wapp) {
927 switch (event->xclient.data.l[0]) {
928 case WMFHideOtherApplications:
929 wHideOtherApplications(wapp->main_window_desc);
930 done = 1;
931 break;
933 case WMFHideApplication:
934 wHideApplication(wapp);
935 done = 1;
936 break;
939 if (!done) {
940 wwin = wWindowFor(event->xclient.window);
941 if (wwin) {
942 switch (event->xclient.data.l[0]) {
943 case WMFHideOtherApplications:
944 wHideOtherApplications(wwin);
945 break;
947 case WMFHideApplication:
948 wHideApplication(wApplicationOf(wwin->main_window));
949 break;
953 } else if (event->xclient.message_type == _XA_GNUSTEP_WM_ATTR) {
954 wwin = wWindowFor(event->xclient.window);
955 if (!wwin) return;
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);
965 break;
967 } else if (event->xclient.message_type == _XA_GNUSTEP_TITLEBAR_STATE) {
968 wwin = wWindowFor(event->xclient.window);
969 if (!wwin) return;
970 switch (event->xclient.data.l[0]) {
971 case WMTitleBarNormal:
972 wFrameWindowChangeState(wwin->frame, WS_UNFOCUSED);
973 break;
974 case WMTitleBarMain:
975 wFrameWindowChangeState(wwin->frame, WS_PFOCUSED);
976 break;
977 case WMTitleBarKey:
978 wFrameWindowChangeState(wwin->frame, WS_FOCUSED);
979 break;
981 #ifdef NETWM_HINTS
982 } else if (wNETWMProcessClientMessage(&event->xclient)) {
983 /* do nothing */
984 #endif
985 #ifdef XDND
986 } else if (wXDNDProcessClientMessage(&event->xclient)) {
987 /* do nothing */
988 #endif /* XDND */
989 } else {
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,
1009 event);
1017 static void
1018 raiseWindow(WScreen *scr)
1020 WWindow *wwin;
1022 scr->autoRaiseTimer = NULL;
1024 wwin = wWindowFor(scr->autoRaiseWindow);
1025 if (!wwin)
1026 return;
1028 if (!wwin->flags.destroyed && wwin->flags.focused) {
1029 wRaiseFrame(wwin->frame->core);
1030 /* this is needed or a race condition will occur */
1031 XSync(dpy, False);
1036 static void
1037 handleEnterNotify(XEvent *event)
1039 WWindow *wwin;
1040 WObjDescriptor *desc = NULL;
1041 #ifdef VIRTUAL_DESKTOP
1042 void (*vdHandler)(XEvent * event);
1043 #endif
1044 XEvent ev;
1045 WScreen *scr = wScreenForRootWindow(event->xcrossing.root);
1046 #ifdef DEBUG
1047 printf("got enter notify\n");
1048 #endif
1050 #ifdef VIRTUAL_DESKTOP
1051 if (XFindContext(dpy, event->xcrossing.window, wVEdgeContext,
1052 (XPointer *)&vdHandler)!=XCNOENT) {
1053 (*vdHandler)( event);
1055 #endif
1057 if (XCheckTypedWindowEvent(dpy, event->xcrossing.window, LeaveNotify,
1058 &ev)) {
1059 /* already left the window... */
1060 saveTimestamp(&ev);
1061 if (ev.xcrossing.mode==event->xcrossing.mode
1062 && ev.xcrossing.detail==event->xcrossing.detail) {
1063 return;
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);
1075 if (!wwin) {
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;
1084 } else {
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;
1105 scr->autoRaiseTimer
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);
1115 else
1116 wColormapInstallForWindow(scr, NULL);
1120 /* a little kluge to hide the clip balloon */
1121 if (!wPreferences.flags.noclip && scr->flags.clip_balloon_mapped) {
1122 if (!desc) {
1123 XUnmapWindow(dpy, scr->clip_balloon);
1124 scr->flags.clip_balloon_mapped = 0;
1125 } else {
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);
1142 #ifdef BALLOON_TEXT
1143 wBalloonEnteredObject(scr, desc);
1144 #endif
1148 static void
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);
1161 #ifdef SHAPE
1162 static void
1163 handleShapeNotify(XEvent *event)
1165 XShapeEvent *shev = (XShapeEvent*)event;
1166 WWindow *wwin;
1167 XEvent ev;
1168 #ifdef DEBUG
1169 printf("got shape notify\n");
1170 #endif
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) {
1176 *shev = *sev;
1177 } else {
1178 XPutBackEvent(dpy, &ev);
1179 break;
1184 wwin = wWindowFor(shev->window);
1185 if (!wwin || shev->kind != ShapeBounding)
1186 return;
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);
1199 #endif /* SHAPE */
1201 #ifdef KEEP_XKB_LOCK_STATUS
1202 /* please help ]d if you know what to do */
1203 handleXkbIndicatorStateNotify(XEvent *event)
1205 WWindow *wwin;
1206 WScreen *scr;
1207 XkbStateRec staterec;
1208 int i;
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);
1223 #endif
1227 #endif /*KEEP_XKB_LOCK_STATUS*/
1229 static void
1230 handleColormapNotify(XEvent *event)
1232 WWindow *wwin;
1233 WScreen *scr;
1234 Bool reinstall = False;
1236 wwin = wWindowFor(event->xcolormap.window);
1237 if (!wwin)
1238 return;
1240 scr = wwin->screen_ptr;
1242 do {
1243 if (wwin) {
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;
1252 reinstall = True;
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
1259 * reinstall = True;
1261 } else if (event->xcolormap.state == ColormapInstalled &&
1262 scr->current_colormap == event->xcolormap.colormap) {
1264 /* someone has put our colormap back */
1265 reinstall = False;
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);
1279 static void
1280 handleFocusIn(XEvent *event)
1282 WWindow *wwin;
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) {
1292 return;
1295 wwin = wWindowFor(event->xfocus.window);
1296 if (wwin && !wwin->flags.focused) {
1297 if (wwin->flags.mapped)
1298 wSetFocusTo(wwin->screen_ptr, wwin);
1299 else
1300 wSetFocusTo(wwin->screen_ptr, NULL);
1301 } else if (!wwin) {
1302 WScreen *scr = wScreenForWindow(event->xfocus.window);
1303 if (scr)
1304 wSetFocusTo(scr, NULL);
1309 static WWindow*
1310 windowUnderPointer(WScreen *scr)
1312 unsigned int mask;
1313 int foo;
1314 Window bar, win;
1316 if (XQueryPointer(dpy, scr->root_win, &bar, &win, &foo, &foo, &foo, &foo,
1317 &mask))
1318 return wWindowFor(win);
1319 return NULL;
1325 static void
1326 handleKeyPress(XEvent *event)
1328 WScreen *scr = wScreenForRootWindow(event->xkey.root);
1329 WWindow *wwin = scr->focused_window;
1330 int i;
1331 int modifiers;
1332 int command=-1, index;
1333 #ifdef KEEP_XKB_LOCK_STATUS
1334 XkbStateRec staterec;
1335 #endif /*KEEP_XKB_LOCK_STATUS*/
1337 /* ignore CapsLock */
1338 modifiers = event->xkey.state & ValidModMask;
1340 for (i=0; i<WKBD_LAST; i++) {
1341 if (wKeyBindings[i].keycode==0)
1342 continue;
1344 if (wKeyBindings[i].keycode==event->xkey.keycode
1345 && (/*wKeyBindings[i].modifier==0
1346 ||*/ wKeyBindings[i].modifier==modifiers)) {
1347 command = i;
1348 break;
1353 if (command < 0) {
1354 #ifdef LITE
1356 #if 0
1358 #endif
1359 #else
1360 if (!wRootMenuPerformShortcut(event)) {
1361 #endif
1362 static int dontLoop = 0;
1364 if (dontLoop > 10) {
1365 wwarning("problem with key event processing code");
1366 return;
1368 dontLoop++;
1369 /* if the focused window is an internal window, try redispatching
1370 * the event to the managed window, as it can be a WINGs window */
1371 if (wwin && wwin->flags.internal_window
1372 && wwin->client_leader!=None) {
1373 /* client_leader contains the WINGs toplevel */
1374 event->xany.window = wwin->client_leader;
1375 WMHandleEvent(event);
1377 dontLoop--;
1379 return;
1382 #define ISMAPPED(w) ((w) && !(w)->flags.miniaturized && ((w)->flags.mapped || (w)->flags.shaded))
1383 #define ISFOCUSED(w) ((w) && (w)->flags.focused)
1385 switch (command) {
1386 #ifndef LITE
1387 case WKBD_ROOTMENU:
1388 /*OpenRootMenu(scr, event->xkey.x_root, event->xkey.y_root, True);*/
1390 WMRect rect = wGetRectForHead(scr, wGetHeadForPointerLocation(scr));
1391 OpenRootMenu(scr, rect.pos.x + rect.size.width/2, rect.pos.y + rect.size.height/2, True);
1393 break;
1394 case WKBD_WINDOWLIST:
1396 WMRect rect = wGetRectForHead(scr, wGetHeadForPointerLocation(scr));
1397 OpenSwitchMenu(scr, rect.pos.x + rect.size.width/2, rect.pos.y + rect.size.height/2, True);
1399 break;
1400 #endif /* !LITE */
1401 case WKBD_WINDOWMENU:
1402 if (ISMAPPED(wwin) && ISFOCUSED(wwin))
1403 OpenWindowMenu(wwin, wwin->frame_x,
1404 wwin->frame_y+wwin->frame->top_width, True);
1405 break;
1406 case WKBD_MINIATURIZE:
1407 if (ISMAPPED(wwin) && ISFOCUSED(wwin)
1408 && !WFLAGP(wwin, no_miniaturizable)) {
1409 CloseWindowMenu(scr);
1411 if (wwin->protocols.MINIATURIZE_WINDOW)
1412 wClientSendProtocol(wwin, _XA_GNUSTEP_WM_MINIATURIZE_WINDOW,
1413 event->xbutton.time);
1414 else {
1415 wIconifyWindow(wwin);
1418 break;
1419 case WKBD_HIDE:
1420 if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1421 WApplication *wapp = wApplicationOf(wwin->main_window);
1422 CloseWindowMenu(scr);
1424 if (wapp && !WFLAGP(wapp->main_window_desc, no_appicon)) {
1425 wHideApplication(wapp);
1428 break;
1429 case WKBD_HIDE_OTHERS:
1430 if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1431 CloseWindowMenu(scr);
1433 wHideOtherApplications(wwin);
1435 break;
1436 case WKBD_MAXIMIZE:
1437 if (ISMAPPED(wwin) && ISFOCUSED(wwin) && IS_RESIZABLE(wwin)) {
1438 int newdir = (MAX_VERTICAL|MAX_HORIZONTAL);
1440 CloseWindowMenu(scr);
1442 if (wwin->flags.maximized == newdir) {
1443 wUnmaximizeWindow(wwin);
1444 } else {
1445 wMaximizeWindow(wwin, newdir|MAX_KEYBOARD);
1448 break;
1449 case WKBD_VMAXIMIZE:
1450 if (ISMAPPED(wwin) && ISFOCUSED(wwin) && IS_RESIZABLE(wwin)) {
1451 int newdir = (MAX_VERTICAL ^ wwin->flags.maximized);
1453 CloseWindowMenu(scr);
1455 if (newdir) {
1456 wMaximizeWindow(wwin, newdir|MAX_KEYBOARD);
1457 } else {
1458 wUnmaximizeWindow(wwin);
1461 break;
1462 case WKBD_HMAXIMIZE:
1463 if (ISMAPPED(wwin) && ISFOCUSED(wwin) && IS_RESIZABLE(wwin)) {
1464 int newdir = (MAX_HORIZONTAL ^ wwin->flags.maximized);
1466 CloseWindowMenu(scr);
1468 if (newdir) {
1469 wMaximizeWindow(wwin, newdir|MAX_KEYBOARD);
1470 } else {
1471 wUnmaximizeWindow(wwin);
1474 break;
1475 case WKBD_RAISE:
1476 if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1477 CloseWindowMenu(scr);
1479 wRaiseFrame(wwin->frame->core);
1481 break;
1482 case WKBD_LOWER:
1483 if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1484 CloseWindowMenu(scr);
1486 wLowerFrame(wwin->frame->core);
1488 break;
1489 case WKBD_RAISELOWER:
1490 /* raise or lower the window under the pointer, not the
1491 * focused one
1493 wwin = windowUnderPointer(scr);
1494 if (wwin)
1495 wRaiseLowerFrame(wwin->frame->core);
1496 break;
1497 case WKBD_SHADE:
1498 if (ISMAPPED(wwin) && ISFOCUSED(wwin) && !WFLAGP(wwin, no_shadeable)) {
1499 if (wwin->flags.shaded)
1500 wUnshadeWindow(wwin);
1501 else
1502 wShadeWindow(wwin);
1504 break;
1505 case WKBD_MOVERESIZE:
1506 if (ISMAPPED(wwin) && ISFOCUSED(wwin) &&
1507 (IS_RESIZABLE(wwin) || IS_MOVABLE(wwin))) {
1508 CloseWindowMenu(scr);
1510 wKeyboardMoveResizeWindow(wwin);
1512 break;
1513 case WKBD_CLOSE:
1514 if (ISMAPPED(wwin) && ISFOCUSED(wwin) && !WFLAGP(wwin, no_closable)) {
1515 CloseWindowMenu(scr);
1516 if (wwin->protocols.DELETE_WINDOW)
1517 wClientSendProtocol(wwin, _XA_WM_DELETE_WINDOW,
1518 event->xkey.time);
1520 break;
1521 case WKBD_SELECT:
1522 if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1523 wSelectWindow(wwin, !wwin->flags.selected);
1525 break;
1526 case WKBD_FOCUSNEXT:
1527 StartWindozeCycle(wwin, event, True);
1528 break;
1530 case WKBD_FOCUSPREV:
1531 StartWindozeCycle(wwin, event, False);
1532 break;
1534 #if (defined(__STDC__) && !defined(UNIXCPP)) || defined(ANSICPP)
1535 #define GOTOWORKS(wk) case WKBD_WORKSPACE##wk:\
1536 i = (scr->current_workspace/10)*10 + wk - 1;\
1537 if (wPreferences.ws_advance || i<scr->workspace_count)\
1538 wWorkspaceChange(scr, i);\
1539 break
1540 #else
1541 #define GOTOWORKS(wk) case WKBD_WORKSPACE/**/wk:\
1542 i = (scr->current_workspace/10)*10 + wk - 1;\
1543 if (wPreferences.ws_advance || i<scr->workspace_count)\
1544 wWorkspaceChange(scr, i);\
1545 break
1546 #endif
1547 GOTOWORKS(1);
1548 GOTOWORKS(2);
1549 GOTOWORKS(3);
1550 GOTOWORKS(4);
1551 GOTOWORKS(5);
1552 GOTOWORKS(6);
1553 GOTOWORKS(7);
1554 GOTOWORKS(8);
1555 GOTOWORKS(9);
1556 GOTOWORKS(10);
1557 #undef GOTOWORKS
1558 case WKBD_NEXTWORKSPACE:
1559 wWorkspaceRelativeChange(scr, 1);
1560 break;
1561 case WKBD_PREVWORKSPACE:
1562 wWorkspaceRelativeChange(scr, -1);
1563 break;
1564 case WKBD_WINDOW1:
1565 case WKBD_WINDOW2:
1566 case WKBD_WINDOW3:
1567 case WKBD_WINDOW4:
1568 case WKBD_WINDOW5:
1569 case WKBD_WINDOW6:
1570 case WKBD_WINDOW7:
1571 case WKBD_WINDOW8:
1572 case WKBD_WINDOW9:
1573 case WKBD_WINDOW10:
1575 index = command-WKBD_WINDOW1;
1577 if (scr->shortcutWindows[index]) {
1578 WMArray *list = scr->shortcutWindows[index];
1579 int cw;
1580 int count = WMGetArrayItemCount(list);
1581 WWindow *twin;
1582 WMArrayIterator iter;
1583 WWindow *wwin;
1585 wUnselectWindows(scr);
1586 cw = scr->current_workspace;
1588 WM_ETARETI_ARRAY(list, wwin, iter) {
1589 if (count > 1)
1590 wWindowChangeWorkspace(wwin, cw);
1592 wMakeWindowVisible(wwin);
1594 if (count > 1)
1595 wSelectWindow(wwin, True);
1598 /* rotate the order of windows, to create a cycling effect */
1599 twin = WMGetFromArray(list, 0);
1600 WMDeleteFromArray(list, 0);
1601 WMAddToArray(list, twin);
1603 } else if (wwin && ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1604 if (scr->shortcutWindows[index]) {
1605 WMFreeArray(scr->shortcutWindows[index]);
1606 scr->shortcutWindows[index] = NULL;
1609 if (wwin->flags.selected && scr->selected_windows) {
1610 scr->shortcutWindows[index] =
1611 WMDuplicateArray(scr->selected_windows);
1612 /*WMRemoveFromArray(scr->shortcutWindows[index], wwin);
1613 WMInsertInArray(scr->shortcutWindows[index], 0, wwin);*/
1614 } else {
1615 scr->shortcutWindows[index] = WMCreateArray(4);
1616 WMAddToArray(scr->shortcutWindows[index], wwin);
1619 wSelectWindow(wwin, !wwin->flags.selected);
1620 XFlush(dpy);
1621 wusleep(3000);
1622 wSelectWindow(wwin, !wwin->flags.selected);
1623 XFlush(dpy);
1625 } else if (scr->selected_windows
1626 && WMGetArrayItemCount(scr->selected_windows)) {
1628 if (wwin->flags.selected && scr->selected_windows) {
1629 if (scr->shortcutWindows[index]) {
1630 WMFreeArray(scr->shortcutWindows[index]);
1632 scr->shortcutWindows[index] =
1633 WMDuplicateArray(scr->selected_windows);
1637 break;
1639 case WKBD_SWITCH_SCREEN:
1640 if (wScreenCount > 1) {
1641 WScreen *scr2;
1642 int i;
1644 /* find index of this screen */
1645 for (i = 0; i < wScreenCount; i++) {
1646 if (wScreenWithNumber(i) == scr)
1647 break;
1649 i++;
1650 if (i >= wScreenCount) {
1651 i = 0;
1653 scr2 = wScreenWithNumber(i);
1655 if (scr2) {
1656 XWarpPointer(dpy, scr->root_win, scr2->root_win, 0, 0, 0, 0,
1657 scr2->scr_width/2, scr2->scr_height/2);
1660 break;
1662 case WKBD_NEXTWSLAYER:
1663 case WKBD_PREVWSLAYER:
1665 int row, column;
1667 row = scr->current_workspace/10;
1668 column = scr->current_workspace%10;
1670 if (command==WKBD_NEXTWSLAYER) {
1671 if ((row+1)*10 < scr->workspace_count)
1672 wWorkspaceChange(scr, column+(row+1)*10);
1673 } else {
1674 if (row > 0)
1675 wWorkspaceChange(scr, column+(row-1)*10);
1678 break;
1679 case WKBD_CLIPLOWER:
1680 if (!wPreferences.flags.noclip)
1681 wDockLower(scr->workspaces[scr->current_workspace]->clip);
1682 break;
1683 case WKBD_CLIPRAISE:
1684 if (!wPreferences.flags.noclip)
1685 wDockRaise(scr->workspaces[scr->current_workspace]->clip);
1686 break;
1687 case WKBD_CLIPRAISELOWER:
1688 if (!wPreferences.flags.noclip)
1689 wDockRaiseLower(scr->workspaces[scr->current_workspace]->clip);
1690 break;
1691 #ifdef KEEP_XKB_LOCK_STATUS
1692 case WKBD_TOGGLE:
1693 if(wPreferences.modelock) {
1694 /*toggle*/
1695 wwin = scr->focused_window;
1697 if (wwin && wwin->flags.mapped
1698 && wwin->frame->workspace == wwin->screen_ptr->current_workspace
1699 && !wwin->flags.miniaturized && !wwin->flags.hidden) {
1700 XkbGetState(dpy,XkbUseCoreKbd,&staterec);
1702 wwin->frame->languagemode = wwin->frame->last_languagemode;
1703 wwin->frame->last_languagemode = staterec.group;
1704 XkbLockGroup(dpy,XkbUseCoreKbd, wwin->frame->languagemode);
1708 break;
1709 #endif /* KEEP_XKB_LOCK_STATUS */
1710 #ifdef VIRTUAL_DESKTOP
1711 case WKBD_VDESK_LEFT:
1712 wWorkspaceKeyboardMoveDesktop(scr, VEC_LEFT);
1713 break;
1715 case WKBD_VDESK_RIGHT:
1716 wWorkspaceKeyboardMoveDesktop(scr, VEC_RIGHT);
1717 break;
1719 case WKBD_VDESK_UP:
1720 wWorkspaceKeyboardMoveDesktop(scr, VEC_UP);
1721 break;
1723 case WKBD_VDESK_DOWN:
1724 wWorkspaceKeyboardMoveDesktop(scr, VEC_DOWN);
1725 break;
1726 #endif
1732 static void
1733 handleMotionNotify(XEvent *event)
1735 WScreen *scr = wScreenForRootWindow(event->xmotion.root);
1737 if (wPreferences.scrollable_menus) {
1738 WMPoint p = wmkpoint(event->xmotion.x_root, event->xmotion.y_root);
1739 WMRect rect = wGetRectForHead(scr, wGetHeadForPoint(scr, p));
1741 if (scr->flags.jump_back_pending ||
1742 p.x <= (rect.pos.x + 1) ||
1743 p.x >= (rect.pos.x + rect.size.width - 2) ||
1744 p.y <= (rect.pos.y + 1) ||
1745 p.y >= (rect.pos.y + rect.size.height - 2)) {
1746 WMenu *menu;
1747 #ifdef DEBUG
1748 printf("pointer at screen edge\n");
1749 #endif
1750 menu = wMenuUnderPointer(scr);
1751 if (menu!=NULL)
1752 wMenuScroll(menu, event);
1756 #if 0 // what is with this? -Dan
1757 if (event->xmotion.subwindow == None)
1758 return;
1760 if (scr->scrolledFMaximize != None) {
1761 WWindow *twin;
1763 twin = wWindowFor(scr->scrolledFMaximize);
1764 if (twin && twin->frame_y ==) {
1768 scr->scrolledFMaximize = NULL;
1770 } else {
1772 /* scroll full maximized window */
1773 if (event->xmotion.y_root < 1
1774 || event->xmotion.y_root > scr->scr_height - 1) {
1776 wwin = wWindowFor(event->xmotion.subwindow);
1778 if (wwin && (wwin->flags.maximized & MAX_VERTICAL)
1779 && WFLAGP(wwin, full_maximize)
1780 && event->xmotion.x_root >= wwin->frame_x
1781 && event->xmotion.x_root <= wwin->frame_x + wwin->frame->core->width) {
1783 if (HAS_BORDER(wwin)
1784 && wwin->frame_y <= - wwin->frame->top_width) {
1786 wWindowMove(wwin, wwin->frame_x, 0);
1787 wwin->flags.dragged_while_fmaximized = 0;
1789 } else if (HAS_RESIZEBAR(wwin)
1790 && wwin->frame_y + wwin->frame->core->height >=
1791 scr->scr_height + wwin->frame->bottom_width) {
1793 int y = scr->scr_height + wwin->frame->bottom_width;
1795 y = scr->scr_height - wwin->frame_y - wwin->frame->core->height;
1797 wWindowMove(wwin, wwin->frame_x, y);
1798 wwin->flags.dragged_while_fmaximized = 0;
1802 #endif
1806 static void
1807 handleVisibilityNotify(XEvent *event)
1809 WWindow *wwin;
1811 wwin = wWindowFor(event->xvisibility.window);
1812 if (!wwin)
1813 return;
1814 wwin->flags.obscured =
1815 (event->xvisibility.state == VisibilityFullyObscured);