~mc-return/compiz/compiz.merge-src-screen.cpp-improvements

« back to all changes in this revision

Viewing changes to plugins/decor/src/decor.cpp

  • Committer: Dennis kasprzyk
  • Author(s): Dennis Kasprzyk
  • Date: 2009-03-15 05:09:18 UTC
  • Revision ID: git-v1:163f6b6f3c3b7764987cbdf8e03cc355edeaa499
New generalized build system.

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
#ifdef HAVE_CONFIG_H
 
27
#  include <config.h>
 
28
#endif
 
29
 
 
30
#include <stdio.h>
 
31
#include <stdlib.h>
 
32
#include <string.h>
 
33
#include <math.h>
 
34
#include <unistd.h>
 
35
 
 
36
#include <core/core.h>
 
37
#include <decoration.h>
 
38
#include "decor.h"
 
39
 
 
40
#include <X11/Xatom.h>
 
41
#include <X11/extensions/shape.h>
 
42
 
 
43
COMPIZ_PLUGIN_20081216 (decor, DecorPluginVTable)
 
44
 
 
45
bool
 
46
DecorWindow::glDraw (const GLMatrix     &transform,
 
47
                     GLFragment::Attrib &attrib,
 
48
                     const CompRegion   &region,
 
49
                     unsigned int       mask)
 
50
{
 
51
    bool status;
 
52
 
 
53
    status = gWindow->glDraw (transform, attrib, region, mask);
 
54
 
 
55
    const CompRegion reg = (mask & PAINT_WINDOW_TRANSFORMED_MASK) ?
 
56
                           infiniteRegion : region;
 
57
 
 
58
    if (wd && !reg.isEmpty () &&
 
59
        wd->decor->type == WINDOW_DECORATION_TYPE_PIXMAP)
 
60
    {
 
61
        CompRect box;
 
62
        GLTexture::MatrixList ml (1);
 
63
        mask |= PAINT_WINDOW_BLEND_MASK;
 
64
 
 
65
        gWindow->geometry ().reset ();
 
66
 
 
67
        for (int i = 0; i < wd->nQuad; i++)
 
68
        {
 
69
            box.setGeometry (wd->quad[i].box.x1,
 
70
                             wd->quad[i].box.y1,
 
71
                             wd->quad[i].box.x2 - wd->quad[i].box.x1,
 
72
                             wd->quad[i].box.y2 - wd->quad[i].box.y1);
 
73
 
 
74
            if (box.width () > 0 && box.height () > 0)
 
75
            {
 
76
                ml[0] = wd->quad[i].matrix;
 
77
                gWindow->glAddGeometry (ml, CompRegion (box), reg);
 
78
            }
 
79
        }
 
80
 
 
81
        if (gWindow->geometry ().vCount)
 
82
            gWindow->glDrawTexture (wd->decor->texture->textures[0],
 
83
                                    attrib, mask);
 
84
    }
 
85
    else if (wd && !reg.isEmpty () &&
 
86
             wd->decor->type == WINDOW_DECORATION_TYPE_WINDOW)
 
87
    {
 
88
        GLTexture::MatrixList ml (1);
 
89
 
 
90
        if (gWindow->textures ().empty ())
 
91
            gWindow->bind ();
 
92
        if (gWindow->textures ().empty ())
 
93
            return status;
 
94
 
 
95
        if (gWindow->textures ().size () == 1)
 
96
        {
 
97
            ml[0] = gWindow->matrices ()[0];
 
98
            gWindow->geometry ().reset ();
 
99
            gWindow->glAddGeometry (ml, window->frameRegion (), reg);
 
100
 
 
101
            if (gWindow->geometry ().vCount)
 
102
                gWindow->glDrawTexture (gWindow->textures ()[0], attrib, mask);
 
103
        }
 
104
        else
 
105
        {
 
106
            if (updateReg)
 
107
                updateWindowRegions ();
 
108
            for (unsigned int i = 0; i < gWindow->textures ().size (); i++)
 
109
            {
 
110
                ml[0] = gWindow->matrices ()[i];
 
111
                gWindow->geometry ().reset ();
 
112
                gWindow->glAddGeometry (ml, regions[i], reg);
 
113
 
 
114
                if (gWindow->geometry ().vCount)
 
115
                    gWindow->glDrawTexture (gWindow->textures ()[i], attrib,
 
116
                                            mask);
 
117
            }
 
118
        }
 
119
    }
 
120
 
 
121
    return status;
 
122
}
 
123
 
 
124
static bool bindFailed;
 
125
 
 
126
DecorTexture::DecorTexture (Pixmap pixmap) :
 
127
    status (true),
 
128
    refCount (1),
 
129
    pixmap (pixmap),
 
130
    damage (None)
 
131
{
 
132
    unsigned int width, height, depth, ui;
 
133
    Window       root;
 
134
    int          i;
 
135
 
 
136
    if (!XGetGeometry (screen->dpy (), pixmap, &root,
 
137
                       &i, &i, &width, &height, &ui, &depth))
 
138
    {
 
139
        status = false;
 
140
        return;
 
141
    }
 
142
 
 
143
    bindFailed = false;
 
144
    textures = GLTexture::bindPixmapToTexture (pixmap, width, height, depth);
 
145
    if (textures.size () != 1)
 
146
    {
 
147
        bindFailed = true;
 
148
        status = false;
 
149
        return;
 
150
    }
 
151
 
 
152
    if (!DecorScreen::get (screen)->opt[DECOR_OPTION_MIPMAP].value ().b ())
 
153
        textures[0]->setMipmap (false);
 
154
 
 
155
    damage = XDamageCreate (screen->dpy (), pixmap,
 
156
                             XDamageReportRawRectangles);
 
157
}
 
158
 
 
159
DecorTexture::~DecorTexture ()
 
160
{
 
161
    if (damage)
 
162
        XDamageDestroy (screen->dpy (), damage);
 
163
}
 
164
 
 
165
DecorTexture *
 
166
DecorScreen::getTexture (Pixmap pixmap)
 
167
{
 
168
    if (!cmActive)
 
169
        return NULL;
 
170
 
 
171
    foreach (DecorTexture *t, textures)
 
172
        if (t->pixmap == pixmap)
 
173
        {
 
174
            t->refCount++;
 
175
            return t;
 
176
        }
 
177
 
 
178
    DecorTexture *texture = new DecorTexture (pixmap);
 
179
 
 
180
    if (!texture->status)
 
181
    {
 
182
        delete texture;
 
183
        return NULL;
 
184
    }
 
185
 
 
186
    textures.push_back (texture);
 
187
 
 
188
    return texture;
 
189
}
 
190
 
 
191
 
 
192
void
 
193
DecorScreen::releaseTexture (DecorTexture *texture)
 
194
{
 
195
    texture->refCount--;
 
196
    if (texture->refCount)
 
197
        return;
 
198
 
 
199
    std::list<DecorTexture *>::iterator it =
 
200
        std::find (textures.begin (), textures.end (), texture);
 
201
 
 
202
    if (it == textures.end ())
 
203
        return;
 
204
 
 
205
    textures.erase (it);
 
206
    delete texture;
 
207
}
 
208
 
 
209
static void
 
210
computeQuadBox (decor_quad_t *q,
 
211
                int          width,
 
212
                int          height,
 
213
                int          *return_x1,
 
214
                int          *return_y1,
 
215
                int          *return_x2,
 
216
                int          *return_y2,
 
217
                float        *return_sx,
 
218
                float        *return_sy)
 
219
{
 
220
    int   x1, y1, x2, y2;
 
221
    float sx = 1.0f;
 
222
    float sy = 1.0f;
 
223
 
 
224
    decor_apply_gravity (q->p1.gravity, q->p1.x, q->p1.y, width, height,
 
225
                         &x1, &y1);
 
226
    decor_apply_gravity (q->p2.gravity, q->p2.x, q->p2.y, width, height,
 
227
                         &x2, &y2);
 
228
 
 
229
    if (q->clamp & CLAMP_HORZ)
 
230
    {
 
231
        if (x1 < 0)
 
232
            x1 = 0;
 
233
        if (x2 > width)
 
234
            x2 = width;
 
235
    }
 
236
 
 
237
    if (q->clamp & CLAMP_VERT)
 
238
    {
 
239
        if (y1 < 0)
 
240
            y1 = 0;
 
241
        if (y2 > height)
 
242
            y2 = height;
 
243
    }
 
244
 
 
245
    if (q->stretch & STRETCH_X)
 
246
    {
 
247
        sx = (float)q->max_width / ((float)(x2 - x1));
 
248
    }
 
249
    else if (q->max_width < x2 - x1)
 
250
    {
 
251
        if (q->align & ALIGN_RIGHT)
 
252
            x1 = x2 - q->max_width;
 
253
        else
 
254
            x2 = x1 + q->max_width;
 
255
    }
 
256
 
 
257
    if (q->stretch & STRETCH_Y)
 
258
    {
 
259
        sy = (float)q->max_height / ((float)(y2 - y1));
 
260
    }
 
261
    else if (q->max_height < y2 - y1)
 
262
    {
 
263
        if (q->align & ALIGN_BOTTOM)
 
264
            y1 = y2 - q->max_height;
 
265
        else
 
266
            y2 = y1 + q->max_height;
 
267
    }
 
268
 
 
269
    *return_x1 = x1;
 
270
    *return_y1 = y1;
 
271
    *return_x2 = x2;
 
272
    *return_y2 = y2;
 
273
 
 
274
    if (return_sx)
 
275
        *return_sx = sx;
 
276
    if (return_sy)
 
277
        *return_sy = sy;
 
278
}
 
