~shnatsel/+junk/cairo-compmgr

« back to all changes in this revision

Viewing changes to src/ccm-display.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 software; you can redistribute 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 <string.h>
 
24
#include <X11/Xresource.h>
 
25
#include <X11/extensions/Xcomposite.h>
 
26
#include <X11/extensions/Xdamage.h>
 
27
#include <X11/extensions/XShm.h>
 
28
#include <X11/extensions/Xfixes.h>
 
29
#include <X11/extensions/Xdbe.h>
 
30
#include <X11/extensions/XInput.h>
 
31
#include <X11/extensions/shape.h>
 
32
#include <gtk/gtk.h>
 
33
 
 
34
#include "ccm-debug.h"
 
35
#include "ccm-display.h"
 
36
#include "ccm-cursor.h"
 
37
#include "ccm-screen.h"
 
38
#include "ccm-watch.h"
 
39
#include "ccm-config.h"
 
40
#include "ccm-window.h"
 
41
 
 
42
G_DEFINE_TYPE (CCMDisplay, ccm_display, G_TYPE_OBJECT);
 
43
 
 
44
enum
 
45
{
 
46
    PROP_0,
 
47
    PROP_XDISPLAY,
 
48
    PROP_USE_XSHM,
 
49
    PROP_USE_XDBE,
 
50
    PROP_SHM_SHARED_PIXMAP
 
51
};
 
52
 
 
53
enum
 
54
{
 
55
    CCM_DISPLAY_OPTION_USE_XSHM,
 
56
    CCM_DISPLAY_OPTION_USE_XDBE,
 
57
    CCM_DISPLAY_UNMANAGED_SCREEN,
 
58
    CCM_DISPLAY_OPTION_N
 
59
};
 
60
 
 
61
static gchar *CCMDisplayOptions[CCM_DISPLAY_OPTION_N] = {
 
62
    "use_xshm",
 
63
    "use_xdbe",
 
64
    "unmanaged_screen"
 
65
};
 
66
 
 
67
enum
 
68
{
 
69
    EVENT,
 
70
    DAMAGE_EVENT,
 
71
    CURSOR_CHANGED,
 
72
    N_SIGNALS
 
73
};
 
74
 
 
75
static guint signals[N_SIGNALS] = { 0 };
 
76
 
 
77
typedef struct
 
78
{
 
79
    gboolean available;
 
80
    int event_base;
 
81
    int error_base;
 
82
} CCMExtension;
 
83
 
 
84
typedef struct
 
85
{
 
86
    gulong press;
 
87
    gulong release;
 
88
    gulong motion;
 
89
} CCMPointerEvents;
 
90
 
 
91
struct _CCMDisplayPrivate
 
92
{
 
93
    Display *xdisplay;
 
94
 
 
95
    gint nb_screens;
 
96
    CCMScreen **screens;
 
97
 
 
98
    CCMExtension shape;
 
99
    CCMExtension composite;
 
100
    CCMExtension damage;
 
101
    CCMExtension shm;
 
102
    gboolean shm_shared_pixmap;
 
103
    CCMExtension dbe;
 
104
    CCMExtension fixes;
 
105
    CCMExtension input;
 
106
 
 
107
    GSList *pointers;
 
108
    int type_button_press;
 
109
    int type_button_release;
 
110
    int type_motion_notify;
 
111
    CCMPointerEvents last_events;
 
112
 
 
113
    gchar *cursors_theme;
 
114
    gint cursors_size;
 
115
    CCMCursor *cursor_current;
 
116
    GHashTable *cursors;
 
117
 
 
118
    gboolean use_shm;
 
119
    gboolean use_dbe;
 
120
 
 
121
    gint fd;
 
122
    CCMConfig *options[CCM_DISPLAY_OPTION_N];
 
123
};
 
124
 
 
125
static gint CCMLastXError = 0;
 
126
static CCMDisplay* CCMDefaultDisplay = NULL;
 
127
 
 
128
#define CCM_DISPLAY_GET_PRIVATE(o)  \
 
129
(G_TYPE_INSTANCE_GET_PRIVATE ((o), CCM_TYPE_DISPLAY, CCMDisplayPrivate))
 
130
 
 
131
static void
 
132
ccm_display_set_property (GObject * object, guint prop_id, const GValue * value,
 
133
                          GParamSpec * pspec)
 
134
{
 
135
    CCMDisplayPrivate *priv = CCM_DISPLAY_GET_PRIVATE (object);
 
136
 
 
137
    switch (prop_id)
 
138
    {
 
139
        case PROP_XDISPLAY:
 
140
        {
 
141
            priv->xdisplay = g_value_get_pointer (value);
 
142
        }
 
143
            break;
 
144
        default:
 
145
            break;
 
146
    }
 
147
}
 
148
 
 
149
static void
 
150
ccm_display_get_property (GObject * object, guint prop_id, GValue * value,
 
151
                          GParamSpec * pspec)
 
