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

« back to all changes in this revision

Viewing changes to .pc/fix-869316_869919.patch/src/stackdebugger.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 © 2011 Canonical Ltd.
 
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
 * Canonical Ltd. not be used in advertising or publicity pertaining to
 
10
 * distribution of the software without specific, written prior permission.
 
11
 * Canonical Ltd. 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
 * CANONICAL, LTD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 
16
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
 
17
 * NO EVENT SHALL CANONICAL, LTD. 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
 * Authored by: Sam Spilsbury <sam.spilsbury@canonical.com>
 
24
 */
 
25
 
 
26
#include "privatestackdebugger.h"
 
27
#include "privatewindow.h"
 
28
#include <poll.h>
 
29
 
 
30
namespace
 
31
{
 
32
    StackDebugger * gStackDebugger = NULL;
 
33
}
 
34
 
 
35
StackDebugger *
 
36
StackDebugger::Default ()
 
37
{
 
38
    return gStackDebugger;
 
39
}
 
40
 
 
41
void
 
42
StackDebugger::SetDefault (StackDebugger *dbg)
 
43
{
 
44
    if (gStackDebugger)
 
45
        delete gStackDebugger;
 
46
 
 
47
    gStackDebugger = dbg;
 
48
}
 
49
 
 
50
StackDebugger::StackDebugger (Display *dpy, Window root, boost::function <eventList ()> evProc) :
 
51
    mServerNChildren (0),
 
52
    mServerChildren (NULL),
 
53
    mWindowsChanged (false),
 
54
    mServerWindowsChanged (false),
 
55
    mRoot (root),
 
56
    mDpy (dpy),
 
57
    getEventsProc (evProc)
 
58
{
 
59
}
 
60
 
 
61
StackDebugger::~StackDebugger ()
 
62
{
 
63
    if (mServerChildren)
 
64
    {
 
65
        XFree (mServerChildren);
 
66
        mServerChildren = NULL;
 
67
        mServerNChildren = 0;
 
68
    }
 
69
}
 
70
 
 
71
bool
 
72
StackDebugger::timedOut ()
 
73
{
 
74
    return mTimeoutRequired;
 
75
}
 
76
 
 
77
void
 
78
StackDebugger::removeServerWindow (Window id)
 
79
{
 
80
    /* Find the toplevel window in the list and remove it */
 
81
    for (CompWindowList::iterator it = mLastServerWindows.begin ();
 
82
         it != mLastServerWindows.end ();
 
83
         it++)
 
84
    {
 
85
        if ((*it)->id () == id)
 
86
        {
 
87
            mLastServerWindows.erase (it);
 
88
            break;
 
89
        }
 
90
    }
 
91
}
 
92
 
 
93
void
 
94
StackDebugger::overrideRedirectRestack (Window toplevel, Window sibling)
 
95
{
 
96
    CompWindow *tl = screen->findWindow (toplevel);
 
97
 
 
98
    removeServerWindow (toplevel);
 
99
 
 
100
    /* Find the sibling of this window and insert above it or at
 
101
     * the bottom if the sibling is 0 */
 
102
 
 
103
    if (sibling)
 
104
    {
 
105
        for (CompWindowList::iterator it = mLastServerWindows.begin ();
 
106
             it != mLastServerWindows.end ();
 
107
             it++)
 
108
        {
 
109
            if (sibling == (*it)->id () ||
 
110
                sibling == (*it)->frame ())
 
111
            {
 
112
                mLastServerWindows.insert (++it, tl);
 
113
                break;
 
114
            }
 
115
        }
 
116
    }
 
117
    else
 
118
        mLastServerWindows.push_front (tl);
 
119
}
 
120
 
 
121
StackDebugger::eventList
 
122
StackDebugger::loadStack (CompWindowList &serverWindows, bool wait)
 
