~mc-return/compiz/compiz0.9.9.merge-plugin-startup

« back to all changes in this revision

Viewing changes to src/configurerequestbuffer.cpp

Merged latest lp:compiz

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright © 2012 Sam Spilsbury
 
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 <smspillaz@gmail.com>
 
24
 */
 
25
#include <cstdio>
 
26
#include <cassert>
 
27
#include <boost/foreach.hpp>
 
28
#include <boost/weak_ptr.hpp>
 
29
#include <boost/bind.hpp>
 
30
#include "asyncserverwindow.h"
 
31
#include "configurerequestbuffer-impl.h"
 
32
 
 
33
#ifndef foreach
 
34
#define foreach BOOST_FOREACH
 
35
#endif
 
36
 
 
37
namespace crb = compiz::window::configure_buffers;
 
38
namespace cw = compiz::window;
 
39
 
 
40
class crb::ConfigureRequestBuffer::Private
 
41
{
 
42
    public:
 
43
 
 
44
        typedef crb::Lockable::Weak LockObserver;
 
45
 
 
46
        Private (cw::AsyncServerWindow                          *asyncServerWindow,
 
47
                 cw::SyncServerWindow                           *syncServerWindow,
 
48
                 const crb::ConfigureRequestBuffer::LockFactory &lockFactory) :
 
49
            clientChangeMask (0),
 
50
            wrapperChangeMask (0),
 
51
            frameChangeMask (0),
 
52
            sendSyntheticConfigure (false),
 
53
            lockCount (0),
 
54
            asyncServerWindow (asyncServerWindow),
 
55
            syncServerWindow (syncServerWindow),
 
56
            lockFactory (lockFactory)
 
57
        {
 
58
        }
 
59
 
 
60
        void dispatchConfigure (bool force = false);
 
61
 
 
62
        XWindowChanges clientChanges;
 
63
        unsigned int   clientChangeMask;
 
64
 
 
65
        XWindowChanges wrapperChanges;
 
66
        unsigned int   wrapperChangeMask;
 
67
 
 
68
        XWindowChanges frameChanges;
 
69
        unsigned int   frameChangeMask;
 
70
 
 
71
        bool           sendSyntheticConfigure;
 
72
 
 
73
        unsigned int   lockCount;
 
74
 
 
75
        cw::AsyncServerWindow *asyncServerWindow;
 
76
        cw::SyncServerWindow  *syncServerWindow;
 
77
 
 
78
        crb::ConfigureRequestBuffer::LockFactory lockFactory;
 
79
        std::vector <LockObserver>               locks;
 
80
};
 
81
 
 
82
void
 
83
crb::ConfigureRequestBuffer::Private::dispatchConfigure (bool force)
 
84
{
 
85
    const unsigned int allEventMasks = 0x7f;
 
86
    bool immediate = frameChangeMask & (CWStackMode | CWSibling);
 
87
 
 
88
    /* This is a stop-gap solution for not having a plugin API to
 
89
     * query the window shape. Once we have that, we can safely
 
90
     * remove these and require the queue to be unlocked when that
 
91
     * happens. Its a separate unit of work for improving resize
 
92
     * performance anyways.
 
93
     */
 
94
    immediate |= (frameChangeMask & (CWWidth | CWHeight | CWBorderWidth));
 
95
    immediate |= (wrapperChangeMask & (CWWidth | CWHeight | CWBorderWidth | CWX | CWY));
 
96
    immediate |= (clientChangeMask & (CWWidth | CWHeight | CWBorderWidth | CWX | CWY));
 
97
    immediate |= force;
 
98
 
 
99
    bool clientDispatch = (clientChangeMask & allEventMasks);
 
100
    bool wrapperDispatch = (wrapperChangeMask & allEventMasks);
 
101
    bool frameDispatch  = (frameChangeMask & allEventMasks);
 
102
 
 
103
    bool dispatch = !lockCount && (clientDispatch ||
 
104
                                   wrapperDispatch ||
 
105
                                   frameDispatch ||
 
106
                                   sendSyntheticConfigure);
 
107
 
 
108
    if (dispatch || immediate)
 
109
    {
 
110
        if (frameDispatch)
 
111
        {
 
112
            asyncServerWindow->requestConfigureOnFrame (frameChanges,
 
113
                                                        frameChangeMask);
 
114
            frameChangeMask = 0;
 
115
        }
 
116
 
 
117
        if (wrapperDispatch)
 
118
        {
 
119
            asyncServerWindow->requestConfigureOnWrapper (wrapperChanges,
 
120
                                                          wrapperChangeMask);
 
121
            wrapperChangeMask = 0;
 
122
        }
 
123
 
 
124
        if (clientDispatch)
 
125
        {
 
126
            asyncServerWindow->requestConfigureOnClient (clientChanges,
 
127
                                                         clientChangeMask);
 
128
            clientChangeMask = 0;
 
129
        }
 
130
 
 
131
        if (sendSyntheticConfigure)
 
132
        {
 
133
            asyncServerWindow->sendSyntheticConfigureNotify ();
 
134
            sendSyntheticConfigure = false;
 
135
        }
 
136
 
 
137
        foreach (const LockObserver &lock, locks)
 
138
        {
 
139
            crb::Lockable::Ptr strongLock (lock.lock ());
 
140
 
 
141
            /* We might be in a lock's destructor so check
 
142
             * if this can really be re-locked, if not, its
 
143
             * no big deal as the lock is going away anyways
 
144
             */
 
145
            if (strongLock)
 
146
                strongLock->lock ();
 
147
        }
 
148
    }
 
149
}
 
