~shnatsel/+junk/cairo-compmgr

« back to all changes in this revision

Viewing changes to src/ccm-pixmap.c

  • Committer: Sergey "Shnatsel" Davidoff
  • Date: 2012-03-04 22:53:22 UTC
  • Revision ID: shnatsel@gmail.com-20120304225322-q2hz82j51yxv1qqw
fixed up build dependencies

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*- */
 
2
/*
 
3
 * cairo-compmgr
 
4
 * Copyright (C) Nicolas Bruguier 2007-2010 <gandalfn@club-internet.fr>
 
5
 * 
 
6
 * cairo-compmgr is free softwstribute it and/or
 
7
 * modify it under the terms of the GNU Lesser General Public
 
8
 * License as published by the Free Software Foundation; either
 
9
 * version 2.1 of the License, or (at your option) any later version.
 
10
 * 
 
11
 * cairo-compmgr is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
 * Lesser General Public License for more details.
 
15
 * 
 
16
 * You should have received a copy of the GNU Lesser General Public
 
17
 * License along with cairo-compmgr.  If not, write to:
 
18
 *      The Free Software Foundation, Inc.,
 
19
 *      51 Franklin Street, Fifth Floor
 
20
 *      Boston, MA  02110-1301, USA.
 
21
 */
 
22
 
 
23
#include <glib.h>
 
24
#include <X11/Xlib.h>
 
25
#include <X11/extensions/Xdamage.h>
 
26
#include <X11/extensions/Xfixes.h>
 
27
#include <stdlib.h>
 
28
#include <cairo.h>
 
29
 
 
30
#include "ccm-debug.h"
 
31
#include "ccm-pixmap.h"
 
32
#include "ccm-pixmap-backend.h"
 
33
#include "ccm-window.h"
 
34
#include "ccm-screen.h"
 
35
#include "ccm-display.h"
 
36
#include "ccm-object.h"
 
37
 
 
38
CCM_DEFINE_TYPE (CCMPixmap, ccm_pixmap, CCM_TYPE_DRAWABLE);
 
39
 
 
40
enum
 
41
{
 
42
    PROP_0,
 
43
    PROP_Y_INVERT,
 
44
    PROP_FREEZE,
 
45
    PROP_FOREIGN,
 
46
};
 
47
 
 
48
struct _CCMPixmapPrivate
 
49
{
 
50
    gboolean foreign;
 
51
 
 
52
    Damage damage;
 
53
 
 
54
    gboolean y_invert;
 
55
    gboolean freeze;
 
56
 
 
57
    gulong id_damage;
 
58
};
 
59
 
 
60
#define CCM_PIXMAP_GET_PRIVATE(o)  \
 
61
(G_TYPE_INSTANCE_GET_PRIVATE ((o), CCM_TYPE_PIXMAP, CCMPixmapPrivate))
 
62
 
 
63
static void ccm_pixmap_bind (CCMPixmap * self);
 
64
static void ccm_pixmap_release (CCMPixmap * self);
 
65
static void ccm_pixmap_on_damage (CCMPixmap * self, Damage damage,
 
66
                                  CCMDisplay * display);
 
67
 
 
68
static void
 
69
ccm_pixmap_set_property (GObject * object, guint prop_id, const GValue * value,
 
70
                         GParamSpec * pspec)
 
71
{
 
72
    CCMPixmap *self = CCM_PIXMAP (object);
 
73
 
 
74
    switch (prop_id)
 
75
    {
 
76
        case PROP_Y_INVERT:
 
77
            {
 
78
                self->priv->y_invert = g_value_get_boolean (value);
 
79
            }
 
80
            break;
 
81
        case PROP_FREEZE:
 
82
            {
 
83
                self->priv->freeze = g_value_get_boolean (value);
 
84
            }
 
85
            break;
 
86
        case PROP_FOREIGN:
 
87
            {
 
88
                self->priv->foreign = g_value_get_boolean (value);
 
89
            }
 
90
        default:
 
91
            break;
 
92
    }
 
93
}
 
