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

« back to all changes in this revision

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

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

Show diffs side-by-side

added added

removed removed

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