fixed many bugs, removed linked list
[wmaker-crm.git] / src / event.c
blob9de886b1de2eb6e6aab51dd60a69bd16ea589131
1 /* event.c- event loop and handling
2 *
3 * Window Maker window manager
4 *
5 * Copyright (c) 1997, 1998 Alfredo K. Kojima
6 *
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>
32 #include <X11/Xlib.h>
33 #include <X11/Xutil.h>
34 #ifdef SHAPE
35 #include <X11/extensions/shape.h>
36 #endif
37 #ifdef XDND
38 #include "xdnd.h"
39 #endif
41 #ifdef KEEP_XKB_LOCK_STATUS
42 #include <X11/XKBlib.h>
43 #endif /* KEEP_XKB_LOCK_STATUS */
45 #include "WindowMaker.h"
46 #include "window.h"
47 #include "actions.h"
48 #include "client.h"
49 #include "funcs.h"
50 #include "keybind.h"
51 #include "application.h"
52 #include "stacking.h"
53 #include "defaults.h"
54 #include "workspace.h"
55 #include "dock.h"
56 #include "framewin.h"
57 #include "properties.h"
58 #include "balloon.h"
60 #ifdef GNOME_STUFF
61 # include "gnome.h"
62 #endif
63 #ifdef KWM_HINTS
64 # include "kwm.h"
65 #endif
67 /******** Global Variables **********/
68 extern XContext wWinContext;
70 extern Cursor wCursor[WCUR_LAST];
72 extern WShortKey wKeyBindings[WKBD_LAST];
73 extern int wScreenCount;
74 extern Time LastTimestamp;
75 extern Time LastFocusChange;
77 extern WPreferences wPreferences;
79 #define MOD_MASK wPreferences.modifier_mask
81 extern Atom _XA_WM_COLORMAP_NOTIFY;
83 extern Atom _XA_WM_CHANGE_STATE;
84 extern Atom _XA_WM_DELETE_WINDOW;
85 extern Atom _XA_GNUSTEP_WM_MINIATURIZE_WINDOW;
86 extern Atom _XA_WINDOWMAKER_WM_FUNCTION;
87 extern Atom _XA_WINDOWMAKER_COMMAND;
89 #ifdef OFFIX_DND
90 extern Atom _XA_DND_PROTOCOL;
91 #endif
94 #ifdef SHAPE
95 extern Bool wShapeSupported;
96 extern int wShapeEventBase;
97 #endif
99 #ifdef KEEP_XKB_LOCK_STATUS
100 extern int wXkbEventBase;
101 #endif
103 /* special flags */
104 extern char WDelayedActionSet;
107 /************ Local stuff ***********/
110 static void saveTimestamp(XEvent *event);
111 static void handleColormapNotify();
112 static void handleMapNotify(), handleUnmapNotify();
113 static void handleButtonPress(), handleExpose();
114 static void handleDestroyNotify();
115 static void handleConfigureRequest();
116 static void handleMapRequest();
117 static void handlePropertyNotify();
118 static void handleEnterNotify();
119 static void handleLeaveNotify();
120 static void handleExtensions();
121 static void handleClientMessage();
122 static void handleKeyPress();
123 static void handleFocusIn();
124 static void handleMotionNotify();
125 static void handleVisibilityNotify();
128 #ifdef SHAPE
129 static void handleShapeNotify();
130 #endif
132 /* called from the signal handler */
133 void NotifyDeadProcess(pid_t pid, unsigned char status);
135 /* real dead process handler */
136 static void handleDeadProcess(void *foo);
139 typedef struct DeadProcesses {
140 pid_t pid;
141 unsigned char exit_status;
142 } DeadProcesses;
144 /* stack of dead processes */
145 static DeadProcesses deadProcesses[MAX_DEAD_PROCESSES];
146 static int deadProcessPtr=0;
149 typedef struct DeathHandler {
150 WDeathHandler *callback;
151 pid_t pid;
152 void *client_data;
153 } DeathHandler;
155 static WMBag *deathHandlers=NULL;
159 WMagicNumber
160 wAddDeathHandler(pid_t pid, WDeathHandler *callback, void *cdata)
162 DeathHandler *handler;
164 handler = malloc(sizeof(DeathHandler));
165 if (!handler)
166 return 0;
168 handler->pid = pid;
169 handler->callback = callback;
170 handler->client_data = cdata;
172 if (!deathHandlers)
173 deathHandlers = WMCreateBag(8);
175 WMPutInBag(deathHandlers, handler);
177 return handler;
182 void
183 wDeleteDeathHandler(WMagicNumber id)
185 DeathHandler *handler=(DeathHandler*)id;
187 if (!handler || !deathHandlers)
188 return;
190 WMRemoveFromBag(deathHandlers, handler);
192 free(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);
220 /* for the case that all that is wanted to be dispatched is
221 * the stuff above */
222 if (!event)
223 return;
225 saveTimestamp(event);
226 switch (event->type) {
227 case MapRequest:
228 handleMapRequest(event);
229 break;
231 case KeyPress:
232 handleKeyPress(event);
233 break;
235 case MotionNotify:
236 handleMotionNotify(event);
237 break;
239 case ConfigureRequest:
240 handleConfigureRequest(event);
241 break;
243 case DestroyNotify:
244 handleDestroyNotify(event);
245 break;
247 case MapNotify:
248 handleMapNotify(event);
249 break;
251 case UnmapNotify:
252 handleUnmapNotify(event);
253 break;
255 case ButtonPress:
256 handleButtonPress(event);
257 break;
259 case Expose:
260 handleExpose(event);
261 break;
263 case PropertyNotify:
264 handlePropertyNotify(event);
265 break;
267 case EnterNotify:
268 handleEnterNotify(event);
269 break;
271 case LeaveNotify:
272 handleLeaveNotify(event);
273 break;
275 case ClientMessage:
276 handleClientMessage(event);
277 break;
279 case ColormapNotify:
280 handleColormapNotify(event);
281 break;
283 case MappingNotify:
284 if (event->xmapping.request == MappingKeyboard
285 || event->xmapping.request == MappingModifier)
286 XRefreshKeyboardMapping(&event->xmapping);
287 break;
289 case FocusIn:
290 handleFocusIn(event);
291 break;
293 case VisibilityNotify:
294 handleVisibilityNotify(event);
295 break;
296 default:
297 handleExtensions(event);
298 break;
304 *----------------------------------------------------------------------
305 * EventLoop-
306 * Processes X and internal events indefinitely.
308 * Returns:
309 * Never returns
311 * Side effects:
312 * The LastTimestamp global variable is updated.
313 *----------------------------------------------------------------------
315 void
316 EventLoop()
318 XEvent event;
320 for(;;) {
321 WMNextEvent(dpy, &event);
322 WMHandleEvent(&event);
328 Bool
329 IsDoubleClick(WScreen *scr, XEvent *event)
331 if ((scr->last_click_time>0) &&
332 (event->xbutton.time-scr->last_click_time<=wPreferences.dblclick_time)
333 && (event->xbutton.button == scr->last_click_button)
334 && (event->xbutton.window == scr->last_click_window)) {
336 scr->flags.next_click_is_not_double = 1;
337 scr->last_click_time = 0;
338 scr->last_click_window = event->xbutton.window;
340 return True;
342 return False;
346 void
347 NotifyDeadProcess(pid_t pid, unsigned char status)
349 if (deadProcessPtr>=MAX_DEAD_PROCESSES-1) {
350 wwarning("stack overflow: too many dead processes");
351 return;
353 /* stack the process to be handled later,
354 * as this is called from the signal handler */
355 deadProcesses[deadProcessPtr].pid = pid;
356 deadProcesses[deadProcessPtr].exit_status = status;
357 deadProcessPtr++;
361 static void
362 handleDeadProcess(void *foo)
364 DeathHandler *tmp;
365 int i;
367 for (i=0; i<deadProcessPtr; i++) {
368 wWindowDeleteSavedStatesForPID(deadProcesses[i].pid);
371 if (!deathHandlers) {
372 deadProcessPtr=0;
373 return;
376 /* get the pids on the queue and call handlers */
377 while (deadProcessPtr>0) {
378 deadProcessPtr--;
380 for (i = WMGetBagItemCount(deathHandlers)-1; i >= 0; i--) {
381 tmp = WMGetFromBag(deathHandlers, i);
382 if (!tmp)
383 continue;
385 if (tmp->pid == deadProcesses[deadProcessPtr].pid) {
386 (*tmp->callback)(tmp->pid,
387 deadProcesses[deadProcessPtr].exit_status,
388 tmp->client_data);
389 wDeleteDeathHandler(tmp);
396 static void
397 saveTimestamp(XEvent *event)
399 LastTimestamp = CurrentTime;
401 switch (event->type) {
402 case ButtonRelease:
403 case ButtonPress:
404 LastTimestamp = event->xbutton.time;
405 break;
406 case KeyPress:
407 case KeyRelease:
408 LastTimestamp = event->xkey.time;
409 break;
410 case MotionNotify:
411 LastTimestamp = event->xmotion.time;
412 break;
413 case PropertyNotify:
414 LastTimestamp = event->xproperty.time;
415 break;
416 case EnterNotify:
417 case LeaveNotify:
418 LastTimestamp = event->xcrossing.time;
419 break;
420 case SelectionClear:
421 LastTimestamp = event->xselectionclear.time;
422 break;
423 case SelectionRequest:
424 LastTimestamp = event->xselectionrequest.time;
425 break;
426 case SelectionNotify:
427 LastTimestamp = event->xselection.time;
428 #ifdef XDND
429 wXDNDProcessSelection(event);
430 #endif
431 break;
436 static void
437 handleExtensions(XEvent *event)
439 #ifdef KEEP_XKB_LOCK_STATUS
440 XkbEvent *xkbevent;
441 xkbevent = (XkbEvent *)event;
442 #endif /*KEEP_XKB_LOCK_STATUS*/
443 #ifdef SHAPE
444 if (wShapeSupported && event->type == (wShapeEventBase+ShapeNotify)) {
445 handleShapeNotify(event);
447 #endif
448 #ifdef KEEP_XKB_LOCK_STATUS
449 if (wPreferences.modelock && (xkbevent->type == wXkbEventBase)){
450 handleXkbIndicatorStateNotify(event);
452 #endif /*KEEP_XKB_LOCK_STATUS*/
456 static void
457 handleMapRequest(XEvent *ev)
459 WWindow *wwin;
460 WScreen *scr = NULL;
461 Window window = ev->xmaprequest.window;
463 #ifdef DEBUG
464 dprintf("got map request for %x\n", (unsigned)window);
465 #endif
467 if ((wwin = wWindowFor(window))) {
468 if (wwin->flags.shaded) {
469 wUnshadeWindow(wwin);
471 /* deiconify window */
472 if (wwin->flags.miniaturized) {
473 wDeiconifyWindow(wwin);
474 } else if (wwin->flags.hidden) {
475 WApplication *wapp = wApplicationOf(wwin->main_window);
476 /* go to the last workspace that the user worked on the app */
477 #ifndef REDUCE_APPICONS
478 /* This severely breaks REDUCE_APPICONS. last_workspace is a neat
479 * concept but it needs to be reworked to handle REDUCE_APPICONS -cls
481 if (wapp) {
482 wWorkspaceChange(wwin->screen_ptr, wapp->last_workspace);
484 #endif
485 wUnhideApplication(wapp, False, False);
487 return;
490 scr = wScreenForRootWindow(ev->xmaprequest.parent);
492 wwin = wManageWindow(scr, window);
495 * This is to let the Dock know that the application it launched
496 * has already been mapped (eg: it has finished launching).
497 * It is not necessary for normally docked apps, but is needed for
498 * apps that were forcedly docked (like with dockit).
500 if (scr->last_dock) {
501 if (wwin && wwin->main_window!=None && wwin->main_window!=window)
502 wDockTrackWindowLaunch(scr->last_dock, wwin->main_window);
503 else
504 wDockTrackWindowLaunch(scr->last_dock, window);
507 if (wwin) {
508 wClientSetState(wwin, NormalState, None);
509 if (wwin->flags.maximized) {
510 wMaximizeWindow(wwin, wwin->flags.maximized);
512 if (wwin->flags.shaded) {
513 wwin->flags.shaded = 0;
514 wwin->flags.skip_next_animation = 1;
515 wShadeWindow(wwin);
517 if (wwin->flags.miniaturized) {
518 wwin->flags.miniaturized = 0;
519 wwin->flags.skip_next_animation = 1;
520 wIconifyWindow(wwin);
522 if (wwin->flags.hidden) {
523 WApplication *wapp = wApplicationOf(wwin->main_window);
525 wwin->flags.hidden = 0;
526 wwin->flags.skip_next_animation = 1;
527 if (wapp) {
528 wHideApplication(wapp);
535 static void
536 handleDestroyNotify(XEvent *event)
538 WWindow *wwin;
539 WApplication *app;
540 Window window = event->xdestroywindow.window;
542 #ifdef DEBUG
543 dputs("got destroy notify");
544 #endif
546 wwin = wWindowFor(window);
547 if (wwin) {
548 wUnmanageWindow(wwin, False, True);
551 app = wApplicationOf(window);
552 if (app) {
553 if (window == app->main_window) {
554 app->refcount = 0;
555 wwin = app->main_window_desc->screen_ptr->focused_window;
556 while (wwin) {
557 if (wwin->main_window == window) {
558 wwin->main_window = None;
560 wwin = wwin->prev;
563 wApplicationDestroy(app);
566 #ifdef KWM_HINTS
567 wKWMCheckDestroy(&event->xdestroywindow);
568 #endif
573 static void
574 handleExpose(XEvent *event)
576 WObjDescriptor *desc;
577 XEvent ev;
579 #ifdef DEBUG
580 dputs("got expose");
581 #endif
583 while (XCheckTypedWindowEvent(dpy, event->xexpose.window, Expose, &ev));
585 if (XFindContext(dpy, event->xexpose.window, wWinContext,
586 (XPointer *)&desc)==XCNOENT) {
587 return;
590 if (desc->handle_expose) {
591 (*desc->handle_expose)(desc, event);
596 /* bindable */
597 static void
598 handleButtonPress(XEvent *event)
600 WObjDescriptor *desc;
601 WScreen *scr;
603 #ifdef DEBUG
604 dputs("got button press");
605 #endif
607 scr = wScreenForRootWindow(event->xbutton.root);
609 #ifdef BALLOON_TEXT
610 wBalloonHide(scr);
611 #endif
614 #ifndef LITE
615 if (event->xbutton.window==scr->root_win) {
617 if (event->xbutton.button==wPreferences.menu_button) {
618 OpenRootMenu(scr, event->xbutton.x_root,
619 event->xbutton.y_root, False);
620 /* ugly hack */
621 if (scr->root_menu) {
622 if (scr->root_menu->brother->flags.mapped)
623 event->xbutton.window = scr->root_menu->brother->frame->core->window;
624 else
625 event->xbutton.window = scr->root_menu->frame->core->window;
627 } else if (event->xbutton.button==wPreferences.windowl_button) {
628 OpenSwitchMenu(scr, event->xbutton.x_root,
629 event->xbutton.y_root, False);
630 if (scr->switch_menu) {
631 if (scr->switch_menu->brother->flags.mapped)
632 event->xbutton.window = scr->switch_menu->brother->frame->core->window;
633 else
634 event->xbutton.window = scr->switch_menu->frame->core->window;
636 } else if (event->xbutton.button==wPreferences.select_button) {
637 wUnselectWindows(scr);
638 wSelectWindows(scr, event);
640 #ifdef MOUSE_WS_SWITCH
641 else if (event->xbutton.button==Button5) {
643 wWorkspaceRelativeChange(scr, -1);
645 } else if (event->xbutton.button==Button4) {
647 wWorkspaceRelativeChange(scr, 1);
650 #endif /* MOUSE_WS_SWITCH */
651 #ifdef GNOME_STUFF
652 else if (wGNOMEProxyizeButtonEvent(scr, event))
653 return;
654 #endif
656 #endif /* !LITE */
658 if (XFindContext(dpy, event->xbutton.subwindow, wWinContext,
659 (XPointer *)&desc)==XCNOENT) {
660 if (XFindContext(dpy, event->xbutton.window, wWinContext,
661 (XPointer *)&desc)==XCNOENT) {
662 return;
666 if (desc->handle_mousedown!=NULL) {
667 (*desc->handle_mousedown)(desc, event);
670 if (desc->parent_type == WCLASS_WINDOW) {
671 XSync(dpy, 0);
673 if (event->xbutton.state & MOD_MASK) {
674 XAllowEvents(dpy, AsyncPointer, CurrentTime);
677 if (wPreferences.focus_mode == WKF_CLICK) {
678 if (wPreferences.ignore_focus_click) {
679 XAllowEvents(dpy, AsyncPointer, CurrentTime);
681 XAllowEvents(dpy, ReplayPointer, CurrentTime);
683 XSync(dpy, 0);
684 } else if (desc->parent_type == WCLASS_APPICON
685 || desc->parent_type == WCLASS_MINIWINDOW
686 || desc->parent_type == WCLASS_DOCK_ICON) {
687 if (event->xbutton.state & MOD_MASK) {
688 XSync(dpy, 0);
689 XAllowEvents(dpy, AsyncPointer, CurrentTime);
690 XSync(dpy, 0);
694 /* save double-click information */
695 if (scr->flags.next_click_is_not_double) {
696 scr->flags.next_click_is_not_double = 0;
697 } else {
698 scr->last_click_time = event->xbutton.time;
699 scr->last_click_button = event->xbutton.button;
700 scr->last_click_window = event->xbutton.window;
705 static void
706 handleMapNotify(XEvent *event)
708 WWindow *wwin;
710 #ifdef DEBUG
711 dputs("got map");
712 #endif
714 wwin = wWindowFor(event->xmap.event);
715 if (wwin && wwin->client_win == event->xmap.event) {
716 if (wwin->flags.miniaturized) {
717 wDeiconifyWindow(wwin);
718 } else {
719 XGrabServer(dpy);
720 wWindowMap(wwin);
721 wClientSetState(wwin, NormalState, None);
722 XUngrabServer(dpy);
728 static void
729 handleUnmapNotify(XEvent *event)
731 WWindow *wwin;
732 XEvent ev;
733 Bool withdraw = False;
735 #ifdef DEBUG
736 dputs("got unmap");
737 #endif
739 /* only process windows with StructureNotify selected
740 * (ignore SubstructureNotify) */
741 wwin = wWindowFor(event->xunmap.window);
742 if (!wwin)
743 return;
745 /* whether the event is a Withdrawal request */
746 if (event->xunmap.event == wwin->screen_ptr->root_win
747 && event->xunmap.send_event)
748 withdraw = True;
750 if (wwin->client_win != event->xunmap.event && !withdraw)
751 return;
753 if (!wwin->flags.mapped && !withdraw
754 && wwin->frame->workspace == wwin->screen_ptr->current_workspace
755 && !wwin->flags.miniaturized && !wwin->flags.hidden)
756 return;
758 XGrabServer(dpy);
759 XUnmapWindow(dpy, wwin->frame->core->window);
760 wwin->flags.mapped = 0;
761 XSync(dpy, 0);
762 /* check if the window was destroyed */
763 if (XCheckTypedWindowEvent(dpy, wwin->client_win, DestroyNotify,&ev)) {
764 DispatchEvent(&ev);
765 } else {
766 Bool reparented = False;
768 if (XCheckTypedWindowEvent(dpy, wwin->client_win, ReparentNotify, &ev))
769 reparented = True;
771 /* withdraw window */
772 wwin->flags.mapped = 0;
773 if (!reparented)
774 wClientSetState(wwin, WithdrawnState, None);
776 /* if the window was reparented, do not reparent it back to the
777 * root window */
778 wUnmanageWindow(wwin, !reparented, False);
780 XUngrabServer(dpy);
784 static void
785 handleConfigureRequest(XEvent *event)
787 WWindow *wwin;
789 #ifdef DEBUG
790 dputs("got configure request");
791 #endif
792 if (!(wwin=wWindowFor(event->xconfigurerequest.window))) {
794 * Configure request for unmapped window
796 wClientConfigure(NULL, &(event->xconfigurerequest));
797 } else {
798 wClientConfigure(wwin, &(event->xconfigurerequest));
803 static void
804 handlePropertyNotify(XEvent *event)
806 WWindow *wwin;
807 WApplication *wapp;
808 Window jr;
809 int ji;
810 unsigned int ju;
811 WScreen *scr;
813 #ifdef DEBUG
814 dputs("got property notify");
815 #endif
816 if ((wwin=wWindowFor(event->xproperty.window))) {
817 if (!XGetGeometry(dpy, wwin->client_win, &jr, &ji, &ji,
818 &ju, &ju, &ju, &ju)) {
819 return;
821 wClientCheckProperty(wwin, &event->xproperty);
823 wapp = wApplicationOf(event->xproperty.window);
824 if (wapp) {
825 wClientCheckProperty(wapp->main_window_desc, &event->xproperty);
828 scr = wScreenForWindow(event->xproperty.window);
829 if (scr && scr->root_win == event->xproperty.window) {
830 #ifdef KWM_HINTS
831 wKWMCheckRootHintChange(scr, &event->xproperty);
832 #endif
837 static void
838 handleClientMessage(XEvent *event)
840 WWindow *wwin;
841 WObjDescriptor *desc;
843 #ifdef DEBUG
844 dputs("got client message");
845 #endif
846 /* handle transition from Normal to Iconic state */
847 if (event->xclient.message_type == _XA_WM_CHANGE_STATE
848 && event->xclient.format == 32
849 && event->xclient.data.l[0] == IconicState) {
851 wwin = wWindowFor(event->xclient.window);
852 if (!wwin) return;
853 if (!wwin->flags.miniaturized)
854 wIconifyWindow(wwin);
855 } else if (event->xclient.message_type == _XA_WM_COLORMAP_NOTIFY
856 && event->xclient.format == 32) {
857 WScreen *scr = wScreenSearchForRootWindow(event->xclient.window);
859 if (!scr)
860 return;
862 if (event->xclient.data.l[1] == 1) { /* starting */
863 wColormapAllowClientInstallation(scr, True);
864 } else { /* stopping */
865 wColormapAllowClientInstallation(scr, False);
867 } else if (event->xclient.message_type == _XA_WINDOWMAKER_COMMAND) {
869 wDefaultsCheckDomains("bla");
871 } else if (event->xclient.message_type == _XA_WINDOWMAKER_WM_FUNCTION) {
872 WApplication *wapp;
873 int done=0;
874 wapp = wApplicationOf(event->xclient.window);
875 if (wapp) {
876 switch (event->xclient.data.l[0]) {
877 case WMFHideOtherApplications:
878 wHideOtherApplications(wapp->main_window_desc);
879 done = 1;
880 break;
882 case WMFHideApplication:
883 wHideApplication(wapp);
884 done = 1;
885 break;
888 if (!done) {
889 wwin = wWindowFor(event->xclient.window);
890 if (wwin) {
891 switch (event->xclient.data.l[0]) {
892 case WMFHideOtherApplications:
893 wHideOtherApplications(wwin);
894 break;
896 case WMFHideApplication:
897 wHideApplication(wApplicationOf(wwin->main_window));
898 break;
902 #ifdef GNOME_STUFF
903 } else if (wGNOMEProcessClientMessage(&event->xclient)) {
904 /* do nothing */
905 #endif /* GNOME_STUFF */
906 #ifdef KWM_HINTS
907 } else if (wKWMProcessClientMessage(&event->xclient)) {
908 /* do nothing */
909 #endif /* KWM_HINTS */
910 #ifdef XDND
911 } else if (wXDNDProcessClientMessage(&event->xclient)) {
912 /* do nothing */
913 #endif /* XDND */
914 #ifdef OFFIX_DND
915 } else if (event->xclient.message_type==_XA_DND_PROTOCOL) {
916 WScreen *scr = wScreenForWindow(event->xclient.window);
917 if (scr && wDockReceiveDNDDrop(scr,event))
918 goto redirect_message;
919 #endif /* OFFIX_DND */
920 } else {
921 #ifdef OFFIX_DND
922 redirect_message:
923 #endif
925 * Non-standard thing, but needed by OffiX DND.
926 * For when the icon frame gets a ClientMessage
927 * that should have gone to the icon_window.
929 if (XFindContext(dpy, event->xbutton.window, wWinContext,
930 (XPointer *)&desc)!=XCNOENT) {
931 struct WIcon *icon=NULL;
933 if (desc->parent_type == WCLASS_MINIWINDOW) {
934 icon = (WIcon*)desc->parent;
935 } else if (desc->parent_type == WCLASS_DOCK_ICON
936 || desc->parent_type == WCLASS_APPICON) {
937 icon = ((WAppIcon*)desc->parent)->icon;
939 if (icon && (wwin=icon->owner)) {
940 if (wwin->client_win!=event->xclient.window) {
941 event->xclient.window = wwin->client_win;
942 XSendEvent(dpy, wwin->client_win, False, NoEventMask,
943 event);
951 static void
952 raiseWindow(WScreen *scr)
954 WWindow *wwin;
956 scr->autoRaiseTimer = NULL;
958 wwin = wWindowFor(scr->autoRaiseWindow);
959 if (!wwin)
960 return;
962 if (!wwin->flags.destroyed && wwin->flags.focused) {
963 wRaiseFrame(wwin->frame->core);
964 /* this is needed or a race condition will occur */
965 XSync(dpy, False);
970 static void
971 handleEnterNotify(XEvent *event)
973 WMenu *menu;
974 WWindow *wwin;
975 WObjDescriptor *desc = NULL;
976 XEvent ev;
977 WScreen *scr = wScreenForRootWindow(event->xcrossing.root);
980 #ifdef DEBUG
981 dputs("got enter notify");
982 #endif
984 if (XCheckTypedWindowEvent(dpy, event->xcrossing.window, LeaveNotify,
985 &ev)) {
986 /* already left the window... */
987 saveTimestamp(&ev);
988 if (ev.xcrossing.mode==event->xcrossing.mode
989 && ev.xcrossing.detail==event->xcrossing.detail) {
990 return;
994 /* start my fix scrolled menus */
995 if (wPreferences.scrollable_menus) {
996 if (scr->flags.jump_back_pending ||
997 event->xcrossing.x_root <= 1 ||
998 event->xcrossing.x_root >= (scr->scr_width - 2) ||
999 event->xcrossing.y_root <= 1 ||
1000 event->xcrossing.y_root >= (scr->scr_height - 2)) {
1002 #ifdef DEBUG
1003 debug_puts("pointer at screen edge in EnterNotify event, fear");
1004 #endif
1006 menu = wMenuUnderPointer(scr);
1007 if (menu!=NULL) {
1008 wMenuScroll(menu, event);
1009 return;
1013 /* end fix scrolled menus */
1016 if (XFindContext(dpy, event->xcrossing.window, wWinContext,
1017 (XPointer *)&desc)!=XCNOENT) {
1018 if(desc->handle_enternotify)
1019 (*desc->handle_enternotify)(desc, event);
1022 /* enter to window */
1023 wwin = wWindowFor(event->xcrossing.window);
1024 if (!wwin) {
1025 if (wPreferences.focus_mode==WKF_POINTER
1026 && event->xcrossing.window==event->xcrossing.root) {
1027 wSetFocusTo(scr, NULL);
1029 if (wPreferences.colormap_mode==WKF_POINTER) {
1030 wColormapInstallForWindow(scr, NULL);
1032 if (scr->autoRaiseTimer
1033 && event->xcrossing.root==event->xcrossing.window) {
1034 WMDeleteTimerHandler(scr->autoRaiseTimer);
1035 scr->autoRaiseTimer = NULL;
1037 } else {
1038 /* set auto raise timer even if in focus-follows-mouse mode
1039 * and the event is for the frame window, even if the window
1040 * has focus already. useful if you move the pointer from a focused
1041 * window to the root window and back pretty fast
1043 * set focus if in focus-follows-mouse mode and the event
1044 * is for the frame window and window doesn't have focus yet */
1045 if ((wPreferences.focus_mode==WKF_POINTER
1046 || wPreferences.focus_mode==WKF_SLOPPY)
1047 && wwin->frame->core->window==event->xcrossing.window
1048 && !scr->flags.doing_alt_tab) {
1050 if (!wwin->flags.focused && !WFLAGP(wwin, no_focusable))
1051 wSetFocusTo(scr, wwin);
1053 if (scr->autoRaiseTimer)
1054 WMDeleteTimerHandler(scr->autoRaiseTimer);
1055 scr->autoRaiseTimer = NULL;
1057 if (wPreferences.raise_delay && !WFLAGP(wwin, no_focusable)) {
1058 scr->autoRaiseWindow = wwin->frame->core->window;
1059 scr->autoRaiseTimer
1060 = WMAddTimerHandler(wPreferences.raise_delay,
1061 (WMCallback*)raiseWindow, scr);
1064 /* Install colormap for window, if the colormap installation mode
1065 * is colormap_follows_mouse */
1066 if (wPreferences.colormap_mode==WKF_POINTER) {
1067 if (wwin->client_win==event->xcrossing.window)
1068 wColormapInstallForWindow(scr, wwin);
1069 else
1070 wColormapInstallForWindow(scr, NULL);
1074 /* a little kluge to hide the clip balloon */
1075 if (!wPreferences.flags.noclip && scr->flags.clip_balloon_mapped) {
1076 if (!desc) {
1077 XUnmapWindow(dpy, scr->clip_balloon);
1078 scr->flags.clip_balloon_mapped = 0;
1079 } else {
1080 if (desc->parent_type!=WCLASS_DOCK_ICON
1081 || scr->clip_icon != desc->parent) {
1082 XUnmapWindow(dpy, scr->clip_balloon);
1083 scr->flags.clip_balloon_mapped = 0;
1088 if (event->xcrossing.window == event->xcrossing.root
1089 && event->xcrossing.detail == NotifyNormal
1090 && event->xcrossing.detail != NotifyInferior
1091 && wPreferences.focus_mode != WKF_CLICK) {
1093 wSetFocusTo(scr, scr->focused_window);
1096 #ifdef BALLOON_TEXT
1097 wBalloonEnteredObject(scr, desc);
1098 #endif
1102 static void
1103 handleLeaveNotify(XEvent *event)
1105 WObjDescriptor *desc = NULL;
1107 if (XFindContext(dpy, event->xcrossing.window, wWinContext,
1108 (XPointer *)&desc)!=XCNOENT) {
1109 if(desc->handle_leavenotify)
1110 (*desc->handle_leavenotify)(desc, event);
1112 if (event->xcrossing.window == event->xcrossing.root
1113 && event->xcrossing.mode == NotifyNormal
1114 && event->xcrossing.detail != NotifyInferior
1115 && wPreferences.focus_mode != WKF_CLICK) {
1117 WScreen *scr = wScreenForRootWindow(event->xcrossing.root);
1119 wSetFocusTo(scr, NULL);
1124 #ifdef SHAPE
1125 static void
1126 handleShapeNotify(XEvent *event)
1128 XShapeEvent *shev = (XShapeEvent*)event;
1129 WWindow *wwin;
1130 XEvent ev;
1132 #ifdef DEBUG
1133 dputs("got shape notify");
1134 #endif
1136 while (XCheckTypedWindowEvent(dpy, shev->window, event->type, &ev)) {
1137 XShapeEvent *sev = (XShapeEvent*)&ev;
1139 if (sev->kind == ShapeBounding) {
1140 if (sev->shaped == shev->shaped) {
1141 *shev = *sev;
1142 } else {
1143 XPutBackEvent(dpy, &ev);
1144 break;
1149 wwin = wWindowFor(shev->window);
1150 if (!wwin || shev->kind != ShapeBounding)
1151 return;
1153 if (!shev->shaped && wwin->flags.shaped) {
1155 wwin->flags.shaped = 0;
1156 wWindowClearShape(wwin);
1158 } else if (shev->shaped) {
1160 wwin->flags.shaped = 1;
1161 wWindowSetShape(wwin);
1164 #endif /* SHAPE */
1166 #ifdef KEEP_XKB_LOCK_STATUS
1167 /* please help ]d if you know what to do */
1168 handleXkbIndicatorStateNotify(XEvent *event)
1170 WWindow *wwin;
1171 WScreen *scr;
1172 XkbStateRec staterec;
1173 int i;
1175 for (i=0; i<wScreenCount; i++) {
1176 scr = wScreenWithNumber(i);
1177 wwin = scr->focused_window;
1178 if (wwin && wwin->flags.focused) {
1179 XkbGetState(dpy,XkbUseCoreKbd,&staterec);
1180 if (wwin->frame->languagemode != staterec.group) {
1181 wwin->frame->last_languagemode = wwin->frame->languagemode;
1182 wwin->frame->languagemode = staterec.group;
1184 #ifdef XKB_BUTTON_HINT
1185 if (wwin->frame->titlebar) {
1186 wFrameWindowPaint(wwin->frame);
1188 #endif
1192 #endif /*KEEP_XKB_LOCK_STATUS*/
1194 static void
1195 handleColormapNotify(XEvent *event)
1197 WWindow *wwin;
1198 WScreen *scr;
1199 Bool reinstall = False;
1201 wwin = wWindowFor(event->xcolormap.window);
1202 if (!wwin)
1203 return;
1205 scr = wwin->screen_ptr;
1207 do {
1208 if (wwin) {
1209 if (event->xcolormap.new) {
1210 XWindowAttributes attr;
1212 XGetWindowAttributes(dpy, wwin->client_win, &attr);
1214 if (wwin == scr->cmap_window && wwin->cmap_window_no == 0)
1215 scr->current_colormap = attr.colormap;
1217 reinstall = True;
1218 } else if (event->xcolormap.state == ColormapUninstalled &&
1219 scr->current_colormap == event->xcolormap.colormap) {
1221 /* some bastard app (like XV) removed our colormap */
1223 * can't enforce or things like xscreensaver wont work
1224 * reinstall = True;
1226 } else if (event->xcolormap.state == ColormapInstalled &&
1227 scr->current_colormap == event->xcolormap.colormap) {
1229 /* someone has put our colormap back */
1230 reinstall = False;
1233 } while (XCheckTypedEvent(dpy, ColormapNotify, event)
1234 && ((wwin = wWindowFor(event->xcolormap.window)) || 1));
1236 if (reinstall && scr->current_colormap!=None) {
1237 if (!scr->flags.colormap_stuff_blocked)
1238 XInstallColormap(dpy, scr->current_colormap);
1244 static void
1245 handleFocusIn(XEvent *event)
1247 WWindow *wwin;
1250 * For applications that like stealing the focus.
1252 while (XCheckTypedEvent(dpy, FocusIn, event));
1253 saveTimestamp(event);
1254 if (event->xfocus.mode == NotifyUngrab
1255 || event->xfocus.mode == NotifyGrab
1256 || event->xfocus.detail > NotifyNonlinearVirtual) {
1257 return;
1260 wwin = wWindowFor(event->xfocus.window);
1261 if (wwin && !wwin->flags.focused) {
1262 if (wwin->flags.mapped)
1263 wSetFocusTo(wwin->screen_ptr, wwin);
1264 else
1265 wSetFocusTo(wwin->screen_ptr, NULL);
1266 } else if (!wwin) {
1267 WScreen *scr = wScreenForWindow(event->xfocus.window);
1268 if (scr)
1269 wSetFocusTo(scr, NULL);
1274 static WWindow*
1275 windowUnderPointer(WScreen *scr)
1277 unsigned int mask;
1278 int foo;
1279 Window bar, win;
1281 if (XQueryPointer(dpy, scr->root_win, &bar, &win, &foo, &foo, &foo, &foo,
1282 &mask))
1283 return wWindowFor(win);
1284 return NULL;
1288 #ifdef WEENDOZE_CYCLE
1290 static WWindow*
1291 nextToFocusAfter(WWindow *wwin)
1293 WWindow *tmp = wwin->prev;
1295 while (tmp) {
1296 if (wWindowCanReceiveFocus(tmp) && !WFLAGP(tmp, skip_window_list)) {
1298 return tmp;
1300 tmp = tmp->prev;
1303 tmp = wwin;
1304 /* start over from the beginning of the list */
1305 while (tmp->next)
1306 tmp = tmp->next;
1308 while (tmp && tmp != wwin) {
1309 if (wWindowCanReceiveFocus(tmp) && !WFLAGP(tmp, skip_window_list)) {
1311 return tmp;
1313 tmp = tmp->prev;
1316 return wwin;
1320 static WWindow*
1321 nextToFocusBefore(WWindow *wwin)
1323 WWindow *tmp = wwin->next;
1325 while (tmp) {
1326 if (wWindowCanReceiveFocus(tmp) && !WFLAGP(tmp, skip_window_list)) {
1328 return tmp;
1330 tmp = tmp->next;
1333 /* start over from the beginning of the list */
1334 tmp = wwin;
1335 while (tmp->prev)
1336 tmp = tmp->prev;
1338 while (tmp && tmp != wwin) {
1339 if (wWindowCanReceiveFocus(tmp) && !WFLAGP(tmp, skip_window_list)) {
1341 return tmp;
1343 tmp = tmp->next;
1346 return wwin;
1351 static void
1352 doWindozeCycle(WWindow *wwin, XEvent *event, Bool next)
1354 WScreen *scr = wScreenForRootWindow(event->xkey.root);
1355 Bool done = False;
1356 Bool openedSwitchMenu = False;
1357 WWindow *newFocused;
1358 WWindow *oldFocused;
1359 int modifiers;
1360 XModifierKeymap *keymap;
1362 if (!wwin)
1363 return;
1365 /* dputs("IN");*/
1366 keymap = XGetModifierMapping(dpy);
1369 XGrabKeyboard(dpy, scr->root_win, False, GrabModeAsync, GrabModeAsync,
1370 CurrentTime);
1372 if (next) {
1373 newFocused = nextToFocusAfter(wwin);
1374 } else {
1375 newFocused = nextToFocusBefore(wwin);
1378 scr->flags.doing_alt_tab = 1;
1380 wWindowFocus(newFocused, scr->focused_window);
1381 oldFocused = newFocused;
1382 if (wPreferences.circ_raise)
1383 wRaiseFrame(newFocused->frame->core);
1385 if (wPreferences.popup_switchmenu &&
1386 (!scr->switch_menu || !scr->switch_menu->flags.mapped)) {
1388 OpenSwitchMenu(scr, scr->scr_width/2, scr->scr_height/2, False);
1389 openedSwitchMenu = True;
1392 while (!done) {
1393 XEvent ev;
1395 WMMaskEvent(dpy,KeyPressMask|KeyReleaseMask|ExposureMask, &ev);
1396 /* WMNextEvent(dpy, &ev);*/
1397 if (ev.type != KeyRelease && ev.type != KeyPress) {
1398 WMHandleEvent(&ev);
1399 continue;
1401 /*dputs("EV");*/
1402 /* ignore CapsLock */
1403 modifiers = ev.xkey.state & ValidModMask;
1405 if (ev.type == KeyPress
1406 && wKeyBindings[WKBD_FOCUSNEXT].keycode == ev.xkey.keycode
1407 && wKeyBindings[WKBD_FOCUSNEXT].modifier == modifiers) {
1409 UpdateSwitchMenu(scr, newFocused, ACTION_CHANGE_STATE);
1410 newFocused = nextToFocusAfter(newFocused);
1411 wWindowFocus(newFocused, oldFocused);
1412 oldFocused = newFocused;
1413 if (wPreferences.circ_raise)
1414 wRaiseFrame(newFocused->frame->core);
1415 UpdateSwitchMenu(scr, newFocused, ACTION_CHANGE_STATE);
1417 } else if (ev.type == KeyPress
1418 && wKeyBindings[WKBD_FOCUSPREV].keycode == ev.xkey.keycode
1419 && wKeyBindings[WKBD_FOCUSPREV].modifier == modifiers) {
1421 UpdateSwitchMenu(scr, newFocused, ACTION_CHANGE_STATE);
1422 newFocused = nextToFocusBefore(newFocused);
1423 wWindowFocus(newFocused, oldFocused);
1424 oldFocused = newFocused;
1425 if (wPreferences.circ_raise)
1426 wRaiseFrame(newFocused->frame->core);
1427 UpdateSwitchMenu(scr, newFocused, ACTION_CHANGE_STATE);
1429 if (ev.type == KeyRelease) {
1430 int i;
1432 for (i = 0; i <= 8 * keymap->max_keypermod; i++) {
1433 if (keymap->modifiermap[i] == ev.xkey.keycode &&
1434 wKeyBindings[WKBD_FOCUSNEXT].modifier
1435 & 1<<(i/keymap->max_keypermod)) {
1436 done = True;
1437 break;
1442 /*dputs("OUT");*/
1443 XFree(keymap);
1445 XUngrabKeyboard(dpy, CurrentTime);
1446 wSetFocusTo(scr, newFocused);
1447 scr->flags.doing_alt_tab = 0;
1448 if (openedSwitchMenu)
1449 OpenSwitchMenu(scr, scr->scr_width/2, scr->scr_height/2, False);
1453 #endif /* WEENDOZE_CYCLE */
1458 static void
1459 handleKeyPress(XEvent *event)
1461 WScreen *scr = wScreenForRootWindow(event->xkey.root);
1462 WWindow *wwin = scr->focused_window;
1463 int i;
1464 int modifiers;
1465 int command=-1, index;
1466 #ifdef KEEP_XKB_LOCK_STATUS
1467 XkbStateRec staterec;
1468 #endif /*KEEP_XKB_LOCK_STATUS*/
1470 /* ignore CapsLock */
1471 modifiers = event->xkey.state & ValidModMask;
1473 for (i=0; i<WKBD_LAST; i++) {
1474 if (wKeyBindings[i].keycode==0)
1475 continue;
1477 if (wKeyBindings[i].keycode==event->xkey.keycode
1478 && (/*wKeyBindings[i].modifier==0
1479 ||*/ wKeyBindings[i].modifier==modifiers)) {
1480 command = i;
1481 break;
1485 if (command < 0) {
1486 #ifdef LITE
1488 #if 0
1490 #endif
1491 #else
1492 if (!wRootMenuPerformShortcut(event)) {
1493 #endif
1494 static int dontLoop = 0;
1496 if (dontLoop > 10) {
1497 wwarning("problem with key event processing code");
1498 return;
1500 dontLoop++;
1501 /* if the focused window is an internal window, try redispatching
1502 * the event to the managed window, as it can be a WINGs window */
1503 if (wwin && wwin->flags.internal_window
1504 && wwin->client_leader!=None) {
1505 /* client_leader contains the WINGs toplevel */
1506 event->xany.window = wwin->client_leader;
1507 WMHandleEvent(event);
1509 dontLoop--;
1511 return;
1514 #define ISMAPPED(w) ((w) && !(w)->flags.miniaturized && ((w)->flags.mapped || (w)->flags.shaded))
1515 #define ISFOCUSED(w) ((w) && (w)->flags.focused)
1517 switch (command) {
1518 #ifndef LITE
1519 case WKBD_ROOTMENU:
1520 OpenRootMenu(scr, event->xkey.x_root, event->xkey.y_root, True);
1521 break;
1522 case WKBD_WINDOWLIST:
1523 OpenSwitchMenu(scr, event->xkey.x_root, event->xkey.y_root, True);
1524 break;
1525 #endif /* !LITE */
1526 case WKBD_WINDOWMENU:
1527 if (ISMAPPED(wwin) && ISFOCUSED(wwin))
1528 OpenWindowMenu(wwin, wwin->frame_x,
1529 wwin->frame_y+wwin->frame->top_width, True);
1530 break;
1531 case WKBD_MINIATURIZE:
1532 if (ISMAPPED(wwin) && ISFOCUSED(wwin)
1533 && !WFLAGP(wwin, no_miniaturizable)) {
1534 CloseWindowMenu(scr);
1536 if (wwin->protocols.MINIATURIZE_WINDOW)
1537 wClientSendProtocol(wwin, _XA_GNUSTEP_WM_MINIATURIZE_WINDOW,
1538 event->xbutton.time);
1539 else {
1540 wIconifyWindow(wwin);
1543 break;
1544 case WKBD_HIDE:
1545 if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1546 WApplication *wapp = wApplicationOf(wwin->main_window);
1547 CloseWindowMenu(scr);
1549 if (wapp && !WFLAGP(wapp->main_window_desc, no_appicon)) {
1550 wHideApplication(wapp);
1553 break;
1554 case WKBD_MAXIMIZE:
1555 if (ISMAPPED(wwin) && ISFOCUSED(wwin) && !WFLAGP(wwin, no_resizable)) {
1556 CloseWindowMenu(scr);
1558 if (wwin->flags.maximized) {
1559 wUnmaximizeWindow(wwin);
1560 } else {
1561 wMaximizeWindow(wwin, MAX_VERTICAL|MAX_HORIZONTAL);
1564 break;
1565 case WKBD_VMAXIMIZE:
1566 if (ISMAPPED(wwin) && ISFOCUSED(wwin) && !WFLAGP(wwin, no_resizable)) {
1567 CloseWindowMenu(scr);
1569 if (wwin->flags.maximized) {
1570 wUnmaximizeWindow(wwin);
1571 } else {
1572 wMaximizeWindow(wwin, MAX_VERTICAL);
1575 break;
1576 case WKBD_RAISE:
1577 if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1578 CloseWindowMenu(scr);
1580 wRaiseFrame(wwin->frame->core);
1582 break;
1583 case WKBD_LOWER:
1584 if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1585 CloseWindowMenu(scr);
1587 wLowerFrame(wwin->frame->core);
1589 break;
1590 case WKBD_RAISELOWER:
1591 /* raise or lower the window under the pointer, not the
1592 * focused one
1594 wwin = windowUnderPointer(scr);
1595 if (wwin)
1596 wRaiseLowerFrame(wwin->frame->core);
1597 break;
1598 case WKBD_SHADE:
1599 if (ISMAPPED(wwin) && ISFOCUSED(wwin) && !WFLAGP(wwin, no_shadeable)) {
1600 if (wwin->flags.shaded)
1601 wUnshadeWindow(wwin);
1602 else
1603 wShadeWindow(wwin);
1605 break;
1606 case WKBD_MOVERESIZE:
1607 if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1608 CloseWindowMenu(scr);
1610 wKeyboardMoveResizeWindow(wwin);
1612 break;
1613 case WKBD_CLOSE:
1614 if (ISMAPPED(wwin) && ISFOCUSED(wwin) && !WFLAGP(wwin, no_closable)) {
1615 CloseWindowMenu(scr);
1616 if (wwin->protocols.DELETE_WINDOW)
1617 wClientSendProtocol(wwin, _XA_WM_DELETE_WINDOW,
1618 event->xkey.time);
1620 break;
1621 case WKBD_SELECT:
1622 if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1623 wSelectWindow(wwin, !wwin->flags.selected);
1625 break;
1626 case WKBD_FOCUSNEXT:
1627 #ifdef WEENDOZE_CYCLE
1628 if (wPreferences.windoze_cycling) {
1629 doWindozeCycle(wwin, event, True);
1630 } else
1631 #endif /* WEENDOZE_CYCLE */
1633 wwin = NextFocusWindow(scr);
1634 if (wwin != NULL) {
1635 wSetFocusTo(scr, wwin);
1636 if (wPreferences.circ_raise)
1637 wRaiseFrame(wwin->frame->core);
1640 break;
1642 case WKBD_FOCUSPREV:
1643 #ifdef WEENDOZE_CYCLE
1644 if (wPreferences.windoze_cycling) {
1645 doWindozeCycle(wwin, event, False);
1646 } else
1647 #endif /* WEENDOZE_CYCLE */
1649 wwin = PrevFocusWindow(scr);
1650 if (wwin != NULL) {
1651 wSetFocusTo(scr, wwin);
1652 if (wPreferences.circ_raise)
1653 wRaiseFrame(wwin->frame->core);
1656 break;
1658 #if (defined(__STDC__) && !defined(UNIXCPP)) || defined(ANSICPP)
1659 #define GOTOWORKS(wk) case WKBD_WORKSPACE##wk:\
1660 i = (scr->current_workspace/10)*10 + wk - 1;\
1661 if (wPreferences.ws_advance || i<scr->workspace_count)\
1662 wWorkspaceChange(scr, i);\
1663 break
1664 #else
1665 #define GOTOWORKS(wk) case WKBD_WORKSPACE/**/wk:\
1666 i = (scr->current_workspace/10)*10 + wk - 1;\
1667 if (wPreferences.ws_advance || i<scr->workspace_count)\
1668 wWorkspaceChange(scr, i);\
1669 break
1670 #endif
1671 GOTOWORKS(1);
1672 GOTOWORKS(2);
1673 GOTOWORKS(3);
1674 GOTOWORKS(4);
1675 GOTOWORKS(5);
1676 GOTOWORKS(6);
1677 GOTOWORKS(7);
1678 GOTOWORKS(8);
1679 GOTOWORKS(9);
1680 GOTOWORKS(10);
1681 #undef GOTOWORKS
1682 case WKBD_NEXTWORKSPACE:
1683 wWorkspaceRelativeChange(scr, 1);
1684 break;
1685 case WKBD_PREVWORKSPACE:
1686 wWorkspaceRelativeChange(scr, -1);
1687 break;
1688 case WKBD_WINDOW1:
1689 case WKBD_WINDOW2:
1690 case WKBD_WINDOW3:
1691 case WKBD_WINDOW4:
1692 #ifdef EXTEND_WINDOWSHORTCUT
1693 case WKBD_WINDOW5:
1694 case WKBD_WINDOW6:
1695 case WKBD_WINDOW7:
1696 case WKBD_WINDOW8:
1697 case WKBD_WINDOW9:
1698 case WKBD_WINDOW10:
1699 #endif
1701 #define INITBAG(bag) if (bag) WMEmptyBag(bag); else bag = WMCreateBag(4)
1703 index = command-WKBD_WINDOW1;
1705 if (scr->shortcutSelectedWindows[index]) {
1706 WMBag *list = scr->shortcutSelectedWindows[index];
1707 int cw;
1708 int i;
1710 wUnselectWindows(scr);
1711 if (scr->shortcutWindow[index])
1712 wMakeWindowVisible(scr->shortcutWindow[index]);
1713 cw = scr->current_workspace;
1714 for (i = 0; i < WMGetBagItemCount(list); i++) {
1715 WWindow *wwin = WMGetFromBag(list, i);
1716 wWindowChangeWorkspace(wwin, cw);
1717 wMakeWindowVisible(wwin);
1718 wSelectWindow(wwin, True);
1720 } else if (scr->shortcutWindow[index]){
1722 wMakeWindowVisible(scr->shortcutWindow[index]);
1724 } else if (wwin && ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1726 scr->shortcutWindow[index] = wwin;
1727 if (wwin->flags.selected && scr->selected_windows) {
1728 WMBag *bag;
1729 int i;
1731 bag = scr->selected_windows;
1732 INITBAG(scr->shortcutSelectedWindows[index]);
1734 for (i = 0; i < WMGetBagItemCount(bag); i++) {
1735 WWindow *tmp = WMGetFromBag(bag, i);
1737 WMPutInBag(scr->shortcutSelectedWindows[index], tmp);
1740 wSelectWindow(wwin, !wwin->flags.selected);
1741 XFlush(dpy);
1742 wusleep(3000);
1743 wSelectWindow(wwin, !wwin->flags.selected);
1744 XFlush(dpy);
1746 } else if (WMGetBagItemCount(scr->selected_windows)) {
1748 if (wwin->flags.selected && scr->selected_windows) {
1749 WMBag *bag;
1750 int i;
1752 bag = scr->selected_windows;
1753 INITBAG(scr->shortcutSelectedWindows[index]);
1755 for (i = 0; i < WMGetBagItemCount(bag); i++) {
1756 WWindow *tmp = WMGetFromBag(bag, i);
1758 WMPutInBag(scr->shortcutSelectedWindows[index], tmp);
1762 #undef INITBAG
1764 break;
1765 case WKBD_NEXTWSLAYER:
1766 case WKBD_PREVWSLAYER:
1768 int row, column;
1770 row = scr->current_workspace/10;
1771 column = scr->current_workspace%10;
1773 if (command==WKBD_NEXTWSLAYER) {
1774 if ((row+1)*10 < scr->workspace_count)
1775 wWorkspaceChange(scr, column+(row+1)*10);
1776 } else {
1777 if (row > 0)
1778 wWorkspaceChange(scr, column+(row-1)*10);
1781 break;
1782 case WKBD_CLIPLOWER:
1783 if (!wPreferences.flags.noclip)
1784 wDockLower(scr->workspaces[scr->current_workspace]->clip);
1785 break;
1786 case WKBD_CLIPRAISE:
1787 if (!wPreferences.flags.noclip)
1788 wDockRaise(scr->workspaces[scr->current_workspace]->clip);
1789 break;
1790 case WKBD_CLIPRAISELOWER:
1791 if (!wPreferences.flags.noclip)
1792 wDockRaiseLower(scr->workspaces[scr->current_workspace]->clip);
1793 break;
1794 #ifdef KEEP_XKB_LOCK_STATUS
1795 case WKBD_TOGGLE:
1796 if(wPreferences.modelock) {
1797 /*toggle*/
1798 wwin = scr->focused_window;
1800 if (wwin && wwin->flags.mapped
1801 && wwin->frame->workspace == wwin->screen_ptr->current_workspace
1802 && !wwin->flags.miniaturized && !wwin->flags.hidden) {
1803 XkbGetState(dpy,XkbUseCoreKbd,&staterec);
1805 wwin->frame->languagemode = wwin->frame->last_languagemode;
1806 wwin->frame->last_languagemode = staterec.group;
1807 XkbLockGroup(dpy,XkbUseCoreKbd, wwin->frame->languagemode);
1811 break;
1812 #endif /* KEEP_XKB_LOCK_STATUS */
1818 static void
1819 handleMotionNotify(XEvent *event)
1821 WMenu *menu;
1822 WScreen *scr = wScreenForRootWindow(event->xmotion.root);
1824 if (wPreferences.scrollable_menus) {
1825 if (scr->flags.jump_back_pending ||
1826 event->xmotion.x_root <= 1 ||
1827 event->xmotion.x_root >= (scr->scr_width - 2) ||
1828 event->xmotion.y_root <= 1 ||
1829 event->xmotion.y_root >= (scr->scr_height - 2)) {
1831 #ifdef DEBUG
1832 dputs("pointer at screen edge");
1833 #endif
1835 menu = wMenuUnderPointer(scr);
1836 if (menu!=NULL)
1837 wMenuScroll(menu, event);
1840 #if 0
1841 if (event->xmotion.subwindow == None)
1842 return;
1844 if (scr->scrolledFMaximize != None) {
1845 WWindow *twin;
1847 twin = wWindowFor(scr->scrolledFMaximize);
1848 if (twin && twin->frame_y ==) {
1852 scr->scrolledFMaximize = NULL;
1854 } else {
1856 /* scroll full maximized window */
1857 if (event->xmotion.y_root < 1
1858 || event->xmotion.y_root > scr->scr_height - 1) {
1860 wwin = wWindowFor(event->xmotion.subwindow);
1862 if (wwin && (wwin->flags.maximized & MAX_VERTICAL)
1863 && WFLAGP(wwin, full_maximize)
1864 && event->xmotion.x_root >= wwin->frame_x
1865 && event->xmotion.x_root <= wwin->frame_x + wwin->frame->core->width) {
1867 if (!WFLAGP(wwin, no_titlebar)
1868 && wwin->frame_y <= - wwin->frame->top_width) {
1870 wWindowMove(wwin, wwin->frame_x, 0);
1871 wwin->flags.dragged_while_fmaximized = 0;
1873 } else if (!WFLAGP(wwin, no_resizebar)
1874 && wwin->frame_y + wwin->frame->core->height >=
1875 scr->scr_height + wwin->frame->bottom_width) {
1877 int y = scr->scr_height + wwin->frame->bottom_width;
1879 y = scr->scr_height - wwin->frame_y - wwin->frame->core->height;
1881 wWindowMove(wwin, wwin->frame_x, y);
1882 wwin->flags.dragged_while_fmaximized = 0;
1886 #endif
1890 static void
1891 handleVisibilityNotify(XEvent *event)
1893 WWindow *wwin;
1895 wwin = wWindowFor(event->xvisibility.window);
1896 if (!wwin)
1897 return;
1898 wwin->flags.obscured =
1899 (event->xvisibility.state == VisibilityFullyObscured);