94
 
 
95
static void
 
96
ccm_pixmap_get_property (GObject * object, guint prop_id, GValue * value,
 
97
                         GParamSpec * pspec)
 
98
{
 
99
    CCMPixmap *self = CCM_PIXMAP (object);
 
100
 
 
101
    switch (prop_id)
 
102
    {
 
103
        case PROP_Y_INVERT:
 
104
            {
 
105
                g_value_set_boolean (value, self->priv->y_invert);
 
106
            }
 
107
            break;
 
108
        case PROP_FREEZE:
 
109
            {
 
110
                g_value_set_boolean (value, self->priv->freeze);
 
111
            }
 
112
            break;
 
113
        case PROP_FOREIGN:
 
114
            {
 
115
                g_value_set_boolean (value, self->priv->foreign);
 
116
            }
 
117
            break;
 
118
        default:
 
119
            break;
 
120
    }
 
121
}
 
122
 
 
123
static void
 
124
ccm_pixmap_init (CCMPixmap * self)
 
125
{
 
126
    self->priv = CCM_PIXMAP_GET_PRIVATE (self);
 
127
 
 
128
    self->priv->foreign = FALSE;
 
129
    self->priv->damage = 0;
 
130
    self->priv->y_invert = FALSE;
 
131
    self->priv->freeze = FALSE;
 
132
    self->priv->id_damage = 0;
 
133
}
 
134
 
 
135
static void
 
136
ccm_pixmap_finalize (GObject * object)
 
137
{
 
138
    CCMPixmap *self = CCM_PIXMAP (object);
 
139
    CCMDisplay *display = ccm_drawable_get_display (CCM_DRAWABLE (object));
 
140
 
 
141
    ccm_pixmap_release (self);
 
142
 
 
143
    if (CCM_IS_DISPLAY (display) && 
 
144
        G_OBJECT (display)->ref_count && 
 
145
        self->priv->damage)
 
146
    {
 
147
        XDamageDestroy (CCM_DISPLAY_XDISPLAY (display), self->priv->damage);
 
148
        g_signal_handler_disconnect (display, self->priv->id_damage);
 
149
        self->priv->damage = None;
 
150
    }
 
151
    self->priv->y_invert = FALSE;
 
152
    self->priv->freeze = FALSE;
 
153
 
 
154
    if (!self->priv->foreign)
 
155
        XFreePixmap (CCM_DISPLAY_XDISPLAY (display), CCM_PIXMAP_XPIXMAP (self));
 
156
 
 
157
    G_OBJECT_CLASS (ccm_pixmap_parent_class)->finalize (object);
 
158
}
 
159
 
 
160
static void
 
161
ccm_pixmap_class_init (CCMPixmapClass * klass)
 
162
{
 
163
    GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
164
 
 
165
    g_type_class_add_private (klass, sizeof (CCMPixmapPrivate));
 
166
 
 
167
    object_class->set_property = ccm_pixmap_set_property;
 
168
    object_class->get_property = ccm_pixmap_get_property;
 
169
 
 
170
    /**
 
171
     * CCMPixmap:y_invert:
 
172
     *
 
173
     * This property indicate if the pixmap paint is y inverted.
 
174
     */
 
175
    g_object_class_install_property (object_class, PROP_Y_INVERT,
 
176
                                     g_param_spec_boolean ("y_invert",
 
177
                                                           "Y Invert",
 
178
                                                           "Get if pixmap is y inverted",
 
179
                                                           FALSE,
 
180
                                                           G_PARAM_READABLE |
 
181
                                                           G_PARAM_WRITABLE));
 
182
 
 
183
    /**
 
184
     * CCMPixmap:freeze:
 
185
     *
 
186
     * This property locks paint and damage if is true.
 
187
     */
 
188
    g_object_class_install_property (object_class, PROP_FREEZE,
 
189
                                     g_param_spec_boolean ("freeze", "Freeze",
 
190
                                                           "Freeze pixmap damage and repair",
 
191
                                                           FALSE,
 
192
                                                           G_PARAM_READABLE |
 
193
                                                           G_PARAM_WRITABLE));
 
194
 
 
195
    /**
 
196
     * CCMPixmap:foreign:
 
197
     *
 
198
     * This property indicate the object doesn't owned XPixmap if true.
 
199
     */
 
200
    g_object_class_install_property (object_class, PROP_FOREIGN,
 
201
                                     g_param_spec_boolean ("foreign", "Foreign",
 
202
                                                           "Foreign pixmap",
 
203
                                                           FALSE,
 
204
                                                           G_PARAM_READABLE |
 
205
                                                           G_PARAM_WRITABLE));
 
206
 
 
207
    object_class->finalize = ccm_pixmap_finalize;
 
208
}
 
