12 #include <xcb/damage.h>
13 #include <xcb/render.h>
14 #include <xcb/xfixes.h>
15 #include <xcb/composite.h>
21 xcb_intern_atom_cookie_t ck;
24 #define setup_extension(name) \
25 xcb_##name##_query_version_cookie_t ck_##name;
27 #define find_extension_xfixes(dpy) &dpy->xfixes;
28 #define find_extension_render(dpy) &dpy->render;
29 #define find_extension_composite(dpy) &dpy->composite;
30 #define find_extension_damage(dpy) &dpy->damage;
31 #define find_extension_shape(dpy) &dpy->shape;
32 #define find_extension_glx(dpy) &dpy->glx;
34 #define version_extension_xfixes \
35 XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MAJOR_VERSION
36 #define version_extension_render \
37 XCB_RENDER_MAJOR_VERSION, XCB_RENDER_MAJOR_VERSION
38 #define version_extension_composite \
39 XCB_COMPOSITE_MAJOR_VERSION, XCB_COMPOSITE_MAJOR_VERSION
40 #define version_extension_damage \
41 XCB_DAMAGE_MAJOR_VERSION, XCB_DAMAGE_MAJOR_VERSION
42 #define version_extension_glx \
43 XCB_GLX_MAJOR_VERSION, XCB_GLX_MAJOR_VERSION
45 #define query_extension(dpy, name) \
47 const xcb_query_extension_reply_t *rep; \
48 d_display_ext_t *ext; \
50 xcb_prefetch_extension_data(dpy->conn, &xcb_##name##_id); \
51 rep = xcb_get_extension_data(dpy->conn, &xcb_##name##_id); \
53 ext = find_extension_##name(dpy) \
54 ext->present = rep && rep->present; \
55 ext->error = rep ? rep->first_error : 0; \
56 ext->event = rep ? rep->first_event : 0; \
57 ext->opcode = rep ? rep->major_opcode : 0; \
60 #define query_extension_version(dpy, name) \
62 d_display_ext_t *ext; \
64 ext = find_extension_##name(dpy) \
67 ck_##name = xcb_##name##_query_version(dpy->conn, \
68 version_extension_##name); \
71 #define query_extension_version_no_client_version(dpy, name) \
73 d_display_ext_t *ext; \
75 ext = find_extension_##name(dpy) \
78 ck_##name = xcb_##name##_query_version(dpy->conn); \
81 #define reply_extension(dpy, name) \
83 xcb_##name##_query_version_reply_t *rep; \
84 d_display_ext_t *ext; \
86 ext = find_extension_##name(dpy) \
88 rep = xcb_##name##_query_version_reply(dpy->conn, ck_##name, NULL); \
90 ext->major_version = rep->major_version; \
91 ext->minor_version = rep->minor_version; \
95 printf("error querying the %s extension's version\n", "##name##");\
96 ext->present = FALSE; \
102 query_atom(d_display_t *dpy, d_atom_query_t *q)
104 q->ck = xcb_intern_atom(dpy->conn, FALSE, strlen(q->name), q->name);
108 reply_atom(d_display_t *dpy, d_atom_query_t *q)
110 xcb_intern_atom_reply_t *rep;
111 rep = xcb_intern_atom_reply(dpy->conn, q->ck, NULL);
113 *q->atom = rep->atom;
117 printf("unable to query atom %s\n", q->name);
123 query_statics(d_display_t *dpy)
125 d_atom_query_t atoms[] = {
126 { .atom = &dpy->a.utf8_string,
127 .name = "UTF8_STRING" },
128 { .atom = &dpy->a.esetroot_pmap_id,
129 .name = "ESETROOT_PMAP_ID" },
130 { .atom = &dpy->a.xrootpmap_id,
131 .name = "_XROOTPMAP_ID" },
132 { .atom = &dpy->a.xsetroot_id,
133 .name = "_XSETROOT_ID" },
134 { .atom = &dpy->a.net_wm_window_opacity,
135 .name = "_NET_WM_WINDOW_OPACITY" },
136 { .atom = &dpy->a.net_wm_window_type,
137 .name = "_NET_WM_WINDOW_TYPE" },
138 { .atom = &dpy->a.net_wm_window_type_desktop,
139 .name = "_NET_WM_WINDOW_TYPE_DESKTOP" },
140 { .atom = &dpy->a.net_wm_window_type_dock,
141 .name = "_NET_WM_WINDOW_TYPE_DOCK" },
142 { .atom = &dpy->a.net_wm_window_type_normal,
143 .name = "_NET_WM_WINDOW_TYPE_NORMAL" },
144 { .atom = &dpy->a.net_wm_window_type_dialog,
145 .name = "_NET_WM_WINDOW_TYPE_DIALOG" },
146 { .atom = &dpy->a.net_wm_window_type_toolbar,
147 .name = "_NET_WM_WINDOW_TYPE_TOOLBAR" },
148 { .atom = &dpy->a.net_wm_window_type_menu,
149 .name = "_NET_WM_WINDOW_TYPE_MENU" },
150 { .atom = &dpy->a.net_wm_window_type_utility,
151 .name = "_NET_WM_WINDOW_TYPE_UTILITY" },
152 { .atom = &dpy->a.net_wm_window_type_splash,
153 .name = "_NET_WM_WINDOW_TYPE_SPLAH" },
154 { .atom = &dpy->a.net_wm_window_type_tooltip,
155 .name = "_NET_WM_WINDOW_TYPE_TOOLTIP" },
156 { .atom = &dpy->a.net_wm_window_type_combo,
157 .name = "_NET_WM_WINDOW_TYPE_COMBO" },
158 { .atom = &dpy->a.net_wm_window_type_dropdown_menu,
159 .name = "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU" },
160 { .atom = &dpy->a.net_wm_window_type_popup_menu,
161 .name = "_NET_WM_WINDOW_TYPE_POPUP_MENU" },
162 { .atom = &dpy->a.net_wm_window_type_notification,
163 .name = "_NET_WM_WINDOW_TYPE_NOTIFICATION" },
167 setup_extension(xfixes);
168 setup_extension(render);
169 setup_extension(composite);
170 setup_extension(damage);
171 setup_extension(shape);
172 setup_extension(glx);
174 query_extension(dpy, xfixes);
175 query_extension(dpy, render);
176 query_extension(dpy, composite);
177 query_extension(dpy, damage);
178 query_extension(dpy, shape);
179 query_extension(dpy, glx);
181 query_extension_version(dpy, xfixes);
182 query_extension_version(dpy, render);
183 query_extension_version(dpy, composite);
184 query_extension_version(dpy, damage);
185 query_extension_version_no_client_version(dpy, shape);
186 query_extension_version(dpy, glx);
188 for (i = 0; atoms[i].atom != NULL; ++i)
189 query_atom(dpy, &atoms[i]);
191 xcb_flush(dpy->conn);
193 reply_extension(dpy, xfixes);
194 reply_extension(dpy, render);
195 reply_extension(dpy, composite);
196 reply_extension(dpy, damage);
197 reply_extension(dpy, shape);
198 reply_extension(dpy, glx);
200 for (i = 0; atoms[i].atom != NULL; ++i)
201 reply_atom(dpy, &atoms[i]);
203 /* hard-coded ones, you can't request these */
209 dpy->a.wm_transient_for = 68;
213 display_open(const char *name)
215 d_display_t *dpy = NULL;
216 xcb_connection_t *conn = NULL;
217 Display *xlib_dpy = NULL;
219 xlib_dpy = XOpenDisplay(name);
221 conn = XGetXCBConnection(xlib_dpy);
223 XSetEventQueueOwner(xlib_dpy, XCBOwnsEventQueue);
226 //conn = xcb_connect(name, NULL);
227 if (conn && !xcb_connection_has_error(conn)) {
228 dpy = malloc(sizeof(d_display_t));
230 dpy->xlib_dpy = xlib_dpy;
232 dpy->fd = xcb_get_file_descriptor(conn);
233 dpy->screens = list_new();
241 display_ref(d_display_t *dpy)
247 display_unref(d_display_t *dpy)
249 if (dpy && --dpy->ref == 0) {
252 for (it = list_top(dpy->screens); it; it = it->next)
253 screen_unref(it->data);
254 list_unref(dpy->screens);
256 //xcb_disconnect(dpy->conn);
257 XCloseDisplay(dpy->xlib_dpy);
263 display_error(d_display_t *dpy, xcb_generic_error_t *ev)
265 const int major_opcode = ((xcb_request_error_t*)ev)->major_opcode;
266 const int minor_opcode = ((xcb_request_error_t*)ev)->minor_opcode;
267 const char *name, *req;
269 /* XXX check if we should ignore it (ev->full_sequence) */
274 switch (ev->error_code) {
275 case XCB_REQUEST: name = "BadRequest"; break;
276 case XCB_VALUE: name = "BadValue"; break;
277 case XCB_WINDOW: name = "BadWindow"; break;
278 case XCB_PIXMAP: name = "BadPixmap"; break;
279 case XCB_MATCH: name = "BadMatch"; break;
280 case XCB_DRAWABLE: name = "BadDrawable"; break;
281 case XCB_G_CONTEXT: name = "BadGC"; break;
282 case XCB_ID_CHOICE: name = "BadID"; break;
286 switch (ev->error_code - dpy->xfixes.error) {
287 case XCB_XFIXES_BAD_REGION: name = "BadRegion"; break;
291 switch (ev->error_code - dpy->damage.error) {
292 case XCB_DAMAGE_BAD_DAMAGE: name = "BadDamage"; break;
296 switch (ev->error_code - dpy->render.error) {
297 case XCB_RENDER_PICT_FORMAT: name = "BadPictFormat"; break;
298 case XCB_RENDER_PICT_OP: name = "BadPictOp"; break;
299 case XCB_RENDER_PICTURE: name = "BadPicture"; break;
300 case XCB_RENDER_GLYPH_SET: name = "BadGlyphSet"; break;
301 case XCB_RENDER_GLYPH: name = "BadGlyph"; break;
306 if (major_opcode <= 127)
307 switch (major_opcode) {
308 case 1: req = "CreateWindow"; break;
309 case 2: req = "ChangeWindowAttributes"; break;
310 case 3: req = "GetWindowAttributes"; break;
311 case 14: req = "GetGeometry"; break;
312 case 15: req = "QueryTree"; break;
313 case 18: req = "ChangeProperty"; break;
314 case 20: req = "GetProperty"; break;
315 case 22: req = "SetSelectionOwner"; break;
316 case 23: req = "GetSelectionOwner"; break;
317 case 53: req = "CreatePixmap"; break;
318 case 54: req = "FreePixmap"; break;
319 case 55: req = "CreateGC"; break;
320 case 56: req = "ChangeGC"; break;
321 case 60: req = "FreeGC"; break;
322 case 72: req = "PutImage"; break;
325 else if (major_opcode == dpy->damage.opcode)
326 switch (minor_opcode)
328 case 0: req = "DamageQueryVersion"; break;
329 case 1: req = "DamageCreate"; break;
330 case 2: req = "DamageDestroy"; break;
331 case 3: req = "DamageSubtract"; break;
334 else if (major_opcode == dpy->render.opcode)
335 switch (minor_opcode)
337 case 0: req = "RenderQueryVersion"; break;
338 case 1: req = "RenderQueryPictFormats"; break;
339 case 2: req = "RenderQueryPictIndexValues"; break;
340 case 4: req = "RenderCreatePicture"; break;
341 case 5: req = "RenderChangePicture"; break;
342 case 6: req = "RenderSetPictureClipRectangles"; break;
343 case 7: req = "RenderFreePicture"; break;
344 case 8: req = "RenderComposite"; break;
345 case 10: req = "RenderCompositeTrapezoids"; break;
346 case 11: req = "RenderCompositeTriangles"; break;
347 case 12: req = "RenderCompositeTriStrip"; break;
348 case 13: req = "RenderCompositeTriFan"; break;
349 case 17: req = "RenderCreateGlyphSet"; break;
350 case 18: req = "RenderReferenceGlyphSet"; break;
351 case 19: req = "RenderFreeGlyphSet"; break;
352 case 20: req = "RenderAddGlyphs"; break;
353 case 22: req = "RenderFreeGlyphs"; break;
354 case 23: req = "RenderCompositeGlyphs8"; break;
355 case 24: req = "RenderCompositeGlyphs16"; break;
356 case 25: req = "RenderCompositeGlyphs32"; break;
357 case 26: req = "RenderFillRectangles"; break;
358 case 27: req = "RenderCreateCursor"; break;
359 case 28: req = "RenderSetPictureTransform"; break;
360 case 29: req = "RenderQueryFilters"; break;
361 case 30: req = "RenderSetPictureFilter"; break;
362 case 31: req = "RenderCreateAnimCursor"; break;
363 case 32: req = "RenderAddTraps"; break;
364 case 33: req = "RenderCreateSolidFill"; break;
365 case 34: req = "RenderLinearGradient"; break;
366 case 35: req = "RenderRadialGradient"; break;
367 case 36: req = "RenderConicalGradient"; break;
370 else if (major_opcode == dpy->composite.opcode)
371 switch (minor_opcode)
373 case 0: req = "CompositeQueryVersion"; break;
374 case 1: req = "CompositeRedirectWindow"; break;
375 case 2: req = "CompositeRedirectSubwindows"; break;
376 case 3: req = "CompositeUnredirectWindow"; break;
377 case 4: req = "CompositeUnredirectSubwindows"; break;
378 case 5: req = "CompositeCreateRegionFromBorderClip"; break;
379 case 6: req = "CompositeNameWindowPixmap"; break;
380 case 7: req = "CompositeGetOverlayWindow"; break;
381 case 8: req = "CompositeReleaseOverlayWindow"; break;
384 else if (major_opcode == dpy->shape.opcode)
385 switch (minor_opcode)
387 case 0: req = "ShapeQueryVersion"; break;
388 case 1: req = "ShapeRectangles"; break;
389 case 2: req = "ShapeMask"; break;
390 case 3: req = "ShapeCombine"; break;
391 case 4: req = "ShapeOffset"; break;
392 case 5: req = "ShapeQueryExtents"; break;
393 case 6: req = "ShapeSelectInput"; break;
394 case 7: req = "ShapeInputSelected"; break;
395 case 8: req = "ShapeGetRectangles"; break;
398 else if (major_opcode == dpy->xfixes.opcode)
399 switch (minor_opcode)
401 case 0: req = "XFixesQueryVersion"; break;
402 case 1: req = "XFixesChangeSaveSet"; break;
403 case 2: req = "XFixesSelectSelectionInput"; break;
404 case 3: req = "XFixesSelectCursorInput"; break;
405 case 4: req = "XFixesGetCursorImage"; break;
406 case 5: req = "XFixesCreateRegion"; break;
407 case 6: req = "XFixesCreateRegionFromBitmap"; break;
408 case 7: req = "XFixesCreateRegionFromWindow"; break;
409 case 8: req = "XFixesCreateRegionFromGC"; break;
410 case 9: req = "XFixesCreateRegionFromPicture"; break;
411 case 10: req = "XFixesDestroyRegion"; break;
412 case 11: req = "XFixesSetRegion"; break;
413 case 12: req = "XFixesCopyRegion"; break;
414 case 13: req = "XFixesUnionRegion"; break;
415 case 14: req = "XFixesIntersectRegion"; break;
416 case 15: req = "XFixesSubtractRegion"; break;
417 case 16: req = "XFixesInvertRegion"; break;
418 case 17: req = "XFixesTranslanteRegion"; break;
419 case 18: req = "XFixesRegionExtents"; break;
420 case 19: req = "XFixesFetchRegion"; break;
421 case 20: req = "XFixesGCClipRegion"; break;
422 case 21: req = "XFixesSetWindowShapeRegion"; break;
423 case 22: req = "XFixesSetPictureClipRegion"; break;
426 else if (major_opcode == dpy->glx.opcode)
427 switch (minor_opcode)
429 case 1: req = "glXRender"; break;
430 case 2: req = "glXRenderLarge"; break;
431 case 3: req = "glxCreateContext"; break;
432 case 4: req = "glxDestroyContext"; break;
433 case 5: req = "glxMakeCurrent"; break;
434 case 6: req = "glXIsDirect"; break;
435 case 7: req = "glXQueryVersion"; break;
436 case 8: req = "glXWaitGL"; break;
437 case 9: req = "glXWaitX"; break;
438 case 10: req = "glXCopyContext"; break;
439 case 11: req = "glXSwapBuffers"; break;
440 case 12: req = "glXUseXFont"; break;
441 case 13: req = "glXCreateGLXPixmap"; break;
442 case 14: req = "glXGetVisualConfigs"; break;
443 case 15: req = "glXDestroyGLXPixmap"; break;
444 case 16: req = "glXVendorPrivate"; break;
445 case 17: req = "glXVendorPrivateWithReply"; break;
446 case 18: req = "glXQueryExtensionsString"; break;
447 case 19: req = "glXQueryServerString"; break;
448 case 20: req = "glXClientInfo"; break;
449 case 21: req = "glXGetFBConfigs"; break;
450 case 22: req = "glXCreatePixmap"; break;
451 case 23: req = "glXDestroyPixmap"; break;
452 case 24: req = "glXCreateNewContext"; break;
453 case 25: req = "glXQueryContext"; break;
454 case 26: req = "glXMakeContextCurrent"; break;
459 printf("XError: %s %s\n",
462 printf("XError: %s major opcode %d minor opcode %d\n",
463 name, major_opcode, minor_opcode);
465 printf("XError: error code %d major opcode %d minor opcode %d\n",
466 ev->error_code, major_opcode, minor_opcode);
472 display_claim_screens(d_display_t *dpy)
474 static const xcb_setup_t *setup;
475 xcb_screen_iterator_t it;
479 setup = xcb_get_setup(dpy->conn);
482 for (it = xcb_setup_roots_iterator(setup); it.rem; xcb_screen_next(&it)) {
483 sc = screen_new(dpy, i++, it.data);
484 if (screen_register(sc)) {
485 list_append(dpy->screens, sc);
486 printf(_("managing screen %d\n"), sc->num);
491 return list_length(dpy->screens);
495 display_screen_from_root(d_display_t *dpy, xcb_window_t root)
499 for (it = list_top(dpy->screens); it; it = it->next) {
500 d_screen_t *sc = it->data;
501 if (sc->super->root == root)