12 #include <xcb/damage.h>
13 #include <xcb/render.h>
14 #include <xcb/xfixes.h>
15 #include <xcb/composite.h>
20 xcb_intern_atom_cookie_t ck;
23 #define setup_extension(name) \
24 xcb_##name##_query_version_cookie_t ck_##name;
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;
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
40 #define query_extension(dpy, name) \
42 const xcb_query_extension_reply_t *rep; \
43 d_display_ext_t *ext; \
45 xcb_prefetch_extension_data(dpy->conn, &xcb_##name##_id); \
46 rep = xcb_get_extension_data(dpy->conn, &xcb_##name##_id); \
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; \
55 ck_##name = xcb_##name##_query_version(dpy->conn, \
56 version_extension_##name); \
59 #define reply_extension(dpy, name) \
61 xcb_##name##_query_version_reply_t *rep; \
62 d_display_ext_t *ext; \
64 ext = find_extension_##name(dpy) \
66 rep = xcb_##name##_query_version_reply(dpy->conn, ck_##name, NULL); \
68 ext->major_version = rep->major_version; \
69 ext->minor_version = rep->minor_version; \
73 printf("error querying the %s extension's version\n", "##name##");\
74 ext->present = FALSE; \
80 query_atom(d_display_t *dpy, d_atom_query_t *q)
82 q->ck = xcb_intern_atom(dpy->conn, FALSE, strlen(q->name), q->name);
86 reply_atom(d_display_t *dpy, d_atom_query_t *q)
88 xcb_intern_atom_reply_t *rep;
89 rep = xcb_intern_atom_reply(dpy->conn, q->ck, NULL);
95 printf("unable to query atom %s\n", q->name);
101 query_statics(d_display_t *dpy)
103 d_atom_query_t atoms[] = {
104 { .atom = &dpy->a.utf8_string,
105 .name = "UTF8_STRING" },
106 { .atom = &dpy->a.net_wm_window_type,
107 .name = "_NET_WM_WINDOW_TYPE" },
108 { .atom = &dpy->a.net_wm_window_type_desktop,
109 .name = "_NET_WM_WINDOW_TYPE_DESKTOP" },
110 { .atom = &dpy->a.net_wm_window_type_dock,
111 .name = "_NET_WM_WINDOW_TYPE_DOCK" },
112 { .atom = &dpy->a.net_wm_window_type_normal,
113 .name = "_NET_WM_WINDOW_TYPE_NORMAL" },
114 { .atom = &dpy->a.net_wm_window_type_dialog,
115 .name = "_NET_WM_WINDOW_TYPE_DIALOG" },
116 { .atom = &dpy->a.net_wm_window_type_toolbar,
117 .name = "_NET_WM_WINDOW_TYPE_TOOLBAR" },
118 { .atom = &dpy->a.net_wm_window_type_menu,
119 .name = "_NET_WM_WINDOW_TYPE_MENU" },
120 { .atom = &dpy->a.net_wm_window_type_utility,
121 .name = "_NET_WM_WINDOW_TYPE_UTILITY" },
122 { .atom = &dpy->a.net_wm_window_type_splash,
123 .name = "_NET_WM_WINDOW_TYPE_SPLAH" },
124 { .atom = &dpy->a.net_wm_window_type_tooltip,
125 .name = "_NET_WM_WINDOW_TYPE_TOOLTIP" },
126 { .atom = &dpy->a.net_wm_window_type_combo,
127 .name = "_NET_WM_WINDOW_TYPE_COMBO" },
128 { .atom = &dpy->a.net_wm_window_type_dropdown_menu,
129 .name = "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU" },
130 { .atom = &dpy->a.net_wm_window_type_popup_menu,
131 .name = "_NET_WM_WINDOW_TYPE_POPUP_MENU" },
132 { .atom = &dpy->a.net_wm_window_type_notification,
133 .name = "_NET_WM_WINDOW_TYPE_NOTIFICATION" },
137 setup_extension(xfixes);
138 setup_extension(render);
139 setup_extension(composite);
140 setup_extension(damage);
142 query_extension(dpy, xfixes);
143 query_extension(dpy, render);
144 query_extension(dpy, composite);
145 query_extension(dpy, damage);
147 for (i = 0; atoms[i].atom != NULL; ++i)
148 query_atom(dpy, &atoms[i]);
150 xcb_flush(dpy->conn);
152 reply_extension(dpy, xfixes);
153 reply_extension(dpy, render);
154 reply_extension(dpy, composite);
155 reply_extension(dpy, damage);
157 for (i = 0; atoms[i].atom != NULL; ++i)
158 reply_atom(dpy, &atoms[i]);
160 /* hard-coded ones, you can't request these */
168 display_open(const char *name)
170 d_display_t *dpy = NULL;
171 xcb_connection_t *conn;
173 conn = xcb_connect(name, NULL);
174 if (conn && !xcb_connection_has_error(conn)) {
175 dpy = malloc(sizeof(d_display_t));
178 dpy->fd = xcb_get_file_descriptor(conn);
179 dpy->screens = list_new();
187 display_ref(d_display_t *dpy)
193 display_unref(d_display_t *dpy)
195 if (dpy && --dpy->ref == 0) {
198 for (it = list_top(dpy->screens); it; it = it->next)
199 screen_unref(it->data);
200 list_unref(dpy->screens);
202 xcb_disconnect(dpy->conn);
208 display_error(d_display_t *dpy, xcb_generic_error_t *ev)
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;
214 /* XXX check if we should ignore it (ev->full_sequence) */
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;
230 switch (ev->error_code - dpy->xfixes.error) {
231 case XCB_XFIXES_BAD_REGION: name = "BadRegion"; break;
235 switch (ev->error_code - dpy->damage.error) {
236 case XCB_DAMAGE_BAD_DAMAGE: name = "BadDamage"; break;
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;
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;
269 else if (major_opcode == dpy->damage.opcode)
270 switch (minor_opcode)
272 case 0: req = "DamageQueryVersion"; break;
273 case 1: req = "DamageCreate"; break;
274 case 2: req = "DamageDestroy"; break;
275 case 3: req = "DamageSubtract"; break;
278 else if (major_opcode == dpy->render.opcode)
279 switch (minor_opcode)
281 case 0: req = "RenderQueryVersion"; break;
282 case 1: req = "RenderQueryPictFormats"; break;
283 case 2: req = "RenderQueryPictIndexValues"; break;
284 case 4: req = "RenderCreatePicture"; break;
285 case 5: req = "RenderChangePicture"; break;
286 case 6: req = "RenderSetPictureClipRectangles"; break;
287 case 7: req = "RenderFreePicture"; break;
288 case 8: req = "RenderComposite"; break;
289 case 10: req = "RenderCompositeTrapezoids"; break;
290 case 11: req = "RenderCompositeTriangles"; break;
291 case 12: req = "RenderCompositeTriStrip"; break;
292 case 13: req = "RenderCompositeTriFan"; break;
293 case 17: req = "RenderCreateGlyphSet"; break;
294 case 18: req = "RenderReferenceGlyphSet"; break;
295 case 19: req = "RenderFreeGlyphSet"; break;
296 case 20: req = "RenderAddGlyphs"; break;
297 case 22: req = "RenderFreeGlyphs"; break;
298 case 23: req = "RenderCompositeGlyphs8"; break;
299 case 24: req = "RenderCompositeGlyphs16"; break;
300 case 25: req = "RenderCompositeGlyphs32"; break;
301 case 26: req = "RenderFillRectangles"; break;
302 case 27: req = "RenderCreateCursor"; break;
303 case 28: req = "RenderSetPictureTransform"; break;
304 case 29: req = "RenderQueryFilters"; break;
305 case 30: req = "RenderSetPictureFilter"; break;
306 case 31: req = "RenderCreateAnimCursor"; break;
307 case 32: req = "RenderAddTraps"; break;
308 case 33: req = "RenderCreateSolidFill"; break;
309 case 34: req = "RenderLinearGradient"; break;
310 case 35: req = "RenderRadialGradient"; break;
311 case 36: req = "RenderConicalGradient"; break;
314 else if (major_opcode == dpy->composite.opcode)
315 switch (minor_opcode)
317 case 0: req = "CompositeQueryVersion"; break;
318 case 1: req = "CompositeRedirectWindow"; break;
319 case 2: req = "CompositeRedirectSubwindows"; break;
320 case 3: req = "CompositeUnredirectWindow"; break;
321 case 4: req = "CompositeUnredirectSubwindows"; break;
322 case 5: req = "CompositeCreateRegionFromBorderClip"; break;
323 case 6: req = "CompositeNameWindowPixmap"; break;
324 case 7: req = "CompositeGetOverlayWindow"; break;
325 case 8: req = "CompositeReleaseOverlayWindow"; break;
330 printf("XError: %s %s!\n",
333 printf("XError: %s major opcode %d minor opcode %d!\n",
334 name, major_opcode, minor_opcode);
336 printf("XError: code %d major opcode %d minor opcode %d!\n",
337 ev->error_code, major_opcode, minor_opcode);
343 display_claim_screens(d_display_t *dpy)
345 static const xcb_setup_t *setup;
346 xcb_screen_iterator_t it;
350 setup = xcb_get_setup(dpy->conn);
353 for (it = xcb_setup_roots_iterator(setup); it.rem; xcb_screen_next(&it)) {
354 sc = screen_new(dpy, i++, it.data);
355 if (screen_register(sc)) {
356 list_append(dpy->screens, sc);
357 printf(_("managing screen %d\n"), sc->num);
362 return list_length(dpy->screens);
366 display_screen_from_root(d_display_t *dpy, xcb_window_t root)
370 for (it = list_top(dpy->screens); it; it = it->next) {
371 d_screen_t *sc = it->data;
372 if (sc->super.root == root)