150
 
 
151
void
 
152
crb::ConfigureRequestBuffer::freeze ()
 
153
{
 
154
    priv->lockCount++;
 
155
 
 
156
    assert (priv->lockCount <= priv->locks.size ());
 
157
}
 
158
 
 
159
void
 
160
crb::ConfigureRequestBuffer::release ()
 
161
{
 
162
    assert (priv->lockCount);
 
163
 
 
164
    priv->lockCount--;
 
165
 
 
166
    priv->dispatchConfigure ();
 
167
}
 
168
 
 
169
namespace
 
170
{
 
171
void applyChangeToXWC (const XWindowChanges &from,
 
172
                       XWindowChanges       &to,
 
173
                       unsigned int         mask)
 
174
{
 
175
    if (mask & CWX)
 
176
        to.x = from.x;
 
177
 
 
178
    if (mask & CWY)
 
179
        to.y = from.y;
 
180
 
 
181
    if (mask & CWWidth)
 
182
        to.width = from.width;
 
183
 
 
184
    if (mask & CWHeight)
 
185
        to.height = from.height;
 
186
 
 
187
    if (mask & CWBorderWidth)
 
188
        to.border_width = from.border_width;
 
189
 
 
190
    if (mask & CWSibling)
 
191
        to.sibling = from.sibling;
 
192
 
 
193
    if (mask & CWStackMode)
 
194
        to.stack_mode = from.stack_mode;
 
195
}
 
196
}
 
197
 
 
198
void
 
199
crb::ConfigureRequestBuffer::pushClientRequest (const XWindowChanges &xwc,
 
200
                                                unsigned int         mask)
 
201
{
 
202
    applyChangeToXWC (xwc, priv->clientChanges, mask);
 
203
    priv->clientChangeMask |= mask;
 
204
 
 
205
    priv->dispatchConfigure ();
 
206
}
 
207
 
 
208
void
 
209
crb::ConfigureRequestBuffer::pushWrapperRequest (const XWindowChanges &xwc,
 
210
                                                 unsigned int         mask)
 
211
{
 
212
    applyChangeToXWC (xwc, priv->wrapperChanges, mask);
 
213
    priv->wrapperChangeMask |= mask;
 
214
 
 
215
    priv->dispatchConfigure ();
 
216
}
 
217
 
 
218
void
 
219
crb::ConfigureRequestBuffer::pushFrameRequest (const XWindowChanges &xwc,
 
220
                                               unsigned int         mask)
 
221
{
 
222
    applyChangeToXWC (xwc, priv->frameChanges, mask);
 
223
    priv->frameChangeMask |= mask;
 
224
 
 
225
    priv->dispatchConfigure ();
 
226
}
 
227
 
 
228
void
 
229
crb::ConfigureRequestBuffer::pushSyntheticConfigureNotify ()
 
230
{
 
231
    priv->sendSyntheticConfigure = true;
 
232
 
 
233
    priv->dispatchConfigure ();
 
234
}
 
235
 
 
236
crb::Releasable::Ptr
 
237
crb::ConfigureRequestBuffer::obtainLock ()
 
238
{
 
239
    crb::BufferLock::Ptr lock (priv->lockFactory (this));
 
240
 
 
241
    priv->locks.push_back (crb::Lockable::Weak (lock));
 
242
    lock->lock ();
 
243
 
 
244
    return lock;
 
245
}
 
246
 
 
247
namespace
 
