~profzoom/ubuntu/quantal/wmaker/bug-1079925

« back to all changes in this revision

Viewing changes to src/event.c

  • Committer: Bazaar Package Importer
  • Author(s): Marcelo E. Magallon
  • Date: 2004-11-10 14:05:30 UTC
  • Revision ID: james.westby@ubuntu.com-20041110140530-qpd66b5lm38x7apk
Tags: upstream-0.91.0
ImportĀ upstreamĀ versionĀ 0.91.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* event.c- event loop and handling
 
2
 *
 
3
 *  Window Maker window manager
 
4
 *
 
5
 *  Copyright (c) 1997-2003 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.
 
11
 *
 
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.
 
16
 *
 
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.
 
21
 */
 
22
 
 
23
 
 
24
#include "wconfig.h"
 
25
 
 
26
 
 
27
#include <stdio.h>
 
28
#include <stdlib.h>
 
29
#include <unistd.h>
 
30
#include <string.h>
 
31
 
 
32
 
 
33
 
 
34
#include <X11/Xlib.h>
 
35
#include <X11/Xutil.h>
 
36
#ifdef SHAPE
 
37
# include <X11/extensions/shape.h>
 
38
#endif
 
39
#ifdef XDND
 
40
#include "xdnd.h"
 
41
#endif
 
42
 
 
43
#ifdef KEEP_XKB_LOCK_STATUS
 
44
#include <X11/XKBlib.h>
 
45
#endif /* KEEP_XKB_LOCK_STATUS */
 
46
 
 
47
#include "WindowMaker.h"
 
48
#include "window.h"
 
49
#include "actions.h"
 
50
#include "client.h"
 
51
#include "funcs.h"
 
52
#include "keybind.h"
 
53
#include "application.h"
 
54
#include "stacking.h"
 
55
#include "defaults.h"
 
56
#include "workspace.h"
 
57
#include "dock.h"
 
58
#include "framewin.h"
 
59
#include "properties.h"
 
60
#include "balloon.h"
 
61
#include "xinerama.h"
 
62
 
 
63
#ifdef NETWM_HINTS
 
64
# include "wmspec.h"
 
65
#endif
 
66
 
 
67
/******** Global Variables **********/
 
68
extern XContext wWinContext;
 
69
extern XContext wVEdgeContext;
 
70
 
 
71
extern Cursor wCursor[WCUR_LAST];
 
72
 
 
73
extern WShortKey wKeyBindings[WKBD_LAST];
 
74
extern int wScreenCount;
 
75
extern Time LastTimestamp;
 
76
extern Time LastFocusChange;
 
77
 
 
78
extern WPreferences wPreferences;
 
79
 
 
80
#define MOD_MASK wPreferences.modifier_mask
 
81
 
 
82
extern Atom _XA_WM_COLORMAP_NOTIFY;
 
83
 
 
84
extern Atom _XA_WM_CHANGE_STATE;
 
85
extern Atom _XA_WM_DELETE_WINDOW;
 
86
extern Atom _XA_GNUSTEP_WM_ATTR;
 
87
extern Atom _XA_GNUSTEP_WM_MINIATURIZE_WINDOW;
 
88
extern Atom _XA_GNUSTEP_TITLEBAR_STATE;
 
89
extern Atom _XA_WINDOWMAKER_WM_FUNCTION;
 
90
extern Atom _XA_WINDOWMAKER_COMMAND;
 
91
 
 
92
 
 
93
#ifdef SHAPE
 
94
extern Bool wShapeSupported;
 
95
extern int wShapeEventBase;
 
96
#endif
 
97
 
 
98
#ifdef KEEP_XKB_LOCK_STATUS
 
99
extern int wXkbEventBase;
 
100
#endif
 
101
 
 
102
/* special flags */
 
103
extern char WDelayedActionSet;
 
104
 
 
105
 
 
106
/************ Local stuff ***********/
 
107
 
 
108
 
 
109
static void saveTimestamp(XEvent *event);
 
110
static void handleColormapNotify();
 
111
static void handleMapNotify();
 
112
static void handleUnmapNotify();
 
113
static void handleButtonPress();
 
114
static void handleExpose();
 
115
static void handleDestroyNotify();
 
116
static void handleConfigureRequest();
 
117
static void handleMapRequest();
 
118
static void handlePropertyNotify();
 
119
static void handleEnterNotify();
 
120
static void handleLeaveNotify();
 
121
static void handleExtensions();
 
122
static void handleClientMessage();
 
123
static void handleKeyPress();
 
124
static void handleFocusIn();
 
125
static void handleMotionNotify();
 
126
static void handleVisibilityNotify();
 
127
 
 
128
 
 
129
#ifdef SHAPE
 
130
static void handleShapeNotify();
 
131
#endif
 
132
 
 
133
/* called from the signal handler */
 
134
void NotifyDeadProcess(pid_t pid, unsigned char status);
 
135
 
 
136
/* real dead process handler */
 
137
static void handleDeadProcess(void *foo);
 
138
 
 
139
 
 
140
typedef struct DeadProcesses {
 
141
    pid_t               pid;
 
142
    unsigned char       exit_status;
 
143
} DeadProcesses;
 
144
 
 
145
/* stack of dead processes */
 
146
static DeadProcesses deadProcesses[MAX_DEAD_PROCESSES];
 
147
static int deadProcessPtr=0;
 
148
 
 
149
 
 
150
typedef struct DeathHandler {
 
151
    WDeathHandler       *callback;
 
152
    pid_t               pid;
 
153
    void                *client_data;
 
154
} DeathHandler;
 
155
 
 
156
static WMArray *deathHandlers=NULL;
 
157
 
 
158
 
 
159
 
 
160
WMagicNumber
 
161
wAddDeathHandler(pid_t pid, WDeathHandler *callback, void *cdata)
 
162
{
 
163
    DeathHandler *handler;
 
164
 
 
165
    handler = malloc(sizeof(DeathHandler));
 
166
    if (!handler)
 
167
        return 0;
 
168
 
 
169
    handler->pid = pid;
 
170
    handler->callback = callback;
 
171
    handler->client_data = cdata;
 
172
 
 
173
    if (!deathHandlers)
 
174
        deathHandlers = WMCreateArrayWithDestructor(8, wfree);
 
175
 
 
176
    WMAddToArray(deathHandlers, handler);
 
177
 
 
178
    return handler;
 
179
}
 
180
 
 
181
 
 
182
 
 
183
void
 
184
wDeleteDeathHandler(WMagicNumber id)
 
185
{
 
186
    DeathHandler *handler=(DeathHandler*)id;
 
187
 
 
188
    if (!handler || !deathHandlers)
 
189
        return;
 
190
 
 
191
    /* array destructor will call wfree(handler) */
 
192
    WMRemoveFromArray(deathHandlers, handler);
 
193
}
 
194
 
 
195
 
 
196
void
 
197
DispatchEvent(XEvent *event)
 
198
{
 
199
    if (deathHandlers)
 
200
        handleDeadProcess(NULL);
 
201
 
 
202
    if (WCHECK_STATE(WSTATE_NEED_EXIT)) {
 
203
        WCHANGE_STATE(WSTATE_EXITING);
 
204
        /* received SIGTERM */
 
205
        /*
 
206
         * WMHandleEvent() can't be called from anything
 
207
         * executed inside here, or we can get in a infinite
 
208
         * recursive loop.
 
209
         */
 
210
        Shutdown(WSExitMode);
 
211
 
 
212
    } else if (WCHECK_STATE(WSTATE_NEED_RESTART)) {
 
213
        WCHANGE_STATE(WSTATE_RESTARTING);
 
214
 
 
215
        Shutdown(WSRestartPreparationMode);
 
216
        /* received SIGHUP */
 
217
        Restart(NULL, True);
 
218
    } else if (WCHECK_STATE(WSTATE_NEED_REREAD)) {
 
219
        WCHANGE_STATE(WSTATE_NORMAL);
 
220
        wDefaultsCheckDomains("bla");
 
221
    }
 
222
 
 
223
    /* for the case that all that is wanted to be dispatched is
 
224
     * the stuff above */
 
225
    if (!event)
 
226
        return;
 
227
 
 
228
    saveTimestamp(event);
 
229
    switch (event->type) {
 
230
    case MapRequest:
 
231
        handleMapRequest(event);
 
232
        break;
 
233
 
 
234
    case KeyPress:
 
235
        handleKeyPress(event);
 
236
        break;
 
237
 
 
238
    case MotionNotify:
 
239
        handleMotionNotify(event);
 
240
        break;
 
241
 
 
242
    case ConfigureRequest:
 
243
        handleConfigureRequest(event);
 
244
        break;
 
245
 
 
246
    case DestroyNotify:
 
247
        handleDestroyNotify(event);
 
248
        break;
 
249
 
 
250
    case MapNotify:
 
251
        handleMapNotify(event);
 
252
        break;
 
253
 
 
254
    case UnmapNotify:
 
255
        handleUnmapNotify(event);
 
256
        break;
 
257
 
 
258
    case ButtonPress:
 
259
        handleButtonPress(event);
 
260
        break;
 
261
 
 
262
    case Expose:
 
263
        handleExpose(event);
 
264
        break;
 
265
 
 
266
    case PropertyNotify:
 
267
        handlePropertyNotify(event);
 
268
        break;
 
269
 
 
270
    case EnterNotify:
 
271
        handleEnterNotify(event);
 
272
        break;
 
273
 
 
274
    case LeaveNotify:
 
275
        handleLeaveNotify(event);
 
276
        break;
 
277
 
 
278
    case ClientMessage:
 
279
        handleClientMessage(event);
 
280
        break;
 
281
 
 
282
    case ColormapNotify:
 
283
        handleColormapNotify(event);
 
284
        break;
 
285
 
 
286
    case MappingNotify:
 
287
        if (event->xmapping.request == MappingKeyboard
 
288
            || event->xmapping.request == MappingModifier)
 
289
            XRefreshKeyboardMapping(&event->xmapping);
 
290
        break;
 
291
 
 
292
    case FocusIn:
 
293
        handleFocusIn(event);
 
294
        break;
 
295
 
 
296
    case VisibilityNotify:
 
297
        handleVisibilityNotify(event);
 
298
        break;
 
299
    default:
 
300
        handleExtensions(event);
 
301
        break;
 
302
    }
 
303
}
 