152
{
 
153
    CCMDisplayPrivate *priv = CCM_DISPLAY_GET_PRIVATE (object);
 
154
 
 
155
    switch (prop_id)
 
156
    {
 
157
        case PROP_XDISPLAY:
 
158
        {
 
159
            g_value_set_pointer (value, priv->xdisplay);
 
160
        }
 
161
            break;
 
162
        case PROP_USE_XSHM:
 
163
        {
 
164
            g_value_set_boolean (value, priv->use_shm);
 
165
        }
 
166
            break;
 
167
        case PROP_USE_XDBE:
 
168
        {
 
169
            g_value_set_boolean (value, priv->use_dbe);
 
170
        }
 
171
            break;
 
172
        case PROP_SHM_SHARED_PIXMAP:
 
173
        {
 
174
            GError *error = NULL;
 
175
            gboolean xshm =
 
176
                ccm_config_get_boolean (priv->options[CCM_DISPLAY_OPTION_USE_XSHM],
 
177
                                        &error);
 
178
 
 
179
            if (error)
 
180
            {
 
181
                g_warning ("Error on get xshm configuration value");
 
182
                g_error_free (error);
 
183
                xshm = FALSE;
 
184
            }
 
185
            g_value_set_boolean (value, xshm && priv->shm.available && priv->shm_shared_pixmap);
 
186
        }
 
187
            break;
 
188
        default:
 
189
            break;
 
190
    }
 
191
}
 
192
 
 
193
static void
 
194
ccm_display_init (CCMDisplay * self)
 
195
{
 
196
    self->priv = CCM_DISPLAY_GET_PRIVATE (self);
 
197
 
 
198
    self->priv->xdisplay = NULL;
 
199
    self->priv->nb_screens = 0;
 
200
    self->priv->fd = 0;
 
201
    self->priv->screens = NULL;
 
202
    self->priv->shm_shared_pixmap = FALSE;
 
203
    self->priv->use_shm = FALSE;
 
204
    self->priv->use_dbe = FALSE;
 
205
    self->priv->pointers = NULL;
 
206
    self->priv->type_button_press = 0;
 
207
    self->priv->type_button_release = 0;
 
208
    self->priv->type_motion_notify = 0;
 
209
    self->priv->last_events.press = 0;
 
210
    self->priv->last_events.release = 0;
 
211
    self->priv->last_events.motion = 0;
 
212
    self->priv->cursors = g_hash_table_new_full (g_int_hash, g_int_equal, 
 
213
                                                 g_free, g_object_unref);
 
214
    self->priv->cursor_current = NULL;
 
215
}
 
216
 
 
217
static void
 
218
ccm_display_finalize (GObject * object)
 
219
{
 
220
    CCMDisplay *self = CCM_DISPLAY (object);
 
221
    gint cpt;
 
222
 
 
223
    ccm_debug ("DISPLAY FINALIZE");
 
224
 
 
225
    if (self == CCMDefaultDisplay)
 
226
        CCMDefaultDisplay = NULL;
 
227
 
 
228
    if (self->priv->cursors)
 
229
        g_hash_table_destroy (self->priv->cursors);
 
230
 
 
231
    if (self->priv->pointers)
 
232
    {
 
233
        GSList *item;
 
234
 
 
235
        for (item = self->priv->pointers; item; item = item->next)
 
236
            XCloseDevice (self->priv->xdisplay, item->data);
 
237
        g_slist_free (self->priv->pointers);
 
238
    }
 
239
 
 
240
    if (self->priv->nb_screens)
 
241
    {
 
242
        for (cpt = 0; cpt < self->priv->nb_screens; ++cpt)
 
243
        {
 
244
            if (self->priv->screens[cpt] && CCM_IS_SCREEN (self->priv->screens[cpt]))
 
245
            {
 
246
                g_object_unref (self->priv->screens[cpt]);
 
247
                self->priv->screens[cpt] = NULL;
 
248
            }
 
249
        }
 
250
        self->priv->nb_screens = 0;
 
251
 
 
252
        g_slice_free1 (sizeof (CCMScreen *) * (self->priv->nb_screens + 1),
 
253
                       self->priv->screens);
 
254
    }
 
255
 
 
256
    for (cpt = 0; cpt < CCM_DISPLAY_OPTION_N; ++cpt)
 
257
        g_object_unref (self->priv->options[cpt]);
 
258
 
 
259
    if (self->priv->fd)
 
260
        fd_remove_watch (self->priv->fd);
 
261
 
 
262
    G_OBJECT_CLASS (ccm_display_parent_class)->finalize (object);
 
263
}
 
264
 
 
265
static void
 
266
ccm_display_class_init (CCMDisplayClass * klass)
 