279
 
 
280
Decoration *
 
281
Decoration::create (Window id,
 
282
                    Atom   decorAtom)
 
283
{
 
284
    Decoration      *decoration;
 
285
    Atom            actual;
 
286
    int             result, format;
 
287
    unsigned long   n, nleft;
 
288
    unsigned char   *data;
 
289
    long            *prop;
 
290
    Pixmap          pixmap = None;
 
291
    decor_extents_t input;
 
292
    decor_extents_t maxInput;
 
293
    decor_quad_t    *quad = NULL;
 
294
    int             nQuad = 0;
 
295
    int             minWidth;
 
296
    int             minHeight;
 
297
    int             left, right, top, bottom;
 
298
    int             x1, y1, x2, y2;
 
299
    int             type;
 
300
 
 
301
    result = XGetWindowProperty (screen->dpy (), id,
 
302
                                 decorAtom, 0L, 1024L, FALSE,
 
303
                                 XA_INTEGER, &actual, &format,
 
304
                                 &n, &nleft, &data);
 
305
 
 
306
    if (result != Success || !n || !data)
 
307
        return NULL;
 
308
 
 
309
    prop = (long *) data;
 
310
 
 
311
    if (decor_property_get_version (prop) != decor_version ())
 
312
    {
 
313
        compLogMessage ("decoration", CompLogLevelWarn,
 
314
                        "Property ignored because "
 
315
                        "version is %d and decoration plugin version is %d\n",
 
316
                        decor_property_get_version (prop), decor_version ());
 
317
 
 
318
        XFree (data);
 
319
        return NULL;
 
320
    }
 
321
 
 
322
    type = decor_property_get_type (prop);
 
323
 
 
324
    if (type ==  WINDOW_DECORATION_TYPE_PIXMAP &&
 
325
        !DecorScreen::get (screen)->cmActive)
 
326
        return NULL;
 
327
 
 
328
    if (type == WINDOW_DECORATION_TYPE_PIXMAP)
 
329
    {
 
330
 
 
331
        nQuad = (n - BASE_PROP_SIZE) / QUAD_PROP_SIZE;
 
332
 
 
333
        quad = new decor_quad_t [nQuad];
 
334
        if (!quad)
 
335
        {
 
336
            XFree (data);
 
337
            return NULL;
 
338
        }
 
339
 
 
340
        nQuad = decor_pixmap_property_to_quads (prop, n, &pixmap, &input,
 
341
                                                &maxInput, &minWidth,
 
342
                                                &minHeight, quad);
 
343
 
 
344
        XFree (data);
 
345
 
 
346
        if (!nQuad)
 
347
        {
 
348
            delete [] quad;
 
349
            return NULL;
 
350
        }
 
351
    }
 
352
    else if (type == WINDOW_DECORATION_TYPE_WINDOW)
 
353
    {
 
354
        if (!decor_window_property (prop, n, &input, &maxInput,
 
355
                                    &minWidth, &minHeight))
 
356
        {
 
357
            XFree (data);
 
358
            return NULL;
 
359
        }
 
360
        XFree (data);
 
361
    }
 
362
    else
 
363
        return NULL;
 
364
 
 
365
    decoration = new Decoration ();
 
366
    if (!decoration)
 
367
    {
 
368
        delete [] quad;
 
369
        return NULL;
 
370
    }
 
371
 
 
372
    if (pixmap)
 
373
        decoration->texture = DecorScreen::get (screen)->getTexture (pixmap);
 
374
    else
 
375
        decoration->texture = NULL;
 
376
 
 
377
    if (!decoration->texture && type == WINDOW_DECORATION_TYPE_PIXMAP)
 
378
    {
 
379
        delete decoration;
 
380
        delete [] quad;
 
381
        return NULL;
 
382
    }
 
383
 
 
384
    decoration->minWidth  = minWidth;
 
385
    decoration->minHeight = minHeight;
 
386
    decoration->quad      = quad;
 
387
    decoration->nQuad     = nQuad;
 
388
 
 
389
    if (type == WINDOW_DECORATION_TYPE_PIXMAP)
 
390
    {
 
391
        left   = 0;
 
392
        right  = minWidth;
 
393
        top    = 0;
 
394
        bottom = minHeight;
 
395
 
 
396
        while (nQuad--)
 
397
        {
 
398
            computeQuadBox (quad, minWidth, minHeight, &x1, &y1, &x2, &y2,
 
399
                            NULL, NULL);
 
400
 
 
401
            if (x1 < left)
 
402
                left = x1;
 
403
            if (y1 < top)
 
404
                top = y1;
 
405
            if (x2 > right)
 
406
                right = x2;
 
407
            if (y2 > bottom)
 
408
                bottom = y2;
 
409
 
 
410
            quad++;
 
411
        }
 
412
 
 
413
        decoration->output.left   = -left;
 
414
        decoration->output.right  = right - minWidth;
 
415
        decoration->output.top    = -top;
 
416
        decoration->output.bottom = bottom - minHeight;
 
417
    }
 
418
    else
 
419
    {
 
420
        decoration->output.left   = MAX (input.left, maxInput.left);
 
421
        decoration->output.right  = MAX (input.right, maxInput.right);
 
422
        decoration->output.top    = MAX (input.top, maxInput.top);
 
423
        decoration->output.bottom = MAX (input.bottom, maxInput.bottom);
 
424
    }
 
425
 
 
426
    decoration->input.left   = input.left;
 
427
    decoration->input.right  = input.right;
 
428
    decoration->input.top    = input.top;
 
429
    decoration->input.bottom = input.bottom;
 
430
 
 
431
    decoration->maxInput.left   = maxInput.left;
 
432
    decoration->maxInput.right  = maxInput.right;
 
433
    decoration->maxInput.top    = maxInput.top;
 
434
    decoration->maxInput.bottom = maxInput.bottom;
 
435
 
 
436
    decoration->refCount = 1;
 
437
    decoration->type = type;
 
438
 
 
439
    return decoration;
 
440
}
 
441
 
 
442
void
 
443
Decoration::release (Decoration *decoration)
 
444
{
 
445
    decoration->refCount--;
 
446
    if (decoration->refCount)
 
447
        return;
 
448
 
 
449
    if (decoration->texture)
 
450
        DecorScreen::get (screen)->releaseTexture (decoration->texture);
 
451
 
 
452
    delete [] decoration->quad;
 
453
    delete decoration;
 
454
}
 
455
 
 
456
void
 
457
DecorWindow::updateDecoration ()
 
458
{
 
459
    Decoration *decoration;
 
460
 
 
461
    bindFailed = false;
 
462
    decoration = Decoration::create (window->id (), dScreen->winDecorAtom);
 
463
 
 
464
    if (decor)
 
465
        Decoration::release (decor);
 
466
 
 
467
    if (bindFailed)
 
468
        pixmapFailed = true;
 
469
    else
 
470
        pixmapFailed = false;
 
471
 
 
472
    decor = decoration;
 
473
}
 
474
 
 
475
WindowDecoration *
 
476
WindowDecoration::create (Decoration *d)
 
477
{
 
478
    WindowDecoration *wd;
 
479
 
 
480
    wd = new WindowDecoration ();
 
481
    if (!wd)
 
482
        return NULL;
 
483
 
 
484
    if (d->type == WINDOW_DECORATION_TYPE_PIXMAP)
 
485
    {
 
486
        wd->quad = new ScaledQuad[d->nQuad];
 
487
 
 
488
        if (!wd->quad)
 
489
        {
 
490
            delete wd;
 
491
            return NULL;
 
492
        }
 
493
    }
 
494
    else
 
495
        wd->quad = NULL;
 
496
 
 
497
    d->refCount++;
 
498
 
 
499
    wd->decor = d;
 
500
    wd->nQuad = d->nQuad;
 
501
 
 
502
    return wd;
 
503
}
 