304
 
 
305
 
 
306
/*
 
307
 *----------------------------------------------------------------------
 
308
 * EventLoop-
 
309
 *      Processes X and internal events indefinitely.
 
310
 *
 
311
 * Returns:
 
312
 *      Never returns
 
313
 *
 
314
 * Side effects:
 
315
 *      The LastTimestamp global variable is updated.
 
316
 *----------------------------------------------------------------------
 
317
 */
 
318
void
 
319
EventLoop()
 
320
{
 
321
    XEvent event;
 
322
 
 
323
    for(;;) {
 
324
        WMNextEvent(dpy, &event);
 
325
        WMHandleEvent(&event);
 
326
    }
 
327
}
 
328
 
 
329
 
 
330
/*
 
331
 *----------------------------------------------------------------------
 
332
 * ProcessPendingEvents --
 
333
 *      Processes the events that are currently pending (at the time
 
334
 *      this function is called) in the display's queue.
 
335
 *
 
336
 * Returns:
 
337
 *      After the pending events that were present at the function call
 
338
 *      are processed.
 
339
 *
 
340
 * Side effects:
 
341
 *      Many -- whatever handling events may involve.
 
342
 *
 
343
 *----------------------------------------------------------------------
 
344
 */
 
345
void
 
346
ProcessPendingEvents()
 
347
{
 
348
    XEvent event;
 
349
    int count;
 
350
 
 
351
    XSync(dpy, False);
 
352
 
 
353
    /* Take a snapshot of the event count in the queue */
 
354
    count = XPending(dpy);
 
355
 
 
356
    while (count>0 && XPending(dpy)) {
 
357
        WMNextEvent(dpy, &event);
 
358
        WMHandleEvent(&event);
 
359
        count--;
 
360
    }
 
361
}
 
362
 
 
363
 
 
364
Bool
 
365
IsDoubleClick(WScreen *scr, XEvent *event)
 
366
{
 
367
    if ((scr->last_click_time>0) &&
 
368
        (event->xbutton.time-scr->last_click_time<=wPreferences.dblclick_time)
 
369
        && (event->xbutton.button == scr->last_click_button)
 
370
        && (event->xbutton.window == scr->last_click_window)) {
 
371
 
 
372
        scr->flags.next_click_is_not_double = 1;
 
373
        scr->last_click_time = 0;
 
374
        scr->last_click_window = event->xbutton.window;
 
375
 
 
376
        return True;
 
377
    }
 
378
    return False;
 
379
}
 
380
 
 
381
 
 
382
void
 
383
NotifyDeadProcess(pid_t pid, unsigned char status)
 
384
{
 
385
    if (deadProcessPtr>=MAX_DEAD_PROCESSES-1) {
 
386
        wwarning("stack overflow: too many dead processes");
 
387
        return;
 
388
    }
 
389
    /* stack the process to be handled later,
 
390
     * as this is called from the signal handler */
 
391
    deadProcesses[deadProcessPtr].pid = pid;
 
392
    deadProcesses[deadProcessPtr].exit_status = status;
 
393
    deadProcessPtr++;
 
394
}
 
395
 
 
396
 
 
397
static void
 
398
handleDeadProcess(void *foo)
 
399
{
 
400
    DeathHandler *tmp;
 
401
    int i;
 
402
 
 
403
    for (i=0; i<deadProcessPtr; i++) {
 
404
        wWindowDeleteSavedStatesForPID(deadProcesses[i].pid);
 
405
    }
 
406
 
 
407
    if (!deathHandlers) {
 
408
        deadProcessPtr=0;
 
409
        return;
 
410
    }
 
411
 
 
412
    /* get the pids on the queue and call handlers */
 
413
    while (deadProcessPtr>0) {
 
414
        deadProcessPtr--;
 
415
 
 
416
        for (i = WMGetArrayItemCount(deathHandlers)-1; i >= 0; i--) {
 
417
            tmp = WMGetFromArray(deathHandlers, i);
 
418
            if (!tmp)
 
419
                continue;
 
420
 
 
421
            if (tmp->pid == deadProcesses[deadProcessPtr].pid) {
 
422
                (*tmp->callback)(tmp->pid,
 
423
                                 deadProcesses[deadProcessPtr].exit_status,
 
424
                                 tmp->client_data);
 
425
                wDeleteDeathHandler(tmp);
 
426
            }
 
427
        }
 
428
    }
 
429
}
 
430
 
 
431
 
 
432
static void
 
433
saveTimestamp(XEvent *event)
 
434
{
 
435
    /*
 
436
     * Never save CurrentTime as LastTimestamp because CurrentTime
 
437
     * it's not a real timestamp (it's the 0L constant)
 
438
     */
 
439
 
 
440
    switch (event->type) {
 
441
    case ButtonRelease:
 
442
    case ButtonPress:
 
443
        LastTimestamp = event->xbutton.time;
 
444
        break;
 
445
    case KeyPress:
 
446
    case KeyRelease:
 
447
        LastTimestamp = event->xkey.time;
 
448
        break;
 
449
    case MotionNotify:
 
450
        LastTimestamp = event->xmotion.time;
 
451
        break;
 
452
    case PropertyNotify:
 
453
        LastTimestamp = event->xproperty.time;
 
454
        break;
 
455
    case EnterNotify:
 
456
    case LeaveNotify:
 
457
        LastTimestamp = event->xcrossing.time;
 
458
        break;
 
459
    case SelectionClear:
 
460
        LastTimestamp = event->xselectionclear.time;
 
461
        break;
 
462
    case SelectionRequest:
 
463
        LastTimestamp = event->xselectionrequest.time;
 
464
        break;
 
465
    case SelectionNotify:
 
466
        LastTimestamp = event->xselection.time;
 
467
#ifdef XDND
 
468
        wXDNDProcessSelection(event);
 
469
#endif
 
470
        break;
 
471
    }
 
472
}
 
473
 
 
474
 
 
475
static int
 
476
matchWindow(void *item, void *cdata)
 
477
{
 
478
    return (((WFakeGroupLeader*)item)->origLeader == (Window)cdata);
 
479
}
 
480
 
 
481
 
 
482
static void
 
483
handleExtensions(XEvent *event)
 
484
{
 
485
#ifdef KEEP_XKB_LOCK_STATUS
 
486
    XkbEvent *xkbevent;
 
487
    xkbevent = (XkbEvent *)event;
 
488
#endif /*KEEP_XKB_LOCK_STATUS*/
 
489
#ifdef SHAPE
 
490
    if (wShapeSupported && event->type == (wShapeEventBase+ShapeNotify)) {
 
491
        handleShapeNotify(event);
 
492
    }
 
493
#endif
 
494
#ifdef KEEP_XKB_LOCK_STATUS
 
495
    if (wPreferences.modelock && (xkbevent->type == wXkbEventBase)){
 
496
        handleXkbIndicatorStateNotify(event);
 
497
    }
 
498
#endif /*KEEP_XKB_LOCK_STATUS*/
 
499
}
 
500
 
 
501
 
 
502
static void
 
503
handleMapRequest(XEvent *ev)
 