267
{
 
268
    GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
269
 
 
270
    g_type_class_add_private (klass, sizeof (CCMDisplayPrivate));
 
271
 
 
272
    object_class->get_property = ccm_display_get_property;
 
273
    object_class->set_property = ccm_display_set_property;
 
274
    object_class->finalize = ccm_display_finalize;
 
275
 
 
276
    g_object_class_install_property (object_class, PROP_XDISPLAY,
 
277
                                     g_param_spec_pointer ("xdisplay",
 
278
                                                           "XDisplay",
 
279
                                                           "Display xid",
 
280
                                                           G_PARAM_READWRITE |
 
281
                                                           G_PARAM_CONSTRUCT_ONLY));
 
282
 
 
283
    g_object_class_install_property (object_class, PROP_USE_XSHM,
 
284
                                     g_param_spec_boolean ("use_xshm",
 
285
                                                           "UseXShm",
 
286
                                                           "Use XSHM", TRUE,
 
287
                                                           G_PARAM_READWRITE));
 
288
 
 
289
    g_object_class_install_property (object_class, PROP_SHM_SHARED_PIXMAP,
 
290
                                     g_param_spec_boolean ("shm_shared_pixmap",
 
291
                                                           "ShmSharedPixmap",
 
292
                                                           "SHM Shared Pixmap",
 
293
                                                           TRUE,
 
294
                                                           G_PARAM_READWRITE));
 
295
 
 
296
    g_object_class_install_property (object_class, PROP_USE_XDBE,
 
297
                                     g_param_spec_boolean ("use_xdbe",
 
298
                                                           "UseXdbe",
 
299
                                                           "Use Double Buffer Extension",
 
300
                                                           TRUE,
 
301
                                                           G_PARAM_READABLE));
 
302
 
 
303
    signals[EVENT] =
 
304
        g_signal_new ("event", G_OBJECT_CLASS_TYPE (object_class),
 
305
                      G_SIGNAL_RUN_LAST, 0, NULL, NULL,
 
306
                      g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
 
307
                      G_TYPE_POINTER);
 
308
 
 
309
    signals[DAMAGE_EVENT] =
 
310
        g_signal_new ("damage-event", G_OBJECT_CLASS_TYPE (object_class),
 
311
                      G_SIGNAL_RUN_LAST, 0, NULL, NULL,
 
312
                      g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
 
313
                      G_TYPE_POINTER);
 
314
 
 
315
    signals[CURSOR_CHANGED] =
 
316
        g_signal_new ("cursor-changed", G_OBJECT_CLASS_TYPE (object_class),
 
317
                      G_SIGNAL_RUN_LAST, 0, NULL, NULL,
 
318
                      g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
 
319
                      G_TYPE_POINTER);
 
320
}
 
321
 
 
322
static void
 
323
ccm_display_load_config (CCMDisplay * self)
 
324
{
 
325
    g_return_if_fail (self != NULL);
 
326
 
 
327
    gint cpt;
 
328
 
 
329
    for (cpt = 0; cpt < CCM_DISPLAY_OPTION_N; ++cpt)
 
330
    {
 
331
        self->priv->options[cpt] = ccm_config_new (-1, NULL, CCMDisplayOptions[cpt]);
 
332
    }
 
333
    self->priv->use_shm = ccm_config_get_boolean (self->priv->options[CCM_DISPLAY_OPTION_USE_XSHM], NULL) && 
 
334
                                                  self->priv->shm.available;
 
335
    self->priv->use_dbe = ccm_config_get_boolean (self->priv->options[CCM_DISPLAY_OPTION_USE_XDBE], NULL) &&
 
336
                                                  self->priv->dbe.available;
 
337
}
 
338
 
 
339
static void
 
340
ccm_display_check_cursor (CCMDisplay * self, Atom cursor_name,
 
341
                          gboolean emit_event)
 
342
{
 
343
    g_return_if_fail (self != NULL);
 
344
 
 
345
    CCMCursor *current = NULL;
 
346
 
 
347
    if (cursor_name)
 
348
    {
 
349
        current = g_hash_table_lookup (self->priv->cursors, &cursor_name);
 
350
 
 
351
        if (!current)
 
352
        {
 
353
            XFixesCursorImage *cursor;
 
354
 
 
355
            cursor = XFixesGetCursorImage (CCM_DISPLAY_XDISPLAY (self));
 
356
            ccm_debug ("CHECK CURSOR %li", cursor_name);
 
357
 
 
358
            current = ccm_cursor_new (self, cursor);
 
359
            XFree (cursor);
 
360
            if (current)
 
361
                g_hash_table_insert (self->priv->cursors,
 
362
                                     g_memdup (&cursor_name, sizeof (gulong)),
 
363
                                     current);
 
364
        }
 
365
    }
 
366
    else
 
367
    {
 
368
        XFixesCursorImage *cursor;
 
369
 
 
370
        cursor = XFixesGetCursorImage (CCM_DISPLAY_XDISPLAY (self));
 
371
 
 
372
        current = ccm_cursor_new (self, cursor);
 
373
 
 
374
        XFree (cursor);
 
375
    }
 
376
 
 
377
    if (self->priv->cursor_current != current)
 
378
    {
 
379
        gboolean animated = FALSE;
 
380
 
 
381
        if (self->priv->cursor_current)
 
382
        {
 
383
            g_object_get (self->priv->cursor_current, "animated", &animated, NULL);
 
384
            if (animated)
 
385
                g_object_unref (self->priv->cursor_current);
 
386
        }
 
387
        self->priv->cursor_current = current;
 
388
        if (emit_event)
 
389
            g_signal_emit (self, signals[CURSOR_CHANGED], 0, self->priv->cursor_current);
 
390
    }
 
391
 
 
392
}
 
