~hypodermia/ubuntu/oneiric/compiz/fix-for-bug-301174

« back to all changes in this revision

Viewing changes to src/window.cpp.orig

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2011-04-15 17:08:40 UTC
  • mfrom: (0.168.6 upstream)
  • Revision ID: james.westby@ubuntu.com-20110415170840-x56m5m6qs4b7n8rb
Tags: 1:0.9.4+bzr20110415-0ubuntu1
* New upstream snapshot
  - Focus problem with Thunderbird (LP: #753951)
  - Chromium fullscreen + Alt-TAB confuses the launcher (LP: #757434)
  - compiz hangs randomly several times per day (LP: #740126)
* debian/patches/00_*:
  - removed as part of upstream tarball

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 <compiz.h>
 
27
 
 
28
#include <X11/Xlib.h>
 
29
#include <X11/Xatom.h>
 
30
#include <X11/Xproto.h>
 
31
#include <X11/extensions/shape.h>
 
32
 
 
33
#include <stdio.h>
 
34
#include <string.h>
 
35
#include <strings.h>
 
36
#include <stdlib.h>
 
37
#include <stdint.h>
 
38
#include <assert.h>
 
39
#include <math.h>
 
40
 
 
41
#include <boost/bind.hpp>
 
42
 
 
43
#include <core/core.h>
 
44
#include <core/icon.h>
 
45
#include <core/atoms.h>
 
46
#include "privatewindow.h"
 
47
#include "privatescreen.h"
 
48
 
 
49
PluginClassStorage::Indices windowPluginClassIndices (0);
 
50
 
 
51
unsigned int
 
52
CompWindow::allocPluginClassIndex ()
 
53
{
 
54
    unsigned int i = PluginClassStorage::allocatePluginClassIndex (windowPluginClassIndices);
 
55
 
 
56
    foreach (CompWindow *w, screen->windows ())
 
57
        if (windowPluginClassIndices.size () != w->pluginClasses.size ())
 
58
            w->pluginClasses.resize (windowPluginClassIndices.size ());
 
59
 
 
60
    return i;
 
61
}
 
62
 
 
63
void
 
64
CompWindow::freePluginClassIndex (unsigned int index)
 
65
{
 
66
    PluginClassStorage::freePluginClassIndex (windowPluginClassIndices, index);
 
67
 
 
68
    foreach (CompWindow *w, ::screen->windows ())
 
69
        if (windowPluginClassIndices.size () != w->pluginClasses.size ())
 
70
            w->pluginClasses.resize (windowPluginClassIndices.size ());
 
71
}
 
72
 
 
73
bool
 
74
PrivateWindow::isAncestorTo (CompWindow *transient,
 
75
                             CompWindow *ancestor)
 
76
{
 
77
    if (transient->priv->transientFor)
 
78
    {
 
79
        if (transient->priv->transientFor == ancestor->priv->id)
 
80
            return true;
 
81
 
 
82
        transient = screen->findWindow (transient->priv->transientFor);
 
83
        if (transient)
 
84
            return isAncestorTo (transient, ancestor);
 
85
    }
 
86
 
 
87
    return false;
 
88
}
 
89
 
 
90
void
 
91
PrivateWindow::recalcNormalHints ()
 
92
{
 
93
    int maxSize;
 
94
 
 
95
#warning fixme to max Texture size
 
96
    maxSize  = MAXSHORT;
 
97
    maxSize -= serverGeometry.border () * 2;
 
98
 
 
99
    sizeHints.x      = serverGeometry.x ();
 
100
    sizeHints.y      = serverGeometry.y ();
 
101
    sizeHints.width  = serverGeometry.width ();
 
102
    sizeHints.height = serverGeometry.height ();
 
103
 
 
104
    if (!(sizeHints.flags & PBaseSize))
 
105
    {
 
106
        if (sizeHints.flags & PMinSize)
 
107
        {
 
108
            sizeHints.base_width  = sizeHints.min_width;
 
109
            sizeHints.base_height = sizeHints.min_height;
 
110
        }
 
111
        else
 
112
        {
 
113
            sizeHints.base_width  = 0;
 
114
            sizeHints.base_height = 0;
 
115
        }
 
116
 
 
117
        sizeHints.flags |= PBaseSize;
 
118
    }
 
119
 
 
120
    if (!(sizeHints.flags & PMinSize))
 
121
    {
 
122
        sizeHints.min_width  = sizeHints.base_width;
 
123
        sizeHints.min_height = sizeHints.base_height;
 
124
        sizeHints.flags |= PMinSize;
 
125
    }
 
126
 
 
127
    if (!(sizeHints.flags & PMaxSize))
 
128
    {
 
129
        sizeHints.max_width  = 65535;
 
130
        sizeHints.max_height = 65535;
 
131
        sizeHints.flags |= PMaxSize;
 
132
    }
 
133
 
 
134
    if (sizeHints.max_width < sizeHints.min_width)
 
135
        sizeHints.max_width = sizeHints.min_width;
 
136
 
 
137
    if (sizeHints.max_height < sizeHints.min_height)
 
138
        sizeHints.max_height = sizeHints.min_height;
 
139
 
 
140
    if (sizeHints.min_width < 1)
 
141
        sizeHints.min_width = 1;
 
142
 
 
143
    if (sizeHints.max_width < 1)
 
144
        sizeHints.max_width = 1;
 
145
 
 
146
    if (sizeHints.min_height < 1)
 
147
        sizeHints.min_height = 1;
 
148
 
 
149
    if (sizeHints.max_height < 1)
 
150
        sizeHints.max_height = 1;
 
151
 
 
152
    if (sizeHints.max_width > maxSize)
 
153
        sizeHints.max_width = maxSize;
 
154
 
 
155
    if (sizeHints.max_height > maxSize)
 
156
        sizeHints.max_height = maxSize;
 
157
 
 
158
    if (sizeHints.min_width > maxSize)
 
159
        sizeHints.min_width = maxSize;
 
160
 
 
161
    if (sizeHints.min_height > maxSize)
 
162
        sizeHints.min_height = maxSize;
 
163
 
 
164
    if (sizeHints.base_width > maxSize)
 
165
        sizeHints.base_width = maxSize;
 
166
 
 
167
    if (sizeHints.base_height > maxSize)
 
168
        sizeHints.base_height = maxSize;
 
169
 
 
170
    if (sizeHints.flags & PResizeInc)
 
171
    {
 
172
        if (sizeHints.width_inc == 0)
 
173
            sizeHints.width_inc = 1;
 
174
 
 
175
        if (sizeHints.height_inc == 0)
 
176
            sizeHints.height_inc = 1;
 
177
    }
 
178
    else
 
179
    {
 
180
        sizeHints.width_inc  = 1;
 
181
        sizeHints.height_inc = 1;
 
182
        sizeHints.flags |= PResizeInc;
 
183
    }
 
184
 
 
185
    if (sizeHints.flags & PAspect)
 
186
    {
 
187
        /* don't divide by 0 */
 
188
        if (sizeHints.min_aspect.y < 1)
 
189
            sizeHints.min_aspect.y = 1;
 
190
 
 
191
        if (sizeHints.max_aspect.y < 1)
 
192
            sizeHints.max_aspect.y = 1;
 
193
    }
 
194
    else
 
195
    {
 
196
        sizeHints.min_aspect.x = 1;
 
197
        sizeHints.min_aspect.y = 65535;
 
198
        sizeHints.max_aspect.x = 65535;
 
199
        sizeHints.max_aspect.y = 1;
 
200
        sizeHints.flags |= PAspect;
 
201
    }
 
202
 
 
203
    if (!(sizeHints.flags & PWinGravity))
 
204
    {
 
205
        sizeHints.win_gravity = NorthWestGravity;
 
206
        sizeHints.flags |= PWinGravity;
 
207
    }
 
208
}
 
209
 
 
210
void
 
211
PrivateWindow::updateNormalHints ()
 
212
{
 
213
    Status status;
 
214
    long   supplied;
 
215
 
 
216
    status = XGetWMNormalHints (screen->dpy (), priv->id,
 
217
                                &priv->sizeHints, &supplied);
 
218
 
 
219
    if (!status)
 
220
        priv->sizeHints.flags = 0;
 
221
 
 
222
    priv->recalcNormalHints ();
 
223
}
 
224
 
 
225
void
 
226
PrivateWindow::updateWmHints ()
 
227
{
 
228
    XWMHints *newHints;
 
229
    long     dFlags = 0;
 
230
    bool     iconChanged = false;
 
231
 
 
232
    if (hints)
 
233
        dFlags = hints->flags;
 
234
 
 
235
    inputHint = true;
 
236
 
 
237
    newHints = XGetWMHints (screen->dpy (), id);
 
238
    if (newHints)
 
239
    {
 
240
        dFlags ^= newHints->flags;
 
241
 
 
242
        if (newHints->flags & InputHint)
 
243
            inputHint = newHints->input;
 
244
 
 
245
        if (hints)
 
246
        {
 
247
            if ((newHints->flags & IconPixmapHint) &&
 
248
                (hints->icon_pixmap != newHints->icon_pixmap))
 
249
            {
 
250
                iconChanged = true;
 
251
            }
 
252
            else if ((newHints->flags & IconMaskHint) &&
 
253
                     (hints->icon_mask != newHints->icon_mask))
 
254
            {
 
255
                iconChanged = true;
 
256
            }
 
257
        }
 
258
    }
 
259
 
 
260
    iconChanged |= (dFlags & (IconPixmapHint | IconMaskHint));
 
261
 
 
262
    if (iconChanged)
 
263
        freeIcons ();
 
264
 
 
265
    if (hints)
 
266
        XFree (hints);
 
267
 
 
268
    hints = newHints;
 
269
}
 
270
 
 
271
void
 
272
PrivateWindow::updateClassHints ()
 
273
{
 
274
    XClassHint classHint;
 
275
    int        status;
 
276
 
 
277
    if (priv->resName)
 
278
    {
 
279
        free (priv->resName);
 
280
        priv->resName = NULL;
 
281
    }
 
282
 
 
283
    if (priv->resClass)
 
284
    {
 
285
        free (priv->resClass);
 
286
        priv->resClass = NULL;
 
287
    }
 
288
 
 
289
    status = XGetClassHint (screen->dpy (),
 
290
                            priv->id, &classHint);
 
291
    if (status)
 
292
    {
 
293
        if (classHint.res_name)
 
294
        {
 
295
            priv->resName = strdup (classHint.res_name);
 
296
            XFree (classHint.res_name);
 
297
        }
 
298
 
 
299
        if (classHint.res_class)
 
300
        {
 
301
            priv->resClass = strdup (classHint.res_class);
 
302
            XFree (classHint.res_class);
 
303
        }
 
304
    }
 
305
}
 
306
 
 
307
void
 
308
PrivateWindow::updateTransientHint ()
 
309
{
 
310
    Window transientFor;
 
311
    Status status;
 
312
 
 
313
    priv->transientFor = None;
 
314
 
 
315
    status = XGetTransientForHint (screen->dpy (),
 
316
                                   priv->id, &transientFor);
 
317
 
 
318
    if (status)
 
319
    {
 
320
        CompWindow *ancestor;
 
321
 
 
322
        ancestor = screen->findWindow (transientFor);
 
323
        if (!ancestor)
 
324
            return;
 
325
 
 
326
        /* protect against circular transient dependencies */
 
327
        if (transientFor == priv->id ||
 
328
            PrivateWindow::isAncestorTo (ancestor, window))
 
329
            return;
 
330
 
 
331
        priv->transientFor = transientFor;
 
332
    }
 
333
}
 
334
 
 
335
void
 
336
PrivateWindow::updateIconGeometry ()
 
337
{
 
338
    Atom          actual;
 
339
    int           result, format;
 
340
    unsigned long n, left;
 
341
    unsigned char *data;
 
342
 
 
343
    priv->iconGeometry.setGeometry (0, 0, 0, 0);
 
344
 
 
345
    result = XGetWindowProperty (screen->dpy (), priv->id,
 
346
                                 Atoms::wmIconGeometry,
 
347
                                 0L, 1024L, False, XA_CARDINAL,
 
348
                                 &actual, &format, &n, &left, &data);
 
349
 
 
350
    if (result == Success && data)
 
351
    {
 
352
        if (n == 4)
 
353
        {
 
354
            unsigned long *geometry = (unsigned long *) data;
 
355
 
 
356
            priv->iconGeometry.setX (geometry[0]);
 
357
            priv->iconGeometry.setY (geometry[1]);
 
358
            priv->iconGeometry.setWidth (geometry[2]);
 
359
            priv->iconGeometry.setHeight (geometry[3]);
 
360
        }
 
361
 
 
362
        XFree (data);
 
363
    }
 
364
}
 
365
 
 
366
Window
 
367
PrivateWindow::getClientLeaderOfAncestor ()
 
368
{
 
369
    if (transientFor)
 
370
    {
 
371
        CompWindow *w = screen->findWindow (transientFor);
 
372
        if (w)
 
373
        {
 
374
            if (w->priv->clientLeader)
 
375
                return w->priv->clientLeader;
 
376
 
 
377
            return w->priv->getClientLeaderOfAncestor ();
 
378
        }
 
379
    }
 
380
 
 
381
    return None;
 
382
}
 
383
 
 
384
Window
 
385
PrivateWindow::getClientLeader ()
 
386
{
 
387
    Atom          actual;
 
388
    int           result, format;
 
389
    unsigned long n, left;
 
390
    unsigned char *data;
 
391
 
 
392
    result = XGetWindowProperty (screen->dpy (), priv->id,
 
393
                                 Atoms::wmClientLeader,
 
394
                                 0L, 1L, False, XA_WINDOW, &actual, &format,
 
395
                                 &n, &left, &data);
 
396
 
 
397
    if (result == Success && data)
 
398
    {
 
399
        Window win = None;
 
400
 
 
401
        if (n)
 
402
            memcpy (&win, data, sizeof (Window));
 
403
 
 
404
        XFree ((void *) data);
 
405
 
 
406
        if (win)
 
407
            return win;
 
408
    }
 
409
 
 
410
    return priv->getClientLeaderOfAncestor ();
 
411
}
 
412
 
 
413
char *
 
414
PrivateWindow::getStartupId ()
 
415
{
 
416
    Atom          actual;
 
417
    int           result, format;
 
418
    unsigned long n, left;
 
419
    unsigned char *data;
 
420
 
 
421
    result = XGetWindowProperty (screen->dpy (), priv->id,
 
422
                                 Atoms::startupId,
 
423
                                 0L, 1024L, False,
 
424
                                 Atoms::utf8String,
 
425
                                 &actual, &format,
 
426
                                 &n, &left, &data);
 
427
 
 
428
    if (result == Success && data)
 
429
    {
 
430
        char *id = NULL;
 
431
 
 
432
        if (n)
 
433
            id = strdup ((char *) data);
 
434
        XFree ((void *) data);
 
435
 
 
436
        return id;
 
437
    }
 
438
 
 
439
    return NULL;
 
440
}
 
441
 
 
442
void
 
443
PrivateWindow::setFullscreenMonitors (CompFullscreenMonitorSet *monitors)
 
444
{
 
445
    bool         hadFsMonitors = fullscreenMonitorsSet;
 
446
    unsigned int outputs = screen->outputDevs ().size ();
 
447
 
 
448
    fullscreenMonitorsSet = false;
 
449
 
 
450
    if (monitors                   &&
 
451
        (unsigned int) monitors->left   < outputs &&
 
452
        (unsigned int) monitors->right  < outputs &&
 
453
        (unsigned int) monitors->top    < outputs &&
 
454
        (unsigned int) monitors->bottom < outputs)
 
455
    {
 
456
        CompRect fsRect (screen->outputDevs ()[monitors->left].x1 (),
 
457
                         screen->outputDevs ()[monitors->top].y1 (),
 
458
                         screen->outputDevs ()[monitors->right].x2 (),
 
459
                         screen->outputDevs ()[monitors->bottom].y2 ());
 
460
 
 
461
        if (fsRect.x1 () < fsRect.x2 () && fsRect.y1 () < fsRect.y2 ())
 
462
        {
 
463
            fullscreenMonitorsSet = true;
 
464
            fullscreenMonitorRect = fsRect;
 
465
        }
 
466
    }
 
467
 
 
468
    if (fullscreenMonitorsSet)
 
469
    {
 
470
        long data[4];
 
471
 
 
472
        data[0] = monitors->top;
 
473
        data[1] = monitors->bottom;
 
474
        data[2] = monitors->left;
 
475
        data[3] = monitors->right;
 
476
 
 
477
        XChangeProperty (screen->dpy (), id, Atoms::wmFullscreenMonitors,
 
478
                         XA_CARDINAL, 32, PropModeReplace,
 
479
                         (unsigned char *) data, 4);
 
480
    }
 
481
    else if (hadFsMonitors)
 
482
    {
 
483
        XDeleteProperty (screen->dpy (), id, Atoms::wmFullscreenMonitors);
 
484
    }
 
485
 
 
486
    if (state & CompWindowStateFullscreenMask)
 
487
        if (fullscreenMonitorsSet || hadFsMonitors)
 
488
            window->updateAttributes (CompStackingUpdateModeNone);
 
489
}
 
490
 
 
491
void
 
492
CompWindow::changeState (unsigned int newState)
 
493
{
 
494
    unsigned int oldState;
 
495
 
 
496
    if (priv->state == newState)
 
497
        return;
 
498
 
 
499
    oldState = priv->state;
 
500
    priv->state = newState;
 
501
 
 
502
    recalcType ();
 
503
    recalcActions ();
 
504
 
 
505
    if (priv->managed)
 
506
        screen->priv->setWindowState (priv->state, priv->id);
 
507
 
 
508
    stateChangeNotify (oldState);
 
509
    screen->matchPropertyChanged (this);
 
510
}
 
511
 
 
512
static void
 
513
setWindowActions (CompScreen   *s,
 
514
                  unsigned int actions,
 
515
                  Window       id)
 
516
{
 
517
    Atom data[32];
 
518
    int  i = 0;
 
519
 
 
520
    if (actions & CompWindowActionMoveMask)
 
521
        data[i++] = Atoms::winActionMove;
 
522
    if (actions & CompWindowActionResizeMask)
 
523
        data[i++] = Atoms::winActionResize;
 
524
    if (actions & CompWindowActionStickMask)
 
525
        data[i++] = Atoms::winActionStick;
 
526
    if (actions & CompWindowActionMinimizeMask)
 
527
        data[i++] = Atoms::winActionMinimize;
 
528
    if (actions & CompWindowActionMaximizeHorzMask)
 
529
        data[i++] = Atoms::winActionMaximizeHorz;
 
530
    if (actions & CompWindowActionMaximizeVertMask)
 
531
        data[i++] = Atoms::winActionMaximizeVert;
 
532
    if (actions & CompWindowActionFullscreenMask)
 
533
        data[i++] = Atoms::winActionFullscreen;
 
534
    if (actions & CompWindowActionCloseMask)
 
535
        data[i++] = Atoms::winActionClose;
 
536
    if (actions & CompWindowActionShadeMask)
 
537
        data[i++] = Atoms::winActionShade;
 
538
    if (actions & CompWindowActionChangeDesktopMask)
 
539
        data[i++] = Atoms::winActionChangeDesktop;
 
540
    if (actions & CompWindowActionAboveMask)
 
541
        data[i++] = Atoms::winActionAbove;
 
542
    if (actions & CompWindowActionBelowMask)
 
543
        data[i++] = Atoms::winActionBelow;
 
544
 
 
545
    XChangeProperty (s->dpy (), id, Atoms::wmAllowedActions,
 
546
                     XA_ATOM, 32, PropModeReplace,
 
547
                     (unsigned char *) data, i);
 
548
}
 
549
 
 
550
void
 
551
CompWindow::recalcActions ()
 
552
{
 
553
    unsigned int actions = 0;
 
554
    unsigned int setActions, clearActions;
 
555
 
 
556
    switch (priv->type) {
 
557
    case CompWindowTypeFullscreenMask:
 
558
    case CompWindowTypeNormalMask:
 
559
        actions =
 
560
            CompWindowActionMaximizeHorzMask |
 
561
            CompWindowActionMaximizeVertMask |
 
562
            CompWindowActionFullscreenMask   |
 
563
            CompWindowActionMoveMask         |
 
564
            CompWindowActionResizeMask       |
 
565
            CompWindowActionStickMask        |
 
566
            CompWindowActionMinimizeMask     |
 
567
            CompWindowActionCloseMask        |
 
568
            CompWindowActionChangeDesktopMask;
 
569
        break;
 
570
    case CompWindowTypeUtilMask:
 
571
    case CompWindowTypeMenuMask:
 
572
    case CompWindowTypeToolbarMask:
 
573
        actions =
 
574
            CompWindowActionMoveMask   |
 
575
            CompWindowActionResizeMask |
 
576
            CompWindowActionStickMask  |
 
577
            CompWindowActionCloseMask  |
 
578
            CompWindowActionChangeDesktopMask;
 
579
        break;
 
580
    case CompWindowTypeDialogMask:
 
581
    case CompWindowTypeModalDialogMask:
 
582
        actions =
 
583
            CompWindowActionMaximizeHorzMask |
 
584
            CompWindowActionMaximizeVertMask |
 
585
            CompWindowActionMoveMask         |
 
586
            CompWindowActionResizeMask       |
 
587
            CompWindowActionStickMask        |
 
588
            CompWindowActionCloseMask        |
 
589
            CompWindowActionChangeDesktopMask;
 
590
 
 
591
        /* allow minimization for dialog windows if they
 
592
           a) are not a transient (transients can be minimized
 
593
              with their parent)
 
594
           b) don't have the skip taskbar hint set (as those
 
595
              have no target to be minimized to)
 
596
        */
 
597
        if (!priv->transientFor &&
 
598
            !(priv->state & CompWindowStateSkipTaskbarMask))
 
599
        {
 
600
            actions |= CompWindowActionMinimizeMask;
 
601
        }
 
602
    default:
 
603
        break;
 
604
    }
 
605
 
 
606
    if (priv->input.top)
 
607
        actions |= CompWindowActionShadeMask;
 
608
 
 
609
    actions |= (CompWindowActionAboveMask | CompWindowActionBelowMask);
 
610
 
 
611
    switch (priv->wmType) {
 
612
    case CompWindowTypeNormalMask:
 
613
        actions |= CompWindowActionFullscreenMask |
 
614
                   CompWindowActionMinimizeMask;
 
615
    default:
 
616
        break;
 
617
    }
 
618
 
 
619
    if (priv->sizeHints.min_width  == priv->sizeHints.max_width &&
 
620
        priv->sizeHints.min_height == priv->sizeHints.max_height)
 
621
        actions &= ~(CompWindowActionResizeMask       |
 
622
                     CompWindowActionMaximizeHorzMask |
 
623
                     CompWindowActionMaximizeVertMask |
 
624
                     CompWindowActionFullscreenMask);
 
625
 
 
626
    if (!(priv->mwmFunc & MwmFuncAll))
 
627
    {
 
628
        if (!(priv->mwmFunc & MwmFuncResize))
 
629
            actions &= ~(CompWindowActionResizeMask       |
 
630
                         CompWindowActionMaximizeHorzMask |
 
631
                         CompWindowActionMaximizeVertMask |
 
632
                         CompWindowActionFullscreenMask);
 
633
 
 
634
        if (!(priv->mwmFunc & MwmFuncMove))
 
635
            actions &= ~(CompWindowActionMoveMask         |
 
636
                         CompWindowActionMaximizeHorzMask |
 
637
                         CompWindowActionMaximizeVertMask |
 
638
                         CompWindowActionFullscreenMask);
 
639
 
 
640
        if (!(priv->mwmFunc & MwmFuncIconify))
 
641
            actions &= ~CompWindowActionMinimizeMask;
 
642
 
 
643
        if (!(priv->mwmFunc & MwmFuncClose))
 
644
            actions &= ~CompWindowActionCloseMask;
 
645
    }
 
646
 
 
647
    getAllowedActions (setActions, clearActions);
 
648
    actions &= ~clearActions;
 
649
    actions |= setActions;
 
650
 
 
651
    if (actions != priv->actions)
 
652
    {
 
653
        priv->actions = actions;
 
654
        setWindowActions (screen, actions, priv->id);
 
655
    }
 
656
}
 
657
 
 
658
void
 
659
CompWindow::getAllowedActions (unsigned int &setActions,
 
660
                               unsigned int &clearActions)
 
661
{
 
662
    WRAPABLE_HND_FUNC (1, getAllowedActions, setActions, clearActions)
 
663
 
 
664
    setActions   = 0;
 
665
    clearActions = 0;
 
666
}
 
667
 
 
668
unsigned int
 
669
CompWindow::constrainWindowState (unsigned int state,
 
670
                                  unsigned int actions)
 
671
{
 
672
    if (!(actions & CompWindowActionMaximizeHorzMask))
 
673
        state &= ~CompWindowStateMaximizedHorzMask;
 
674
 
 
675
    if (!(actions & CompWindowActionMaximizeVertMask))
 
676
        state &= ~CompWindowStateMaximizedVertMask;
 
677
 
 
678
    if (!(actions & CompWindowActionShadeMask))
 
679
        state &= ~CompWindowStateShadedMask;
 
680
 
 
681
    if (!(actions & CompWindowActionFullscreenMask))
 
682
        state &= ~CompWindowStateFullscreenMask;
 
683
 
 
684
    return state;
 
685
}
 
686
 
 
687
unsigned int
 
688
PrivateWindow::windowTypeFromString (const char *str)
 
689
{
 
690
    if (strcasecmp (str, "desktop") == 0)
 
691
        return CompWindowTypeDesktopMask;
 
692
    else if (strcasecmp (str, "dock") == 0)
 
693
        return CompWindowTypeDockMask;
 
694
    else if (strcasecmp (str, "toolbar") == 0)
 
695
        return CompWindowTypeToolbarMask;
 
696
    else if (strcasecmp (str, "menu") == 0)
 
697
        return CompWindowTypeMenuMask;
 
698
    else if (strcasecmp (str, "utility") == 0)
 
699
        return CompWindowTypeUtilMask;
 
700
    else if (strcasecmp (str, "splash") == 0)
 
701
        return CompWindowTypeSplashMask;
 
702
    else if (strcasecmp (str, "dialog") == 0)
 
703
        return CompWindowTypeDialogMask;
 
704
    else if (strcasecmp (str, "normal") == 0)
 
705
        return CompWindowTypeNormalMask;
 
706
    else if (strcasecmp (str, "dropdownmenu") == 0)
 
707
        return CompWindowTypeDropdownMenuMask;
 
708
    else if (strcasecmp (str, "popupmenu") == 0)
 
709
        return CompWindowTypePopupMenuMask;
 
710
    else if (strcasecmp (str, "tooltip") == 0)
 
711
        return CompWindowTypeTooltipMask;
 
712
    else if (strcasecmp (str, "notification") == 0)
 
713
        return CompWindowTypeNotificationMask;
 
714
    else if (strcasecmp (str, "combo") == 0)
 
715
        return CompWindowTypeComboMask;
 
716
    else if (strcasecmp (str, "dnd") == 0)
 
717
        return CompWindowTypeDndMask;
 
718
    else if (strcasecmp (str, "modaldialog") == 0)
 
719
        return CompWindowTypeModalDialogMask;
 
720
    else if (strcasecmp (str, "fullscreen") == 0)
 
721
        return CompWindowTypeFullscreenMask;
 
722
    else if (strcasecmp (str, "unknown") == 0)
 
723
        return CompWindowTypeUnknownMask;
 
724
    else if (strcasecmp (str, "any") == 0)
 
725
        return ~0;
 
726
 
 
727
    return 0;
 
728
}
 
729
 
 
730
void
 
731
CompWindow::recalcType ()
 
732
{
 
733
    unsigned int type;
 
734
 
 
735
    type = priv->wmType;
 
736
 
 
737
    if (!overrideRedirect () && priv->wmType == CompWindowTypeUnknownMask)
 
738
        type = CompWindowTypeNormalMask;
 
739
 
 
740
    if (priv->state & CompWindowStateFullscreenMask)
 
741
        type = CompWindowTypeFullscreenMask;
 
742
 
 
743
    if (type == CompWindowTypeNormalMask)
 
744
    {
 
745
        if (priv->transientFor)
 
746
            type = CompWindowTypeDialogMask;
 
747
    }
 
748
 
 
749
    if (type == CompWindowTypeDockMask &&
 
750
        (priv->state & CompWindowStateBelowMask))
 
751
    {
 
752
        type = CompWindowTypeNormalMask;
 
753
    }
 
754
 
 
755
    if ((type & (CompWindowTypeNormalMask | CompWindowTypeDialogMask)) &&
 
756
        (priv->state & CompWindowStateModalMask))
 
757
    {
 
758
        type = CompWindowTypeModalDialogMask;
 
759
    }
 
760
 
 
761
    priv->type = type;
 
762
}
 
763
 
 
764
 
 
765
void
 
766
PrivateWindow::updateFrameWindow ()
 
767
{
 
768
    if (!frame)
 
769
        return;
 
770
 
 
771
    if (input.left || input.right || input.top || input.bottom)
 
772
    {
 
773
        int        x, y, width, height;
 
774
        int        bw = serverGeometry.border () * 2;
 
775
 
 
776
        x      = serverGeometry.x () - input.left;
 
777
        y      = serverGeometry.y () - input.top;
 
778
        width  = serverGeometry.width () + input.left + input.right + bw;
 
779
        height = serverGeometry.height () + input.top  + input.bottom + bw;
 
780
 
 
781
        if (shaded)
 
782
            height = input.top + input.bottom;
 
783
 
 
784
        XMoveResizeWindow (screen->dpy (), frame, x, y, width, height);
 
785
        if (shaded)
 
786
        {
 
787
            XUnmapWindow (screen->dpy (), wrapper);
 
788
        }
 
789
        else
 
790
        {
 
791
            XMapWindow (screen->dpy (), wrapper);
 
792
            XMoveResizeWindow (screen->dpy (), wrapper, input.left, input.top,
 
793
                               serverGeometry.width (), serverGeometry.height ());
 
794
        }
 
795
        XMoveResizeWindow (screen->dpy (), id, 0, 0,
 
796
                           serverGeometry.width (), serverGeometry.height ());
 
797
        window->sendConfigureNotify ();
 
798
 
 
799
        window->updateFrameRegion ();
 
800
        window->windowNotify (CompWindowNotifyFrameUpdate);
 
801
    }
 
802
    else
 
803
    {
 
804
        int        x, y, width, height;
 
805
        int        bw = serverGeometry.border () * 2;
 
806
 
 
807
        x      = serverGeometry.x ();
 
808
        y      = serverGeometry.y ();
 
809
        width  = serverGeometry.width () + bw;
 
810
        height = serverGeometry.height () + bw;
 
811
 
 
812
        if (shaded)
 
813
            height = 0;
 
814
 
 
815
        XMoveResizeWindow (screen->dpy (), frame, x, y, width, height);
 
816
        if (shaded)
 
817
        {
 
818
            XUnmapWindow (screen->dpy (), wrapper);
 
819
        }
 
820
        else
 
821
        {
 
822
            XMapWindow (screen->dpy (), wrapper);
 
823
            XMoveResizeWindow (screen->dpy (), wrapper, 0, 0,
 
824
                               serverGeometry.width (), serverGeometry.height ());
 
825
        }
 
826
        XMoveResizeWindow (screen->dpy (), id, 0, 0,
 
827
                           serverGeometry.width (), serverGeometry.height ());
 
828
        window->sendConfigureNotify ();
 
829
        frameRegion = CompRegion ();
 
830
        window->windowNotify (CompWindowNotifyFrameUpdate);
 
831
    }
 
832
 
 
833
    window->recalcActions ();
 
834
}
 
835
 
 
836
 
 
837
 
 
838
void
 
839
CompWindow::updateWindowOutputExtents ()
 
840
{
 
841
    CompWindowExtents output (priv->output);
 
842
 
 
843
    getOutputExtents (output);
 
844
 
 
845
    if (output.left   != priv->output.left  ||
 
846
        output.right  != priv->output.right ||
 
847
        output.top    != priv->output.top   ||
 
848
        output.bottom != priv->output.bottom)
 
849
    {
 
850
        priv->output = output;
 
851
 
 
852
        resizeNotify (0, 0, 0, 0);
 
853
    }
 
854
}
 
855
 
 
856
void
 
857
CompWindow::getOutputExtents (CompWindowExtents& output)
 
858
{
 
859
    WRAPABLE_HND_FUNC (0, getOutputExtents, output)
 
860
 
 
861
    output.left   = 0;
 
862
    output.right  = 0;
 
863
    output.top    = 0;
 
864
    output.bottom = 0;
 
865
}
 
866
 
 
867
CompRegion
 
868
PrivateWindow::rectsToRegion (unsigned int n, XRectangle *rects)
 
869
{
 
870
    CompRegion ret;
 
871
    int        x1, x2, y1, y2;
 
872
 
 
873
    for (unsigned int i = 0; i < n; i++)
 
874
    {
 
875
        x1 = rects[i].x + priv->attrib.border_width;
 
876
        y1 = rects[i].y + priv->attrib.border_width;
 
877
        x2 = x1 + rects[i].width;
 
878
        y2 = y1 + rects[i].height;
 
879
 
 
880
        if (x1 < 0)
 
881
            x1 = 0;
 
882
        if (y1 < 0)
 
883
            y1 = 0;
 
884
        if (x2 > priv->width)
 
885
            x2 = priv->width;
 
886
        if (y2 > priv->height)
 
887
            y2 = priv->height;
 
888
 
 
889
        if (y1 < y2 && x1 < x2)
 
890
        {
 
891
            x1 += priv->attrib.x;
 
892
            y1 += priv->attrib.y;
 
893
            x2 += priv->attrib.x;
 
894
            y2 += priv->attrib.y;
 
895
 
 
896
            ret += CompRect (x1, y1, x2 - x1, y2 - y1);
 
897
        }
 
898
    }
 
899
 
 
900
    return ret;
 
901
}
 
902
 
 
903
/* TODO: This function should be able to check the XShape event
 
904
 * kind and only get/set shape rectangles for either ShapeInput
 
905
 * or ShapeBounding, but not both at the same time
 
906
 */
 
907
 
 
908
void
 
909
PrivateWindow::updateRegion ()
 
910
{
 
911
    XRectangle r, *boundingShapeRects = NULL;
 
912
    XRectangle *inputShapeRects = NULL;
 
913
    int        nBounding = 0, nInput = 0;
 
914
 
 
915
    priv->region = CompRegion ();
 
916
    priv->inputRegion = CompRegion ();
 
917
 
 
918
    if (screen->XShape ())
 
919
    {
 
920
        int order;
 
921
 
 
922
        boundingShapeRects = XShapeGetRectangles (screen->dpy (), priv->id,
 
923
                                                  ShapeBounding, &nBounding, &order);
 
924
        inputShapeRects = XShapeGetRectangles (screen->dpy (), priv->id,
 
925
                                               ShapeInput, &nInput, &order);
 
926
 
 
927
    }
 
928
 
 
929
    r.x      = -priv->attrib.border_width;
 
930
    r.y      = -priv->attrib.border_width;
 
931
    r.width  = priv->width + priv->attrib.border_width;
 
932
    r.height = priv->height + priv->attrib.border_width;
 
933
 
 
934
    if (nBounding < 1)
 
935
    {
 
936
        boundingShapeRects = &r;
 
937
        nBounding = 1;
 
938
    }
 
939
 
 
940
    if (nInput < 1)
 
941
    {
 
942
        inputShapeRects = &r;
 
943
        nBounding = 1;
 
944
    }
 
945
 
 
946
    priv->region += rectsToRegion (nBounding, boundingShapeRects);
 
947
    priv->inputRegion += rectsToRegion (nInput, inputShapeRects);
 
948
 
 
949
    if (boundingShapeRects && boundingShapeRects != &r)
 
950
        XFree (boundingShapeRects);
 
951
    if (inputShapeRects && inputShapeRects != &r)
 
952
        XFree (inputShapeRects);
 
953
 
 
954
    window->updateFrameRegion ();
 
955
}
 
956
 
 
957
bool
 
958
CompWindow::updateStruts ()
 
959
{
 
960
    Atom          actual;
 
961
    int           result, format;
 
962
    unsigned long n, left;
 
963
    unsigned char *data;
 
964
    bool          hasOld, hasNew;
 
965
    CompStruts    oldStrut, newStrut;
 
966
 
 
967
    if (priv->struts)
 
968
    {
 
969
        hasOld = true;
 
970
 
 
971
        oldStrut.left   = priv->struts->left;
 
972
        oldStrut.right  = priv->struts->right;
 
973
        oldStrut.top    = priv->struts->top;
 
974
        oldStrut.bottom = priv->struts->bottom;
 
975
    }
 
976
    else
 
977
    {
 
978
        hasOld = false;
 
979
    }
 
980
 
 
981
    hasNew = false;
 
982
 
 
983
    newStrut.left.x         = 0;
 
984
    newStrut.left.y         = 0;
 
985
    newStrut.left.width  = 0;
 
986
    newStrut.left.height = screen->height ();
 
987
 
 
988
    newStrut.right.x      = screen->width ();
 
989
    newStrut.right.y      = 0;
 
990
    newStrut.right.width  = 0;
 
991
    newStrut.right.height = screen->height ();
 
992
 
 
993
    newStrut.top.x         = 0;
 
994
    newStrut.top.y         = 0;
 
995
    newStrut.top.width  = screen->width ();
 
996
    newStrut.top.height = 0;
 
997
 
 
998
    newStrut.bottom.x      = 0;
 
999
    newStrut.bottom.y      = screen->height ();
 
1000
    newStrut.bottom.width  = screen->width ();
 
1001
    newStrut.bottom.height = 0;
 
1002
 
 
1003
    result = XGetWindowProperty (screen->dpy (), priv->id,
 
1004
                                 Atoms::wmStrutPartial,
 
1005
                                 0L, 12L, false, XA_CARDINAL, &actual, &format,
 
1006
                                 &n, &left, &data);
 
1007
 
 
1008
    if (result == Success && data)
 
1009
    {
 
1010
        unsigned long *struts = (unsigned long *) data;
 
1011
 
 
1012
        if (n == 12)
 
1013
        {
 
1014
            hasNew = true;
 
1015
 
 
1016
            newStrut.left.y        = struts[4];
 
1017
            newStrut.left.width    = struts[0];
 
1018
            newStrut.left.height   = struts[5] - newStrut.left.y + 1;
 
1019
 
 
1020
            newStrut.right.width   = struts[1];
 
1021
            newStrut.right.x       = screen->width () - newStrut.right.width;
 
1022
            newStrut.right.y       = struts[6];
 
1023
            newStrut.right.height  = struts[7] - newStrut.right.y + 1;
 
1024
 
 
1025
            newStrut.top.x         = struts[8];
 
1026
            newStrut.top.width     = struts[9] - newStrut.top.x + 1;
 
1027
            newStrut.top.height    = struts[2];
 
1028
 
 
1029
            newStrut.bottom.x      = struts[10];
 
1030
            newStrut.bottom.width  = struts[11] - newStrut.bottom.x + 1;
 
1031
            newStrut.bottom.height = struts[3];
 
1032
            newStrut.bottom.y      = screen->height () - newStrut.bottom.height;
 
1033
        }
 
1034
 
 
1035
        XFree (data);
 
1036
    }
 
1037
 
 
1038
    if (!hasNew)
 
1039
    {
 
1040
        result = XGetWindowProperty (screen->dpy (), priv->id,
 
1041
                                     Atoms::wmStrut,
 
1042
                                     0L, 4L, false, XA_CARDINAL,
 
1043
                                     &actual, &format, &n, &left, &data);
 
1044
 
 
1045
        if (result == Success && data)
 
1046
        {
 
1047
            unsigned long *struts = (unsigned long *) data;
 
1048
 
 
1049
            if (n == 4)
 
1050
            {
 
1051
                hasNew = true;
 
1052
 
 
1053
                newStrut.left.x        = 0;
 
1054
                newStrut.left.width    = struts[0];
 
1055
 
 
1056
                newStrut.right.width   = struts[1];
 
1057
                newStrut.right.x       = screen->width () - newStrut.right.width;
 
1058
 
 
1059
                newStrut.top.y         = 0;
 
1060
                newStrut.top.height    = struts[2];
 
1061
 
 
1062
                newStrut.bottom.height = struts[3];
 
1063
                newStrut.bottom.y      = screen->height () - newStrut.bottom.height;
 
1064
            }
 
1065
 
 
1066
            XFree (data);
 
1067
        }
 
1068
    }
 
1069
 
 
1070
    if (hasNew)
 
1071
    {
 
1072
        int strutX1, strutY1, strutX2, strutY2;
 
1073
        int x1, y1, x2, y2;
 
1074
 
 
1075
        /* applications expect us to clip struts to xinerama edges */
 
1076
        for (unsigned int i = 0;
 
1077
             i < screen->screenInfo ().size (); i++)
 
1078
        {
 
1079
            x1 = screen->screenInfo ()[i].x_org;
 
1080
            y1 = screen->screenInfo ()[i].y_org;
 
1081
            x2 = x1 + screen->screenInfo ()[i].width;
 
1082
            y2 = y1 + screen->screenInfo ()[i].height;
 
1083
 
 
1084
            strutX1 = newStrut.left.x;
 
1085
            strutX2 = strutX1 + newStrut.left.width;
 
1086
            strutY1 = newStrut.left.y;
 
1087
            strutY2 = strutY1 + newStrut.left.height;
 
1088
 
 
1089
            if (strutX2 > x1 && strutX2 <= x2 &&
 
1090
                strutY1 < y2 && strutY2 > y1)
 
1091
            {
 
1092
                newStrut.left.x     = x1;
 
1093
                newStrut.left.width = strutX2 - x1;
 
1094
            }
 
1095
 
 
1096
            strutX1 = newStrut.right.x;
 
1097
            strutX2 = strutX1 + newStrut.right.width;
 
1098
            strutY1 = newStrut.right.y;
 
1099
            strutY2 = strutY1 + newStrut.right.height;
 
1100
 
 
1101
            if (strutX1 > x1 && strutX1 <= x2 &&
 
1102
                strutY1 < y2 && strutY2 > y1)
 
1103
            {
 
1104
                newStrut.right.x     = strutX1;
 
1105
                newStrut.right.width = x2 - strutX1;
 
1106
            }
 
1107
 
 
1108
            strutX1 = newStrut.top.x;
 
1109
            strutX2 = strutX1 + newStrut.top.width;
 
1110
            strutY1 = newStrut.top.y;
 
1111
            strutY2 = strutY1 + newStrut.top.height;
 
1112
 
 
1113
            if (strutX1 < x2 && strutX2 > x1 &&
 
1114
                strutY2 > y1 && strutY2 <= y2)
 
1115
            {
 
1116
                newStrut.top.y      = y1;
 
1117
                newStrut.top.height = strutY2 - y1;
 
1118
            }
 
1119
 
 
1120
            strutX1 = newStrut.bottom.x;
 
1121
            strutX2 = strutX1 + newStrut.bottom.width;
 
1122
            strutY1 = newStrut.bottom.y;
 
1123
            strutY2 = strutY1 + newStrut.bottom.height;
 
1124
 
 
1125
            if (strutX1 < x2 && strutX2 > x1 &&
 
1126
                strutY1 > y1 && strutY1 <= y2)
 
1127
            {
 
1128
                newStrut.bottom.y      = strutY1;
 
1129
                newStrut.bottom.height = y2 - strutY1;
 
1130
            }
 
1131
        }
 
1132
    }
 
1133
 
 
1134
    if (hasOld != hasNew ||
 
1135
        (hasNew && hasOld &&
 
1136
         memcmp (&newStrut, &oldStrut, sizeof (CompStruts))))
 
1137
    {
 
1138
        if (hasNew)
 
1139
        {
 
1140
            if (!priv->struts)
 
1141
            {
 
1142
                priv->struts = (CompStruts *) malloc (sizeof (CompStruts));
 
1143
                if (!priv->struts)
 
1144
                    return false;
 
1145
            }
 
1146
 
 
1147
            *priv->struts = newStrut;
 
1148
        }
 
1149
        else
 
1150
        {
 
1151
            free (priv->struts);
 
1152
            priv->struts = NULL;
 
1153
        }
 
1154
 
 
1155
        return true;
 
1156
    }
 
1157
 
 
1158
    return false;
 
1159
}
 
1160
 
 
1161
void
 
1162
CompWindow::incrementDestroyReference ()
 
1163
{
 
1164
    priv->destroyRefCnt++;
 
1165
}
 
1166
 
 
1167
void
 
1168
CompWindow::destroy ()
 
1169
{
 
1170
    windowNotify (CompWindowNotifyBeforeDestroy);
 
1171
 
 
1172
    screen->priv->eraseWindowFromMap (id ());
 
1173
 
 
1174
    priv->id = 1;
 
1175
    priv->mapNum = 0;
 
1176
 
 
1177
    priv->destroyRefCnt--;
 
1178
    if (priv->destroyRefCnt)
 
1179
        return;
 
1180
 
 
1181
 
 
1182
    if (!priv->destroyed)
 
1183
    {
 
1184
        priv->destroyed = true;
 
1185
        screen->priv->pendingDestroys++;
 
1186
    }
 
1187
 
 
1188
    if (priv->frame)
 
1189
        priv->unreparent ();
 
1190
 
 
1191
}
 
1192
 
 
1193
void
 
1194
CompWindow::sendConfigureNotify ()
 
1195
{
 
1196
    XConfigureEvent xev;
 
1197
 
 
1198
    xev.type   = ConfigureNotify;
 
1199
    xev.event  = priv->id;
 
1200
    xev.window = priv->id;
 
1201
 
 
1202
    /* normally we should never send configure notify events to override
 
1203
       redirect windows but if they support the _NET_WM_SYNC_REQUEST
 
1204
       protocol we need to do this when the window is mapped. however the
 
1205
       only way we can make sure that the attributes we send are correct
 
1206
       and is to grab the server. */
 
1207
    if (priv->attrib.override_redirect)
 
1208
    {
 
1209
        XWindowAttributes attrib;
 
1210
 
 
1211
        XGrabServer (screen->dpy ());
 
1212
 
 
1213
        if (XGetWindowAttributes (screen->dpy (), priv->id, &attrib))
 
1214
        {
 
1215
            xev.x            = attrib.x;
 
1216
            xev.y            = attrib.y;
 
1217
            xev.width        = attrib.width;
 
1218
            xev.height       = attrib.height;
 
1219
            xev.border_width = attrib.border_width;
 
1220
 
 
1221
            xev.above             = (prev) ? prev->priv->id : None;
 
1222
            xev.override_redirect = true;
 
1223
 
 
1224
            XSendEvent (screen->dpy (), priv->id, false,
 
1225
                        StructureNotifyMask, (XEvent *) &xev);
 
1226
        }
 
1227
 
 
1228
        XUngrabServer (screen->dpy ());
 
1229
        XSync (screen->dpy (), false);
 
1230
    }
 
1231
    else
 
1232
    {
 
1233
        xev.x            = priv->serverGeometry.x ();
 
1234
        xev.y            = priv->serverGeometry.y ();
 
1235
        xev.width        = priv->serverGeometry.width ();
 
1236
        xev.height       = priv->serverGeometry.height ();
 
1237
        xev.border_width = priv->serverGeometry.border ();
 
1238
 
 
1239
        xev.above             = (prev) ? prev->priv->id : None;
 
1240
        xev.override_redirect = priv->attrib.override_redirect;
 
1241
 
 
1242
        XSendEvent (screen->dpy (), priv->id, false,
 
1243
                    StructureNotifyMask, (XEvent *) &xev);
 
1244
    }
 
1245
}
 
1246
 
 
1247
void
 
1248
CompWindow::map ()
 
1249
{
 
1250
    windowNotify (CompWindowNotifyBeforeMap);
 
1251
 
 
1252
    if (!isViewable ())
 
1253
    {
 
1254
        if (priv->pendingMaps > 0)
 
1255
            priv->pendingMaps = 0;
 
1256
 
 
1257
        priv->mapNum = screen->priv->mapNum++;
 
1258
 
 
1259
        if (priv->struts)
 
1260
            screen->updateWorkarea ();
 
1261
 
 
1262
        if (windowClass () == InputOnly)
 
1263
            return;
 
1264
 
 
1265
        priv->unmapRefCnt = 1;
 
1266
 
 
1267
        priv->attrib.map_state = IsViewable;
 
1268
 
 
1269
        if (!overrideRedirect ())
 
1270
            screen->priv->setWmState (NormalState, priv->id);
 
1271
 
 
1272
        priv->invisible  = true;
 
1273
        priv->alive      = true;
 
1274
 
 
1275
        priv->lastPong = screen->priv->lastPing;
 
1276
 
 
1277
        priv->updateRegion ();
 
1278
        priv->updateSize ();
 
1279
 
 
1280
        screen->priv->updateClientList ();
 
1281
 
 
1282
        if (priv->type & CompWindowTypeDesktopMask)
 
1283
            screen->priv->desktopWindowCount++;
 
1284
 
 
1285
        if (priv->protocols & CompWindowProtocolSyncRequestMask)
 
1286
        {
 
1287
            sendSyncRequest ();
 
1288
            sendConfigureNotify ();
 
1289
        }
 
1290
 
 
1291
        if (!overrideRedirect ())
 
1292
        {
 
1293
            /* been shaded */
 
1294
            if (!priv->height)
 
1295
                resize (priv->attrib.x, priv->attrib.y, priv->attrib.width,
 
1296
                        ++priv->attrib.height - 1, priv->attrib.border_width);
 
1297
        }
 
1298
    }
 
1299
 
 
1300
    windowNotify (CompWindowNotifyMap);
 
1301
}
 
1302
 
 
1303
void
 
1304
CompWindow::incrementUnmapReference ()
 
1305
{
 
1306
    priv->unmapRefCnt++;
 
1307
}
 
1308
 
 
1309
void
 
1310
CompWindow::unmap ()
 
1311
{
 
1312
    windowNotify (CompWindowNotifyBeforeUnmap);
 
1313
 
 
1314
    if (priv->mapNum)
 
1315
        priv->mapNum = 0;
 
1316
 
 
1317
    priv->unmapRefCnt--;
 
1318
    if (priv->unmapRefCnt > 0)
 
1319
        return;
 
1320
 
 
1321
    if (priv->unmanaging)
 
1322
    {
 
1323
        XWindowChanges xwc;
 
1324
        unsigned int   xwcm;
 
1325
        int                gravity = priv->sizeHints.win_gravity;
 
1326
 
 
1327
        if (priv->frame)
 
1328
            priv->unreparent ();
 
1329
 
 
1330
        /* revert gravity adjustment made at MapNotify time */
 
1331
        xwc.x   = priv->serverGeometry.x ();
 
1332
        xwc.y   = priv->serverGeometry.y ();
 
1333
        xwc.width   = 0;
 
1334
        xwc.height  = 0;
 
1335
 
 
1336
        xwcm = priv->adjustConfigureRequestForGravity (&xwc,
 
1337
                                                       CWX | CWY,
 
1338
                                                       gravity,
 
1339
                                                       -1);
 
1340
        if (xwcm)
 
1341
            configureXWindow (xwcm, &xwc);
 
1342
 
 
1343
        priv->unmanaging = false;
 
1344
    }
 
1345
 
 
1346
    if (priv->struts)
 
1347
        screen->updateWorkarea ();
 
1348
 
 
1349
    if (priv->attrib.map_state != IsViewable)
 
1350
        return;
 
1351
 
 
1352
    if (priv->type == CompWindowTypeDesktopMask)
 
1353
        screen->priv->desktopWindowCount--;
 
1354
 
 
1355
    priv->attrib.map_state = IsUnmapped;
 
1356
 
 
1357
    priv->invisible = true;
 
1358
 
 
1359
    if (priv->shaded && priv->height)
 
1360
        resize (priv->attrib.x, priv->attrib.y,
 
1361
                priv->attrib.width, ++priv->attrib.height - 1,
 
1362
                priv->attrib.border_width);
 
1363
 
 
1364
    screen->priv->updateClientList ();
 
1365
 
 
1366
    windowNotify (CompWindowNotifyUnmap);
 
1367
}
 
1368
 
 
1369
void
 
1370
PrivateWindow::withdraw ()
 
1371
{
 
1372
    if (!attrib.override_redirect)
 
1373
        screen->priv->setWmState (WithdrawnState, id);
 
1374
 
 
1375
    placed     = false;
 
1376
    unmanaging = managed;
 
1377
    managed    = false;
 
1378
}
 
1379
 
 
1380
bool
 
1381
PrivateWindow::restack (Window aboveId)
 
1382
{
 
1383
    if (aboveId && (aboveId == id || aboveId == frame))
 
1384
        // Don't try to raise a window above itself
 
1385
        return false;
 
1386
    else if (window->prev)
 
1387
    {
 
1388
        if (aboveId && (aboveId == window->prev->id () ||
 
1389
                        aboveId == window->prev->frame ()))
 
1390
            return false;
 
1391
    }
 
1392
    else if (aboveId == None && !window->next)
 
1393
        return false;
 
1394
 
 
1395
    if (aboveId && !screen->findTopLevelWindow (aboveId, true))
 
1396
        return false;
 
1397
 
 
1398
    screen->unhookWindow (window);
 
1399
    screen->insertWindow (window, aboveId);
 
1400
 
 
1401
    screen->priv->updateClientList ();
 
1402
 
 
1403
    window->windowNotify (CompWindowNotifyRestack);
 
1404
 
 
1405
    return true;
 
1406
}
 
1407
 
 
1408
bool
 
1409
CompWindow::resize (XWindowAttributes attr)
 
1410
{
 
1411
    return resize (Geometry (attr.x, attr.y, attr.width, attr.height,
 
1412
                             attr.border_width));
 
1413
}
 
1414
 
 
1415
bool
 
1416
CompWindow::resize (int          x,
 
1417
                    int          y,
 
1418
                    int          width,
 
1419
                    int          height,
 
1420
                    int          border)
 
1421
{
 
1422
    return resize (Geometry (x, y, width, height, border));
 
1423
}
 
1424
 
 
1425
bool
 
1426
CompWindow::resize (CompWindow::Geometry gm)
 
1427
{
 
1428
    if (priv->attrib.width        != gm.width ()  ||
 
1429
        priv->attrib.height       != gm.height () ||
 
1430
        priv->attrib.border_width != gm.border ())
 
1431
    {
 
1432
        int pw, ph;
 
1433
        int dx, dy, dwidth, dheight;
 
1434
 
 
1435
        pw = gm.width () + gm.border () * 2;
 
1436
        ph = gm.height () + gm.border () * 2;
 
1437
 
 
1438
        if (priv->shaded)
 
1439
            ph = 0;
 
1440
 
 
1441
        dx      = gm.x () - priv->attrib.x;
 
1442
        dy      = gm.y () - priv->attrib.y;
 
1443
        dwidth  = gm.width () - priv->attrib.width;
 
1444
        dheight = gm.height () - priv->attrib.height;
 
1445
 
 
1446
        priv->attrib.x            = gm.x ();
 
1447
        priv->attrib.y            = gm.y ();
 
1448
        priv->attrib.width        = gm.width ();
 
1449
        priv->attrib.height       = gm.height ();
 
1450
        priv->attrib.border_width = gm.border ();
 
1451
 
 
1452
        priv->geometry.set (priv->attrib.x, priv->attrib.y,
 
1453
                            priv->attrib.width, priv->attrib.height,
 
1454
                            priv->attrib.border_width);
 
1455
 
 
1456
        priv->width = pw;
 
1457
        priv->height = ph;
 
1458
 
 
1459
        if (priv->mapNum)
 
1460
            priv->updateRegion ();
 
1461
 
 
1462
        resizeNotify (dx, dy, dwidth, dheight);
 
1463
 
 
1464
        priv->invisible = WINDOW_INVISIBLE (priv);
 
1465
        priv->updateFrameWindow ();
 
1466
    }
 
1467
    else if (priv->attrib.x != gm.x () || priv->attrib.y != gm.y ())
 
1468
    {
 
1469
        int dx, dy;
 
1470
 
 
1471
        dx = gm.x () - priv->attrib.x;
 
1472
        dy = gm.y () - priv->attrib.y;
 
1473
 
 
1474
        move (dx, dy);
 
1475
    }
 
1476
 
 
1477
    return true;
 
1478
}
 
1479
 
 
1480
static void
 
1481
syncValueIncrement (XSyncValue *value)
 
1482
{
 
1483
    XSyncValue one;
 
1484
    int        overflow;
 
1485
 
 
1486
    XSyncIntToValue (&one, 1);
 
1487
    XSyncValueAdd (value, *value, one, &overflow);
 
1488
}
 
1489
 
 
1490
bool
 
1491
PrivateWindow::initializeSyncCounter ()
 
1492
{
 
1493
    XSyncAlarmAttributes values;
 
1494
    Atom                 actual;
 
1495
    int                  result, format;
 
1496
    unsigned long        n, left;
 
1497
    unsigned char        *data;
 
1498
 
 
1499
    if (syncCounter)
 
1500
        return syncAlarm != None;
 
1501
 
 
1502
    if (!(protocols & CompWindowProtocolSyncRequestMask))
 
1503
        return false;
 
1504
 
 
1505
    result = XGetWindowProperty (screen->dpy (), id,
 
1506
                                 Atoms::wmSyncRequestCounter,
 
1507
                                 0L, 1L, false, XA_CARDINAL, &actual, &format,
 
1508
                                 &n, &left, &data);
 
1509
 
 
1510
    if (result == Success && n && data)
 
1511
    {
 
1512
        unsigned long *counter = (unsigned long *) data;
 
1513
 
 
1514
        syncCounter = *counter;
 
1515
 
 
1516
        XFree (data);
 
1517
 
 
1518
        XSyncIntsToValue (&syncValue, (unsigned int) rand (), 0);
 
1519
        XSyncSetCounter (screen->dpy (),
 
1520
                         syncCounter,
 
1521
                         syncValue);
 
1522
 
 
1523
        syncValueIncrement (&syncValue);
 
1524
 
 
1525
        values.events = true;
 
1526
 
 
1527
        values.trigger.counter    = syncCounter;
 
1528
        values.trigger.wait_value = syncValue;
 
1529
 
 
1530
        values.trigger.value_type = XSyncAbsolute;
 
1531
        values.trigger.test_type  = XSyncPositiveComparison;
 
1532
 
 
1533
        XSyncIntToValue (&values.delta, 1);
 
1534
 
 
1535
        values.events = true;
 
1536
 
 
1537
        CompScreen::checkForError (screen->dpy ());
 
1538
 
 
1539
        /* Note that by default, the alarm increments the trigger value
 
1540
         * when it fires until the condition (counter.value < trigger.value)
 
1541
         * is false again.
 
1542
         */
 
1543
        syncAlarm = XSyncCreateAlarm (screen->dpy (),
 
1544
                                      XSyncCACounter   |
 
1545
                                      XSyncCAValue     |
 
1546
                                      XSyncCAValueType |
 
1547
                                      XSyncCATestType  |
 
1548
                                      XSyncCADelta     |
 
1549
                                      XSyncCAEvents,
 
1550
                                      &values);
 
1551
 
 
1552
        if (CompScreen::checkForError (screen->dpy ()))
 
1553
            return true;
 
1554
 
 
1555
        XSyncDestroyAlarm (screen->dpy (), syncAlarm);
 
1556
        syncAlarm = None;
 
1557
    }
 
1558
    else if (result == Success && data)
 
1559
    {
 
1560
        XFree (data);
 
1561
    }
 
1562
 
 
1563
    return false;
 
1564
}
 
1565
 
 
1566
void
 
1567
CompWindow::sendSyncRequest ()
 
1568
{
 
1569
    XClientMessageEvent xev;
 
1570
 
 
1571
    if (priv->syncWait)
 
1572
        return;
 
1573
 
 
1574
    if (!priv->initializeSyncCounter ())
 
1575
        return;
 
1576
 
 
1577
    xev.type         = ClientMessage;
 
1578
    xev.window       = priv->id;
 
1579
    xev.message_type = Atoms::wmProtocols;
 
1580
    xev.format       = 32;
 
1581
    xev.data.l[0]    = Atoms::wmSyncRequest;
 
1582
    xev.data.l[1]    = CurrentTime;
 
1583
    xev.data.l[2]    = XSyncValueLow32 (priv->syncValue);
 
1584
    xev.data.l[3]    = XSyncValueHigh32 (priv->syncValue);
 
1585
    xev.data.l[4]    = 0;
 
1586
 
 
1587
    syncValueIncrement (&priv->syncValue);
 
1588
 
 
1589
    XSendEvent (screen->dpy (), priv->id, false, 0, (XEvent *) &xev);
 
1590
 
 
1591
    priv->syncWait     = true;
 
1592
    priv->syncGeometry = priv->serverGeometry;
 
1593
 
 
1594
    if (!priv->syncWaitTimer.active ())
 
1595
        priv->syncWaitTimer.start ();
 
1596
}
 
1597
 
 
1598
void
 
1599
PrivateWindow::configure (XConfigureEvent *ce)
 
1600
{
 
1601
    if (priv->frame)
 
1602
        return;
 
1603
 
 
1604
    priv->attrib.override_redirect = ce->override_redirect;
 
1605
 
 
1606
    if (priv->syncWait)
 
1607
    {
 
1608
        priv->syncGeometry.set (ce->x, ce->y, ce->width, ce->height,
 
1609
                                ce->border_width);
 
1610
    }
 
1611
    else
 
1612
    {
 
1613
        if (ce->override_redirect)
 
1614
        {
 
1615
            priv->serverGeometry.set (ce->x, ce->y, ce->width, ce->height,
 
1616
                                      ce->border_width);
 
1617
        }
 
1618
 
 
1619
        window->resize (ce->x, ce->y, ce->width, ce->height, ce->border_width);
 
1620
    }
 
1621
 
 
1622
    if (ce->event == screen->root ())
 
1623
        priv->restack (ce->above);
 
1624
}
 
1625
 
 
1626
void
 
1627
PrivateWindow::configureFrame (XConfigureEvent *ce)
 
1628
{
 
1629
    int x, y, width, height;
 
1630
    CompWindow       *above;
 
1631
 
 
1632
    if (!priv->frame)
 
1633
        return;
 
1634
 
 
1635
    x      = ce->x + priv->input.left;
 
1636
    y      = ce->y + priv->input.top;
 
1637
    width  = ce->width - priv->serverGeometry.border () * 2 - priv->input.left - priv->input.right;
 
1638
    height = ce->height - priv->serverGeometry.border () * 2 - priv->input.top - priv->input.bottom;
 
1639
 
 
1640
    if (priv->syncWait)
 
1641
    {
 
1642
        priv->syncGeometry.set (x, y, width, height, ce->border_width);
 
1643
    }
 
1644
    else
 
1645
    {
 
1646
        if (ce->override_redirect)
 
1647
        {
 
1648
            priv->serverGeometry.set (x, y, width, height, ce->border_width);
 
1649
        }
 
1650
 
 
1651
        window->resize (x, y, width, height, ce->border_width);
 
1652
    }
 
1653
 
 
1654
    if (priv->restack (ce->above))
 
1655
        priv->updatePassiveButtonGrabs ();
 
1656
 
 
1657
    above = screen->findWindow (ce->above);
 
1658
 
 
1659
    if (above)
 
1660
        above->priv->updatePassiveButtonGrabs ();
 
1661
}
 
1662
 
 
1663
void
 
1664
PrivateWindow::circulate (XCirculateEvent *ce)
 
1665
{
 
1666
    Window newAboveId;
 
1667
 
 
1668
    if (ce->place == PlaceOnTop)
 
1669
        newAboveId = screen->priv->getTopWindow ();
 
1670
    else
 
1671
        newAboveId = 0;
 
1672
 
 
1673
    priv->restack (newAboveId);
 
1674
}
 
1675
 
 
1676
void
 
1677
CompWindow::move (int  dx,
 
1678
                  int  dy,
 
1679
                  bool immediate)
 
1680
{
 
1681
    if (dx || dy)
 
1682
    {
 
1683
        priv->attrib.x += dx;
 
1684
        priv->attrib.y += dy;
 
1685
 
 
1686
        priv->geometry.setX (priv->attrib.x);
 
1687
        priv->geometry.setY (priv->attrib.y);
 
1688
 
 
1689
        priv->region.translate (dx, dy);
 
1690
        priv->inputRegion.translate (dx, dy);
 
1691
        if (!priv->frameRegion.isEmpty ())
 
1692
            priv->frameRegion.translate (dx, dy);
 
1693
 
 
1694
        priv->invisible = WINDOW_INVISIBLE (priv);
 
1695
 
 
1696
        moveNotify (dx, dy, immediate);
 
1697
    }
 
1698
}
 
1699
 
 
1700
void
 
1701
CompWindow::syncPosition ()
 
1702
{
 
1703
    priv->serverGeometry.setX (priv->attrib.x);
 
1704
    priv->serverGeometry.setY (priv->attrib.y);
 
1705
 
 
1706
    XMoveWindow (screen->dpy (), ROOTPARENT (this),
 
1707
                 priv->attrib.x - priv->input.left,
 
1708
                 priv->attrib.y - priv->input.top);
 
1709
 
 
1710
    if (priv->frame)
 
1711
    {
 
1712
        XMoveWindow (screen->dpy (), priv->wrapper,
 
1713
                     priv->input.left, priv->input.top);
 
1714
        sendConfigureNotify ();
 
1715
    }
 
1716
}
 
1717
 
 
1718
bool
 
1719
CompWindow::focus ()
 
1720
{
 
1721
    WRAPABLE_HND_FUNC_RETURN (2, bool, focus)
 
1722
 
 
1723
    if (overrideRedirect ())
 
1724
        return false;
 
1725
 
 
1726
    if (!priv->managed || priv->unmanaging)
 
1727
        return false;
 
1728
 
 
1729
    if (!onCurrentDesktop ())
 
1730
        return false;
 
1731
 
 
1732
    if (priv->destroyed)
 
1733
        return false;
 
1734
 
 
1735
    if (!priv->shaded && (priv->state & CompWindowStateHiddenMask))
 
1736
        return false;
 
1737
 
 
1738
    if (priv->attrib.x + priv->width  <= 0      ||
 
1739
        priv->attrib.y + priv->height <= 0      ||
 
1740
        priv->attrib.x >= (int) screen->width ()||
 
1741
        priv->attrib.y >= (int) screen->height ())
 
1742
        return false;
 
1743
 
 
1744
    return true;
 
1745
}
 
1746
 
 
1747
bool
 
1748
CompWindow::place (CompPoint &pos)
 
1749
{
 
1750
    WRAPABLE_HND_FUNC_RETURN (4, bool, place, pos)
 
1751
    return false;
 
1752
}
 
1753
 
 
1754
void
 
1755
CompWindow::validateResizeRequest (unsigned int   &mask,
 
1756
                                   XWindowChanges *xwc,
 
1757
                                   unsigned int   source)
 
1758
{
 
1759
    WRAPABLE_HND_FUNC (5, validateResizeRequest, mask, xwc, source)
 
1760
 
 
1761
    if (!(priv->type & (CompWindowTypeDockMask    |
 
1762
                     CompWindowTypeFullscreenMask |
 
1763
                     CompWindowTypeUnknownMask)))
 
1764
    {
 
1765
        if (mask & CWY)
 
1766
        {
 
1767
            int min, max;
 
1768
 
 
1769
            min = screen->workArea ().y () + priv->input.top;
 
1770
            max = screen->workArea ().bottom ();
 
1771
 
 
1772
            if (priv->state & CompWindowStateStickyMask &&
 
1773
                 (xwc->y < min || xwc->y > max))
 
1774
            {
 
1775
                xwc->y = priv->serverGeometry.y ();
 
1776
            }
 
1777
            else
 
1778
            {
 
1779
                min -= screen->vp ().y () * screen->height ();
 
1780
                max += (screen->vpSize ().height () - screen->vp ().y () - 1) *
 
1781
                        screen->height ();
 
1782
 
 
1783
                if (xwc->y < min)
 
1784
                    xwc->y = min;
 
1785
                else if (xwc->y > max)
 
1786
                    xwc->y = max;
 
1787
            }
 
1788
        }
 
1789
 
 
1790
        if (mask & CWX)
 
1791
        {
 
1792
            int min, max;
 
1793
 
 
1794
            min = screen->workArea ().x () + priv->input.left;
 
1795
            max = screen->workArea ().right ();
 
1796
 
 
1797
            if (priv->state & CompWindowStateStickyMask &&
 
1798
                (xwc->x < min || xwc->x > max))
 
1799
            {
 
1800
                xwc->x = priv->serverGeometry.x ();
 
1801
            }
 
1802
            else
 
1803
            {
 
1804
                min -= screen->vp ().x () * screen->width ();
 
1805
                max += (screen->vpSize ().width () - screen->vp ().x () - 1) *
 
1806
                        screen->width ();
 
1807
 
 
1808
                if (xwc->x < min)
 
1809
                    xwc->x = min;
 
1810
                else if (xwc->x > max)
 
1811
                    xwc->x = max;
 
1812
            }
 
1813
        }
 
1814
    }
 
1815
}
 
1816
 
 
1817
void
 
1818
CompWindow::resizeNotify (int dx,
 
1819
                          int dy,
 
1820
                          int dwidth,
 
1821
                          int dheight)
 
1822
    WRAPABLE_HND_FUNC (6, resizeNotify, dx, dy, dwidth, dheight)
 
1823
 
 
1824
void
 
1825
CompWindow::moveNotify (int  dx,
 
1826
                        int  dy,
 
1827
                        bool immediate)
 
1828
    WRAPABLE_HND_FUNC (7, moveNotify, dx, dy, immediate)
 
1829
 
 
1830
void
 
1831
CompWindow::windowNotify (CompWindowNotify n)
 
1832
    WRAPABLE_HND_FUNC (8, windowNotify, n)
 
1833
 
 
1834
void
 
1835
CompWindow::grabNotify (int          x,
 
1836
                        int          y,
 
1837
                        unsigned int state,
 
1838
                        unsigned int mask)
 
1839
{
 
1840
    WRAPABLE_HND_FUNC (9, grabNotify, x, y, state, mask)
 
1841
    priv->grabbed = true;
 
1842
}
 
1843
 
 
1844
void
 
1845
CompWindow::ungrabNotify ()
 
1846
{
 
1847
    WRAPABLE_HND_FUNC (10, ungrabNotify)
 
1848
    priv->grabbed = false;
 
1849
}
 
1850
 
 
1851
void
 
1852
CompWindow::stateChangeNotify (unsigned int lastState)
 
1853
{
 
1854
    WRAPABLE_HND_FUNC (11, stateChangeNotify, lastState);
 
1855
 
 
1856
    /* if being made sticky */
 
1857
    if (!(lastState & CompWindowStateStickyMask) &&
 
1858
        (priv->state & CompWindowStateStickyMask))
 
1859
    {
 
1860
        CompPoint vp;   /* index of the window's vp */
 
1861
 
 
1862
        /* Find which viewport the window falls in,
 
1863
           and check if it's the current viewport */
 
1864
        vp = defaultViewport ();
 
1865
        if (screen->vp () != vp)
 
1866
        {
 
1867
            int moveX = (screen->vp ().x () - vp.x ()) * screen->width ();
 
1868
            int moveY = (screen->vp ().y () - vp.y ()) * screen->height ();
 
1869
 
 
1870
            move (moveX, moveY, TRUE);
 
1871
            syncPosition ();
 
1872
        }
 
1873
    }
 
1874
}
 
1875
 
 
1876
 
 
1877
bool
 
1878
PrivateWindow::isGroupTransient (Window clientLeader)
 
1879
{
 
1880
    if (!clientLeader)
 
1881
        return false;
 
1882
 
 
1883
    if (transientFor == None || transientFor == screen->root ())
 
1884
    {
 
1885
        if (type & (CompWindowTypeUtilMask    |
 
1886
                    CompWindowTypeToolbarMask |
 
1887
                    CompWindowTypeMenuMask    |
 
1888
                    CompWindowTypeDialogMask  |
 
1889
                    CompWindowTypeModalDialogMask))
 
1890
        {
 
1891
            if (this->clientLeader == clientLeader)
 
1892
                return true;
 
1893
        }
 
1894
    }
 
1895
 
 
1896
    return false;
 
1897
}
 
1898
 
 
1899
CompWindow *
 
1900
PrivateWindow::getModalTransient ()
 
1901
{
 
1902
    CompWindow *w, *modalTransient;
 
1903
 
 
1904
    modalTransient = window;
 
1905
 
 
1906
    for (w = screen->windows ().back (); w; w = w->prev)
 
1907
    {
 
1908
        if (w == modalTransient || w->priv->mapNum == 0)
 
1909
            continue;
 
1910
 
 
1911
        if (w->priv->transientFor == modalTransient->priv->id)
 
1912
        {
 
1913
            if (w->priv->state & CompWindowStateModalMask)
 
1914
            {
 
1915
                modalTransient = w;
 
1916
                w = screen->windows ().back ();
 
1917
            }
 
1918
        }
 
1919
    }
 
1920
 
 
1921
    if (modalTransient == window)
 
1922
    {
 
1923
        /* don't look for group transients with modal state if current window
 
1924
           has modal state */
 
1925
        if (state & CompWindowStateModalMask)
 
1926
            return NULL;
 
1927
 
 
1928
        for (w = screen->windows ().back (); w; w = w->prev)
 
1929
        {
 
1930
            if (w == modalTransient || w->priv->mapNum == 0)
 
1931
                continue;
 
1932
 
 
1933
            if (isAncestorTo (modalTransient, w))
 
1934
                continue;
 
1935
 
 
1936
            if (w->priv->isGroupTransient (modalTransient->priv->clientLeader))
 
1937
            {
 
1938
                if (w->priv->state & CompWindowStateModalMask)
 
1939
                {
 
1940
                    modalTransient = w;
 
1941
                    w = w->priv->getModalTransient ();
 
1942
                    if (w)
 
1943
                        modalTransient = w;
 
1944
 
 
1945
                    break;
 
1946
                }
 
1947
            }
 
1948
        }
 
1949
    }
 
1950
 
 
1951
    if (modalTransient == window)
 
1952
        modalTransient = NULL;
 
1953
 
 
1954
    return modalTransient;
 
1955
}
 
1956
 
 
1957
void
 
1958
CompWindow::moveInputFocusTo ()
 
1959
{
 
1960
    CompScreen  *s = screen;
 
1961
    CompWindow  *modalTransient;
 
1962
 
 
1963
    modalTransient = priv->getModalTransient ();
 
1964
    if (modalTransient)
 
1965
        return modalTransient->moveInputFocusTo ();
 
1966
 
 
1967
    if (priv->state & CompWindowStateHiddenMask)
 
1968
    {
 
1969
        XSetInputFocus (s->dpy (), priv->frame,
 
1970
                        RevertToPointerRoot, CurrentTime);
 
1971
        XChangeProperty (s->dpy (), s->root (), Atoms::winActive,
 
1972
                         XA_WINDOW, 32, PropModeReplace,
 
1973
                         (unsigned char *) &priv->id, 1);
 
1974
    }
 
1975
    else
 
1976
    {
 
1977
        bool setFocus = false;
 
1978
 
 
1979
        if (priv->inputHint)
 
1980
        {
 
1981
            XSetInputFocus (s->dpy (), priv->id, RevertToPointerRoot,
 
1982
                            CurrentTime);
 
1983
            setFocus = true;
 
1984
        }
 
1985
 
 
1986
        if (priv->protocols & CompWindowProtocolTakeFocusMask)
 
1987
        {
 
1988
            XEvent ev;
 
1989
 
 
1990
            ev.type                 = ClientMessage;
 
1991
            ev.xclient.window       = priv->id;
 
1992
            ev.xclient.message_type = Atoms::wmProtocols;
 
1993
            ev.xclient.format       = 32;
 
1994
            ev.xclient.data.l[0]    = Atoms::wmTakeFocus;
 
1995
            ev.xclient.data.l[1]    = s->getCurrentTime ();
 
1996
            ev.xclient.data.l[2]    = 0;
 
1997
            ev.xclient.data.l[3]    = 0;
 
1998
            ev.xclient.data.l[4]    = 0;
 
1999
 
 
2000
            XSendEvent (s->dpy (), priv->id, false, NoEventMask, &ev);
 
2001
 
 
2002
            setFocus = true;
 
2003
        }
 
2004
 
 
2005
        if (setFocus)
 
2006
            screen->priv->nextActiveWindow = priv->id;
 
2007
 
 
2008
        if (!setFocus && !modalTransient)
 
2009
        {
 
2010
            CompWindow *ancestor;
 
2011
 
 
2012
            /* move input to closest ancestor */
 
2013
            for (ancestor = s->windows ().front (); ancestor;
 
2014
                 ancestor = ancestor->next)
 
2015
            {
 
2016
                if (PrivateWindow::isAncestorTo (this, ancestor))
 
2017
                {
 
2018
                    ancestor->moveInputFocusTo ();
 
2019
                    break;
 
2020
                }
 
2021
            }
 
2022
        }
 
2023
    }
 
2024
}
 
2025
 
 
2026
void
 
2027
CompWindow::moveInputFocusToOtherWindow ()
 
2028
{
 
2029
    if (priv->id == screen->activeWindow () ||
 
2030
        priv->id == screen->priv->nextActiveWindow)
 
2031
    {
 
2032
        CompWindow *ancestor;
 
2033
 
 
2034
        if (priv->transientFor && priv->transientFor != screen->root ())
 
2035
        {
 
2036
            ancestor = screen->findWindow (priv->transientFor);
 
2037
            if (ancestor &&
 
2038
                ancestor->focus () &&
 
2039
                !(ancestor->priv->type & (CompWindowTypeDesktopMask |
 
2040
                                          CompWindowTypeDockMask)))
 
2041
            {
 
2042
                ancestor->moveInputFocusTo ();
 
2043
            }
 
2044
            else
 
2045
                screen->focusDefaultWindow ();
 
2046
        }
 
2047
        else if (priv->type & (CompWindowTypeDialogMask |
 
2048
                               CompWindowTypeModalDialogMask))
 
2049
        {
 
2050
            CompWindow *a, *focus = NULL;
 
2051
 
 
2052
            for (a = screen->windows ().back (); a; a = a->prev)
 
2053
            {
 
2054
                if (a->priv->clientLeader == priv->clientLeader)
 
2055
                {
 
2056
                    if (a->focus ())
 
2057
                    {
 
2058
                        if (focus)
 
2059
                        {
 
2060
                            if (a->priv->type & (CompWindowTypeNormalMask |
 
2061
                                                 CompWindowTypeDialogMask |
 
2062
                                                 CompWindowTypeModalDialogMask))
 
2063
                            {
 
2064
                                if (priv->compareWindowActiveness (focus, a) < 0)
 
2065
                                    focus = a;
 
2066
                            }
 
2067
                        }
 
2068
                        else
 
2069
                            focus = a;
 
2070
                    }
 
2071
                }
 
2072
            }
 
2073
 
 
2074
            if (focus && !(focus->priv->type & (CompWindowTypeDesktopMask |
 
2075
                                                CompWindowTypeDockMask)))
 
2076
            {
 
2077
                focus->moveInputFocusTo ();
 
2078
            }
 
2079
            else
 
2080
                screen->focusDefaultWindow ();
 
2081
        }
 
2082
        else
 
2083
            screen->focusDefaultWindow ();
 
2084
    }
 
2085
}
 
2086
 
 
2087
 
 
2088
bool
 
2089
PrivateWindow::stackLayerCheck (CompWindow *w,
 
2090
                                Window      clientLeader,
 
2091
                                CompWindow *below)
 
2092
{
 
2093
    if (isAncestorTo (w, below))
 
2094
        return true;
 
2095
 
 
2096
    if (isAncestorTo (below, w))
 
2097
        return false;
 
2098
 
 
2099
    if (clientLeader && below->priv->clientLeader == clientLeader)
 
2100
        if (below->priv->isGroupTransient (clientLeader))
 
2101
            return false;
 
2102
 
 
2103
    if (w->priv->state & CompWindowStateAboveMask)
 
2104
    {
 
2105
        return true;
 
2106
    }
 
2107
    else if (w->priv->state & CompWindowStateBelowMask)
 
2108
    {
 
2109
        if (below->priv->state & CompWindowStateBelowMask)
 
2110
            return true;
 
2111
    }
 
2112
    else if (!(below->priv->state & CompWindowStateAboveMask))
 
2113
    {
 
2114
        return true;
 
2115
    }
 
2116
 
 
2117
    return false;
 
2118
}
 
2119
 
 
2120
bool
 
2121
PrivateWindow::avoidStackingRelativeTo (CompWindow *w)
 
2122
{
 
2123
    if (w->overrideRedirect ())
 
2124
        return true;
 
2125
 
 
2126
    if (!w->priv->shaded && !w->priv->pendingMaps)
 
2127
    {
 
2128
        if (!w->isViewable () || !w->isMapped ())
 
2129
            return true;
 
2130
    }
 
2131
 
 
2132
    return false;
 
2133
}
 
2134
 
 
2135
/* goes through the stack, top-down until we find a window we should
 
2136
   stack above, normal windows can be stacked above fullscreen windows
 
2137
   (and fullscreen windows over others in their layer) if aboveFs is true. */
 
2138
CompWindow *
 
2139
PrivateWindow::findSiblingBelow (CompWindow *w,
 
2140
                                 bool       aboveFs)
 
2141
{
 
2142
    CompWindow   *below;
 
2143
    Window       clientLeader = w->priv->clientLeader;
 
2144
    unsigned int type = w->priv->type;
 
2145
    unsigned int belowMask;
 
2146
 
 
2147
    if (aboveFs)
 
2148
        belowMask = CompWindowTypeDockMask;
 
2149
    else
 
2150
        belowMask = CompWindowTypeDockMask | CompWindowTypeFullscreenMask;
 
2151
 
 
2152
    /* normal stacking of fullscreen windows with below state */
 
2153
    if ((type & CompWindowTypeFullscreenMask) &&
 
2154
        (w->priv->state & CompWindowStateBelowMask))
 
2155
        type = CompWindowTypeNormalMask;
 
2156
 
 
2157
    if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
 
2158
        clientLeader = None;
 
2159
 
 
2160
    for (below = screen->windows ().back (); below;
 
2161
         below = below->prev)
 
2162
    {
 
2163
        if (below == w || avoidStackingRelativeTo (below))
 
2164
            continue;
 
2165
 
 
2166
        /* always above desktop windows */
 
2167
        if (below->priv->type & CompWindowTypeDesktopMask)
 
2168
            return below;
 
2169
 
 
2170
        switch (type) {
 
2171
        case CompWindowTypeDesktopMask:
 
2172
            /* desktop window layer */
 
2173
            break;
 
2174
        case CompWindowTypeFullscreenMask:
 
2175
            if (aboveFs)
 
2176
                return below;
 
2177
            /* otherwise fall-through */
 
2178
        case CompWindowTypeDockMask:
 
2179
            /* fullscreen and dock layer */
 
2180
            if (below->priv->type & (CompWindowTypeFullscreenMask |
 
2181
                               CompWindowTypeDockMask))
 
2182
            {
 
2183
                if (stackLayerCheck (w, clientLeader, below))
 
2184
                    return below;
 
2185
            }
 
2186
            else
 
2187
            {
 
2188
                return below;
 
2189
            }
 
2190
            break;
 
2191
        default:
 
2192
            /* fullscreen and normal layer */
 
2193
            if (!(below->priv->type & belowMask))
 
2194
            {
 
2195
                if (stackLayerCheck (w, clientLeader, below))
 
2196
                    return below;
 
2197
            }
 
2198
            break;
 
2199
        }
 
2200
    }
 
2201
 
 
2202
    return NULL;
 
2203
}
 
2204
 
 
2205
/* goes through the stack, top-down and returns the lowest window we
 
2206
   can stack above. */
 
2207
CompWindow *
 
2208
PrivateWindow::findLowestSiblingBelow (CompWindow *w)
 
2209
{
 
2210
    CompWindow   *below, *lowest = screen->windows ().back ();
 
2211
    Window       clientLeader = w->priv->clientLeader;
 
2212
    unsigned int type = w->priv->type;
 
2213
 
 
2214
    /* normal stacking fullscreen windows with below state */
 
2215
    if ((type & CompWindowTypeFullscreenMask) &&
 
2216
        (w->priv->state & CompWindowStateBelowMask))
 
2217
        type = CompWindowTypeNormalMask;
 
2218
 
 
2219
    if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
 
2220
        clientLeader = None;
 
2221
 
 
2222
    for (below = screen->windows ().back (); below;
 
2223
         below = below->prev)
 
2224
    {
 
2225
        if (below == w || avoidStackingRelativeTo (below))
 
2226
            continue;
 
2227
 
 
2228
        /* always above desktop windows */
 
2229
        if (below->priv->type & CompWindowTypeDesktopMask)
 
2230
            return below;
 
2231
 
 
2232
        switch (type) {
 
2233
        case CompWindowTypeDesktopMask:
 
2234
            /* desktop window layer - desktop windows always should be
 
2235
               stacked at the bottom; no other window should be below them */
 
2236
            return NULL;
 
2237
            break;
 
2238
        case CompWindowTypeFullscreenMask:
 
2239
        case CompWindowTypeDockMask:
 
2240
            /* fullscreen and dock layer */
 
2241
            if (below->priv->type & (CompWindowTypeFullscreenMask |
 
2242
                               CompWindowTypeDockMask))
 
2243
            {
 
2244
                if (!stackLayerCheck (below, clientLeader, w))
 
2245
                    return lowest;
 
2246
            }
 
2247
            else
 
2248
            {
 
2249
                return lowest;
 
2250
            }
 
2251
            break;
 
2252
        default:
 
2253
            /* fullscreen and normal layer */
 
2254
            if (!(below->priv->type & CompWindowTypeDockMask))
 
2255
            {
 
2256
                if (!stackLayerCheck (below, clientLeader, w))
 
2257
                    return lowest;
 
2258
            }
 
2259
            break;
 
2260
        }
 
2261
 
 
2262
        lowest = below;
 
2263
    }
 
2264
 
 
2265
    return lowest;
 
2266
}
 
2267
 
 
2268
bool
 
2269
PrivateWindow::validSiblingBelow (CompWindow *w,
 
2270
                                  CompWindow *sibling)
 
2271
{
 
2272
    Window       clientLeader = w->priv->clientLeader;
 
2273
    unsigned int type = w->priv->type;
 
2274
 
 
2275
    /* normal stacking fullscreen windows with below state */
 
2276
    if ((type & CompWindowTypeFullscreenMask) &&
 
2277
        (w->priv->state & CompWindowStateBelowMask))
 
2278
        type = CompWindowTypeNormalMask;
 
2279
 
 
2280
    if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
 
2281
        clientLeader = None;
 
2282
 
 
2283
    if (sibling == w || avoidStackingRelativeTo (sibling))
 
2284
        return false;
 
2285
 
 
2286
    /* always above desktop windows */
 
2287
    if (sibling->priv->type & CompWindowTypeDesktopMask)
 
2288
        return true;
 
2289
 
 
2290
    switch (type) {
 
2291
    case CompWindowTypeDesktopMask:
 
2292
        /* desktop window layer */
 
2293
        break;
 
2294
    case CompWindowTypeFullscreenMask:
 
2295
    case CompWindowTypeDockMask:
 
2296
        /* fullscreen and dock layer */
 
2297
        if (sibling->priv->type & (CompWindowTypeFullscreenMask |
 
2298
                             CompWindowTypeDockMask))
 
2299
        {
 
2300
            if (stackLayerCheck (w, clientLeader, sibling))
 
2301
                return true;
 
2302
        }
 
2303
        else
 
2304
        {
 
2305
            return true;
 
2306
        }
 
2307
        break;
 
2308
    default:
 
2309
        /* fullscreen and normal layer */
 
2310
        if (!(sibling->priv->type & CompWindowTypeDockMask))
 
2311
        {
 
2312
            if (stackLayerCheck (w, clientLeader, sibling))
 
2313
                return true;
 
2314
        }
 
2315
        break;
 
2316
    }
 
2317
 
 
2318
    return false;
 
2319
}
 
2320
 
 
2321
void
 
2322
PrivateWindow::saveGeometry (int mask)
 
2323
{
 
2324
    int m = mask & ~saveMask;
 
2325
 
 
2326
    /* only save geometry if window has been placed */
 
2327
    if (!placed)
 
2328
        return;
 
2329
 
 
2330
    if (m & CWX)
 
2331
        saveWc.x = serverGeometry.x ();
 
2332
 
 
2333
    if (m & CWY)
 
2334
        saveWc.y = serverGeometry.y ();
 
2335
 
 
2336
    if (m & CWWidth)
 
2337
        saveWc.width = serverGeometry.width ();
 
2338
 
 
2339
    if (m & CWHeight)
 
2340
        saveWc.height = serverGeometry.height ();
 
2341
 
 
2342
    if (m & CWBorderWidth)
 
2343
        saveWc.border_width = serverGeometry.border ();
 
2344
 
 
2345
    saveMask |= m;
 
2346
}
 
2347
 
 
2348
int
 
2349
PrivateWindow::restoreGeometry (XWindowChanges *xwc,
 
2350
                                int            mask)
 
2351
{
 
2352
    int m = mask & saveMask;
 
2353
 
 
2354
    if (m & CWX)
 
2355
        xwc->x = saveWc.x;
 
2356
 
 
2357
    if (m & CWY)
 
2358
        xwc->y = saveWc.y;
 
2359
 
 
2360
    if (m & CWWidth)
 
2361
    {
 
2362
        xwc->width = saveWc.width;
 
2363
 
 
2364
        /* This is not perfect but it works OK for now. If the saved width is
 
2365
           the same as the current width then make it a little be smaller so
 
2366
           the user can see that it changed and it also makes sure that
 
2367
           windowResizeNotify is called and plugins are notified. */
 
2368
        if (xwc->width == (int) serverGeometry.width ())
 
2369
        {
 
2370
            xwc->width -= 10;
 
2371
            if (m & CWX)
 
2372
                xwc->x += 5;
 
2373
        }
 
2374
    }
 
2375
 
 
2376
    if (m & CWHeight)
 
2377
    {
 
2378
        xwc->height = saveWc.height;
 
2379
 
 
2380
        /* As above, if the saved height is the same as the current height
 
2381
           then make it a little be smaller. */
 
2382
        if (xwc->height == (int) serverGeometry.height ())
 
2383
        {
 
2384
            xwc->height -= 10;
 
2385
            if (m & CWY)
 
2386
                xwc->y += 5;
 
2387
        }
 
2388
    }
 
2389
 
 
2390
    if (m & CWBorderWidth)
 
2391
        xwc->border_width = saveWc.border_width;
 
2392
 
 
2393
    saveMask &= ~mask;
 
2394
 
 
2395
    return m;
 
2396
}
 
2397
 
 
2398
void
 
2399
PrivateWindow::reconfigureXWindow (unsigned int   valueMask,
 
2400
                                   XWindowChanges *xwc)
 
2401
{
 
2402
    if (valueMask & CWX)
 
2403
        serverGeometry.setX (xwc->x);
 
2404
 
 
2405
    if (valueMask & CWY)
 
2406
        serverGeometry.setY (xwc->y);
 
2407
 
 
2408
    if (valueMask & CWWidth)
 
2409
        serverGeometry.setWidth (xwc->width);
 
2410
 
 
2411
    if (valueMask & CWHeight)
 
2412
        serverGeometry.setHeight (xwc->height);
 
2413
 
 
2414
    if (valueMask & CWBorderWidth)
 
2415
        serverGeometry.setBorder (xwc->border_width);
 
2416
 
 
2417
    /* Compiz's window list is immediately restacked on reconfigureXWindow
 
2418
       in order to ensure correct operation of the raise, lower and restacking
 
2419
       functions. This function should only recieve stack_mode == Above
 
2420
       but warn incase something else does get through, to make the cause
 
2421
       of any potential misbehaviour obvious. */
 
2422
    if (valueMask & (CWSibling | CWStackMode))
 
2423
    {
 
2424
        if (xwc->stack_mode == Above)
 
2425
            restack (xwc->sibling);
 
2426
        else
 
2427
            compLogMessage ("core", CompLogLevelWarn, "restack_mode not Above");
 
2428
    }
 
2429
 
 
2430
    if (frame)
 
2431
    {
 
2432
        XWindowChanges wc = *xwc;
 
2433
 
 
2434
        wc.x      -= input.left - serverGeometry.border ();
 
2435
        wc.y      -= input.top - serverGeometry.border ();
 
2436
        wc.width  += input.left + input.right + serverGeometry.border ();
 
2437
        wc.height += input.top + input.bottom + serverGeometry.border ();
 
2438
 
 
2439
        XConfigureWindow (screen->dpy (), frame, valueMask, &wc);
 
2440
        valueMask &= ~(CWSibling | CWStackMode);
 
2441
 
 
2442
        xwc->x = input.left;
 
2443
        xwc->y = input.top;
 
2444
        XConfigureWindow (screen->dpy (), wrapper, valueMask, xwc);
 
2445
 
 
2446
        xwc->x = 0;
 
2447
        xwc->y = 0;
 
2448
    }
 
2449
 
 
2450
    XConfigureWindow (screen->dpy (), id, valueMask, xwc);
 
2451
}
 
2452
 
 
2453
bool
 
2454
PrivateWindow::stackTransients (CompWindow      *w,
 
2455
                                CompWindow      *avoid,
 
2456
                                XWindowChanges *xwc,
 
2457
                                CompWindowList &updateList)
 
2458
{
 
2459
    CompWindow *t;
 
2460
    Window     clientLeader = w->priv->clientLeader;
 
2461
 
 
2462
    if (w->priv->transientFor || w->priv->isGroupTransient (clientLeader))
 
2463
        clientLeader = None;
 
2464
 
 
2465
    for (t = screen->windows ().back (); t; t = t->prev)
 
2466
    {
 
2467
        if (t == w || t == avoid)
 
2468
            continue;
 
2469
 
 
2470
        if (t->priv->transientFor == w->priv->id ||
 
2471
            t->priv->isGroupTransient (clientLeader))
 
2472
        {
 
2473
            if (w->priv->type & CompWindowTypeDockMask)
 
2474
                if (!(t->priv->type & CompWindowTypeDockMask))
 
2475
                    return false;
 
2476
 
 
2477
            if (!stackTransients (t, avoid, xwc, updateList))
 
2478
                return false;
 
2479
 
 
2480
            if (xwc->sibling == t->priv->id ||
 
2481
                (t->priv->frame && xwc->sibling == t->priv->frame))
 
2482
                return false;
 
2483
 
 
2484
            if (t->priv->mapNum || t->priv->pendingMaps)
 
2485
                updateList.push_back (t);
 
2486
        }
 
2487
    }
 
2488
 
 
2489
    return true;
 
2490
}
 
2491
 
 
2492
void
 
2493
PrivateWindow::stackAncestors (CompWindow     *w,
 
2494
                               XWindowChanges *xwc,
 
2495
                               CompWindowList &updateList)
 
2496
{
 
2497
    CompWindow *transient = NULL;
 
2498
 
 
2499
    if (w->priv->transientFor)
 
2500
        transient = screen->findWindow (w->priv->transientFor);
 
2501
 
 
2502
    if (transient                           &&
 
2503
        xwc->sibling != transient->priv->id &&
 
2504
        (!transient->priv->frame || xwc->sibling != transient->priv->frame))
 
2505
    {
 
2506
        CompWindow *ancestor;
 
2507
 
 
2508
        ancestor = screen->findWindow (w->priv->transientFor);
 
2509
        if (ancestor)
 
2510
        {
 
2511
            if (!stackTransients (ancestor, w, xwc, updateList))
 
2512
                return;
 
2513
 
 
2514
            if (ancestor->priv->type & CompWindowTypeDesktopMask)
 
2515
                return;
 
2516
 
 
2517
            if (ancestor->priv->type & CompWindowTypeDockMask)
 
2518
                if (!(w->priv->type & CompWindowTypeDockMask))
 
2519
                    return;
 
2520
 
 
2521
            if (ancestor->priv->mapNum || ancestor->priv->pendingMaps)
 
2522
                updateList.push_back (ancestor);
 
2523
 
 
2524
            stackAncestors (ancestor, xwc, updateList);
 
2525
        }
 
2526
    }
 
2527
    else if (w->priv->isGroupTransient (w->priv->clientLeader))
 
2528
    {
 
2529
        CompWindow *a;
 
2530
 
 
2531
        for (a = screen->windows ().back (); a; a = a->prev)
 
2532
        {
 
2533
            if (a->priv->clientLeader == w->priv->clientLeader &&
 
2534
                a->priv->transientFor == None                  &&
 
2535
                !a->priv->isGroupTransient (w->priv->clientLeader))
 
2536
            {
 
2537
                if (xwc->sibling == a->priv->id ||
 
2538
                    (a->priv->frame && xwc->sibling == a->priv->frame))
 
2539
                    break;
 
2540
 
 
2541
                if (!stackTransients (a, w, xwc, updateList))
 
2542
                    break;
 
2543
 
 
2544
                if (a->priv->type & CompWindowTypeDesktopMask)
 
2545
                    continue;
 
2546
 
 
2547
                if (a->priv->type & CompWindowTypeDockMask)
 
2548
                    if (!(w->priv->type & CompWindowTypeDockMask))
 
2549
                        break;
 
2550
 
 
2551
                if (a->priv->mapNum || a->priv->pendingMaps)
 
2552
                    updateList.push_back (a);
 
2553
            }
 
2554
        }
 
2555
    }
 
2556
}
 
2557
 
 
2558
void
 
2559
CompWindow::configureXWindow (unsigned int valueMask,
 
2560
                              XWindowChanges *xwc)
 
2561
{
 
2562
    if (priv->managed && (valueMask & (CWSibling | CWStackMode)))
 
2563
    {
 
2564
        CompWindowList transients;
 
2565
        CompWindowList ancestors;
 
2566
 
 
2567
        /* Since the window list is being reordered in reconfigureXWindow
 
2568
           the list of windows which need to be restacked must be stored
 
2569
           first. The windows are stacked in the opposite order than they
 
2570
           were previously stacked, in order that they are above xwc->sibling
 
2571
           so that when compiz gets the ConfigureNotify event it doesn't
 
2572
           have to restack all the windows again. */
 
2573
 
 
2574
        /* transient children above */
 
2575
        if (PrivateWindow::stackTransients (this, NULL, xwc, transients))
 
2576
        {
 
2577
            /* ancestors, siblings and sibling transients below */
 
2578
            PrivateWindow::stackAncestors (this, xwc, ancestors);
 
2579
 
 
2580
            for (CompWindowList::reverse_iterator w = ancestors.rbegin ();
 
2581
                 w != ancestors.rend (); w++)
 
2582
            {
 
2583
                (*w)->priv->reconfigureXWindow (CWSibling | CWStackMode, xwc);
 
2584
                xwc->sibling = ROOTPARENT (*w);
 
2585
            }
 
2586
 
 
2587
            this->priv->reconfigureXWindow (valueMask, xwc);
 
2588
            xwc->sibling = ROOTPARENT (this);
 
2589
 
 
2590
            for (CompWindowList::reverse_iterator w = transients.rbegin ();
 
2591
                 w != transients.rend (); w++)
 
2592
            {
 
2593
                (*w)->priv->reconfigureXWindow (CWSibling | CWStackMode, xwc);
 
2594
                xwc->sibling = ROOTPARENT (*w);
 
2595
            }
 
2596
        }
 
2597
    }
 
2598
    else
 
2599
    {
 
2600
        priv->reconfigureXWindow (valueMask, xwc);
 
2601
    }
 
2602
}
 
2603
 
 
2604
int
 
2605
PrivateWindow::addWindowSizeChanges (XWindowChanges       *xwc,
 
2606
                                     CompWindow::Geometry old)
 
2607
{
 
2608
    CompRect  workArea;
 
2609
    int       mask = 0;
 
2610
    int       x, y;
 
2611
    int       output;
 
2612
    CompPoint viewport;
 
2613
 
 
2614
    screen->viewportForGeometry (old, viewport);
 
2615
 
 
2616
    x = (viewport.x () - screen->vp ().x ()) * screen->width ();
 
2617
    y = (viewport.y () - screen->vp ().y ()) * screen->height ();
 
2618
 
 
2619
    output   = screen->outputDeviceForGeometry (old);
 
2620
    workArea = screen->getWorkareaForOutput (output);
 
2621
 
 
2622
    if (type & CompWindowTypeFullscreenMask)
 
2623
    {
 
2624
        saveGeometry (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
 
2625
 
 
2626
        if (fullscreenMonitorsSet)
 
2627
        {
 
2628
            xwc->x      = x + fullscreenMonitorRect.x ();
 
2629
            xwc->y      = y + fullscreenMonitorRect.y ();
 
2630
            xwc->width  = fullscreenMonitorRect.width ();
 
2631
            xwc->height = fullscreenMonitorRect.height ();
 
2632
        }
 
2633
        else
 
2634
        {
 
2635
            xwc->x      = x + screen->outputDevs ()[output].x ();
 
2636
            xwc->y      = y + screen->outputDevs ()[output].y ();
 
2637
            xwc->width  = screen->outputDevs ()[output].width ();
 
2638
            xwc->height = screen->outputDevs ()[output].height ();
 
2639
        }
 
2640
 
 
2641
        xwc->border_width = 0;
 
2642
 
 
2643
        mask |= CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
 
2644
    }
 
2645
    else
 
2646
    {
 
2647
        mask |= restoreGeometry (xwc, CWBorderWidth);
 
2648
 
 
2649
        if (state & CompWindowStateMaximizedVertMask)
 
2650
        {
 
2651
            saveGeometry (CWY | CWHeight);
 
2652
 
 
2653
            xwc->height = workArea.height () - input.top -
 
2654
                          input.bottom - old.border () * 2;
 
2655
 
 
2656
            mask |= CWHeight;
 
2657
        }
 
2658
        else
 
2659
        {
 
2660
            mask |= restoreGeometry (xwc, CWY | CWHeight);
 
2661
        }
 
2662
 
 
2663
        if (state & CompWindowStateMaximizedHorzMask)
 
2664
        {
 
2665
            saveGeometry (CWX | CWWidth);
 
2666
 
 
2667
            xwc->width = workArea.width () - input.left -
 
2668
                         input.right - old.border () * 2;
 
2669
 
 
2670
            mask |= CWWidth;
 
2671
        }
 
2672
        else
 
2673
        {
 
2674
            mask |= restoreGeometry (xwc, CWX | CWWidth);
 
2675
        }
 
2676
 
 
2677
        /* constrain window width if smaller than minimum width */
 
2678
        if (!(mask & CWWidth) && (int) old.width () < sizeHints.min_width)
 
2679
        {
 
2680
            xwc->width = sizeHints.min_width;
 
2681
            mask |= CWWidth;
 
2682
        }
 
2683
 
 
2684
        /* constrain window width if greater than maximum width */
 
2685
        if (!(mask & CWWidth) && (int) old.width () > sizeHints.max_width)
 
2686
        {
 
2687
            xwc->width = sizeHints.max_width;
 
2688
            mask |= CWWidth;
 
2689
        }
 
2690
 
 
2691
        /* constrain window height if smaller than minimum height */
 
2692
        if (!(mask & CWHeight) && (int) old.height () < sizeHints.min_height)
 
2693
        {
 
2694
            xwc->height = sizeHints.min_height;
 
2695
            mask |= CWHeight;
 
2696
        }
 
2697
 
 
2698
        /* constrain window height if greater than maximum height */
 
2699
        if (!(mask & CWHeight) && (int) old.height () > sizeHints.max_height)
 
2700
        {
 
2701
            xwc->height = sizeHints.max_height;
 
2702
            mask |= CWHeight;
 
2703
        }
 
2704
 
 
2705
        if (mask & (CWWidth | CWHeight))
 
2706
        {
 
2707
            int width, height, max;
 
2708
 
 
2709
            width  = (mask & CWWidth)  ? xwc->width  : old.width ();
 
2710
            height = (mask & CWHeight) ? xwc->height : old.height ();
 
2711
 
 
2712
            xwc->width  = old.width ();
 
2713
            xwc->height = old.height ();
 
2714
 
 
2715
            window->constrainNewWindowSize (width, height, &width, &height);
 
2716
 
 
2717
            if (width != (int) old.width ())
 
2718
            {
 
2719
                mask |= CWWidth;
 
2720
                xwc->width = width;
 
2721
            }
 
2722
            else
 
2723
                mask &= ~CWWidth;
 
2724
 
 
2725
            if (height != (int) old.height ())
 
2726
            {
 
2727
                mask |= CWHeight;
 
2728
                xwc->height = height;
 
2729
            }
 
2730
            else
 
2731
                mask &= ~CWHeight;
 
2732
 
 
2733
            if (state & CompWindowStateMaximizedVertMask)
 
2734
            {
 
2735
                if (old.y () < y + workArea.y () + input.top)
 
2736
                {
 
2737
                    xwc->y = y + workArea.y () + input.top;
 
2738
                    mask |= CWY;
 
2739
                }
 
2740
                else
 
2741
                {
 
2742
                    height = xwc->height + old.border () * 2;
 
2743
 
 
2744
                    max = y + workArea.bottom ();
 
2745
                    if (old.y () + (int) old.height () + input.bottom > max)
 
2746
                    {
 
2747
                        xwc->y = max - height - input.bottom;
 
2748
                        mask |= CWY;
 
2749
                    }
 
2750
                    else if (old.y () + height + input.bottom > max)
 
2751
                    {
 
2752
                        xwc->y = y + workArea.y () +
 
2753
                                 (workArea.height () - input.top - height -
 
2754
                                  input.bottom) / 2 + input.top;
 
2755
                        mask |= CWY;
 
2756
                    }
 
2757
                }
 
2758
            }
 
2759
 
 
2760
            if (state & CompWindowStateMaximizedHorzMask)
 
2761
            {
 
2762
                if (old.x () < x + workArea.x () + input.left)
 
2763
                {
 
2764
                    xwc->x = x + workArea.x () + input.left;
 
2765
                    mask |= CWX;
 
2766
                }
 
2767
                else
 
2768
                {
 
2769
                    width = xwc->width + old.border () * 2;
 
2770
 
 
2771
                    max = x + workArea.right ();
 
2772
                    if (old.x () + (int) old.width () + input.right > max)
 
2773
                    {
 
2774
                        xwc->x = max - width - input.right;
 
2775
                        mask |= CWX;
 
2776
                    }
 
2777
                    else if (old.x () + width + input.right > max)
 
2778
                    {
 
2779
                        xwc->x = x + workArea.x () +
 
2780
                                 (workArea.width () - input.left - width -
 
2781
                                  input.right) / 2 + input.left;
 
2782
                        mask |= CWX;
 
2783
                    }
 
2784
                }
 
2785
            }
 
2786
        }
 
2787
    }
 
2788
 
 
2789
    if ((mask & CWX) && (xwc->x == old.x ()))
 
2790
        mask &= ~CWX;
 
2791
 
 
2792
    if ((mask & CWY) && (xwc->y == old.y ()))
 
2793
        mask &= ~CWY;
 
2794
 
 
2795
    if ((mask & CWWidth) && (xwc->width == (int) old.width ()))
 
2796
        mask &= ~CWWidth;
 
2797
 
 
2798
    if ((mask & CWHeight) && (xwc->height == (int) old.height ()))
 
2799
        mask &= ~CWHeight;
 
2800
 
 
2801
    return mask;
 
2802
}
 
2803
 
 
2804
unsigned int
 
2805
PrivateWindow::adjustConfigureRequestForGravity (XWindowChanges *xwc,
 
2806
                                                 unsigned int   xwcm,
 
2807
                                                 int            gravity,
 
2808
                                                 int            direction)
 
2809
{
 
2810
    int          newX, newY;
 
2811
    unsigned int mask = 0;
 
2812
 
 
2813
    newX = xwc->x;
 
2814
    newY = xwc->y;
 
2815
 
 
2816
    if (xwcm & (CWX | CWWidth))
 
2817
    {
 
2818
        switch (gravity) {
 
2819
        case NorthWestGravity:
 
2820
        case WestGravity:
 
2821
        case SouthWestGravity:
 
2822
            if (xwcm & CWX)
 
2823
                newX += priv->input.left * direction;
 
2824
            break;
 
2825
 
 
2826
        case NorthGravity:
 
2827
        case CenterGravity:
 
2828
        case SouthGravity:
 
2829
            if (xwcm & CWX)
 
2830
                newX -= (xwc->width / 2 - priv->input.left +
 
2831
                        (priv->input.left + priv->input.right) / 2) * direction;
 
2832
            else
 
2833
                newX -= (xwc->width - priv->serverGeometry.width ()) * direction;
 
2834
            break;
 
2835
 
 
2836
        case NorthEastGravity:
 
2837
        case EastGravity:
 
2838
        case SouthEastGravity:
 
2839
            if (xwcm & CWX)
 
2840
                newX -= xwc->width + priv->input.right * direction;
 
2841
            else
 
2842
                newX -= (xwc->width - priv->serverGeometry.width ()) * direction;
 
2843
            break;
 
2844
 
 
2845
        case StaticGravity:
 
2846
        default:
 
2847
            break;
 
2848
        }
 
2849
    }
 
2850
 
 
2851
    if (xwcm & (CWY | CWHeight))
 
2852
    {
 
2853
        switch (gravity) {
 
2854
        case NorthWestGravity:
 
2855
        case NorthGravity:
 
2856
        case NorthEastGravity:
 
2857
            if (xwcm & CWY)
 
2858
                newY = xwc->y + priv->input.top * direction;
 
2859
            break;
 
2860
 
 
2861
        case WestGravity:
 
2862
        case CenterGravity:
 
2863
        case EastGravity:
 
2864
            if (xwcm & CWY)
 
2865
                newY -= (xwc->height / 2 - priv->input.top +
 
2866
                        (priv->input.top + priv->input.bottom) / 2) * direction;
 
2867
            else
 
2868
                newY -= ((xwc->height - priv->serverGeometry.height ()) / 2) * direction;
 
2869
            break;
 
2870
 
 
2871
        case SouthWestGravity:
 
2872
        case SouthGravity:
 
2873
        case SouthEastGravity:
 
2874
            if (xwcm & CWY)
 
2875
                newY -= xwc->height + priv->input.bottom * direction;
 
2876
            else
 
2877
                newY -= (xwc->height - priv->serverGeometry.height ()) * direction;
 
2878
            break;
 
2879
 
 
2880
        case StaticGravity:
 
2881
        default:
 
2882
            break;
 
2883
        }
 
2884
    }
 
2885
 
 
2886
    if (newX != xwc->x)
 
2887
    {
 
2888
        xwc->x += (newX - xwc->x);
 
2889
        mask |= CWX;
 
2890
    }
 
2891
 
 
2892
    if (newY != xwc->y)
 
2893
    {
 
2894
        xwc->y += (newY - xwc->y);
 
2895
        mask |= CWY;
 
2896
    }
 
2897
 
 
2898
    return mask;
 
2899
}
 
2900
 
 
2901
void
 
2902
CompWindow::moveResize (XWindowChanges *xwc,
 
2903
                        unsigned int   xwcm,
 
2904
                        int            gravity,
 
2905
                        unsigned int   source)
 
2906
{
 
2907
    bool placed = false;
 
2908
 
 
2909
    xwcm &= (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
 
2910
 
 
2911
    if (xwcm & (CWX | CWY))
 
2912
        if (priv->sizeHints.flags & (USPosition | PPosition))
 
2913
            placed = true;
 
2914
 
 
2915
    if (gravity == 0)
 
2916
        gravity = priv->sizeHints.win_gravity;
 
2917
 
 
2918
    if (!(xwcm & CWX))
 
2919
        xwc->x = priv->serverGeometry.x ();
 
2920
    if (!(xwcm & CWY))
 
2921
        xwc->y = priv->serverGeometry.y ();
 
2922
    if (!(xwcm & CWWidth))
 
2923
        xwc->width = priv->serverGeometry.width ();
 
2924
    if (!(xwcm & CWHeight))
 
2925
        xwc->height = priv->serverGeometry.height ();
 
2926
 
 
2927
    if (xwcm & (CWWidth | CWHeight))
 
2928
    {
 
2929
        int width, height;
 
2930
 
 
2931
        if (constrainNewWindowSize (xwc->width, xwc->height, &width, &height))
 
2932
        {
 
2933
            if (width != xwc->width)
 
2934
                xwcm |= CWWidth;
 
2935
 
 
2936
            if (height != xwc->height)
 
2937
                xwcm |= CWHeight;
 
2938
 
 
2939
            xwc->width = width;
 
2940
            xwc->height = height;
 
2941
        }
 
2942
    }
 
2943
 
 
2944
    xwcm |= priv->adjustConfigureRequestForGravity (xwc, xwcm, gravity, 1);
 
2945
 
 
2946
    validateResizeRequest (xwcm, xwc, source);
 
2947
 
 
2948
    /* when horizontally maximized only allow width changes added by
 
2949
       addWindowSizeChanges */
 
2950
    if (priv->state & CompWindowStateMaximizedHorzMask)
 
2951
        xwcm &= ~CWWidth;
 
2952
 
 
2953
    /* when vertically maximized only allow height changes added by
 
2954
       addWindowSizeChanges */
 
2955
    if (priv->state & CompWindowStateMaximizedVertMask)
 
2956
        xwcm &= ~CWHeight;
 
2957
 
 
2958
    xwcm |= priv->addWindowSizeChanges (xwc, Geometry (xwc->x, xwc->y,
 
2959
                                        xwc->width, xwc->height,
 
2960
                                        xwc->border_width));
 
2961
 
 
2962
    /* check if the new coordinates are useful and valid (different
 
2963
       to current size); if not, we have to clear them to make sure
 
2964
       we send a synthetic ConfigureNotify event if all coordinates
 
2965
       match the server coordinates */
 
2966
    if (xwc->x == priv->serverGeometry.x ())
 
2967
        xwcm &= ~CWX;
 
2968
 
 
2969
    if (xwc->y == priv->serverGeometry.y ())
 
2970
        xwcm &= ~CWY;
 
2971
 
 
2972
    if (xwc->width == (int) priv->serverGeometry.width ())
 
2973
        xwcm &= ~CWWidth;
 
2974
 
 
2975
    if (xwc->height == (int) priv->serverGeometry.height ())
 
2976
        xwcm &= ~CWHeight;
 
2977
 
 
2978
    if (xwc->border_width == (int) priv->serverGeometry.border ())
 
2979
        xwcm &= ~CWBorderWidth;
 
2980
 
 
2981
    /* update saved window coordinates - if CWX or CWY is set for fullscreen
 
2982
       or maximized windows after addWindowSizeChanges, it should be pretty
 
2983
       safe to assume that the saved coordinates should be updated too, e.g.
 
2984
       because the window was moved to another viewport by some client */
 
2985
    if ((xwcm & CWX) && (priv->saveMask & CWX))
 
2986
        priv->saveWc.x += (xwc->x - priv->serverGeometry.x ());
 
2987
 
 
2988
    if ((xwcm & CWY) && (priv->saveMask & CWY))
 
2989
        priv->saveWc.y += (xwc->y - priv->serverGeometry.y ());
 
2990
 
 
2991
    if (priv->mapNum && (xwcm & (CWWidth | CWHeight)))
 
2992
        sendSyncRequest ();
 
2993
 
 
2994
    if (xwcm)
 
2995
        configureXWindow (xwcm, xwc);
 
2996
    else
 
2997
    {
 
2998
        /* we have to send a configure notify on ConfigureRequest events if
 
2999
           we decide not to do anything according to ICCCM 4.1.5 */
 
3000
        sendConfigureNotify ();
 
3001
    }
 
3002
 
 
3003
    if (placed)
 
3004
        priv->placed = true;
 
3005
}
 
3006
 
 
3007
void
 
3008
PrivateWindow::updateSize ()
 
3009
{
 
3010
    XWindowChanges xwc;
 
3011
    int            mask;
 
3012
 
 
3013
    if (window->overrideRedirect () || !managed)
 
3014
        return;
 
3015
 
 
3016
    mask = priv->addWindowSizeChanges (&xwc, priv->serverGeometry);
 
3017
    if (mask)
 
3018
    {
 
3019
        if (priv->mapNum && (mask & (CWWidth | CWHeight)))
 
3020
            window->sendSyncRequest ();
 
3021
 
 
3022
        window->configureXWindow (mask, &xwc);
 
3023
    }
 
3024
}
 
3025
 
 
3026
int
 
3027
PrivateWindow::addWindowStackChanges (XWindowChanges *xwc,
 
3028
                                      CompWindow     *sibling)
 
3029
{
 
3030
    int mask = 0;
 
3031
 
 
3032
    if (!sibling || sibling->priv->id != id)
 
3033
    {
 
3034
        if (window->prev)
 
3035
        {
 
3036
            if (!sibling)
 
3037
            {
 
3038
                XLowerWindow (screen->dpy (), id);
 
3039
                if (frame)
 
3040
                    XLowerWindow (screen->dpy (), frame);
 
3041
 
 
3042
                /* Restacking of compiz's window list happens
 
3043
                   immediately and since this path doesn't call
 
3044
                   reconfigureXWindow, restack must be called here. */
 
3045
                restack (0);
 
3046
            }
 
3047
            else if (sibling->priv->id != window->prev->priv->id)
 
3048
            {
 
3049
                mask |= CWSibling | CWStackMode;
 
3050
 
 
3051
                xwc->stack_mode = Above;
 
3052
                xwc->sibling    = ROOTPARENT (sibling);
 
3053
            }
 
3054
        }
 
3055
        else if (sibling)
 
3056
        {
 
3057
            mask |= CWSibling | CWStackMode;
 
3058
 
 
3059
            xwc->stack_mode = Above;
 
3060
            xwc->sibling    = ROOTPARENT (sibling);
 
3061
        }
 
3062
    }
 
3063
 
 
3064
    if (sibling && mask)
 
3065
    {
 
3066
        /* a normal window can be stacked above fullscreen windows but we
 
3067
           don't want normal windows to be stacked above dock window so if
 
3068
           the sibling we're stacking above is a fullscreen window we also
 
3069
           update all dock windows. */
 
3070
        if ((sibling->priv->type & CompWindowTypeFullscreenMask) &&
 
3071
            (!(type & (CompWindowTypeFullscreenMask |
 
3072
                          CompWindowTypeDockMask))) &&
 
3073
            !isAncestorTo (window, sibling))
 
3074
        {
 
3075
            CompWindow *dw;
 
3076
 
 
3077
            for (dw = screen->windows ().back (); dw; dw = dw->prev)
 
3078
                if (dw == sibling)
 
3079
                    break;
 
3080
 
 
3081
            /* Collect all dock windows first */
 
3082
            CompWindowList dockWindows;
 
3083
            for (; dw; dw = dw->prev)
 
3084
                if (dw->priv->type & CompWindowTypeDockMask)
 
3085
                    dockWindows.push_back (dw);
 
3086
 
 
3087
            /* Then update the dock windows */
 
3088
            foreach (CompWindow *dw, dockWindows)
 
3089
                dw->configureXWindow (mask, xwc);
 
3090
        }
 
3091
    }
 
3092
 
 
3093
    return mask;
 
3094
}
 
3095
 
 
3096
void
 
3097
CompWindow::raise ()
 
3098
{
 
3099
    XWindowChanges xwc;
 
3100
    int            mask;
 
3101
    bool           aboveFs = false;
 
3102
 
 
3103
    /* an active fullscreen window should be raised over all other
 
3104
       windows in its layer */
 
3105
    if (priv->type & CompWindowTypeFullscreenMask)
 
3106
        if (priv->id == screen->activeWindow ())
 
3107
            aboveFs = true;
 
3108
 
 
3109
    mask = priv->addWindowStackChanges (&xwc,
 
3110
        PrivateWindow::findSiblingBelow (this, aboveFs));
 
3111
 
 
3112
    if (mask)
 
3113
        configureXWindow (mask, &xwc);
 
3114
}
 
3115
 
 
3116
CompWindow *
 
3117
PrivateScreen::focusTopMostWindow ()
 
3118
{
 
3119
    CompWindow  *focus = NULL;
 
3120
    CompWindowList::reverse_iterator it = windows.rbegin ();
 
3121
 
 
3122
    for (; it != windows.rend (); it++)
 
3123
    {
 
3124
        CompWindow *w = *it;
 
3125
 
 
3126
        if (w->type () & CompWindowTypeDockMask)
 
3127
            continue;
 
3128
 
 
3129
        if (w->focus ())
 
3130
        {
 
3131
            focus = w;
 
3132
            break;
 
3133
        }
 
3134
    }
 
3135
 
 
3136
    if (focus)
 
3137
    {
 
3138
        if (focus->id () != activeWindow)
 
3139
            focus->moveInputFocusTo ();
 
3140
    }
 
3141
    else
 
3142
        XSetInputFocus (dpy, root, RevertToPointerRoot,
 
3143
                        CurrentTime);
 
3144
    return focus;
 
3145
}
 
3146
 
 
3147
 
 
3148
void
 
3149
CompWindow::lower ()
 
3150
{
 
3151
    XWindowChanges xwc;
 
3152
    int            mask;
 
3153
 
 
3154
    mask = priv->addWindowStackChanges (&xwc,
 
3155
        PrivateWindow::findLowestSiblingBelow (this));
 
3156
    if (mask)
 
3157
        configureXWindow (mask, &xwc);
 
3158
 
 
3159
    /* when lowering a window, focus the topmost window if
 
3160
       the click-to-focus option is on */
 
3161
    if ((screen->priv->optionGetClickToFocus ()))
 
3162
    {
 
3163
        Window aboveWindowId = prev ? prev->id () : None;
 
3164
        screen->unhookWindow (this);
 
3165
        CompWindow *focusedWindow = screen->priv->focusTopMostWindow ();
 
3166
        screen->insertWindow (this , aboveWindowId);
 
3167
 
 
3168
        /* if the newly focused window is a desktop window,
 
3169
           give the focus back to w */
 
3170
        if (focusedWindow &&
 
3171
            focusedWindow->type () & CompWindowTypeDesktopMask)
 
3172
        {
 
3173
            moveInputFocusTo ();
 
3174
        }
 
3175
    }
 
3176
}
 
3177
 
 
3178
void
 
3179
CompWindow::restackAbove (CompWindow *sibling)
 
3180
{
 
3181
    for (; sibling; sibling = sibling->next)
 
3182
        if (PrivateWindow::validSiblingBelow (this, sibling))
 
3183
            break;
 
3184
 
 
3185
    if (sibling)
 
3186
    {
 
3187
        XWindowChanges xwc;
 
3188
        int            mask;
 
3189
 
 
3190
        mask = priv->addWindowStackChanges (&xwc, sibling);
 
3191
        if (mask)
 
3192
            configureXWindow (mask, &xwc);
 
3193
    }
 
3194
}
 
3195
 
 
3196
/* finds the highest window under sibling we can stack above */
 
3197
CompWindow *
 
3198
PrivateWindow::findValidStackSiblingBelow (CompWindow *w,
 
3199
                                           CompWindow *sibling)
 
3200
{
 
3201
    CompWindow *lowest, *last, *p;
 
3202
 
 
3203
    /* check whether we're allowed to stack under a sibling by finding
 
3204
     * the above 'sibling' and checking whether or not we're allowed
 
3205
     * to stack under that - if not, then there is no valid sibling
 
3206
     * underneath it */
 
3207
 
 
3208
    for (p = sibling; p; p = p->next)
 
3209
    {
 
3210
        if (!avoidStackingRelativeTo (p))
 
3211
        {
 
3212
            if (!validSiblingBelow (p, w))
 
3213
                return NULL;
 
3214
            break;
 
3215
        }
 
3216
    }
 
3217
 
 
3218
    /* get lowest sibling we're allowed to stack above */
 
3219
    lowest = last = findLowestSiblingBelow (w);
 
3220
 
 
3221
    /* walk from bottom up */
 
3222
    for (p = screen->windows ().front (); p; p = p->next)
 
3223
    {
 
3224
        /* stop walking when we reach the sibling we should try to stack
 
3225
           below */
 
3226
        if (p == sibling)
 
3227
            return lowest;
 
3228
 
 
3229
        /* skip windows that we should avoid */
 
3230
        if (w == p || avoidStackingRelativeTo (p))
 
3231
            continue;
 
3232
 
 
3233
        if (validSiblingBelow (w, p))
 
3234
        {
 
3235
            /* update lowest as we find windows below sibling that we're
 
3236
               allowed to stack above. last window must be equal to the
 
3237
               lowest as we shouldn't update lowest if we passed an
 
3238
               invalid window */
 
3239
            if (last == lowest)
 
3240
                lowest = p;
 
3241
        }
 
3242
 
 
3243
        /* update last pointer */
 
3244
        last = p;
 
3245
    }
 
3246
 
 
3247
    return lowest;
 
3248
}
 
3249
 
 
3250
void
 
3251
CompWindow::restackBelow (CompWindow *sibling)
 
3252
{
 
3253
    XWindowChanges xwc;
 
3254
    unsigned int   mask;
 
3255
 
 
3256
    mask = priv->addWindowStackChanges (&xwc,
 
3257
        PrivateWindow::findValidStackSiblingBelow (this, sibling));
 
3258
 
 
3259
    if (mask)
 
3260
        configureXWindow (mask, &xwc);
 
3261
}
 
3262
 
 
3263
void
 
3264
CompWindow::updateAttributes (CompStackingUpdateMode stackingMode)
 
3265
{
 
3266
    XWindowChanges xwc;
 
3267
    int            mask = 0;
 
3268
 
 
3269
    if (overrideRedirect () || !priv->managed)
 
3270
        return;
 
3271
 
 
3272
    if (priv->state & CompWindowStateShadedMask)
 
3273
    {
 
3274
        windowNotify (CompWindowNotifyShade);
 
3275
 
 
3276
        priv->hide ();
 
3277
    }
 
3278
    else if (priv->shaded)
 
3279
    {
 
3280
        windowNotify (CompWindowNotifyUnshade);
 
3281
 
 
3282
        priv->show ();
 
3283
    }
 
3284
 
 
3285
    if (stackingMode != CompStackingUpdateModeNone)
 
3286
    {
 
3287
        bool       aboveFs;
 
3288
        CompWindow *sibling;
 
3289
 
 
3290
        aboveFs = (stackingMode == CompStackingUpdateModeAboveFullscreen);
 
3291
        if (priv->type & CompWindowTypeFullscreenMask)
 
3292
        {
 
3293
            /* put active or soon-to-be-active fullscreen windows over
 
3294
               all others in their layer */
 
3295
            if (priv->id == screen->activeWindow ())
 
3296
            {
 
3297
                aboveFs = true;
 
3298
            }
 
3299
        }
 
3300
 
 
3301
        /* put windows that are just mapped, over fullscreen windows */
 
3302
        if (stackingMode == CompStackingUpdateModeInitialMap)
 
3303
            aboveFs = true;
 
3304
 
 
3305
        sibling = PrivateWindow::findSiblingBelow (this, aboveFs);
 
3306
 
 
3307
        if (sibling &&
 
3308
            (stackingMode == CompStackingUpdateModeInitialMapDeniedFocus))
 
3309
        {
 
3310
            CompWindow *p;
 
3311
 
 
3312
            for (p = sibling; p; p = p->prev)
 
3313
                if (p->priv->id == screen->activeWindow ())
 
3314
                    break;
 
3315
 
 
3316
            /* window is above active window so we should lower it,
 
3317
             * assuing that is allowed (if, for example, our window has
 
3318
             * the "above" state, then lowering beneath the active
 
3319
             * window may not be allowed). */
 
3320
            if (p && PrivateWindow::validSiblingBelow (p, this))
 
3321
            {
 
3322
                p = PrivateWindow::findValidStackSiblingBelow (sibling, p);
 
3323
 
 
3324
                /* if we found a valid sibling under the active window, it's
 
3325
                   our new sibling we want to stack above */
 
3326
                if (p)
 
3327
                    sibling = p;
 
3328
            }
 
3329
        }
 
3330
 
 
3331
        mask |= priv->addWindowStackChanges (&xwc, sibling);
 
3332
    }
 
3333
 
 
3334
    if ((stackingMode == CompStackingUpdateModeInitialMap) ||
 
3335
        (stackingMode == CompStackingUpdateModeInitialMapDeniedFocus))
 
3336
    {
 
3337
        /* If we are called from the MapRequest handler, we have to
 
3338
           immediately update the internal stack. If we don't do that,
 
3339
           the internal stacking order is invalid until the ConfigureNotify
 
3340
           arrives because we put the window at the top of the stack when
 
3341
           it was created */
 
3342
        if (mask & CWStackMode)
 
3343
        {
 
3344
            Window above = (mask & CWSibling) ? xwc.sibling : 0;
 
3345
            priv->restack (above);
 
3346
        }
 
3347
    }
 
3348
 
 
3349
    mask |= priv->addWindowSizeChanges (&xwc, priv->serverGeometry);
 
3350
 
 
3351
    if (priv->mapNum && (mask & (CWWidth | CWHeight)))
 
3352
        sendSyncRequest ();
 
3353
 
 
3354
    if (mask)
 
3355
        configureXWindow (mask, &xwc);
 
3356
}
 
3357
 
 
3358
void
 
3359
PrivateWindow::ensureWindowVisibility ()
 
3360
{
 
3361
    int x1, y1, x2, y2;
 
3362
    int width = serverGeometry.width () + serverGeometry.border () * 2;
 
3363
    int height = serverGeometry.height () + serverGeometry.border () * 2;
 
3364
    int dx = 0;
 
3365
    int dy = 0;
 
3366
 
 
3367
    if (struts || attrib.override_redirect)
 
3368
        return;
 
3369
 
 
3370
    if (type & (CompWindowTypeDockMask       |
 
3371
                CompWindowTypeFullscreenMask |
 
3372
                CompWindowTypeUnknownMask))
 
3373
        return;
 
3374
 
 
3375
    x1 = screen->workArea ().x () - screen->width () * screen->vp ().x ();
 
3376
    y1 = screen->workArea ().y () - screen->height () * screen->vp ().y ();
 
3377
    x2 = x1 + screen->workArea ().width () + screen->vpSize ().width () *
 
3378
         screen->width ();
 
3379
    y2 = y1 + screen->workArea ().height () + screen->vpSize ().height () *
 
3380
         screen->height ();
 
3381
 
 
3382
    if (serverGeometry.x () - input.left >= x2)
 
3383
        dx = (x2 - 25) - serverGeometry.x ();
 
3384
    else if (serverGeometry.x () + width + input.right <= x1)
 
3385
        dx = (x1 + 25) - (serverGeometry.x () + width);
 
3386
 
 
3387
    if (serverGeometry.y () - input.top >= y2)
 
3388
        dy = (y2 - 25) - serverGeometry.y ();
 
3389
    else if (serverGeometry.y () + height + input.bottom <= y1)
 
3390
        dy = (y1 + 25) - (serverGeometry.y () + height);
 
3391
 
 
3392
    if (dx || dy)
 
3393
    {
 
3394
        XWindowChanges xwc;
 
3395
 
 
3396
        xwc.x = serverGeometry.x () + dx;
 
3397
        xwc.y = serverGeometry.y () + dy;
 
3398
 
 
3399
        window->configureXWindow (CWX | CWY, &xwc);
 
3400
    }
 
3401
}
 
3402
 
 
3403
void
 
3404
PrivateWindow::reveal ()
 
3405
{
 
3406
    if (window->minimized ())
 
3407
        window->unminimize ();
 
3408
 
 
3409
    screen->leaveShowDesktopMode (window);
 
3410
}
 
3411
 
 
3412
void
 
3413
PrivateWindow::revealAncestors (CompWindow *w,
 
3414
                                CompWindow *transient)
 
3415
{
 
3416
    if (isAncestorTo (transient, w))
 
3417
    {
 
3418
        screen->forEachWindow (boost::bind (revealAncestors, _1, w));
 
3419
        w->priv->reveal ();
 
3420
    }
 
3421
}
 
3422
 
 
3423
void
 
3424
CompWindow::activate ()
 
3425
{
 
3426
    WRAPABLE_HND_FUNC (3, activate)
 
3427
 
 
3428
    screen->priv->setCurrentDesktop (priv->desktop);
 
3429
 
 
3430
    screen->forEachWindow (
 
3431
        boost::bind (PrivateWindow::revealAncestors, _1, this));
 
3432
    priv->reveal ();
 
3433
 
 
3434
    if (priv->state & CompWindowStateHiddenMask)
 
3435
    {
 
3436
        priv->state &= ~CompWindowStateShadedMask;
 
3437
        if (priv->shaded)
 
3438
            priv->show ();
 
3439
    }
 
3440
 
 
3441
    if (priv->state & CompWindowStateHiddenMask)
 
3442
        return;
 
3443
 
 
3444
    if (!onCurrentDesktop ())
 
3445
        return;
 
3446
 
 
3447
    priv->ensureWindowVisibility ();
 
3448
    updateAttributes (CompStackingUpdateModeAboveFullscreen);
 
3449
    moveInputFocusTo ();
 
3450
}
 
3451
 
 
3452
 
 
3453
#define PVertResizeInc (1 << 0)
 
3454
#define PHorzResizeInc (1 << 1)
 
3455
 
 
3456
bool
 
3457
CompWindow::constrainNewWindowSize (int        width,
 
3458
                                    int        height,
 
3459
                                    int        *newWidth,
 
3460
                                    int        *newHeight)
 
3461
{
 
3462
    const XSizeHints *hints = &priv->sizeHints;
 
3463
    int              oldWidth = width;
 
3464
    int              oldHeight = height;
 
3465
    int              min_width = 0;
 
3466
    int              min_height = 0;
 
3467
    int              base_width = 0;
 
3468
    int              base_height = 0;
 
3469
    int              xinc = 1;
 
3470
    int              yinc = 1;
 
3471
    int              max_width = MAXSHORT;
 
3472
    int              max_height = MAXSHORT;
 
3473
    long             flags = hints->flags;
 
3474
    long             resizeIncFlags = (flags & PResizeInc) ? ~0 : 0;
 
3475
 
 
3476
    if (screen->priv->optionGetIgnoreHintsWhenMaximized ())
 
3477
    {
 
3478
        if (priv->state & MAXIMIZE_STATE)
 
3479
        {
 
3480
            flags &= ~PAspect;
 
3481
 
 
3482
            if (priv->state & CompWindowStateMaximizedHorzMask)
 
3483
                resizeIncFlags &= ~PHorzResizeInc;
 
3484
 
 
3485
            if (priv->state & CompWindowStateMaximizedVertMask)
 
3486
                resizeIncFlags &= ~PVertResizeInc;
 
3487
        }
 
3488
    }
 
3489
 
 
3490
    /* Ater gdk_window_constrain_size(), which is partially borrowed from fvwm.
 
3491
     *
 
3492
     * Copyright 1993, Robert Nation
 
3493
     *     You may use this code for any purpose, as long as the original
 
3494
     *     copyright remains in the source code and all documentation
 
3495
     *
 
3496
     * which in turn borrows parts of the algorithm from uwm
 
3497
     */
 
3498
 
 
3499
#define FLOOR(value, base) (((int) ((value) / (base))) * (base))
 
3500
#define FLOOR64(value, base) (((uint64_t) ((value) / (base))) * (base))
 
3501
 
 
3502
    if ((flags & PBaseSize) && (flags & PMinSize))
 
3503
    {
 
3504
        base_width = hints->base_width;
 
3505
        base_height = hints->base_height;
 
3506
        min_width = hints->min_width;
 
3507
        min_height = hints->min_height;
 
3508
    }
 
3509
    else if (flags & PBaseSize)
 
3510
    {
 
3511
        base_width = hints->base_width;
 
3512
        base_height = hints->base_height;
 
3513
        min_width = hints->base_width;
 
3514
        min_height = hints->base_height;
 
3515
    }
 
3516
    else if (flags & PMinSize)
 
3517
    {
 
3518
        base_width = hints->min_width;
 
3519
        base_height = hints->min_height;
 
3520
        min_width = hints->min_width;
 
3521
        min_height = hints->min_height;
 
3522
    }
 
3523
 
 
3524
    if (flags & PMaxSize)
 
3525
    {
 
3526
        max_width = hints->max_width;
 
3527
        max_height = hints->max_height;
 
3528
    }
 
3529
 
 
3530
    if (resizeIncFlags & PHorzResizeInc)
 
3531
        xinc = MAX (xinc, hints->width_inc);
 
3532
 
 
3533
    if (resizeIncFlags & PVertResizeInc)
 
3534
        yinc = MAX (yinc, hints->height_inc);
 
3535
 
 
3536
    /* clamp width and height to min and max values */
 
3537
    width  = CLAMP (width, min_width, max_width);
 
3538
    height = CLAMP (height, min_height, max_height);
 
3539
 
 
3540
    /* shrink to base + N * inc */
 
3541
    width  = base_width + FLOOR (width - base_width, xinc);
 
3542
    height = base_height + FLOOR (height - base_height, yinc);
 
3543
 
 
3544
    /* constrain aspect ratio, according to:
 
3545
     *
 
3546
     * min_aspect.x       width      max_aspect.x
 
3547
     * ------------  <= -------- <=  -----------
 
3548
     * min_aspect.y       height     max_aspect.y
 
3549
     */
 
3550
    if ((flags & PAspect) && hints->min_aspect.y > 0 && hints->max_aspect.x > 0)
 
3551
    {
 
3552
        /* Use 64 bit arithmetic to prevent overflow */
 
3553
 
 
3554
        uint64_t min_aspect_x = hints->min_aspect.x;
 
3555
        uint64_t min_aspect_y = hints->min_aspect.y;
 
3556
        uint64_t max_aspect_x = hints->max_aspect.x;
 
3557
        uint64_t max_aspect_y = hints->max_aspect.y;
 
3558
        uint64_t delta;
 
3559
 
 
3560
        if (min_aspect_x * height > width * min_aspect_y)
 
3561
        {
 
3562
            delta = FLOOR64 (height - width * min_aspect_y / min_aspect_x,
 
3563
                             yinc);
 
3564
            if (height - (int) delta >= min_height)
 
3565
                height -= delta;
 
3566
            else
 
3567
            {
 
3568
                delta = FLOOR64 (height * min_aspect_x / min_aspect_y - width,
 
3569
                                 xinc);
 
3570
                if (width + (int) delta <= max_width)
 
3571
                    width += delta;
 
3572
            }
 
3573
        }
 
3574
 
 
3575
        if (width * max_aspect_y > max_aspect_x * height)
 
3576
        {
 
3577
            delta = FLOOR64 (width - height * max_aspect_x / max_aspect_y,
 
3578
                             xinc);
 
3579
            if (width - (int) delta >= min_width)
 
3580
                width -= delta;
 
3581
            else
 
3582
            {
 
3583
                delta = FLOOR64 (width * min_aspect_y / min_aspect_x - height,
 
3584
                                 yinc);
 
3585
                if (height + (int) delta <= max_height)
 
3586
                    height += delta;
 
3587
            }
 
3588
        }
 
3589
    }
 
3590
 
 
3591
#undef CLAMP
 
3592
#undef FLOOR64
 
3593
#undef FLOOR
 
3594
 
 
3595
    if (width != oldWidth || height != oldHeight)
 
3596
    {
 
3597
        *newWidth  = width;
 
3598
        *newHeight = height;
 
3599
 
 
3600
        return true;
 
3601
    }
 
3602
 
 
3603
    return false;
 
3604
}
 
3605
 
 
3606
void
 
3607
CompWindow::hide ()
 
3608
{
 
3609
    priv->hidden = true;
 
3610
    priv->hide ();
 
3611
}
 
3612
 
 
3613
void
 
3614
CompWindow::show ()
 
3615
{
 
3616
    priv->hidden = false;
 
3617
    priv->show ();
 
3618
}
 
3619
 
 
3620
void
 
3621
PrivateWindow::hide ()
 
3622
{
 
3623
    bool onDesktop = window->onCurrentDesktop ();
 
3624
 
 
3625
    if (!managed)
 
3626
        return;
 
3627
 
 
3628
    if (!window->minimized () && !inShowDesktopMode &&
 
3629
        !hidden && onDesktop)
 
3630
    {
 
3631
        if (state & CompWindowStateShadedMask)
 
3632
        {
 
3633
            shaded = true;
 
3634
        }
 
3635
        else
 
3636
        {
 
3637
            return;
 
3638
        }
 
3639
    }
 
3640
    else
 
3641
    {
 
3642
        shaded = false;
 
3643
 
 
3644
        if ((state & CompWindowStateShadedMask) && frame)
 
3645
            XUnmapWindow (screen->dpy (), frame);
 
3646
    }
 
3647
 
 
3648
    if (!pendingMaps && !window->isViewable ())
 
3649
        return;
 
3650
 
 
3651
    window->windowNotify (CompWindowNotifyHide);
 
3652
 
 
3653
    pendingUnmaps++;
 
3654
 
 
3655
    if (frame && !shaded)
 
3656
        XUnmapWindow (screen->dpy (), frame);
 
3657
 
 
3658
    XUnmapWindow (screen->dpy (), id);
 
3659
 
 
3660
    if (window->minimized () || inShowDesktopMode || hidden || shaded)
 
3661
        window->changeState (state | CompWindowStateHiddenMask);
 
3662
 
 
3663
    if (shaded && id == screen->activeWindow ())
 
3664
        window->moveInputFocusTo ();
 
3665
}
 
3666
 
 
3667
void
 
3668
PrivateWindow::show ()
 
3669
{
 
3670
    bool onDesktop = window->onCurrentDesktop ();
 
3671
 
 
3672
    if (!managed)
 
3673
        return;
 
3674
 
 
3675
    if (minimized || inShowDesktopMode ||
 
3676
        hidden    || !onDesktop)
 
3677
    {
 
3678
        /* no longer hidden but not on current desktop */
 
3679
        if (!minimized && !inShowDesktopMode && !hidden)
 
3680
            window->changeState (state & ~CompWindowStateHiddenMask);
 
3681
 
 
3682
        return;
 
3683
    }
 
3684
 
 
3685
    /* transition from minimized to shaded */
 
3686
    if (state & CompWindowStateShadedMask)
 
3687
    {
 
3688
        shaded = true;
 
3689
 
 
3690
        if (frame)
 
3691
            XMapWindow (screen->dpy (), frame);
 
3692
 
 
3693
        if (height)
 
3694
            window->resize (attrib.x, attrib.y,
 
3695
                            attrib.width, ++attrib.height - 1,
 
3696
                            attrib.border_width);
 
3697
 
 
3698
        return;
 
3699
    }
 
3700
    else
 
3701
    {
 
3702
        shaded = false;
 
3703
    }
 
3704
 
 
3705
    window->windowNotify (CompWindowNotifyShow);
 
3706
 
 
3707
    pendingMaps++;
 
3708
 
 
3709
    if (frame)
 
3710
    {
 
3711
        XMapWindow (screen->dpy (), frame);
 
3712
        XMapWindow (screen->dpy (), wrapper);
 
3713
    }
 
3714
 
 
3715
    XMapWindow (screen->dpy (), id);
 
3716
 
 
3717
    window->changeState (state & ~CompWindowStateHiddenMask);
 
3718
    screen->priv->setWindowState (state, id);
 
3719
}
 
3720
 
 
3721
void
 
3722
PrivateWindow::minimizeTransients (CompWindow *w,
 
3723
                                   CompWindow *ancestor)
 
3724
{
 
3725
    if (w->priv->transientFor == ancestor->priv->id ||
 
3726
        w->priv->isGroupTransient (ancestor->priv->clientLeader))
 
3727
    {
 
3728
        w->minimize ();
 
3729
    }
 
3730
}
 
3731
 
 
3732
void
 
3733
CompWindow::minimize ()
 
3734
{
 
3735
    WRAPABLE_HND_FUNC (13, minimize);
 
3736
 
 
3737
    if (!priv->managed)
 
3738
        return;
 
3739
 
 
3740
    if (!priv->minimized)
 
3741
    {
 
3742
        windowNotify (CompWindowNotifyMinimize);
 
3743
 
 
3744
        priv->minimized = true;
 
3745
 
 
3746
        screen->forEachWindow (
 
3747
            boost::bind (PrivateWindow::minimizeTransients, _1, this));
 
3748
 
 
3749
        priv->hide ();
 
3750
    }
 
3751
}
 
3752
 
 
3753
void
 
3754
PrivateWindow::unminimizeTransients (CompWindow *w,
 
3755
                                     CompWindow *ancestor)
 
3756
{
 
3757
    if (w->priv->transientFor == ancestor->priv->id ||
 
3758
        w->priv->isGroupTransient (ancestor->priv->clientLeader))
 
3759
        w->unminimize ();
 
3760
}
 
3761
 
 
3762
void
 
3763
CompWindow::unminimize ()
 
3764
{
 
3765
    WRAPABLE_HND_FUNC (14, unminimize);
 
3766
    if (priv->minimized)
 
3767
    {
 
3768
        windowNotify (CompWindowNotifyUnminimize);
 
3769
 
 
3770
        priv->minimized = false;
 
3771
 
 
3772
        priv->show ();
 
3773
 
 
3774
        screen->forEachWindow (
 
3775
            boost::bind (PrivateWindow::unminimizeTransients, _1, this));
 
3776
    }
 
3777
}
 
3778
 
 
3779
void
 
3780
CompWindow::maximize (unsigned int state)
 
3781
{
 
3782
    if (overrideRedirect ())
 
3783
        return;
 
3784
 
 
3785
    state = constrainWindowState (state, priv->actions);
 
3786
 
 
3787
    state &= MAXIMIZE_STATE;
 
3788
 
 
3789
    if (state == (priv->state & MAXIMIZE_STATE))
 
3790
        return;
 
3791
 
 
3792
    state |= (priv->state & ~MAXIMIZE_STATE);
 
3793
 
 
3794
    changeState (state);
 
3795
    updateAttributes (CompStackingUpdateModeNone);
 
3796
}
 
3797
 
 
3798
bool
 
3799
PrivateWindow::getUserTime (Time& time)
 
3800
{
 
3801
    Atom          actual;
 
3802
    int           result, format;
 
3803
    unsigned long n, left;
 
3804
    unsigned char *data;
 
3805
    bool          retval = false;
 
3806
 
 
3807
    result = XGetWindowProperty (screen->dpy (), priv->id,
 
3808
                                 Atoms::wmUserTime,
 
3809
                                 0L, 1L, False, XA_CARDINAL, &actual, &format,
 
3810
                                 &n, &left, &data);
 
3811
 
 
3812
    if (result == Success && data)
 
3813
    {
 
3814
        if (n)
 
3815
        {
 
3816
            CARD32 value;
 
3817
 
 
3818
            memcpy (&value, data, sizeof (CARD32));
 
3819
            retval = true;
 
3820
            time   = (Time) value;
 
3821
        }
 
3822
 
 
3823
        XFree ((void *) data);
 
3824
    }
 
3825
 
 
3826
    return retval;
 
3827
}
 
3828
 
 
3829
void
 
3830
PrivateWindow::setUserTime (Time time)
 
3831
{
 
3832
    CARD32 value = (CARD32) time;
 
3833
 
 
3834
    XChangeProperty (screen->dpy (), priv->id,
 
3835
                     Atoms::wmUserTime,
 
3836
                     XA_CARDINAL, 32, PropModeReplace,
 
3837
                     (unsigned char *) &value, 1);
 
3838
}
 
3839
 
 
3840
/*
 
3841
 * Macros from metacity
 
3842
 *
 
3843
 * Xserver time can wraparound, thus comparing two timestamps needs to
 
3844
 * take this into account.  Here's a little macro to help out.  If no
 
3845
 * wraparound has occurred, this is equivalent to
 
3846
 *   time1 < time2
 
3847
 * Of course, the rest of the ugliness of this macro comes from
 
3848
 * accounting for the fact that wraparound can occur and the fact that
 
3849
 * a timestamp of 0 must be special-cased since it means older than
 
3850
 * anything else.
 
3851
 *
 
3852
 * Note that this is NOT an equivalent for time1 <= time2; if that's
 
3853
 * what you need then you'll need to swap the order of the arguments
 
3854
 * and negate the result.
 
3855
 */
 
3856
#define XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS(time1, time2) \
 
3857
    ( (( (time1) < (time2) ) &&                                       \
 
3858
       ( (time2) - (time1) < ((unsigned long) -1) / 2 )) ||           \
 
3859
      (( (time1) > (time2) ) &&                                       \
 
3860
       ( (time1) - (time2) > ((unsigned long) -1) / 2 ))              \
 
3861
        )
 
3862
#define XSERVER_TIME_IS_BEFORE(time1, time2)                             \
 
3863
    ( (time1) == 0 ||                                                    \
 
3864
      (XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS (time1, time2) && \
 
3865
       (time2) != 0)                                                     \
 
3866
        )
 
3867
 
 
3868
bool
 
3869
PrivateWindow::getUsageTimestamp (Time& timestamp)
 
3870
{
 
3871
    if (getUserTime (timestamp))
 
3872
        return true;
 
3873
 
 
3874
    if (initialTimestampSet)
 
3875
    {
 
3876
        timestamp = initialTimestamp;
 
3877
        return true;
 
3878
    }
 
3879
 
 
3880
    return false;
 
3881
}
 
3882
 
 
3883
bool
 
3884
PrivateWindow::isWindowFocusAllowed (Time timestamp)
 
3885
{
 
3886
    CompScreen   *s = screen;
 
3887
    CompWindow   *active;
 
3888
    Time         wUserTime, aUserTime;
 
3889
    bool         gotTimestamp = false;
 
3890
    int          level;
 
3891
    CompPoint    dvp;
 
3892
 
 
3893
    level = s->priv->optionGetFocusPreventionLevel ();
 
3894
 
 
3895
    if (level == CoreOptions::FocusPreventionLevelOff)
 
3896
        return true;
 
3897
 
 
3898
    if (timestamp)
 
3899
    {
 
3900
        /* the caller passed a timestamp, so use that
 
3901
           instead of the window's user time */
 
3902
        wUserTime = timestamp;
 
3903
        gotTimestamp = true;
 
3904
    }
 
3905
    else
 
3906
    {
 
3907
        gotTimestamp = getUsageTimestamp (wUserTime);
 
3908
    }
 
3909
 
 
3910
    /* if we got no timestamp for the window, try to get at least a timestamp
 
3911
       for its transient parent, if any */
 
3912
    if (!gotTimestamp && transientFor)
 
3913
    {
 
3914
        CompWindow *parent;
 
3915
 
 
3916
        parent = screen->findWindow (transientFor);
 
3917
        if (parent)
 
3918
            gotTimestamp = parent->priv->getUsageTimestamp (wUserTime);
 
3919
    }
 
3920
 
 
3921
    if (gotTimestamp && !wUserTime)
 
3922
    {
 
3923
        /* window explicitly requested no focus */
 
3924
        return false;
 
3925
    }
 
3926
 
 
3927
    /* allow focus for excluded windows */
 
3928
    CompMatch &match = s->priv->optionGetFocusPreventionMatch ();
 
3929
    if (!match.evaluate (window))
 
3930
        return true;
 
3931
 
 
3932
    if (level == CoreOptions::FocusPreventionLevelVeryHigh)
 
3933
        return false;
 
3934
 
 
3935
    active = s->findWindow (s->activeWindow ());
 
3936
 
 
3937
    /* no active window */
 
3938
    if (!active || (active->type () & CompWindowTypeDesktopMask))
 
3939
        return true;
 
3940
 
 
3941
    /* active window belongs to same application */
 
3942
    if (window->clientLeader () == active->clientLeader ())
 
3943
       return true;
 
3944
 
 
3945
    if (level == CoreOptions::FocusPreventionLevelHigh)
 
3946
       return false;
 
3947
 
 
3948
    /* not in current viewport or desktop */
 
3949
    if (!window->onCurrentDesktop ())
 
3950
        return false;
 
3951
 
 
3952
    dvp = window->defaultViewport ();
 
3953
    if (dvp.x () != s->vp ().x () || dvp.y () != s->vp ().y ())
 
3954
        return false;
 
3955
 
 
3956
    if (!gotTimestamp)
 
3957
    {
 
3958
        /* unsure as we have nothing to compare - allow focus in low level,
 
3959
           don't allow in normal level */
 
3960
        if (level == CoreOptions::FocusPreventionLevelNormal)
 
3961
            return false;
 
3962
 
 
3963
        return true;
 
3964
    }
 
3965
 
 
3966
    /* can't get user time for active window */
 
3967
    if (!active->priv->getUserTime (aUserTime))
 
3968
        return true;
 
3969
 
 
3970
    if (XSERVER_TIME_IS_BEFORE (wUserTime, aUserTime))
 
3971
        return false;
 
3972
 
 
3973
    return true;
 
3974
}
 
3975
 
 
3976
bool
 
3977
PrivateWindow::allowWindowFocus (unsigned int noFocusMask,
 
3978
                                 Time         timestamp)
 
3979
{
 
3980
    bool retval;
 
3981
 
 
3982
    if (priv->id == screen->activeWindow ())
 
3983
        return true;
 
3984
 
 
3985
    /* do not focus windows of these types */
 
3986
    if (priv->type & noFocusMask)
 
3987
        return false;
 
3988
 
 
3989
    /* window doesn't take focus */
 
3990
    if (!priv->inputHint &&
 
3991
        !(priv->protocols & CompWindowProtocolTakeFocusMask))
 
3992
    {
 
3993
        return false;
 
3994
    }
 
3995
 
 
3996
    retval = priv->isWindowFocusAllowed (timestamp);
 
3997
    if (!retval)
 
3998
    {
 
3999
        /* add demands attention state if focus was prevented */
 
4000
        window->changeState (priv->state | CompWindowStateDemandsAttentionMask);
 
4001
    }
 
4002
 
 
4003
    return retval;
 
4004
}
 
4005
 
 
4006
CompPoint
 
4007
CompWindow::defaultViewport ()
 
4008
{
 
4009
    CompPoint viewport;
 
4010
 
 
4011
    if (priv->serverGeometry.x () < (int) screen->width ()            &&
 
4012
        priv->serverGeometry.x () + priv->serverGeometry.width () > 0 &&
 
4013
        priv->serverGeometry.y () < (int) screen->height ()           &&
 
4014
        priv->serverGeometry.y ()+ priv->serverGeometry.height () > 0)
 
4015
    {
 
4016
        return screen->vp ();
 
4017
    }
 
4018
 
 
4019
    screen->viewportForGeometry (priv->serverGeometry, viewport);
 
4020
 
 
4021
    return viewport;
 
4022
}
 
4023
 
 
4024
CompPoint &
 
4025
CompWindow::initialViewport () const
 
4026
{
 
4027
    return priv->initialViewport;
 
4028
}
 
4029
 
 
4030
void
 
4031
PrivateWindow::readIconHint ()
 
4032
{
 
4033
    XImage       *image, *maskImage = NULL;
 
4034
    Display      *dpy = screen->dpy ();
 
4035
    unsigned int width, height, dummy;
 
4036
    unsigned int i, j, k;
 
4037
    int          iDummy;
 
4038
    Window       wDummy;
 
4039
    CompIcon     *icon;
 
4040
    XColor       *colors;
 
4041
    CARD32       *p;
 
4042
 
 
4043
    if (!XGetGeometry (dpy, hints->icon_pixmap, &wDummy, &iDummy,
 
4044
                       &iDummy, &width, &height, &dummy, &dummy))
 
4045
        return;
 
4046
 
 
4047
    image = XGetImage (dpy, hints->icon_pixmap, 0, 0, width, height,
 
4048
                       AllPlanes, ZPixmap);
 
4049
    if (!image)
 
4050
        return;
 
4051
 
 
4052
    colors = new XColor[width * height];
 
4053
    if (!colors)
 
4054
    {
 
4055
        XDestroyImage (image);
 
4056
        return;
 
4057
    }
 
4058
 
 
4059
    k = 0;
 
4060
    for (j = 0; j < height; j++)
 
4061
        for (i = 0; i < width; i++)
 
4062
            colors[k++].pixel = XGetPixel (image, i, j);
 
4063
 
 
4064
    for (i = 0; i < k; i += 256)
 
4065
        XQueryColors (dpy, screen->priv->colormap,
 
4066
                      &colors[i], MIN (k - i, 256));
 
4067
 
 
4068
    XDestroyImage (image);
 
4069
 
 
4070
    icon = new CompIcon (screen, width, height);
 
4071
    if (!icon)
 
4072
    {
 
4073
        delete [] colors;
 
4074
        return;
 
4075
    }
 
4076
 
 
4077
    if (hints->flags & IconMaskHint)
 
4078
        maskImage = XGetImage (dpy, hints->icon_mask, 0, 0,
 
4079
                               width, height, AllPlanes, ZPixmap);
 
4080
 
 
4081
    k = 0;
 
4082
    p = (CARD32 *) icon->data ();
 
4083
 
 
4084
    for (j = 0; j < height; j++)
 
4085
    {
 
4086
        for (i = 0; i < width; i++)
 
4087
        {
 
4088
            if (maskImage && !XGetPixel (maskImage, i, j))
 
4089
                *p++ = 0;
 
4090
            else if (image->depth == 1)  /* white   : black */
 
4091
                *p++ = colors[k].pixel ? 0xffffffff : 0xff000000;
 
4092
            else
 
4093
                *p++ = 0xff000000                             | /* alpha */
 
4094
                       (((colors[k].red >> 8) & 0xff) << 16)  | /* red */
 
4095
                       (((colors[k].green >> 8) & 0xff) << 8) | /* green */
 
4096
                       ((colors[k].blue >> 8) & 0xff);          /* blue */
 
4097
 
 
4098
            k++;
 
4099
        }
 
4100
    }
 
4101
 
 
4102
    delete [] colors;
 
4103
    if (maskImage)
 
4104
        XDestroyImage (maskImage);
 
4105
 
 
4106
    icons.push_back (icon);
 
4107
}
 
4108
 
 
4109
/* returns icon with dimensions as close as possible to width and height
 
4110
   but never greater. */
 
4111
CompIcon *
 
4112
CompWindow::getIcon (int width,
 
4113
                     int height)
 
4114
{
 
4115
    CompIcon     *icon;
 
4116
    int          wh, diff, oldDiff;
 
4117
    unsigned int i;
 
4118
 
 
4119
    /* need to fetch icon property */
 
4120
    if (priv->icons.size () == 0 && !priv->noIcons)
 
4121
    {
 
4122
        Atom          actual;
 
4123
        int           result, format;
 
4124
        unsigned long n, left;
 
4125
        unsigned char *data;
 
4126
 
 
4127
        result = XGetWindowProperty (screen->dpy (), priv->id, Atoms::wmIcon,
 
4128
                                     0L, 65536L, false, XA_CARDINAL,
 
4129
                                     &actual, &format, &n, &left, &data);
 
4130
 
 
4131
        if (result == Success && data)
 
4132
        {
 
4133
            CARD32        *p;
 
4134
            CARD32        alpha, red, green, blue;
 
4135
            unsigned long iw, ih;
 
4136
 
 
4137
            for (i = 0; i + 2 < n; i += iw * ih + 2)
 
4138
            {
 
4139
                unsigned long *idata = (unsigned long *) data;
 
4140
 
 
4141
                iw = idata[i];
 
4142
                ih = idata[i + 1];
 
4143
 
 
4144
                /* iw * ih may be larger than the value range of unsigned
 
4145
                * long, so better do some checking for extremely weird
 
4146
                * icon sizes first */
 
4147
                if (iw > 2048 || ih > 2048 || iw * ih + 2 > n - i)
 
4148
                    break;
 
4149
 
 
4150
                if (iw && ih)
 
4151
                {
 
4152
                    unsigned long j;
 
4153
                    icon = new CompIcon (screen, iw, ih);
 
4154
                    if (!icon)
 
4155
                        continue;
 
4156
 
 
4157
                    priv->icons.push_back (icon);
 
4158
 
 
4159
                    p = (CARD32 *) (icon->data ());
 
4160
 
 
4161
                    /* EWMH doesn't say if icon data is premultiplied or
 
4162
                       not but most applications seem to assume data should
 
4163
                       be unpremultiplied. */
 
4164
                    for (j = 0; j < iw * ih; j++)
 
4165
                    {
 
4166
                        alpha = (idata[i + j + 2] >> 24) & 0xff;
 
4167
                        red   = (idata[i + j + 2] >> 16) & 0xff;
 
4168
                        green = (idata[i + j + 2] >>  8) & 0xff;
 
4169
                        blue  = (idata[i + j + 2] >>  0) & 0xff;
 
4170
 
 
4171
                        red   = (red   * alpha) >> 8;
 
4172
                        green = (green * alpha) >> 8;
 
4173
                        blue  = (blue  * alpha) >> 8;
 
4174
 
 
4175
                        p[j] =
 
4176
                            (alpha << 24) |
 
4177
                            (red   << 16) |
 
4178
                            (green <<  8) |
 
4179
                            (blue  <<  0);
 
4180
                    }
 
4181
                }
 
4182
            }
 
4183
 
 
4184
            XFree (data);
 
4185
        }
 
4186
        else if (priv->hints && (priv->hints->flags & IconPixmapHint))
 
4187
        {
 
4188
            priv->readIconHint ();
 
4189
        }
 
4190
 
 
4191
        /* don't fetch property again */
 
4192
        if (priv->icons.size () == 0)
 
4193
            priv->noIcons = true;
 
4194
    }
 
4195
 
 
4196
    /* no icons available for this window */
 
4197
    if (priv->noIcons)
 
4198
        return NULL;
 
4199
 
 
4200
    icon = NULL;
 
4201
    wh   = width + height;
 
4202
 
 
4203
    for (i = 0; i < priv->icons.size (); i++)
 
4204
    {
 
4205
        const CompSize iconSize = *priv->icons[i];
 
4206
 
 
4207
        if ((int) iconSize.width () > width ||
 
4208
            (int) iconSize.height () > height)
 
4209
            continue;
 
4210
 
 
4211
        if (icon)
 
4212
        {
 
4213
            diff    = wh - (iconSize.width () + iconSize.height ());
 
4214
            oldDiff = wh - (icon->width () + icon->height ());
 
4215
 
 
4216
            if (diff < oldDiff)
 
4217
                icon = priv->icons[i];
 
4218
        }
 
4219
        else
 
4220
            icon = priv->icons[i];
 
4221
    }
 
4222
 
 
4223
    return icon;
 
4224
}
 
4225
 
 
4226
const CompRect&
 
4227
CompWindow::iconGeometry () const
 
4228
{
 
4229
    return priv->iconGeometry;
 
4230
}
 
4231
 
 
4232
void
 
4233
PrivateWindow::freeIcons ()
 
4234
{
 
4235
    for (unsigned int i = 0; i < priv->icons.size (); i++)
 
4236
        delete priv->icons[i];
 
4237
 
 
4238
    priv->icons.resize (0);
 
4239
    priv->noIcons = false;
 
4240
}
 
4241
 
 
4242
int
 
4243
CompWindow::outputDevice ()
 
4244
{
 
4245
    return screen->outputDeviceForGeometry (priv->serverGeometry);
 
4246
}
 
4247
 
 
4248
bool
 
4249
CompWindow::onCurrentDesktop ()
 
4250
{
 
4251
    if (priv->desktop == 0xffffffff ||
 
4252
        priv->desktop == screen->currentDesktop ())
 
4253
    {
 
4254
        return true;
 
4255
    }
 
4256
 
 
4257
    return false;
 
4258
}
 
4259
 
 
4260
void
 
4261
CompWindow::setDesktop (unsigned int desktop)
 
4262
{
 
4263
    if (desktop != 0xffffffff)
 
4264
    {
 
4265
        if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
 
4266
            return;
 
4267
 
 
4268
        if (desktop >= screen->nDesktop ())
 
4269
            return;
 
4270
    }
 
4271
 
 
4272
    if (desktop == priv->desktop)
 
4273
        return;
 
4274
 
 
4275
    priv->desktop = desktop;
 
4276
 
 
4277
    if (desktop == 0xffffffff || desktop == screen->currentDesktop ())
 
4278
        priv->show ();
 
4279
    else
 
4280
        priv->hide ();
 
4281
 
 
4282
    screen->setWindowProp (priv->id, Atoms::winDesktop, priv->desktop);
 
4283
}
 
4284
 
 
4285
/* The compareWindowActiveness function compares the two windows 'w1'
 
4286
   and 'w2'. It returns an integer less than, equal to, or greater
 
4287
   than zero if 'w1' is found, respectively, to activated longer time
 
4288
   ago than, to be activated at the same time, or be activated more
 
4289
   recently than 'w2'. */
 
4290
int
 
4291
PrivateWindow::compareWindowActiveness (CompWindow *w1,
 
4292
                                        CompWindow *w2)
 
4293
{
 
4294
    CompActiveWindowHistory *history = screen->currentHistory ();
 
4295
    int                     i;
 
4296
 
 
4297
    /* check current window history first */
 
4298
    for (i = 0; i < ACTIVE_WINDOW_HISTORY_SIZE; i++)
 
4299
    {
 
4300
        if (history->id[i] == w1->priv->id)
 
4301
            return 1;
 
4302
 
 
4303
        if (history->id[i] == w2->priv->id)
 
4304
            return -1;
 
4305
 
 
4306
        if (!history->id[i])
 
4307
            break;
 
4308
    }
 
4309
 
 
4310
    return w1->priv->activeNum - w2->priv->activeNum;
 
4311
}
 
4312
 
 
4313
bool
 
4314
CompWindow::onAllViewports ()
 
4315
{
 
4316
    if (overrideRedirect ())
 
4317
        return true;
 
4318
 
 
4319
    if (!priv->managed && !isViewable ())
 
4320
        return true;
 
4321
 
 
4322
    if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
 
4323
        return true;
 
4324
 
 
4325
    if (priv->state & CompWindowStateStickyMask)
 
4326
        return true;
 
4327
 
 
4328
    return false;
 
4329
}
 
4330
 
 
4331
CompPoint
 
4332
CompWindow::getMovementForOffset (CompPoint offset)
 
4333
{
 
4334
    CompScreen *s = screen;
 
4335
    int         m, vWidth, vHeight;
 
4336
    int         offX = offset.x (), offY = offset.y ();
 
4337
    CompPoint   rv;
 
4338
 
 
4339
    vWidth = s->width () * s->vpSize ().width ();
 
4340
    vHeight = s->height () * s->vpSize ().height ();
 
4341
 
 
4342
    offX %= vWidth;
 
4343
    offY %= vHeight;
 
4344
 
 
4345
    /* x */
 
4346
    if (s->vpSize ().width () == 1)
 
4347
    {
 
4348
        rv.setX (offX);
 
4349
    }
 
4350
    else
 
4351
    {
 
4352
        m = priv->attrib.x + offX;
 
4353
        if (m - priv->input.left < (int) s->width () - vWidth)
 
4354
            rv.setX (offX + vWidth);
 
4355
        else if (m + priv->width + priv->input.right > vWidth)
 
4356
            rv.setX (offX - vWidth);
 
4357
        else
 
4358
            rv.setX (offX);
 
4359
    }
 
4360
 
 
4361
    if (s->vpSize ().height () == 1)
 
4362
    {
 
4363
        rv.setY (offY);
 
4364
    }
 
4365
    else
 
4366
    {
 
4367
        m = priv->attrib.y + offY;
 
4368
        if (m - priv->input.top < (int) s->height () - vHeight)
 
4369
            rv.setY (offY + vHeight);
 
4370
        else if (m + priv->height + priv->input.bottom > vHeight)
 
4371
            rv.setY (offY - vHeight);
 
4372
        else
 
4373
            rv.setY (offY);
 
4374
    }
 
4375
 
 
4376
    return rv;
 
4377
}
 
4378
 
 
4379
void
 
4380
WindowInterface::getOutputExtents (CompWindowExtents& output)
 
4381
    WRAPABLE_DEF (getOutputExtents, output)
 
4382
 
 
4383
void
 
4384
WindowInterface::getAllowedActions (unsigned int &setActions,
 
4385
                                    unsigned int &clearActions)
 
4386
    WRAPABLE_DEF (getAllowedActions, setActions, clearActions)
 
4387
 
 
4388
bool
 
4389
WindowInterface::focus ()
 
4390
    WRAPABLE_DEF (focus)
 
4391
 
 
4392
void
 
4393
WindowInterface::activate ()
 
4394
    WRAPABLE_DEF (activate)
 
4395
 
 
4396
bool
 
4397
WindowInterface::place (CompPoint &pos)
 
4398
    WRAPABLE_DEF (place, pos)
 
4399
 
 
4400
void
 
4401
WindowInterface::validateResizeRequest (unsigned int   &mask,
 
4402
                                        XWindowChanges *xwc,
 
4403
                                        unsigned int   source)
 
4404
    WRAPABLE_DEF (validateResizeRequest, mask, xwc, source)
 
4405
 
 
4406
void
 
4407
WindowInterface::resizeNotify (int dx,
 
4408
                               int dy,
 
4409
                               int dwidth,
 
4410
                               int dheight)
 
4411
    WRAPABLE_DEF (resizeNotify, dx, dy, dwidth, dheight)
 
4412
 
 
4413
void
 
4414
WindowInterface::moveNotify (int  dx,
 
4415
                             int  dy,
 
4416
                             bool immediate)
 
4417
    WRAPABLE_DEF (moveNotify, dx, dy, immediate)
 
4418
 
 
4419
void
 
4420
WindowInterface::windowNotify (CompWindowNotify n)
 
4421
    WRAPABLE_DEF (windowNotify, n)
 
4422
 
 
4423
void
 
4424
WindowInterface::grabNotify (int          x,
 
4425
                             int          y,
 
4426
                             unsigned int state,
 
4427
                             unsigned int mask)
 
4428
    WRAPABLE_DEF (grabNotify, x, y, state, mask)
 
4429
 
 
4430
void
 
4431
WindowInterface::ungrabNotify ()
 
4432
    WRAPABLE_DEF (ungrabNotify)
 
4433
 
 
4434
void
 
4435
WindowInterface::stateChangeNotify (unsigned int lastState)
 
4436
    WRAPABLE_DEF (stateChangeNotify, lastState)
 
4437
 
 
4438
void
 
4439
WindowInterface::updateFrameRegion (CompRegion &region)
 
4440
    WRAPABLE_DEF (updateFrameRegion, region)
 
4441
 
 
4442
void
 
4443
WindowInterface::minimize ()
 
4444
    WRAPABLE_DEF (minimize);
 
4445
 
 
4446
void
 
4447
WindowInterface::unminimize ()
 
4448
    WRAPABLE_DEF (unminimize);
 
4449
 
 
4450
bool
 
4451
WindowInterface::minimized ()
 
4452
    WRAPABLE_DEF (minimized);
 
4453
 
 
4454
bool
 
4455
WindowInterface::alpha ()
 
4456
    WRAPABLE_DEF (alpha);
 
4457
 
 
4458
bool
 
4459
WindowInterface::isFocussable ()
 
4460
    WRAPABLE_DEF (isFocussable);
 
4461
 
 
4462
bool
 
4463
WindowInterface::managed ()
 
4464
    WRAPABLE_DEF (managed);
 
4465
 
 
4466
Window
 
4467
CompWindow::id ()
 
4468
{
 
4469
    return priv->id;
 
4470
}
 
4471
 
 
4472
unsigned int
 
4473
CompWindow::type ()
 
4474
{
 
4475
    return priv->type;
 
4476
}
 
4477
 
 
4478
unsigned int &
 
4479
CompWindow::state ()
 
4480
{
 
4481
    return priv->state;
 
4482
}
 
4483
 
 
4484
unsigned int
 
4485
CompWindow::actions ()
 
4486
{
 
4487
    return priv->actions;
 
4488
}
 
4489
 
 
4490
unsigned int &
 
4491
CompWindow::protocols ()
 
4492
{
 
4493
    return priv->protocols;
 
4494
}
 
4495
 
 
4496
void
 
4497
CompWindow::close (Time serverTime)
 
4498
{
 
4499
    if (serverTime == 0)
 
4500
        serverTime = screen->getCurrentTime ();
 
4501
 
 
4502
    if (priv->alive)
 
4503
    {
 
4504
        if (priv->protocols & CompWindowProtocolDeleteMask)
 
4505
        {
 
4506
            XEvent ev;
 
4507
 
 
4508
            ev.type                 = ClientMessage;
 
4509
            ev.xclient.window       = priv->id;
 
4510
            ev.xclient.message_type = Atoms::wmProtocols;
 
4511
            ev.xclient.format       = 32;
 
4512
            ev.xclient.data.l[0]    = Atoms::wmDeleteWindow;
 
4513
            ev.xclient.data.l[1]    = serverTime;
 
4514
            ev.xclient.data.l[2]    = 0;
 
4515
            ev.xclient.data.l[3]    = 0;
 
4516
            ev.xclient.data.l[4]    = 0;
 
4517
 
 
4518
            XSendEvent (screen->dpy (), priv->id, false, NoEventMask, &ev);
 
4519
        }
 
4520
        else
 
4521
        {
 
4522
            XKillClient (screen->dpy (), priv->id);
 
4523
        }
 
4524
 
 
4525
        priv->closeRequests++;
 
4526
    }
 
4527
    else
 
4528
    {
 
4529
        screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
 
4530
                                     serverTime, priv->id, true, 0, 0);
 
4531
    }
 
4532
 
 
4533
    priv->lastCloseRequestTime = serverTime;
 
4534
}
 
4535
 
 
4536
bool
 
4537
PrivateWindow::handlePingTimeout (unsigned int lastPing)
 
4538
{
 
4539
    if (!window->isViewable ())
 
4540
        return false;
 
4541
 
 
4542
    if (!(priv->type & CompWindowTypeNormalMask))
 
4543
        return false;
 
4544
 
 
4545
    if (priv->protocols & CompWindowProtocolPingMask)
 
4546
    {
 
4547
        if (priv->transientFor)
 
4548
            return false;
 
4549
 
 
4550
        if (priv->lastPong < lastPing)
 
4551
        {
 
4552
            if (priv->alive)
 
4553
            {
 
4554
                priv->alive = false;
 
4555
 
 
4556
                window->windowNotify (CompWindowNotifyAliveChanged);
 
4557
 
 
4558
                if (priv->closeRequests)
 
4559
                {
 
4560
                    screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
 
4561
                                           priv->lastCloseRequestTime,
 
4562
                                           priv->id, true, 0, 0);
 
4563
 
 
4564
                    priv->closeRequests = 0;
 
4565
                }
 
4566
            }
 
4567
        }
 
4568
 
 
4569
        return true;
 
4570
    }
 
4571
    return false;
 
4572
}
 
4573
 
 
4574
void
 
4575
PrivateWindow::handlePing (int lastPing)
 
4576
{
 
4577
    if (!priv->alive)
 
4578
    {
 
4579
        priv->alive = true;
 
4580
 
 
4581
        window->windowNotify (CompWindowNotifyAliveChanged);
 
4582
 
 
4583
        if (priv->lastCloseRequestTime)
 
4584
        {
 
4585
            screen->toolkitAction (Atoms::toolkitActionForceQuitDialog,
 
4586
                                   priv->lastCloseRequestTime,
 
4587
                                   priv->id, false, 0, 0);
 
4588
 
 
4589
            priv->lastCloseRequestTime = 0;
 
4590
        }
 
4591
    }
 
4592
    priv->lastPong = lastPing;
 
4593
}
 
4594
 
 
4595
void
 
4596
PrivateWindow::processMap ()
 
4597
{
 
4598
    bool                   allowFocus;
 
4599
    bool                   wasManaged = priv->managed;
 
4600
    CompStackingUpdateMode stackingMode;
 
4601
 
 
4602
    priv->initialViewport = screen->vp ();
 
4603
 
 
4604
    priv->initialTimestampSet = false;
 
4605
 
 
4606
    screen->priv->applyStartupProperties (window);
 
4607
 
 
4608
    if (!frame)
 
4609
        reparent ();
 
4610
    priv->managed = true;
 
4611
 
 
4612
    if (!priv->placed)
 
4613
    {
 
4614
        int            gravity = priv->sizeHints.win_gravity;
 
4615
        XWindowChanges xwc;
 
4616
        unsigned int   xwcm;
 
4617
 
 
4618
        /* adjust for gravity, but only for frame size */
 
4619
        xwc.x      = priv->serverGeometry.x ();
 
4620
        xwc.y      = priv->serverGeometry.y ();
 
4621
        xwc.width  = 0;
 
4622
        xwc.height = 0;
 
4623
 
 
4624
        xwcm = adjustConfigureRequestForGravity (&xwc, CWX | CWY, gravity, 1);
 
4625
 
 
4626
        window->validateResizeRequest (xwcm, &xwc, ClientTypeApplication);
 
4627
 
 
4628
        CompPoint pos (xwc.x, xwc.y);
 
4629
        if (window->place (pos))
 
4630
        {
 
4631
            xwc.x = pos.x ();
 
4632
            xwc.y = pos.y ();
 
4633
            xwcm |= CWX | CWY;
 
4634
        }
 
4635
 
 
4636
        if (xwcm)
 
4637
            window->configureXWindow (xwcm, &xwc);
 
4638
 
 
4639
        priv->placed = true;
 
4640
    }
 
4641
 
 
4642
    allowFocus = allowWindowFocus (NO_FOCUS_MASK, 0);
 
4643
 
 
4644
    if (!allowFocus && (priv->type & ~NO_FOCUS_MASK))
 
4645
        stackingMode = CompStackingUpdateModeInitialMapDeniedFocus;
 
4646
    else
 
4647
        stackingMode = CompStackingUpdateModeInitialMap;
 
4648
 
 
4649
    window->updateAttributes (stackingMode);
 
4650
 
 
4651
    /* Window was either minimized by us, or it was mapped again
 
4652
     * since it has gone from withdrawn to iconic state, so
 
4653
     * unminimize it */
 
4654
    if (window->minimized () && (window->pendingMaps () || wasManaged))
 
4655
        window->unminimize ();
 
4656
 
 
4657
    screen->leaveShowDesktopMode (window);
 
4658
 
 
4659
    if (allowFocus && !window->onCurrentDesktop ())
 
4660
        screen->priv->setCurrentDesktop (priv->desktop);
 
4661
 
 
4662
    if (!(priv->state & CompWindowStateHiddenMask))
 
4663
        show ();
 
4664
 
 
4665
    if (allowFocus)
 
4666
        window->moveInputFocusTo ();
 
4667
}
 
4668
 
 
4669
/*
 
4670
 * PrivateWindow::updatePassiveButtonGrabs
 
4671
 *
 
4672
 * Updates the passive button grabs for a window. When
 
4673
 * one of the specified button + modifier combinations
 
4674
 * for this window is activated, compiz will be given
 
4675
 * an active grab for the window (which we can turn off
 
4676
 * by calling XAllowEvents later in ::handleEvent)
 
4677
 *
 
4678
 * NOTE: ICCCM says that we are only allowed to grab
 
4679
 * windows that we actually own as a client, so only
 
4680
 * grab the frame window. Additionally, although there
 
4681
 * isn't anything in the ICCCM that says we cannot
 
4682
 * grab every button, some clients do not interpret
 
4683
 * EnterNotify and LeaveNotify events caused by the
 
4684
 * activation of the grab correctly, so ungrab button
 
4685
 * and modifier combinations that we do not need on
 
4686
 * active windows (but in reality we shouldn't be grabbing
 
4687
 * for buttons that we don't actually need at that point
 
4688
 * anyways)
 
4689
 */
 
4690
 
 
4691
void
 
4692
PrivateWindow::updatePassiveButtonGrabs ()
 
4693
{
 
4694
    bool onlyActions = (priv->id == screen->priv->activeWindow ||
 
4695
                        !screen->priv->optionGetClickToFocus ());
 
4696
 
 
4697
    if (!priv->frame)
 
4698
        return;
 
4699
 
 
4700
    /* Ungrab everything */
 
4701
    XUngrabButton (screen->priv->dpy, AnyButton, AnyModifier, frame);
 
4702
 
 
4703
    /* We don't need the full grab in the following cases:
 
4704
     * - This window has the focus and either
 
4705
     *   - it is raised or
 
4706
     *   - we don't want click raise
 
4707
     */
 
4708
 
 
4709
    if (onlyActions)
 
4710
    {
 
4711
        if (screen->priv->optionGetRaiseOnClick ())
 
4712
        {
 
4713
            for (CompWindow *above = window->next;
 
4714
                above != NULL; above = above->next)
 
4715
            {
 
4716
                if (above->priv->attrib.map_state != IsViewable)
 
4717
                    continue;
 
4718
 
 
4719
                if (above->type () & CompWindowTypeDockMask)
 
4720
                    continue;
 
4721
 
 
4722
                if (above->region ().intersects (region))
 
4723
                {
 
4724
                    onlyActions = false;
 
4725
                    break;
 
4726
                }
 
4727
            }
 
4728
        }
 
4729
    }
 
4730
 
 
4731
    if (onlyActions)
 
4732
    {
 
4733
        /* Grab only we have bindings on */
 
4734
        foreach (PrivateScreen::ButtonGrab &bind, screen->priv->buttonGrabs)
 
4735
        {
 
4736
            unsigned int mods = modHandler->virtualToRealModMask (bind.modifiers);
 
4737
 
 
4738
            if (mods & CompNoMask)
 
4739
                continue;
 
4740
 
 
4741
            for (unsigned int ignore = 0;
 
4742
                     ignore <= modHandler->ignoredModMask (); ignore++)
 
4743
            {
 
4744
                if (ignore & ~modHandler->ignoredModMask ())
 
4745
                    continue;
 
4746
 
 
4747
                XGrabButton (screen->priv->dpy,
 
4748
                             bind.button,
 
4749
                             mods | ignore,
 
4750
                             frame,
 
4751
                             false,
 
4752
                             ButtonPressMask | ButtonReleaseMask |
 
4753
                                ButtonMotionMask,
 
4754
                             GrabModeSync,
 
4755
                             GrabModeAsync,
 
4756
                             None,
 
4757
                             None);
 
4758
            }
 
4759
        }
 
4760
    }
 
4761
    else
 
4762
    {
 
4763
        /* Grab everything */
 
4764
        XGrabButton (screen->priv->dpy,
 
4765
                     AnyButton,
 
4766
                     AnyModifier,
 
4767
                     frame, false,
 
4768
                     ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
 
4769
                     GrabModeSync,
 
4770
                     GrabModeAsync,
 
4771
                     None,
 
4772
                     None);
 
4773
    }
 
4774
}
 
4775
 
 
4776
 
 
4777
const CompRegion &
 
4778
CompWindow::region () const
 
4779
{
 
4780
    return priv->region;
 
4781
}
 
4782
 
 
4783
const CompRegion &
 
4784
CompWindow::frameRegion () const
 
4785
{
 
4786
    return priv->frameRegion;
 
4787
}
 
4788
 
 
4789
bool
 
4790
CompWindow::inShowDesktopMode ()
 
4791
{
 
4792
    return priv->inShowDesktopMode;
 
4793
}
 
4794
 
 
4795
void
 
4796
CompWindow::setShowDesktopMode (bool value)
 
4797
{
 
4798
    priv->inShowDesktopMode = value;
 
4799
}
 
4800
 
 
4801
bool
 
4802
CompWindow::managed ()
 
4803
{
 
4804
    WRAPABLE_HND_FUNC_RETURN (18, bool, managed);
 
4805
    return priv->managed;
 
4806
}
 
4807
 
 
4808
bool
 
4809
CompWindow::grabbed ()
 
4810
{
 
4811
    return priv->grabbed;
 
4812
}
 
4813
 
 
4814
int
 
4815
CompWindow::pendingMaps ()
 
4816
{
 
4817
    return priv->pendingMaps;
 
4818
}
 
4819
 
 
4820
unsigned int &
 
4821
CompWindow::wmType ()
 
4822
{
 
4823
    return priv->wmType;
 
4824
}
 
4825
 
 
4826
unsigned int
 
4827
CompWindow::activeNum ()
 
4828
{
 
4829
    return priv->activeNum;
 
4830
}
 
4831
 
 
4832
Window
 
4833
CompWindow::frame ()
 
4834
{
 
4835
    return priv->frame;
 
4836
}
 
4837
 
 
4838
CompString
 
4839
CompWindow::resName ()
 
4840
{
 
4841
    if (priv->resName)
 
4842
        return priv->resName;
 
4843
 
 
4844
    return CompString ();
 
4845
}
 
4846
 
 
4847
int
 
4848
CompWindow::mapNum () const
 
4849
{
 
4850
    return priv->mapNum;
 
4851
}
 
4852
 
 
4853
CompStruts *
 
4854
CompWindow::struts ()
 
4855
{
 
4856
    return priv->struts;
 
4857
}
 
4858
 
 
4859
int &
 
4860
CompWindow::saveMask ()
 
4861
{
 
4862
    return priv->saveMask;
 
4863
}
 
4864
 
 
4865
XWindowChanges &
 
4866
CompWindow::saveWc ()
 
4867
{
 
4868
    return priv->saveWc;
 
4869
}
 
4870
 
 
4871
void
 
4872
CompWindow::moveToViewportPosition (int  x,
 
4873
                                    int  y,
 
4874
                                    bool sync)
 
4875
{
 
4876
    int tx, ty;
 
4877
    int vWidth  = screen->width () * screen->vpSize ().width ();
 
4878
    int vHeight = screen->height () * screen->vpSize ().height ();
 
4879
 
 
4880
    if (screen->vpSize ().width () != 1)
 
4881
    {
 
4882
        x += screen->vp ().x () * screen->width ();
 
4883
        x = MOD (x, vWidth);
 
4884
        x -= screen->vp ().x () * screen->width ();
 
4885
    }
 
4886
 
 
4887
    if (screen->vpSize ().height () != 1)
 
4888
    {
 
4889
        y += screen->vp ().y () * screen->height ();
 
4890
        y = MOD (y, vHeight);
 
4891
        y -= screen->vp ().y () * screen->height ();
 
4892
    }
 
4893
 
 
4894
    tx = x - priv->attrib.x;
 
4895
    ty = y - priv->attrib.y;
 
4896
 
 
4897
    if (tx || ty)
 
4898
    {
 
4899
        int m, wx, wy;
 
4900
 
 
4901
        if (!priv->managed)
 
4902
            return;
 
4903
 
 
4904
        if (priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
 
4905
            return;
 
4906
 
 
4907
        if (priv->state & CompWindowStateStickyMask)
 
4908
            return;
 
4909
 
 
4910
        wx = tx;
 
4911
        wy = ty;
 
4912
 
 
4913
        if (screen->vpSize ().width ()!= 1)
 
4914
        {
 
4915
            m = priv->attrib.x + tx;
 
4916
 
 
4917
            if (m - priv->output.left < (int) screen->width () - vWidth)
 
4918
                wx = tx + vWidth;
 
4919
            else if (m + priv->width + priv->output.right > vWidth)
 
4920
                wx = tx - vWidth;
 
4921
        }
 
4922
 
 
4923
        if (screen->vpSize ().height () != 1)
 
4924
        {
 
4925
            m = priv->attrib.y + ty;
 
4926
 
 
4927
            if (m - priv->output.top < (int) screen->height () - vHeight)
 
4928
                wy = ty + vHeight;
 
4929
            else if (m + priv->height + priv->output.bottom > vHeight)
 
4930
                wy = ty - vHeight;
 
4931
        }
 
4932
 
 
4933
        if (priv->saveMask & CWX)
 
4934
            priv->saveWc.x += wx;
 
4935
 
 
4936
        if (priv->saveMask & CWY)
 
4937
            priv->saveWc.y += wy;
 
4938
 
 
4939
        move (wx, wy);
 
4940
 
 
4941
        if (sync)
 
4942
            syncPosition ();
 
4943
    }
 
4944
}
 
4945
 
 
4946
char *
 
4947
CompWindow::startupId ()
 
4948
{
 
4949
     return priv->startupId;
 
4950
}
 
4951
 
 
4952
void
 
4953
PrivateWindow::applyStartupProperties (CompStartupSequence *s)
 
4954
{
 
4955
    int workspace;
 
4956
 
 
4957
    priv->initialViewport.setX (s->viewportX);
 
4958
    priv->initialViewport.setY (s->viewportY);
 
4959
 
 
4960
    workspace = sn_startup_sequence_get_workspace (s->sequence);
 
4961
    if (workspace >= 0)
 
4962
        window->setDesktop (workspace);
 
4963
 
 
4964
    priv->initialTimestamp    =
 
4965
        sn_startup_sequence_get_timestamp (s->sequence);
 
4966
    priv->initialTimestampSet = true;
 
4967
}
 
4968
 
 
4969
unsigned int
 
4970
CompWindow::desktop ()
 
4971
{
 
4972
    return priv->desktop;
 
4973
}
 
4974
 
 
4975
Window
 
4976
CompWindow::clientLeader (bool checkAncestor)
 
4977
{
 
4978
    if (priv->clientLeader)
 
4979
        return priv->clientLeader;
 
4980
 
 
4981
    if (checkAncestor)
 
4982
        return priv->getClientLeaderOfAncestor ();
 
4983
 
 
4984
    return None;
 
4985
}
 
4986
 
 
4987
Window
 
4988
CompWindow::transientFor ()
 
4989
{
 
4990
    return priv->transientFor;
 
4991
}
 
4992
 
 
4993
int
 
4994
CompWindow::pendingUnmaps ()
 
4995
{
 
4996
    return priv->pendingUnmaps;
 
4997
}
 
4998
 
 
4999
bool
 
5000
CompWindow::minimized ()
 
5001
{
 
5002
    WRAPABLE_HND_FUNC_RETURN (15, bool, minimized);
 
5003
    return priv->minimized;
 
5004
}
 
5005
 
 
5006
bool
 
5007
CompWindow::placed ()
 
5008
{
 
5009
    return priv->placed;
 
5010
}
 
5011
 
 
5012
bool
 
5013
CompWindow::shaded ()
 
5014
{
 
5015
    return priv->shaded;
 
5016
}
 
5017
 
 
5018
CompWindowExtents &
 
5019
CompWindow::border () const
 
5020
{
 
5021
    return priv->border;
 
5022
}
 
5023
 
 
5024
CompWindowExtents &
 
5025
CompWindow::input () const
 
5026
{
 
5027
    return priv->input;
 
5028
}
 
5029
 
 
5030
CompWindowExtents &
 
5031
CompWindow::output () const
 
5032
{
 
5033
    return priv->output;
 
5034
}
 
5035
 
 
5036
XSizeHints &
 
5037
CompWindow::sizeHints () const
 
5038
{
 
5039
    return priv->sizeHints;
 
5040
}
 
5041
 
 
5042
void
 
5043
PrivateWindow::updateMwmHints ()
 
5044
{
 
5045
    screen->priv->getMwmHints (priv->id, &priv->mwmFunc, &priv->mwmDecor);
 
5046
    window->recalcActions ();
 
5047
}
 
5048
 
 
5049
void
 
5050
PrivateWindow::updateStartupId ()
 
5051
{
 
5052
    char *oldId = startupId;
 
5053
    bool newId = true;
 
5054
 
 
5055
    startupId = getStartupId ();
 
5056
 
 
5057
    if (oldId)
 
5058
    {
 
5059
        if (strcmp (startupId, oldId) == 0)
 
5060
            newId = false;
 
5061
 
 
5062
        free (oldId);
 
5063
    }
 
5064
 
 
5065
    if (managed && startupId && newId)
 
5066
    {
 
5067
        Time       timestamp = 0;
 
5068
        CompPoint  vp, svp;
 
5069
        CompSize   size;
 
5070
        int        x, y;
 
5071
 
 
5072
        initialTimestampSet = false;
 
5073
        screen->priv->applyStartupProperties (window);
 
5074
 
 
5075
        if (initialTimestampSet)
 
5076
            timestamp = initialTimestamp;
 
5077
 
 
5078
        /* as the viewport can't be transmitted via startup
 
5079
           notification, assume the client changing the ID
 
5080
           wanted to activate the window on the current viewport */
 
5081
 
 
5082
        vp   = window->defaultViewport ();
 
5083
        svp  = screen->vp ();
 
5084
        size = *screen;
 
5085
 
 
5086
        x = window->geometry ().x () + (svp.x () - vp.x ()) * size.width ();
 
5087
        y = window->geometry ().y () + (svp.y () - vp.y ()) * size.height ();
 
5088
        window->moveToViewportPosition (x, y, true);
 
5089
 
 
5090
        if (allowWindowFocus (0, timestamp))
 
5091
            window->activate ();
 
5092
    }
 
5093
}
 
5094
 
 
5095
bool
 
5096
CompWindow::destroyed ()
 
5097
{
 
5098
    return priv->destroyed;
 
5099
}
 
5100
 
 
5101
bool
 
5102
CompWindow::invisible ()
 
5103
{
 
5104
    return priv->invisible;
 
5105
}
 
5106
 
 
5107
XSyncAlarm
 
5108
CompWindow::syncAlarm ()
 
5109
{
 
5110
    return priv->syncAlarm;
 
5111
}
 
5112
 
 
5113
CompWindow::CompWindow (Window            aboveId,
 
5114
                        XWindowAttributes &wa,
 
5115
                        PrivateWindow     *priv) :
 
5116
    PluginClassStorage (windowPluginClassIndices),
 
5117
    priv (priv)
 
5118
{
 
5119
    // TODO: Reparent first!
 
5120
 
 
5121
    priv->window = this;
 
5122
 
 
5123
    screen->insertWindow (this, aboveId);
 
5124
 
 
5125
    priv->attrib = wa;
 
5126
    priv->serverGeometry.set (priv->attrib.x, priv->attrib.y,
 
5127
                              priv->attrib.width, priv->attrib.height,
 
5128
                              priv->attrib.border_width);
 
5129
    priv->syncGeometry.set (priv->attrib.x, priv->attrib.y,
 
5130
                            priv->attrib.width, priv->attrib.height,
 
5131
                            priv->attrib.border_width);
 
5132
    priv->geometry.set (priv->attrib.x, priv->attrib.y,
 
5133
                        priv->attrib.width, priv->attrib.height,
 
5134
                        priv->attrib.border_width);
 
5135
 
 
5136
    priv->width  = priv->attrib.width  + priv->attrib.border_width * 2;
 
5137
    priv->height = priv->attrib.height + priv->attrib.border_width * 2;
 
5138
 
 
5139
    priv->sizeHints.flags = 0;
 
5140
 
 
5141
    priv->recalcNormalHints ();
 
5142
 
 
5143
    priv->transientFor = None;
 
5144
    priv->clientLeader = None;
 
5145
 
 
5146
    XSelectInput (screen->dpy (), priv->id,
 
5147
                  PropertyChangeMask |
 
5148
                  EnterWindowMask    |
 
5149
                  FocusChangeMask);
 
5150
 
 
5151
    priv->alpha     = (priv->attrib.depth == 32);
 
5152
    priv->lastPong  = screen->priv->lastPing;
 
5153
 
 
5154
    if (screen->XShape ())
 
5155
        XShapeSelectInput (screen->dpy (), priv->id, ShapeNotifyMask);
 
5156
 
 
5157
    if (priv->attrib.c_class != InputOnly)
 
5158
    {
 
5159
        priv->region = CompRegion (priv->attrib.x, priv->attrib.y,
 
5160
                                   priv->width, priv->height);
 
5161
        priv->inputRegion = priv->region;
 
5162
 
 
5163
        /* need to check for DisplayModal state on all windows */
 
5164
        priv->state = screen->priv->getWindowState (priv->id);
 
5165
 
 
5166
        priv->updateClassHints ();
 
5167
    }
 
5168
    else
 
5169
    {
 
5170
        priv->attrib.map_state = IsUnmapped;
 
5171
    }
 
5172
 
 
5173
    priv->wmType    = screen->priv->getWindowType (priv->id);
 
5174
    priv->protocols = screen->priv->getProtocols (priv->id);
 
5175
 
 
5176
    if (!overrideRedirect ())
 
5177
    {
 
5178
        priv->updateNormalHints ();
 
5179
        updateStruts ();
 
5180
        priv->updateWmHints ();
 
5181
        priv->updateTransientHint ();
 
5182
 
 
5183
        priv->clientLeader = priv->getClientLeader ();
 
5184
        priv->startupId = priv->getStartupId ();
 
5185
 
 
5186
        recalcType ();
 
5187
 
 
5188
        screen->priv->getMwmHints (priv->id, &priv->mwmFunc, &priv->mwmDecor);
 
5189
 
 
5190
        if (!(priv->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask)))
 
5191
        {
 
5192
            priv->desktop = screen->getWindowProp (priv->id, Atoms::winDesktop,
 
5193
                                                   priv->desktop);
 
5194
            if (priv->desktop != 0xffffffff)
 
5195
            {
 
5196
                if (priv->desktop >= screen->nDesktop ())
 
5197
                    priv->desktop = screen->currentDesktop ();
 
5198
            }
 
5199
        }
 
5200
    }
 
5201
    else
 
5202
    {
 
5203
        recalcType ();
 
5204
    }
 
5205
 
 
5206
    if (priv->attrib.map_state == IsViewable)
 
5207
    {
 
5208
        priv->placed = true;
 
5209
 
 
5210
        if (!overrideRedirect ())
 
5211
        {
 
5212
            // needs to happen right after maprequest
 
5213
            if (!priv->frame)
 
5214
                priv->reparent ();
 
5215
            priv->managed = true;
 
5216
 
 
5217
            if (screen->priv->getWmState (priv->id) == IconicState)
 
5218
            {
 
5219
                if (priv->state & CompWindowStateShadedMask)
 
5220
                    priv->shaded = true;
 
5221
                else
 
5222
                    priv->minimized = true;
 
5223
            }
 
5224
            else
 
5225
            {
 
5226
                if (priv->wmType & (CompWindowTypeDockMask |
 
5227
                                 CompWindowTypeDesktopMask))
 
5228
                {
 
5229
                    setDesktop (0xffffffff);
 
5230
                }
 
5231
                else
 
5232
                {
 
5233
                    if (priv->desktop != 0xffffffff)
 
5234
                        priv->desktop = screen->currentDesktop ();
 
5235
 
 
5236
                    screen->setWindowProp (priv->id, Atoms::winDesktop,
 
5237
                                           priv->desktop);
 
5238
                }
 
5239
            }
 
5240
        }
 
5241
 
 
5242
        priv->attrib.map_state = IsUnmapped;
 
5243
        priv->pendingMaps++;
 
5244
 
 
5245
        map ();
 
5246
 
 
5247
        updateAttributes (CompStackingUpdateModeNormal);
 
5248
 
 
5249
        if (priv->minimized || priv->inShowDesktopMode ||
 
5250
            priv->hidden || priv->shaded)
 
5251
        {
 
5252
            priv->state |= CompWindowStateHiddenMask;
 
5253
 
 
5254
            priv->pendingUnmaps++;
 
5255
 
 
5256
            if (priv->frame && !priv->shaded)
 
5257
                XUnmapWindow (screen->dpy (), priv->frame);
 
5258
 
 
5259
            XUnmapWindow (screen->dpy (), priv->id);
 
5260
 
 
5261
            screen->priv->setWindowState (priv->state, priv->id);
 
5262
        }
 
5263
    }
 
5264
    else if (!overrideRedirect ())
 
5265
    {
 
5266
        if (screen->priv->getWmState (priv->id) == IconicState ||
 
5267
            (priv->hints && priv->hints->initial_state == IconicState))
 
5268
        {
 
5269
            // before everything else in maprequest
 
5270
            if (!priv->frame)
 
5271
                priv->reparent ();
 
5272
 
 
5273
            /* Not managed until map processing is done here
 
5274
             * since to go from Withdrawn -> Iconic the client
 
5275
             * needs to map the window again */
 
5276
            priv->managed = false;
 
5277
            priv->placed  = !(priv->hints && priv->hints->initial_state == IconicState);
 
5278
 
 
5279
            
 
5280
            /* FIXME: CompWindowStateShadedMask can't be set
 
5281
             * at this time anyways, so any window that wants
 
5282
             * to start out shaded will have to be minimized instead */
 
5283
            if (priv->state & CompWindowStateShadedMask)
 
5284
                priv->shaded = true;
 
5285
            else
 
5286
                priv->minimized = true;
 
5287
        }
 
5288
    }
 
5289
 
 
5290
    /* TODO: bailout properly when objectInitPlugins fails */
 
5291
    assert (CompPlugin::windowInitPlugins (this));
 
5292
 
 
5293
    recalcActions ();
 
5294
    priv->updateIconGeometry ();
 
5295
 
 
5296
    if (priv->shaded)
 
5297
        resize (priv->attrib.x, priv->attrib.y,
 
5298
                priv->attrib.width, ++priv->attrib.height - 1,
 
5299
                priv->attrib.border_width);
 
5300
 
 
5301
    if (priv->attrib.map_state == IsViewable)
 
5302
    {
 
5303
        priv->invisible = WINDOW_INVISIBLE (priv);
 
5304
    }
 
5305
}
 
5306
 
 
5307
CompWindow *
 
5308
CoreWindow::manage (Window aboveId, XWindowAttributes &wa)
 
5309
{
 
5310
    return new CompWindow (aboveId, wa, priv);
 
5311
}
 
5312
 
 
5313
CoreWindow::CoreWindow (Window id)
 
5314
{
 
5315
    priv = new PrivateWindow ();
 
5316
    assert (priv);
 
5317
    priv->id = id;
 
5318
}
 
5319
 
 
5320
CompWindow::~CompWindow ()
 
5321
{
 
5322
    screen->unhookWindow (this);
 
5323
 
 
5324
    if (!priv->destroyed)
 
5325
    {
 
5326
        if (priv->frame)
 
5327
        {
 
5328
            priv->unreparent ();
 
5329
        }
 
5330
 
 
5331
        /* restore saved geometry and map if hidden */
 
5332
        if (!priv->attrib.override_redirect)
 
5333
        {
 
5334
            if (priv->saveMask)
 
5335
                XConfigureWindow (screen->dpy (), priv->id,
 
5336
                                  priv->saveMask, &priv->saveWc);
 
5337
 
 
5338
            if (!priv->hidden)
 
5339
            {
 
5340
                if (priv->state & CompWindowStateHiddenMask)
 
5341
                    XMapWindow (screen->dpy (), priv->id);
 
5342
            }
 
5343
        }
 
5344
 
 
5345
        if (screen->XShape ())
 
5346
            XShapeSelectInput (screen->dpy (), priv->id, NoEventMask);
 
5347
 
 
5348
        if (priv->id != screen->priv->grabWindow)
 
5349
            XSelectInput (screen->dpy (), priv->id, NoEventMask);
 
5350
 
 
5351
        XUngrabButton (screen->dpy (), AnyButton, AnyModifier, priv->id);
 
5352
    }
 
5353
 
 
5354
    if (priv->attrib.map_state == IsViewable)
 
5355
    {
 
5356
        if (priv->type == CompWindowTypeDesktopMask)
 
5357
            screen->priv->desktopWindowCount--;
 
5358
 
 
5359
        if (priv->destroyed && priv->struts)
 
5360
            screen->updateWorkarea ();
 
5361
    }
 
5362
 
 
5363
    if (priv->destroyed)
 
5364
        screen->priv->updateClientList ();
 
5365
 
 
5366
    CompPlugin::windowFiniPlugins (this);
 
5367
 
 
5368
    delete priv;
 
5369
}
 
5370
 
 
5371
PrivateWindow::PrivateWindow () :
 
5372
    priv (this),
 
5373
    refcnt (1),
 
5374
    id (None),
 
5375
    frame (None),
 
5376
    wrapper (None),
 
5377
    mapNum (0),
 
5378
    activeNum (0),
 
5379
    transientFor (None),
 
5380
    clientLeader (None),
 
5381
    hints (NULL),
 
5382
    inputHint (true),
 
5383
    alpha (false),
 
5384
    width (0),
 
5385
    height (0),
 
5386
    region (),
 
5387
    wmType (0),
 
5388
    type (CompWindowTypeUnknownMask),
 
5389
    state (0),
 
5390
    actions (0),
 
5391
    protocols (0),
 
5392
    mwmDecor (MwmDecorAll),
 
5393
    mwmFunc (MwmFuncAll),
 
5394
    invisible (true),
 
5395
    destroyed (false),
 
5396
    managed (false),
 
5397
    unmanaging (false),
 
5398
    destroyRefCnt (1),
 
5399
    unmapRefCnt (1),
 
5400
 
 
5401
    initialViewport (0, 0),
 
5402
 
 
5403
    initialTimestamp (0),
 
5404
    initialTimestampSet (false),
 
5405
 
 
5406
    fullscreenMonitorsSet (false),
 
5407
 
 
5408
    placed (false),
 
5409
    minimized (false),
 
5410
    inShowDesktopMode (false),
 
5411
    shaded (false),
 
5412
    hidden (false),
 
5413
    grabbed (false),
 
5414
 
 
5415
    desktop (0),
 
5416
 
 
5417
    pendingUnmaps (0),
 
5418
    pendingMaps (0),
 
5419
 
 
5420
    startupId (0),
 
5421
    resName (0),
 
5422
    resClass (0),
 
5423
 
 
5424
    group (0),
 
5425
 
 
5426
    lastPong (0),
 
5427
    alive (true),
 
5428
 
 
5429
    struts (0),
 
5430
 
 
5431
    icons (0),
 
5432
    noIcons (false),
 
5433
 
 
5434
    saveMask (0),
 
5435
    syncCounter (0),
 
5436
    syncAlarm (None),
 
5437
    syncWaitTimer (),
 
5438
 
 
5439
    syncWait (false),
 
5440
    closeRequests (false),
 
5441
    lastCloseRequestTime (0)
 
5442
{
 
5443
    input.left   = 0;
 
5444
    input.right  = 0;
 
5445
    input.top    = 0;
 
5446
    input.bottom = 0;
 
5447
 
 
5448
    border.top    = 0;
 
5449
    border.bottom = 0;
 
5450
    border.left   = 0;
 
5451
    border.right  = 0;
 
5452
 
 
5453
    output.left   = 0;
 
5454
    output.right  = 0;
 
5455
    output.top    = 0;
 
5456
    output.bottom = 0;
 
5457
 
 
5458
    syncWaitTimer.setTimes (1000, 1200);
 
5459
    syncWaitTimer.setCallback (boost::bind (&PrivateWindow::handleSyncAlarm,
 
5460
                                            this));
 
5461
}
 
5462
 
 
5463
PrivateWindow::~PrivateWindow ()
 
5464
{
 
5465
     if (syncAlarm)
 
5466
        XSyncDestroyAlarm (screen->dpy (), syncAlarm);
 
5467
 
 
5468
    syncWaitTimer.stop ();
 
5469
 
 
5470
    if (frame)
 
5471
        XDestroyWindow (screen->dpy (), frame);
 
5472
 
 
5473
    if (struts)
 
5474
        free (struts);
 
5475
 
 
5476
    if (hints)
 
5477
        XFree (hints);
 
5478
 
 
5479
    if (icons.size ())
 
5480
        freeIcons ();
 
5481
 
 
5482
    if (startupId)
 
5483
        free (startupId);
 
5484
 
 
5485
    if (resName)
 
5486
        free (resName);
 
5487
 
 
5488
    if (resClass)
 
5489
        free (resClass);
 
5490
}
 
5491
 
 
5492
bool
 
5493
CompWindow::syncWait ()
 
5494
{
 
5495
    return priv->syncWait;
 
5496
}
 
5497
 
 
5498
bool
 
5499
CompWindow::alpha ()
 
5500
{
 
5501
    WRAPABLE_HND_FUNC_RETURN (16, bool, alpha);
 
5502
 
 
5503
    return priv->alpha;
 
5504
}
 
5505
 
 
5506
bool
 
5507
CompWindow::overrideRedirect ()
 
5508
{
 
5509
    return priv->attrib.override_redirect;
 
5510
}
 
5511
 
 
5512
void
 
5513
PrivateWindow::setOverrideRedirect (bool overrideRedirect)
 
5514
{
 
5515
    if (overrideRedirect == window->overrideRedirect ())
 
5516
        return;
 
5517
 
 
5518
    priv->attrib.override_redirect = overrideRedirect ? 1 : 0;
 
5519
    window->recalcType ();
 
5520
    window->recalcActions ();
 
5521
 
 
5522
    screen->matchPropertyChanged (window);
 
5523
}
 
5524
 
 
5525
bool
 
5526
CompWindow::isMapped () const
 
5527
{
 
5528
    return priv->mapNum > 0;
 
5529
}
 
5530
 
 
5531
bool
 
5532
CompWindow::isViewable () const
 
5533
{
 
5534
    return (priv->attrib.map_state == IsViewable);
 
5535
}
 
5536
 
 
5537
bool
 
5538
CompWindow::isFocussable ()
 
5539
{
 
5540
    WRAPABLE_HND_FUNC_RETURN (17, bool, isFocussable);
 
5541
 
 
5542
    if (priv->inputHint)
 
5543
        return true;
 
5544
 
 
5545
    if (priv->protocols & CompWindowProtocolTakeFocusMask)
 
5546
        return true;
 
5547
 
 
5548
    return false;
 
5549
}
 
5550
 
 
5551
int
 
5552
CompWindow::windowClass ()
 
5553
{
 
5554
    return priv->attrib.c_class;
 
5555
}
 
5556
 
 
5557
unsigned int
 
5558
CompWindow::depth ()
 
5559
{
 
5560
    return priv->attrib.depth;
 
5561
}
 
5562
 
 
5563
bool
 
5564
CompWindow::alive ()
 
5565
{
 
5566
    return priv->alive;
 
5567
}
 
5568
 
 
5569
unsigned int
 
5570
CompWindow::mwmDecor ()
 
5571
{
 
5572
    return priv->mwmDecor;
 
5573
}
 
5574
 
 
5575
unsigned int
 
5576
CompWindow::mwmFunc ()
 
5577
{
 
5578
    return priv->mwmFunc;
 
5579
}
 
5580
 
 
5581
/* TODO: This function should be able to check the XShape event
 
5582
 * kind and only get/set shape rectangles for either ShapeInput
 
5583
 * or ShapeBounding, but not both at the same time
 
5584
 */
 
5585
 
 
5586
void
 
5587
CompWindow::updateFrameRegion ()
 
5588
{
 
5589
    if (priv->frame && priv->serverGeometry.width () == priv->geometry.width () &&
 
5590
         priv->serverGeometry.height () == priv->geometry.height ())
 
5591
    {
 
5592
        CompRect   r;
 
5593
        int        x, y;
 
5594
 
 
5595
        priv->frameRegion = CompRegion ();
 
5596
 
 
5597
        updateFrameRegion (priv->frameRegion);
 
5598
 
 
5599
        if (!shaded ())
 
5600
        {
 
5601
            r = priv->region.boundingRect ();
 
5602
            priv->frameRegion -= r;
 
5603
 
 
5604
            r.setGeometry (r.x1 () - priv->input.left,
 
5605
                        r.y1 () - priv->input.top,
 
5606
                        r.width  () + priv->input.right + priv->input.left,
 
5607
                        r.height () + priv->input.bottom + priv->input.top);
 
5608
 
 
5609
            priv->frameRegion &= CompRegion (r);
 
5610
        }
 
5611
 
 
5612
        x = priv->geometry.x () - priv->input.left;
 
5613
        y = priv->geometry.y () - priv->input.top;
 
5614
 
 
5615
        XShapeCombineRegion (screen->dpy (), priv->frame,
 
5616
                             ShapeBounding, -x, -y,
 
5617
                             priv->frameRegion.united (priv->region).handle (),
 
5618
                             ShapeSet);
 
5619
 
 
5620
        XShapeCombineRegion (screen->dpy (), priv->frame,
 
5621
                             ShapeInput, -x, -y,
 
5622
                             priv->frameRegion.united (priv->inputRegion).handle (),
 
5623
                             ShapeSet);
 
5624
    }
 
5625
}
 
5626
 
 
5627
void
 
5628
CompWindow::setWindowFrameExtents (CompWindowExtents *b,
 
5629
                                   CompWindowExtents *i)
 
5630
{
 
5631
    /* Input extents are used for frame size,
 
5632
     * Border extents used for placement.
 
5633
     */
 
5634
 
 
5635
    if (!i)
 
5636
        i = b;
 
5637
  
 
5638
    if (priv->input.left   != i->left ||
 
5639
        priv->input.right  != i->right ||
 
5640
        priv->input.top    != i->top ||
 
5641
        priv->input.bottom != i->bottom)
 
5642
    {
 
5643
        unsigned long data[4];
 
5644
 
 
5645
        priv->input = *i;
 
5646
        priv->border = *b;
 
5647
 
 
5648
        recalcActions ();
 
5649
 
 
5650
        /* Use b for _NET_WM_FRAME_EXTENTS here because
 
5651
         * that is the representation of the actual decoration
 
5652
         * around the window that the user sees and should
 
5653
         * be used for placement and such */
 
5654
 
 
5655
        data[0] = b->left;
 
5656
        data[1] = b->right;
 
5657
        data[2] = b->top;
 
5658
        data[3] = b->bottom;
 
5659
 
 
5660
        XChangeProperty (screen->dpy (), priv->id,
 
5661
                         Atoms::frameExtents,
 
5662
                         XA_CARDINAL, 32, PropModeReplace,
 
5663
                         (unsigned char *) data, 4);
 
5664
        priv->updateSize ();
 
5665
        priv->updateFrameWindow ();
 
5666
    }
 
5667
}
 
5668
 
 
5669
bool
 
5670
CompWindow::hasUnmapReference ()
 
5671
{
 
5672
    return (priv && priv->unmapRefCnt > 1);
 
5673
}
 
5674
 
 
5675
void
 
5676
CompWindow::updateFrameRegion (CompRegion& region)
 
5677
    WRAPABLE_HND_FUNC (12, updateFrameRegion, region)
 
5678
 
 
5679
bool
 
5680
PrivateWindow::reparent ()
 
5681
{
 
5682
    XSetWindowAttributes attr;
 
5683
    XWindowAttributes    wa;
 
5684
    XWindowChanges       xwc;
 
5685
    int                  mask;
 
5686
    unsigned int         nchildren;
 
5687
    Window               *children, root_return, parent_return;
 
5688
    CompWindow::Geometry &sg = serverGeometry;
 
5689
    Display              *dpy = screen->dpy ();
 
5690
    Visual               *visual = DefaultVisual (screen->dpy (),
 
5691
                                                  screen->screenNum ());
 
5692
    Colormap             cmap = DefaultColormap (screen->dpy (),
 
5693
                                                 screen->screenNum ());
 
5694
    bool success = false;
 
5695
 
 
5696
    if (frame || attrib.override_redirect)
 
5697
        return false;
 
5698
 
 
5699
    XSync (dpy, false);
 
5700
    XGrabServer (dpy);
 
5701
 
 
5702
    /* Don't ever reparent windows which have ended up
 
5703
     * reparented themselves on the server side but not
 
5704
     * on the client side */
 
5705
 
 
5706
    success = XQueryTree (dpy, id, &root_return,
 
5707
                          &parent_return, &children, &nchildren);
 
5708
 
 
5709
    if (success && parent_return != root_return)
 
5710
    {
 
5711
        success = false;
 
5712
        XFree (children);
 
5713
    }
 
5714
 
 
5715
    if (success && !XGetWindowAttributes (dpy, id, &wa))
 
5716
    {
 
5717
        success = false;
 
5718
        XFree (children);
 
5719
    }
 
5720
 
 
5721
    if (!success)
 
5722
    {
 
5723
        XUngrabServer (dpy);
 
5724
        XSync (dpy, false);
 
5725
        return false;
 
5726
    }
 
5727
 
 
5728
    XFree (children);
 
5729
 
 
5730
    XChangeSaveSet (dpy, id, SetModeInsert);
 
5731
    XSelectInput (dpy, id, NoEventMask);
 
5732
    XSelectInput (dpy, screen->root (), NoEventMask);
 
5733
 
 
5734
    xwc.border_width = 0;
 
5735
    XConfigureWindow (dpy, id, CWBorderWidth, &xwc);
 
5736
 
 
5737
    mask = CWBorderPixel | CWColormap | CWBackPixmap;
 
5738
 
 
5739
    if (attrib.depth == 32)
 
5740
    {
 
5741
        cmap = attrib.colormap;
 
5742
        visual = attrib.visual;
 
5743
    }
 
5744
 
 
5745
    attr.background_pixmap = None;
 
5746
    attr.border_pixel      = 0;
 
5747
    attr.colormap          = cmap;
 
5748
 
 
5749
    frame = XCreateWindow (dpy, screen->root (), 0, 0,
 
5750
                           sg.width (), sg.height (), 0, attrib.depth,
 
5751
                           InputOutput, visual, mask, &attr);
 
5752
 
 
5753
    wrapper = XCreateWindow (dpy, frame, 0, 0,
 
5754
                            sg.width (), sg.height (), 0, attrib.depth,
 
5755
                            InputOutput, visual, mask, &attr);
 
5756
 
 
5757
    xwc.stack_mode = Below;
 
5758
    xwc.sibling = id;
 
5759
 
 
5760
    /* Make sure the frame is underneath the client */
 
5761
    XConfigureWindow (dpy, frame, CWSibling | CWStackMode, &xwc);
 
5762
 
 
5763
    /* Wait for the restacking to finish */
 
5764
    XSync (dpy, false);
 
5765
 
 
5766
    /* Always need to have the wrapper window mapped */
 
5767
    XMapWindow (dpy, wrapper);
 
5768
 
 
5769
    /* Reparent the client into the wrapper window */
 
5770
    XReparentWindow (dpy, id, wrapper, 0, 0);
 
5771
 
 
5772
    attr.event_mask = PropertyChangeMask | FocusChangeMask |
 
5773
                      EnterWindowMask | LeaveWindowMask;
 
5774
 
 
5775
    /* We don't care about client events on the frame, and listening for them
 
5776
     * will probably end up fighting the client anyways, so disable them */
 
5777
 
 
5778
    attr.do_not_propagate_mask = KeyPressMask | KeyReleaseMask |
 
5779
                                 ButtonPressMask | ButtonReleaseMask |
 
5780
                                 EnterWindowMask | LeaveWindowMask |
 
5781
                                 PointerMotionMask | PointerMotionHintMask |
 
5782
                                 Button1MotionMask | Button2MotionMask |
 
5783
                                 Button3MotionMask | Button4MotionMask |
 
5784
                                 Button5MotionMask | ButtonMotionMask |
 
5785
                                 KeymapStateMask | ExposureMask |
 
5786
                                 VisibilityChangeMask | StructureNotifyMask |
 
5787
                                 ResizeRedirectMask | SubstructureNotifyMask |
 
5788
                                 SubstructureRedirectMask | FocusChangeMask |
 
5789
                                 PropertyChangeMask | ColormapChangeMask |
 
5790
                                 OwnerGrabButtonMask;
 
5791
 
 
5792
    XChangeWindowAttributes (dpy, id, CWEventMask | CWDontPropagate, &attr);
 
5793
 
 
5794
    if (wa.map_state == IsViewable || shaded)
 
5795
        XMapWindow (dpy, frame);
 
5796
 
 
5797
    attr.event_mask = SubstructureRedirectMask | StructureNotifyMask |
 
5798
                      SubstructureNotifyMask | EnterWindowMask |
 
5799
                      LeaveWindowMask;
 
5800
 
 
5801
    XChangeWindowAttributes (dpy, frame, CWEventMask, &attr);
 
5802
    XChangeWindowAttributes (dpy, wrapper, CWEventMask, &attr);
 
5803
 
 
5804
    XSelectInput (dpy, screen->root (),
 
5805
                  SubstructureRedirectMask |
 
5806
                  SubstructureNotifyMask   |
 
5807
                  StructureNotifyMask      |
 
5808
                  PropertyChangeMask       |
 
5809
                  LeaveWindowMask          |
 
5810
                  EnterWindowMask          |
 
5811
                  KeyPressMask             |
 
5812
                  KeyReleaseMask           |
 
5813
                  ButtonPressMask          |
 
5814
                  ButtonReleaseMask        |
 
5815
                  FocusChangeMask          |
 
5816
                  ExposureMask);
 
5817
 
 
5818
    XUngrabServer (dpy);
 
5819
    XSync (dpy, false);
 
5820
 
 
5821
    XMoveResizeWindow (dpy, frame, sg.x (), sg.y (), sg.width (), sg.height ());
 
5822
 
 
5823
    updatePassiveButtonGrabs ();
 
5824
 
 
5825
    window->windowNotify (CompWindowNotifyReparent);
 
5826
 
 
5827
    return true;
 
5828
}
 
5829
 
 
5830
void
 
5831
PrivateWindow::unreparent ()
 
5832
{
 
5833
    Display        *dpy = screen->dpy ();
 
5834
    XEvent         e;
 
5835
    bool           alive = true;
 
5836
    XWindowChanges xwc;
 
5837
 
 
5838
    if (!frame)
 
5839
        return;
 
5840
 
 
5841
    XSync (dpy, false);
 
5842
 
 
5843
    if (XCheckTypedWindowEvent (dpy, id, DestroyNotify, &e))
 
5844
    {
 
5845
        XPutBackEvent (dpy, &e);
 
5846
        alive = false;
 
5847
    }
 
5848
 
 
5849
    if ((!destroyed) && alive)
 
5850
    {
 
5851
        XGrabServer (dpy);
 
5852
 
 
5853
        XChangeSaveSet (dpy, id, SetModeDelete);
 
5854
        XSelectInput (dpy, frame, NoEventMask);
 
5855
        XSelectInput (dpy, wrapper, NoEventMask);
 
5856
        XSelectInput (dpy, id, NoEventMask);
 
5857
        XSelectInput (dpy, screen->root (), NoEventMask);
 
5858
        XReparentWindow (dpy, id, screen->root (), 0, 0);
 
5859
 
 
5860
        /* Wait for the reparent to finish */
 
5861
        XSync (dpy, false);
 
5862
 
 
5863
        xwc.stack_mode = Below;
 
5864
        xwc.sibling    = frame;
 
5865
        XConfigureWindow (dpy, id, CWSibling | CWStackMode, &xwc);
 
5866
 
 
5867
        /* Wait for the window to be restacked */
 
5868
        XSync (dpy, false);
 
5869
 
 
5870
        XUnmapWindow (dpy, frame);
 
5871
 
 
5872
        XSelectInput (dpy, id, PropertyChangeMask | EnterWindowMask |
 
5873
                      FocusChangeMask);
 
5874
 
 
5875
        XSelectInput (dpy, screen->root (),
 
5876
                  SubstructureRedirectMask |
 
5877
                  SubstructureNotifyMask   |
 
5878
                  StructureNotifyMask      |
 
5879
                  PropertyChangeMask       |
 
5880
                  LeaveWindowMask          |
 
5881
                  EnterWindowMask          |
 
5882
                  KeyPressMask             |
 
5883
                  KeyReleaseMask           |
 
5884
                  ButtonPressMask          |
 
5885
                  ButtonReleaseMask        |
 
5886
                  FocusChangeMask          |
 
5887
                  ExposureMask);
 
5888
 
 
5889
        XUngrabServer (dpy);
 
5890
        XSync (dpy, false);
 
5891
 
 
5892
        XMoveWindow (dpy, id, serverGeometry.x (), serverGeometry.y ());
 
5893
    }
 
5894
 
 
5895
    XDestroyWindow (dpy, wrapper);
 
5896
    XDestroyWindow (dpy, frame);
 
5897
    wrapper = None;
 
5898
    frame = None;
 
5899
 
 
5900
    window->windowNotify (CompWindowNotifyUnreparent);
 
5901
}