504
 
 
505
void
 
506
WindowDecoration::destroy (WindowDecoration *wd)
 
507
{
 
508
    Decoration::release (wd->decor);
 
509
    delete [] wd->quad;
 
510
    delete wd;
 
511
}
 
512
 
 
513
void
 
514
DecorWindow::setDecorationMatrices ()
 
515
{
 
516
    int               i;
 
517
    float             x0, y0;
 
518
    decor_matrix_t    a;
 
519
    GLTexture::Matrix b;
 
520
 
 
521
    if (!wd)
 
522
        return;
 
523
 
 
524
    for (i = 0; i < wd->nQuad; i++)
 
525
    {
 
526
        wd->quad[i].matrix = wd->decor->texture->textures[0]->matrix ();
 
527
 
 
528
        x0 = wd->decor->quad[i].m.x0;
 
529
        y0 = wd->decor->quad[i].m.y0;
 
530
 
 
531
        a = wd->decor->quad[i].m;
 
532
        b = wd->quad[i].matrix;
 
533
 
 
534
        wd->quad[i].matrix.xx = a.xx * b.xx + a.yx * b.xy;
 
535
        wd->quad[i].matrix.yx = a.xx * b.yx + a.yx * b.yy;
 
536
        wd->quad[i].matrix.xy = a.xy * b.xx + a.yy * b.xy;
 
537
        wd->quad[i].matrix.yy = a.xy * b.yx + a.yy * b.yy;
 
538
        wd->quad[i].matrix.x0 = x0 * b.xx + y0 * b.xy + b.x0;
 
539
        wd->quad[i].matrix.y0 = x0 * b.yx + y0 * b.yy + b.y0;
 
540
 
 
541
        wd->quad[i].matrix.xx *= wd->quad[i].sx;
 
542
        wd->quad[i].matrix.yx *= wd->quad[i].sx;
 
543
        wd->quad[i].matrix.xy *= wd->quad[i].sy;
 
544
        wd->quad[i].matrix.yy *= wd->quad[i].sy;
 
545
 
 
546
        if (wd->decor->quad[i].align & ALIGN_RIGHT)
 
547
            x0 = wd->quad[i].box.x2 - wd->quad[i].box.x1;
 
548
        else
 
549
            x0 = 0.0f;
 
550
 
 
551
        if (wd->decor->quad[i].align & ALIGN_BOTTOM)
 
552
            y0 = wd->quad[i].box.y2 - wd->quad[i].box.y1;
 
553
        else
 
554
            y0 = 0.0f;
 
555
 
 
556
        wd->quad[i].matrix.x0 -=
 
557
            x0 * wd->quad[i].matrix.xx +
 
558
            y0 * wd->quad[i].matrix.xy;
 
559
 
 
560
        wd->quad[i].matrix.y0 -=
 
561
            y0 * wd->quad[i].matrix.yy +
 
562
            x0 * wd->quad[i].matrix.yx;
 
563
 
 
564
        wd->quad[i].matrix.x0 -=
 
565
            wd->quad[i].box.x1 * wd->quad[i].matrix.xx +
 
566
            wd->quad[i].box.y1 * wd->quad[i].matrix.xy;
 
567
 
 
568
        wd->quad[i].matrix.y0 -=
 
569
            wd->quad[i].box.y1 * wd->quad[i].matrix.yy +
 
570
            wd->quad[i].box.x1 * wd->quad[i].matrix.yx;
 
571
    }
 
572
}
 
573
 
 
574
void
 
575
DecorWindow::updateDecorationScale ()
 
576
{
 
577
    int              x1, y1, x2, y2;
 
578
    float            sx, sy;
 
579
    int              i;
 
580
 
 
581
    if (!wd)
 
582
        return;
 
583
 
 
584
    for (i = 0; i < wd->nQuad; i++)
 
585
    {
 
586
        int x, y;
 
587
 
 
588
        computeQuadBox (&wd->decor->quad[i], window->size ().width (),
 
589
                        window->size ().height (),
 
590
                        &x1, &y1, &x2, &y2, &sx, &sy);
 
591
 
 
592
        x = window->geometry ().x ();
 
593
        y = window->geometry ().y ();
 
594
 
 
595
        wd->quad[i].box.x1 = x1 + x;
 
596
        wd->quad[i].box.y1 = y1 + y;
 
597
        wd->quad[i].box.x2 = x2 + x;
 
598
        wd->quad[i].box.y2 = y2 + y;
 
599
        wd->quad[i].sx     = sx;
 
600
        wd->quad[i].sy     = sy;
 
601
    }
 
602
 
 
603
    setDecorationMatrices ();
 
604
}
 
605
 
 
606
bool
 
607
DecorWindow::checkSize (Decoration *decor)
 
608
{
 
609
    return (decor->minWidth <= (int) window->size ().width () &&
 
610
            decor->minHeight <= (int) window->size ().height ());
 
611
}
 
612
 
 
613
int
 
614
DecorWindow::shiftX ()
 
615
{
 
616
    switch (window->sizeHints ().win_gravity) {
 
617
        case WestGravity:
 
618
        case NorthWestGravity:
 
619
        case SouthWestGravity:
 
620
            return window->input ().left;
 
621
        case EastGravity:
 
622
        case NorthEastGravity:
 
623
        case SouthEastGravity:
 
624
            return -window->input ().right;
 
625
    }
 
626
 
 
627
    return 0;
 
628
}
 
629
 
 
630
int
 
631
DecorWindow::shiftY ()
 
632
{
 
633
    switch (window->sizeHints ().win_gravity) {
 
634
        case NorthGravity:
 
635
        case NorthWestGravity:
 
636
        case NorthEastGravity:
 
637
            return window->input ().top;
 
638
        case SouthGravity:
 
639
        case SouthWestGravity:
 
640
        case SouthEastGravity:
 
641
            return -window->input ().bottom;
 
642
    }
 
643
 
 
644
    return 0;
 
645
}
 
646
 
 
647
static bool
 
648
decorOffsetMove (CompWindow *w, XWindowChanges xwc, unsigned int mask)
 
649
{
 
650
    w->configureXWindow (mask, &xwc);
 
651
    return false;
 
652
}
 
653
 
 
654
bool
 
655
DecorWindow::update (bool allowDecoration)
 