209
 
 
210
static void
 
211
ccm_pixmap_bind (CCMPixmap * self)
 
212
{
 
213
    g_return_if_fail (self != NULL);
 
214
 
 
215
    if (CCM_PIXMAP_GET_CLASS (self)->bind)
 
216
        CCM_PIXMAP_GET_CLASS (self)->bind (self);
 
217
}
 
218
 
 
219
static void
 
220
ccm_pixmap_release (CCMPixmap * self)
 
221
{
 
222
    g_return_if_fail (self != NULL);
 
223
 
 
224
    if (CCM_PIXMAP_GET_CLASS (self)->release)
 
225
        CCM_PIXMAP_GET_CLASS (self)->release (self);
 
226
}
 
227
 
 
228
static void
 
229
ccm_pixmap_on_damage (CCMPixmap * self, Damage damage, CCMDisplay * display)
 
230
{
 
231
    g_return_if_fail (self != NULL);
 
232
 
 
233
    if (!self->priv->freeze && self->priv->damage == damage)
 
234
    {
 
235
        CCMDisplay *display = ccm_drawable_get_display (CCM_DRAWABLE (self));
 
236
        XserverRegion region =
 
237
            XFixesCreateRegion (CCM_DISPLAY_XDISPLAY (display), NULL, 0);
 
238
 
 
239
        if (region)
 
240
        {
 
241
            XRectangle *rects;
 
242
            gint nb_rects, cpt;
 
243
 
 
244
            XDamageSubtract (CCM_DISPLAY_XDISPLAY (display), self->priv->damage,
 
245
                             None, region);
 
246
            rects = XFixesFetchRegion (CCM_DISPLAY_XDISPLAY (display), region,
 
247
                                       &nb_rects);
 
248
            if (rects)
 
249
            {
 
250
                CCMRegion *damaged = ccm_region_new ();
 
251
 
 
252
                for (cpt = 0; cpt < nb_rects; ++cpt)
 
253
                {
 
254
                    ccm_region_union_with_xrect (damaged, &rects[cpt]);
 
255
                    ccm_debug ("PIXMAP DAMAGE %i,%i,%i,%i", rects[cpt].x,
 
256
                               rects[cpt].y, rects[cpt].width,
 
257
                               rects[cpt].height);
 
258
                }
 
259
                XFree (rects);
 
260
 
 
261
                ccm_drawable_damage_region (CCM_DRAWABLE (self), damaged);
 
262
                ccm_drawable_repair(CCM_DRAWABLE (self));
 
263
                ccm_region_destroy (damaged);
 
264
            }
 
265
            XFixesDestroyRegion (CCM_DISPLAY_XDISPLAY (display), region);
 
266
        }
 
267
    }
 
268
}
 
269
 
 
270
static void
 
271
ccm_pixmap_register_damage (CCMPixmap * self)
 
