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

« back to all changes in this revision

Viewing changes to .pc/102_attrib-fix-rev-2796.patch/src/window.cpp

  • Committer: Package Import Robot
  • Author(s): Didier Roche, David Barth, Didier Roche
  • Date: 2011-09-12 08:09:46 UTC
  • mfrom: (0.168.10 upstream)
  • Revision ID: package-import@ubuntu.com-20110912080946-1tp6975muls4eb2v
Tags: 1:0.9.5.94+bzr2803-0ubuntu1
[ David Barth ]
* New upstream release 0.9.5.94
  - Merge in change to have a serverWindows () this break the API
  - "mumble fix", ie "It is possible to stack windows relative to windows that are destroyed" (LP: #837252)
  - fix for "Severe screen corruption after rotate the screen" (LP: #833549)
  - Remove inactive API
  - Fix for "vp switch causes windows to move further offscreen" (LP: #831987)
  - Debug messages removed
  - Memory leak fix in gtk and unity window decorators
  - Fix further issues with shaped windows mapping/unmapping (rev. 2793)
* removed patches that were integrated into the new upstream release
  - debian/patches/100_core-fix-rev-2794.patch
  - debian/patches/101_memleak-fix-rev-2794.patch
  - debian/patches/102_attrib-fix-rev-2796.patch
  - debian/patches/103_driver_workaround.patch

[ Didier Roche ]
* debian/rules, debian/compiz-gnome.install, debian/compiz-keybindings.sed:
  - readd and tweak some compiz keys for g-c-c and Gnome integration
    This fixes Ctrl + Alt + T to open a terminal (LP: #820266)

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