656
{
 
657
    Decoration       *old, *decoration = NULL;
 
658
    bool             decorate = false;
 
659
    CompMatch        *match;
 
660
    int              moveDx, moveDy;
 
661
    int              oldShiftX = 0;
 
662
    int              oldShiftY  = 0;
 
663
 
 
664
    old = (wd) ? wd->decor : NULL;
 
665
 
 
666
    switch (window->type ()) {
 
667
        case CompWindowTypeDialogMask:
 
668
        case CompWindowTypeModalDialogMask:
 
669
        case CompWindowTypeUtilMask:
 
670
        case CompWindowTypeMenuMask:
 
671
        case CompWindowTypeNormalMask:
 
672
            if (window->mwmDecor () & (MwmDecorAll | MwmDecorTitle))
 
673
                decorate = window->managed ();
 
674
        default:
 
675
            break;
 
676
    }
 
677
 
 
678
    if (window->overrideRedirect ())
 
679
        decorate = false;
 
680
 
 
681
    if (decorate)
 
682
    {
 
683
        match =
 
684
            &dScreen->opt[DECOR_OPTION_DECOR_MATCH].value ().match ();
 
685
        if (!match->evaluate (window))
 
686
            decorate = false;
 
687
    }
 
688
 
 
689
    if (decorate)
 
690
    {
 
691
        if (decor && checkSize (decor))
 
692
        {
 
693
            decoration = decor;
 
694
        }
 
695
        else
 
696
        {
 
697
            
 
698
            if (dScreen->dmSupports & WINDOW_DECORATION_TYPE_PIXMAP &&
 
699
                dScreen->cmActive &&
 
700
                !(dScreen->dmSupports & WINDOW_DECORATION_TYPE_WINDOW &&
 
701
                  pixmapFailed))
 
702
            {
 
703
                if (window->id () == screen->activeWindow ())
 
704
                    decoration = dScreen->decor[DECOR_ACTIVE];
 
705
                else
 
706
                    decoration = dScreen->decor[DECOR_NORMAL];
 
707
            }
 
708
            else if (dScreen->dmSupports & WINDOW_DECORATION_TYPE_WINDOW)
 
709
                decoration = &dScreen->windowDefault;
 
710
        }
 
711
    }
 
712
    else
 
713
    {
 
714
        match = &dScreen->opt[DECOR_OPTION_SHADOW_MATCH].value ().match ();
 
715
        if (match->evaluate (window))
 
716
        {
 
717
            if (window->region ().numRects () == 1 && !window->alpha ())
 
718
                decoration = dScreen->decor[DECOR_BARE];
 
719
 
 
720
            if (decoration)
 
721
            {
 
722
                if (!checkSize (decoration))
 
723
                    decoration = NULL;
 
724
            }
 
725
        }
 
726
    }
 
727
 
 
728
    if (!dScreen->dmWin || !allowDecoration)
 
729
        decoration = NULL;
 
730
 
 
731
    if (decoration == old)
 
732
        return false;
 
733
 
 
734
    if (dScreen->cmActive)
 
735
        cWindow->damageOutputExtents ();
 
736
 
 
737
    if (old)
 
738
    {
 
739
        oldShiftX = shiftX ();
 
740
        oldShiftY = shiftY ();
 
741
 
 
742
        WindowDecoration::destroy (wd);
 
743
 
 
744
        wd = NULL;
 
745
    }
 
746
 
 
747
    if (decoration)
 
748
    {
 
749
        wd = WindowDecoration::create (decoration);
 
750
        if (!wd)
 
751
            return false;
 
752
 
 
753
        if ((window->state () & MAXIMIZE_STATE) == MAXIMIZE_STATE)
 
754
            window->setWindowFrameExtents (&wd->decor->maxInput);
 
755
        else
 
756
            window->setWindowFrameExtents (&wd->decor->input);
 
757
 
 
758
        moveDx = shiftX () - oldShiftX;
 
759
        moveDy = shiftY () - oldShiftY;
 
760
 
 
761
        updateFrame ();
 
762
        window->updateWindowOutputExtents ();
 
763
        if (dScreen->cmActive)
 
764
            cWindow->damageOutputExtents ();
 
765
        updateDecorationScale ();
 
766
    }
 
767
    else
 
768
    {
 
769
        CompWindowExtents emptyExtents;
 
770
        wd = NULL;
 
771
 
 
772
        updateFrame ();
 
773
        
 
774
        memset (&emptyExtents, 0, sizeof (CompWindowExtents));
 
775
 
 
776
        window->setWindowFrameExtents (&emptyExtents);
 
777
 
 
778
        moveDx = -oldShiftX;
 
779
        moveDy = -oldShiftY;
 
780
    }
 
781
 
 
782
    if (window->placed () && !window->overrideRedirect () &&
 
783
        (moveDx || moveDy))
 
784
    {
 
785
        XWindowChanges xwc;
 
786
        unsigned int   mask = CWX | CWY;
 
787
 
 
788
        memset (&xwc, 0, sizeof (XWindowChanges));
 
789
 
 
790
        xwc.x = window->serverGeometry ().x () + moveDx;
 
791
        xwc.y = window->serverGeometry ().y () + moveDy;
 
792
 
 
793
        if (window->state () & CompWindowStateFullscreenMask)
 
794
            mask &= ~(CWX | CWY);
 
795
 
 
796
        if (window->state () & CompWindowStateMaximizedHorzMask)
 
797
            mask &= ~CWX;
 
798
 
 
799
        if (window->state () & CompWindowStateMaximizedVertMask)
 
800
            mask &= ~CWY;
 
801
 
 
802
        if (window->saveMask () & CWX)
 
803
            window->saveWc ().x += moveDx;
 
804
 
 
805
        if (window->saveMask () & CWY)
 
806
            window->saveWc ().y += moveDy;
 
807
 
 
808
        if (mask)
 
809
            moveUpdate.start (boost::bind (decorOffsetMove, window, xwc, mask), 0);
 
810
    }
 
811
 
 
812
    return true;
 
813
}
 
814
 
 
815
void
 
816
DecorWindow::updateFrame ()
 
817
{
 
818
    if (!wd || !(window->input ().left || window->input ().right ||
 
819
        window->input ().top || window->input ().bottom) ||
 
820
        (wd->decor->type == WINDOW_DECORATION_TYPE_PIXMAP && outputFrame) ||
 
821
        (wd->decor->type == WINDOW_DECORATION_TYPE_WINDOW && inputFrame))
 
822
    {
 
823
        if (inputFrame)
 
824
        {
 
825
            XDeleteProperty (screen->dpy (), window->id (),
 
826
                             dScreen->inputFrameAtom);
 
827
            XDestroyWindow (screen->dpy (), inputFrame);
 
828
            inputFrame = None;
 
829
            frameRegion = CompRegion ();
 
830
 
 
831
            oldX = 0;
 
832
            oldY = 0;
 
833
            oldWidth  = 0;
 
834
            oldHeight = 0;
 
835
        }
 
836
        if (outputFrame)
 
837
        {
 
838
            XDamageDestroy (screen->dpy (), frameDamage);
 
839
            XDeleteProperty (screen->dpy (), window->id (),
 
840
                             dScreen->outputFrameAtom);
 
841
            XDestroyWindow (screen->dpy (), outputFrame);
 
842
            dScreen->frames.erase (outputFrame);
 
843
 
 
844
            outputFrame = None;
 
845
            frameRegion = CompRegion ();
 
846
 
 
847
            oldX = 0;
 
848
            oldY = 0;
 
849
            oldWidth  = 0;
 
850
            oldHeight = 0;
 
851
        }
 
852
    }
 
853
    if (wd && (window->input ().left || window->input ().right ||
 
854
        window->input ().top || window->input ().bottom))
 
855
    {
 
856
        if (wd->decor->type == WINDOW_DECORATION_TYPE_PIXMAP)
 
857
            updateInputFrame ();
 
858
        else if (wd->decor->type == WINDOW_DECORATION_TYPE_WINDOW)
 
859
            updateOutputFrame ();
 
860
    }
 
861
}
 
862
 
 
863
void
 
864
DecorWindow::updateInputFrame ()
 
865
{
 
866
    XRectangle           rects[4];
 
867
    int                  x, y, width, height;
 
868
    int                  i = 0;
 
869
    CompWindow::Geometry server = window->serverGeometry ();
 
870
    int                  bw = server.border () * 2;
 
871
    CompWindowExtents    input;
 
872
 
 
873
    if ((window->state () & MAXIMIZE_STATE) == MAXIMIZE_STATE)
 
874
        input = wd->decor->maxInput;
 
875
    else
 
876
        input = wd->decor->input;
 
877
 
 
878
    x      = window->input ().left - input.left;
 
879
    y      = window->input ().top - input.top;
 
880
    width  = server.width () + input.left + input.right + bw;
 
881
    height = server.height ()+ input.top  + input.bottom + bw;
 
882
 
 
883
    if (window->shaded ())
 
884
        height = input.top + input.bottom;
 
885
 
 
886
    XGrabServer (screen->dpy ());
 
887
 
 
888
    if (!inputFrame)
 
889
    {
 
890
        XSetWindowAttributes attr;
 
891
 
 
892
        attr.event_mask    = StructureNotifyMask;
 
893
        attr.override_redirect = TRUE;
 
894
 
 
895
        inputFrame = XCreateWindow (screen->dpy (), window->frame (),
 
896
                                    x, y, width, height, 0, CopyFromParent,
 
897
                                    InputOnly, CopyFromParent,
 
898
                                    CWOverrideRedirect | CWEventMask,
 
899
                                    &attr);
 
900
 
 
901
        XGrabButton (screen->dpy (), AnyButton, AnyModifier, inputFrame,
 
902
                     TRUE, ButtonPressMask | ButtonReleaseMask |
 
903
                     ButtonMotionMask, GrabModeSync, GrabModeSync, None,
 
904
                     None);
 
905
 
 
906
        XMapWindow (screen->dpy (), inputFrame);
 
907
 
 
908
        XChangeProperty (screen->dpy (), window->id (),
 
909
                         dScreen->inputFrameAtom, XA_WINDOW, 32,
 
910
                         PropModeReplace, (unsigned char *) &inputFrame, 1);
 
911
 
 
912
        if (screen->XShape ())
 
913
            XShapeSelectInput (screen->dpy (), inputFrame, ShapeNotifyMask);
 
914
 
 
915
        oldX = 0;
 
916
        oldY = 0;
 
917
        oldWidth  = 0;
 
918
        oldHeight = 0;
 
919
    }
 
920
 
 
921
    if (x != oldX || y != oldY || width != oldWidth || height != oldHeight)
 
922
    {
 
923
        oldX = x;
 
924
        oldY = y;
 
925
        oldWidth  = width;
 
926
        oldHeight = height;
 
927
 
 
928
        XMoveResizeWindow (screen->dpy (), inputFrame, x, y,
 
929
                           width, height);
 
930
        XLowerWindow (screen->dpy (), inputFrame);
 
931
 
 
932
 
 
933
        rects[i].x      = 0;
 
934
        rects[i].y      = 0;
 
935
        rects[i].width  = width;
 
936
        rects[i].height = input.top;
 
937
 
 
938
        if (rects[i].width && rects[i].height)
 
939
            i++;
 
940
 
 
941
        rects[i].x      = 0;
 
942
        rects[i].y      = input.top;
 
943
        rects[i].width  = input.left;
 
944
        rects[i].height = height - input.top - input.bottom;
 
945
 
 
946
        if (rects[i].width && rects[i].height)
 
947
            i++;
 
948
 
 
949
        rects[i].x      = width - input.right;
 
950
        rects[i].y      = input.top;
 
951
        rects[i].width  = input.right;
 
952
        rects[i].height = height - input.top - input.bottom;
 
953
 
 
954
        if (rects[i].width && rects[i].height)
 
955
            i++;
 
956
 
 
957
        rects[i].x      = 0;
 
958
        rects[i].y      = height - input.bottom;
 
959
        rects[i].width  = width;
 
960
        rects[i].height = input.bottom;
 
961
 
 
962
        if (rects[i].width && rects[i].height)
 
963
            i++;
 
964
 
 
965
        XShapeCombineRectangles (screen->dpy (), inputFrame,
 
966
                                 ShapeInput, 0, 0, rects, i,
 
967
                                 ShapeSet, YXBanded);
 
968
 
 
969
        frameRegion = CompRegion ();
 
970
    }
 
971
 
 
972
    XUngrabServer (screen->dpy ());
 
973
}
 
