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

« back to all changes in this revision

Viewing changes to .pc/02_fix_autofocus_minimize_window.patch/src/window.cpp

  • Committer: Package Import Robot
  • Author(s): Didier Roche
  • Date: 2011-10-04 08:29:38 UTC
  • Revision ID: package-import@ubuntu.com-20111004082938-sy427ni6to2x581u
Tags: 1:0.9.6+bzr20110929-0ubuntu2
* debian/patches/02_fix_autofocus_minimize_window.patch:
  - closing a window gives focus to last minimized window (LP: #862719)
* debian/patches/03_fix_configureframe.patch:
  - compiz crashed with SIGSEGV in PrivateWindow::configureFrame()
    (LP: #861909)

Show diffs side-by-side

added added

removed removed

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