~ubuntu-branches/ubuntu/precise/compiz/precise

« back to all changes in this revision

Viewing changes to .pc/fix_871801.patch/src/window.cpp

  • Committer: Package Import Robot
  • Author(s): Didier Roche, Łukasz 'sil2100' Zemczak, Didier Roche
  • Date: 2012-03-12 10:22:10 UTC
  • mfrom: (0.168.15)
  • Revision ID: package-import@ubuntu.com-20120312102210-e248pzbccr7r2tdq
Tags: 1:0.9.7.0+bzr3035-0ubuntu1
[ Łukasz 'sil2100' Zemczak ]
* New upstream snapshot:
  - Fix gtk-window-decorator crash upon demaximizing a window (LP: #930071)
  - Fix core keybindings (LP: #930412)
  - Fixes compiz crash with SIGSEGV on shutdown (LP: #931283)
  - Plugins can't tell the difference between a key-tap and modifier
    key-release (LP: #925293)
  - compiz-core r3001 (and 3002) ftbfs (LP: #933226)
  - Semi-maximized windows have no shadow or frame (LP: #924736)
  - Untranslated strings in gtk-window-decorator (LP: #780505)
  - Initialize the _NET_WM_STATE_FOCUSED (LP: #932087)
  - [regression] Customized shortcuts don't work (LP: #931927)
  - Window stacking problem (LP: #936675)
  - Quickly demaximized windows can receive maximized window decorations if 
    they were initially maximized (LP: #936778)
  - Maximized windows do not get shadows at all (LP: #936774)
  - [regression] Launcher, top panel and keyboard un-responsive after using 
    any Super-x shortcut (LP: #934058)
  - No draggable border if mutter isn't installed (LP: #936781)
  - Fix compiz crash with SIGSEGV in XDefineCursor() (LP: #936487)
  - Fixes memory leak at DecorWindow::updateSwitcher() (LP: #940115)
  - Unresolved symbols in plugins cause compiz to exit (LP: #938478)
  - Fix compiz spending about 51% of its CPU time in CompRegion 
    construction/destruction (LP: #940139)
  - Fix Conditional jump or move depends on uninitialised value(s) in 
    decor_match_pixmap (LP: #940066)
  - Fix 'show desktop' behaviour (LP: #871801)
  - Tweak algorithm used to cast shadows on maximized windows (LP: #936784)
  - "Svg" and "Png" should be "SVG and "PNG" (LP: #942890)
  - Fix invalid memory usage after free() in DecorWindow (LP: #943116)
  - Fix alt + F10 (LP: #943223)
* Removed cherry-picked patches
* debian/patches/fix_944631.patch:
  - Always replay the keyboard if something was grabbed and didn't trigger 
    an action and don't trigger actions which aren't added accidentally 
    (LP: #943612) (LP: #944631)
* debian/patches/fix_923683.patch:
  - Backports a patch which prevents the shift race condition

[ Didier Roche ]
* debian/patches/fix_alt_pressing.patch:
  - Patch from ddv to fix all the regressions with the alt key fix and other
    (LP: #943851, #945373)
  - Fix Quicklist are not showing if right-clicking a launcher icon in Expo
    mode if triggered by Super + S (LP: #944979)
* debian/patches/fix_806255.patch:
  - Unity/compiz intercepts keystrokes from grabbed windows (LP: #806255)
* debian/patches/fix_943194.patch:
  - second part for the alt key fix (LP: #943194)
* debian/patches/additional_alt_tapping_fix.patch:
  - again another alt tapping related fix for some regressions from the
    previous branch. Taken from "tapping-panacea" upstream branch.

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