~mniess/ubuntu/precise/compiz/fix-screenshot

« back to all changes in this revision

Viewing changes to .pc/fix-864330.patch/src/window.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2011-10-12 10:44:49 UTC
  • Revision ID: james.westby@ubuntu.com-20111012104449-j23o8yxernjq2dju
Tags: 1:0.9.6+bzr20110929-0ubuntu5
* debian/patches/fix-864330.patch:
  - fix windows which can have towed moving (LP: #864330)
* debian/patches/fix-864478.patch:
  - Window shading is broken (LP: #864478)

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