974
 
 
975
void
 
976
DecorWindow::updateOutputFrame ()
 
977
{
 
978
    XRectangle           rects[4];
 
979
    int                  x, y, width, height;
 
980
    int                  i = 0;
 
981
    CompWindow::Geometry server = window->serverGeometry ();
 
982
    int                  bw = server.border () * 2;
 
983
    CompWindowExtents    input;
 
984
 
 
985
    if ((window->state () & MAXIMIZE_STATE) == MAXIMIZE_STATE)
 
986
        input = wd->decor->maxInput;
 
987
    else
 
988
        input = wd->decor->input;
 
989
 
 
990
    x      = window->input ().left - input.left;
 
991
    y      = window->input ().top - input.top;
 
992
    width  = server.width () + input.left + input.right + bw;
 
993
    height = server.height ()+ input.top  + input.bottom + bw;
 
994
 
 
995
    if (window->shaded ())
 
996
        height = input.top + input.bottom;
 
997
 
 
998
    XGrabServer (screen->dpy ());
 
999
 
 
1000
    if (!outputFrame)
 
1001
    {
 
1002
        XSetWindowAttributes attr;
 
1003
 
 
1004
        attr.background_pixel  = 0x0;
 
1005
        attr.event_mask        = StructureNotifyMask;
 
1006
        attr.override_redirect = TRUE;
 
1007
 
 
1008
        outputFrame = XCreateWindow (screen->dpy (), window->frame (),
 
1009
                                     x, y, width, height, 0, CopyFromParent,
 
1010
                                     InputOutput, CopyFromParent,
 
1011
                                     CWOverrideRedirect | CWEventMask,
 
1012
                                     &attr);
 
1013
 
 
1014
        XGrabButton (screen->dpy (), AnyButton, AnyModifier, outputFrame,
 
1015
                        TRUE, ButtonPressMask | ButtonReleaseMask |
 
1016
                        ButtonMotionMask, GrabModeSync, GrabModeSync, None,
 
1017
                        None);
 
1018
 
 
1019
        XMapWindow (screen->dpy (), outputFrame);
 
1020
 
 
1021
        XChangeProperty (screen->dpy (), window->id (),
 
1022
                         dScreen->outputFrameAtom, XA_WINDOW, 32,
 
1023
                         PropModeReplace, (unsigned char *) &outputFrame, 1);
 
1024
        
 
1025
        if (screen->XShape ())
 
1026
            XShapeSelectInput (screen->dpy (), outputFrame,
 
1027
                               ShapeNotifyMask);
 
1028
 
 
1029
        oldX = 0;
 
1030
        oldY = 0;
 
1031
        oldWidth  = 0;
 
1032
        oldHeight = 0;
 
1033
 
 
1034
        frameDamage = XDamageCreate (screen->dpy (), outputFrame,
 
1035
                                     XDamageReportRawRectangles);
 
1036
 
 
1037
        dScreen->frames[outputFrame] = this;
 
1038
    }
 
1039
 
 
1040
    if (x != oldX || y != oldY || width != oldWidth || height != oldHeight)
 
1041
    {
 
1042
        oldX = x;
 
1043
        oldY = y;
 
1044
        oldWidth  = width;
 
1045
        oldHeight = height;
 
1046
 
 
1047
        XMoveResizeWindow (screen->dpy (), outputFrame, x, y, width, height);
 
1048
        XLowerWindow (screen->dpy (), outputFrame);
 
1049
 
 
1050
 
 
1051
        rects[i].x      = 0;
 
1052
        rects[i].y      = 0;
 
1053
        rects[i].width  = width;
 
1054
        rects[i].height = input.top;
 
1055
 
 
1056
        if (rects[i].width && rects[i].height)
 
1057
            i++;
 
1058
 
 
1059
        rects[i].x      = 0;
 
1060
        rects[i].y      = input.top;
 
1061
        rects[i].width  = input.left;
 
1062
        rects[i].height = height - input.top - input.bottom;
 
1063
 
 
1064
        if (rects[i].width && rects[i].height)
 
1065
            i++;
 
1066
 
 
1067
        rects[i].x      = width - input.right;
 
1068
        rects[i].y      = input.top;
 
1069
        rects[i].width  = input.right;
 
1070
        rects[i].height = height - input.top - input.bottom;
 
1071
 
 
1072
        if (rects[i].width && rects[i].height)
 
1073
            i++;
 
1074
 
 
1075
        rects[i].x      = 0;
 
1076
        rects[i].y      = height - input.bottom;
 
1077
        rects[i].width  = width;
 
1078
        rects[i].height = input.bottom;
 
1079
 
 
1080
        if (rects[i].width && rects[i].height)
 
1081
            i++;
 
1082
 
 
1083
        XShapeCombineRectangles (screen->dpy (), outputFrame,
 
1084
                                 ShapeBounding, 0, 0, rects, i,
 
1085
                                 ShapeSet, YXBanded);
 
1086
 
 
1087
        frameRegion = CompRegion ();
 
1088
    }
 
1089
 
 
1090
    XUngrabServer (screen->dpy ());
 
1091
}
 
1092
 
 
1093
void
 
1094
DecorScreen::checkForDm (bool updateWindows)
 