123
{
 
124
    Window rootRet, parentRet;
 
125
    eventList events;
 
126
 
 
127
    if (mServerChildren)
 
128
        XFree (mServerChildren);
 
129
 
 
130
    XSync (mDpy, FALSE);
 
131
    XGrabServer (mDpy);
 
132
    XQueryTree (mDpy, mRoot, &rootRet, &parentRet,
 
133
                &mServerChildren, &mServerNChildren);
 
134
 
 
135
    events = getEventsProc ();
 
136
 
 
137
    XSync (mDpy, FALSE);
 
138
 
 
139
    /* It is possible that X might not be keeping up with us, so
 
140
     * we should give it about 300 ms in case the stacks are out of sync
 
141
     * in order to deliver any more events that might be pending */
 
142
 
 
143
    mTimeoutRequired = false;
 
144
    mLastServerWindows = serverWindows;
 
145
 
 
146
    if (mServerNChildren != serverWindows.size () && wait)
 
147
    {
 
148
        eventList moreEvents;
 
149
        struct pollfd pfd;
 
150
 
 
151
        pfd.events = POLLIN;
 
152
        pfd.revents = 0;
 
153
        pfd.fd = ConnectionNumber (mDpy);
 
154
 
 
155
        poll (&pfd, 1, 300);
 
156
 
 
157
        moreEvents = getEventsProc ();
 
158
 
 
159
        foreach (XEvent e, moreEvents)
 
160
            events.push_back (e);
 
161
 
 
162
        mTimeoutRequired = true;
 
163
    }
 
164
 
 
165
    mDestroyedFrames.clear ();
 
166
 
 
167
    XUngrabServer (mDpy);
 
168
    XSync (mDpy, FALSE);
 
169
 
 
170
    return events;
 
171
}
 
172
 
 
173
void
 
174
StackDebugger::addDestroyedFrame (Window f)
 
175
{
 
176
    mDestroyedFrames.push_back (f);
 
177
}
 
178
 
 
179
void
 
180
StackDebugger::removeDestroyedFrame (Window f)
 
181
{
 
182
    mDestroyedFrames.remove (f);
 
183
}
 
184
 
 
185
bool
 
186
StackDebugger::cmpStack (CompWindowList &windows,
 
187
                         CompWindowList &serverWindows,
 
188
                         bool           verbose)
 
189
{
 
190
    std::vector <Window>             serverSideWindows;
 
191
    CompWindowList::reverse_iterator lrrit = windows.rbegin ();
 
192
    CompWindowList::reverse_iterator lsrit = mLastServerWindows.rbegin ();
 
193
    unsigned int                     i = 0;
 
194
    bool                             err = false;
 
195
 
 
196
    for (unsigned int n = 0; n < mServerNChildren; n++)
 
197
    {
 
198
        if (std::find (mDestroyedFrames.begin (),
 
199
                       mDestroyedFrames.end (), mServerChildren[n])
 
200
                == mDestroyedFrames.end ())
 
201
            serverSideWindows.push_back (mServerChildren[n]);
 
202
    }
 
203
 
 
204
    if (verbose)
 
205
        compLogMessage ("core", CompLogLevelDebug, "sent       | recv       | server     |");
 
206
 
 
207
    for (;(lrrit != windows.rend () ||
 
208
           lsrit != mLastServerWindows.rend () ||
 
209
           i != serverSideWindows.size ());)
 
210
    {
 
211
        Window lrXid = 0;
 
212
        Window lsXid = 0;
 
213
        Window sXid = 0;
 
214
 
 
215
        if (lrrit != windows.rend ())
 
216
            lrXid = (*lrrit)->priv->frame ? (*lrrit)->priv->frame : (*lrrit)->id ();
 
217
 
 
218
        if (lsrit != mLastServerWindows.rend ())
 
219
            lsXid = (*lsrit)->priv->frame ? (*lsrit)->priv->frame : (*lsrit)->id ();
 
220
 
 
221
        if (i != serverSideWindows.size ())
 
222
            sXid = serverSideWindows[serverSideWindows.size () - (i + 1)];
 
223
 
 
224
        if (verbose)
 
225
            compLogMessage ("core", CompLogLevelDebug, "id 0x%x id 0x%x id 0x%x %s",
 
226
                     (unsigned int) lsXid, (unsigned int) lrXid,
 
227
                     (unsigned int) sXid, (lrXid != sXid) ? "  /!\\ " : "");
 
228
 
 
229
        if (lrXid != sXid)
 
230
            err = true;
 
231
 
 
232
        if (lrrit != windows.rend ())
 
233
            lrrit++;
 
234
 
 
235
        if (lsrit != mLastServerWindows.rend())
 
236
            lsrit++;
 
237
 
 
238
        if (i != serverSideWindows.size ())
 
239
            i++;
 
240
    }
 
241
 
 
242
    return err;
 
243
}
 