504
{
 
505
    WWindow *wwin;
 
506
    WScreen *scr = NULL;
 
507
    Window window = ev->xmaprequest.window;
 
508
 
 
509
#ifdef DEBUG
 
510
    printf("got map request for %x\n", (unsigned)window);
 
511
#endif
 
512
    if ((wwin = wWindowFor(window))) {
 
513
        if (wwin->flags.shaded) {
 
514
            wUnshadeWindow(wwin);
 
515
        }
 
516
        /* deiconify window */
 
517
        if (wwin->flags.miniaturized) {
 
518
            wDeiconifyWindow(wwin);
 
519
        } else if (wwin->flags.hidden) {
 
520
            WApplication *wapp = wApplicationOf(wwin->main_window);
 
521
            /* go to the last workspace that the user worked on the app */
 
522
            if (wapp) {
 
523
                wWorkspaceChange(wwin->screen_ptr, wapp->last_workspace);
 
524
            }
 
525
            wUnhideApplication(wapp, False, False);
 
526
        }
 
527
        return;
 
528
    }
 
529
 
 
530
    scr = wScreenForRootWindow(ev->xmaprequest.parent);
 
531
 
 
532
    wwin = wManageWindow(scr, window);
 
533
 
 
534
    /*
 
535
     * This is to let the Dock know that the application it launched
 
536
     * has already been mapped (eg: it has finished launching).
 
537
     * It is not necessary for normally docked apps, but is needed for
 
538
     * apps that were forcedly docked (like with dockit).
 
539
     */
 
540
    if (scr->last_dock) {
 
541
        if (wwin && wwin->main_window!=None && wwin->main_window!=window)
 
542
            wDockTrackWindowLaunch(scr->last_dock, wwin->main_window);
 
543
        else
 
544
            wDockTrackWindowLaunch(scr->last_dock, window);
 
545
    }
 
546
 
 
547
    if (wwin) {
 
548
        wClientSetState(wwin, NormalState, None);
 
549
        if (wwin->flags.maximized) {
 
550
            wMaximizeWindow(wwin, wwin->flags.maximized);
 
551
        }
 
552
        if (wwin->flags.shaded) {
 
553
            wwin->flags.shaded = 0;
 
554
            wwin->flags.skip_next_animation = 1;
 
555
            wShadeWindow(wwin);
 
556
        }
 
557
        if (wwin->flags.miniaturized) {
 
558
            wwin->flags.miniaturized = 0;
 
559
            wwin->flags.skip_next_animation = 1;
 
560
            wIconifyWindow(wwin);
 
561
        }
 
562
        if (wwin->flags.hidden) {
 
563
            WApplication *wapp = wApplicationOf(wwin->main_window);
 
564
 
 
565
            wwin->flags.hidden = 0;
 
566
            wwin->flags.skip_next_animation = 1;
 
567
            if (wapp) {
 
568
                wHideApplication(wapp);
 
569
            }
 
570
        }
 
571
    }
 
572
}
 
573
 
 
574
 
 
575
static void
 
576
handleDestroyNotify(XEvent *event)
 
577
{
 
578
    WWindow *wwin;
 
579
    WApplication *app;
 
580
    Window window = event->xdestroywindow.window;
 
581
    WScreen *scr = wScreenForRootWindow(event->xdestroywindow.event);
 
582
    int index;
 
583
 
 
584
#ifdef DEBUG
 
585
    printf("got destroy notify\n");
 
586
#endif
 
587
    wwin = wWindowFor(window);
 
588
    if (wwin) {
 
589
        wUnmanageWindow(wwin, False, True);
 
590
    }
 
591
 
 
592
    if (scr != NULL) {
 
593
        while ((index = WMFindInArray(scr->fakeGroupLeaders, matchWindow,
 
594
                                      (void*)window)) != WANotFound) {
 
595
            WFakeGroupLeader *fPtr;
 
596
 
 
597
            fPtr = WMGetFromArray(scr->fakeGroupLeaders, index);
 
598
            if (fPtr->retainCount > 0) {
 
599
                fPtr->retainCount--;
 
600
                if (fPtr->retainCount==0 && fPtr->leader!=None) {
 
601
                    XDestroyWindow(dpy, fPtr->leader);
 
602
                    fPtr->leader = None;
 
603
                    XFlush(dpy);
 
604
                }
 
605
            }
 
606
            fPtr->origLeader = None;
 
607
        }
 
608
    }
 
609
 
 
610
    app = wApplicationOf(window);
 
611
    if (app) {
 
612
        if (window == app->main_window) {
 
613
            app->refcount = 0;
 
614
            wwin = app->main_window_desc->screen_ptr->focused_window;
 
615
            while (wwin) {
 
616
                if (wwin->main_window == window) {
 
617
                    wwin->main_window = None;
 
618
                }
 
619
                wwin = wwin->prev;
 
620
            }
 
621
        }
 
622
        wApplicationDestroy(app);
 
623
    }
 
624
}
 
625
 
 
626
 
 
627
 
 
628
static void
 
629
handleExpose(XEvent *event)
 
630
{
 
631
    WObjDescriptor *desc;
 
632
    XEvent ev;
 
633
 
 
634
#ifdef DEBUG
 
635
    printf("got expose\n");
 
636
#endif
 
637
    while (XCheckTypedWindowEvent(dpy, event->xexpose.window, Expose, &ev));
 
638
 
 
639
    if (XFindContext(dpy, event->xexpose.window, wWinContext,
 
640
                     (XPointer *)&desc)==XCNOENT) {
 
641
        return;
 
642
    }
 
643
 
 
644
    if (desc->handle_expose) {
 
645
        (*desc->handle_expose)(desc, event);
 
646
    }
 
647
}
 
648
 
 
649
static void
 
650
executeButtonAction(WScreen *scr, XEvent *event, int action)
 
651
{
 
652
    switch(action) {
 
653
    case WA_SELECT_WINDOWS:
 
654
        wUnselectWindows(scr);
 
655
        wSelectWindows(scr, event);
 
656
        break;
 
657
    case WA_OPEN_APPMENU:
 
658
        OpenRootMenu(scr, event->xbutton.x_root, event->xbutton.y_root, False);
 
659
        /* ugly hack */
 
660
        if (scr->root_menu) {
 
661
            if (scr->root_menu->brother->flags.mapped)
 
662
                event->xbutton.window = scr->root_menu->brother->frame->core->window;
 
663
            else
 
664
                event->xbutton.window = scr->root_menu->frame->core->window;
 
665
        }
 
666
        break;
 
667
    case WA_OPEN_WINLISTMENU:
 
668
        OpenSwitchMenu(scr, event->xbutton.x_root, event->xbutton.y_root, False);
 
669
        if (scr->switch_menu) {
 
670
            if (scr->switch_menu->brother->flags.mapped)
 
671
                event->xbutton.window = scr->switch_menu->brother->frame->core->window;
 
672
            else
 
673
                event->xbutton.window = scr->switch_menu->frame->core->window;
 
674
        }
 
675
        break;
 
676
    default:
 
677
        break;
 
678
    }
 
679
}
 
680
 
 
681
 
 
682
/* bindable */
 
683
static void
 
684
handleButtonPress(XEvent *event)
 
685
{
 
686
    WObjDescriptor *desc;
 
687
    WScreen *scr;
 
688
 
 
689
#ifdef DEBUG
 
690
    printf("got button press\n");
 
691
#endif
 
692
    scr = wScreenForRootWindow(event->xbutton.root);
 
693
 
 
694
#ifdef BALLOON_TEXT
 
695
    wBalloonHide(scr);
 
696
#endif
 
697
 
 
698
 
 
699
#ifndef LITE
 
700
    if (event->xbutton.window==scr->root_win) {
 
701
        if (event->xbutton.button==Button1 &&
 
702
            wPreferences.mouse_button1!=WA_NONE) {
 
703
            executeButtonAction(scr, event, wPreferences.mouse_button1);
 
704
        } else if (event->xbutton.button==Button2 &&
 
705
                   wPreferences.mouse_button2!=WA_NONE) {
 
706
            executeButtonAction(scr, event, wPreferences.mouse_button2);
 
707
        } else if (event->xbutton.button==Button3 &&
 
708
                   wPreferences.mouse_button3!=WA_NONE) {
 
709
            executeButtonAction(scr, event, wPreferences.mouse_button3);
 
710
        } else if (event->xbutton.button==Button4 &&
 
711
                   wPreferences.mouse_wheel!=WA_NONE) {
 
712
            wWorkspaceRelativeChange(scr, 1);
 
713
        } else if (event->xbutton.button==Button5 &&
 
714
                   wPreferences.mouse_wheel!=WA_NONE) {
 
715
            wWorkspaceRelativeChange(scr, -1);
 
716
        }
 
717
    }
 
718
#endif /* !LITE */
 
719
 
 
720
    desc = NULL;
 
721
    if (XFindContext(dpy, event->xbutton.subwindow, wWinContext,
 
722
                     (XPointer *)&desc)==XCNOENT) {
 
723
        if (XFindContext(dpy, event->xbutton.window, wWinContext,
 
724
                         (XPointer *)&desc)==XCNOENT) {
 
725
            return;
 
726
        }
 
727
    }
 
728
 
 
729
    if (desc->parent_type == WCLASS_WINDOW) {
 
730
        XSync(dpy, 0);
 
731
 
 
732
        if (event->xbutton.state & MOD_MASK) {
 
733
            XAllowEvents(dpy, AsyncPointer, CurrentTime);
 
734
        }
 
735
 
 
736
        /*      if (wPreferences.focus_mode == WKF_CLICK) {*/
 
737
        if (wPreferences.ignore_focus_click) {
 
738
            XAllowEvents(dpy, AsyncPointer, CurrentTime);
 
739
        }
 
740
        XAllowEvents(dpy, ReplayPointer, CurrentTime);
 
741
        /*      }*/
 
742
        XSync(dpy, 0);
 
743
    } else if (desc->parent_type == WCLASS_APPICON
 
744
               || desc->parent_type == WCLASS_MINIWINDOW
 
745
               || desc->parent_type == WCLASS_DOCK_ICON) {
 
746
        if (event->xbutton.state & MOD_MASK) {
 
747
            XSync(dpy, 0);
 
748
            XAllowEvents(dpy, AsyncPointer, CurrentTime);
 
749
            XSync(dpy, 0);
 
750
        }
 
751
    }
 
752
 
 
753
    if (desc->handle_mousedown!=NULL) {
 
754
        (*desc->handle_mousedown)(desc, event);
 
755
    }
 
756
 
 
757
    /* save double-click information */
 
758
    if (scr->flags.next_click_is_not_double) {
 
759
        scr->flags.next_click_is_not_double = 0;
 
760
    } else {
 
761
        scr->last_click_time = event->xbutton.time;
 
762
        scr->last_click_button = event->xbutton.button;
 
763
        scr->last_click_window = event->xbutton.window;
 
764
    }
 
765
}
 
