~focus-follows-mouse/ubuntu/precise/compiz/fix-883383

« back to all changes in this revision

Viewing changes to .pc/101_git_fix_uninitialized_val.patch/src/window.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2011-03-22 21:45:34 UTC
  • mfrom: (0.168.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20110322214534-l6i6ds54os5uoqt1
Tags: 1:0.9.4git20110322-0ubuntu1
* New upstream bug fix snapshot:
  - Application windows can sometimes fail to display and will
    mask regions of the screen (LP: #709461)
  - Compiz switcher Alt-Tab order is not predictable - should
    maintain LIFO ordering in application switcher (LP: #175874)
  - after compiz crashed, gnome-panel isn't mapped again (LP: #711378)
  - invisible windows border problem (LP: #710271)
  - Compiz thinks you are clicking in an edge window when you
    are not (LP: #734250)
  - Add test case for invisible window regressions (LP: #736876)
  - often can't alt-click-dnd to move the focussed dialog (LP: #711911)
  - When windows open for the first time they should not hide (LP: #723878)
  - Unity Grid is broken for multi-monitor setups (LP: #709221)
  - Pixmaps trashed during animations when window is unmapped (LP: #733331)
  - Windows have blank decorations when rapidly closing and
    reopening (LP: #733328)
  - Unity is not restored on unity/compiz crash: compiz doesn't register
    properly with gnome-session (LP: #716462)
* remove the patch taken from upstream
* refresh u-w-d patch with latest upstream work
* debian/compiz-core.install:
  - image move to the final destination
* debian/patches/100_bump_core.h.patch:
  - bump for ABI breakage
* debian/compiz-decorator:
  - use gtk-window-decorator and not unity-window-decorator as it's really
    crashy for now (will probably redo an upload tomorrow with a fixed
    decorator)

Show diffs side-by-side

added added

removed removed

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