1095
{
 
1096
    Atom          actual;
 
1097
    int           result, format, dmSupports = 0;
 
1098
    unsigned long n, left;
 
1099
    unsigned char *data;
 
1100
    Window        dmWin = None;
 
1101
 
 
1102
    result = XGetWindowProperty (screen->dpy (), screen->root (),
 
1103
                                 supportingDmCheckAtom, 0L, 1L, FALSE,
 
1104
                                 XA_WINDOW, &actual, &format,
 
1105
                                 &n, &left, &data);
 
1106
 
 
1107
    if (result == Success && n && data)
 
1108
    {
 
1109
        XWindowAttributes attr;
 
1110
 
 
1111
        memcpy (&dmWin, data, sizeof (Window));
 
1112
        XFree (data);
 
1113
 
 
1114
        CompScreen::checkForError (screen->dpy ());
 
1115
 
 
1116
        XGetWindowAttributes (screen->dpy (), dmWin, &attr);
 
1117
 
 
1118
        if (CompScreen::checkForError (screen->dpy ()))
 
1119
            dmWin = None;
 
1120
        else
 
1121
        {
 
1122
            result = XGetWindowProperty (screen->dpy (), dmWin,
 
1123
                                         decorTypeAtom, 0L, 2L, FALSE,
 
1124
                                         XA_ATOM, &actual, &format,
 
1125
                                         &n, &left, &data);
 
1126
            if (result == Success && n && data)
 
1127
            {
 
1128
                Atom *ret = (Atom *) data;
 
1129
 
 
1130
                for (unsigned long i = 0; i < n; i++)
 
1131
                {
 
1132
                    if (ret[i] == decorTypePixmapAtom)
 
1133
                        dmSupports |= WINDOW_DECORATION_TYPE_PIXMAP;
 
1134
                    else if (ret[i] == decorTypeWindowAtom)
 
1135
                        dmSupports |= WINDOW_DECORATION_TYPE_WINDOW;
 
1136
                }
 
1137
 
 
1138
                if (!dmSupports)
 
1139
                    dmWin = None;
 
1140
                
 
1141
                XFree (data);
 
1142
            }
 
1143
            else
 
1144
                dmWin = None;
 
1145
        }
 
1146
    }
 
1147
 
 
1148
    if (dmWin != this->dmWin)
 
1149
    {
 
1150
        int i;
 
1151
 
 
1152
        this->dmSupports = dmSupports;
 
1153
 
 
1154
        if (dmWin)
 
1155
        {
 
1156
            for (i = 0; i < DECOR_NUM; i++)
 
1157
                decor[i] = Decoration::create (screen->root (), decorAtom[i]);
 
1158
        }
 
1159
        else
 
1160
        {
 
1161
            for (i = 0; i < DECOR_NUM; i++)
 
1162
            {
 
1163
                if (decor[i])
 
1164
                {
 
1165
                    Decoration::release (decor[i]);
 
1166
                    decor[i] = 0;
 
1167
                }
 
1168
            }
 
1169
 
 
1170
            foreach (CompWindow *w, screen->windows ())
 
1171
            {
 
1172
                DecorWindow *dw = DecorWindow::get (w);
 
1173
 
 
1174
                if (dw->decor)
 
1175
                {
 
1176
                    Decoration::release (dw->decor);
 
1177
                    dw->decor = 0;
 
1178
                }
 
1179
            }
 
1180
        }
 
1181
 
 
1182
        this->dmWin = dmWin;
 
1183
 
 
1184
        if (updateWindows)
 
1185
        {
 
1186
            foreach (CompWindow *w, screen->windows ())
 
1187
                if (w->shaded () || w->isViewable ())
 
1188
                    DecorWindow::get (w)->update (true);
 
1189
        }
 
1190
    }
 
1191
}
 
1192
 
 
1193
void
 
1194
DecorWindow::updateFrameRegion (CompRegion &region)
 
1195
{
 
1196
    window->updateFrameRegion (region);
 
1197
    if (wd)
 
1198
    {
 
1199
        if (!frameRegion.isEmpty ())
 
1200
        {
 
1201
            int x, y;
 
1202
 
 
1203
            x = window->geometry (). x ();
 
1204
            y = window->geometry (). y ();
 
1205
 
 
1206
            region += frameRegion.translated (x - window->input ().left,
 
1207
                                              y - window->input ().top);
 
1208
        }
 
1209
        else
 
1210
        {
 
1211
            region += infiniteRegion;
 
1212
        }
 
1213
    }
 
1214
    updateReg = true;
 
1215
}
 
1216
 
 
1217
void
 
1218
DecorWindow::updateWindowRegions ()
 
1219
{
 
1220
    if (regions.size () != gWindow->textures ().size ())
 
1221
        regions.resize (gWindow->textures ().size ());
 
1222
    for (unsigned int i = 0; i < gWindow->textures ().size (); i++)
 
1223
    {
 
1224
        regions[i] = CompRegion (*gWindow->textures ()[i]);
 
1225
        regions[i].translate (window->geometry ().x () - window->input ().left,
 
1226
                              window->geometry ().y () - window->input ().top);
 
1227
        regions[i] &= window->frameRegion ();
 
1228
    }
 
1229
    updateReg = false;
 
1230
}
 
1231
 
 
1232
void
 
1233
DecorScreen::handleEvent (XEvent *event)
 
1234
{
 
1235
    Window  activeWindow = screen->activeWindow ();
 
1236
    CompWindow *w;
 
1237
 
 
1238
    switch (event->type) {
 
1239
        case DestroyNotify:
 
1240
            w = screen->findWindow (event->xdestroywindow.window);
 
1241
            if (w)
 
1242
            {
 
1243
                if (w->id () == dmWin)
 
1244
                    checkForDm (true);
 
1245
            }
 
1246
            break;
 
1247
        case MapRequest:
 
1248
            w = screen->findWindow (event->xdestroywindow.window);
 
1249
            if (w)
 
1250
                DecorWindow::get (w)->update (true);
 
1251
            break;
 
1252
        default:
 
1253
            if (cmActive &&
 
1254
                event->type == cScreen->damageEvent () + XDamageNotify)
 
1255
            {
 
1256
                XDamageNotifyEvent *de = (XDamageNotifyEvent *) event;
 
1257
 
 
1258
                if (frames.find (de->drawable) != frames.end ())
 
1259
                    frames[de->drawable]->cWindow->damageOutputExtents ();
 
1260
                
 
1261
                foreach (DecorTexture *t, textures)
 
1262
                {
 
1263
                    if (t->pixmap == de->drawable)
 
1264
                    {
 
1265
                        foreach (CompWindow *w, screen->windows ())
 
1266
                        {
 
1267
                            if (w->shaded () || w->mapNum ())
 
1268
                            {
 
1269
                                DECOR_WINDOW (w);
 
1270
 
 
1271
                                if (dw->wd && dw->wd->decor->texture == t)
 
1272
                                    dw->cWindow->damageOutputExtents ();
 
1273
                            }
 
1274
                        }
 
1275
                        return;
 
1276
                    }
 
1277
                }
 
1278
            }
 
1279
            break;
 
1280
    }
 
1281
 
 
1282
    screen->handleEvent (event);
 
1283
 
 
1284
    if (screen->activeWindow () != activeWindow)
 
1285
    {
 
1286
        w = screen->findWindow (activeWindow);
 
1287
        if (w)
 
1288
            DecorWindow::get (w)->update (true);
 
1289
 
 
1290
        w = screen->findWindow (screen->activeWindow ());
 
1291
        if (w)
 
1292
            DecorWindow::get (w)->update (true);
 
1293
    }
 
1294
 
 
1295
    switch (event->type) {
 
1296
        case PropertyNotify:
 
1297
            if (event->xproperty.atom == winDecorAtom)
 
1298
            {
 
1299
                w = screen->findWindow (event->xproperty.window);
 
1300
                if (w)
 
1301
                {
 
1302
                    DECOR_WINDOW (w);
 
1303
                    dw->updateDecoration ();
 
1304
                    dw->update (true);
 
1305
                }
 
1306
            }
 
1307
            else if (event->xproperty.atom == Atoms::mwmHints)
 
1308
            {
 
1309
                w = screen->findWindow (event->xproperty.window);
 
1310
                if (w)
 
1311
                    DecorWindow::get (w)->update (true);
 
1312
            }
 
1313
            else
 
1314
            {
 
1315
                if (event->xproperty.window == screen->root ())
 
1316
                {
 
1317
                    if (event->xproperty.atom == supportingDmCheckAtom)
 
1318
                    {
 
1319
                        checkForDm (true);
 
1320
                    }
 
1321
                    else
 
1322
                    {
 
1323
                        int i;
 
1324
 
 
1325
                        for (i = 0; i < DECOR_NUM; i++)
 
1326
                        {
 
1327
                            if (event->xproperty.atom == decorAtom[i])
 
1328
                            {
 
1329
                                if (decor[i])
 
1330
                                    Decoration::release (decor[i]);
 
1331
 
 
1332
                                decor[i] =
 
1333
                                    Decoration::create (screen->root (),
 
1334
                                                        decorAtom[i]);
 
1335
 
 
1336
                                foreach (CompWindow *w, screen->windows ())
 
1337
                                    DecorWindow::get (w)->update (true);
 
1338
                            }
 
1339
                        }
 
1340
                    }
 
1341
                }
 
1342
            }
 
1343
            break;
 
1344
        case ConfigureNotify:
 
1345
            w = screen->findTopLevelWindow (event->xconfigure.window);
 
1346
            if (w)
 
1347
            {
 
1348
                DECOR_WINDOW (w);
 
1349
                if (dw->decor)
 
1350
                {
 
1351
                    dw->updateFrame ();
 
1352
                }
 
1353
            }
 
1354
            break;
 
1355
        case DestroyNotify:
 
1356
            w = screen->findTopLevelWindow (event->xproperty.window);
 
1357
            if (w)
 
1358
            {
 
1359
                DECOR_WINDOW (w);
 
1360
                if (dw->inputFrame &&
 
1361
                    dw->inputFrame == event->xdestroywindow.window)
 
1362
                {
 
1363
                    XDeleteProperty (screen->dpy (), w->id (),
 
1364
                                     inputFrameAtom);
 
1365
                    dw->inputFrame = None;
 
1366
                }
 
1367
                else if (dw->outputFrame &&
 
1368
                         dw->outputFrame == event->xdestroywindow.window)
 
1369
                {
 
1370
                    XDeleteProperty (screen->dpy (), w->id (),
 
1371
                                     outputFrameAtom);
 
1372
                    dw->outputFrame = None;
 
1373
                }
 
1374
            }
 
1375
            break;
 
1376
        default:
 
1377
            if (screen->XShape () && event->type ==
 
1378
                screen->shapeEvent () + ShapeNotify)
 
1379
            {
 
1380
                w = screen->findWindow (((XShapeEvent *) event)->window);
 
1381
                if (w)
 
1382
                    DecorWindow::get (w)->update (true);
 
1383
                else
 
1384
                {
 
1385
                    foreach (w, screen->windows ())
 
1386
                    {
 
1387
                        DECOR_WINDOW (w);
 
1388
                        if (dw->inputFrame ==
 
1389
                            ((XShapeEvent *) event)->window)
 
1390
                        {
 
1391
                            XRectangle *shapeRects = 0;
 
1392
                            int order, n;
 
1393
 
 
1394
                            dw->frameRegion = CompRegion ();
 
1395
 
 
1396
                            shapeRects =
 
1397
                                XShapeGetRectangles (screen->dpy (),
 
1398
                                    dw->inputFrame, ShapeInput,
 
1399
                                    &n, &order);
 
1400
                            if (!n || !shapeRects)
 
1401
                                break;
 
1402
 
 
1403
                            for (int i = 0; i < n; i++)
 
1404
                                dw->frameRegion +=
 
1405
                                    CompRegion (shapeRects[i].x,
 
1406
                                                shapeRects[i].y,
 
1407
                                                shapeRects[i].width,
 
1408
                                                shapeRects[i].height);
 
1409
 
 
1410
                            w->updateFrameRegion ();
 
1411
 
 
1412
                            XFree (shapeRects);
 
1413
                        }
 
1414
                        else if (dw->outputFrame ==
 
1415
                                 ((XShapeEvent *) event)->window)
 
1416
                        {
 
1417
                            XRectangle *shapeRects = 0;
 
1418
                            int order, n;
 
1419
 
 
1420
                            dw->frameRegion = CompRegion ();
 
1421
 
 
1422
                            shapeRects =
 
1423
                                XShapeGetRectangles (screen->dpy (),
 
1424
                                    dw->outputFrame, ShapeBounding,
 
1425
                                    &n, &order);
 
1426
                            if (!n || !shapeRects)
 
1427
                                break;
 
1428
 
 
1429
                            for (int i = 0; i < n; i++)
 
1430
                                dw->frameRegion +=
 
1431
                                    CompRegion (shapeRects[i].x,
 
1432
                                                shapeRects[i].y,
 
1433
                                                shapeRects[i].width,
 
1434
                                                shapeRects[i].height);
 
1435
 
 
1436
                            w->updateFrameRegion ();
 
1437
 
 
1438
                            XFree (shapeRects);
 
1439
                        }
 
1440
                    }
 
1441
                }
 
1442
            }
 
1443
            break;
 
1444
    }
 
1445
}
 