244
 
 
245
/* Checks the sanity of the list of windows last sent to the server.
 
246
 *
 
247
 * There are a few stacking "layers" here. From top to bottom:
 
248
 * - 1) Docks stacked above toplevel windows which are stacked
 
249
 *      above fullscreen windows
 
250
 * - 2) "Keep above" toplevel windows above fullscreen windows
 
251
 *      where a toplevel is in focus
 
252
 * - 3) Toplevel windows in focus above fullscreen windows
 
253
 * - 4) Fullscreen windows
 
254
 * - 5) Dock windows
 
255
 * - 6) Keep above windows
 
256
 * - 7) Toplevel windows
 
257
 * - 8) Docks which are marked "Keep Below"
 
258
 * - 9) "Keep Below" windows
 
259
 * - 10) Desktop windows
 
260
 *
 
261
 * There are also a few rules which apply here:
 
262
 * - 1) Dock windows should always be above normal windows
 
263
 *      except if marked keep below on any layer.
 
264
 * - 2) Dock windows should ONLY be on one layer at a time,
 
265
 *      eg if they are on layer 1 then there cannot
 
266
 *      also be dock windows on layer 5 (except in the
 
267
 *      case of below dock windows on layer 8)
 
268
 * - 3) Fullscreen windows must always be above docks when in
 
269
 *      focus, no matter if there is another window with "Keep Above"
 
270
 * - 4) Focused windows take priority over fullscreen windows and
 
271
 *      docks must always be above them (see rule 1)
 
272
 *
 
273
 * As we pass through each layer, this function flags each one from
 
274
 * lowest being the most bits set to highest being the least bits
 
275
 * set. If a window violates this it raises a warning */
 
276
 
 
277
#define DOCKS_ABOVE_TOPLEVELS_ABOVE_FULLSCREEN 0xffffffff >> 1
 
278
#define KEEP_ABOVE_TOPLEVELS_ABOVE_FULLSCREEN 0xffffffff >> 2
 
279
#define TOPLEVELS_ABOVE_FULLSCREEN 0xffffffff >> 3
 
280
#define FULLSCREEN 0xffffffff >> 4
 
281
#define DOCKS 0xffffffff >> 5
 
282
#define KEEP_ABOVE 0xffffffff >> 6
 
283
#define TOPLEVELS 0xffffffff >> 7
 
284
#define DOCKS_BELOW 0xffffffff >> 8
 
285
#define KEEP_BELOW 0xffffffff >> 9
 
286
#define DESKTOP 0xffffffff >> 10
 
287
 
 
288
namespace
 
289
{
 
290
    bool setCurrentLayer (Window requestingWindow, int layer, int &current)
 
291
    {
 
292
        bool ret = false;
 
293
        /* Only allow steps down */
 
294
        if ((current & layer) != layer)
 
295
        {
 
296
            ret = true;
 
297
            compLogMessage ("stackdebugger", CompLogLevelWarn, "0x%x requested invalid layer 0x%x",
 
298
                            requestingWindow, layer, current);
 
299
        }
 
300
 
 
301
        current = layer;
 
302
 
 
303
        return ret;
 
304
    }
 
305
}
 
306
 
 
307
bool
 
308
StackDebugger::checkSanity (CompWindowList &serverWindows, bool verbose)
 
