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

« back to all changes in this revision

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

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

Show diffs side-by-side

added added

removed removed

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