766
 
 
767
 
 
768
static void
 
769
handleMapNotify(XEvent *event)
 
770
{
 
771
    WWindow *wwin;
 
772
#ifdef DEBUG
 
773
    printf("got map\n");
 
774
#endif
 
775
    wwin = wWindowFor(event->xmap.event);
 
776
    if (wwin && wwin->client_win == event->xmap.event) {
 
777
        if (wwin->flags.miniaturized) {
 
778
            wDeiconifyWindow(wwin);
 
779
        } else {
 
780
            XGrabServer(dpy);
 
781
            wWindowMap(wwin);
 
782
            wClientSetState(wwin, NormalState, None);
 
783
            XUngrabServer(dpy);
 
784
        }
 
785
    }
 
786
}
 
787
 
 
788
 
 
789
static void
 
790
handleUnmapNotify(XEvent *event)
 
791
{
 
792
    WWindow *wwin;
 
793
    XEvent ev;
 
794
    Bool withdraw = False;
 
795
#ifdef DEBUG
 
796
    printf("got unmap\n");
 
797
#endif
 
798
    /* only process windows with StructureNotify selected
 
799
     * (ignore SubstructureNotify) */
 
800
    wwin = wWindowFor(event->xunmap.window);
 
801
    if (!wwin)
 
802
        return;
 
803
 
 
804
    /* whether the event is a Withdrawal request */
 
805
    if (event->xunmap.event == wwin->screen_ptr->root_win
 
806
        && event->xunmap.send_event)
 
807
        withdraw = True;
 
808
 
 
809
    if (wwin->client_win != event->xunmap.event && !withdraw)
 
810
        return;
 
811
 
 
812
    if (!wwin->flags.mapped && !withdraw
 
813
        && wwin->frame->workspace == wwin->screen_ptr->current_workspace
 
814
        && !wwin->flags.miniaturized && !wwin->flags.hidden)
 
815
        return;
 
816
 
 
817
    XGrabServer(dpy);
 
818
    XUnmapWindow(dpy, wwin->frame->core->window);
 
819
    wwin->flags.mapped = 0;
 
820
    XSync(dpy, 0);
 
821
    /* check if the window was destroyed */
 
822
    if (XCheckTypedWindowEvent(dpy, wwin->client_win, DestroyNotify,&ev)) {
 
823
        DispatchEvent(&ev);
 
824
    } else {
 
825
        Bool reparented = False;
 
826
 
 
827
        if (XCheckTypedWindowEvent(dpy, wwin->client_win, ReparentNotify, &ev))
 
828
            reparented = True;
 
829
 
 
830
        /* withdraw window */
 
831
        wwin->flags.mapped = 0;
 
832
        if (!reparented)
 
833
            wClientSetState(wwin, WithdrawnState, None);
 
834
 
 
835
        /* if the window was reparented, do not reparent it back to the
 
836
         * root window */
 
837
        wUnmanageWindow(wwin, !reparented, False);
 
838
    }
 
839
    XUngrabServer(dpy);
 
840
}
 
841
 
 
842
 
 
843
static void
 
844
handleConfigureRequest(XEvent *event)
 
845
{
 
846
    WWindow *wwin;
 
847
#ifdef DEBUG
 
848
    printf("got configure request\n");
 
849
#endif
 
850
    if (!(wwin=wWindowFor(event->xconfigurerequest.window))) {
 
851
        /*
 
852
         * Configure request for unmapped window
 
853
         */
 
854
        wClientConfigure(NULL, &(event->xconfigurerequest));
 
855
    } else {
 
856
        wClientConfigure(wwin, &(event->xconfigurerequest));
 
857
    }
 
858
}
 
859
 
 
860
 
 
861
static void
 
862
handlePropertyNotify(XEvent *event)
 
863
{
 
864
    WWindow *wwin;
 
865
    WApplication *wapp;
 
866
    Window jr;
 
867
    int ji;
 
868
    unsigned int ju;
 
869
    WScreen *scr;
 
870
#ifdef DEBUG
 
871
    printf("got property notify\n");
 
872
#endif
 
873
    if ((wwin=wWindowFor(event->xproperty.window))) {
 
874
        if (!XGetGeometry(dpy, wwin->client_win, &jr, &ji, &ji,
 
875
                          &ju, &ju, &ju, &ju)) {
 
876
            return;
 
877
        }
 
878
        wClientCheckProperty(wwin, &event->xproperty);
 
879
    }
 
880
    wapp = wApplicationOf(event->xproperty.window);
 
881
    if (wapp) {
 
882
        wClientCheckProperty(wapp->main_window_desc, &event->xproperty);
 
883
    }
 
884
 
 
885
    scr = wScreenForWindow(event->xproperty.window);
 
886
}
 
887
 
 
888
 
 
889
static void
 
890
handleClientMessage(XEvent *event)
 
891
{
 
892
    WWindow *wwin;
 
893
    WObjDescriptor *desc;
 
894
#ifdef DEBUG
 
895
    printf("got client message\n");
 
896
#endif
 
897
    /* handle transition from Normal to Iconic state */
 
898
    if (event->xclient.message_type == _XA_WM_CHANGE_STATE
 
899
        && event->xclient.format == 32
 
900
        && event->xclient.data.l[0] == IconicState) {
 
901
 
 
902
        wwin = wWindowFor(event->xclient.window);
 
903
        if (!wwin) return;
 
904
        if (!wwin->flags.miniaturized)
 
905
            wIconifyWindow(wwin);
 
906
    } else if (event->xclient.message_type == _XA_WM_COLORMAP_NOTIFY
 
907
               && event->xclient.format == 32) {
 
908
        WScreen *scr = wScreenSearchForRootWindow(event->xclient.window);
 
909
 
 
910
        if (!scr)
 
911
            return;
 
912
 
 
913
        if (event->xclient.data.l[1] == 1) {   /* starting */
 
914
            wColormapAllowClientInstallation(scr, True);
 
915
        } else {                       /* stopping */
 
916
            wColormapAllowClientInstallation(scr, False);
 
917
        }
 
918
    } else if (event->xclient.message_type == _XA_WINDOWMAKER_COMMAND) {
 
919
 
 
920
        wDefaultsCheckDomains("bla");
 
921
 
 
922
    } else if (event->xclient.message_type == _XA_WINDOWMAKER_WM_FUNCTION) {
 
923
        WApplication *wapp;
 
924
        int done=0;
 
925
        wapp = wApplicationOf(event->xclient.window);
 
926
        if (wapp) {
 
927
            switch (event->xclient.data.l[0]) {
 
928
            case WMFHideOtherApplications:
 
929
                wHideOtherApplications(wapp->main_window_desc);
 
930
                done = 1;
 
931
                break;
 
932
 
 
933
            case WMFHideApplication:
 
934
                wHideApplication(wapp);
 
935
                done = 1;
 
936
                break;
 
937
            }
 
938
        }
 
939
        if (!done) {
 
940
            wwin = wWindowFor(event->xclient.window);
 
941
            if (wwin) {
 
942
                switch (event->xclient.data.l[0]) {
 
943
                case WMFHideOtherApplications:
 
944
                    wHideOtherApplications(wwin);
 
945
                    break;
 
946
 
 
947
                case WMFHideApplication:
 
948
                    wHideApplication(wApplicationOf(wwin->main_window));
 
949
                    break;
 
950
                }
 
951
            }
 
952
        }
 
953
    } else if (event->xclient.message_type == _XA_GNUSTEP_WM_ATTR) {
 
954
        wwin = wWindowFor(event->xclient.window);
 
955
        if (!wwin) return;
 
956
        switch (event->xclient.data.l[0]) {
 
957
        case GSWindowLevelAttr:
 
958
            {
 
959
                int level = (int)event->xclient.data.l[1];
 
960
 
 
961
                if (WINDOW_LEVEL(wwin) != level) {
 
962
                    ChangeStackingLevel(wwin->frame->core, level);
 
963
                }
 
964
            }
 
965
            break;
 
966
        }
 
967
    } else if (event->xclient.message_type == _XA_GNUSTEP_TITLEBAR_STATE) {
 
968
        wwin = wWindowFor(event->xclient.window);
 
969
        if (!wwin) return;
 
970
        switch (event->xclient.data.l[0]) {
 
971
        case WMTitleBarNormal:
 
972
            wFrameWindowChangeState(wwin->frame, WS_UNFOCUSED);
 
973
            break;
 
974
        case WMTitleBarMain:
 
975
            wFrameWindowChangeState(wwin->frame, WS_PFOCUSED);
 
976
            break;
 
977
        case WMTitleBarKey:
 
978
            wFrameWindowChangeState(wwin->frame, WS_FOCUSED);
 
979
            break;
 
980
        }
 
981
#ifdef NETWM_HINTS
 
982
    } else if (wNETWMProcessClientMessage(&event->xclient)) {
 
983
        /* do nothing */
 
984
#endif
 
985
#ifdef XDND
 
986
    } else if (wXDNDProcessClientMessage(&event->xclient)) {
 
987
        /* do nothing */
 
988
#endif /* XDND */
 
989
    } else {
 
990
        /*
 
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.
 
994
         */
 
995
        if (XFindContext(dpy, event->xbutton.window, wWinContext,
 
996
                         (XPointer *)&desc)!=XCNOENT) {
 
997
            struct WIcon *icon=NULL;
 
998
 
 
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;
 
1004
            }
 
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);
 
1010
                }
 
