~3v1n0/ubuntu/precise/compiz/scale-hotkeys-change

« back to all changes in this revision

Viewing changes to .pc/fix-865863.patch/src/event.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2011-10-06 17:57:36 UTC
  • Revision ID: james.westby@ubuntu.com-20111006175736-ra3xnpa8tyy3z7vn
Tags: 1:0.9.6+bzr20110929-0ubuntu4
* debian/control:
  - don't suggest nvidia-glx, it's part of the old initial packaging
    and probably a bad hint on non nvidia system (LP: #844218)
* Cherry-pick upstream patches:
  - Windows should not automatically be focused when opened if the focus
    is on another application (LP: #748840)
  - Launcher - If a spread contains minimised windows, when the spread
    exits, the minimised windows momentarily appear on the desktop
    before disappearing (LP: #863328)
  - reproducible stacking bug in compiz (LP: #869316)
  - Click-dragging a window that's stacked above a fullscreen window will
    cause it to go underneath the fullscreen window (LP: #869919)
  - sometimes the keyboard input doesn't go to the apparently focussed
    dialog (LP: #869967)
  - Opening mumble can cause it to be stacked above the dash if you
    open the dash at the same time (LP: #865863)
  - Sometimes configure events are missed and windows move slow as a result
    (LP: #866752)
  - Workaround ubuntu desktop unity. Mouse at the left side doesn't reveal
    launcher (LP: #832150)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright © 2005 Novell, Inc.
 
3
 *
 
4
 * Permission to use, copy, modify, distribute, and sell this software
 
5
 * and its documentation for any purpose is hereby granted without
 
6
 * fee, provided that the above copyright notice appear in all copies
 
7
 * and that both that copyright notice and this permission notice
 
8
 * appear in supporting documentation, and that the name of
 
9
 * Novell, Inc. not be used in advertising or publicity pertaining to
 
10
 * distribution of the software without specific, written prior permission.
 
11
 * Novell, Inc. makes no representations about the suitability of this
 
12
 * software for any purpose. It is provided "as is" without express or
 
13
 * implied warranty.
 
14
 *
 
15
 * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 
16
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
 
17
 * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 
18
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
 
19
 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 
20
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 
21
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
22
 *
 
23
 * Author: David Reveman <davidr@novell.com>
 
24
 */
 
25
 
 
26
#include <stdlib.h>
 
27
#include <string.h>
 
28
 
 
29
#include <boost/bind.hpp>
 
30
#include <boost/foreach.hpp>
 
31
#define foreach BOOST_FOREACH
 
32
 
 
33
#include <X11/Xlib.h>
 
34
#include <X11/Xatom.h>
 
35
#include <X11/extensions/shape.h>
 
36
#include <X11/extensions/Xrandr.h>
 
37
#include <X11/extensions/Xfixes.h>
 
38
 
 
39
#include <core/core.h>
 
40
#include <core/atoms.h>
 
41
#include "privatescreen.h"
 
42
#include "privatewindow.h"
 
43
#include "privatestackdebugger.h"
 
44
 
 
45
bool
 
46
PrivateWindow::handleSyncAlarm ()
 
47
{
 
48
    if (priv->syncWait)
 
49
    {
 
50
        priv->syncWait = false;
 
51
 
 
52
        if (window->resize (priv->syncGeometry))
 
53
        {
 
54
            window->windowNotify (CompWindowNotifySyncAlarm);
 
55
        }
 
56
        else
 
57
        {
 
58
            /* resizeWindow failing means that there is another pending
 
59
               resize and we must send a new sync request to the client */
 
60
            window->sendSyncRequest ();
 
61
        }
 
62
    }
 
63
 
 
64
    return false;
 
65
}
 
66
 
 
67
 
 
68
static bool
 
69
autoRaiseTimeout (CompScreen *screen)
 
70
{
 
71
    CompWindow  *w = screen->findWindow (screen->activeWindow ());
 
72
 
 
73
    if (screen->autoRaiseWindow () == screen->activeWindow () ||
 
74
        (w && (screen->autoRaiseWindow () == w->transientFor ())))
 
75
    {
 
76
        w = screen->findWindow (screen->autoRaiseWindow ());
 
77
        if (w)
 
78
            w->updateAttributes (CompStackingUpdateModeNormal);
 
79
    }
 
80
 
 
81
    return false;
 
82
}
 
83
 
 
84
#define REAL_MOD_MASK (ShiftMask | ControlMask | Mod1Mask | Mod2Mask | \
 
85
                       Mod3Mask | Mod4Mask | Mod5Mask | CompNoMask)
 
86
 
 
87
static bool
 
88
isCallBackBinding (CompOption              &option,
 
89
                   CompAction::BindingType type,
 
90
                   CompAction::State       state)
 
91
{
 
92
    if (!option.isAction ())
 
93
        return false;
 
94
 
 
95
    if (!(option.value ().action ().type () & type))
 
96
        return false;
 
97
 
 
98
    if (!(option.value ().action ().state () & state))
 
99
        return false;
 
100
 
 
101
    return true;
 
102
}
 
103
 
 
104
static bool
 
105
isInitiateBinding (CompOption              &option,
 
106
                   CompAction::BindingType type,
 
107
                   CompAction::State       state,
 
108
                   CompAction              **action)
 
109
{
 
110
    if (!isCallBackBinding (option, type, state))
 
111
        return false;
 
112
 
 
113
    if (option.value ().action ().initiate ().empty ())
 
114
        return false;
 
115
 
 
116
    *action = &option.value ().action ();
 
117
 
 
118
    return true;
 
119
}
 
120
 
 
121
static bool
 
122
isTerminateBinding (CompOption              &option,
 
123
                    CompAction::BindingType type,
 
124
                    CompAction::State       state,
 
125
                    CompAction              **action)
 
126
{
 
127
    if (!isCallBackBinding (option, type, state))
 
128
        return false;
 
129
 
 
130
    if (option.value ().action ().terminate ().empty ())
 
131
        return false;
 
132
 
 
133
    *action = &option.value ().action ();
 
134
 
 
135
    return true;
 
136
}
 
137
 
 
138
bool
 
139
PrivateScreen::triggerButtonPressBindings (CompOption::Vector &options,
 
140
                                           XButtonEvent       *event,
 
141
                                           CompOption::Vector &arguments)
 
142
{
 
143
    CompAction::State state = CompAction::StateInitButton;
 
144
    CompAction        *action;
 
145
    unsigned int      ignored = modHandler->ignoredModMask ();
 
146
    unsigned int      modMask = REAL_MOD_MASK & ~ignored;
 
147
    unsigned int      bindMods;
 
148
    unsigned int      edge = 0;
 
149
 
 
150
    if (priv->edgeWindow)
 
151
    {
 
152
        unsigned int i;
 
153
 
 
154
        if (event->root != root)
 
155
            return false;
 
156
 
 
157
        if (event->window != priv->edgeWindow)
 
158
        {
 
159
            if (grabs.empty () || event->window != root)
 
160
                return false;
 
161
        }
 
162
 
 
163
        for (i = 0; i < SCREEN_EDGE_NUM; i++)
 
164
        {
 
165
            if (priv->edgeWindow == screenEdge[i].id)
 
166
            {
 
167
                edge = 1 << i;
 
168
                arguments[1].value ().set ((int) activeWindow);
 
169
                break;
 
170
            }
 
171
        }
 
172
    }
 
173
 
 
174
    foreach (CompOption &option, options)
 
175
    {
 
176
        if (isInitiateBinding (option, CompAction::BindingTypeButton, state,
 
177
                               &action))
 
178
        {
 
179
            if (action->button ().button () == (int) event->button)
 
180
            {
 
181
                bindMods = modHandler->virtualToRealModMask (
 
182
                    action->button ().modifiers ());
 
183
 
 
184
                if ((bindMods & modMask) == (event->state & modMask))
 
185
                {
 
186
                    if (action->initiate () (action, state, arguments))
 
187
                        return true;
 
188
                }
 
189
            }
 
190
        }
 
191
 
 
192
        if (edge)
 
193
        {
 
194
            if (isInitiateBinding (option, CompAction::BindingTypeEdgeButton,
 
195
                                   state | CompAction::StateInitEdge, &action))
 
196
            {
 
197
                if ((action->button ().button () == (int) event->button) &&
 
198
                    (action->edgeMask () & edge))
 
199
                {
 
200
                    bindMods = modHandler->virtualToRealModMask (
 
201
                        action->button ().modifiers ());
 
202
 
 
203
                    if ((bindMods & modMask) == (event->state & modMask))
 
204
                        if (action->initiate () (action, state |
 
205
                                                 CompAction::StateInitEdge,
 
206
                                                 arguments))
 
207
                            return true;
 
208
                }
 
209
            }
 
210
        }
 
211
    }
 
212
 
 
213
    return false;
 
214
}
 
215
 
 
216
bool
 
217
PrivateScreen::triggerButtonReleaseBindings (CompOption::Vector &options,
 
218
                                             XButtonEvent       *event,
 
219
                                             CompOption::Vector &arguments)
 
220
{
 
221
    CompAction::State       state = CompAction::StateTermButton;
 
222
    CompAction::BindingType type  = CompAction::BindingTypeButton |
 
223
                                    CompAction::BindingTypeEdgeButton;
 
224
    CompAction              *action;
 
225
 
 
226
    foreach (CompOption &option, options)
 
227
    {
 
228
        if (isTerminateBinding (option, type, state, &action))
 
229
        {
 
230
            if (action->button ().button () == (int) event->button)
 
231
            {
 
232
                if (action->terminate () (action, state, arguments))
 
233
                    return true;
 
234
            }
 
235
        }
 
236
    }
 
237
 
 
238
    return false;
 
239
}
 
240
 
 
241
bool
 
242
PrivateScreen::triggerKeyPressBindings (CompOption::Vector &options,
 
243
                                        XKeyEvent          *event,
 
244
                                        CompOption::Vector &arguments)
 
245
{
 
246
    CompAction::State state = 0;
 
247
    CompAction        *action;
 
248
    unsigned int      modMask = REAL_MOD_MASK & ~modHandler->ignoredModMask ();
 
249
    unsigned int      bindMods;
 
250
 
 
251
    if (event->keycode == escapeKeyCode)
 
252
        state = CompAction::StateCancel;
 
253
    else if (event->keycode == returnKeyCode)
 
254
        state = CompAction::StateCommit;
 
255
 
 
256
    if (state)
 
257
    {
 
258
        foreach (CompOption &o, options)
 
259
        {
 
260
            if (o.isAction ())
 
261
            {
 
262
                if (!o.value ().action ().terminate ().empty ())
 
263
                    o.value ().action ().terminate () (&o.value ().action (),
 
264
                                                       state, noOptions);
 
265
            }
 
266
        }
 
267
 
 
268
        if (state == CompAction::StateCancel)
 
269
            return false;
 
270
    }
 
271
 
 
272
    state = CompAction::StateInitKey;
 
273
    foreach (CompOption &option, options)
 
274
    {
 
275
        if (isInitiateBinding (option, CompAction::BindingTypeKey,
 
276
                               state, &action))
 
277
        {
 
278
            bindMods = modHandler->virtualToRealModMask (
 
279
                action->key ().modifiers ());
 
280
 
 
281
            if (action->key ().keycode () == (int) event->keycode)
 
282
            {
 
283
                if ((bindMods & modMask) == (event->state & modMask))
 
284
                    if (action->initiate () (action, state, arguments))
 
285
                        return true;
 
286
            }
 
287
            else if (!xkbEvent && action->key ().keycode () == 0)
 
288
            {
 
289
                if (bindMods == (event->state & modMask))
 
290
                    if (action->initiate () (action, state, arguments))
 
291
                        return true;
 
292
            }
 
293
        }
 
294
    }
 
295
 
 
296
    return false;
 
297
}
 
298
 
 
299
bool
 
300
PrivateScreen::triggerKeyReleaseBindings (CompOption::Vector &options,
 
301
                                          XKeyEvent          *event,
 
302
                                          CompOption::Vector &arguments)
 
303
{
 
304
    CompAction::State state = CompAction::StateTermKey;
 
305
    CompAction        *action;
 
306
    unsigned int      ignored = modHandler->ignoredModMask ();
 
307
    unsigned int      modMask = REAL_MOD_MASK & ~ignored;
 
308
    unsigned int      bindMods;
 
309
    unsigned int      mods;
 
310
 
 
311
    mods = modHandler->keycodeToModifiers (event->keycode);
 
312
    if (!xkbEvent && !mods)
 
313
        return false;
 
314
 
 
315
    foreach (CompOption &option, options)
 
316
    {
 
317
        if (isTerminateBinding (option, CompAction::BindingTypeKey,
 
318
                                state, &action))
 
319
        {
 
320
            bindMods = modHandler->virtualToRealModMask (action->key ().modifiers ());
 
321
 
 
322
            if ((bindMods & modMask) == 0)
 
323
            {
 
324
                if ((unsigned int) action->key ().keycode () ==
 
325
                                                  (unsigned int) event->keycode)
 
326
                {
 
327
                    if (action->terminate () (action, state, arguments))
 
328
                        return true;
 
329
                }
 
330
            }
 
331
            else if (!xkbEvent && ((mods & modMask & bindMods) != bindMods))
 
332
            {
 
333
                if (action->terminate () (action, state, arguments))
 
334
                    return true;
 
335
            }
 
336
        }
 
337
    }
 
338
 
 
339
    return false;
 
340
}
 
341
 
 
342
bool
 
343
PrivateScreen::triggerStateNotifyBindings (CompOption::Vector  &options,
 
344
                                           XkbStateNotifyEvent *event,
 
345
                                           CompOption::Vector  &arguments)
 
346
{
 
347
    CompAction::State state;
 
348
    CompAction        *action;
 
349
    unsigned int      ignored = modHandler->ignoredModMask ();
 
350
    unsigned int      modMask = REAL_MOD_MASK & ~ignored;
 
351
    unsigned int      bindMods;
 
352
 
 
353
    if (event->event_type == KeyPress)
 
354
    {
 
355
        state = CompAction::StateInitKey;
 
356
 
 
357
        foreach (CompOption &option, options)
 
358
        {
 
359
            if (isInitiateBinding (option, CompAction::BindingTypeKey,
 
360
                                   state, &action))
 
361
            {
 
362
                if (action->key ().keycode () == 0)
 
363
                {
 
364
                    bindMods =
 
365
                        modHandler->virtualToRealModMask (action->key ().modifiers ());
 
366
 
 
367
                    if ((event->mods & modMask & bindMods) == bindMods)
 
368
                    {
 
369
                        if (action->initiate () (action, state, arguments))
 
370
                            return true;
 
371
                    }
 
372
                }
 
373
            }
 
374
        }
 
375
    }
 
376
    else
 
377
    {
 
378
        state = CompAction::StateTermKey;
 
379
 
 
380
        foreach (CompOption &option, options)
 
381
        {
 
382
            if (isTerminateBinding (option, CompAction::BindingTypeKey,
 
383
                                    state, &action))
 
384
            {
 
385
                bindMods = modHandler->virtualToRealModMask (action->key ().modifiers ());
 
386
 
 
387
                if ((event->mods & modMask & bindMods) != bindMods)
 
388
                {
 
389
                    if (action->terminate () (action, state, arguments))
 
390
                        return true;
 
391
                }
 
392
            }
 
393
        }
 
394
    }
 
395
 
 
396
    return false;
 
397
}
 
398
 
 
399
static bool
 
400
isBellAction (CompOption        &option,
 
401
              CompAction::State state,
 
402
              CompAction        **action)
 
403
{
 
404
    if (option.type () != CompOption::TypeAction &&
 
405
        option.type () != CompOption::TypeBell)
 
406
        return false;
 
407
 
 
408
    if (!option.value ().action ().bell ())
 
409
        return false;
 
410
 
 
411
    if (!(option.value ().action ().state () & state))
 
412
        return false;
 
413
 
 
414
    if (option.value ().action ().initiate ().empty ())
 
415
        return false;
 
416
 
 
417
    *action = &option.value ().action ();
 
418
 
 
419
    return true;
 
420
}
 
421
 
 
422
static bool
 
423
triggerBellNotifyBindings (CompOption::Vector &options,
 
424
                           CompOption::Vector &arguments)
 
425
{
 
426
    CompAction::State state = CompAction::StateInitBell;
 
427
    CompAction        *action;
 
428
 
 
429
    foreach (CompOption &option, options)
 
430
    {
 
431
        if (isBellAction (option, state, &action))
 
432
        {
 
433
            if (action->initiate () (action, state, arguments))
 
434
                return true;
 
435
        }
 
436
    }
 
437
 
 
438
    return false;
 
439
}
 
440
 
 
441
static bool
 
442
isEdgeAction (CompOption        &option,
 
443
              CompAction::State state,
 
444
              unsigned int      edge)
 
445
{
 
446
    if (option.type () != CompOption::TypeAction &&
 
447
        option.type () != CompOption::TypeButton &&
 
448
        option.type () != CompOption::TypeEdge)
 
449
        return false;
 
450
 
 
451
    if (!(option.value ().action ().edgeMask () & edge))
 
452
        return false;
 
453
 
 
454
    if (!(option.value ().action ().state () & state))
 
455
        return false;
 
456
 
 
457
    return true;
 
458
}
 
459
 
 
460
static bool
 
461
isEdgeEnterAction (CompOption        &option,
 
462
                   CompAction::State state,
 
463
                   CompAction::State delayState,
 
464
                   unsigned int      edge,
 
465
                   CompAction        **action)
 
466
{
 
467
    if (!isEdgeAction (option, state, edge))
 
468
        return false;
 
469
 
 
470
    if (option.value ().action ().type () & CompAction::BindingTypeEdgeButton)
 
471
        return false;
 
472
 
 
473
    if (option.value ().action ().initiate ().empty ())
 
474
        return false;
 
475
 
 
476
    if (delayState)
 
477
    {
 
478
        if ((option.value ().action ().state () &
 
479
             CompAction::StateNoEdgeDelay) !=
 
480
            (delayState & CompAction::StateNoEdgeDelay))
 
481
        {
 
482
            /* ignore edge actions which shouldn't be delayed when invoking
 
483
               undelayed edges (or vice versa) */
 
484
            return false;
 
485
        }
 
486
    }
 
487
 
 
488
 
 
489
    *action = &option.value ().action ();
 
490
 
 
491
    return true;
 
492
}
 
493
 
 
494
static bool
 
495
isEdgeLeaveAction (CompOption        &option,
 
496
                   CompAction::State state,
 
497
                   unsigned int      edge,
 
498
                   CompAction        **action)
 
499
{
 
500
    if (!isEdgeAction (option, state, edge))
 
501
        return false;
 
502
 
 
503
    if (option.value ().action ().terminate ().empty ())
 
504
        return false;
 
505
 
 
506
    *action = &option.value ().action ();
 
507
 
 
508
    return true;
 
509
}
 
510
 
 
511
static bool
 
512
triggerEdgeEnterBindings (CompOption::Vector &options,
 
513
                          CompAction::State  state,
 
514
                          CompAction::State  delayState,
 
515
                          unsigned int       edge,
 
516
                          CompOption::Vector &arguments)
 
517
{
 
518
    CompAction *action;
 
519
 
 
520
    foreach (CompOption &option, options)
 
521
    {
 
522
        if (isEdgeEnterAction (option, state, delayState, edge, &action))
 
523
        {
 
524
            if (action->initiate () (action, state, arguments))
 
525
                return true;
 
526
        }
 
527
    }
 
528
 
 
529
    return false;
 
530
}
 
531
 
 
532
static bool
 
533
triggerEdgeLeaveBindings (CompOption::Vector &options,
 
534
                          CompAction::State  state,
 
535
                          unsigned int       edge,
 
536
                          CompOption::Vector &arguments)
 
537
{
 
538
    CompAction *action;
 
539
 
 
540
    foreach (CompOption &option, options)
 
541
    {
 
542
        if (isEdgeLeaveAction (option, state, edge, &action))
 
543
        {
 
544
            if (action->terminate () (action, state, arguments))
 
545
                return true;
 
546
        }
 
547
    }
 
548
 
 
549
    return false;
 
550
}
 
551
 
 
552
static bool
 
553
triggerAllEdgeEnterBindings (CompAction::State  state,
 
554
                             CompAction::State  delayState,
 
555
                             unsigned int       edge,
 
556
                             CompOption::Vector &arguments)
 
557
{
 
558
    foreach (CompPlugin *p, CompPlugin::getPlugins ())
 
559
    {
 
560
        CompOption::Vector &options = p->vTable->getOptions ();
 
561
        if (triggerEdgeEnterBindings (options, state, delayState, edge,
 
562
                                      arguments))
 
563
        {
 
564
            return true;
 
565
        }
 
566
    }
 
567
    return false;
 
568
}
 
569
 
 
570
static bool
 
571
delayedEdgeTimeout (CompDelayedEdgeSettings *settings)
 
572
{
 
573
    triggerAllEdgeEnterBindings (settings->state,
 
574
                                 ~CompAction::StateNoEdgeDelay,
 
575
                                 settings->edge,
 
576
                                 settings->options);
 
577
 
 
578
    return false;
 
579
}
 
580
 
 
581
bool
 
582
PrivateScreen::triggerEdgeEnter (unsigned int       edge,
 
583
                                 CompAction::State  state,
 
584
                                 CompOption::Vector &arguments)
 
585
{
 
586
    int                     delay;
 
587
 
 
588
    delay = optionGetEdgeDelay ();
 
589
 
 
590
    if (delay > 0)
 
591
    {
 
592
        CompAction::State delayState;
 
593
        edgeDelaySettings.edge    = edge;
 
594
        edgeDelaySettings.state   = state;
 
595
        edgeDelaySettings.options = arguments;
 
596
 
 
597
        edgeDelayTimer.start  (
 
598
            boost::bind (delayedEdgeTimeout, &edgeDelaySettings),
 
599
                         delay, (unsigned int) ((float) delay * 1.2));
 
600
 
 
601
        delayState = CompAction::StateNoEdgeDelay;
 
602
        if (triggerAllEdgeEnterBindings (state, delayState, edge, arguments))
 
603
            return true;
 
604
    }
 
605
    else
 
606
    {
 
607
        if (triggerAllEdgeEnterBindings (state, 0, edge, arguments))
 
608
            return true;
 
609
    }
 
610
 
 
611
    return false;
 
612
}
 
613
 
 
614
bool
 
615
PrivateScreen::handleActionEvent (XEvent *event)
 
616
{
 
617
    static CompOption::Vector o (8);
 
618
    Window xid;
 
619
 
 
620
    o[0].setName ("event_window", CompOption::TypeInt);
 
621
    o[1].setName ("window", CompOption::TypeInt);
 
622
    o[2].setName ("modifiers", CompOption::TypeInt);
 
623
    o[3].setName ("x", CompOption::TypeInt);
 
624
    o[4].setName ("y", CompOption::TypeInt);
 
625
    o[5].setName ("root", CompOption::TypeInt);
 
626
    o[6].reset ();
 
627
    o[7].reset ();
 
628
 
 
629
    switch (event->type) {
 
630
    case ButtonPress:
 
631
        /* We need to determine if we clicked on a parent frame
 
632
         * window, if so, pass the appropriate child window as
 
633
         * "window" and the frame as "event_window"
 
634
         */
 
635
 
 
636
        xid = event->xbutton.window;
 
637
 
 
638
        foreach (CompWindow *w, screen->windows ())
 
639
        {
 
640
            if (w->priv->frame == xid)
 
641
                xid = w->id ();
 
642
        }
 
643
 
 
644
        o[0].value ().set ((int) event->xbutton.window);
 
645
        o[1].value ().set ((int) xid);
 
646
        o[2].value ().set ((int) event->xbutton.state);
 
647
        o[3].value ().set ((int) event->xbutton.x_root);
 
648
        o[4].value ().set ((int) event->xbutton.y_root);
 
649
        o[5].value ().set ((int) event->xbutton.root);
 
650
 
 
651
        o[6].setName ("button", CompOption::TypeInt);
 
652
        o[7].setName ("time", CompOption::TypeInt);
 
653
 
 
654
        o[6].value ().set ((int) event->xbutton.button);
 
655
        o[7].value ().set ((int) event->xbutton.time);
 
656
 
 
657
        foreach (CompPlugin *p, CompPlugin::getPlugins ())
 
658
        {
 
659
            CompOption::Vector &options = p->vTable->getOptions ();
 
660
            if (triggerButtonPressBindings (options, &event->xbutton, o))
 
661
                return true;
 
662
        }
 
663
        break;
 
664
    case ButtonRelease:
 
665
        o[0].value ().set ((int) event->xbutton.window);
 
666
        o[1].value ().set ((int) event->xbutton.window);
 
667
        o[2].value ().set ((int) event->xbutton.state);
 
668
        o[3].value ().set ((int) event->xbutton.x_root);
 
669
        o[4].value ().set ((int) event->xbutton.y_root);
 
670
        o[5].value ().set ((int) event->xbutton.root);
 
671
 
 
672
        o[6].setName ("button", CompOption::TypeInt);
 
673
        o[7].setName ("time", CompOption::TypeInt);
 
674
 
 
675
        o[6].value ().set ((int) event->xbutton.button);
 
676
        o[7].value ().set ((int) event->xbutton.time);
 
677
 
 
678
        foreach (CompPlugin *p, CompPlugin::getPlugins ())
 
679
        {
 
680
            CompOption::Vector &options = p->vTable->getOptions ();
 
681
            if (triggerButtonReleaseBindings (options, &event->xbutton, o))
 
682
                return true;
 
683
        }
 
684
        break;
 
685
    case KeyPress:
 
686
        o[0].value ().set ((int) event->xkey.window);
 
687
        o[1].value ().set ((int) activeWindow);
 
688
        o[2].value ().set ((int) event->xkey.state);
 
689
        o[3].value ().set ((int) event->xkey.x_root);
 
690
        o[4].value ().set ((int) event->xkey.y_root);
 
691
        o[5].value ().set ((int) event->xkey.root);
 
692
 
 
693
        o[6].setName ("keycode", CompOption::TypeInt);
 
694
        o[7].setName ("time", CompOption::TypeInt);
 
695
 
 
696
        o[6].value ().set ((int) event->xkey.keycode);
 
697
        o[7].value ().set ((int) event->xkey.time);
 
698
 
 
699
        foreach (CompPlugin *p, CompPlugin::getPlugins ())
 
700
        {
 
701
            CompOption::Vector &options = p->vTable->getOptions ();
 
702
            if (triggerKeyPressBindings (options, &event->xkey, o))
 
703
                return true;
 
704
        }
 
705
        break;
 
706
    case KeyRelease:
 
707
        o[0].value ().set ((int) event->xkey.window);
 
708
        o[1].value ().set ((int) activeWindow);
 
709
        o[2].value ().set ((int) event->xkey.state);
 
710
        o[3].value ().set ((int) event->xkey.x_root);
 
711
        o[4].value ().set ((int) event->xkey.y_root);
 
712
        o[5].value ().set ((int) event->xkey.root);
 
713
 
 
714
        o[6].setName ("keycode", CompOption::TypeInt);
 
715
        o[7].setName ("time", CompOption::TypeInt);
 
716
 
 
717
        o[6].value ().set ((int) event->xkey.keycode);
 
718
        o[7].value ().set ((int) event->xkey.time);
 
719
 
 
720
        foreach (CompPlugin *p, CompPlugin::getPlugins ())
 
721
        {
 
722
            CompOption::Vector &options = p->vTable->getOptions ();
 
723
            if (triggerKeyReleaseBindings (options, &event->xkey, o))
 
724
                return true;
 
725
        }
 
726
        break;
 
727
    case EnterNotify:
 
728
        if (event->xcrossing.mode   != NotifyGrab   &&
 
729
            event->xcrossing.mode   != NotifyUngrab &&
 
730
            event->xcrossing.detail != NotifyInferior)
 
731
        {
 
732
            unsigned int      edge, i;
 
733
            CompAction::State state;
 
734
 
 
735
            if (event->xcrossing.root != root)
 
736
                return false;
 
737
 
 
738
            if (edgeDelayTimer.active ())
 
739
                edgeDelayTimer.stop ();
 
740
 
 
741
            if (priv->edgeWindow && priv->edgeWindow != event->xcrossing.window)
 
742
            {
 
743
                state = CompAction::StateTermEdge;
 
744
                edge  = 0;
 
745
 
 
746
                for (i = 0; i < SCREEN_EDGE_NUM; i++)
 
747
                {
 
748
                    if (priv->edgeWindow == screenEdge[i].id)
 
749
                    {
 
750
                        edge = 1 << i;
 
751
                        break;
 
752
                    }
 
753
                }
 
754
 
 
755
                priv->edgeWindow = None;
 
756
 
 
757
                o[0].value ().set ((int) event->xcrossing.window);
 
758
                o[1].value ().set ((int) activeWindow);
 
759
                o[2].value ().set ((int) event->xcrossing.state);
 
760
                o[3].value ().set ((int) event->xcrossing.x_root);
 
761
                o[4].value ().set ((int) event->xcrossing.y_root);
 
762
                o[5].value ().set ((int) event->xcrossing.root);
 
763
 
 
764
                o[6].setName ("time", CompOption::TypeInt);
 
765
                o[6].value ().set ((int) event->xcrossing.time);
 
766
 
 
767
                foreach (CompPlugin *p, CompPlugin::getPlugins ())
 
768
                {
 
769
                    CompOption::Vector &options = p->vTable->getOptions ();
 
770
                    if (triggerEdgeLeaveBindings (options, state, edge, o))
 
771
                        return true;
 
772
                }
 
773
            }
 
774
 
 
775
            edge = 0;
 
776
 
 
777
            for (i = 0; i < SCREEN_EDGE_NUM; i++)
 
778
            {
 
779
                if (event->xcrossing.window == screenEdge[i].id)
 
780
                {
 
781
                    edge = 1 << i;
 
782
                    break;
 
783
                }
 
784
            }
 
785
 
 
786
            if (edge)
 
787
            {
 
788
                state = CompAction::StateInitEdge;
 
789
 
 
790
                priv->edgeWindow = event->xcrossing.window;
 
791
 
 
792
                o[0].value ().set ((int) event->xcrossing.window);
 
793
                o[1].value ().set ((int) activeWindow);
 
794
                o[2].value ().set ((int) event->xcrossing.state);
 
795
                o[3].value ().set ((int) event->xcrossing.x_root);
 
796
                o[4].value ().set ((int) event->xcrossing.y_root);
 
797
                o[5].value ().set ((int) event->xcrossing.root);
 
798
 
 
799
                o[6].setName ("time", CompOption::TypeInt);
 
800
                o[6].value ().set ((int) event->xcrossing.time);
 
801
 
 
802
                if (triggerEdgeEnter (edge, state, o))
 
803
                    return true;
 
804
            }
 
805
        }
 
806
        break;
 
807
    case ClientMessage:
 
808
        if (event->xclient.message_type == Atoms::xdndEnter)
 
809
        {
 
810
            priv->xdndWindow = event->xclient.window;
 
811
        }
 
812
        else if (event->xclient.message_type == Atoms::xdndLeave)
 
813
        {
 
814
            unsigned int      edge = 0;
 
815
            CompAction::State state;
 
816
 
 
817
            if (!priv->xdndWindow)
 
818
            {
 
819
                CompWindow *w;
 
820
 
 
821
                w = screen->findWindow (event->xclient.window);
 
822
                if (w)
 
823
                {
 
824
                    unsigned int i;
 
825
 
 
826
                    for (i = 0; i < SCREEN_EDGE_NUM; i++)
 
827
                    {
 
828
                        if (event->xclient.window == screenEdge[i].id)
 
829
                        {
 
830
                            edge = 1 << i;
 
831
                            break;
 
832
                        }
 
833
                    }
 
834
                }
 
835
            }
 
836
 
 
837
            if (edge)
 
838
            {
 
839
                state = CompAction::StateTermEdgeDnd;
 
840
 
 
841
                o[0].value ().set ((int) event->xclient.window);
 
842
                o[1].value ().set ((int) activeWindow);
 
843
                o[2].value ().set ((int) 0); /* fixme */
 
844
                o[3].value ().set ((int) 0); /* fixme */
 
845
                o[4].value ().set ((int) 0); /* fixme */
 
846
                o[5].value ().set ((int) root);
 
847
 
 
848
                foreach (CompPlugin *p, CompPlugin::getPlugins ())
 
849
                {
 
850
                    CompOption::Vector &options = p->vTable->getOptions ();
 
851
                    if (triggerEdgeLeaveBindings (options, state, edge, o))
 
852
                        return true;
 
853
                }
 
854
            }
 
855
        }
 
856
        else if (event->xclient.message_type == Atoms::xdndPosition)
 
857
        {
 
858
            unsigned int      edge = 0;
 
859
            CompAction::State state;
 
860
 
 
861
            if (priv->xdndWindow == event->xclient.window)
 
862
            {
 
863
                CompWindow *w;
 
864
 
 
865
                w = screen->findWindow (event->xclient.window);
 
866
                if (w)
 
867
                {
 
868
                    unsigned int i;
 
869
 
 
870
                    for (i = 0; i < SCREEN_EDGE_NUM; i++)
 
871
                    {
 
872
                        if (priv->xdndWindow == screenEdge[i].id)
 
873
                        {
 
874
                            edge = 1 << i;
 
875
                            break;
 
876
                        }
 
877
                    }
 
878
                }
 
879
            }
 
880
 
 
881
            if (edge)
 
882
            {
 
883
                state = CompAction::StateInitEdgeDnd;
 
884
 
 
885
                o[0].value ().set ((int) event->xclient.window);
 
886
                o[1].value ().set ((int) activeWindow);
 
887
                o[2].value ().set ((int) 0); /* fixme */
 
888
                o[3].value ().set ((int) event->xclient.data.l[2] >> 16);
 
889
                o[4].value ().set ((int) event->xclient.data.l[2] & 0xffff);
 
890
                o[5].value ().set ((int) root);
 
891
 
 
892
                if (triggerEdgeEnter (edge, state, o))
 
893
                    return true;
 
894
            }
 
895
 
 
896
            priv->xdndWindow = None;
 
897
        }
 
898
        break;
 
899
    default:
 
900
        if (event->type == xkbEvent)
 
901
        {
 
902
            XkbAnyEvent *xkbEvent = (XkbAnyEvent *) event;
 
903
 
 
904
            if (xkbEvent->xkb_type == XkbStateNotify)
 
905
            {
 
906
                XkbStateNotifyEvent *stateEvent = (XkbStateNotifyEvent *) event;
 
907
 
 
908
                o[0].value ().set ((int) activeWindow);
 
909
                o[1].value ().set ((int) activeWindow);
 
910
                o[2].value ().set ((int) stateEvent->mods);
 
911
 
 
912
                o[3].setName ("time", CompOption::TypeInt);
 
913
                o[3].value ().set ((int) xkbEvent->time);
 
914
                o[4].reset ();
 
915
                o[5].reset ();
 
916
 
 
917
                foreach (CompPlugin *p, CompPlugin::getPlugins ())
 
918
                {
 
919
                    CompOption::Vector &options = p->vTable->getOptions ();
 
920
                    if (triggerStateNotifyBindings (options, stateEvent, o))
 
921
                        return true;
 
922
                }
 
923
            }
 
924
            else if (xkbEvent->xkb_type == XkbBellNotify)
 
925
            {
 
926
                o[0].value ().set ((int) activeWindow);
 
927
                o[1].value ().set ((int) activeWindow);
 
928
 
 
929
                o[2].setName ("time", CompOption::TypeInt);
 
930
                o[2].value ().set ((int) xkbEvent->time);
 
931
                o[3].reset ();
 
932
                o[4].reset ();
 
933
                o[5].reset ();
 
934
 
 
935
 
 
936
                foreach (CompPlugin *p, CompPlugin::getPlugins ())
 
937
                {
 
938
                    CompOption::Vector &options = p->vTable->getOptions ();
 
939
                    if (triggerBellNotifyBindings (options, o))
 
940
                        return true;
 
941
                }
 
942
            }
 
943
        }
 
944
        break;
 
945
    }
 
946
 
 
947
    return false;
 
948
}
 
949
 
 
950
void
 
951
PrivateScreen::setDefaultWindowAttributes (XWindowAttributes *wa)
 
952
{
 
953
    wa->x                     = 0;
 
954
    wa->y                     = 0;
 
955
    wa->width                 = 1;
 
956
    wa->height                = 1;
 
957
    wa->border_width          = 0;
 
958
    wa->depth                 = 0;
 
959
    wa->visual                = NULL;
 
960
    wa->root                  = priv->root;
 
961
    wa->c_class               = InputOnly;
 
962
    wa->bit_gravity           = NorthWestGravity;
 
963
    wa->win_gravity           = NorthWestGravity;
 
964
    wa->backing_store         = NotUseful;
 
965
    wa->backing_planes        = 0;
 
966
    wa->backing_pixel         = 0;
 
967
    wa->save_under            = false;
 
968
    wa->colormap              = None;
 
969
    wa->map_installed         = false;
 
970
    wa->map_state             = IsUnviewable;
 
971
    wa->all_event_masks       = 0;
 
972
    wa->your_event_mask       = 0;
 
973
    wa->do_not_propagate_mask = 0;
 
974
    wa->override_redirect     = true;
 
975
    wa->screen                = ScreenOfDisplay (priv->dpy, priv->screenNum);
 
976
}
 
977
 
 
978
void
 
979
CompScreen::handleCompizEvent (const char         *plugin,
 
980
                               const char         *event,
 
981
                               CompOption::Vector &options)
 
982
    WRAPABLE_HND_FUNC (7, handleCompizEvent, plugin, event, options)
 
983
 
 
984
void
 
985
CompScreen::handleEvent (XEvent *event)
 
986
{
 
987
    WRAPABLE_HND_FUNC (6, handleEvent, event)
 
988
 
 
989
    CompWindow *w = NULL;
 
990
    XWindowAttributes wa;
 
991
    bool              actionEventHandled = false;
 
992
 
 
993
    switch (event->type) {
 
994
    case ButtonPress:
 
995
        if (event->xbutton.root == priv->root)
 
996
            priv->setCurrentOutput (
 
997
                outputDeviceForPoint (event->xbutton.x_root,
 
998
                                                 event->xbutton.y_root));
 
999
        break;
 
1000
    case MotionNotify:
 
1001
        if (event->xmotion.root == priv->root)
 
1002
            priv->setCurrentOutput (
 
1003
                outputDeviceForPoint (event->xmotion.x_root,
 
1004
                                      event->xmotion.y_root));
 
1005
        break;
 
1006
    case KeyPress:
 
1007
        w = findWindow (priv->activeWindow);
 
1008
        if (w)
 
1009
            priv->setCurrentOutput (w->outputDevice ());
 
1010
        break;
 
1011
    default:
 
1012
        break;
 
1013
    }
 
1014
 
 
1015
    if (priv->handleActionEvent (event))
 
1016
    {
 
1017
        if (priv->grabs.empty ())
 
1018
            XAllowEvents (priv->dpy, AsyncPointer, event->xbutton.time);
 
1019
 
 
1020
        actionEventHandled = true;
 
1021
    }
 
1022
 
 
1023
    if (priv->grabs.empty ())
 
1024
    {
 
1025
        switch (event->type)
 
1026
        {
 
1027
            case KeyPress:
 
1028
                XUngrabKeyboard (priv->dpy, event->xkey.time);
 
1029
                break;
 
1030
            default:
 
1031
                break;
 
1032
        }
 
1033
    }
 
1034
 
 
1035
    if (actionEventHandled)
 
1036
        return;
 
1037
 
 
1038
    switch (event->type) {
 
1039
    case SelectionRequest:
 
1040
        priv->handleSelectionRequest (event);
 
1041
        break;
 
1042
    case SelectionClear:
 
1043
        priv->handleSelectionClear (event);
 
1044
        break;
 
1045
    case ConfigureNotify:
 
1046
        w = findWindow (event->xconfigure.window);
 
1047
 
 
1048
        if (w && !w->priv->frame)
 
1049
        {
 
1050
            w->priv->configure (&event->xconfigure);
 
1051
        }
 
1052
        else
 
1053
        {
 
1054
            w = findTopLevelWindow (event->xconfigure.window);
 
1055
 
 
1056
            if (w && w->priv->frame == event->xconfigure.window)
 
1057
                w->priv->configureFrame (&event->xconfigure);
 
1058
            else
 
1059
            {
 
1060
                if (event->xconfigure.window == priv->root)
 
1061
                    priv->configure (&event->xconfigure);
 
1062
            }
 
1063
        }
 
1064
        break;
 
1065
    case CreateNotify:
 
1066
    {
 
1067
        bool create = true;
 
1068
 
 
1069
        /* Failure means that window has been destroyed. We still have to add 
 
1070
         * the window to the window list as we might get configure requests
 
1071
         * which require us to stack other windows relative to it. Setting
 
1072
         * some default values if this is the case. */
 
1073
        if (!XGetWindowAttributes (priv->dpy, event->xcreatewindow.window, &wa))
 
1074
            priv->setDefaultWindowAttributes (&wa);
 
1075
 
 
1076
        foreach (CompWindow *w, screen->windows ())
 
1077
        {
 
1078
            if (w->priv->serverFrame == event->xcreatewindow.window)
 
1079
            {
 
1080
                w->priv->frame = event->xcreatewindow.window;
 
1081
                w->priv->updatePassiveButtonGrabs ();
 
1082
                create = false;
 
1083
            }
 
1084
        }
 
1085
 
 
1086
        foreach (CompWindow *w, screen->priv->destroyedWindows)
 
1087
        {
 
1088
            if (w->priv->serverId == event->xcreatewindow.window)
 
1089
            {
 
1090
                /* Previously destroyed window
 
1091
                 * plugins were keeping around
 
1092
                 * in order to avoid an xid conflict,
 
1093
                 * destroy it right away and manage
 
1094
                 * the new window */
 
1095
 
 
1096
                StackDebugger *dbg = StackDebugger::Default ();
 
1097
 
 
1098
                while (w->priv->destroyRefCnt)
 
1099
                    w->destroy ();
 
1100
 
 
1101
                if (dbg)
 
1102
                    dbg->removeDestroyedFrame (event->xcreatewindow.window);
 
1103
            }
 
1104
 
 
1105
        }
 
1106
 
 
1107
        if (wa.root != event->xcreatewindow.parent)
 
1108
            create = false;
 
1109
 
 
1110
        if (create)
 
1111
        {
 
1112
            /* Track the window if it was created on this
 
1113
             * screen, otherwise we still need to register
 
1114
             * for FocusChangeMask. Also, we don't want to
 
1115
             * manage it straight away - in reality we want
 
1116
             * that to wait until the map request */
 
1117
            if ((wa.root == priv->root))
 
1118
            {
 
1119
                CoreWindow *cw = new CoreWindow (event->xcreatewindow.window);
 
1120
                cw->manage (priv->getTopWindow (), wa);
 
1121
 
 
1122
                priv->createdWindows.remove (cw);
 
1123
                delete cw;
 
1124
            }
 
1125
            else
 
1126
                XSelectInput (priv->dpy, event->xcreatewindow.window,
 
1127
                              FocusChangeMask);
 
1128
        }
 
1129
        else
 
1130
            compLogMessage ("core", CompLogLevelDebug, "refusing to manage window 0x%x", (unsigned int) event->xcreatewindow.window);
 
1131
 
 
1132
        break;
 
1133
    }
 
1134
    case DestroyNotify:
 
1135
        w = findWindow (event->xdestroywindow.window);
 
1136
 
 
1137
        /* It is possible that some plugin might call
 
1138
         * w->destroy () before the window actually receives
 
1139
         * its first DestroyNotify event which would mean
 
1140
         * that it is already in the list of destroyed
 
1141
         * windows, so check that list too */
 
1142
 
 
1143
        if (!w)
 
1144
        {
 
1145
            foreach (CompWindow *dw, screen->priv->destroyedWindows)
 
1146
            {
 
1147
                if (dw->priv->serverId == event->xdestroywindow.window)
 
1148
                {
 
1149
                    w = dw;
 
1150
                    break;
 
1151
                }
 
1152
            }
 
1153
        }
 
1154
 
 
1155
        if (w)
 
1156
        {
 
1157
            w->moveInputFocusToOtherWindow ();
 
1158
            w->destroy ();
 
1159
        }
 
1160
        break;
 
1161
    case MapNotify:
 
1162
 
 
1163
        /* Search in already-created windows for this window */
 
1164
        if (!w)
 
1165
            w = findWindow (event->xmap.window);
 
1166
 
 
1167
        if (w)
 
1168
        {
 
1169
            if (w->priv->pendingMaps)
 
1170
            {
 
1171
                /* The only case where this happens
 
1172
                 * is where the window unmaps itself
 
1173
                 * but doesn't get destroyed so when
 
1174
                 * it re-maps we need to reparent it */
 
1175
 
 
1176
                if (!w->priv->serverFrame)
 
1177
                    w->priv->reparent ();
 
1178
 
 
1179
                w->priv->managed = true;
 
1180
            }
 
1181
 
 
1182
            /* been shaded */
 
1183
            if (w->priv->height == 0)
 
1184
            {
 
1185
                if (w->id () == priv->activeWindow)
 
1186
                    w->moveInputFocusTo ();
 
1187
            }
 
1188
 
 
1189
            w->map ();
 
1190
        }
 
1191
 
 
1192
        break;
 
1193
    case UnmapNotify:
 
1194
        w = findWindow (event->xunmap.window);
 
1195
        if (w)
 
1196
        {
 
1197
            /* Normal -> Iconic */
 
1198
            if (w->pendingUnmaps ())
 
1199
            {
 
1200
                priv->setWmState (IconicState, w->id ());
 
1201
                w->priv->pendingUnmaps--;
 
1202
            }
 
1203
            else /* X -> Withdrawn */
 
1204
            {
 
1205
                /* Iconic -> Withdrawn:
 
1206
                 *
 
1207
                 * The window is already unmapped so we need to check the
 
1208
                 * synthetic UnmapNotify that comes and withdraw the window here */
 
1209
                if (w->state () & CompWindowStateHiddenMask)
 
1210
                {
 
1211
                    w->priv->minimized = false;
 
1212
                    w->changeState (w->state () & ~CompWindowStateHiddenMask);
 
1213
 
 
1214
                    priv->updateClientList ();
 
1215
                    w->priv->withdraw ();
 
1216
                }
 
1217
                /* Closing:
 
1218
                 *
 
1219
                 * ICCCM Section 4.1.4 says that clients need to send
 
1220
                 * a synthetic UnmapNotify for every real unmap
 
1221
                 * in order to reflect the change in state, but
 
1222
                 * since we already withdraw the window on the real
 
1223
                 * UnmapNotify, no need to do it again on the synthetic
 
1224
                 * one. */
 
1225
                else if (!event->xunmap.send_event)
 
1226
                {
 
1227
                    w->windowNotify (CompWindowNotifyClose);
 
1228
                    w->priv->withdraw ();
 
1229
                }
 
1230
            }
 
1231
 
 
1232
            if (!event->xunmap.send_event)
 
1233
            {
 
1234
                w->unmap ();
 
1235
 
 
1236
                if (!w->shaded () && !w->priv->pendingMaps)
 
1237
                    w->moveInputFocusToOtherWindow ();
 
1238
            }
 
1239
        }
 
1240
        break;
 
1241
    case ReparentNotify:
 
1242
        w = findWindow (event->xreparent.window);
 
1243
 
 
1244
        /* It is possible that some plugin might call
 
1245
         * w->destroy () before the window actually receives
 
1246
         * its first ReparentNotify event which would mean
 
1247
         * that it is already in the list of destroyed
 
1248
         * windows, so check that list too */
 
1249
        if (!w)
 
1250
        {
 
1251
            foreach (CompWindow *dw, screen->priv->destroyedWindows)
 
1252
            {
 
1253
                if (dw->priv->serverId == event->xdestroywindow.window)
 
1254
                {
 
1255
                    w = dw;
 
1256
                    break;
 
1257
                }
 
1258
            }
 
1259
        }
 
1260
 
 
1261
        if (!w && event->xreparent.parent == priv->root)
 
1262
        {
 
1263
            /* Failure means that window has been destroyed. We still have to add 
 
1264
             * the window to the window list as we might get configure requests
 
1265
             * which require us to stack other windows relative to it. Setting
 
1266
             * some default values if this is the case. */
 
1267
            if (!XGetWindowAttributes (priv->dpy, event->xcreatewindow.window, &wa))
 
1268
                priv->setDefaultWindowAttributes (&wa);
 
1269
 
 
1270
            CoreWindow *cw = new CoreWindow (event->xcreatewindow.window);
 
1271
            cw->manage (priv->getTopWindow (), wa);
 
1272
 
 
1273
            priv->createdWindows.remove (cw);
 
1274
            delete cw;
 
1275
        }
 
1276
        else if (!(event->xreparent.parent == priv->root))
 
1277
        {
 
1278
            /* This is the only case where a window is removed but not
 
1279
               destroyed. We must remove our event mask and all passive
 
1280
               grabs. */
 
1281
 
 
1282
            if (w)
 
1283
            {
 
1284
                if (event->xreparent.parent != w->priv->wrapper)
 
1285
                {
 
1286
                    w->moveInputFocusToOtherWindow ();
 
1287
                    w->destroy ();
 
1288
 
 
1289
                    XSelectInput (priv->dpy, w->id (), NoEventMask);
 
1290
                    XShapeSelectInput (priv->dpy, w->id (), NoEventMask);
 
1291
                    XUngrabButton (priv->dpy, AnyButton, AnyModifier, w->id ());
 
1292
                }
 
1293
            }
 
1294
        }
 
1295
        break;
 
1296
    case CirculateNotify:
 
1297
        w = findWindow (event->xcirculate.window);
 
1298
        if (w)
 
1299
            w->priv->circulate (&event->xcirculate);
 
1300
        break;
 
1301
    case ButtonPress:
 
1302
        if (event->xbutton.button == Button1 ||
 
1303
            event->xbutton.button == Button2 ||
 
1304
            event->xbutton.button == Button3)
 
1305
        {
 
1306
            w = findTopLevelWindow (event->xbutton.window);
 
1307
            if (w)
 
1308
            {
 
1309
                if (priv->optionGetRaiseOnClick ())
 
1310
                {
 
1311
                    w->updateAttributes (CompStackingUpdateModeAboveFullscreen);
 
1312
                }
 
1313
 
 
1314
                if (w->id () != priv->activeWindow)
 
1315
                    if (!(w->type () & CompWindowTypeDockMask))
 
1316
                        if (w->focus ())
 
1317
                            w->moveInputFocusTo ();
 
1318
            }
 
1319
        }
 
1320
 
 
1321
        if (priv->grabs.empty ())
 
1322
            XAllowEvents (priv->dpy, ReplayPointer, event->xbutton.time);
 
1323
 
 
1324
        break;
 
1325
    case PropertyNotify:
 
1326
        if (event->xproperty.atom == Atoms::winType)
 
1327
        {
 
1328
            w = findWindow (event->xproperty.window);
 
1329
            if (w)
 
1330
            {
 
1331
                unsigned int type;
 
1332
 
 
1333
                type = priv->getWindowType (w->id ());
 
1334
 
 
1335
                if (type != w->wmType ())
 
1336
                {
 
1337
                    if (w->isViewable ())
 
1338
                    {
 
1339
                        if (w->type () == CompWindowTypeDesktopMask)
 
1340
                            priv->desktopWindowCount--;
 
1341
                        else if (type == CompWindowTypeDesktopMask)
 
1342
                            priv->desktopWindowCount++;
 
1343
                    }
 
1344
 
 
1345
                    w->wmType () = type;
 
1346
 
 
1347
                    w->recalcType ();
 
1348
                    w->recalcActions ();
 
1349
 
 
1350
                    if (type & (CompWindowTypeDockMask |
 
1351
                                CompWindowTypeDesktopMask))
 
1352
                        w->setDesktop (0xffffffff);
 
1353
 
 
1354
                    priv->updateClientList ();
 
1355
 
 
1356
                    matchPropertyChanged (w);
 
1357
                }
 
1358
            }
 
1359
        }
 
1360
        else if (event->xproperty.atom == Atoms::winState)
 
1361
        {
 
1362
            w = findWindow (event->xproperty.window);
 
1363
            if (w && !w->managed ())
 
1364
            {
 
1365
                unsigned int state;
 
1366
 
 
1367
                state = priv->getWindowState (w->id ());
 
1368
                state = CompWindow::constrainWindowState (state, w->actions ());
 
1369
 
 
1370
                /* EWMH suggests that we ignore changes
 
1371
                   to _NET_WM_STATE_HIDDEN */
 
1372
                if (w->state () & CompWindowStateHiddenMask)
 
1373
                    state |= CompWindowStateHiddenMask;
 
1374
                else
 
1375
                    state &= ~CompWindowStateHiddenMask;
 
1376
 
 
1377
                w->changeState (state);
 
1378
            }
 
1379
        }
 
1380
        else if (event->xproperty.atom == XA_WM_NORMAL_HINTS)
 
1381
        {
 
1382
            w = findWindow (event->xproperty.window);
 
1383
            if (w)
 
1384
            {
 
1385
                w->priv->updateNormalHints ();
 
1386
                w->recalcActions ();
 
1387
            }
 
1388
        }
 
1389
        else if (event->xproperty.atom == XA_WM_HINTS)
 
1390
        {
 
1391
            w = findWindow (event->xproperty.window);
 
1392
            if (w)
 
1393
                w->priv->updateWmHints ();
 
1394
        }
 
1395
        else if (event->xproperty.atom == XA_WM_TRANSIENT_FOR)
 
1396
        {
 
1397
            w = findWindow (event->xproperty.window);
 
1398
            if (w)
 
1399
            {
 
1400
                w->priv->updateTransientHint ();
 
1401
                w->recalcActions ();
 
1402
            }
 
1403
        }
 
1404
        else if (event->xproperty.atom == Atoms::wmClientLeader)
 
1405
        {
 
1406
            w = findWindow (event->xproperty.window);
 
1407
            if (w)
 
1408
                w->priv->clientLeader = w->priv->getClientLeader ();
 
1409
        }
 
1410
        else if (event->xproperty.atom == Atoms::wmIconGeometry)
 
1411
        {
 
1412
            w = findWindow (event->xproperty.window);
 
1413
            if (w)
 
1414
                w->priv->updateIconGeometry ();
 
1415
        }
 
1416
        else if (event->xproperty.atom == Atoms::wmStrut ||
 
1417
                 event->xproperty.atom == Atoms::wmStrutPartial)
 
1418
        {
 
1419
            w = findWindow (event->xproperty.window);
 
1420
            if (w)
 
1421
            {
 
1422
                if (w->updateStruts ())
 
1423
                    updateWorkarea ();
 
1424
            }
 
1425
        }
 
1426
        else if (event->xproperty.atom == Atoms::mwmHints)
 
1427
        {
 
1428
            w = findWindow (event->xproperty.window);
 
1429
            if (w)
 
1430
                w->priv->updateMwmHints ();
 
1431
        }
 
1432
        else if (event->xproperty.atom == Atoms::wmProtocols)
 
1433
        {
 
1434
            w = findWindow (event->xproperty.window);
 
1435
            if (w)
 
1436
                w->priv->protocols = priv->getProtocols (w->id ());
 
1437
        }
 
1438
        else if (event->xproperty.atom == Atoms::wmIcon)
 
1439
        {
 
1440
            w = findWindow (event->xproperty.window);
 
1441
            if (w)
 
1442
                w->priv->freeIcons ();
 
1443
        }
 
1444
        else if (event->xproperty.atom == Atoms::startupId)
 
1445
        {
 
1446
            w = findWindow (event->xproperty.window);
 
1447
            if (w)
 
1448
                w->priv->updateStartupId ();
 
1449
        }
 
1450
        else if (event->xproperty.atom == XA_WM_CLASS)
 
1451
        {
 
1452
            w = findWindow (event->xproperty.window);
 
1453
            if (w)
 
1454
                w->priv->updateClassHints ();
 
1455
        }
 
1456
        break;
 
1457
    case MotionNotify:
 
1458
        break;
 
1459
    case ClientMessage:
 
1460
        if (event->xclient.message_type == Atoms::winActive)
 
1461
        {
 
1462
            w = findTopLevelWindow (event->xclient.window);
 
1463
            if (w)
 
1464
            {
 
1465
                /* use focus stealing prevention if request came
 
1466
                   from an application  */
 
1467
                if (event->xclient.data.l[0] != ClientTypeApplication ||
 
1468
                    w->priv->allowWindowFocus (0, event->xclient.data.l[1]))
 
1469
                {
 
1470
                    w->activate ();
 
1471
                }
 
1472
            }
 
1473
        }
 
1474
        else if (event->xclient.message_type == Atoms::winState)
 
1475
        {
 
1476
            w = findWindow (event->xclient.window);
 
1477
            if (w)
 
1478
            {
 
1479
                unsigned long wState, state;
 
1480
                int           i;
 
1481
 
 
1482
                wState = w->state ();
 
1483
 
 
1484
                for (i = 1; i < 3; i++)
 
1485
                {
 
1486
                    state = priv->windowStateMask (event->xclient.data.l[i]);
 
1487
                    if (state & ~CompWindowStateHiddenMask)
 
1488
                    {
 
1489
 
 
1490
#define _NET_WM_STATE_REMOVE 0
 
1491
#define _NET_WM_STATE_ADD    1
 
1492
#define _NET_WM_STATE_TOGGLE 2
 
1493
 
 
1494
                        switch (event->xclient.data.l[0]) {
 
1495
                        case _NET_WM_STATE_REMOVE:
 
1496
                            wState &= ~state;
 
1497
                            break;
 
1498
                        case _NET_WM_STATE_ADD:
 
1499
                            wState |= state;
 
1500
                            break;
 
1501
                        case _NET_WM_STATE_TOGGLE:
 
1502
                            wState ^= state;
 
1503
                            break;
 
1504
                        }
 
1505
                    }
 
1506
                }
 
1507
 
 
1508
                wState = CompWindow::constrainWindowState (wState,
 
1509
                                                           w->actions ());
 
1510
                if (w->id () == priv->activeWindow)
 
1511
                    wState &= ~CompWindowStateDemandsAttentionMask;
 
1512
 
 
1513
                if (wState != w->state ())
 
1514
                {
 
1515
                    CompStackingUpdateMode stackingUpdateMode;
 
1516
                    unsigned long          dState = wState ^ w->state ();
 
1517
 
 
1518
                    stackingUpdateMode = CompStackingUpdateModeNone;
 
1519
 
 
1520
                    /* raise the window whenever its fullscreen state,
 
1521
                       above/below state or maximization state changed */
 
1522
                    if (dState & (CompWindowStateFullscreenMask |
 
1523
                                  CompWindowStateAboveMask |
 
1524
                                  CompWindowStateBelowMask |
 
1525
                                  CompWindowStateMaximizedHorzMask |
 
1526
                                  CompWindowStateMaximizedVertMask))
 
1527
                        stackingUpdateMode = CompStackingUpdateModeNormal;
 
1528
 
 
1529
                    w->changeState (wState);
 
1530
 
 
1531
                    w->updateAttributes (stackingUpdateMode);
 
1532
                }
 
1533
            }
 
1534
        }
 
1535
        else if (event->xclient.message_type == Atoms::wmProtocols)
 
1536
        {
 
1537
            if ((unsigned long) event->xclient.data.l[0] == Atoms::wmPing)
 
1538
            {
 
1539
                w = findWindow (event->xclient.data.l[2]);
 
1540
                if (w)
 
1541
                    w->priv->handlePing (priv->lastPing);
 
1542
            }
 
1543
        }
 
1544
        else if (event->xclient.message_type == Atoms::closeWindow)
 
1545
        {
 
1546
            w = findWindow (event->xclient.window);
 
1547
            if (w)
 
1548
                w->close (event->xclient.data.l[0]);
 
1549
        }
 
1550
        else if (event->xclient.message_type == Atoms::desktopGeometry)
 
1551
        {
 
1552
            if (event->xclient.window == priv->root)
 
1553
            {
 
1554
                CompOption::Value value;
 
1555
 
 
1556
                value.set ((int) (event->xclient.data.l[0] /
 
1557
                           width ()));
 
1558
 
 
1559
                setOptionForPlugin ("core", "hsize", value);
 
1560
 
 
1561
                value.set ((int) (event->xclient.data.l[1] /
 
1562
                           height ()));
 
1563
 
 
1564
                setOptionForPlugin ("core", "vsize", value);
 
1565
            }
 
1566
        }
 
1567
        else if (event->xclient.message_type == Atoms::moveResizeWindow)
 
1568
        {
 
1569
            w = findWindow (event->xclient.window);
 
1570
            if (w)
 
1571
            {
 
1572
                unsigned int   xwcm = 0;
 
1573
                XWindowChanges xwc;
 
1574
                int            gravity;
 
1575
                int            value_mask;
 
1576
                unsigned int   source;
 
1577
 
 
1578
                gravity = (event->xclient.data.l[0] & 0xFF);            
 
1579
                value_mask = (event->xclient.data.l[0] & 0xF00) >> 8;
 
1580
                source = (event->xclient.data.l[0] & 0xF000) >> 12;
 
1581
 
 
1582
                memset (&xwc, 0, sizeof (xwc));
 
1583
 
 
1584
                if (value_mask & CWX)
 
1585
                {
 
1586
                    xwcm |= CWX;
 
1587
                    xwc.x = event->xclient.data.l[1];
 
1588
                }
 
1589
 
 
1590
                if (value_mask & CWY)
 
1591
                {
 
1592
                    xwcm |= CWY;
 
1593
                    xwc.y = event->xclient.data.l[2];
 
1594
                }
 
1595
 
 
1596
                if (value_mask & CWWidth)
 
1597
                {
 
1598
                    xwcm |= CWWidth;
 
1599
                    xwc.width = event->xclient.data.l[3];
 
1600
                }
 
1601
 
 
1602
                if (value_mask & CWHeight)
 
1603
                {
 
1604
                    xwcm |= CWHeight;
 
1605
                    xwc.height = event->xclient.data.l[4];
 
1606
                }
 
1607
 
 
1608
                w->moveResize (&xwc, xwcm, gravity, source);
 
1609
            }
 
1610
        }
 
1611
        else if (event->xclient.message_type == Atoms::restackWindow)
 
1612
        {
 
1613
            w = findWindow (event->xclient.window);
 
1614
            if (w)
 
1615
            {
 
1616
                /* TODO: other stack modes than Above and Below */
 
1617
                if (event->xclient.data.l[1])
 
1618
                {
 
1619
                    CompWindow *sibling;
 
1620
 
 
1621
                    sibling = findWindow (event->xclient.data.l[1]);
 
1622
                    if (sibling)
 
1623
                    {
 
1624
                        if (event->xclient.data.l[2] == Above)
 
1625
                            w->restackAbove (sibling);
 
1626
                        else if (event->xclient.data.l[2] == Below)
 
1627
                            w->restackBelow (sibling);
 
1628
                    }
 
1629
                }
 
1630
                else
 
1631
                {
 
1632
                    if (event->xclient.data.l[2] == Above)
 
1633
                        w->raise ();
 
1634
                    else if (event->xclient.data.l[2] == Below)
 
1635
                        w->lower ();
 
1636
                }
 
1637
            }
 
1638
        }
 
1639
        else if (event->xclient.message_type == Atoms::wmChangeState)
 
1640
        {
 
1641
            w = findWindow (event->xclient.window);
 
1642
            if (w)
 
1643
            {
 
1644
                if (event->xclient.data.l[0] == IconicState)
 
1645
                {
 
1646
                    if (w->actions () & CompWindowActionMinimizeMask)
 
1647
                        w->minimize ();
 
1648
                }
 
1649
                else if (event->xclient.data.l[0] == NormalState)
 
1650
                {
 
1651
                    w->unminimize ();
 
1652
                }
 
1653
            }
 
1654
        }
 
1655
        else if (event->xclient.message_type == Atoms::showingDesktop)
 
1656
        {
 
1657
            if (event->xclient.window == priv->root ||
 
1658
                event->xclient.window == None)
 
1659
            {
 
1660
                if (event->xclient.data.l[0])
 
1661
                    enterShowDesktopMode ();
 
1662
                else
 
1663
                    leaveShowDesktopMode (NULL);
 
1664
            }
 
1665
        }
 
1666
        else if (event->xclient.message_type == Atoms::numberOfDesktops)
 
1667
        {
 
1668
            if (event->xclient.window == priv->root)
 
1669
            {
 
1670
                CompOption::Value value;
 
1671
 
 
1672
                value.set ((int) event->xclient.data.l[0]);
 
1673
 
 
1674
                setOptionForPlugin ("core", "number_of_desktops", value);
 
1675
            }
 
1676
        }
 
1677
        else if (event->xclient.message_type == Atoms::currentDesktop)
 
1678
        {
 
1679
            if (event->xclient.window == priv->root)
 
1680
                priv->setCurrentDesktop (event->xclient.data.l[0]);
 
1681
        }
 
1682
        else if (event->xclient.message_type == Atoms::winDesktop)
 
1683
        {
 
1684
            w = findWindow (event->xclient.window);
 
1685
            if (w)
 
1686
                w->setDesktop (event->xclient.data.l[0]);
 
1687
        }
 
1688
        else if (event->xclient.message_type == Atoms::wmFullscreenMonitors)
 
1689
        {
 
1690
            w = findWindow (event->xclient.window);
 
1691
            if (w)
 
1692
            {
 
1693
                CompFullscreenMonitorSet monitors;
 
1694
 
 
1695
                monitors.top    = event->xclient.data.l[0];
 
1696
                monitors.bottom = event->xclient.data.l[1];
 
1697
                monitors.left   = event->xclient.data.l[2];
 
1698
                monitors.right  = event->xclient.data.l[3];
 
1699
 
 
1700
                w->priv->setFullscreenMonitors (&monitors);
 
1701
            }
 
1702
        }
 
1703
        break;
 
1704
    case MappingNotify:
 
1705
        modHandler->updateModifierMappings ();
 
1706
        break;
 
1707
    case MapRequest:
 
1708
        w = screen->findWindow (event->xmaprequest.window);
 
1709
 
 
1710
        if (w)
 
1711
        {
 
1712
            XWindowAttributes attr;
 
1713
            bool              doMapProcessing = true;
 
1714
 
 
1715
            /* We should check the override_redirect flag here, because the
 
1716
               client might have changed it while being unmapped. */
 
1717
            if (XGetWindowAttributes (priv->dpy, w->id (), &attr))
 
1718
                w->priv->setOverrideRedirect (attr.override_redirect != 0);
 
1719
 
 
1720
            if (w->state () & CompWindowStateHiddenMask)
 
1721
                if (!w->minimized () && !w->inShowDesktopMode ())
 
1722
                    doMapProcessing = false;
 
1723
 
 
1724
            if (doMapProcessing)
 
1725
                w->priv->processMap ();
 
1726
 
 
1727
            w->priv->managed = true;
 
1728
 
 
1729
            setWindowProp (w->id (), Atoms::winDesktop, w->desktop ());
 
1730
        }
 
1731
        else
 
1732
        {
 
1733
            XMapWindow (priv->dpy, event->xmaprequest.window);
 
1734
        }
 
1735
        break;
 
1736
    case ConfigureRequest:
 
1737
        w = findWindow (event->xconfigurerequest.window);
 
1738
        if (w && w->managed ())
 
1739
        {
 
1740
            XWindowChanges xwc;
 
1741
 
 
1742
            memset (&xwc, 0, sizeof (xwc));
 
1743
 
 
1744
            xwc.x            = event->xconfigurerequest.x;
 
1745
            xwc.y            = event->xconfigurerequest.y;
 
1746
            xwc.width        = event->xconfigurerequest.width;
 
1747
            xwc.height       = event->xconfigurerequest.height;
 
1748
            xwc.border_width = event->xconfigurerequest.border_width;
 
1749
 
 
1750
            w->moveResize (&xwc, event->xconfigurerequest.value_mask,
 
1751
                           0, ClientTypeUnknown);
 
1752
 
 
1753
            if (event->xconfigurerequest.value_mask & CWStackMode)
 
1754
            {
 
1755
                Window     above    = None;
 
1756
                CompWindow *sibling = NULL;
 
1757
 
 
1758
                if (event->xconfigurerequest.value_mask & CWSibling)
 
1759
                {
 
1760
                    above   = event->xconfigurerequest.above;
 
1761
                    sibling = findTopLevelWindow (above);
 
1762
                }
 
1763
 
 
1764
                switch (event->xconfigurerequest.detail) {
 
1765
                case Above:
 
1766
                    if (w->priv->allowWindowFocus (NO_FOCUS_MASK, 0))
 
1767
                    {
 
1768
                        if (above)
 
1769
                        {
 
1770
                            if (sibling)
 
1771
                                w->restackAbove (sibling);
 
1772
                        }
 
1773
                        else
 
1774
                            w->raise ();
 
1775
                    }
 
1776
                    break;
 
1777
                case Below:
 
1778
                    if (above)
 
1779
                    {
 
1780
                        if (sibling)
 
1781
                            w->restackBelow (sibling);
 
1782
                    }
 
1783
                    else
 
1784
                        w->lower ();
 
1785
                    break;
 
1786
                default:
 
1787
                    /* no handling of the TopIf, BottomIf, Opposite cases -
 
1788
                       there will hardly be any client using that */
 
1789
                    break;
 
1790
                }
 
1791
            }
 
1792
        }
 
1793
        else
 
1794
        {
 
1795
            XWindowChanges xwc;
 
1796
            unsigned int   xwcm;
 
1797
 
 
1798
            xwcm = event->xconfigurerequest.value_mask &
 
1799
                (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
 
1800
 
 
1801
            xwc.x            = event->xconfigurerequest.x;
 
1802
            xwc.y            = event->xconfigurerequest.y;
 
1803
            xwc.width        = event->xconfigurerequest.width;
 
1804
            xwc.height       = event->xconfigurerequest.height;
 
1805
            xwc.border_width = event->xconfigurerequest.border_width;
 
1806
 
 
1807
            if (w)
 
1808
            {
 
1809
                /* Any window that receives a ConfigureRequest
 
1810
                 * is not override redirect, and may have changed
 
1811
                 * to being not override redirect */
 
1812
                w->priv->setOverrideRedirect (false);
 
1813
                w->configureXWindow (xwcm, &xwc);
 
1814
            }
 
1815
            else
 
1816
                XConfigureWindow (priv->dpy, event->xconfigurerequest.window,
 
1817
                                  xwcm, &xwc);
 
1818
        }
 
1819
        break;
 
1820
    case CirculateRequest:
 
1821
        break;
 
1822
    case FocusIn:
 
1823
    {
 
1824
        if (!XGetWindowAttributes (priv->dpy, event->xfocus.window, &wa))
 
1825
            priv->setDefaultWindowAttributes (&wa);
 
1826
 
 
1827
        /* If the call to XGetWindowAttributes failed it means
 
1828
         * the window was destroyed, so track the focus change
 
1829
         * anyways since we need to increment activeNum
 
1830
         * and the passive button grabs and then we will
 
1831
         * get the DestroyNotify later and change the focus
 
1832
         * there
 
1833
         */
 
1834
 
 
1835
        if (wa.root == priv->root)
 
1836
        {
 
1837
            if (event->xfocus.mode != NotifyGrab)
 
1838
            {
 
1839
                w = findTopLevelWindow (event->xfocus.window);
 
1840
                if (w && w->managed ())
 
1841
                {
 
1842
                    unsigned int state = w->state ();
 
1843
 
 
1844
                    if (w->id () != priv->activeWindow)
 
1845
                    {
 
1846
                        CompWindow     *active = screen->findWindow (priv->activeWindow);
 
1847
                        w->windowNotify (CompWindowNotifyFocusChange);
 
1848
 
 
1849
                        priv->activeWindow = w->id ();
 
1850
                        w->priv->activeNum = priv->activeNum++;
 
1851
 
 
1852
                        if (active)
 
1853
                            active->priv->updatePassiveButtonGrabs ();
 
1854
 
 
1855
                        w->priv->updatePassiveButtonGrabs ();
 
1856
 
 
1857
                        priv->addToCurrentActiveWindowHistory (w->id ());
 
1858
 
 
1859
                        XChangeProperty (priv->dpy , priv->root,
 
1860
                                         Atoms::winActive,
 
1861
                                         XA_WINDOW, 32, PropModeReplace,
 
1862
                                         (unsigned char *) &priv->activeWindow, 1);
 
1863
                    }
 
1864
 
 
1865
                    state &= ~CompWindowStateDemandsAttentionMask;
 
1866
                    w->changeState (state);
 
1867
 
 
1868
                    if (priv->nextActiveWindow == event->xfocus.window)
 
1869
                        priv->nextActiveWindow = None;
 
1870
                }
 
1871
                else if (event->xfocus.window == priv->root)
 
1872
                {
 
1873
                    /* Don't ever let the focus go to the root
 
1874
                     * window except in grab cases
 
1875
                     *
 
1876
                     * FIXME: There might be a case where we have to
 
1877
                     * handle root windows of other screens here, but
 
1878
                     * the other window managers should handle that
 
1879
                     */
 
1880
 
 
1881
                    if (event->xfocus.detail == NotifyDetailNone ||
 
1882
                        (event->xfocus.mode == NotifyNormal &&
 
1883
                         event->xfocus.detail == NotifyInferior))
 
1884
                    {
 
1885
                        priv->activeWindow = None;
 
1886
 
 
1887
                        if (event->xfocus.detail == NotifyDetailNone ||
 
1888
                            (event->xfocus.mode == NotifyNormal &&
 
1889
                             event->xfocus.detail == NotifyInferior))
 
1890
                        {
 
1891
                            screen->focusDefaultWindow ();
 
1892
                        }
 
1893
                    }
 
1894
                }
 
1895
            }
 
1896
            else
 
1897
                priv->grabbed = true;
 
1898
        }
 
1899
        else
 
1900
        {
 
1901
            CompWindow *w;
 
1902
 
 
1903
            w = screen->findWindow (priv->activeWindow);
 
1904
 
 
1905
            priv->nextActiveWindow = None;
 
1906
            priv->activeWindow = None;
 
1907
 
 
1908
            if (w)
 
1909
                w->priv->updatePassiveButtonGrabs ();
 
1910
        }
 
1911
    }
 
1912
    break;
 
1913
    case FocusOut:
 
1914
        if (event->xfocus.mode == NotifyUngrab)
 
1915
            priv->grabbed = false;
 
1916
        break;
 
1917
    case EnterNotify:
 
1918
        if (event->xcrossing.root == priv->root)
 
1919
            w = findTopLevelWindow (event->xcrossing.window);
 
1920
        else
 
1921
            w = NULL;
 
1922
 
 
1923
        if (w && w->id () != priv->below)
 
1924
        {
 
1925
            priv->below = w->id ();
 
1926
 
 
1927
            if (!priv->optionGetClickToFocus () &&
 
1928
                priv->grabs.empty ()                                 &&
 
1929
                event->xcrossing.mode   != NotifyGrab                &&
 
1930
                event->xcrossing.detail != NotifyInferior)
 
1931
            {
 
1932
                bool raise;
 
1933
                int  delay;
 
1934
 
 
1935
                raise = priv->optionGetAutoraise ();
 
1936
                delay = priv->optionGetAutoraiseDelay ();
 
1937
 
 
1938
                if (priv->autoRaiseTimer.active () &&
 
1939
                    priv->autoRaiseWindow != w->id ())
 
1940
                {
 
1941
                    priv->autoRaiseTimer.stop ();
 
1942
                }
 
1943
 
 
1944
                if (w->type () & ~(CompWindowTypeDockMask |
 
1945
                                   CompWindowTypeDesktopMask))
 
1946
                {
 
1947
                    w->moveInputFocusTo ();
 
1948
 
 
1949
                    if (raise)
 
1950
                    {
 
1951
                        if (delay > 0)
 
1952
                        {
 
1953
                            priv->autoRaiseWindow = w->id ();
 
1954
                            priv->autoRaiseTimer.start (
 
1955
                                boost::bind (autoRaiseTimeout, this),
 
1956
                                delay, (unsigned int) ((float) delay * 1.2));
 
1957
                        }
 
1958
                        else
 
1959
                        {
 
1960
                            CompStackingUpdateMode mode =
 
1961
                                CompStackingUpdateModeNormal;
 
1962
 
 
1963
                            w->updateAttributes (mode);
 
1964
                        }
 
1965
                    }
 
1966
                }
 
1967
            }
 
1968
        }
 
1969
        break;
 
1970
    case LeaveNotify:
 
1971
        if (event->xcrossing.detail != NotifyInferior)
 
1972
        {
 
1973
            if (event->xcrossing.window == priv->below)
 
1974
                priv->below = None;
 
1975
        }
 
1976
        break;
 
1977
    default:
 
1978
        if (priv->shapeExtension &&
 
1979
                 event->type == priv->shapeEvent + ShapeNotify)
 
1980
        {
 
1981
            w = findWindow (((XShapeEvent *) event)->window);
 
1982
            if (w)
 
1983
            {
 
1984
                if (w->mapNum ())
 
1985
                    w->priv->updateRegion ();
 
1986
            }
 
1987
        }
 
1988
        else if (event->type == priv->syncEvent + XSyncAlarmNotify)
 
1989
        {
 
1990
            XSyncAlarmNotifyEvent *sa;
 
1991
 
 
1992
            sa = (XSyncAlarmNotifyEvent *) event;
 
1993
 
 
1994
 
 
1995
            foreach (w, priv->windows)
 
1996
            {
 
1997
                if (w->priv->syncAlarm == sa->alarm)
 
1998
                {
 
1999
                    w->priv->handleSyncAlarm ();
 
2000
                    break;
 
2001
                }
 
2002
            }
 
2003
        }
 
2004
        break;
 
2005
    }
 
2006
}