393
 
 
394
static void
 
395
ccm_display_get_pointers (CCMDisplay * self)
 
396
{
 
397
    g_return_if_fail (self != NULL);
 
398
 
 
399
    XDeviceInfo *info;
 
400
    gint ndevices, cpt;
 
401
 
 
402
    info = XListInputDevices (self->priv->xdisplay, &ndevices);
 
403
    for (cpt = 0; cpt < ndevices; ++cpt)
 
404
    {
 
405
        XDeviceInfo *current = &info[cpt];
 
406
        if (current->use == IsXExtensionPointer)
 
407
        {
 
408
            XDevice *device = XOpenDevice (self->priv->xdisplay, current->id);
 
409
            ccm_debug ("Found device: %s (%d)", current->name, current->id);
 
410
            self->priv->pointers = g_slist_prepend (self->priv->pointers, device);
 
411
        }
 
412
    }
 
413
    XFree (info);
 
414
}
 
415
 
 
416
static gboolean
 
417
ccm_display_init_shape (CCMDisplay * self)
 
418
{
 
419
    g_return_val_if_fail (self != NULL, FALSE);
 
420
 
 
421
    if (XShapeQueryExtension (self->priv->xdisplay, 
 
422
                              &self->priv->shape.event_base,
 
423
                              &self->priv->shape.error_base))
 
424
    {
 
425
        self->priv->shape.available = TRUE;
 
426
        ccm_debug ("SHAPE ERROR BASE: %i", self->priv->shape.error_base);
 
427
        return TRUE;
 
428
    }
 
429
 
 
430
    return FALSE;
 
431
}
 
432
 
 
433
static gboolean
 
434
ccm_display_init_composite (CCMDisplay * self)
 
435
{
 
436
    g_return_val_if_fail (self != NULL, FALSE);
 
437
 
 
438
    if (XCompositeQueryExtension (self->priv->xdisplay, 
 
439
                                  &self->priv->composite.event_base,
 
440
                                  &self->priv->composite.error_base))
 
441
    {
 
442
        self->priv->composite.available = TRUE;
 
443
        ccm_debug ("COMPOSITE ERROR BASE: %i",
 
444
                   self->priv->composite.error_base);
 
445
        return TRUE;
 
446
    }
 
447
 
 
448
    return FALSE;
 
449
}
 
450
 
 
451
static gboolean
 
452
ccm_display_init_damage (CCMDisplay * self)
 
453
{
 
454
    g_return_val_if_fail (self != NULL, FALSE);
 
455
 
 
456
    if (XDamageQueryExtension (self->priv->xdisplay, 
 
457
                               &self->priv->damage.event_base,
 
458
                               &self->priv->damage.error_base))
 
459
    {
 
460
        self->priv->damage.available = TRUE;
 
461
        ccm_debug ("DAMAGE ERROR BASE: %i", self->priv->damage.error_base);
 
462
        return TRUE;
 
463
    }
 
464
 
 
465
    return FALSE;
 
466
}
 
467
 
 
468
static gboolean
 
469
ccm_display_init_shm (CCMDisplay * self)
 
470
{
 
471
    g_return_val_if_fail (self != NULL, FALSE);
 
472
    int major, minor;
 
473
 
 
474
    if (XShmQueryExtension (self->priv->xdisplay) &&
 
475
        XShmQueryVersion (self->priv->xdisplay, &major, &minor,
 
476
                          &self->priv->shm_shared_pixmap))
 
477
    {
 
478
        self->priv->shm.available = TRUE;
 
479
        return TRUE;
 
480
    }
 
481
 
 
482
    return FALSE;
 
483
}
 
484
 
 
485
static gboolean
 
486
ccm_display_init_dbe(CCMDisplay *self)
 
487
{
 
488
    g_return_val_if_fail(self != NULL, FALSE);
 
489
 
 
490
    int major, minor;
 
491
 
 
492
    if (XdbeQueryExtension (self->priv->xdisplay, &major, &minor))
 
493
    {
 
494
        self->priv->dbe.available = TRUE;
 
495
        return TRUE;
 
496
    }
 
497
 
 
498
    return FALSE;
 
499
}
 