1446
 
 
1447
bool
 
1448
DecorWindow::damageRect (bool initial, const CompRect &rect)
 
1449
{
 
1450
    if (initial)
 
1451
        update (true);
 
1452
 
 
1453
    return cWindow->damageRect (initial, rect);
 
1454
}
 
1455
 
 
1456
void
 
1457
DecorWindow::getOutputExtents (CompWindowExtents& output)
 
1458
{
 
1459
    window->getOutputExtents (output);
 
1460
 
 
1461
    if (wd)
 
1462
    {
 
1463
        CompWindowExtents *e = &wd->decor->output;
 
1464
 
 
1465
        if (e->left > output.left)
 
1466
            output.left = e->left;
 
1467
        if (e->right > output.right)
 
1468
            output.right = e->right;
 
1469
        if (e->top > output.top)
 
1470
            output.top = e->top;
 
1471
        if (e->bottom > output.bottom)
 
1472
            output.bottom = e->bottom;
 
1473
    }
 
1474
}
 
1475
 
 
1476
CompOption::Vector &
 
1477
DecorScreen::getOptions ()
 
1478
{
 
1479
    return opt;
 
1480
}
 
1481
 
 
1482
bool
 
1483
DecorScreen::setOption (const char        *name,
 
1484
                        CompOption::Value &value)
 
1485
{
 
1486
    CompOption   *o;
 
1487
    unsigned int index;
 
1488
 
 
1489
    o = CompOption::findOption (opt, name, &index);
 
1490
    if (!o)
 
1491
        return false;
 
1492
 
 
1493
    switch (index) {
 
1494
    case DECOR_OPTION_COMMAND:
 
1495
        if (o->set(value))
 
1496
        {
 
1497
 
 
1498
            if (!dmWin)
 
1499
                screen->runCommand (o->value ().s ());
 
1500
            return true;
 
1501
        }
 
1502
        break;
 
1503
    case DECOR_OPTION_SHADOW_MATCH:
 
1504
        {
 
1505
            CompString matchString;
 
1506
 
 
1507
            /*
 
1508
               Make sure RGBA matching is always present and disable shadows
 
1509
               for RGBA windows by default if the user didn't specify an
 
1510
               RGBA match.
 
1511
               Reasoning for that is that shadows are desired for some RGBA
 
1512
               windows (e.g. rectangular windows that just happen to have an
 
1513
               RGBA colormap), while it's absolutely undesired for others
 
1514
               (especially shaped ones) ... by enforcing no shadows for RGBA
 
1515
               windows by default, we are flexible to user desires while still
 
1516
               making sure we don't show ugliness by default
 
1517
             */
 
1518
 
 
1519
            matchString = value.match ().toString ();
 
1520
            if (matchString.find ("rgba=") == CompString::npos)
 
1521
            {
 
1522
                CompMatch rgbaMatch("rgba=0");
 
1523
                value.match () &= rgbaMatch;
 
1524
            }
 
1525
        }
 
1526
        /* fall-through intended */
 
1527
    case DECOR_OPTION_DECOR_MATCH:
 
1528
        if (o->set(value))
 
1529
        {
 
1530
            foreach (CompWindow *w, screen->windows ())
 
1531
                DecorWindow::get (w)->update (true);
 
1532
        }
 
1533
        break;
 
1534
    default:
 
1535
        return CompOption::setOption (*o, value);
 
1536
    }
 
1537
 
 
1538
    return false;
 
1539
}
 
1540
 
 
1541
void
 
1542
DecorWindow::moveNotify (int dx, int dy, bool immediate)
 
1543
{
 
1544
    if (wd)
 
1545
    {
 
1546
        int              i;
 
1547
 
 
1548
        for (i = 0; i < wd->nQuad; i++)
 
1549
        {
 
1550
            wd->quad[i].box.x1 += dx;
 
1551
            wd->quad[i].box.y1 += dy;
 
1552
            wd->quad[i].box.x2 += dx;
 
1553
            wd->quad[i].box.y2 += dy;
 
1554
        }
 
1555
 
 
1556
        setDecorationMatrices ();
 
1557
    }
 
1558
    updateReg = true;
 
1559
 
 
1560
    window->moveNotify (dx, dy, immediate);
 
1561
}
 
1562
 
 
1563
bool
 
1564
DecorWindow::resizeTimeout ()
 
1565
{
 
1566
    update (true);
 
1567
    return false;
 
1568
}
 
1569
 
 
1570
void
 
1571
DecorWindow::resizeNotify (int dx, int dy, int dwidth, int dheight)
 
1572
{
 
1573
    /* FIXME: we should not need a timer for calling decorWindowUpdate,
 
1574
       and only call updateWindowDecorationScale if decorWindowUpdate
 
1575
       returns FALSE. Unfortunately, decorWindowUpdate may call
 
1576
       updateWindowOutputExtents, which may call WindowResizeNotify. As
 
1577
       we never should call a wrapped function that's currently
 
1578
       processed, we need the timer for the moment. updateWindowOutputExtents
 
1579
       should be fixed so that it does not emit a resize notification. */
 
1580
    resizeUpdate.start (boost::bind (&DecorWindow::resizeTimeout, this), 0);
 
1581
    updateDecorationScale ();
 
1582
    updateReg = true;
 
1583
 
 
1584
    window->resizeNotify (dx, dy, dwidth, dheight);
 
1585
}
 
