+#include "efence.h"
+
#include "display.h"
+#include "screen.h"
+#include "list.h"
+#include "gettext.h"
#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
#include <stdio.h>
#include <xcb/damage.h>
#include <xcb/xfixes.h>
#include <xcb/composite.h>
+typedef struct {
+ xcb_atom_t *atom;
+ const char *name;
+ xcb_intern_atom_cookie_t ck;
+} d_atom_query_t;
+
+#define setup_extension(name) \
+ xcb_##name##_query_version_cookie_t ck_##name;
+
+#define find_extension_xfixes(dpy) &dpy->xfixes;
+#define find_extension_render(dpy) &dpy->render;
+#define find_extension_composite(dpy) &dpy->composite;
+#define find_extension_damage(dpy) &dpy->damage;
+
+#define version_extension_xfixes \
+ XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MAJOR_VERSION
+#define version_extension_render \
+ XCB_RENDER_MAJOR_VERSION, XCB_RENDER_MAJOR_VERSION
+#define version_extension_composite \
+ XCB_COMPOSITE_MAJOR_VERSION, XCB_COMPOSITE_MAJOR_VERSION
+#define version_extension_damage \
+ XCB_DAMAGE_MAJOR_VERSION, XCB_DAMAGE_MAJOR_VERSION
+
+#define query_extension(dpy, name) \
+{ \
+ const xcb_query_extension_reply_t *rep; \
+ d_display_ext_t *ext; \
+\
+ xcb_prefetch_extension_data(dpy->conn, &xcb_##name##_id); \
+ rep = xcb_get_extension_data(dpy->conn, &xcb_##name##_id); \
+\
+ ext = find_extension_##name(dpy) \
+ ext->present = rep && rep->present; \
+ ext->error = rep ? rep->first_error : 0; \
+ ext->event = rep ? rep->first_event : 0; \
+ ext->opcode = rep ? rep->major_opcode : 0; \
+\
+ if (ext->present) \
+ ck_##name = xcb_##name##_query_version(dpy->conn, \
+ version_extension_##name); \
+}
+
+#define reply_extension(dpy, name) \
+{ \
+ xcb_##name##_query_version_reply_t *rep; \
+ d_display_ext_t *ext; \
+\
+ ext = find_extension_##name(dpy) \
+ if (ext->present) { \
+ rep = xcb_##name##_query_version_reply(dpy->conn, ck_##name, NULL); \
+ if (rep) { \
+ ext->major_version = rep->major_version; \
+ ext->minor_version = rep->minor_version; \
+ free(rep); \
+ } \
+ else { \
+ printf("error querying the %s extension's version\n", "##name##");\
+ ext->present = FALSE; \
+ } \
+ } \
+}
+
+static void
+query_atom(d_display_t *dpy, d_atom_query_t *q)
+{
+ q->ck = xcb_intern_atom(dpy->conn, FALSE, strlen(q->name), q->name);
+}
+
static void
-query_extensions(d_display_t *dpy)
+reply_atom(d_display_t *dpy, d_atom_query_t *q)
{
- xcb_xfixes_query_version_cookie_t fixes_version_cookie;
- xcb_render_query_version_cookie_t render_version_cookie;
- xcb_composite_query_version_cookie_t composite_version_cookie;
- xcb_damage_query_version_cookie_t damage_version_cookie;
- xcb_render_query_pict_formats_cookie_t render_formats_cookie;
-
- const xcb_query_extension_reply_t *rep;
-
- xcb_prefetch_extension_data(dpy->conn, &xcb_xfixes_id);
- xcb_prefetch_extension_data(dpy->conn, &xcb_render_id);
- xcb_prefetch_extension_data(dpy->conn, &xcb_composite_id);
- xcb_prefetch_extension_data(dpy->conn, &xcb_damage_id);
-
- rep = xcb_get_extension_data(dpy->conn, &xcb_xfixes_id);
- dpy->xfixes = rep && rep->present;
- dpy->xfixes_error = rep && rep->first_error;
- dpy->xfixes_event = rep && rep->first_event;
- dpy->xfixes_opcode = rep && rep->major_opcode;
-
- rep = xcb_get_extension_data(dpy->conn, &xcb_render_id);
- dpy->render = rep && rep->present;
- dpy->render_error = rep && rep->first_error;
- dpy->render_event = rep && rep->first_event;
- dpy->render_opcode = rep && rep->major_opcode;
-
- rep = xcb_get_extension_data(dpy->conn, &xcb_composite_id);
- dpy->composite = rep && rep->present;
- dpy->composite_error = rep && rep->first_error;
- dpy->composite_event = rep && rep->first_event;
- dpy->composite_opcode = rep && rep->major_opcode;
-
- rep = xcb_get_extension_data(dpy->conn, &xcb_damage_id);
- dpy->damage = rep && rep->present;
- dpy->damage_error = rep && rep->first_error;
- dpy->damage_event = rep && rep->first_event;
- dpy->damage_opcode = rep && rep->major_opcode;
+ xcb_intern_atom_reply_t *rep;
+ rep = xcb_intern_atom_reply(dpy->conn, q->ck, NULL);
+ if (rep) {
+ *q->atom = rep->atom;
+ free(rep);
+ }
+ else {
+ printf("unable to query atom %s\n", q->name);
+ *q->atom = 0;
+ }
}
+static void
+query_statics(d_display_t *dpy)
+{
+ d_atom_query_t atoms[] = {
+ { .atom = &dpy->a.utf8_string,
+ .name = "UTF8_STRING" },
+ { .atom = &dpy->a.net_wm_window_type,
+ .name = "_NET_WM_WINDOW_TYPE" },
+ { .atom = &dpy->a.net_wm_window_type_desktop,
+ .name = "_NET_WM_WINDOW_TYPE_DESKTOP" },
+ { .atom = &dpy->a.net_wm_window_type_dock,
+ .name = "_NET_WM_WINDOW_TYPE_DOCK" },
+ { .atom = &dpy->a.net_wm_window_type_normal,
+ .name = "_NET_WM_WINDOW_TYPE_NORMAL" },
+ { .atom = &dpy->a.net_wm_window_type_dialog,
+ .name = "_NET_WM_WINDOW_TYPE_DIALOG" },
+ { .atom = &dpy->a.net_wm_window_type_toolbar,
+ .name = "_NET_WM_WINDOW_TYPE_TOOLBAR" },
+ { .atom = &dpy->a.net_wm_window_type_menu,
+ .name = "_NET_WM_WINDOW_TYPE_MENU" },
+ { .atom = &dpy->a.net_wm_window_type_utility,
+ .name = "_NET_WM_WINDOW_TYPE_UTILITY" },
+ { .atom = &dpy->a.net_wm_window_type_splash,
+ .name = "_NET_WM_WINDOW_TYPE_SPLAH" },
+ { .atom = &dpy->a.net_wm_window_type_tooltip,
+ .name = "_NET_WM_WINDOW_TYPE_TOOLTIP" },
+ { .atom = &dpy->a.net_wm_window_type_combo,
+ .name = "_NET_WM_WINDOW_TYPE_COMBO" },
+ { .atom = &dpy->a.net_wm_window_type_dropdown_menu,
+ .name = "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU" },
+ { .atom = &dpy->a.net_wm_window_type_popup_menu,
+ .name = "_NET_WM_WINDOW_TYPE_POPUP_MENU" },
+ { .atom = &dpy->a.net_wm_window_type_notification,
+ .name = "_NET_WM_WINDOW_TYPE_NOTIFICATION" },
+ { .atom = NULL }
+ };
+ int i;
+ setup_extension(xfixes);
+ setup_extension(render);
+ setup_extension(composite);
+ setup_extension(damage);
+
+ query_extension(dpy, xfixes);
+ query_extension(dpy, render);
+ query_extension(dpy, composite);
+ query_extension(dpy, damage);
+
+ for (i = 0; atoms[i].atom != NULL; ++i)
+ query_atom(dpy, &atoms[i]);
+
+ xcb_flush(dpy->conn);
+
+ reply_extension(dpy, xfixes);
+ reply_extension(dpy, render);
+ reply_extension(dpy, composite);
+ reply_extension(dpy, damage);
+
+ for (i = 0; atoms[i].atom != NULL; ++i)
+ reply_atom(dpy, &atoms[i]);
+
+ /* hard-coded ones, you can't request these */
+ dpy->a.atom = 4;
+ dpy->a.cardinal = 6;
+ dpy->a.pixmap = 20;
+ dpy->a.string = 31;
+}
d_display_t*
display_open(const char *name)
xcb_connection_t *conn;
conn = xcb_connect(name, NULL);
- if (conn) {
+ if (conn && !xcb_connection_has_error(conn)) {
dpy = malloc(sizeof(d_display_t));
dpy->conn = conn;
dpy->ref = 1;
+ dpy->fd = xcb_get_file_descriptor(conn);
+ dpy->screens = list_new();
- query_extensions(dpy);
+ query_statics(dpy);
}
return dpy;
}
display_unref(d_display_t *dpy)
{
if (dpy && --dpy->ref == 0) {
+ d_list_it_t *it;
+
+ for (it = list_top(dpy->screens); it; it = it->next)
+ screen_unref(it->data);
+ list_unref(dpy->screens);
+
xcb_disconnect(dpy->conn);
free(dpy);
}
default: break;
}
if (!name)
- switch (ev->error_code - dpy->xfixes_error) {
+ switch (ev->error_code - dpy->xfixes.error) {
case XCB_XFIXES_BAD_REGION: name = "BadRegion"; break;
default: break;
}
if (!name)
- switch (ev->error_code - dpy->damage_error) {
+ switch (ev->error_code - dpy->damage.error) {
case XCB_DAMAGE_BAD_DAMAGE: name = "BadDamage"; break;
default: break;
}
if (!name)
- switch (ev->error_code - dpy->render_error) {
+ switch (ev->error_code - dpy->render.error) {
case XCB_RENDER_PICT_FORMAT: name = "BadPictFormat"; break;
case XCB_RENDER_PICT_OP: name = "BadPictOp"; break;
case XCB_RENDER_PICTURE: name = "BadPicture"; break;
default: break;
}
+ req = NULL;
if (major_opcode <= 127)
switch (major_opcode) {
case 1: req = "CreateWindow"; break;
case 72: req = "PutImage"; break;
default: break;
}
+ else if (major_opcode == dpy->damage.opcode)
+ switch (minor_opcode)
+ {
+ case 0: req = "DamageQueryVersion"; break;
+ case 1: req = "DamageCreate"; break;
+ case 2: req = "DamageDestroy"; break;
+ case 3: req = "DamageSubtract"; break;
+ default: break;
+ }
+ else if (major_opcode == dpy->render.opcode)
+ switch (minor_opcode)
+ {
+ case 0: req = "RenderQueryVersion"; break;
+ case 1: req = "RenderQueryPictFormats"; break;
+ case 2: req = "RenderQueryPictIndexValues"; break;
+ case 4: req = "RenderCreatePicture"; break;
+ case 5: req = "RenderChangePicture"; break;
+ case 6: req = "RenderSetPictureClipRectangles"; break;
+ case 7: req = "RenderFreePicture"; break;
+ case 8: req = "RenderComposite"; break;
+ case 10: req = "RenderCompositeTrapezoids"; break;
+ case 11: req = "RenderCompositeTriangles"; break;
+ case 12: req = "RenderCompositeTriStrip"; break;
+ case 13: req = "RenderCompositeTriFan"; break;
+ case 17: req = "RenderCreateGlyphSet"; break;
+ case 18: req = "RenderReferenceGlyphSet"; break;
+ case 19: req = "RenderFreeGlyphSet"; break;
+ case 20: req = "RenderAddGlyphs"; break;
+ case 22: req = "RenderFreeGlyphs"; break;
+ case 23: req = "RenderCompositeGlyphs8"; break;
+ case 24: req = "RenderCompositeGlyphs16"; break;
+ case 25: req = "RenderCompositeGlyphs32"; break;
+ case 26: req = "RenderFillRectangles"; break;
+ case 27: req = "RenderCreateCursor"; break;
+ case 28: req = "RenderSetPictureTransform"; break;
+ case 29: req = "RenderQueryFilters"; break;
+ case 30: req = "RenderSetPictureFilter"; break;
+ case 31: req = "RenderCreateAnimCursor"; break;
+ case 32: req = "RenderAddTraps"; break;
+ case 33: req = "RenderCreateSolidFill"; break;
+ case 34: req = "RenderLinearGradient"; break;
+ case 35: req = "RenderRadialGradient"; break;
+ case 36: req = "RenderConicalGradient"; break;
+ default: break;
+ }
+ else if (major_opcode == dpy->composite.opcode)
+ switch (minor_opcode)
+ {
+ case 0: req = "CompositeQueryVersion"; break;
+ case 1: req = "CompositeRedirectWindow"; break;
+ case 2: req = "CompositeRedirectSubwindows"; break;
+ case 3: req = "CompositeUnredirectWindow"; break;
+ case 4: req = "CompositeUnredirectSubwindows"; break;
+ case 5: req = "CompositeCreateRegionFromBorderClip"; break;
+ case 6: req = "CompositeNameWindowPixmap"; break;
+ case 7: req = "CompositeGetOverlayWindow"; break;
+ case 8: req = "CompositeReleaseOverlayWindow"; break;
+ default: break;
+ }
if (name && req)
printf("XError: %s %s!\n",
printf("XError: code %d major opcode %d minor opcode %d!\n",
ev->error_code, major_opcode, minor_opcode);
- abort();
+ //abort();
+}
+
+int
+display_claim_screens(d_display_t *dpy)
+{
+ static const xcb_setup_t *setup;
+ xcb_screen_iterator_t it;
+ int i;
+ d_screen_t *sc;
+
+ setup = xcb_get_setup(dpy->conn);
+
+ i = 0;
+ for (it = xcb_setup_roots_iterator(setup); it.rem; xcb_screen_next(&it)) {
+ sc = screen_new(dpy, i++, it.data);
+ if (screen_register(sc)) {
+ list_append(dpy->screens, sc);
+ printf(_("managing screen %d\n"), sc->num);
+ }
+ else
+ screen_unref(sc);
+ }
+ return list_length(dpy->screens);
+}
+
+d_screen_t*
+display_screen_from_root(d_display_t *dpy, xcb_window_t root)
+{
+ d_list_it_t *it;
+
+ for (it = list_top(dpy->screens); it; it = it->next) {
+ d_screen_t *sc = it->data;
+ if (sc->super.root == root)
+ return sc;
+ }
+ assert(0);
+ return NULL;
}