500
 
 
501
static gboolean
 
502
ccm_display_init_xfixes (CCMDisplay * self)
 
503
{
 
504
    g_return_val_if_fail (self != NULL, FALSE);
 
505
 
 
506
    if (XFixesQueryExtension (self->priv->xdisplay, 
 
507
                              &self->priv->fixes.event_base,
 
508
                              &self->priv->fixes.error_base))
 
509
    {
 
510
        self->priv->fixes.available = TRUE;
 
511
        ccm_debug ("FIXES ERROR BASE: %i", self->priv->fixes.error_base);
 
512
        return TRUE;
 
513
    }
 
514
 
 
515
    return FALSE;
 
516
}
 
517
 
 
518
static gboolean
 
519
ccm_display_init_input (CCMDisplay * self)
 
520
{
 
521
    g_return_val_if_fail (self != NULL, FALSE);
 
522
 
 
523
    XExtensionVersion *version;
 
524
 
 
525
#ifdef HAVE_XI2
 
526
    version = XQueryInputVersion (self->priv->xdisplay, XI_2_Major, XI_2_Minor);
 
527
#else
 
528
    version = XGetExtensionVersion (self->priv->xdisplay, INAME);
 
529
#endif
 
530
 
 
531
    if (version && (version != (XExtensionVersion *) NoSuchExtension))
 
532
    {
 
533
        self->priv->input.available = TRUE;
 
534
        XFree (version);
 
535
        return TRUE;
 
536
    }
 
537
 
 
538
    return FALSE;
 
539
}
 
540
 
 
541
static int
 
542
ccm_display_error_handler (Display * dpy, XErrorEvent * evt)
 
543
{
 
544
    gchar str[128];
 
545
 
 
546
    XGetErrorText (dpy, evt->error_code, str, 128);
 
547
    ccm_debug ("ERROR: Xerror: %s", str);
 
548
 
 
549
    sprintf (str, "%d", evt->request_code);
 
550
    XGetErrorDatabaseText (dpy, "XRequest", str, "", str, 128);
 
551
    if (strcmp (str, ""))
 
552
        ccm_debug ("ERROR: XRequest: (%s)", str);
 
553
 
 
554
    CCMLastXError = evt->error_code;
 
555
 
 
556
    ccm_debug_backtrace ();
 
557
 
 
558
    return 0;
 
559
}
 
560
 
 
561
static void
 
562
ccm_display_process_events (CCMDisplay * self)
 
