This update includes the 0.20.3pre3 code
[wmaker-crm.git] / src / event.c
blob4363c8ea0a36a6a4048871a06b4d947a580e5a43
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 XDE_DND
38 #include <X11/Xatom.h>
39 #include <gdk/gdk.h>
40 #endif
42 #ifdef KEEP_XKB_LOCK_STATUS
43 #include <X11/XKBlib.h>
44 #endif /* KEEP_XKB_LOCK_STATUS */
46 #include "WindowMaker.h"
47 #include "window.h"
48 #include "actions.h"
49 #include "client.h"
50 #include "funcs.h"
51 #include "keybind.h"
52 #include "application.h"
53 #include "stacking.h"
54 #include "defaults.h"
55 #include "workspace.h"
56 #include "dock.h"
57 #include "framewin.h"
58 #include "properties.h"
59 #include "balloon.h"
62 /******** Global Variables **********/
63 extern XContext wWinContext;
65 extern Cursor wCursor[WCUR_LAST];
67 extern WShortKey wKeyBindings[WKBD_LAST];
68 extern int wScreenCount;
69 extern Time LastTimestamp;
70 extern Time LastFocusChange;
72 extern WPreferences wPreferences;
74 #define MOD_MASK wPreferences.modifier_mask
76 extern Atom _XA_WM_COLORMAP_NOTIFY;
78 extern Atom _XA_WM_CHANGE_STATE;
79 extern Atom _XA_WM_DELETE_WINDOW;
80 extern Atom _XA_GNUSTEP_WM_MINIATURIZE_WINDOW;
81 extern Atom _XA_WINDOWMAKER_WM_FUNCTION;
83 #ifdef OFFIX_DND
84 extern Atom _XA_DND_PROTOCOL;
85 #endif
86 #ifdef XDE_DND
87 extern Atom _XA_XDE_REQUEST;
88 extern Atom _XA_XDE_ENTER;
89 extern Atom _XA_XDE_LEAVE;
90 extern Atom _XA_XDE_DATA_AVAILABLE;
91 extern Atom _XDE_FILETYPE;
92 extern Atom _XDE_URLTYPE;
93 #endif
96 #ifdef SHAPE
97 extern Bool wShapeSupported;
98 extern int wShapeEventBase;
99 #endif
101 /* special flags */
102 extern char WProgramState;
103 extern char WDelayedActionSet;
106 /************ Local stuff ***********/
109 static void saveTimestamp(XEvent *event);
110 static void handleColormapNotify();
111 static void handleMapNotify(), handleUnmapNotify();
112 static void handleButtonPress(), handleExpose();
113 static void handleDestroyNotify();
114 static void handleConfigureRequest();
115 static void handleMapRequest();
116 static void handlePropertyNotify();
117 static void handleEnterNotify();
118 static void handleLeaveNotify();
119 static void handleExtensions();
120 static void handleClientMessage();
121 static void handleKeyPress();
122 static void handleFocusIn();
123 static void handleMotionNotify();
125 #ifdef SHAPE
126 static void handleShapeNotify();
127 #endif
129 /* called from the signal handler */
130 void NotifyDeadProcess(pid_t pid, unsigned char status);
132 /* real dead process handler */
133 static void handleDeadProcess(void *foo);
136 typedef struct DeadProcesses {
137 pid_t pid;
138 unsigned char exit_status;
139 } DeadProcesses;
141 /* stack of dead processes */
142 static DeadProcesses deadProcesses[MAX_DEAD_PROCESSES];
143 static int deadProcessPtr=0;
146 typedef struct DeathHandler {
147 WDeathHandler *callback;
148 pid_t pid;
149 struct DeathHandler *next;
150 void *client_data;
151 } DeathHandler;
153 static DeathHandler *deathHandler=NULL;
157 WMagicNumber
158 wAddDeathHandler(pid_t pid, WDeathHandler *callback, void *cdata)
160 DeathHandler *handler;
162 handler = malloc(sizeof(DeathHandler));
163 if (!handler)
164 return 0;
166 handler->pid = pid;
167 handler->callback = callback;
168 handler->client_data = cdata;
170 handler->next = deathHandler;
172 deathHandler = handler;
174 return handler;
179 void
180 wDeleteDeathHandler(WMagicNumber id)
182 DeathHandler *tmp, *handler=(DeathHandler*)id;
184 if (!handler || !deathHandler)
185 return;
187 tmp = deathHandler;
188 if (tmp==handler) {
189 deathHandler = handler->next;
190 free(handler);
191 } else {
192 while (tmp->next) {
193 if (tmp->next==handler) {
194 tmp->next=handler->next;
195 free(handler);
196 break;
198 tmp = tmp->next;
204 void
205 DispatchEvent(XEvent *event)
207 int i;
209 if (deathHandler)
210 handleDeadProcess(NULL);
212 if (WProgramState==WSTATE_NEED_EXIT) {
213 WProgramState = WSTATE_EXITING;
216 * WMHandleEvent() can't be called from anything
217 * executed inside here, or we can get in a infinite
218 * recursive loop.
220 for (i=0; i<wScreenCount; i++) {
221 WScreen *scr;
222 scr = wScreenWithNumber(i);
223 if (scr) {
224 wScreenSaveState(scr);
227 RestoreDesktop(NULL);
228 ExecExitScript();
229 /* received SIGTERM */
230 Exit(0);
231 } else if (WProgramState == WSTATE_NEED_RESTART) {
232 WProgramState = WSTATE_RESTARTING;
234 for (i=0; i<wScreenCount; i++) {
235 WScreen *scr;
236 scr = wScreenWithNumber(i);
237 if (scr) {
238 wScreenSaveState(scr);
241 RestoreDesktop(NULL);
242 /* received SIGHUP */
243 Restart(NULL);
246 /* for the case that all that is wanted to be dispatched is
247 * the stuff above */
248 if (!event)
249 return;
251 saveTimestamp(event);
252 switch (event->type) {
253 case MapRequest:
254 handleMapRequest(event);
255 break;
257 case KeyPress:
258 handleKeyPress(event);
259 break;
261 case MotionNotify:
262 handleMotionNotify(event);
263 break;
265 case ConfigureRequest:
266 handleConfigureRequest(event);
267 break;
269 case DestroyNotify:
270 handleDestroyNotify(event->xdestroywindow.window);
271 break;
273 case MapNotify:
274 handleMapNotify(event->xmap.window);
275 break;
277 case UnmapNotify:
278 handleUnmapNotify(event);
279 break;
281 case ButtonPress:
282 handleButtonPress(event);
283 break;
285 case Expose:
286 handleExpose(event);
287 break;
289 case PropertyNotify:
290 handlePropertyNotify(event);
291 break;
293 case EnterNotify:
294 handleEnterNotify(event);
295 break;
297 case LeaveNotify:
298 handleLeaveNotify(event);
299 break;
301 case ClientMessage:
302 handleClientMessage(event);
303 break;
305 case ColormapNotify:
306 handleColormapNotify(event);
307 break;
309 case MappingNotify:
310 if (event->xmapping.request == MappingKeyboard
311 || event->xmapping.request == MappingModifier)
312 XRefreshKeyboardMapping(&event->xmapping);
313 break;
315 case FocusIn:
316 handleFocusIn(event);
317 break;
319 default:
320 handleExtensions(event);
326 *----------------------------------------------------------------------
327 * EventLoop-
328 * Processes X and internal events indefinitely.
330 * Returns:
331 * Never returns
333 * Side effects:
334 * The LastTimestamp global variable is updated.
335 *----------------------------------------------------------------------
337 void
338 EventLoop()
340 XEvent event;
342 for(;;) {
343 WMNextEvent(dpy, &event);
344 WMHandleEvent(&event);
350 Bool
351 IsDoubleClick(WScreen *scr, XEvent *event)
353 if ((scr->last_click_time>0) &&
354 (event->xbutton.time-scr->last_click_time<=wPreferences.dblclick_time)
355 && (event->xbutton.button == scr->last_click_button)
356 && (event->xbutton.subwindow == scr->last_click_window)) {
358 scr->flags.next_click_is_not_double = 1;
359 scr->last_click_time = 0;
360 scr->last_click_window = None;
362 return True;
364 return False;
368 void
369 NotifyDeadProcess(pid_t pid, unsigned char status)
371 if (deadProcessPtr>=MAX_DEAD_PROCESSES-1) {
372 wwarning(_("stack overflow: too many dead processes"));
373 return;
375 /* stack the process to be handled later,
376 * as this is called from the signal handler */
377 deadProcesses[deadProcessPtr].pid = pid;
378 deadProcesses[deadProcessPtr].exit_status = status;
379 deadProcessPtr++;
383 static void
384 handleDeadProcess(void *foo)
386 DeathHandler *tmp;
387 int i;
389 for (i=0; i<deadProcessPtr; i++) {
390 wWindowDeleteSavedStatesForPID(deadProcesses[i].pid);
393 if (!deathHandler) {
394 deadProcessPtr=0;
395 return;
398 /* get the pids on the queue and call handlers */
399 while (deadProcessPtr>0) {
400 deadProcessPtr--;
402 tmp = deathHandler;
403 while (tmp) {
404 DeathHandler *t;
406 t = tmp->next;
408 if (tmp->pid == deadProcesses[deadProcessPtr].pid) {
409 (*tmp->callback)(tmp->pid,
410 deadProcesses[deadProcessPtr].exit_status,
411 tmp->client_data);
412 wDeleteDeathHandler(tmp);
414 tmp = t;
420 static void
421 saveTimestamp(XEvent *event)
423 LastTimestamp = CurrentTime;
425 switch (event->type) {
426 case ButtonRelease:
427 case ButtonPress:
428 LastTimestamp = event->xbutton.time;
429 break;
430 case KeyPress:
431 case KeyRelease:
432 LastTimestamp = event->xkey.time;
433 break;
434 case MotionNotify:
435 LastTimestamp = event->xmotion.time;
436 break;
437 case PropertyNotify:
438 LastTimestamp = event->xproperty.time;
439 break;
440 case EnterNotify:
441 case LeaveNotify:
442 LastTimestamp = event->xcrossing.time;
443 break;
444 case SelectionClear:
445 LastTimestamp = event->xselectionclear.time;
446 break;
447 case SelectionRequest:
448 LastTimestamp = event->xselectionrequest.time;
449 break;
450 case SelectionNotify:
451 LastTimestamp = event->xselection.time;
452 break;
457 static void
458 handleExtensions(XEvent *event)
460 #ifdef SHAPE
461 if (wShapeSupported && event->type == (wShapeEventBase+ShapeNotify)) {
462 handleShapeNotify(event);
464 #endif
467 static void
468 handleMapRequest(XEvent *ev)
470 WWindow *wwin;
471 WScreen *scr = NULL;
472 Window window = ev->xmaprequest.window;
474 #ifdef DEBUG
475 printf("got map request for %x\n", (unsigned)window);
476 #endif
478 if ((wwin=wWindowFor(window))) {
479 /* deiconify window */
480 if (wwin->flags.shaded)
481 wUnshadeWindow(wwin);
482 if (wwin->flags.miniaturized) {
483 wDeiconifyWindow(wwin);
484 } else if (wwin->flags.hidden) {
485 WApplication *wapp = wApplicationOf(wwin->main_window);
486 /* go to the last workspace that the user worked on the app */
487 #ifndef REDUCE_APPICONS
488 /* This severely breaks REDUCE_APPICONS. last_workspace is a neat
489 * concept but it needs to be reworked to handle REDUCE_APPICONS -cls
491 if (wapp) {
492 wWorkspaceChange(wwin->screen_ptr, wapp->last_workspace);
494 #endif
495 wUnhideApplication(wapp, False, False);
497 return;
500 scr = wScreenForRootWindow(ev->xmaprequest.parent);
502 wwin = wManageWindow(scr, window);
505 * This is to let the Dock know that the application it launched
506 * has already been mapped (eg: it has finished launching).
507 * It is not necessary for normally docked apps, but is needed for
508 * apps that were forcedly docked (like with dockit).
510 if (scr->last_dock) {
511 if (wwin && wwin->main_window!=None && wwin->main_window!=window)
512 wDockTrackWindowLaunch(scr->last_dock, wwin->main_window);
513 else
514 wDockTrackWindowLaunch(scr->last_dock, window);
517 if (wwin) {
518 int state;
520 if (wwin->wm_hints && (wwin->wm_hints->flags & StateHint))
521 state = wwin->wm_hints->initial_state;
522 else
523 state = NormalState;
525 if (state==IconicState)
526 wwin->flags.miniaturized = 1;
528 if (state==WithdrawnState) {
529 wwin->flags.mapped = 0;
530 wClientSetState(wwin, WithdrawnState, None);
531 wUnmanageWindow(wwin, True);
532 } else {
533 wClientSetState(wwin, NormalState, None);
534 if (wwin->flags.shaded) {
535 wwin->flags.shaded = 0;
536 wwin->flags.skip_next_animation = 1;
537 wwin->flags.ignore_next_unmap = 1; /* ??? */
538 wShadeWindow(wwin);
540 if (wwin->flags.miniaturized) {
541 wwin->flags.miniaturized = 0;
542 wwin->flags.hidden = 0;
543 wwin->flags.skip_next_animation = 1;
544 wwin->flags.ignore_next_unmap = 1;
545 wIconifyWindow(wwin);
546 } else if (wwin->flags.hidden) {
547 WApplication *wapp = wApplicationOf(wwin->main_window);
548 wwin->flags.hidden = 0;
549 wwin->flags.skip_next_animation = 1;
550 if (wapp) {
551 wHideApplication(wapp);
553 wwin->flags.ignore_next_unmap = 1;
560 static void
561 handleDestroyNotify(Window window)
563 WWindow *wwin;
564 WApplication *app;
565 #ifdef DEBUG
566 puts("got destroy notify");
567 #endif
569 wwin = wWindowFor(window);
570 if (wwin) {
571 wUnmanageWindow(wwin, False);
574 app = wApplicationOf(window);
575 if (app) {
576 if (window == app->main_window) {
577 app->refcount = 0;
578 wwin = app->main_window_desc->screen_ptr->focused_window;
579 while (wwin) {
580 if (wwin->main_window == window) {
581 wwin->main_window = None;
583 wwin = wwin->prev;
586 wApplicationDestroy(app);
592 static void
593 handleExpose(XEvent *event)
595 WObjDescriptor *desc;
597 #ifdef DEBUG
598 puts("got expose");
599 #endif
600 if (event->xexpose.count!=0) {
601 return;
604 if (XFindContext(dpy, event->xexpose.window, wWinContext,
605 (XPointer *)&desc)==XCNOENT) {
606 return;
609 if (desc->handle_expose) {
610 (*desc->handle_expose)(desc, event);
615 /* bindable */
616 static void
617 handleButtonPress(XEvent *event)
619 WObjDescriptor *desc;
620 WScreen *scr;
622 #ifdef DEBUG
623 puts("got button press");
624 #endif
626 scr = wScreenForRootWindow(event->xbutton.root);
628 #ifdef BALLOON_TEXT
629 wBalloonHide(scr);
630 #endif
632 if (event->xbutton.window==scr->root_win) {
633 if (event->xbutton.button==wPreferences.menu_button) {
634 OpenRootMenu(scr, event->xbutton.x_root,
635 event->xbutton.y_root, False);
636 /* ugly hack */
637 if (scr->root_menu) {
638 if (scr->root_menu->brother->flags.mapped)
639 event->xbutton.window = scr->root_menu->brother->frame->core->window;
640 else
641 event->xbutton.window = scr->root_menu->frame->core->window;
643 } else if (event->xbutton.button==wPreferences.windowl_button) {
645 OpenSwitchMenu(scr, event->xbutton.x_root,
646 event->xbutton.y_root, False);
647 if (scr->switch_menu) {
648 if (scr->switch_menu->brother->flags.mapped)
649 event->xbutton.window = scr->switch_menu->brother->frame->core->window;
650 else
651 event->xbutton.window = scr->switch_menu->frame->core->window;
653 } else if (event->xbutton.button==wPreferences.select_button) {
655 wUnselectWindows(scr);
656 wSelectWindows(scr, event);
658 #ifdef MOUSE_WS_SWITCH
659 else if (event->xbutton.button==Button4) {
661 if (scr->current_workspace > 0)
662 wWorkspaceChange(scr, scr->current_workspace-1);
664 } else if (event->xbutton.button==Button5) {
666 if (scr->current_workspace < scr->workspace_count-1)
667 wWorkspaceChange(scr, scr->current_workspace+1);
670 #endif /* MOUSE_WS_SWITCH */
673 if (XFindContext(dpy, event->xbutton.subwindow, wWinContext,
674 (XPointer *)&desc)==XCNOENT) {
675 if (XFindContext(dpy, event->xbutton.window, wWinContext,
676 (XPointer *)&desc)==XCNOENT) {
677 return;
681 if (desc->parent_type == WCLASS_WINDOW) {
682 XSync(dpy, 0);
684 if (event->xbutton.state & MOD_MASK) {
685 XAllowEvents(dpy, AsyncPointer, CurrentTime);
688 if (wPreferences.focus_mode == WKF_CLICK) {
689 if (wPreferences.ignore_focus_click) {
690 XAllowEvents(dpy, AsyncPointer, CurrentTime);
692 XAllowEvents(dpy, ReplayPointer, CurrentTime);
694 XSync(dpy, 0);
695 } else if (desc->parent_type == WCLASS_APPICON
696 || desc->parent_type == WCLASS_MINIWINDOW
697 || desc->parent_type == WCLASS_DOCK_ICON) {
698 if (event->xbutton.state & MOD_MASK) {
699 XSync(dpy, 0);
700 XAllowEvents(dpy, AsyncPointer, CurrentTime);
701 XSync(dpy, 0);
705 if (desc->handle_mousedown!=NULL) {
706 (*desc->handle_mousedown)(desc, event);
709 /* save double-click information */
710 if (scr->flags.next_click_is_not_double) {
711 scr->flags.next_click_is_not_double = 0;
712 } else {
713 scr->last_click_time = event->xbutton.time;
714 scr->last_click_button = event->xbutton.button;
715 scr->last_click_window = event->xbutton.subwindow;
720 static void
721 handleMapNotify(Window window)
723 WWindow *wwin;
725 #ifdef DEBUG
726 puts("got map");
727 #endif
728 wwin= wWindowFor(window);
729 if (wwin && wwin->client_win==window) {
730 if (wwin->flags.ignore_next_unmap) {
731 wwin->flags.ignore_next_unmap=0;
732 return;
734 if (wwin->flags.miniaturized) {
735 wDeiconifyWindow(wwin);
736 } else {
737 XGrabServer(dpy);
738 XSync(dpy,0);
739 XMapWindow(dpy, wwin->client_win);
740 XMapWindow(dpy, wwin->frame->core->window);
741 wwin->flags.mapped=1;
742 wClientSetState(wwin, NormalState, None);
743 XUngrabServer(dpy);
749 static void
750 handleUnmapNotify(XEvent *event)
752 WWindow *wwin;
753 XEvent ev;
755 #ifdef DEBUG
756 puts("got unmap");
757 #endif
758 wwin = wWindowFor(event->xunmap.window);
759 if (!wwin || wwin->client_win!=event->xunmap.window)
760 return;
762 if (!wwin->flags.mapped
763 && wwin->frame->workspace==wwin->screen_ptr->current_workspace
764 && !wwin->flags.miniaturized && !wwin->flags.hidden)
765 return;
767 if (wwin->flags.ignore_next_unmap) {
768 return;
770 XGrabServer(dpy);
771 XUnmapWindow(dpy, wwin->frame->core->window);
772 wwin->flags.mapped = 0;
773 XSync(dpy, 0);
774 /* check if the window was destroyed */
775 if (XCheckTypedWindowEvent(dpy, wwin->client_win, DestroyNotify,&ev)) {
776 DispatchEvent(&ev);
777 } else {
778 Bool reparented = False;
780 if (XCheckTypedWindowEvent(dpy, wwin->client_win, ReparentNotify, &ev))
781 reparented = True;
783 /* withdraw window */
784 wwin->flags.mapped = 0;
785 if (!reparented)
786 wClientSetState(wwin, WithdrawnState, None);
788 /* if the window was reparented, do not reparent it back to the
789 * root window */
790 wUnmanageWindow(wwin, !reparented);
792 XUngrabServer(dpy);
796 static void
797 handleConfigureRequest(XEvent *event)
799 WWindow *wwin;
801 #ifdef DEBUG
802 puts("got configure request");
803 #endif
804 if (!(wwin=wWindowFor(event->xconfigurerequest.window))) {
806 * Configure request for unmapped window
808 wClientConfigure(NULL, &(event->xconfigurerequest));
809 } else {
810 wClientConfigure(wwin, &(event->xconfigurerequest));
815 static void
816 handlePropertyNotify(XEvent *event)
818 WWindow *wwin;
819 WApplication *wapp;
820 Window jr;
821 int ji;
822 unsigned int ju;
824 #ifdef DEBUG
825 puts("got property notify");
826 #endif
827 if ((wwin=wWindowFor(event->xproperty.window))) {
828 if (!XGetGeometry(dpy, wwin->client_win, &jr, &ji, &ji,
829 &ju, &ju, &ju, &ju)) {
830 return;
832 wClientCheckProperty(wwin, &event->xproperty);
834 wapp = wApplicationOf(event->xproperty.window);
835 if (wapp) {
836 wClientCheckProperty(wapp->main_window_desc, &event->xproperty);
841 static void
842 handleClientMessage(XEvent *event)
844 WWindow *wwin;
845 WObjDescriptor *desc;
847 #ifdef DEBUG
848 puts("got client message");
849 #endif
850 /* handle transition from Normal to Iconic state */
851 if (event->xclient.message_type == _XA_WM_CHANGE_STATE
852 && event->xclient.format == 32
853 && event->xclient.data.l[0] == IconicState) {
855 wwin = wWindowFor(event->xclient.window);
856 if (!wwin) return;
857 if (!wwin->flags.miniaturized)
858 wIconifyWindow(wwin);
859 } else if (event->xclient.message_type == _XA_WM_COLORMAP_NOTIFY
860 && event->xclient.format == 32) {
861 WScreen *scr = wScreenForRootWindow(event->xclient.window);
863 if (!scr)
864 return;
866 if (event->xclient.data.l[1] == 1) { /* starting */
867 wColormapAllowClientInstallation(scr, True);
868 } else { /* stopping */
869 wColormapAllowClientInstallation(scr, False);
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 XDE_DND
903 } else if (event->xclient.message_type==_XA_XDE_DATA_AVAILABLE) {
904 GdkEvent gdkev;
905 WScreen *scr = wScreenForWindow(event->xclient.window);
906 Atom tmpatom;
907 int datalenght;
908 long tmplong;
909 char * tmpstr, * runstr, * freestr, * tofreestr;
910 printf("x\n");
911 gdkev.dropdataavailable.u.allflags = event->xclient.data.l[1];
912 gdkev.dropdataavailable.timestamp = event->xclient.data.l[4];
914 if(gdkev.dropdataavailable.u.flags.isdrop){
915 gdkev.dropdataavailable.type = GDK_DROP_DATA_AVAIL;
916 gdkev.dropdataavailable.requestor = event->xclient.data.l[0];
917 XGetWindowProperty(dpy,gdkev.dropdataavailable.requestor,
918 event->xclient.data.l[2],
919 0, LONG_MAX -1,
920 0, XA_PRIMARY, &tmpatom,
921 &datalenght,
922 &gdkev.dropdataavailable.data_numbytes,
923 &tmplong,
924 &tmpstr);
925 datalenght=gdkev.dropdataavailable.data_numbytes-1;
926 tofreestr=tmpstr;
927 runstr=NULL;
928 for(;datalenght>0;datalenght-=(strlen(tmpstr)+1),tmpstr=&tmpstr[strlen(tmpstr)+1]){
929 freestr=runstr;runstr=wstrappend(runstr,tmpstr);free(freestr);
930 freestr=runstr;runstr=wstrappend(runstr," ");free(freestr);
932 free(tofreestr);
933 scr->xdestring=runstr;
934 /* no need to redirect ? */
935 wDockReceiveDNDDrop(scr,event);
936 free(runstr);
937 scr->xdestring=NULL;
940 } else if (event->xclient.message_type==_XA_XDE_LEAVE) {
941 printf("leave\n");
942 } else if (event->xclient.message_type==_XA_XDE_ENTER) {
943 GdkEvent gdkev;
944 XEvent replyev;
946 gdkev.dropenter.u.allflags=event->xclient.data.l[1];
947 printf("from win %x\n",event->xclient.data.l[0]);
948 printf("to win %x\n",event->xclient.window);
949 printf("enter %x\n",event->xclient.data.l[1]);
950 printf("v %x ",event->xclient.data.l[2]);
951 printf("%x ",event->xclient.data.l[3]);
952 printf("%x\n",event->xclient.data.l[4]);
954 if(event->xclient.data.l[2]==_XDE_FILETYPE ||
955 event->xclient.data.l[3]==_XDE_FILETYPE ||
956 event->xclient.data.l[4]==_XDE_FILETYPE ||
957 event->xclient.data.l[2]==_XDE_URLTYPE ||
958 event->xclient.data.l[3]==_XDE_URLTYPE ||
959 event->xclient.data.l[4]==_XDE_URLTYPE)
960 if(gdkev.dropenter.u.flags.sendreply){
961 /*reply*/
962 replyev.xclient.type = ClientMessage;
963 replyev.xclient.window = event->xclient.data.l[0];
964 replyev.xclient.format = 32;
965 replyev.xclient.message_type = _XA_XDE_REQUEST;
966 replyev.xclient.data.l[0] = event->xclient.window;
968 gdkev.dragrequest.u.allflags = 0;
969 gdkev.dragrequest.u.flags.protocol_version = 0;
970 gdkev.dragrequest.u.flags.willaccept = 1;
971 gdkev.dragrequest.u.flags.delete_data = 0;
973 replyev.xclient.data.l[1] = gdkev.dragrequest.u.allflags;
974 replyev.xclient.data.l[2] = replyev.xclient.data.l[3] = 0;
975 replyev.xclient.data.l[4] = event->xclient.data.l[2];
976 XSendEvent(dpy, replyev.xclient.window, 0, NoEventMask, &replyev);
977 XSync(dpy, 0);
979 #endif /* XDE_DND */
980 #ifdef OFFIX_DND
981 } else if (event->xclient.message_type==_XA_DND_PROTOCOL) {
982 WScreen *scr = wScreenForWindow(event->xclient.window);
983 if (scr && wDockReceiveDNDDrop(scr,event))
984 goto redirect_message;
985 #endif /* OFFIX_DND */
986 } else {
987 #ifdef OFFIX_DND
988 redirect_message:
989 #endif
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) {
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 XEvent ev;
1042 WScreen *scr = wScreenForRootWindow(event->xcrossing.root);
1045 #ifdef DEBUG
1046 puts("got enter notify");
1047 #endif
1049 if (XCheckTypedWindowEvent(dpy, event->xcrossing.window, LeaveNotify,
1050 &ev)) {
1051 /* already left the window... */
1052 saveTimestamp(&ev);
1053 if (ev.xcrossing.mode==event->xcrossing.mode
1054 && ev.xcrossing.detail==event->xcrossing.detail) {
1055 return;
1059 if (XFindContext(dpy, event->xcrossing.window, wWinContext,
1060 (XPointer *)&desc)!=XCNOENT) {
1061 if(desc->handle_enternotify)
1062 (*desc->handle_enternotify)(desc, event);
1065 /* enter to window */
1066 wwin = wWindowFor(event->xcrossing.window);
1067 if (!wwin) {
1068 if (wPreferences.focus_mode==WKF_POINTER
1069 && event->xcrossing.window==event->xcrossing.root) {
1070 wSetFocusTo(scr, NULL);
1072 if (wPreferences.colormap_mode==WKF_POINTER) {
1073 wColormapInstallForWindow(scr, NULL);
1075 if (scr->autoRaiseTimer
1076 && event->xcrossing.root==event->xcrossing.window) {
1077 WMDeleteTimerHandler(scr->autoRaiseTimer);
1078 scr->autoRaiseTimer = NULL;
1080 } else {
1081 /* set focus if in focus-follows-mouse mode and the event
1082 * is for the frame window and window doesn't have focus yet */
1083 if ((wPreferences.focus_mode==WKF_POINTER
1084 || wPreferences.focus_mode==WKF_SLOPPY)
1085 && wwin->frame->core->window==event->xcrossing.window
1086 && !wwin->flags.focused) {
1087 wSetFocusTo(scr, wwin);
1089 if (scr->autoRaiseTimer)
1090 WMDeleteTimerHandler(scr->autoRaiseTimer);
1091 scr->autoRaiseTimer = NULL;
1093 if (wPreferences.raise_delay && !wwin->window_flags.no_focusable) {
1094 scr->autoRaiseWindow = wwin->frame->core->window;
1095 scr->autoRaiseTimer
1096 = WMAddTimerHandler(wPreferences.raise_delay,
1097 (WMCallback*)raiseWindow, scr);
1100 /* Install colormap for window, if the colormap installation mode
1101 * is colormap_follows_mouse */
1102 if (wPreferences.colormap_mode==WKF_POINTER) {
1103 if (wwin->client_win==event->xcrossing.window)
1104 wColormapInstallForWindow(scr, wwin);
1105 else
1106 wColormapInstallForWindow(scr, NULL);
1110 /* a little kluge to hide the clip balloon */
1111 if (!wPreferences.flags.noclip && scr->flags.clip_balloon_mapped) {
1112 if (!desc) {
1113 XUnmapWindow(dpy, scr->clip_balloon);
1114 scr->flags.clip_balloon_mapped = 0;
1115 } else {
1116 if (desc->parent_type!=WCLASS_DOCK_ICON
1117 || scr->clip_icon != desc->parent) {
1118 XUnmapWindow(dpy, scr->clip_balloon);
1119 scr->flags.clip_balloon_mapped = 0;
1124 if (event->xcrossing.window == event->xcrossing.root
1125 && event->xcrossing.detail == NotifyNormal
1126 && event->xcrossing.detail != NotifyInferior
1127 && wPreferences.focus_mode != WKF_CLICK) {
1129 wSetFocusTo(scr, scr->focused_window);
1132 #ifdef BALLOON_TEXT
1133 wBalloonEnteredObject(scr, desc);
1134 #endif
1138 static void
1139 handleLeaveNotify(XEvent *event)
1141 WObjDescriptor *desc = NULL;
1143 if (XFindContext(dpy, event->xcrossing.window, wWinContext,
1144 (XPointer *)&desc)!=XCNOENT) {
1145 if(desc->handle_leavenotify)
1146 (*desc->handle_leavenotify)(desc, event);
1148 if (event->xcrossing.window == event->xcrossing.root
1149 && event->xcrossing.mode == NotifyNormal
1150 && event->xcrossing.detail != NotifyInferior
1151 && wPreferences.focus_mode != WKF_CLICK) {
1153 WScreen *scr = wScreenForRootWindow(event->xcrossing.root);
1155 wSetFocusTo(scr, NULL);
1160 #ifdef SHAPE
1161 static void
1162 handleShapeNotify(XEvent *event)
1164 XShapeEvent *shev = (XShapeEvent*)event;
1165 WWindow *wwin;
1166 XEvent ev;
1168 #ifdef DEBUG
1169 puts("got shape notify");
1170 #endif
1172 while (XCheckTypedWindowEvent(dpy, shev->window, event->type, &ev)) {
1173 XShapeEvent *sev = (XShapeEvent*)&ev;
1175 if (sev->kind == ShapeBounding) {
1176 if (sev->shaped == shev->shaped) {
1177 *shev = *sev;
1178 } else {
1179 XPutBackEvent(dpy, &ev);
1180 break;
1185 wwin = wWindowFor(shev->window);
1186 if (!wwin || shev->kind != ShapeBounding)
1187 return;
1189 if (!shev->shaped && wwin->flags.shaped) {
1191 wwin->flags.shaped = 0;
1192 wWindowClearShape(wwin);
1194 } else if (shev->shaped) {
1196 wwin->flags.shaped = 1;
1197 wWindowSetShape(wwin);
1200 #endif /* SHAPE */
1203 static void
1204 handleColormapNotify(XEvent *event)
1206 WWindow *wwin;
1207 WScreen *scr;
1208 Bool reinstall = False;
1210 wwin = wWindowFor(event->xcolormap.window);
1211 if (!wwin)
1212 return;
1214 scr = wwin->screen_ptr;
1216 do {
1217 if (wwin) {
1218 if (event->xcolormap.new) {
1219 XWindowAttributes attr;
1221 XGetWindowAttributes(dpy, wwin->client_win, &attr);
1223 if (wwin == scr->cmap_window && wwin->cmap_window_no == 0)
1224 scr->current_colormap = attr.colormap;
1226 reinstall = True;
1227 } else if (event->xcolormap.state == ColormapUninstalled &&
1228 scr->current_colormap == event->xcolormap.colormap) {
1230 /* some bastard app (like XV) removed our colormap */
1232 * can't enforce or things like xscreensaver wont work
1233 * reinstall = True;
1235 } else if (event->xcolormap.state == ColormapInstalled &&
1236 scr->current_colormap == event->xcolormap.colormap) {
1238 /* someone has put our colormap back */
1239 reinstall = False;
1242 } while (XCheckTypedEvent(dpy, ColormapNotify, event)
1243 && ((wwin = wWindowFor(event->xcolormap.window)) || 1));
1245 if (reinstall && scr->current_colormap!=None) {
1246 if (!scr->flags.colormap_stuff_blocked)
1247 XInstallColormap(dpy, scr->current_colormap);
1253 static void
1254 handleFocusIn(XEvent *event)
1256 WWindow *wwin;
1259 * For applications that like stealing the focus.
1261 while (XCheckTypedEvent(dpy, FocusIn, event));
1262 saveTimestamp(event);
1263 if (event->xfocus.mode == NotifyUngrab
1264 || event->xfocus.mode == NotifyGrab
1265 || event->xfocus.detail > NotifyNonlinearVirtual) {
1266 return;
1269 wwin = wWindowFor(event->xfocus.window);
1270 if (wwin && !wwin->flags.focused) {
1271 if (wwin->flags.mapped)
1272 wSetFocusTo(wwin->screen_ptr, wwin);
1273 else
1274 wSetFocusTo(wwin->screen_ptr, NULL);
1275 } else if (!wwin) {
1276 WScreen *scr = wScreenForWindow(event->xfocus.window);
1277 if (scr)
1278 wSetFocusTo(scr, NULL);
1283 static WWindow*
1284 windowUnderPointer(WScreen *scr)
1286 unsigned int mask;
1287 int foo;
1288 Window bar, win;
1290 if (XQueryPointer(dpy, scr->root_win, &bar, &win, &foo, &foo, &foo, &foo,
1291 &mask))
1292 return wWindowFor(win);
1293 return NULL;
1296 static void
1297 handleKeyPress(XEvent *event)
1299 WScreen *scr = wScreenForRootWindow(event->xkey.root);
1300 WWindow *wwin = scr->focused_window;
1301 int i;
1302 int modifiers;
1303 int command=-1;
1304 #ifdef KEEP_XKB_LOCK_STATUS
1305 XkbStateRec staterec;
1306 #endif /*KEEP_XKB_LOCK_STATUS*/
1308 /* ignore CapsLock */
1309 modifiers = event->xkey.state & ValidModMask;
1311 for (i=0; i<WKBD_LAST; i++) {
1312 if (wKeyBindings[i].keycode==0)
1313 continue;
1315 if (wKeyBindings[i].keycode==event->xkey.keycode
1316 && (/*wKeyBindings[i].modifier==0
1317 ||*/ wKeyBindings[i].modifier==modifiers)) {
1318 command = i;
1319 break;
1323 if (command < 0) {
1324 if (!wRootMenuPerformShortcut(event)) {
1325 static int dontLoop = 0;
1327 if (dontLoop > 10) {
1328 wwarning("problem with key event processing code");
1329 return;
1331 dontLoop++;
1332 /* if the focused window is an internal window, try redispatching
1333 * the event to the managed window, as it can be a WINGs window */
1334 if (wwin && wwin->flags.internal_window
1335 && wwin->client_leader!=None) {
1336 /* client_leader contains the WINGs toplevel */
1337 event->xany.window = wwin->client_leader;
1338 WMHandleEvent(event);
1340 dontLoop--;
1342 return;
1345 #define ISMAPPED(w) ((w) && !(w)->flags.miniaturized && ((w)->flags.mapped || (w)->flags.shaded))
1346 #define ISFOCUSED(w) ((w) && (w)->flags.focused)
1348 switch (command) {
1349 case WKBD_ROOTMENU:
1350 OpenRootMenu(scr, event->xkey.x_root, event->xkey.y_root, True);
1351 break;
1352 case WKBD_WINDOWMENU:
1353 if (ISMAPPED(wwin) && ISFOCUSED(wwin))
1354 OpenWindowMenu(wwin, wwin->frame_x,
1355 wwin->frame_y+wwin->frame->top_width, True);
1356 break;
1357 case WKBD_WINDOWLIST:
1358 OpenSwitchMenu(scr, event->xkey.x_root, event->xkey.y_root, True);
1359 break;
1360 case WKBD_MINIATURIZE:
1361 if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1362 CloseWindowMenu(scr);
1364 if (wwin->protocols.MINIATURIZE_WINDOW)
1365 wClientSendProtocol(wwin, _XA_GNUSTEP_WM_MINIATURIZE_WINDOW,
1366 event->xbutton.time);
1367 else {
1368 if (!wwin->window_flags.no_miniaturizable)
1369 wIconifyWindow(wwin);
1372 break;
1373 case WKBD_HIDE:
1374 if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1375 WApplication *wapp = wApplicationOf(wwin->main_window);
1376 CloseWindowMenu(scr);
1378 if (wapp && !wapp->main_window_desc->window_flags.no_appicon) {
1379 wHideApplication(wapp);
1382 break;
1383 case WKBD_MAXIMIZE:
1384 if (ISMAPPED(wwin) && ISFOCUSED(wwin)
1385 && !wwin->window_flags.no_resizable) {
1386 CloseWindowMenu(scr);
1388 if (wwin->flags.maximized) {
1389 wUnmaximizeWindow(wwin);
1390 } else {
1391 wMaximizeWindow(wwin, MAX_VERTICAL|MAX_HORIZONTAL);
1394 break;
1395 case WKBD_VMAXIMIZE:
1396 if (ISMAPPED(wwin) && ISFOCUSED(wwin)
1397 && !wwin->window_flags.no_resizable) {
1398 CloseWindowMenu(scr);
1400 if (wwin->flags.maximized) {
1401 wUnmaximizeWindow(wwin);
1402 } else {
1403 wMaximizeWindow(wwin, MAX_VERTICAL);
1406 break;
1407 case WKBD_RAISE:
1408 if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1409 CloseWindowMenu(scr);
1411 wRaiseFrame(wwin->frame->core);
1413 break;
1414 case WKBD_LOWER:
1415 if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1416 CloseWindowMenu(scr);
1418 wLowerFrame(wwin->frame->core);
1420 break;
1421 case WKBD_RAISELOWER:
1422 /* raise or lower the window under the pointer, not the
1423 * focused one
1425 wwin = windowUnderPointer(scr);
1426 if (wwin)
1427 wRaiseLowerFrame(wwin->frame->core);
1428 break;
1429 case WKBD_SHADE:
1430 if (ISMAPPED(wwin) && ISFOCUSED(wwin)
1431 && !wwin->window_flags.no_shadeable) {
1432 if (wwin->flags.shaded)
1433 wUnshadeWindow(wwin);
1434 else
1435 wShadeWindow(wwin);
1437 break;
1438 case WKBD_CLOSE:
1439 if (ISMAPPED(wwin) && ISFOCUSED(wwin)
1440 && !wwin->window_flags.no_closable) {
1441 CloseWindowMenu(scr);
1442 if (wwin->protocols.DELETE_WINDOW)
1443 wClientSendProtocol(wwin, _XA_WM_DELETE_WINDOW,
1444 event->xkey.time);
1446 break;
1447 case WKBD_SELECT:
1448 if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1449 wSelectWindow(wwin, !wwin->flags.selected);
1451 break;
1452 case WKBD_FOCUSNEXT:
1453 wwin = NextFocusWindow(scr);
1454 if (wwin != NULL) {
1455 wSetFocusTo(scr, wwin);
1456 if (wPreferences.circ_raise)
1457 wRaiseFrame(wwin->frame->core);
1459 break;
1460 case WKBD_FOCUSPREV:
1461 wwin = PrevFocusWindow(scr);
1462 if (wwin != NULL) {
1463 wSetFocusTo(scr, wwin);
1464 if (wPreferences.circ_raise)
1465 wRaiseFrame(wwin->frame->core);
1467 break;
1468 #if (defined(__STDC__) && !defined(UNIXCPP)) || defined(ANSICPP)
1469 #define GOTOWORKS(wk) case WKBD_WORKSPACE##wk:\
1470 i = (scr->current_workspace/10)*10 + wk - 1;\
1471 if (wPreferences.ws_advance || i<scr->workspace_count)\
1472 wWorkspaceChange(scr, i);\
1473 break
1474 #else
1475 #define GOTOWORKS(wk) case WKBD_WORKSPACE/**/wk:\
1476 i = (scr->current_workspace/10)*10 + wk - 1;\
1477 if (wPreferences.ws_advance || i<scr->workspace_count)\
1478 wWorkspaceChange(scr, i);\
1479 break
1480 #endif
1481 GOTOWORKS(1);
1482 GOTOWORKS(2);
1483 GOTOWORKS(3);
1484 GOTOWORKS(4);
1485 GOTOWORKS(5);
1486 GOTOWORKS(6);
1487 GOTOWORKS(7);
1488 GOTOWORKS(8);
1489 GOTOWORKS(9);
1490 GOTOWORKS(10);
1491 #undef GOTOWORKS
1492 case WKBD_NEXTWORKSPACE:
1493 if (scr->current_workspace < scr->workspace_count-1)
1494 wWorkspaceChange(scr, scr->current_workspace+1);
1495 else if (scr->current_workspace == scr->workspace_count-1) {
1496 if (wPreferences.ws_advance &&
1497 scr->current_workspace < MAX_WORKSPACES-1)
1498 wWorkspaceChange(scr, scr->current_workspace+1);
1499 else if (wPreferences.ws_cycle)
1500 wWorkspaceChange(scr, 0);
1502 break;
1503 case WKBD_PREVWORKSPACE:
1504 if (scr->current_workspace > 0)
1505 wWorkspaceChange(scr, scr->current_workspace-1);
1506 else if (scr->current_workspace==0 && wPreferences.ws_cycle)
1507 wWorkspaceChange(scr, scr->workspace_count-1);
1508 break;
1509 case WKBD_WINDOW1:
1510 case WKBD_WINDOW2:
1511 case WKBD_WINDOW3:
1512 case WKBD_WINDOW4:
1513 if (scr->shortcutWindow[command-WKBD_WINDOW1]) {
1514 wMakeWindowVisible(scr->shortcutWindow[command-WKBD_WINDOW1]);
1515 } else if (wwin && ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1516 scr->shortcutWindow[command-WKBD_WINDOW1] = wwin;
1517 wSelectWindow(wwin, !wwin->flags.selected);
1518 XFlush(dpy);
1519 wusleep(3000);
1520 wSelectWindow(wwin, !wwin->flags.selected);
1521 XFlush(dpy);
1523 break;
1524 case WKBD_NEXTWSLAYER:
1525 case WKBD_PREVWSLAYER:
1527 int row, column;
1529 row = scr->current_workspace/10;
1530 column = scr->current_workspace%10;
1532 if (command==WKBD_NEXTWSLAYER) {
1533 if ((row+1)*10 < scr->workspace_count)
1534 wWorkspaceChange(scr, column+(row+1)*10);
1535 } else {
1536 if (row > 0)
1537 wWorkspaceChange(scr, column+(row-1)*10);
1540 break;
1541 case WKBD_CLIPLOWER:
1542 if (!wPreferences.flags.noclip)
1543 wDockLower(scr->workspaces[scr->current_workspace]->clip);
1544 break;
1545 case WKBD_CLIPRAISE:
1546 if (!wPreferences.flags.noclip)
1547 wDockRaise(scr->workspaces[scr->current_workspace]->clip);
1548 break;
1549 case WKBD_CLIPRAISELOWER:
1550 if (!wPreferences.flags.noclip)
1551 wDockRaiseLower(scr->workspaces[scr->current_workspace]->clip);
1552 break;
1553 #ifdef KEEP_XKB_LOCK_STATUS
1554 case WKBD_TOGGLE:
1555 if(wPreferences.modelock){
1556 XkbGetState(dpy,XkbUseCoreKbd,&staterec);
1557 /*toggle*/
1558 XkbLockGroup(dpy,XkbUseCoreKbd,
1559 wwin->languagemode=staterec.compat_state&32?0:1);
1561 break;
1562 #endif /* KEEP_XKB_LOCK_STATUS */
1568 static void
1569 handleMotionNotify(XEvent *event)
1571 WMenu *menu;
1572 WScreen *scr = wScreenForRootWindow(event->xmotion.root);
1574 if (wPreferences.scrollable_menus) {
1575 if (event->xmotion.x_root <= 1 ||
1576 event->xmotion.x_root >= (scr->scr_width - 2) ||
1577 event->xmotion.y_root <= 1 ||
1578 event->xmotion.y_root >= (scr->scr_height - 2)) {
1580 #ifdef DEBUG
1581 puts("pointer at screen edge");
1582 #endif
1584 menu = wMenuUnderPointer(scr);
1585 if (menu!=NULL)
1586 wMenuScroll(menu, event);