Bug fixes for 0.20.3 pre-release 2
[wmaker-crm.git] / src / event.c
blob7ebfcd243b1cba7f4cb7e8e3c820ddb5f1ee45f8
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);
225 RestoreDesktop(scr);
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);
239 RestoreDesktop(scr);
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.window == 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);
661 if (XFindContext(dpy, event->xbutton.window, wWinContext,
662 (XPointer *)&desc)==XCNOENT) {
663 return;
666 if (desc->parent_type == WCLASS_WINDOW) {
667 XSync(dpy, 0);
669 if (event->xbutton.state & MOD_MASK) {
670 XAllowEvents(dpy, AsyncPointer, CurrentTime);
673 if (wPreferences.focus_mode == WKF_CLICK) {
674 if (wPreferences.ignore_focus_click) {
675 XAllowEvents(dpy, AsyncPointer, CurrentTime);
677 XAllowEvents(dpy, ReplayPointer, CurrentTime);
679 XSync(dpy, 0);
680 } else if (desc->parent_type == WCLASS_APPICON
681 || desc->parent_type == WCLASS_MINIWINDOW
682 || desc->parent_type == WCLASS_DOCK_ICON) {
683 if (event->xbutton.state & MOD_MASK) {
684 XSync(dpy, 0);
685 XAllowEvents(dpy, AsyncPointer, CurrentTime);
686 XSync(dpy, 0);
690 if (desc->handle_mousedown!=NULL) {
691 (*desc->handle_mousedown)(desc, event);
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(Window window)
708 WWindow *wwin;
710 #ifdef DEBUG
711 puts("got map");
712 #endif
713 wwin= wWindowFor(window);
714 if (wwin && wwin->client_win==window) {
715 if (wwin->flags.ignore_next_unmap) {
716 wwin->flags.ignore_next_unmap=0;
717 return;
719 if (wwin->flags.miniaturized) {
720 wDeiconifyWindow(wwin);
721 } else {
722 XGrabServer(dpy);
723 XSync(dpy,0);
724 XMapWindow(dpy, wwin->client_win);
725 XMapWindow(dpy, wwin->frame->core->window);
726 wwin->flags.mapped=1;
727 wClientSetState(wwin, NormalState, None);
728 XUngrabServer(dpy);
734 static void
735 handleUnmapNotify(XEvent *event)
737 WWindow *wwin;
738 XEvent ev;
740 #ifdef DEBUG
741 puts("got unmap");
742 #endif
743 wwin = wWindowFor(event->xunmap.window);
744 if (!wwin || wwin->client_win!=event->xunmap.window)
745 return;
747 if (!wwin->flags.mapped
748 && wwin->frame->workspace==wwin->screen_ptr->current_workspace
749 && !wwin->flags.miniaturized && !wwin->flags.hidden)
750 return;
752 if (wwin->flags.ignore_next_unmap) {
753 return;
755 XGrabServer(dpy);
756 XUnmapWindow(dpy, wwin->frame->core->window);
757 wwin->flags.mapped = 0;
758 XSync(dpy, 0);
759 /* check if the window was destroyed */
760 if (XCheckTypedWindowEvent(dpy, wwin->client_win, DestroyNotify,&ev)) {
761 DispatchEvent(&ev);
762 } else {
763 Bool reparented = False;
765 if (XCheckTypedWindowEvent(dpy, wwin->client_win, ReparentNotify, &ev))
766 reparented = True;
768 /* withdraw window */
769 wwin->flags.mapped = 0;
770 if (!reparented)
771 wClientSetState(wwin, WithdrawnState, None);
773 /* if the window was reparented, do not reparent it back to the
774 * root window */
775 wUnmanageWindow(wwin, !reparented);
777 XUngrabServer(dpy);
781 static void
782 handleConfigureRequest(XEvent *event)
784 WWindow *wwin;
786 #ifdef DEBUG
787 puts("got configure request");
788 #endif
789 if (!(wwin=wWindowFor(event->xconfigurerequest.window))) {
791 * Configure request for unmapped window
793 wClientConfigure(NULL, &(event->xconfigurerequest));
794 } else {
795 wClientConfigure(wwin, &(event->xconfigurerequest));
800 static void
801 handlePropertyNotify(XEvent *event)
803 WWindow *wwin;
804 WApplication *wapp;
805 Window jr;
806 int ji;
807 unsigned int ju;
809 #ifdef DEBUG
810 puts("got property notify");
811 #endif
812 if ((wwin=wWindowFor(event->xproperty.window))) {
813 if (!XGetGeometry(dpy, wwin->client_win, &jr, &ji, &ji,
814 &ju, &ju, &ju, &ju)) {
815 return;
817 wClientCheckProperty(wwin, &event->xproperty);
819 wapp = wApplicationOf(event->xproperty.window);
820 if (wapp) {
821 wClientCheckProperty(wapp->main_window_desc, &event->xproperty);
826 static void
827 handleClientMessage(XEvent *event)
829 WWindow *wwin;
830 WObjDescriptor *desc;
832 #ifdef DEBUG
833 puts("got client message");
834 #endif
835 /* handle transition from Normal to Iconic state */
836 if (event->xclient.message_type == _XA_WM_CHANGE_STATE
837 && event->xclient.format == 32
838 && event->xclient.data.l[0] == IconicState) {
840 wwin = wWindowFor(event->xclient.window);
841 if (!wwin) return;
842 if (!wwin->flags.miniaturized)
843 wIconifyWindow(wwin);
844 } else if (event->xclient.message_type == _XA_WM_COLORMAP_NOTIFY
845 && event->xclient.format == 32) {
846 WScreen *scr = wScreenForRootWindow(event->xclient.window);
848 if (!scr)
849 return;
851 if (event->xclient.data.l[1] == 1) { /* starting */
852 wColormapAllowClientInstallation(scr, True);
853 } else { /* stopping */
854 wColormapAllowClientInstallation(scr, False);
856 } else if (event->xclient.message_type == _XA_WINDOWMAKER_WM_FUNCTION) {
857 WApplication *wapp;
858 int done=0;
859 wapp = wApplicationOf(event->xclient.window);
860 if (wapp) {
861 switch (event->xclient.data.l[0]) {
862 case WMFHideOtherApplications:
863 wHideOtherApplications(wapp->main_window_desc);
864 done = 1;
865 break;
867 case WMFHideApplication:
868 wHideApplication(wapp);
869 done = 1;
870 break;
873 if (!done) {
874 wwin = wWindowFor(event->xclient.window);
875 if (wwin) {
876 switch (event->xclient.data.l[0]) {
877 case WMFHideOtherApplications:
878 wHideOtherApplications(wwin);
879 break;
881 case WMFHideApplication:
882 wHideApplication(wApplicationOf(wwin->main_window));
883 break;
887 #ifdef XDE_DND
888 } else if (event->xclient.message_type==_XA_XDE_DATA_AVAILABLE) {
889 GdkEvent gdkev;
890 WScreen *scr = wScreenForWindow(event->xclient.window);
891 Atom tmpatom;
892 int datalenght;
893 long tmplong;
894 char * tmpstr, * runstr, * freestr, * tofreestr;
895 printf("x\n");
896 gdkev.dropdataavailable.u.allflags = event->xclient.data.l[1];
897 gdkev.dropdataavailable.timestamp = event->xclient.data.l[4];
899 if(gdkev.dropdataavailable.u.flags.isdrop){
900 gdkev.dropdataavailable.type = GDK_DROP_DATA_AVAIL;
901 gdkev.dropdataavailable.requestor = event->xclient.data.l[0];
902 XGetWindowProperty(dpy,gdkev.dropdataavailable.requestor,
903 event->xclient.data.l[2],
904 0, LONG_MAX -1,
905 0, XA_PRIMARY, &tmpatom,
906 &datalenght,
907 &gdkev.dropdataavailable.data_numbytes,
908 &tmplong,
909 &tmpstr);
910 datalenght=gdkev.dropdataavailable.data_numbytes-1;
911 tofreestr=tmpstr;
912 runstr=NULL;
913 for(;datalenght>0;datalenght-=(strlen(tmpstr)+1),tmpstr=&tmpstr[strlen(tmpstr)+1]){
914 freestr=runstr;runstr=wstrappend(runstr,tmpstr);free(freestr);
915 freestr=runstr;runstr=wstrappend(runstr," ");free(freestr);
917 free(tofreestr);
918 scr->xdestring=runstr;
919 /* no need to redirect ? */
920 wDockReceiveDNDDrop(scr,event);
921 free(runstr);
922 scr->xdestring=NULL;
925 } else if (event->xclient.message_type==_XA_XDE_LEAVE) {
926 printf("leave\n");
927 } else if (event->xclient.message_type==_XA_XDE_ENTER) {
928 GdkEvent gdkev;
929 XEvent replyev;
931 gdkev.dropenter.u.allflags=event->xclient.data.l[1];
932 printf("from win %x\n",event->xclient.data.l[0]);
933 printf("to win %x\n",event->xclient.window);
934 printf("enter %x\n",event->xclient.data.l[1]);
935 printf("v %x ",event->xclient.data.l[2]);
936 printf("%x ",event->xclient.data.l[3]);
937 printf("%x\n",event->xclient.data.l[4]);
939 if(event->xclient.data.l[2]==_XDE_FILETYPE ||
940 event->xclient.data.l[3]==_XDE_FILETYPE ||
941 event->xclient.data.l[4]==_XDE_FILETYPE ||
942 event->xclient.data.l[2]==_XDE_URLTYPE ||
943 event->xclient.data.l[3]==_XDE_URLTYPE ||
944 event->xclient.data.l[4]==_XDE_URLTYPE)
945 if(gdkev.dropenter.u.flags.sendreply){
946 /*reply*/
947 replyev.xclient.type = ClientMessage;
948 replyev.xclient.window = event->xclient.data.l[0];
949 replyev.xclient.format = 32;
950 replyev.xclient.message_type = _XA_XDE_REQUEST;
951 replyev.xclient.data.l[0] = event->xclient.window;
953 gdkev.dragrequest.u.allflags = 0;
954 gdkev.dragrequest.u.flags.protocol_version = 0;
955 gdkev.dragrequest.u.flags.willaccept = 1;
956 gdkev.dragrequest.u.flags.delete_data = 0;
958 replyev.xclient.data.l[1] = gdkev.dragrequest.u.allflags;
959 replyev.xclient.data.l[2] = replyev.xclient.data.l[3] = 0;
960 replyev.xclient.data.l[4] = event->xclient.data.l[2];
961 XSendEvent(dpy, replyev.xclient.window, 0, NoEventMask, &replyev);
962 XSync(dpy, 0);
964 #endif /* XDE_DND */
965 #ifdef OFFIX_DND
966 } else if (event->xclient.message_type==_XA_DND_PROTOCOL) {
967 WScreen *scr = wScreenForWindow(event->xclient.window);
968 if (scr && wDockReceiveDNDDrop(scr,event))
969 goto redirect_message;
970 #endif /* OFFIX_DND */
971 } else {
972 #ifdef OFFIX_DND
973 redirect_message:
974 #endif
976 * Non-standard thing, but needed by OffiX DND.
977 * For when the icon frame gets a ClientMessage
978 * that should have gone to the icon_window.
980 if (XFindContext(dpy, event->xbutton.window, wWinContext,
981 (XPointer *)&desc)!=XCNOENT) {
982 struct WIcon *icon=NULL;
984 if (desc->parent_type == WCLASS_MINIWINDOW) {
985 icon = (WIcon*)desc->parent;
986 } else if (desc->parent_type == WCLASS_DOCK_ICON
987 || desc->parent_type == WCLASS_APPICON) {
988 icon = ((WAppIcon*)desc->parent)->icon;
990 if (icon && (wwin=icon->owner)) {
991 if (wwin->client_win!=event->xclient.window) {
992 event->xclient.window = wwin->client_win;
993 XSendEvent(dpy, wwin->client_win, False, NoEventMask,
994 event);
1002 static void
1003 raiseWindow(WScreen *scr)
1005 WWindow *wwin;
1007 scr->autoRaiseTimer = NULL;
1009 wwin = wWindowFor(scr->autoRaiseWindow);
1010 if (!wwin)
1011 return;
1013 if (!wwin->flags.destroyed) {
1014 wRaiseFrame(wwin->frame->core);
1015 /* this is needed or a race condition will occur */
1016 XSync(dpy, False);
1021 static void
1022 handleEnterNotify(XEvent *event)
1024 WWindow *wwin;
1025 WObjDescriptor *desc = NULL;
1026 XEvent ev;
1027 WScreen *scr = wScreenForRootWindow(event->xcrossing.root);
1030 #ifdef DEBUG
1031 puts("got enter notify");
1032 #endif
1034 if (XCheckTypedWindowEvent(dpy, event->xcrossing.window, LeaveNotify,
1035 &ev)) {
1036 /* already left the window... */
1037 saveTimestamp(&ev);
1038 if (ev.xcrossing.mode==event->xcrossing.mode
1039 && ev.xcrossing.detail==event->xcrossing.detail) {
1040 return;
1044 if (XFindContext(dpy, event->xcrossing.window, wWinContext,
1045 (XPointer *)&desc)!=XCNOENT) {
1046 if(desc->handle_enternotify)
1047 (*desc->handle_enternotify)(desc, event);
1050 /* enter to window */
1051 wwin = wWindowFor(event->xcrossing.window);
1052 if (!wwin) {
1053 if (wPreferences.focus_mode==WKF_POINTER
1054 && event->xcrossing.window==event->xcrossing.root) {
1055 wSetFocusTo(scr, NULL);
1057 if (wPreferences.colormap_mode==WKF_POINTER) {
1058 wColormapInstallForWindow(scr, NULL);
1060 if (scr->autoRaiseTimer
1061 && event->xcrossing.root==event->xcrossing.window) {
1062 WMDeleteTimerHandler(scr->autoRaiseTimer);
1063 scr->autoRaiseTimer = NULL;
1065 } else {
1066 /* set focus if in focus-follows-mouse mode and the event
1067 * is for the frame window and window doesn't have focus yet */
1068 if ((wPreferences.focus_mode==WKF_POINTER
1069 || wPreferences.focus_mode==WKF_SLOPPY)
1070 && wwin->frame->core->window==event->xcrossing.window
1071 && !wwin->flags.focused) {
1072 wSetFocusTo(scr, wwin);
1074 if (scr->autoRaiseTimer)
1075 WMDeleteTimerHandler(scr->autoRaiseTimer);
1076 scr->autoRaiseTimer = NULL;
1078 if (wPreferences.raise_delay && !wwin->window_flags.no_focusable) {
1079 scr->autoRaiseWindow = wwin->frame->core->window;
1080 scr->autoRaiseTimer
1081 = WMAddTimerHandler(wPreferences.raise_delay,
1082 (WMCallback*)raiseWindow, scr);
1085 /* Install colormap for window, if the colormap installation mode
1086 * is colormap_follows_mouse */
1087 if (wPreferences.colormap_mode==WKF_POINTER) {
1088 if (wwin->client_win==event->xcrossing.window)
1089 wColormapInstallForWindow(scr, wwin);
1090 else
1091 wColormapInstallForWindow(scr, NULL);
1095 /* a little kluge to hide the clip balloon */
1096 if (!wPreferences.flags.noclip && scr->flags.clip_balloon_mapped) {
1097 if (!desc) {
1098 XUnmapWindow(dpy, scr->clip_balloon);
1099 scr->flags.clip_balloon_mapped = 0;
1100 } else {
1101 if (desc->parent_type!=WCLASS_DOCK_ICON
1102 || scr->clip_icon != desc->parent) {
1103 XUnmapWindow(dpy, scr->clip_balloon);
1104 scr->flags.clip_balloon_mapped = 0;
1109 if (event->xcrossing.window == event->xcrossing.root
1110 && event->xcrossing.detail == NotifyNormal
1111 && event->xcrossing.detail != NotifyInferior
1112 && wPreferences.focus_mode != WKF_CLICK) {
1114 wSetFocusTo(scr, scr->focused_window);
1117 #ifdef BALLOON_TEXT
1118 wBalloonEnteredObject(scr, desc);
1119 #endif
1123 static void
1124 handleLeaveNotify(XEvent *event)
1126 WObjDescriptor *desc = NULL;
1128 if (XFindContext(dpy, event->xcrossing.window, wWinContext,
1129 (XPointer *)&desc)!=XCNOENT) {
1130 if(desc->handle_leavenotify)
1131 (*desc->handle_leavenotify)(desc, event);
1133 if (event->xcrossing.window == event->xcrossing.root
1134 && event->xcrossing.mode == NotifyNormal
1135 && event->xcrossing.detail != NotifyInferior
1136 && wPreferences.focus_mode != WKF_CLICK) {
1138 WScreen *scr = wScreenForRootWindow(event->xcrossing.root);
1140 wSetFocusTo(scr, NULL);
1145 #ifdef SHAPE
1146 static void
1147 handleShapeNotify(XEvent *event)
1149 XShapeEvent *shev = (XShapeEvent*)event;
1150 WWindow *wwin;
1151 XEvent ev;
1153 #ifdef DEBUG
1154 puts("got shape notify");
1155 #endif
1157 while (XCheckTypedWindowEvent(dpy, shev->window, event->type, &ev)) {
1158 XShapeEvent *sev = (XShapeEvent*)&ev;
1160 if (sev->kind == ShapeBounding) {
1161 if (sev->shaped == shev->shaped) {
1162 *shev = *sev;
1163 } else {
1164 XPutBackEvent(dpy, &ev);
1165 break;
1170 wwin = wWindowFor(shev->window);
1171 if (!wwin || shev->kind != ShapeBounding)
1172 return;
1174 if (!shev->shaped && wwin->flags.shaped) {
1176 wwin->flags.shaped = 0;
1177 wWindowClearShape(wwin);
1179 } else if (shev->shaped) {
1181 wwin->flags.shaped = 1;
1182 wWindowSetShape(wwin);
1185 #endif /* SHAPE */
1188 static void
1189 handleColormapNotify(XEvent *event)
1191 WWindow *wwin;
1192 WScreen *scr;
1193 Bool reinstall = False;
1195 wwin = wWindowFor(event->xcolormap.window);
1196 if (!wwin)
1197 return;
1199 scr = wwin->screen_ptr;
1201 do {
1202 if (wwin) {
1203 if (event->xcolormap.new) {
1204 XWindowAttributes attr;
1206 XGetWindowAttributes(dpy, wwin->client_win, &attr);
1208 if (wwin == scr->cmap_window && wwin->cmap_window_no == 0)
1209 scr->current_colormap = attr.colormap;
1211 reinstall = True;
1212 } else if (event->xcolormap.state == ColormapUninstalled &&
1213 scr->current_colormap == event->xcolormap.colormap) {
1215 /* some bastard app (like XV) removed our colormap */
1216 reinstall = True;
1217 } else if (event->xcolormap.state == ColormapInstalled &&
1218 scr->current_colormap == event->xcolormap.colormap) {
1220 /* someone has put our colormap back */
1221 reinstall = False;
1224 } while (XCheckTypedEvent(dpy, ColormapNotify, event)
1225 && ((wwin = wWindowFor(event->xcolormap.window)) || 1));
1227 if (reinstall && scr->current_colormap!=None) {
1228 if (!scr->flags.colormap_stuff_blocked)
1229 XInstallColormap(dpy, scr->current_colormap);
1235 static void
1236 handleFocusIn(XEvent *event)
1238 WWindow *wwin;
1241 * For applications that like stealing the focus.
1243 while (XCheckTypedEvent(dpy, FocusIn, event));
1244 saveTimestamp(event);
1245 if (event->xfocus.mode == NotifyUngrab
1246 || event->xfocus.mode == NotifyGrab
1247 || event->xfocus.detail > NotifyNonlinearVirtual) {
1248 return;
1251 wwin = wWindowFor(event->xfocus.window);
1252 if (wwin && !wwin->flags.focused) {
1253 if (wwin->flags.mapped)
1254 wSetFocusTo(wwin->screen_ptr, wwin);
1255 else
1256 wSetFocusTo(wwin->screen_ptr, NULL);
1257 } else if (!wwin) {
1258 WScreen *scr = wScreenForWindow(event->xfocus.window);
1259 if (scr)
1260 wSetFocusTo(scr, NULL);
1265 static WWindow*
1266 windowUnderPointer(WScreen *scr)
1268 unsigned int mask;
1269 int foo;
1270 Window bar, win;
1272 if (XQueryPointer(dpy, scr->root_win, &bar, &win, &foo, &foo, &foo, &foo,
1273 &mask))
1274 return wWindowFor(win);
1275 return NULL;
1278 static void
1279 handleKeyPress(XEvent *event)
1281 WScreen *scr = wScreenForRootWindow(event->xkey.root);
1282 WWindow *wwin = scr->focused_window;
1283 int i;
1284 int modifiers;
1285 int command=-1;
1286 #ifdef KEEP_XKB_LOCK_STATUS
1287 XkbStateRec staterec;
1288 #endif /*KEEP_XKB_LOCK_STATUS*/
1290 /* ignore CapsLock */
1291 modifiers = event->xkey.state & ValidModMask;
1293 for (i=0; i<WKBD_LAST; i++) {
1294 if (wKeyBindings[i].keycode==0)
1295 continue;
1297 if (wKeyBindings[i].keycode==event->xkey.keycode
1298 && (/*wKeyBindings[i].modifier==0
1299 ||*/ wKeyBindings[i].modifier==modifiers)) {
1300 command = i;
1301 break;
1305 if (command < 0) {
1306 if (!wRootMenuPerformShortcut(event)) {
1307 static int dontLoop = 0;
1309 if (dontLoop > 10) {
1310 wwarning("problem with key event processing code");
1311 return;
1313 dontLoop++;
1314 /* if the focused window is an internal window, try redispatching
1315 * the event to the managed window, as it can be a WINGs window */
1316 if (wwin && wwin->flags.internal_window
1317 && wwin->client_leader!=None) {
1318 /* client_leader contains the WINGs toplevel */
1319 event->xany.window = wwin->client_leader;
1320 WMHandleEvent(event);
1322 dontLoop--;
1324 return;
1327 #define ISMAPPED(w) ((w) && !(w)->flags.miniaturized && ((w)->flags.mapped || (w)->flags.shaded))
1328 #define ISFOCUSED(w) ((w) && (w)->flags.focused)
1330 switch (command) {
1331 case WKBD_ROOTMENU:
1332 OpenRootMenu(scr, event->xkey.x_root, event->xkey.y_root, True);
1333 break;
1334 case WKBD_WINDOWMENU:
1335 if (ISMAPPED(wwin) && ISFOCUSED(wwin))
1336 OpenWindowMenu(wwin, wwin->frame_x,
1337 wwin->frame_y+wwin->frame->top_width, True);
1338 break;
1339 case WKBD_WINDOWLIST:
1340 OpenSwitchMenu(scr, event->xkey.x_root, event->xkey.y_root, True);
1341 break;
1342 case WKBD_MINIATURIZE:
1343 if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1344 CloseWindowMenu(scr);
1346 if (wwin->protocols.MINIATURIZE_WINDOW)
1347 wClientSendProtocol(wwin, _XA_GNUSTEP_WM_MINIATURIZE_WINDOW,
1348 event->xbutton.time);
1349 else {
1350 if (!wwin->window_flags.no_miniaturizable)
1351 wIconifyWindow(wwin);
1354 break;
1355 case WKBD_HIDE:
1356 if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1357 WApplication *wapp = wApplicationOf(wwin->main_window);
1358 CloseWindowMenu(scr);
1360 if (wapp && !wapp->main_window_desc->window_flags.no_appicon) {
1361 wHideApplication(wapp);
1364 break;
1365 case WKBD_MAXIMIZE:
1366 if (ISMAPPED(wwin) && ISFOCUSED(wwin)
1367 && !wwin->window_flags.no_resizable) {
1368 CloseWindowMenu(scr);
1370 if (wwin->flags.maximized) {
1371 wUnmaximizeWindow(wwin);
1372 } else {
1373 wMaximizeWindow(wwin, MAX_VERTICAL|MAX_HORIZONTAL);
1376 break;
1377 case WKBD_VMAXIMIZE:
1378 if (ISMAPPED(wwin) && ISFOCUSED(wwin)
1379 && !wwin->window_flags.no_resizable) {
1380 CloseWindowMenu(scr);
1382 if (wwin->flags.maximized) {
1383 wUnmaximizeWindow(wwin);
1384 } else {
1385 wMaximizeWindow(wwin, MAX_VERTICAL);
1388 break;
1389 case WKBD_RAISE:
1390 if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1391 CloseWindowMenu(scr);
1393 wRaiseFrame(wwin->frame->core);
1395 break;
1396 case WKBD_LOWER:
1397 if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1398 CloseWindowMenu(scr);
1400 wLowerFrame(wwin->frame->core);
1402 break;
1403 case WKBD_RAISELOWER:
1404 /* raise or lower the window under the pointer, not the
1405 * focused one
1407 wwin = windowUnderPointer(scr);
1408 if (wwin)
1409 wRaiseLowerFrame(wwin->frame->core);
1410 break;
1411 case WKBD_SHADE:
1412 if (ISMAPPED(wwin) && ISFOCUSED(wwin)
1413 && !wwin->window_flags.no_shadeable) {
1414 if (wwin->flags.shaded)
1415 wUnshadeWindow(wwin);
1416 else
1417 wShadeWindow(wwin);
1419 break;
1420 case WKBD_CLOSE:
1421 if (ISMAPPED(wwin) && ISFOCUSED(wwin)
1422 && !wwin->window_flags.no_closable) {
1423 CloseWindowMenu(scr);
1424 if (wwin->protocols.DELETE_WINDOW)
1425 wClientSendProtocol(wwin, _XA_WM_DELETE_WINDOW,
1426 event->xkey.time);
1428 break;
1429 case WKBD_SELECT:
1430 if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1431 wSelectWindow(wwin, !wwin->flags.selected);
1433 break;
1434 case WKBD_FOCUSNEXT:
1435 wwin = NextFocusWindow(scr);
1436 if (wwin != NULL) {
1437 wSetFocusTo(scr, wwin);
1438 if (wPreferences.circ_raise)
1439 wRaiseFrame(wwin->frame->core);
1441 break;
1442 case WKBD_FOCUSPREV:
1443 wwin = PrevFocusWindow(scr);
1444 if (wwin != NULL) {
1445 wSetFocusTo(scr, wwin);
1446 if (wPreferences.circ_raise)
1447 wRaiseFrame(wwin->frame->core);
1449 break;
1450 #if (defined(__STDC__) && !defined(UNIXCPP)) || defined(ANSICPP)
1451 #define GOTOWORKS(wk) case WKBD_WORKSPACE##wk:\
1452 i = (scr->current_workspace/10)*10 + wk - 1;\
1453 if (wPreferences.ws_advance || i<scr->workspace_count)\
1454 wWorkspaceChange(scr, i);\
1455 break
1456 #else
1457 #define GOTOWORKS(wk) case WKBD_WORKSPACE/**/wk:\
1458 i = (scr->current_workspace/10)*10 + wk - 1;\
1459 if (wPreferences.ws_advance || i<scr->workspace_count)\
1460 wWorkspaceChange(scr, i);\
1461 break
1462 #endif
1463 GOTOWORKS(1);
1464 GOTOWORKS(2);
1465 GOTOWORKS(3);
1466 GOTOWORKS(4);
1467 GOTOWORKS(5);
1468 GOTOWORKS(6);
1469 GOTOWORKS(7);
1470 GOTOWORKS(8);
1471 GOTOWORKS(9);
1472 GOTOWORKS(10);
1473 #undef GOTOWORKS
1474 case WKBD_NEXTWORKSPACE:
1475 if (scr->current_workspace < scr->workspace_count-1)
1476 wWorkspaceChange(scr, scr->current_workspace+1);
1477 else if (scr->current_workspace == scr->workspace_count-1) {
1478 if (wPreferences.ws_advance &&
1479 scr->current_workspace < MAX_WORKSPACES-1)
1480 wWorkspaceChange(scr, scr->current_workspace+1);
1481 else if (wPreferences.ws_cycle)
1482 wWorkspaceChange(scr, 0);
1484 break;
1485 case WKBD_PREVWORKSPACE:
1486 if (scr->current_workspace > 0)
1487 wWorkspaceChange(scr, scr->current_workspace-1);
1488 else if (scr->current_workspace==0 && wPreferences.ws_cycle)
1489 wWorkspaceChange(scr, scr->workspace_count-1);
1490 break;
1491 case WKBD_WINDOW1:
1492 case WKBD_WINDOW2:
1493 case WKBD_WINDOW3:
1494 case WKBD_WINDOW4:
1495 if (scr->shortcutWindow[command-WKBD_WINDOW1]) {
1496 wMakeWindowVisible(scr->shortcutWindow[command-WKBD_WINDOW1]);
1497 } else if (wwin && ISMAPPED(wwin) && ISFOCUSED(wwin)) {
1498 scr->shortcutWindow[command-WKBD_WINDOW1] = wwin;
1499 wSelectWindow(wwin, !wwin->flags.selected);
1500 XFlush(dpy);
1501 wusleep(3000);
1502 wSelectWindow(wwin, !wwin->flags.selected);
1503 XFlush(dpy);
1505 break;
1506 case WKBD_NEXTWSLAYER:
1507 case WKBD_PREVWSLAYER:
1509 int row, column;
1511 row = scr->current_workspace/10;
1512 column = scr->current_workspace%10;
1514 if (command==WKBD_NEXTWSLAYER) {
1515 if ((row+1)*10 < scr->workspace_count)
1516 wWorkspaceChange(scr, column+(row+1)*10);
1517 } else {
1518 if (row > 0)
1519 wWorkspaceChange(scr, column+(row-1)*10);
1522 break;
1523 case WKBD_CLIPLOWER:
1524 if (!wPreferences.flags.noclip)
1525 wDockLower(scr->workspaces[scr->current_workspace]->clip);
1526 break;
1527 case WKBD_CLIPRAISE:
1528 if (!wPreferences.flags.noclip)
1529 wDockRaise(scr->workspaces[scr->current_workspace]->clip);
1530 break;
1531 case WKBD_CLIPRAISELOWER:
1532 if (!wPreferences.flags.noclip)
1533 wDockRaiseLower(scr->workspaces[scr->current_workspace]->clip);
1534 break;
1535 #ifdef KEEP_XKB_LOCK_STATUS
1536 case WKBD_TOGGLE:
1537 if(wPreferences.modelock){
1538 XkbGetState(dpy,XkbUseCoreKbd,&staterec);
1539 /*toggle*/
1540 XkbLockGroup(dpy,XkbUseCoreKbd,
1541 wwin->languagemode=staterec.compat_state&32?0:1);
1543 break;
1544 #endif /* KEEP_XKB_LOCK_STATUS */
1550 static void
1551 handleMotionNotify(XEvent *event)
1553 WMenu *menu;
1554 WScreen *scr = wScreenForRootWindow(event->xmotion.root);
1556 if (wPreferences.scrollable_menus) {
1557 if (event->xmotion.x_root <= 1 ||
1558 event->xmotion.x_root >= (scr->scr_width - 2) ||
1559 event->xmotion.y_root <= 1 ||
1560 event->xmotion.y_root >= (scr->scr_height - 2)) {
1562 #ifdef DEBUG
1563 puts("pointer at screen edge");
1564 #endif
1566 menu = wMenuUnderPointer(scr);
1567 if (menu!=NULL)
1568 wMenuScroll(menu, event);