248
{
 
249
bool isLock (const crb::Lockable::Weak &lockable,
 
250
             crb::BufferLock           *lock)
 
251
{
 
252
    crb::Lockable::Ptr strongLockable (lockable.lock ());
 
253
 
 
254
    /* Asserting that the lock did not go away without telling
 
255
     * us first */
 
256
    assert (strongLockable.get ());
 
257
 
 
258
    if (strongLockable.get () == lock)
 
259
        return true;
 
260
 
 
261
    return false;
 
262
}
 
263
}
 
264
 
 
265
void
 
266
crb::ConfigureRequestBuffer::untrackLock (crb::BufferLock *lock)
 
267
{
 
268
    std::remove_if (priv->locks.begin (),
 
269
                    priv->locks.end (),
 
270
                    boost::bind (isLock, _1, lock));
 
271
}
 
272
 
 
273
bool crb::ConfigureRequestBuffer::queryAttributes (XWindowAttributes &attrib)
 
274
{
 
275
    priv->dispatchConfigure (true);
 
276
    return priv->syncServerWindow->queryAttributes (attrib);
 
277
}
 
278
 
 
279
bool crb::ConfigureRequestBuffer::queryFrameAttributes (XWindowAttributes &attrib)
 
280
{
 
281
    priv->dispatchConfigure (true);
 
282
    return priv->syncServerWindow->queryFrameAttributes (attrib);
 
283
}
 
284
 
 
285
/* This is more or less of a stop-gap for the fact that
 
286
 * when resizing window we re-query the window shape
 
287
 * and apply that to the frame. That's a separate unit of
 
288
 * work and should be dealt with separately. For now, force
 
289
 * a release of the queue whenever we do that so that
 
290
 * XShapeGetRectangles doesn't return an unexpected value
 
291
 */
 
292
XRectangle *
 
293
crb::ConfigureRequestBuffer::queryShapeRectangles (int kind,
 
294
                                                   int *count,
 
295
                                                   int *ordering)
 
296
{
 
297
    priv->dispatchConfigure (true);
 
298
    return priv->syncServerWindow->queryShapeRectangles (kind, count, ordering);
 
299
}
 
300
 
 
301
void crb::ConfigureRequestBuffer::forceRelease ()
 
302
{
 
303
    priv->dispatchConfigure (true);
 
304
}
 
305
 
 
306
crb::ConfigureRequestBuffer::ConfigureRequestBuffer (AsyncServerWindow                          *asyncServerWindow,
 
307
                                                     SyncServerWindow                           *syncServerWindow,
 
308
                                                     const crb::ConfigureRequestBuffer::LockFactory &factory) :
 
309
    priv (new crb::ConfigureRequestBuffer::Private (asyncServerWindow, syncServerWindow, factory))
 
310
{
 
311
}
 
312
 
 
313
compiz::window::configure_buffers::Buffer::Ptr
 
314
crb::ConfigureRequestBuffer::Create (AsyncServerWindow *asyncServerWindow,
 
315
                                     SyncServerWindow  *syncServerWindow,
 
316
                                     const LockFactory &factory)
 
317
{
 
318
    return crb::Buffer::Ptr (new crb::ConfigureRequestBuffer (asyncServerWindow,
 
319
                                                              syncServerWindow,
 
320
                                                              factory));
 
321
}
 
322
 
 
323
class crb::ConfigureBufferLock::Private
 
324
{
 
325
    public:
 
326
 
 
327
        Private (crb::CountedFreeze *freezable) :
 
328
            freezable (freezable),
 
329
            armed (false)
 
330
        {
 
331
        }
 
332
 
 
333
        crb::CountedFreeze *freezable;
 
334
        bool               armed;
 
335
};
 
336
 
 
337
crb::ConfigureBufferLock::ConfigureBufferLock (crb::CountedFreeze *freezable) :
 
338
    priv (new crb::ConfigureBufferLock::Private (freezable))
 
339
{
 
340
}
 
341
 
 
342
crb::ConfigureBufferLock::~ConfigureBufferLock ()
 
343
{
 
344
    release ();
 
345
}
 
346
 
 
347
void
 
348
crb::ConfigureBufferLock::lock ()
 
349
{
 
350
    if (!priv->armed)
 
351
        priv->freezable->freeze ();
 
352
 
 
353
    priv->armed = true;
 
354
}
 
355
 
 
356
void
 
357
crb::ConfigureBufferLock::release ()
 
358
{
 
359
    if (priv->armed)
 
360
        priv->freezable->release ();
 
361
 
 
362
    priv->armed = false;
 
363
}