1586
 
 
1587
void
 
1588
DecorWindow::stateChangeNotify (unsigned int lastState)
 
1589
{
 
1590
    if (!update (true))
 
1591
    {
 
1592
        if (wd && wd->decor)
 
1593
        {
 
1594
            if ((window->state () & MAXIMIZE_STATE) == MAXIMIZE_STATE)
 
1595
                window->setWindowFrameExtents (&wd->decor->maxInput);
 
1596
            else
 
1597
                window->setWindowFrameExtents (&wd->decor->input);
 
1598
 
 
1599
            updateFrame ();
 
1600
        }
 
1601
    }
 
1602
 
 
1603
    window->stateChangeNotify (lastState);
 
1604
}
 
1605
 
 
1606
void
 
1607
DecorScreen::matchPropertyChanged (CompWindow *w)
 
1608
{
 
1609
    DecorWindow::get (w)->update (true);
 
1610
 
 
1611
    screen->matchPropertyChanged (w);
 
1612
}
 
1613
 
 
1614
bool
 
1615
DecorScreen::decoratorStartTimeout ()
 
1616
{
 
1617
    if (!dmWin)
 
1618
        screen->runCommand (opt[DECOR_OPTION_COMMAND].value ().s ());
 
1619
 
 
1620
    return false;
 
1621
}
 
1622
 
 
1623
static const CompMetadata::OptionInfo decorOptionInfo[] = {
 
1624
    { "shadow_radius", "float", "<min>0.0</min><max>48.0</max>", 0, 0 },
 
1625
    { "shadow_opacity", "float", "<min>0.0</min>", 0, 0 },
 
1626
    { "shadow_color", "color", 0, 0, 0 },
 
1627
    { "shadow_x_offset", "int", "<min>-16</min><max>16</max>", 0, 0 },
 
1628
    { "shadow_y_offset", "int", "<min>-16</min><max>16</max>", 0, 0 },
 
1629
    { "command", "string", 0, 0, 0 },
 
1630
    { "mipmap", "bool", 0, 0, 0 },
 
1631
    { "decoration_match", "match", 0, 0, 0 },
 
1632
    { "shadow_match", "match", 0, 0, 0 }
 
1633
};
 
1634
 
 
1635
DecorScreen::DecorScreen (CompScreen *s) :
 
1636
    PrivateHandler<DecorScreen,CompScreen> (s),
 
1637
    cScreen (CompositeScreen::get (s)),
 
1638
    textures (),
 
1639
    dmWin (None),
 
1640
    dmSupports (0),
 
1641
    cmActive (false),
 
1642
    opt (DECOR_OPTION_NUM)
 
1643
{
 
1644
    if (!decorVTable->getMetadata ()->initOptions (decorOptionInfo,
 
1645
                                                   DECOR_OPTION_NUM, opt))
 
1646
    {
 
1647
        setFailed ();
 
1648
        return;
 
1649
    }
 
1650
 
 
1651
    supportingDmCheckAtom =
 
1652
        XInternAtom (s->dpy (), DECOR_SUPPORTING_DM_CHECK_ATOM_NAME, 0);
 
1653
    winDecorAtom =
 
1654
        XInternAtom (s->dpy (), DECOR_WINDOW_ATOM_NAME, 0);
 
1655
    decorAtom[DECOR_BARE] =
 
1656
        XInternAtom (s->dpy (), DECOR_BARE_ATOM_NAME, 0);
 
1657
    decorAtom[DECOR_NORMAL] =
 
1658
        XInternAtom (s->dpy (), DECOR_NORMAL_ATOM_NAME, 0);
 
1659
    decorAtom[DECOR_ACTIVE] =
 
1660
        XInternAtom (s->dpy (), DECOR_ACTIVE_ATOM_NAME, 0);
 
1661
    inputFrameAtom =
 
1662
        XInternAtom (s->dpy (), DECOR_INPUT_FRAME_ATOM_NAME, 0);
 
1663
    outputFrameAtom =
 
1664
        XInternAtom (s->dpy (), DECOR_OUTPUT_FRAME_ATOM_NAME, 0);
 
1665
    decorTypeAtom =
 
1666
        XInternAtom (s->dpy (), DECOR_TYPE_ATOM_NAME, 0);
 
1667
    decorTypePixmapAtom =
 
1668
        XInternAtom (s->dpy (), DECOR_TYPE_PIXMAP_ATOM_NAME, 0);
 
1669
    decorTypeWindowAtom =
 
1670
        XInternAtom (s->dpy (), DECOR_TYPE_WINDOW_ATOM_NAME, 0);
 
1671
 
 
1672
    windowDefault.texture   = NULL;
 
1673
    windowDefault.minWidth  = 0;
 
1674
    windowDefault.minHeight = 0;
 
1675
    windowDefault.quad      = NULL;
 
1676
    windowDefault.nQuad     = 0;
 
1677
    windowDefault.type      = WINDOW_DECORATION_TYPE_WINDOW;
 
1678
 
 
1679
    windowDefault.input.left   = 0;
 
1680
    windowDefault.input.right  = 0;
 
1681
    windowDefault.input.top    = 1;
 
1682
    windowDefault.input.bottom = 0;
 
1683
 
 
1684
    windowDefault.maxInput = windowDefault.output = windowDefault.input;
 
1685
    windowDefault.refCount = 1;
 
1686
 
 
1687
    cmActive = (cScreen) ? cScreen->compositingActive () &&
 
1688
               GLScreen::get (s) != NULL : false;
 
1689
 
 
1690
    for (unsigned int i = 0; i < DECOR_NUM; i++)
 
1691
        decor[i] = NULL;
 
1692
 
 
1693
    checkForDm (false);
 
1694
 
 
1695
    decoratorStart.start (boost::bind (&DecorScreen::decoratorStartTimeout,
 
1696
                                       this),
 
1697
                          0);
 
1698
 
 
1699
    ScreenInterface::setHandler (s);
 
1700
}
 
1701
 
 
1702
DecorScreen::~DecorScreen ()
 
1703
{
 
1704
    for (unsigned int i = 0; i < DECOR_NUM; i++)
 
1705
        if (decor[i])
 
1706
            Decoration::release (decor[i]);
 
1707
}
 
1708
 
 
1709
DecorWindow::DecorWindow (CompWindow *w) :
 
1710
    PrivateHandler<DecorWindow,CompWindow> (w),
 
1711
    window (w),
 
1712
    gWindow (GLWindow::get (w)),
 
1713
    cWindow (CompositeWindow::get (w)),
 
1714
    dScreen (DecorScreen::get (screen)),
 
1715
    wd (NULL),
 
1716
    decor (NULL),
 
1717
    inputFrame (None),
 
1718
    outputFrame (None),
 
1719
    pixmapFailed (false),
 
1720
    regions (),
 
1721
    updateReg (true)
 
1722
{
 
1723
    WindowInterface::setHandler (window);
 
1724
 
 
1725
    if (dScreen->cmActive)
 
1726
    {
 
1727
        gWindow = GLWindow::get (w);
 
1728
        cWindow = CompositeWindow::get (w);
 
1729
        CompositeWindowInterface::setHandler (cWindow);
 
1730
        GLWindowInterface::setHandler (gWindow);
 
1731
    }
 
1732
 
 
1733
    if (!w->overrideRedirect ())
 
1734
        updateDecoration ();
 
1735
 
 
1736
    if (w->shaded () || w->isViewable ())
 
1737
        update (true);
 
1738
}
 
1739
 
 
1740
 
 
1741
DecorWindow::~DecorWindow ()
 
1742
{
 
1743
    if (!window->destroyed ())
 
1744
        update (false);
 
1745
 
 
1746
    if (wd)
 
1747
        WindowDecoration::destroy (wd);
 
1748
 
 
1749
    if (decor)
 
1750
        Decoration::release (decor);
 
1751
}
 
1752
 
 
1753
bool
 
1754
DecorPluginVTable::init ()
 
1755
{
 
1756
    if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION))
 
1757
         return false;
 
1758
 
 
1759
    getMetadata ()->addFromOptionInfo (decorOptionInfo, DECOR_OPTION_NUM);
 
1760
    getMetadata ()->addFromFile (name ());
 
1761
 
 
1762
    return true;
 
1763
}
 
1764