1011
            }
 
1012
        }
 
1013
    }
 
1014
}
 
1015
 
 
1016
 
 
1017
static void
 
1018
raiseWindow(WScreen *scr)
 
1019
{
 
1020
    WWindow *wwin;
 
1021
 
 
1022
    scr->autoRaiseTimer = NULL;
 
1023
 
 
1024
    wwin = wWindowFor(scr->autoRaiseWindow);
 
1025
    if (!wwin)
 
1026
        return;
 
1027
 
 
1028
    if (!wwin->flags.destroyed && wwin->flags.focused) {
 
1029
        wRaiseFrame(wwin->frame->core);
 
1030
        /* this is needed or a race condition will occur */
 
1031
        XSync(dpy, False);
 
1032
    }
 
1033
}
 
1034
 
 
1035
 
 
1036
static void
 
1037
handleEnterNotify(XEvent *event)
 
1038
{
 
1039
    WWindow *wwin;
 
1040
    WObjDescriptor *desc = NULL;
 
1041
#ifdef VIRTUAL_DESKTOP
 
1042
    void (*vdHandler)(XEvent * event);
 
1043
#endif
 
1044
    XEvent ev;
 
1045
    WScreen *scr = wScreenForRootWindow(event->xcrossing.root);
 
1046
#ifdef DEBUG
 
1047
    printf("got enter notify\n");
 
1048
#endif
 
1049
 
 
1050
#ifdef VIRTUAL_DESKTOP
 
1051
    if (XFindContext(dpy, event->xcrossing.window, wVEdgeContext,
 
1052
                     (XPointer *)&vdHandler)!=XCNOENT) {
 
1053
        (*vdHandler)(event);
 
1054
    }
 
1055
#endif
 
1056
 
 
1057
    if (XCheckTypedWindowEvent(dpy, event->xcrossing.window, LeaveNotify,
 
1058
                               &ev)) {
 
1059
        /* already left the window... */
 
1060
        saveTimestamp(&ev);
 
1061
        if (ev.xcrossing.mode==event->xcrossing.mode
 
1062
            && ev.xcrossing.detail==event->xcrossing.detail) {
 
1063
            return;
 
1064
        }
 
1065
    }
 
1066
 
 
1067
    if (XFindContext(dpy, event->xcrossing.window, wWinContext,
 
1068
                     (XPointer *)&desc)!=XCNOENT) {
 
1069
        if(desc->handle_enternotify)
 
1070
            (*desc->handle_enternotify)(desc, event);
 
1071
    }
 
1072
 
 
1073
    /* enter to window */
 
1074
    wwin = wWindowFor(event->xcrossing.window);
 
1075
    if (!wwin) {
 
1076
        if (wPreferences.colormap_mode==WCM_POINTER) {
 
1077
            wColormapInstallForWindow(scr, NULL);
 
1078
        }
 
1079
        if (scr->autoRaiseTimer
 
1080
            && event->xcrossing.root==event->xcrossing.window) {
 
1081
            WMDeleteTimerHandler(scr->autoRaiseTimer);
 
1082
            scr->autoRaiseTimer = NULL;
 
1083
        }
 
1084
    } else {
 
1085
        /* set auto raise timer even if in focus-follows-mouse mode
 
1086
         * and the event is for the frame window, even if the window
 
1087
         * has focus already.  useful if you move the pointer from a focused
 
1088
         * window to the root window and back pretty fast
 
1089
         *
 
1090
         * set focus if in focus-follows-mouse mode and the event
 
1091
         * is for the frame window and window doesn't have focus yet */
 
1092
        if (wPreferences.focus_mode==WKF_SLOPPY
 
1093
            && wwin->frame->core->window==event->xcrossing.window
 
1094
            && !scr->flags.doing_alt_tab) {
 
1095
 
 
1096
            if (!wwin->flags.focused && !WFLAGP(wwin, no_focusable))
 
1097
                wSetFocusTo(scr, wwin);
 
1098
 
 
1099
            if (scr->autoRaiseTimer)
 
1100
                WMDeleteTimerHandler(scr->autoRaiseTimer);
 
1101
            scr->autoRaiseTimer = NULL;
 
1102
 
 
1103
            if (wPreferences.raise_delay && !WFLAGP(wwin, no_focusable)) {
 
1104
                scr->autoRaiseWindow = wwin->frame->core->window;
 
1105
                scr->autoRaiseTimer
 
1106
                    = WMAddTimerHandler(wPreferences.raise_delay,
 
1107
                                        (WMCallback*)raiseWindow, scr);
 
1108
            }
 
1109
        }
 
1110
        /* Install colormap for window, if the colormap installation mode
 
1111
         * is colormap_follows_mouse */
 
1112
        if (wPreferences.colormap_mode==WCM_POINTER) {
 
1113
            if (wwin->client_win==event->xcrossing.window)
 
1114
                wColormapInstallForWindow(scr, wwin);
 
1115
            else
 
1116
                wColormapInstallForWindow(scr, NULL);
 
1117
        }
 
1118
    }
 
1119
 
 
1120
    /* a little kluge to hide the clip balloon */
 
1121
    if (!wPreferences.flags.noclip && scr->flags.clip_balloon_mapped) {
 
1122
        if (!desc) {
 
1123
            XUnmapWindow(dpy, scr->clip_balloon);
 
1124
            scr->flags.clip_balloon_mapped = 0;
 
1125
        } else {
 
1126
            if (desc->parent_type!=WCLASS_DOCK_ICON
 
1127
                || scr->clip_icon != desc->parent) {
 
1128
                XUnmapWindow(dpy, scr->clip_balloon);
 
1129
                scr->flags.clip_balloon_mapped = 0;
 
1130
            }
 
1131
        }
 
1132
    }
 
1133
 
 
1134
    if (event->xcrossing.window == event->xcrossing.root
 
1135
        && event->xcrossing.detail == NotifyNormal
 
1136
        && event->xcrossing.detail != NotifyInferior
 
1137
        && wPreferences.focus_mode != WKF_CLICK) {
 
1138
 
 
1139
        wSetFocusTo(scr, scr->focused_window);
 
1140
    }
 
1141
 
 
1142
#ifdef BALLOON_TEXT
 
1143
    wBalloonEnteredObject(scr, desc);
 
1144
#endif
 
1145
}
 
1146
 
 
1147
 
 
1148
static void
 
1149
handleLeaveNotify(XEvent *event)
 
1150
{
 
1151
    WObjDescriptor *desc = NULL;
 
1152
 
 
1153
    if (XFindContext(dpy, event->xcrossing.window, wWinContext,
 
1154
                     (XPointer *)&desc)!=XCNOENT) {
 
1155
        if(desc->handle_leavenotify)
 
1156
            (*desc->handle_leavenotify)(desc, event);
 
1157
    }
 
1158
}
 
1159
 
 
1160
 
 
1161
#ifdef SHAPE
 
1162
static void
 
1163
handleShapeNotify(XEvent *event)
 
