1ce9e13ba6f9c68e9924c9df8c51761bd21fa9aa
[dana/dcompmgr.git] / display.c
1 #include "efence.h"
2
3 #include "display.h"
4 #include "screen.h"
5 #include "list.h"
6 #include "gettext.h"
7 #include <stdlib.h>
8 #include <assert.h>
9 #include <string.h>
10 #include <stdio.h>
11
12 #include <xcb/damage.h>
13 #include <xcb/render.h>
14 #include <xcb/xfixes.h>
15 #include <xcb/composite.h>
16
17 typedef struct {
18     xcb_atom_t               *atom;
19     const char               *name;
20     xcb_intern_atom_cookie_t  ck;
21 } d_atom_query_t;
22
23 #define setup_extension(name) \
24     xcb_##name##_query_version_cookie_t ck_##name;
25
26 #define find_extension_xfixes(dpy) &dpy->xfixes;
27 #define find_extension_render(dpy) &dpy->render;
28 #define find_extension_composite(dpy) &dpy->composite;
29 #define find_extension_damage(dpy) &dpy->damage;
30
31 #define version_extension_xfixes \
32   XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MAJOR_VERSION
33 #define version_extension_render \
34   XCB_RENDER_MAJOR_VERSION, XCB_RENDER_MAJOR_VERSION
35 #define version_extension_composite \
36   XCB_COMPOSITE_MAJOR_VERSION, XCB_COMPOSITE_MAJOR_VERSION
37 #define version_extension_damage \
38   XCB_DAMAGE_MAJOR_VERSION, XCB_DAMAGE_MAJOR_VERSION
39
40 #define query_extension(dpy, name) \
41 { \
42     const xcb_query_extension_reply_t *rep;          \
43     d_display_ext_t *ext; \
44 \
45     xcb_prefetch_extension_data(dpy->conn, &xcb_##name##_id);  \
46     rep = xcb_get_extension_data(dpy->conn, &xcb_##name##_id); \
47 \
48     ext = find_extension_##name(dpy) \
49     ext->present = rep && rep->present;          \
50     ext->error   = rep ? rep->first_error : 0;   \
51     ext->event   = rep ? rep->first_event : 0;   \
52     ext->opcode  = rep ? rep->major_opcode : 0;  \
53 \
54     if (ext->present) \
55         ck_##name = xcb_##name##_query_version(dpy->conn, \
56                                                version_extension_##name); \
57 }
58
59 #define reply_extension(dpy, name) \
60 { \
61     xcb_##name##_query_version_reply_t *rep; \
62     d_display_ext_t *ext; \
63 \
64     ext = find_extension_##name(dpy) \
65     if (ext->present) { \
66         rep = xcb_##name##_query_version_reply(dpy->conn, ck_##name, NULL); \
67         if (rep) { \
68             ext->major_version = rep->major_version; \
69             ext->minor_version = rep->minor_version; \
70             free(rep); \
71         } \
72         else { \
73             printf("error querying the %s extension's version\n", "##name##");\
74             ext->present = FALSE; \
75         } \
76     } \
77 }
78
79 static void
80 query_atom(d_display_t *dpy, d_atom_query_t *q)
81 {
82     q->ck = xcb_intern_atom(dpy->conn, FALSE, strlen(q->name), q->name);
83 }
84
85 static void
86 reply_atom(d_display_t *dpy, d_atom_query_t *q)
87 {
88     xcb_intern_atom_reply_t *rep;
89     rep = xcb_intern_atom_reply(dpy->conn, q->ck, NULL);
90     if (rep) {
91         *q->atom = rep->atom;
92         free(rep);
93     }
94     else {
95         printf("unable to query atom %s\n", q->name);
96         *q->atom = 0;
97     }
98 }
99
100 static void
101 query_statics(d_display_t *dpy)
102 {
103     d_atom_query_t atoms[] = {
104         { .atom = &dpy->a.atom,
105           .name = "ATOM" },
106         { .atom = &dpy->a.cardinal,
107           .name = "CARDINAL" },
108         { .atom = &dpy->a.utf8_string,
109           .name = "UTF8_STRING" },
110         { .atom = &dpy->a.string,
111           .name = "STRING" },
112         { .atom = &dpy->a.pixmap,
113           .name = "PIXMAP" },
114         { .atom = &dpy->a.net_wm_window_type,
115           .name = "_NET_WM_WINDOW_TYPE" },
116         { .atom = &dpy->a.net_wm_window_type_desktop,
117           .name = "_NET_WM_WINDOW_TYPE_DESKTOP" },
118         { .atom = &dpy->a.net_wm_window_type_dock,
119           .name = "_NET_WM_WINDOW_TYPE_DOCK" },
120         { .atom = &dpy->a.net_wm_window_type_normal,
121           .name = "_NET_WM_WINDOW_TYPE_NORMAL" },
122         { .atom = &dpy->a.net_wm_window_type_dialog,
123           .name = "_NET_WM_WINDOW_TYPE_DIALOG" },
124         { .atom = &dpy->a.net_wm_window_type_toolbar,
125           .name = "_NET_WM_WINDOW_TYPE_TOOLBAR" },
126         { .atom = &dpy->a.net_wm_window_type_menu,
127           .name = "_NET_WM_WINDOW_TYPE_MENU" },
128         { .atom = &dpy->a.net_wm_window_type_utility,
129           .name = "_NET_WM_WINDOW_TYPE_UTILITY" },
130         { .atom = &dpy->a.net_wm_window_type_splash,
131           .name = "_NET_WM_WINDOW_TYPE_SPLAH" },
132         { .atom = &dpy->a.net_wm_window_type_tooltip,
133           .name = "_NET_WM_WINDOW_TYPE_TOOLTIP" },
134         { .atom = &dpy->a.net_wm_window_type_combo,
135           .name = "_NET_WM_WINDOW_TYPE_COMBO" },
136         { .atom = &dpy->a.net_wm_window_type_dropdown_menu,
137           .name = "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU" },
138         { .atom = &dpy->a.net_wm_window_type_popup_menu,
139           .name = "_NET_WM_WINDOW_TYPE_POPUP_MENU" },
140         { .atom = &dpy->a.net_wm_window_type_notification,
141           .name = "_NET_WM_WINDOW_TYPE_NOTIFICATION" },
142         { .atom = NULL }
143     };
144     int i;
145     setup_extension(xfixes);
146     setup_extension(render);
147     setup_extension(composite);
148     setup_extension(damage);
149
150     query_extension(dpy, xfixes);
151     query_extension(dpy, render);
152     query_extension(dpy, composite);
153     query_extension(dpy, damage);
154
155     for (i = 0; atoms[i].atom != NULL; ++i)
156         query_atom(dpy, &atoms[i]);
157
158     xcb_flush(dpy->conn);
159
160     reply_extension(dpy, xfixes);
161     reply_extension(dpy, render);
162     reply_extension(dpy, composite);
163     reply_extension(dpy, damage);
164
165     for (i = 0; atoms[i].atom != NULL; ++i)
166         reply_atom(dpy, &atoms[i]);
167 }
168
169 d_display_t*
170 display_open(const char *name)
171 {
172     d_display_t *dpy = NULL;
173     xcb_connection_t *conn;
174
175     conn = xcb_connect(name, NULL);
176     if (conn && !xcb_connection_has_error(conn)) {
177         dpy = malloc(sizeof(d_display_t));
178         dpy->conn = conn;
179         dpy->ref = 1;
180         dpy->fd = xcb_get_file_descriptor(conn);
181         dpy->screens = list_new();
182
183         query_statics(dpy);
184     }
185     return dpy;
186 }
187
188 void
189 display_ref(d_display_t *dpy)
190 {
191     ++dpy->ref;
192 }
193
194 void
195 display_unref(d_display_t *dpy)
196 {
197     if (dpy && --dpy->ref == 0) {
198         d_list_it_t *it;
199
200         for (it = list_top(dpy->screens); it; it = it->next)
201             screen_unref(it->data);
202         list_unref(dpy->screens);
203
204         xcb_disconnect(dpy->conn);
205         free(dpy);
206     }
207 }
208
209 void
210 display_error(d_display_t *dpy, xcb_generic_error_t *ev)
211 {
212     const int major_opcode = ((xcb_request_error_t*)ev)->major_opcode;
213     const int minor_opcode = ((xcb_request_error_t*)ev)->minor_opcode;
214     const char *name, *req;
215
216     /* XXX check if we should ignore it (ev->full_sequence) */
217
218     (void)dpy;
219
220     name = NULL;
221     switch (ev->error_code) {
222     case XCB_REQUEST:   name = "BadRequest";   break;
223     case XCB_VALUE:     name = "BadValue";     break;
224     case XCB_WINDOW:    name = "BadWindow";    break;
225     case XCB_PIXMAP:    name = "BadPixmap";    break;
226     case XCB_MATCH:     name = "BadMatch";     break;
227     case XCB_DRAWABLE:  name = "BadDrawable";  break;
228     case XCB_G_CONTEXT: name = "BadGC";        break;
229     default: break;
230     }
231     if (!name)
232         switch (ev->error_code - dpy->xfixes.error) {
233         case XCB_XFIXES_BAD_REGION: name = "BadRegion"; break;
234         default: break;
235         }
236     if (!name)
237         switch (ev->error_code - dpy->damage.error) {
238         case XCB_DAMAGE_BAD_DAMAGE: name = "BadDamage"; break;
239         default: break;
240         }
241     if (!name)
242         switch (ev->error_code - dpy->render.error) {
243         case XCB_RENDER_PICT_FORMAT: name = "BadPictFormat"; break;
244         case XCB_RENDER_PICT_OP:     name = "BadPictOp"; break;
245         case XCB_RENDER_PICTURE:     name = "BadPicture"; break;
246         case XCB_RENDER_GLYPH_SET:   name = "BadGlyphSet"; break;
247         case XCB_RENDER_GLYPH:       name = "BadGlyph"; break;
248         default: break;
249         }
250
251     req = NULL;
252     if (major_opcode <= 127)
253         switch (major_opcode) {
254         case 1:  req = "CreateWindow";           break;
255         case 2:  req = "ChangeWindowAttributes"; break;
256         case 3:  req = "GetWindowAttributes";    break;
257         case 14: req = "GetGeometry";            break;
258         case 15: req = "QueryTree";              break;
259         case 18: req = "ChangeProperty";         break;
260         case 20: req = "GetProperty";            break;
261         case 22: req = "SetSelectionOwner";      break;
262         case 23: req = "GetSelectionOwner";      break;
263         case 53: req = "CreatePixmap";           break;
264         case 54: req = "FreePixmap";             break;
265         case 55: req = "CreateGC";               break;
266         case 56: req = "ChangeGC";               break;
267         case 60: req = "FreeGC";                 break;
268         case 72: req = "PutImage";               break;
269         default: break; 
270         }
271     else if (major_opcode == dpy->damage.opcode)
272         switch (minor_opcode)
273         {
274         case 0: req = "DamageQueryVersion"; break;
275         case 1: req = "DamageCreate";       break;
276         case 2: req = "DamageDestroy";      break;
277         case 3: req = "DamageSubtract";     break;
278         default: break;
279         }
280     else if (major_opcode == dpy->render.opcode)
281         switch (minor_opcode)
282         {
283         case 0:  req = "RenderQueryVersion";             break;
284         case 1:  req = "RenderQueryPictFormats";         break;
285         case 2:  req = "RenderQueryPictIndexValues";     break;
286         case 4:  req = "RenderCreatePicture";            break;
287         case 5:  req = "RenderChangePicture";            break;
288         case 6:  req = "RenderSetPictureClipRectangles"; break;
289         case 7:  req = "RenderFreePicture";              break;
290         case 8:  req = "RenderComposite";                break;
291         case 10: req = "RenderCompositeTrapezoids";      break;
292         case 11: req = "RenderCompositeTriangles";       break;
293         case 12: req = "RenderCompositeTriStrip";        break;
294         case 13: req = "RenderCompositeTriFan";          break;
295         case 17: req = "RenderCreateGlyphSet";           break;
296         case 18: req = "RenderReferenceGlyphSet";        break;
297         case 19: req = "RenderFreeGlyphSet";             break;
298         case 20: req = "RenderAddGlyphs";                break;
299         case 22: req = "RenderFreeGlyphs";               break;
300         case 23: req = "RenderCompositeGlyphs8";         break;
301         case 24: req = "RenderCompositeGlyphs16";        break;
302         case 25: req = "RenderCompositeGlyphs32";        break;
303         case 26: req = "RenderFillRectangles";           break;
304         case 27: req = "RenderCreateCursor";             break;
305         case 28: req = "RenderSetPictureTransform";      break;
306         case 29: req = "RenderQueryFilters";             break;
307         case 30: req = "RenderSetPictureFilter";         break;
308         case 31: req = "RenderCreateAnimCursor";         break;
309         case 32: req = "RenderAddTraps";                 break;
310         case 33: req = "RenderCreateSolidFill";          break;
311         case 34: req = "RenderLinearGradient";           break;
312         case 35: req = "RenderRadialGradient";           break;
313         case 36: req = "RenderConicalGradient";          break;
314         default: break;
315         }
316     else if (major_opcode == dpy->composite.opcode)
317         switch (minor_opcode)
318         {
319         case 0: req = "CompositeQueryVersion";               break;
320         case 1: req = "CompositeRedirectWindow";             break;
321         case 2: req = "CompositeRedirectSubwindows";         break;
322         case 3: req = "CompositeUnredirectWindow";           break;
323         case 4: req = "CompositeUnredirectSubwindows";       break;
324         case 5: req = "CompositeCreateRegionFromBorderClip"; break;
325         case 6: req = "CompositeNameWindowPixmap";           break;
326         case 7: req = "CompositeGetOverlayWindow";           break;
327         case 8: req = "CompositeReleaseOverlayWindow";       break;
328         default: break;
329         }
330
331     if (name && req)
332         printf("XError: %s %s!\n",
333                name, req);
334     else if (name)
335         printf("XError: %s major opcode %d minor opcode %d!\n",
336                name, major_opcode, minor_opcode);
337     else
338         printf("XError: code %d major opcode %d minor opcode %d!\n",
339                ev->error_code, major_opcode, minor_opcode);
340
341     //abort();
342 }
343
344 int
345 display_claim_screens(d_display_t *dpy)
346 {
347     static const xcb_setup_t *setup;
348     xcb_screen_iterator_t it;
349     int i;
350     d_screen_t *sc;
351
352     setup = xcb_get_setup(dpy->conn);
353
354     i = 0;
355     for (it = xcb_setup_roots_iterator(setup); it.rem; xcb_screen_next(&it)) {
356         sc = screen_new(dpy, i++, it.data);
357         if (screen_register(sc)) {
358             list_append(dpy->screens, sc);
359             printf(_("managing screen %d\n"), sc->num);
360         }
361         else
362             screen_unref(sc);
363     }
364     return list_length(dpy->screens);
365 }
366
367 d_screen_t*
368 display_screen_from_root(d_display_t *dpy, xcb_window_t root)
369 {
370     d_list_it_t *it;
371
372     for (it = list_top(dpy->screens); it; it = it->next) {
373         d_screen_t *sc = it->data;
374         if (sc->super.root == root)
375             return sc;
376     }
377     assert(0);
378     return NULL;
379 }