563
{
 
564
    g_return_if_fail (self != NULL);
 
565
 
 
566
    XEvent xevent;
 
567
 
 
568
    while (XEventsQueued (CCM_DISPLAY_XDISPLAY (self), QueuedAfterReading))
 
569
    {
 
570
        XNextEvent (CCM_DISPLAY_XDISPLAY (self), &xevent);
 
571
 
 
572
        if (xevent.type == self->priv->damage.event_base + XDamageNotify)
 
573
        {
 
574
            XDamageNotifyEvent *event_damage = (XDamageNotifyEvent *) & xevent;
 
575
 
 
576
            g_signal_emit (self, signals[DAMAGE_EVENT], 0,
 
577
                           event_damage->damage);
 
578
        }
 
579
        else if (xevent.type ==
 
580
                 self->priv->fixes.event_base + XFixesCursorNotify)
 
581
        {
 
582
            XFixesCursorNotifyEvent *event_cursor = (XFixesCursorNotifyEvent *) &xevent;
 
583
 
 
584
            ccm_debug ("CURSOR NOTIFY %li", event_cursor->cursor_name);
 
585
            ccm_display_check_cursor (self, event_cursor->cursor_name, TRUE);
 
586
        }
 
587
        else
 
588
        {
 
589
            gboolean proceed = FALSE;
 
590
 
 
591
            // Check if event is not already proceed by device events
 
592
            if (xevent.type == self->priv->type_button_press)
 
593
            {
 
594
                XDeviceButtonEvent *button_event =
 
595
                    (XDeviceButtonEvent *) g_memdup (&xevent, sizeof (XEvent));
 
596
 
 
597
                proceed = self->priv->last_events.press == xevent.xany.serial;
 
598
                self->priv->last_events.press = xevent.xany.serial;
 
599
 
 
600
                xevent.xany.type = ButtonPress;
 
601
                xevent.xany.serial = button_event->serial;
 
602
                xevent.xany.send_event = button_event->send_event;
 
603
                xevent.xany.display = button_event->display;
 
604
                xevent.xany.window = button_event->window;
 
605
                xevent.xbutton.root = button_event->root;
 
606
                xevent.xbutton.subwindow = button_event->subwindow;
 
607
                xevent.xbutton.time = button_event->time;
 
608
                xevent.xbutton.x = button_event->x;
 
609
                xevent.xbutton.y = button_event->y;
 
610
                xevent.xbutton.x_root = button_event->x_root;
 
611
                xevent.xbutton.y_root = button_event->y_root;
 
612
                xevent.xbutton.state = button_event->state;
 
613
                xevent.xbutton.button = button_event->button;
 
614
                xevent.xbutton.same_screen = button_event->same_screen;
 
615
 
 
616
                g_free (button_event);
 
617
            }
 
618
            else if (xevent.type == self->priv->type_button_release)
 
619
            {
 
620
                XDeviceButtonEvent *button_event =
 
621
                    (XDeviceButtonEvent *) g_memdup (&xevent, sizeof (XEvent));
 
622
 
 
623
                proceed = self->priv->last_events.release == xevent.xany.serial;
 
624
                self->priv->last_events.release = xevent.xany.serial;
 
625
 
 
626
                xevent.xany.type = ButtonRelease;
 
627
                xevent.xany.serial = button_event->serial;
 
628
                xevent.xany.send_event = button_event->send_event;
 
629
                xevent.xany.display = button_event->display;
 
630
                xevent.xany.window = button_event->window;
 
631
                xevent.xbutton.root = button_event->root;
 
632
                xevent.xbutton.subwindow = button_event->subwindow;
 
633
                xevent.xbutton.time = button_event->time;
 
634
                xevent.xbutton.x = button_event->x;
 
635
                xevent.xbutton.y = button_event->y;
 
636
                xevent.xbutton.x_root = button_event->x_root;
 
637
                xevent.xbutton.y_root = button_event->y_root;
 
638
                xevent.xbutton.state = button_event->state;
 
639
                xevent.xbutton.button = button_event->button;
 
640
                xevent.xbutton.same_screen = button_event->same_screen;
 
641
 
 
642
                g_free (button_event);
 
643
            }
 
644
            else if (xevent.type == self->priv->type_motion_notify)
 
645
            {
 
646
                XDeviceMotionEvent *motion_event =
 
647
                    (XDeviceMotionEvent *) g_memdup (&xevent, sizeof (XEvent));
 
648
 
 
649
                proceed = self->priv->last_events.motion == xevent.xany.serial;
 
650
                self->priv->last_events.motion = xevent.xany.serial;
 
651
 
 
652
                xevent.xany.type = MotionNotify;
 
653
                xevent.xany.serial = motion_event->serial;
 
654
                xevent.xany.send_event = motion_event->send_event;
 
655
                xevent.xany.display = motion_event->display;
 
656
                xevent.xany.window = motion_event->window;
 
657
                xevent.xmotion.root = motion_event->root;
 
658
                xevent.xmotion.subwindow = motion_event->subwindow;
 
659
                xevent.xmotion.time = motion_event->time;
 
660
                xevent.xmotion.x = motion_event->x;
 
661
                xevent.xmotion.y = motion_event->y;
 
662
                xevent.xmotion.x_root = motion_event->x_root;
 
663
                xevent.xmotion.y_root = motion_event->y_root;
 
664
                xevent.xmotion.state = motion_event->state;
 
665
                xevent.xmotion.is_hint = motion_event->is_hint;
 
666
                xevent.xmotion.same_screen = motion_event->same_screen;
 
667
 
 
668
                g_free (motion_event);
 
669
            }
 
670
            else if (xevent.type == ButtonPress)
 
671
            {
 
672
                proceed = self->priv->last_events.press == xevent.xany.serial;
 
673
                self->priv->last_events.press = xevent.xany.serial;
 
674
            }
 
675
            else if (xevent.type == ButtonRelease)
 
676
            {
 
677
                proceed = self->priv->last_events.release == xevent.xany.serial;
 
678
                self->priv->last_events.release = xevent.xany.serial;
 
679
            }
 
680
            else if (xevent.type == MotionNotify)
 
681
            {
 
682
                proceed = self->priv->last_events.motion == xevent.xany.serial;
 
683
                self->priv->last_events.motion = xevent.xany.serial;
 
684
            }
 
685
 
 
686
            if (!proceed)
 
687
                g_signal_emit (self, signals[EVENT], 0, &xevent);
 
688
        }
 
689
    }
 
690
}
 
691
 
 
692
CCMDisplay *
 
693
ccm_display_new (gchar * display)
 