1164
{
 
1165
    XShapeEvent *shev = (XShapeEvent*)event;
 
1166
    WWindow *wwin;
 
1167
    XEvent ev;
 
1168
#ifdef DEBUG
 
1169
    printf("got shape notify\n");
 
1170
#endif
 
1171
    while (XCheckTypedWindowEvent(dpy, shev->window, event->type, &ev)) {
 
1172
        XShapeEvent *sev = (XShapeEvent*)&ev;
 
1173
 
 
1174
        if (sev->kind == ShapeBounding) {
 
1175
            if (sev->shaped == shev->shaped) {
 
1176
                *shev = *sev;
 
1177
            } else {
 
1178
                XPutBackEvent(dpy, &ev);
 
1179
                break;
 
1180
            }
 
1181
        }
 
1182
    }
 
1183
 
 
1184
    wwin = wWindowFor(shev->window);
 
1185
    if (!wwin || shev->kind != ShapeBounding)
 
1186
        return;
 
1187
 
 
1188
    if (!shev->shaped && wwin->flags.shaped) {
 
1189
 
 
1190
        wwin->flags.shaped = 0;
 
1191
        wWindowClearShape(wwin);
 
1192
 
 
1193
    } else if (shev->shaped) {
 
1194
 
 
1195
        wwin->flags.shaped = 1;
 
1196
        wWindowSetShape(wwin);
 
1197
    }
 
1198
}
 
1199
#endif /* SHAPE */
 
1200
 
 
1201
#ifdef KEEP_XKB_LOCK_STATUS
 
1202
/* please help ]d if you know what to do */
 
1203
handleXkbIndicatorStateNotify(XEvent *event)
 
1204
{
 
1205
    WWindow *wwin;
 
1206
    WScreen *scr;
 
1207
    XkbStateRec staterec;
 
1208
    int i;
 
1209
 
 
1210
    for (i=0; i<wScreenCount; i++) {
 
1211
        scr = wScreenWithNumber(i);
 
1212
        wwin = scr->focused_window;
 
1213
        if (wwin && wwin->flags.focused) {
 
1214
            XkbGetState(dpy,XkbUseCoreKbd,&staterec);
 
1215
            if (wwin->frame->languagemode != staterec.group) {
 
1216
                wwin->frame->last_languagemode = wwin->frame->languagemode;
 
1217
                wwin->frame->languagemode = staterec.group;
 
1218
            }
 
1219
#ifdef XKB_BUTTON_HINT
 
1220
            if (wwin->frame->titlebar) {
 
1221
                wFrameWindowPaint(wwin->frame);
 
1222
            }
 
1223
#endif
 
1224
        }
 
1225
    }
 
1226
}
 
1227
#endif /*KEEP_XKB_LOCK_STATUS*/
 
1228
 
 
1229
static void
 
1230
handleColormapNotify(XEvent *event)
 
1231
{
 
1232
    WWindow *wwin;
 
1233
    WScreen *scr;
 
1234
    Bool reinstall = False;
 
1235
 
 
1236
    wwin = wWindowFor(event->xcolormap.window);
 
1237
    if (!wwin)
 
1238
        return;
 
1239
 
 
1240
    scr = wwin->screen_ptr;
 
1241
 
 
1242
    do {
 
1243
        if (wwin) {
 
1244
            if (event->xcolormap.new) {
 
1245
                XWindowAttributes attr;
 
1246
 
 
1247
                XGetWindowAttributes(dpy, wwin->client_win, &attr);
 
1248
 
 
1249
                if (wwin == scr->cmap_window && wwin->cmap_window_no == 0)
 
1250
                    scr->current_colormap = attr.colormap;
 
1251
 
 
1252
                reinstall = True;
 
1253
            } else if (event->xcolormap.state == ColormapUninstalled &&
 
1254
                       scr->current_colormap == event->xcolormap.colormap) {
 
1255
 
 
1256
                /* some bastard app (like XV) removed our colormap */
 
1257
                /*
 
1258
                 * can't enforce or things like xscreensaver wont work
 
1259
                 * reinstall = True;
 
1260
                 */
 
1261
            } else if (event->xcolormap.state == ColormapInstalled &&
 
1262
                       scr->current_colormap == event->xcolormap.colormap) {
 
1263
 
 
1264
                /* someone has put our colormap back */
 
1265
                reinstall = False;
 
1266
            }
 
1267
        }
 
1268
    } while (XCheckTypedEvent(dpy, ColormapNotify, event)
 
1269
             && ((wwin = wWindowFor(event->xcolormap.window)) || 1));
 
1270
 
 
1271
    if (reinstall && scr->current_colormap!=None) {
 
1272
        if (!scr->flags.colormap_stuff_blocked)
 
1273
            XInstallColormap(dpy, scr->current_colormap);
 
1274
    }
 
1275
}
 
1276
 
 
1277
 
 
1278
 
 
1279
static void
 
1280
handleFocusIn(XEvent *event)
 
1281
{
 
1282
    WWindow *wwin;
 
1283
 
 
1284
    /*
 
1285
     * For applications that like stealing the focus.
 
1286
     */
 
1287
    while (XCheckTypedEvent(dpy, FocusIn, event));
 
1288
    saveTimestamp(event);
 
1289
    if (event->xfocus.mode == NotifyUngrab
 
1290
        || event->xfocus.mode == NotifyGrab
 
1291
        || event->xfocus.detail > NotifyNonlinearVirtual) {
 
1292
        return;
 
1293
    }
 
1294
 
 
1295
    wwin = wWindowFor(event->xfocus.window);
 
1296
    if (wwin && !wwin->flags.focused) {
 
1297
        if (wwin->flags.mapped)
 
1298
            wSetFocusTo(wwin->screen_ptr, wwin);
 
1299
        else
 
1300
            wSetFocusTo(wwin->screen_ptr, NULL);
 
1301
    } else if (!wwin) {
 
1302
        WScreen *scr = wScreenForWindow(event->xfocus.window);
 
1303
        if (scr)
 
1304
            wSetFocusTo(scr, NULL);
 
1305
    }
 
1306
}
 
1307
 
 
1308
 
 
1309
static WWindow*
 
1310
windowUnderPointer(WScreen *scr)
 
1311
{
 
1312
    unsigned int mask;
 
1313
    int foo;
 
1314
    Window bar, win;
 
1315
 
 
1316
    if (XQueryPointer(dpy, scr->root_win, &bar, &win, &foo, &foo, &foo, &foo,
 
1317
                      &mask))
 
1318
        return wWindowFor(win);
 
1319
    return NULL;
 
1320
}
 
1321
 
 
1322
 
 
1323
static int CheckFullScreenWindowFocused(WScreen *scr)
 
1324
{
 
1325
  if (scr->focused_window && scr->focused_window->flags.fullscreen)
 
1326
      return 1;
 
1327
  else
 
1328
      return 0;
 
1329
}
 
1330
 
 
1331
 
 
1332
static void
 
1333
handleKeyPress(XEvent *event)
 
1334
{
 
1335
    WScreen *scr = wScreenForRootWindow(event->xkey.root);
 
1336
    WWindow *wwin = scr->focused_window;
 
1337
    int i;
 
1338
    int modifiers;
 
1339
    int command=-1, index;
 
1340
#ifdef KEEP_XKB_LOCK_STATUS
 
1341
    XkbStateRec staterec;
 
1342
#endif /*KEEP_XKB_LOCK_STATUS*/
 
1343
 
 
1344
    /* ignore CapsLock */
 
1345
    modifiers = event->xkey.state & ValidModMask;
 
1346
 
 
1347
    for (i=0; i<WKBD_LAST; i++) {
 
1348
        if (wKeyBindings[i].keycode==0)
 
1349
            continue;
 
1350
 
 
1351
        if (wKeyBindings[i].keycode==event->xkey.keycode
 
1352
            && (/*wKeyBindings[i].modifier==0
 
1353
            ||*/ wKeyBindings[i].modifier==modifiers)) {
 
1354
            command = i;
 
1355
            break;
 
1356
        }
 
1357
    }
 
1358
 
 
1359
 
 
1360
    if (command < 0) {
 
1361
#ifdef LITE
 
1362
        {
 
1363
#if 0
 
1364
        }
 
1365
#endif
 
1366
#else
 
1367
        if (!wRootMenuPerformShortcut(event)) {
 
1368
#endif
 
1369
            static int dontLoop = 0;
 
1370
 
 
1371
            if (dontLoop > 10) {
 
1372
                wwarning("problem with key event processing code");
 
1373
                return;
 
1374
            }
 
1375
            dontLoop++;
 
1376
            /* if the focused window is an internal window, try redispatching
 
1377
             * the event to the managed window, as it can be a WINGs window */
 
1378
            if (wwin && wwin->flags.internal_window
 
1379
                && wwin->client_leader!=None) {
 
1380
                /* client_leader contains the WINGs toplevel */
 
1381
                event->xany.window = wwin->client_leader;
 
1382
                WMHandleEvent(event);
 
1383
            }
 
1384
            dontLoop--;
 
1385
        }
 
1386
        return;
 
1387
    }
 
1388
 
 
1389
#define ISMAPPED(w) ((w) && !(w)->flags.miniaturized && ((w)->flags.mapped || (w)->flags.shaded))
 
1390
#define ISFOCUSED(w) ((w) && (w)->flags.focused)
 
1391
 
 
1392
    switch (command) {
 
1393
#ifndef LITE
 
1394
    case WKBD_ROOTMENU:
 
1395
        /*OpenRootMenu(scr, event->xkey.x_root, event->xkey.y_root, True);*/
 
1396
        if (!CheckFullScreenWindowFocused(scr)) {
 
1397
            WMRect rect = wGetRectForHead(scr, wGetHeadForPointerLocation(scr));
 
1398
            OpenRootMenu(scr, rect.pos.x + rect.size.width/2, rect.pos.y + rect.size.height/2, True);
 
1399
        }
 
1400
        break;
 
1401
    case WKBD_WINDOWLIST:
 
1402
        if (!CheckFullScreenWindowFocused(scr)) {
 
1403
            WMRect rect = wGetRectForHead(scr, wGetHeadForPointerLocation(scr));
 
1404
            OpenSwitchMenu(scr, rect.pos.x + rect.size.width/2, rect.pos.y + rect.size.height/2, True);
 
1405
        }
 
1406
        break;
 
1407
#endif /* !LITE */
 
1408
    case WKBD_WINDOWMENU:
 
1409
        if (ISMAPPED(wwin) && ISFOCUSED(wwin))
 
1410
            OpenWindowMenu(wwin, wwin->frame_x,
 
1411
                           wwin->frame_y+wwin->frame->top_width, True);
 
1412
        break;
 
1413
    case WKBD_MINIATURIZE:
 
1414
        if (ISMAPPED(wwin) && ISFOCUSED(wwin)
 
1415
            && !WFLAGP(wwin, no_miniaturizable)) {
 
1416
            CloseWindowMenu(scr);
 
1417
 
 
1418
            if (wwin->protocols.MINIATURIZE_WINDOW)
 
1419
                wClientSendProtocol(wwin, _XA_GNUSTEP_WM_MINIATURIZE_WINDOW,
 
1420
                                    event->xbutton.time);
 
1421
            else {
 
1422
                wIconifyWindow(wwin);
 
1423
            }
 
1424
        }
 
1425
        break;
 
1426
    case WKBD_HIDE:
 
1427
        if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
 
1428
            WApplication *wapp = wApplicationOf(wwin->main_window);
 
1429
            CloseWindowMenu(scr);
 
1430
 
 
1431
            if (wapp && !WFLAGP(wapp->main_window_desc, no_appicon)) {
 
1432
                wHideApplication(wapp);
 
1433
            }
 
1434
        }
 
1435
        break;
 
1436
    case WKBD_HIDE_OTHERS:
 
1437
        if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
 
1438
            CloseWindowMenu(scr);
 
1439
 
 
1440
            wHideOtherApplications(wwin);
 
1441
        }
 