309
{
 
310
    int current = 0xffffffff;
 
311
    int oldCurrent = current;
 
312
    bool err = false;
 
313
 
 
314
    if (verbose)
 
315
        compLogMessage ("stackdebugger", CompLogLevelDebug, "processing new stack --------");
 
316
 
 
317
    /* go backwards down the stack */
 
318
    for (CompWindowList::reverse_iterator rit = serverWindows.rbegin ();
 
319
         rit != serverWindows.rend (); rit++)
 
320
    {
 
321
        CompWindow *w = (*rit);
 
322
 
 
323
        /* Override redirect windows set all kinds
 
324
         * of crazy stuff and are required to stack
 
325
         * themselves so skip those */
 
326
        if (w->overrideRedirect ())
 
327
            continue;
 
328
 
 
329
        /* ignore non-override redirect unmanaged windows */
 
330
        if (!w->managed ())
 
331
            continue;
 
332
 
 
333
        /* ignore any windows that just got created */
 
334
        if (!w->mapNum ())
 
335
            continue;
 
336
 
 
337
        /* determine the current layer */
 
338
        if (w->type () == CompWindowTypeDockMask)
 
339
        {
 
340
            if ((current & DOCKS_ABOVE_TOPLEVELS_ABOVE_FULLSCREEN) ==
 
341
                           DOCKS_ABOVE_TOPLEVELS_ABOVE_FULLSCREEN)
 
342
            {
 
343
                bool fullscreenWindow = false;
 
344
 
 
345
                /* search down the stack to check if there is a fullscreen
 
346
                 * window, otherwise we are not on the fullscreen layer */
 
347
                for (CompWindow *rw = w->serverPrev; rw; rw = rw->serverPrev)
 
348
                {
 
349
                    if (rw->type () & CompWindowTypeFullscreenMask)
 
350
                    {
 
351
                        fullscreenWindow = true;
 
352
                        break;
 
353
                    }
 
354
                }
 
355
 
 
356
                /* if there is no fullscreen window, change the layer */
 
357
                if (!fullscreenWindow)
 
358
                    err |= setCurrentLayer (w->id (), DOCKS, current);
 
359
                else
 
360
                    err |= setCurrentLayer (w->id (), DOCKS_ABOVE_TOPLEVELS_ABOVE_FULLSCREEN, current);
 
361
            }
 
362
            else if (w->state () & CompWindowStateBelowMask)
 
363
                err |= setCurrentLayer (w->id (), DOCKS_BELOW, current);
 
364
            else
 
365
                err |= setCurrentLayer (w->id (), DOCKS, current);
 
366
        }
 
367
        else if (w->type () == CompWindowTypeFullscreenMask)
 
368
        {
 
369
            err |= setCurrentLayer (w->id (), FULLSCREEN, current);
 
370
        }
 
371
        else if (w->type () == CompWindowTypeDesktopMask)
 
372
        {
 
373
            err |= setCurrentLayer (w->id (), DESKTOP, current);
 
374
        }
 
375
        /* everything else that is not a fullscreen window or a desktop */
 
376
        else
 
377
        {
 
378
            if (w->state () & CompWindowStateAboveMask)
 
379
            {
 
380
                if ((current & KEEP_ABOVE_TOPLEVELS_ABOVE_FULLSCREEN) ==
 
381
                               KEEP_ABOVE_TOPLEVELS_ABOVE_FULLSCREEN)
 
382
                {
 
383
                    bool fullscreenWindow = false;
 
384
 
 
385
                    /* search down the stack to check if there is a fullscreen
 
386
                     * window, otherwise we are not on the fullscreen layer */
 
387
                    for (CompWindow *rw = w->serverPrev; rw; rw = rw->serverPrev)
 
388
                    {
 
389
                        if (rw->type () == CompWindowTypeFullscreenMask)
 
390
                        {
 
391
                            fullscreenWindow = true;
 
392
                            break;
 
393
                        }
 
394
                    }
 
395
 
 
396
                    if (!fullscreenWindow)
 
397
                        err |= setCurrentLayer (w->id (), KEEP_ABOVE, current);
 
398
                    else
 
399
                        err |= setCurrentLayer (w->id (), KEEP_ABOVE_TOPLEVELS_ABOVE_FULLSCREEN, current);
 
400
                }
 
401
                else
 
402
                    err |= setCurrentLayer (w->id (), KEEP_ABOVE, current);
 
403
            }
 
404
            else if (w->state () & CompWindowStateBelowMask)
 
405
                err |= setCurrentLayer (w->id (), KEEP_BELOW, current);
 
406
            else
 
407
            {
 
408
                if ((current & TOPLEVELS_ABOVE_FULLSCREEN) ==
 
409
                               TOPLEVELS_ABOVE_FULLSCREEN)
 
410
                {
 
411
                    bool fullscreenWindow = false;
 
412
 
 
413
                    /* search down the stack to check if there is a fullscreen
 
414
                     * window, otherwise we are not on the fullscreen layer */
 
415
                    for (CompWindow *rw = w->serverPrev; rw; rw = rw->serverPrev)
 
416
                    {
 
417
                        if (rw->type () == CompWindowTypeFullscreenMask)
 
418
                        {
 
419
                            fullscreenWindow = true;
 
420
                            break;
 
421
                        }
 
422
                    }
 
423
 
 
424
                    if (!fullscreenWindow)
 
425
                        err |= setCurrentLayer (w->id (), TOPLEVELS, current);
 
426
                    else
 
427
                        err |= setCurrentLayer (w->id (), TOPLEVELS_ABOVE_FULLSCREEN, current);
 
428
                }
 
429
                else
 
430
                    err |= setCurrentLayer (w->id (), TOPLEVELS, current);
 
431
            }
 
432
        }
 
433
 
 
434
        if ((current & DOCKS_ABOVE_TOPLEVELS_ABOVE_FULLSCREEN) ==
 
435
                       DOCKS_ABOVE_TOPLEVELS_ABOVE_FULLSCREEN)
 
436
        {
 
437
            if (verbose && current != oldCurrent)
 
438
                compLogMessage ("stackdebugger", CompLogLevelDebug, "on layer DOCKS_ABOVE_TOPLEVELS_ABOVE_FULLSCREEN");
 
439
        }
 
440
        else if ((current & KEEP_ABOVE_TOPLEVELS_ABOVE_FULLSCREEN) ==
 
441
                            KEEP_ABOVE_TOPLEVELS_ABOVE_FULLSCREEN)
 
442
        {
 
443
            if (verbose && current != oldCurrent)
 
444
                compLogMessage ("stackdebugger", CompLogLevelDebug, "on layer KEEP_ABOVE_TOPLEVELS_ABOVE_FULLSCREEN");
 
445
        }
 
446
        else if ((current & TOPLEVELS_ABOVE_FULLSCREEN) == TOPLEVELS_ABOVE_FULLSCREEN)
 
447
        {
 
448
            if (verbose && current != oldCurrent)
 
449
                compLogMessage ("stackdebugger", CompLogLevelDebug, "on layer TOPLEVELS_ABOVE_FULLSCREEN");
 
450
        }
 
451
        else if ((current & FULLSCREEN) == FULLSCREEN)
 
452
        {
 
453
            if (verbose && current != oldCurrent)
 
454
                compLogMessage ("stackdebugger", CompLogLevelDebug, "on layer FULLSCREEN");
 
455
        }
 
456
        else if ((current & DOCKS) == DOCKS)
 
457
        {
 
458
            if (verbose && current != oldCurrent)
 
459
                compLogMessage ("stackdebugger", CompLogLevelDebug, "on layer DOCKS");
 
460
        }
 
461
        else if ((current & KEEP_ABOVE) == KEEP_ABOVE)
 
462
        {
 
463
            if (verbose && current != oldCurrent)
 
464
                compLogMessage ("stackdebugger", CompLogLevelDebug, "on layer KEEP_ABOVE");
 
465
        }
 
466
        else if ((current & TOPLEVELS) == TOPLEVELS)
 
467
        {
 
468
            if (verbose && current != oldCurrent)
 
469
                compLogMessage ("stackdebugger", CompLogLevelDebug, "on layer TOPLEVELS");
 
470
        }
 
471
        else if ((current & DOCKS_BELOW) == DOCKS_BELOW)
 
472
        {
 
473
            if (verbose && current != oldCurrent)
 
474
                compLogMessage ("stackdebugger", CompLogLevelDebug, "on layer DOCKS_BELOW");
 
475
        }
 
476
        else if ((current & KEEP_BELOW) == KEEP_BELOW)
 
477
        {
 
478
            if (verbose && current != oldCurrent)
 
479
                compLogMessage ("stackdebugger", CompLogLevelDebug, "on layer KEEP_BELOW");
 
480
        }
 
481
        else if ((current & DESKTOP) == DESKTOP)
 
482
        {
 
483
            if (verbose && current != oldCurrent)
 
484
                compLogMessage ("stackdebugger", CompLogLevelDebug, "on layer DESKTOP");
 
485
        }
 
486
 
 
487
        oldCurrent = current;
 
488
    }
 
489
 
 
490
    return err;
 
491
}