272
{
 
273
    g_return_if_fail (self != NULL);
 
274
 
 
275
    CCMDisplay *display = ccm_drawable_get_display (CCM_DRAWABLE (self));
 
276
 
 
277
    self->priv->damage = XDamageCreate (CCM_DISPLAY_XDISPLAY (display),
 
278
                                        CCM_PIXMAP_XPIXMAP (self), 
 
279
                                        XDamageReportNonEmpty);
 
280
    if (self->priv->damage)
 
281
    {
 
282
        XDamageSubtract (CCM_DISPLAY_XDISPLAY (display), self->priv->damage,
 
283
                         None, None);
 
284
 
 
285
        self->priv->id_damage =
 
286
            g_signal_connect_swapped (display, "damage-event",
 
287
                                      G_CALLBACK (ccm_pixmap_on_damage), self);
 
288
    }
 
289
    else
 
290
        self->priv->damage = None;
 
291
}
 
292
 
 
293
/**
 
294
 * ccm_pixmap_new:
 
295
 * @drawable: #CCMDrawable
 
296
 * @xpixmap: pixmap
 
297
 *
 
298
 * Create a new pixmap
 
299
 *
 
300
 * Returns: #CCMPixmap
 
301
 **/
 
302
CCMPixmap *
 
303
ccm_pixmap_new (CCMDrawable * drawable, Pixmap xpixmap)
 
304
{
 
305
    g_return_val_if_fail (drawable != NULL, NULL);
 
306
    g_return_val_if_fail (xpixmap != None, NULL);
 
307
 
 
308
    CCMScreen *screen = ccm_drawable_get_screen (drawable);
 
309
    Visual *visual = ccm_drawable_get_visual (drawable);
 
310
    CCMPixmap *self;
 
311
 
 
312
    g_return_val_if_fail (screen != NULL && visual != None, NULL);
 
313
 
 
314
    self = g_object_new (ccm_pixmap_backend_get_type (screen), 
 
315
                         "screen", screen,
 
316
                         "drawable", xpixmap, 
 
317
                         "visual", visual, NULL);
 
318
 
 
319
    ccm_drawable_query_geometry (CCM_DRAWABLE (self));
 
320
    if (!ccm_drawable_get_device_geometry (CCM_DRAWABLE (self)))
 
321
    {
 
322
        g_object_unref (self);
 
323
        return NULL;
 
324
    }
 
325
    ccm_pixmap_register_damage (self);
 
326
    if (!self->priv->damage)
 
327
    {
 
328
        g_object_unref (self);
 
329
        return NULL;
 
330
    }
 
331
    ccm_pixmap_bind (self);
 
332
    ccm_drawable_damage (CCM_DRAWABLE (self));
 
333
 
 
334
    return self;
 
335
}
 
336
 
 
337
/**
 
338
 * ccm_pixmap_new_from_visual:
 
339
 * @screen: #CCMScreen
 
340
 * @visual: XVisual
 
341
 * @xpixmap: pixmap
 
342
 *
 
343
 * Create a new pixmap for a screen visual
 
344
 *
 
345
 * Returns: #CCMPixmap
 
346
 **/
 
347
CCMPixmap *
 
348
ccm_pixmap_new_from_visual (CCMScreen * screen, Visual * visual, Pixmap xpixmap)
 
349
{
 
350
    g_return_val_if_fail (screen != NULL, NULL);
 
351
    g_return_val_if_fail (visual != NULL, NULL);
 
352
    g_return_val_if_fail (xpixmap != None, NULL);
 
353
 
 
354
    CCMPixmap *self;
 
355
 
 
356
    self = g_object_new (ccm_pixmap_backend_get_type (screen), 
 
357
                         "screen", screen,
 
358
                         "drawable", xpixmap,
 
359
                         "visual", visual, NULL);
 
360
 
 
361
    ccm_drawable_query_geometry (CCM_DRAWABLE (self));
 
362
    if (!ccm_drawable_get_device_geometry (CCM_DRAWABLE (self)))
 
363
    {
 
364
        g_object_unref (self);
 
365
        return NULL;
 
366
    }
 
367
    ccm_pixmap_register_damage (self);
 
368
    if (!self->priv->damage)
 
369
    {
 
370
        g_object_unref (self);
 
371
        return NULL;
 
372
    }
 
373
    ccm_pixmap_bind (self);
 
374
    ccm_drawable_damage (CCM_DRAWABLE (self));
 
375
 
 
376
    return self;
 
377
}
 