1442
        break;
 
1443
    case WKBD_MAXIMIZE:
 
1444
        if (ISMAPPED(wwin) && ISFOCUSED(wwin) && IS_RESIZABLE(wwin)) {
 
1445
            int newdir = (MAX_VERTICAL|MAX_HORIZONTAL);
 
1446
 
 
1447
            CloseWindowMenu(scr);
 
1448
 
 
1449
            if (wwin->flags.maximized == newdir) {
 
1450
                wUnmaximizeWindow(wwin);
 
1451
            } else {
 
1452
                wMaximizeWindow(wwin, newdir|MAX_KEYBOARD);
 
1453
            }
 
1454
        }
 
1455
        break;
 
1456
    case WKBD_VMAXIMIZE:
 
1457
        if (ISMAPPED(wwin) && ISFOCUSED(wwin) && IS_RESIZABLE(wwin)) {
 
1458
            int newdir = (MAX_VERTICAL ^ wwin->flags.maximized);
 
1459
 
 
1460
            CloseWindowMenu(scr);
 
1461
 
 
1462
            if (newdir) {
 
1463
                wMaximizeWindow(wwin, newdir|MAX_KEYBOARD);
 
1464
            } else {
 
1465
                wUnmaximizeWindow(wwin);
 
1466
            }
 
1467
        }
 
1468
        break;
 
1469
    case WKBD_HMAXIMIZE:
 
1470
        if (ISMAPPED(wwin) && ISFOCUSED(wwin) && IS_RESIZABLE(wwin)) {
 
1471
            int newdir = (MAX_HORIZONTAL ^ wwin->flags.maximized);
 
1472
 
 
1473
            CloseWindowMenu(scr);
 
1474
 
 
1475
            if (newdir) {
 
1476
                wMaximizeWindow(wwin, newdir|MAX_KEYBOARD);
 
1477
            } else {
 
1478
                wUnmaximizeWindow(wwin);
 
1479
            }
 
1480
        }
 
1481
        break;
 
1482
    case WKBD_RAISE:
 
1483
        if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
 
1484
            CloseWindowMenu(scr);
 
1485
 
 
1486
            wRaiseFrame(wwin->frame->core);
 
1487
        }
 
1488
        break;
 
1489
    case WKBD_LOWER:
 
1490
        if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
 
1491
            CloseWindowMenu(scr);
 
1492
 
 
1493
            wLowerFrame(wwin->frame->core);
 
1494
        }
 
1495
        break;
 
1496
    case WKBD_RAISELOWER:
 
1497
        /* raise or lower the window under the pointer, not the
 
1498
         * focused one
 
1499
         */
 
1500
        wwin = windowUnderPointer(scr);
 
1501
        if (wwin)
 
1502
            wRaiseLowerFrame(wwin->frame->core);
 
1503
        break;
 
1504
    case WKBD_SHADE:
 
1505
        if (ISMAPPED(wwin) && ISFOCUSED(wwin) && !WFLAGP(wwin, no_shadeable)) {
 
1506
            if (wwin->flags.shaded)
 
1507
                wUnshadeWindow(wwin);
 
1508
            else
 
1509
                wShadeWindow(wwin);
 
1510
        }
 
1511
        break;
 
1512
    case WKBD_MOVERESIZE:
 
1513
        if (ISMAPPED(wwin) && ISFOCUSED(wwin) &&
 
1514
            (IS_RESIZABLE(wwin) || IS_MOVABLE(wwin))) {
 
1515
            CloseWindowMenu(scr);
 
1516
 
 
1517
            wKeyboardMoveResizeWindow(wwin);
 
1518
        }
 
1519
        break;
 
1520
    case WKBD_CLOSE:
 
1521
        if (ISMAPPED(wwin) && ISFOCUSED(wwin) && !WFLAGP(wwin, no_closable)) {
 
1522
            CloseWindowMenu(scr);
 
1523
            if (wwin->protocols.DELETE_WINDOW)
 
1524
                wClientSendProtocol(wwin, _XA_WM_DELETE_WINDOW,
 
1525
                                    event->xkey.time);
 
1526
        }
 
1527
        break;
 
1528
    case WKBD_SELECT:
 
1529
        if (ISMAPPED(wwin) && ISFOCUSED(wwin)) {
 
1530
            wSelectWindow(wwin, !wwin->flags.selected);
 
1531
        }
 
1532
        break;
 
1533
    case WKBD_FOCUSNEXT:
 
1534
        StartWindozeCycle(wwin, event, True);
 
1535
        break;
 
1536
 
 
1537
    case WKBD_FOCUSPREV:
 
1538
        StartWindozeCycle(wwin, event, False);
 
1539
        break;
 
1540
 
 
1541
#if (defined(__STDC__) && !defined(UNIXCPP)) || defined(ANSICPP)
 
1542
#define GOTOWORKS(wk)   case WKBD_WORKSPACE##wk:\
 
1543
    i = (scr->current_workspace/10)*10 + wk - 1;\
 
1544
    if (wPreferences.ws_advance || i<scr->workspace_count)\
 
1545
    wWorkspaceChange(scr, i);\
 
1546
    break
 
1547
#else
 
1548
#define GOTOWORKS(wk)   case WKBD_WORKSPACE/**/wk:\
 
1549
    i = (scr->current_workspace/10)*10 + wk - 1;\
 
1550
    if (wPreferences.ws_advance || i<scr->workspace_count)\
 
1551
    wWorkspaceChange(scr, i);\
 
1552
    break
 
1553
#endif
 
1554
        GOTOWORKS(1);
 
1555
        GOTOWORKS(2);
 
1556
        GOTOWORKS(3);
 
1557
        GOTOWORKS(4);
 
1558
        GOTOWORKS(5);
 
1559
        GOTOWORKS(6);
 
1560
        GOTOWORKS(7);
 
1561
        GOTOWORKS(8);
 
1562
        GOTOWORKS(9);
 
1563
        GOTOWORKS(10);
 
1564
#undef GOTOWORKS
 
1565
    case WKBD_NEXTWORKSPACE:
 
1566
        wWorkspaceRelativeChange(scr, 1);
 
1567
        break;
 
1568
    case WKBD_PREVWORKSPACE:
 
1569
        wWorkspaceRelativeChange(scr, -1);
 
1570
        break;
 
1571
    case WKBD_WINDOW1:
 
1572
    case WKBD_WINDOW2:
 
1573
    case WKBD_WINDOW3:
 
1574
    case WKBD_WINDOW4:
 
1575
    case WKBD_WINDOW5:
 
1576
    case WKBD_WINDOW6:
 
1577
    case WKBD_WINDOW7:
 
