9 #include <xcb/damage.h>
10 #include <xcb/render.h>
11 #include <xcb/xfixes.h>
12 #include <xcb/composite.h>
17 xcb_intern_atom_cookie_t ck;
20 #define setup_extension(name) \
21 xcb_##name##_query_version_cookie_t ck_##name;
23 #define find_extension_xfixes(dpy) &dpy->xfixes;
24 #define find_extension_render(dpy) &dpy->render;
25 #define find_extension_composite(dpy) &dpy->composite;
26 #define find_extension_damage(dpy) &dpy->damage;
28 #define version_extension_xfixes \
29 XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MAJOR_VERSION
30 #define version_extension_render \
31 XCB_RENDER_MAJOR_VERSION, XCB_RENDER_MAJOR_VERSION
32 #define version_extension_composite \
33 XCB_COMPOSITE_MAJOR_VERSION, XCB_COMPOSITE_MAJOR_VERSION
34 #define version_extension_damage \
35 XCB_DAMAGE_MAJOR_VERSION, XCB_DAMAGE_MAJOR_VERSION
37 #define query_extension(dpy, name) \
39 const xcb_query_extension_reply_t *rep; \
40 d_display_ext_t *ext; \
42 xcb_prefetch_extension_data(dpy->conn, &xcb_##name##_id); \
43 rep = xcb_get_extension_data(dpy->conn, &xcb_##name##_id); \
45 ext = find_extension_##name(dpy) \
46 ext->present = rep && rep->present; \
47 ext->error = rep && rep->first_error; \
48 ext->event = rep && rep->first_event; \
49 ext->opcode = rep && rep->major_opcode; \
52 ck_##name = xcb_##name##_query_version(dpy->conn, \
53 version_extension_##name); \
56 #define reply_extension(dpy, name) \
58 xcb_##name##_query_version_reply_t *rep; \
59 d_display_ext_t *ext; \
61 ext = find_extension_##name(dpy) \
63 rep = xcb_##name##_query_version_reply(dpy->conn, ck_##name, NULL); \
65 ext->major_version = rep->major_version; \
66 ext->minor_version = rep->minor_version; \
70 printf("error querying the %s extension's version\n", "##name##");\
71 ext->present = FALSE; \
77 query_atom(d_display_t *dpy, d_atom_query_t *q)
79 q->ck = xcb_intern_atom(dpy->conn, FALSE, strlen(q->name), q->name);
83 reply_atom(d_display_t *dpy, d_atom_query_t *q)
85 xcb_intern_atom_reply_t *rep;
86 rep = xcb_intern_atom_reply(dpy->conn, q->ck, NULL);
92 printf("unable to query atom %s\n", q->name);
98 query_statics(d_display_t *dpy)
100 d_atom_query_t atoms[] = {
101 { .atom = &dpy->a.atom,
103 { .atom = &dpy->a.cardinal,
104 .name = "CARDINAL" },
105 { .atom = &dpy->a.utf8_string,
106 .name = "UTF8_STRING" },
107 { .atom = &dpy->a.string,
109 { .atom = &dpy->a.pixmap,
111 { .atom = &dpy->a.net_wm_window_type,
112 .name = "_NET_WM_WINDOW_TYPE" },
113 { .atom = &dpy->a.net_wm_window_type_desktop,
114 .name = "_NET_WM_WINDOW_TYPE_DESKTOP" },
115 { .atom = &dpy->a.net_wm_window_type_dock,
116 .name = "_NET_WM_WINDOW_TYPE_DOCK" },
117 { .atom = &dpy->a.net_wm_window_type_normal,
118 .name = "_NET_WM_WINDOW_TYPE_NORMAL" },
119 { .atom = &dpy->a.net_wm_window_type_dialog,
120 .name = "_NET_WM_WINDOW_TYPE_DIALOG" },
121 { .atom = &dpy->a.net_wm_window_type_toolbar,
122 .name = "_NET_WM_WINDOW_TYPE_TOOLBAR" },
123 { .atom = &dpy->a.net_wm_window_type_menu,
124 .name = "_NET_WM_WINDOW_TYPE_MENU" },
125 { .atom = &dpy->a.net_wm_window_type_utility,
126 .name = "_NET_WM_WINDOW_TYPE_UTILITY" },
127 { .atom = &dpy->a.net_wm_window_type_splash,
128 .name = "_NET_WM_WINDOW_TYPE_SPLAH" },
129 { .atom = &dpy->a.net_wm_window_type_tooltip,
130 .name = "_NET_WM_WINDOW_TYPE_TOOLTIP" },
131 { .atom = &dpy->a.net_wm_window_type_combo,
132 .name = "_NET_WM_WINDOW_TYPE_COMBO" },
133 { .atom = &dpy->a.net_wm_window_type_dropdown_menu,
134 .name = "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU" },
135 { .atom = &dpy->a.net_wm_window_type_popup_menu,
136 .name = "_NET_WM_WINDOW_TYPE_POPUP_MENU" },
137 { .atom = &dpy->a.net_wm_window_type_notification,
138 .name = "_NET_WM_WINDOW_TYPE_NOTIFICATION" },
142 setup_extension(xfixes);
143 setup_extension(render);
144 setup_extension(composite);
145 setup_extension(damage);
147 query_extension(dpy, xfixes);
148 query_extension(dpy, render);
149 query_extension(dpy, composite);
150 query_extension(dpy, damage);
152 for (i = 0; atoms[i].atom != NULL; ++i)
153 query_atom(dpy, &atoms[i]);
155 xcb_flush(dpy->conn);
157 reply_extension(dpy, xfixes);
158 reply_extension(dpy, render);
159 reply_extension(dpy, composite);
160 reply_extension(dpy, damage);
162 for (i = 0; atoms[i].atom != NULL; ++i)
163 reply_atom(dpy, &atoms[i]);
167 display_open(const char *name)
169 d_display_t *dpy = NULL;
170 xcb_connection_t *conn;
172 conn = xcb_connect(name, NULL);
173 if (conn && !xcb_connection_has_error(conn)) {
174 dpy = malloc(sizeof(d_display_t));
177 dpy->fd = xcb_get_file_descriptor(conn);
187 display_ref(d_display_t *dpy)
193 display_unref(d_display_t *dpy)
195 if (dpy && --dpy->ref == 0) {
197 xcb_disconnect(dpy->conn);
199 for (i = 0; i < dpy->nscreens; ++i)
200 screen_free(&dpy->screens[i]);
207 display_error(d_display_t *dpy, xcb_generic_error_t *ev)
209 const int major_opcode = ((xcb_request_error_t*)ev)->major_opcode;
210 const int minor_opcode = ((xcb_request_error_t*)ev)->minor_opcode;
211 const char *name, *req;
213 /* XXX check if we should ignore it (ev->full_sequence) */
218 switch (ev->error_code) {
219 case XCB_REQUEST: name = "BadRequest"; break;
220 case XCB_VALUE: name = "BadValue"; break;
221 case XCB_WINDOW: name = "BadWindow"; break;
222 case XCB_PIXMAP: name = "BadPixmap"; break;
223 case XCB_MATCH: name = "BadMatch"; break;
224 case XCB_DRAWABLE: name = "BadDrawable"; break;
225 case XCB_G_CONTEXT: name = "BadGC"; break;
229 switch (ev->error_code - dpy->xfixes.error) {
230 case XCB_XFIXES_BAD_REGION: name = "BadRegion"; break;
234 switch (ev->error_code - dpy->damage.error) {
235 case XCB_DAMAGE_BAD_DAMAGE: name = "BadDamage"; break;
239 switch (ev->error_code - dpy->render.error) {
240 case XCB_RENDER_PICT_FORMAT: name = "BadPictFormat"; break;
241 case XCB_RENDER_PICT_OP: name = "BadPictOp"; break;
242 case XCB_RENDER_PICTURE: name = "BadPicture"; break;
243 case XCB_RENDER_GLYPH_SET: name = "BadGlyphSet"; break;
244 case XCB_RENDER_GLYPH: name = "BadGlyph"; break;
248 if (major_opcode <= 127)
249 switch (major_opcode) {
250 case 1: req = "CreateWindow"; break;
251 case 2: req = "ChangeWindowAttributes"; break;
252 case 3: req = "GetWindowAttributes"; break;
253 case 14: req = "GetGeometry"; break;
254 case 15: req = "QueryTree"; break;
255 case 18: req = "ChangeProperty"; break;
256 case 20: req = "GetProperty"; break;
257 case 22: req = "SetSelectionOwner"; break;
258 case 23: req = "GetSelectionOwner"; break;
259 case 53: req = "CreatePixmap"; break;
260 case 54: req = "FreePixmap"; break;
261 case 55: req = "CreateGC"; break;
262 case 56: req = "ChangeGC"; break;
263 case 60: req = "FreeGC"; break;
264 case 72: req = "PutImage"; break;
269 printf("XError: %s %s!\n",
272 printf("XError: %s major opcode %d minor opcode %d!\n",
273 name, major_opcode, minor_opcode);
275 printf("XError: code %d major opcode %d minor opcode %d!\n",
276 ev->error_code, major_opcode, minor_opcode);
282 display_claim_screens(d_display_t *dpy)
284 static const xcb_setup_t *setup;
285 xcb_screen_iterator_t it;
289 setup = xcb_get_setup(dpy->conn);
292 for (it = xcb_setup_roots_iterator(setup); it.rem; xcb_screen_next(&it)) {
296 if (screen_register(dpy, i, &sc)) {
298 dpy->screens = realloc(dpy->screens,
299 sizeof(d_screen_t)*dpy->nscreens);
300 dpy->screens[dpy->nscreens-1] = sc;
301 printf(_("managing screen %d\n"), sc.num);
304 return dpy->nscreens;
308 display_screen_from_root(d_display_t *dpy, xcb_window_t root)
311 for (i = 0; i < dpy->nscreens; ++i)
312 if (dpy->screens[i].super.root == root)
313 return &dpy->screens[i];
319 display_screen_n(d_display_t *dpy, int n)
321 assert(n >= 0 && n < dpy->nscreens);
322 return &dpy->screens[n];