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