1578
    case WKBD_WINDOW8:
 
1579
    case WKBD_WINDOW9:
 
1580
    case WKBD_WINDOW10:
 
1581
 
 
1582
        index = command-WKBD_WINDOW1;
 
1583
 
 
1584
        if (scr->shortcutWindows[index]) {
 
1585
            WMArray *list = scr->shortcutWindows[index];
 
1586
            int cw;
 
1587
            int count = WMGetArrayItemCount(list);
 
1588
            WWindow *twin;
 
1589
            WMArrayIterator iter;
 
1590
            WWindow *wwin;
 
1591
 
 
1592
            wUnselectWindows(scr);
 
1593
            cw = scr->current_workspace;
 
1594
 
 
1595
            WM_ETARETI_ARRAY(list, wwin, iter) {
 
1596
                if (count > 1)
 
1597
                    wWindowChangeWorkspace(wwin, cw);
 
1598
 
 
1599
                wMakeWindowVisible(wwin);
 
1600
 
 
1601
                if (count > 1)
 
1602
                    wSelectWindow(wwin, True);
 
1603
            }
 
1604
 
 
1605
            /* rotate the order of windows, to create a cycling effect */
 
1606
            twin = WMGetFromArray(list, 0);
 
1607
            WMDeleteFromArray(list, 0);
 
1608
            WMAddToArray(list, twin);
 
1609
 
 
1610
        } else if (wwin && ISMAPPED(wwin) && ISFOCUSED(wwin)) {
 
1611
            if (scr->shortcutWindows[index]) {
 
1612
                WMFreeArray(scr->shortcutWindows[index]);
 
1613
                scr->shortcutWindows[index] = NULL;
 
1614
            }
 
1615
 
 
1616
            if (wwin->flags.selected && scr->selected_windows) {
 
1617
                scr->shortcutWindows[index] =
 
1618
                    WMDuplicateArray(scr->selected_windows);
 
1619
                /*WMRemoveFromArray(scr->shortcutWindows[index], wwin);
 
1620
                 WMInsertInArray(scr->shortcutWindows[index], 0, wwin);*/
 
1621
            } else {
 
1622
                scr->shortcutWindows[index] = WMCreateArray(4);
 
1623
                WMAddToArray(scr->shortcutWindows[index], wwin);
 
1624
            }
 
1625
 
 
1626
            wSelectWindow(wwin, !wwin->flags.selected);
 
1627
            XFlush(dpy);
 
1628
            wusleep(3000);
 
1629
            wSelectWindow(wwin, !wwin->flags.selected);
 
1630
            XFlush(dpy);
 
1631
 
 
1632
        } else if (scr->selected_windows
 
1633
                   && WMGetArrayItemCount(scr->selected_windows)) {
 
1634
 
 
1635
            if (wwin->flags.selected && scr->selected_windows) {
 
1636
                if (scr->shortcutWindows[index]) {
 
1637
                    WMFreeArray(scr->shortcutWindows[index]);
 
1638
                }
 
1639
                scr->shortcutWindows[index] =
 
1640
                    WMDuplicateArray(scr->selected_windows);
 
1641
            }
 
1642
        }
 
1643
 
 
1644
        break;
 
1645
 
 
1646
    case WKBD_SWITCH_SCREEN:
 
1647
        if (wScreenCount > 1) {
 
1648
            WScreen *scr2;
 
1649
            int i;
 
1650
 
 
1651
            /* find index of this screen */
 
1652
            for (i = 0; i < wScreenCount; i++) {
 
1653
                if (wScreenWithNumber(i) == scr)
 
1654
                    break;
 
1655
            }
 
1656
            i++;
 
1657
            if (i >= wScreenCount) {
 
1658
                i = 0;
 
1659
            }
 
1660
            scr2 = wScreenWithNumber(i);
 
1661
 
 
1662
            if (scr2) {
 
1663
                XWarpPointer(dpy, scr->root_win, scr2->root_win, 0, 0, 0, 0,
 
1664
                             scr2->scr_width/2, scr2->scr_height/2);
 
1665
            }
 
1666
        }
 
1667
        break;
 
1668
 
 
1669
    case WKBD_NEXTWSLAYER:
 
1670
    case WKBD_PREVWSLAYER:
 
1671
        {
 
1672
            int row, column;
 
1673
 
 
1674
            row = scr->current_workspace/10;
 
1675
            column = scr->current_workspace%10;
 
1676
 
 
1677
            if (command==WKBD_NEXTWSLAYER) {
 
1678
                if ((row+1)*10 < scr->workspace_count)
 
1679
                    wWorkspaceChange(scr, column+(row+1)*10);
 
1680
            } else {
 
1681
                if (row > 0)
 
1682
                    wWorkspaceChange(scr, column+(row-1)*10);
 
1683
            }
 
1684
        }
 
1685
        break;
 
1686
    case WKBD_CLIPLOWER:
 
1687
        if (!wPreferences.flags.noclip)
 
1688
            wDockLower(scr->workspaces[scr->current_workspace]->clip);
 
1689
        break;
 
1690
    case WKBD_CLIPRAISE:
 
1691
        if (!wPreferences.flags.noclip)
 
1692
            wDockRaise(scr->workspaces[scr->current_workspace]->clip);
 
1693
        break;
 
1694
    case WKBD_CLIPRAISELOWER:
 
1695
        if (!wPreferences.flags.noclip)
 
1696
            wDockRaiseLower(scr->workspaces[scr->current_workspace]->clip);
 
1697
        break;
 
1698
#ifdef KEEP_XKB_LOCK_STATUS
 
1699
    case WKBD_TOGGLE:
 
1700
        if(wPreferences.modelock) {
 
1701
            /*toggle*/
 
1702
            wwin = scr->focused_window;
 
1703
 
 
1704
            if (wwin && wwin->flags.mapped
 
1705
                && wwin->frame->workspace == wwin->screen_ptr->current_workspace
 
1706
                && !wwin->flags.miniaturized && !wwin->flags.hidden) {
 
1707
                XkbGetState(dpy,XkbUseCoreKbd,&staterec);
 
1708
 
 
1709
                wwin->frame->languagemode = wwin->frame->last_languagemode;
 
1710
                wwin->frame->last_languagemode = staterec.group;
 
1711
                XkbLockGroup(dpy,XkbUseCoreKbd, wwin->frame->languagemode);
 
1712
 
 
1713
            }
 
1714
        }
 
1715
        break;
 
1716
#endif /* KEEP_XKB_LOCK_STATUS */
 
1717
#ifdef VIRTUAL_DESKTOP
 
1718
    case WKBD_VDESK_LEFT:
 
1719
        wWorkspaceKeyboardMoveDesktop(scr, VEC_LEFT);
 
1720
        break;
 
1721
 
 
1722
    case WKBD_VDESK_RIGHT:
 
1723
        wWorkspaceKeyboardMoveDesktop(scr, VEC_RIGHT);
 
1724
        break;
 
1725
 
 
1726
    case WKBD_VDESK_UP:
 
1727
        wWorkspaceKeyboardMoveDesktop(scr, VEC_UP);
 
1728
        break;
 
1729
 
 
1730
    case WKBD_VDESK_DOWN:
 
1731
        wWorkspaceKeyboardMoveDesktop(scr, VEC_DOWN);
 
1732
        break;
 
1733
#endif
 
1734
 
 
1735
    }
 
1736
}
 
1737
 
 
1738
 
 
1739
static void
 
1740
handleMotionNotify(XEvent *event)
 
1741
{
 
1742
    WScreen *scr = wScreenForRootWindow(event->xmotion.root);
 
1743
 
 
1744
    if (wPreferences.scrollable_menus) {
 
1745
        WMPoint p = wmkpoint(event->xmotion.x_root, event->xmotion.y_root);
 
1746
        WMRect rect = wGetRectForHead(scr, wGetHeadForPoint(scr, p));
 
1747
 
 
1748
        if (scr->flags.jump_back_pending ||
 
1749
            p.x <= (rect.pos.x + 1) ||
 
1750
            p.x >= (rect.pos.x + rect.size.width - 2) ||
 
1751
            p.y <= (rect.pos.y + 1) ||
 
1752
            p.y >= (rect.pos.y + rect.size.height - 2)) {
 
1753
            WMenu *menu;
 
1754
#ifdef DEBUG
 
1755
            printf("pointer at screen edge\n");
 
1756
#endif
 
1757
            menu = wMenuUnderPointer(scr);
 
1758
            if (menu!=NULL)
 
1759
                wMenuScroll(menu, event);
 
1760
        }
 
1761
    }
 
1762
}
 
1763
 
 
1764
 
 
1765
static void
 
1766
handleVisibilityNotify(XEvent *event)
 
1767
{
 
1768
    WWindow *wwin;
 
1769
 
 
1770
    wwin = wWindowFor(event->xvisibility.window);
 
1771
    if (!wwin)
 
1772
        return;
 
1773
    wwin->flags.obscured =
 
1774
        (event->xvisibility.state == VisibilityFullyObscured);
 
1775
}
 
1776
 
 
1777