694
{
 
695
    CCMDisplay *self;
 
696
    gint cpt;
 
697
    GSList *unmanaged = NULL;
 
698
    Display *xdisplay;
 
699
 
 
700
    xdisplay = XOpenDisplay (display);
 
701
    if (!xdisplay)
 
702
    {
 
703
        g_warning ("Unable to open display %s", display);
 
704
        return NULL;
 
705
    }
 
706
 
 
707
    self = g_object_new (CCM_TYPE_DISPLAY, "xdisplay", xdisplay, NULL);
 
708
 
 
709
    ccm_display_init_dbe(self);
 
710
 
 
711
    if (!ccm_display_init_shape (self))
 
712
    {
 
713
        g_object_unref (self);
 
714
        g_warning ("Shape init failed for %s", display);
 
715
        return NULL;
 
716
    }
 
717
 
 
718
    if (!ccm_display_init_composite (self))
 
719
    {
 
720
        g_object_unref (self);
 
721
        g_warning ("Composite init failed for %s", display);
 
722
        return NULL;
 
723
    }
 
724
 
 
725
    if (!ccm_display_init_damage (self))
 
726
    {
 
727
        g_object_unref (self);
 
728
        g_warning ("Damage init failed for %s", display);
 
729
        return NULL;
 
730
    }
 
731
 
 
732
    if (!ccm_display_init_shm (self))
 
733
    {
 
734
        g_object_unref (self);
 
735
        g_warning ("SHM init failed for %s", display);
 
736
        return NULL;
 
737
    }
 
738
 
 
739
    if (!ccm_display_init_xfixes (self))
 
740
    {
 
741
        g_object_unref (self);
 
742
        g_warning ("FIXES init failed for %s", display);
 
743
        return NULL;
 
744
    }
 
745
 
 
746
    if (!ccm_display_init_input (self))
 
747
    {
 
748
        g_object_unref (self);
 
749
        g_warning ("TEST init failed for %s", display);
 
750
        return NULL;
 
751
    }
 
752
 
 
753
    if (CCMDefaultDisplay == NULL) CCMDefaultDisplay = self;
 
754
 
 
755
    ccm_display_get_pointers (self);
 
756
 
 
757
    ccm_display_load_config (self);
 
758
 
 
759
    XSetErrorHandler (ccm_display_error_handler);
 
760
 
 
761
    self->priv->nb_screens = ScreenCount (self->priv->xdisplay);
 
762
    self->priv->screens = g_slice_alloc0 (sizeof (CCMScreen *) * (self->priv->nb_screens + 1));
 
763
 
 
764
    unmanaged = ccm_config_get_integer_list (self->priv->options[CCM_DISPLAY_UNMANAGED_SCREEN],
 
765
                                             NULL);
 
766
 
 
767
    for (cpt = 0; cpt < self->priv->nb_screens; ++cpt)
 
768
    {
 
769
        gboolean found = FALSE;
 
770
 
 
771
        if (unmanaged)
 
772
        {
 
773
            GSList *item;
 
774
 
 
775
            for (item = unmanaged; item; item = item->next)
 
776
            {
 
777
                if (GPOINTER_TO_INT (item->data) == cpt)
 
778
                {
 
779
                    found = TRUE;
 
780
                    break;
 
781
                }
 
782
            }
 
783
        }
 
784
        if (!found)
 
785
            self->priv->screens[cpt] = ccm_screen_new (self, cpt);
 
786
    }
 
787
    g_slist_free (unmanaged);
 
788
 
 
789
    self->priv->fd = ConnectionNumber (CCM_DISPLAY_XDISPLAY (self));
 
790
    fd_add_watch (self->priv->fd, self);
 
791
    fd_set_read_callback (self->priv->fd,
 
792
                          (CCMWatchCallback) ccm_display_process_events);
 
793
    fd_set_poll_callback (self->priv->fd,
 
794
                          (CCMWatchCallback) ccm_display_process_events);
 
795
 
 
796
    return self;
 
797
}
 
798
 
 
799
Display *
 
800
ccm_display_get_xdisplay (CCMDisplay * self)
 
801
{
 
802
    g_return_val_if_fail (self != NULL, NULL);
 
803
 
 
804
    return self->priv->xdisplay;
 
805
}
 
806
 
 
807
CCMScreen *
 
808
ccm_display_get_screen (CCMDisplay * self, guint number)
 
809
{
 
810
    g_return_val_if_fail (self != NULL, NULL);
 
811
    g_return_val_if_fail (number < self->priv->nb_screens, NULL);
 
812
 
 
813
    return self->priv->screens[number];
 
814
}
 
815
 
 
816
int
 
817
ccm_display_get_shape_notify_event_type (CCMDisplay * self)
 
818
{
 
819
    g_return_val_if_fail (self != NULL, 0);
 
820
 
 
821
    return self->priv->shape.event_base + ShapeNotify;
 
822
}
 
823
 
 
824
gboolean
 
825
ccm_display_report_device_event (CCMDisplay * self, CCMScreen * screen,
 
826
                                 gboolean report)
 
