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