378
 
 
379
/**
 
380
 * ccm_pixmap_image_new:
 
381
 * @drawable: #CCMDrawable
 
382
 * @xpixmap: pixmap
 
383
 *
 
384
 * Create a new pixmap which software rendering backend
 
385
 *
 
386
 * Returns: #CCMPixmap
 
387
 **/
 
388
CCMPixmap *
 
389
ccm_pixmap_image_new (CCMDrawable * drawable, Pixmap xpixmap)
 
390
{
 
391
    g_return_val_if_fail (drawable != NULL, NULL);
 
392
    g_return_val_if_fail (xpixmap != None, NULL);
 
393
 
 
394
    CCMScreen *screen = ccm_drawable_get_screen (drawable);
 
395
    Visual *visual = ccm_drawable_get_visual (drawable);
 
396
    CCMPixmap *self;
 
397
 
 
398
    g_return_val_if_fail (screen != NULL && visual != None, NULL);
 
399
 
 
400
    self = g_object_new (ccm_pixmap_image_get_type (), 
 
401
                         "screen", screen,
 
402
                         "drawable", xpixmap, 
 
403
                         "visual", visual, NULL);
 
404
 
 
405
    ccm_drawable_query_geometry (CCM_DRAWABLE (self));
 
406
    ccm_pixmap_register_damage (self);
 
407
    if (!self->priv->damage)
 
408
    {
 
409
        g_object_unref (self);
 
410
        return NULL;
 
411
    }
 
412
    ccm_pixmap_bind (self);
 
413
    ccm_drawable_damage (CCM_DRAWABLE (self));
 
414
 
 
415
    return self;
 
416
}
 
417
 
 
418
gboolean
 
419
ccm_pixmap_get_y_invert (CCMPixmap * self)
 
420
{
 
421
    g_return_val_if_fail (self != NULL, FALSE);
 
422
 
 
423
    return self->priv->y_invert;
 
424
}
 
425
 
 
426
void
 
427
ccm_pixmap_set_y_invert (CCMPixmap * self, gboolean y_invert)
 
428
{
 
429
    g_return_if_fail (self != NULL);
 
430
 
 
431
    self->priv->y_invert = y_invert;
 
432
 
 
433
    g_object_notify (G_OBJECT (self), "y_invert");
 
434
}
 
435
 
 
436
gboolean
 
437
ccm_pixmap_get_foreign (CCMPixmap * self)
 
438
{
 
439
    g_return_val_if_fail (self != NULL, FALSE);
 
440
 
 
441
    return self->priv->foreign;
 
442
}
 
443
 
 
444
void
 
445
ccm_pixmap_set_foreign (CCMPixmap * self, gboolean foreign)
 
446
{
 
447
    g_return_if_fail (self != NULL);
 
448
 
 
449
    self->priv->foreign = foreign;
 
450
 
 
451
    g_object_notify (G_OBJECT (self), "foreign");
 
452
}
 
453
 
 
454
gboolean
 
455
ccm_pixmap_get_freeze (CCMPixmap * self)
 
456
{
 
457
    g_return_val_if_fail (self != NULL, FALSE);
 
458
 
 
459
    return self->priv->freeze;
 
460
}
 
461
 
 
462
void
 
463
ccm_pixmap_set_freeze (CCMPixmap * self, gboolean freeze)
 
464
{
 
465
    g_return_if_fail (self != NULL);
 
466
 
 
467
    self->priv->freeze = freeze;
 
468
 
 
469
    g_object_notify (G_OBJECT (self), "freeze");
 
470
}