827
{
 
828
    g_return_val_if_fail (self != NULL, FALSE);
 
829
    g_return_val_if_fail (screen != NULL, FALSE);
 
830
 
 
831
    CCMWindow *root = ccm_screen_get_root_window (screen);
 
832
    GSList *item;
 
833
 
 
834
    for (item = self->priv->pointers; item; item = item->next)
 
835
    {
 
836
        XDevice *pointer = (XDevice *) item->data;
 
837
        gint cpt, nb = 0;
 
838
 
 
839
        if (report)
 
840
        {
 
841
            XInputClassInfo *class;
 
842
            XEventClass *event = g_new0 (XEventClass, 9 * pointer->num_classes);
 
843
 
 
844
            for (class = pointer->classes, cpt = 0; cpt < pointer->num_classes;
 
845
                 class++, ++cpt)
 
846
            {
 
847
                switch (class->input_class)
 
848
                {
 
849
                    case ButtonClass:
 
850
                        DeviceButtonPress (pointer,
 
851
                                           self->priv->type_button_press,
 
852
                                           event[nb++]);
 
853
                        DeviceButtonRelease (pointer,
 
854
                                             self->priv->type_button_release,
 
855
                                             event[nb++]);
 
856
                        break;
 
857
 
 
858
                    case ValuatorClass:
 
859
                        DeviceButton1Motion (pointer, 0, event[nb++]);
 
860
                        DeviceButton2Motion (pointer, 0, event[nb++]);
 
861
                        DeviceButton3Motion (pointer, 0, event[nb++]);
 
862
                        DeviceButton4Motion (pointer, 0, event[nb++]);
 
863
                        DeviceButton5Motion (pointer, 0, event[nb++]);
 
864
                        DeviceButtonMotion (pointer, 0, event[nb++]);
 
865
                        DeviceMotionNotify (pointer,
 
866
                                            self->priv->type_motion_notify,
 
867
                                            event[nb++]);
 
868
                        break;
 
869
 
 
870
                    default:
 
871
                        break;
 
872
                }
 
873
            }
 
874
            if (XSelectExtensionEvent (self->priv->xdisplay, 
 
875
                                       CCM_WINDOW_XWINDOW (root), 
 
876
                                       event, nb))
 
877
            {
 
878
                g_free (event);
 
879
                return FALSE;
 
880
            }
 
881
            g_free (event);
 
882
        }
 
883
        else
 
884
        {
 
885
            XEventClass *event = g_new0 (XEventClass, 1);;
 
886
            NoExtensionEvent (pointer, 0, event[nb++]);
 
887
            if (XSelectExtensionEvent (self->priv->xdisplay, 
 
888
                                       CCM_WINDOW_XWINDOW (root), 
 
889
                                       event, nb))
 
890
            {
 
891
                g_free (event);
 
892
                return FALSE;
 
893
            }
 
894
            g_free (event);
 
895
        }
 
896
    }
 
897
 
 
898
    return TRUE;
 
899
}
 
900
 
 
901
void
 
902
ccm_display_flush (CCMDisplay * self)
 
903
{
 
904
    g_return_if_fail (self != NULL);
 
905
 
 
906
    XFlush (self->priv->xdisplay);
 
907
}
 
908
 
 
909
void
 
910
ccm_display_sync (CCMDisplay * self)
 
911
{
 
912
    g_return_if_fail (self != NULL);
 
913
 
 
914
    XSync (self->priv->xdisplay, FALSE);
 
915
}
 
916
 
 
917
void
 
918
ccm_display_grab (CCMDisplay * self)
 
919
{
 
920
    g_return_if_fail (self != NULL);
 
921
 
 
922
    XGrabServer (self->priv->xdisplay);
 
923
}
 
924
 
 
925
void
 
926
ccm_display_ungrab (CCMDisplay * self)
 
927
{
 
928
    g_return_if_fail (self != NULL);
 
929
 
 
930
    XUngrabServer (self->priv->xdisplay);
 
931
}
 
932
 
 
933
void
 
934
ccm_display_trap_error (CCMDisplay * self)
 
935
{
 
936
    CCMLastXError = 0;
 
937
}
 
938
 
 
939
gint
 
940
ccm_display_pop_error (CCMDisplay * self)
 
941
{
 
942
    g_return_val_if_fail (self != NULL, 0);
 
943
 
 
944
    ccm_display_sync (self);
 
945
 
 
946
    return CCMLastXError;
 
947
}
 
948
 
 
949
const CCMCursor *
 
950
ccm_display_get_current_cursor (CCMDisplay * self, gboolean initiate)
 
951
{
 
952
    g_return_val_if_fail (self != NULL, NULL);
 
953
 
 
954
    if (initiate || !self->priv->cursor_current)
 
955
    {
 
956
        XFixesCursorImage *cursor;
 
957
 
 
958
        cursor = XFixesGetCursorImage (CCM_DISPLAY_XDISPLAY (self));
 
959
        ccm_display_check_cursor (self, cursor->atom, FALSE);
 
960
        XFree (cursor);
 
961
    }
 
962
 
 
963
    return (const CCMCursor *) self->priv->cursor_current;
 
964
}
 
965
 
 
966
CCMDisplay*
 
967
ccm_display_get_default()
 
968
{
 
969
    return CCMDefaultDisplay;
 
970
}