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