Make i3 compatible with the very latest xcb

This involves:
 • Compiling with xcb-util instead of xcb-{atom,aux} (they merged the libraries)
 • Not using xcb-{event,property} anymore (code removed upstream)
 • Not using the predefined WINDOW, CARDINEL, … atoms (removed upstream)
 • Using the new xcb_icccm_* data types/functions instead of just xcb_*
   (for example xcb_icccm_get_wm_hints instead of xcb_get_wm_hints)

Also I refactored the atoms to use x-macros.
This commit is contained in:
Michael Stapelberg 2011-03-18 14:36:36 +01:00
parent 36664c6289
commit 0639a7d95b
20 changed files with 336 additions and 229 deletions

View File

@ -11,6 +11,10 @@ endif
GIT_VERSION:="$(shell git describe --tags --always) ($(shell git log --pretty=format:%cd --date=short -n1), branch $(shell [ -f .git/HEAD ] && sed 's/ref: refs\/heads\/\(.*\)/\\\\\\"\1\\\\\\"/g' .git/HEAD || echo 'unknown'))"
VERSION:=$(shell git describe --tags --abbrev=0)
ifeq ($(shell which pkg-config 2>/dev/null 1>/dev/null || echo 1),1)
$(error "pkg-config was not found")
endif
# An easier way to get CFLAGS and LDFLAGS falling back in case there's
# no pkg-config support for certain libraries
cflags_for_lib = $(shell pkg-config --silence-errors --cflags $(1))
@ -24,11 +28,14 @@ CFLAGS += -Wall
CFLAGS += -Wunused-value
CFLAGS += -Iinclude
CFLAGS += -I/usr/local/include
CFLAGS += $(call cflags_for_lib, xcb-event)
CFLAGS += $(call cflags_for_lib, xcb-property)
CFLAGS += $(call cflags_for_lib, xcb-keysyms)
ifeq ($(shell pkg-config --exists xcb-util || echo 1),1)
CFLAGS += -DXCB_COMPAT
CFLAGS += $(call cflags_for_lib, xcb-atom)
CFLAGS += $(call cflags_for_lib, xcb-aux)
else
CFLAGS += $(call cflags_for_lib, xcb-util)
endif
CFLAGS += $(call cflags_for_lib, xcb-icccm)
CFLAGS += $(call cflags_for_lib, xcb-xinerama)
CFLAGS += $(call cflags_for_lib, xcb-randr)
@ -44,8 +51,12 @@ LDFLAGS += -lm
LDFLAGS += $(call ldflags_for_lib, xcb-event, xcb-event)
LDFLAGS += $(call ldflags_for_lib, xcb-property, xcb-property)
LDFLAGS += $(call ldflags_for_lib, xcb-keysyms, xcb-keysyms)
ifeq ($(shell pkg-config --exists xcb-util || echo 1),1)
LDFLAGS += $(call ldflags_for_lib, xcb-atom, xcb-atom)
LDFLAGS += $(call ldflags_for_lib, xcb-aux, xcb-aux)
else
LDFLAGS += $(call ldflags_for_lib, xcb-util)
endif
LDFLAGS += $(call ldflags_for_lib, xcb-icccm, xcb-icccm)
LDFLAGS += $(call ldflags_for_lib, xcb-xinerama, xcb-xinerama)
LDFLAGS += $(call ldflags_for_lib, xcb-randr, xcb-randr)

View File

@ -26,10 +26,14 @@
#include <xcb/xcb.h>
#include <xcb/xcb_aux.h>
#include <xcb/xcb_event.h>
#include <xcb/xcb_keysyms.h>
#include <xcb/xcb_icccm.h>
/* Contains compatibility definitions for old libxcb versions */
#ifdef XCB_COMPAT
#include "xcb_compat.h"
#endif
#include "util.h"
#include "ipc.h"
#include "tree.h"

31
include/atoms.xmacro Normal file
View File

@ -0,0 +1,31 @@
xmacro(_NET_SUPPORTED)
xmacro(_NET_SUPPORTING_WM_CHECK)
xmacro(_NET_WM_NAME)
xmacro(_NET_WM_STATE_FULLSCREEN)
xmacro(_NET_WM_STATE)
xmacro(_NET_WM_WINDOW_TYPE)
xmacro(_NET_WM_WINDOW_TYPE_DOCK)
xmacro(_NET_WM_WINDOW_TYPE_DIALOG)
xmacro(_NET_WM_WINDOW_TYPE_UTILITY)
xmacro(_NET_WM_WINDOW_TYPE_TOOLBAR)
xmacro(_NET_WM_WINDOW_TYPE_SPLASH)
xmacro(_NET_WM_DESKTOP)
xmacro(_NET_WM_STRUT_PARTIAL)
xmacro(WM_PROTOCOLS)
xmacro(WM_DELETE_WINDOW)
xmacro(UTF8_STRING)
xmacro(WM_STATE)
xmacro(WM_CLIENT_LEADER)
xmacro(_NET_CURRENT_DESKTOP)
xmacro(_NET_ACTIVE_WINDOW)
xmacro(_NET_WORKAREA)
xmacro(WM_TAKE_FOCUS)
xmacro(WM_HINTS)
xmacro(WM_NORMAL_HINTS)
xmacro(WM_TRANSIENT_FOR)
xmacro(ATOM)
xmacro(WINDOW)
xmacro(WM_NAME)
xmacro(WM_CLASS)
xmacro(STRING)
xmacro(CARDINAL)

View File

@ -7,7 +7,6 @@
* include/data.h: This file defines all data structures used by i3
*
*/
#include <xcb/xcb.h>
#include <xcb/randr.h>
#include <xcb/xcb_atom.h>
#include <stdbool.h>

View File

@ -13,9 +13,24 @@
#include <xcb/randr.h>
extern int randr_base;
void add_ignore_event(const int sequence);
/**
* Takes an xcb_generic_event_t and calls the appropriate handler, based on the
* event type.
*
*/
void handle_event(int type, xcb_generic_event_t *event);
/**
* Sets the appropriate atoms for the property handlers after the atoms were
* received from X11
*
*/
void property_handlers_init();
/**
* There was a key press. We compare this key code with our bindings table and
* pass the bound action to parse_command().

View File

@ -8,9 +8,6 @@
* See file LICENSE for license information.
*
*/
#include <xcb/xcb.h>
#include <xcb/xcb_property.h>
#include <xcb/xcb_event.h>
#include <xcb/xcb_keysyms.h>
#include <X11/XKBlib.h>
@ -31,11 +28,8 @@ extern TAILQ_HEAD(bindings_head, Binding) *bindings;
extern TAILQ_HEAD(autostarts_head, Autostart) autostarts;
extern TAILQ_HEAD(assignments_head, Assignment) assignments;
extern SLIST_HEAD(stack_wins_head, Stack_Window) stack_wins;
extern xcb_event_handlers_t evenths;
extern xcb_property_handlers_t prophs;
extern uint8_t root_depth;
extern bool xcursor_supported, xkb_supported;
extern xcb_atom_t atoms[NUM_ATOMS];
extern xcb_window_t root;
#endif

View File

@ -8,7 +8,6 @@
* See file LICENSE for license information.
*
*/
#include <xcb/xcb.h>
#include "data.h"

View File

@ -8,7 +8,6 @@
* See file LICENSE for license information.
*
*/
#include <xcb/xcb.h>
#include <err.h>
#include "data.h"

View File

@ -8,7 +8,6 @@
* See file LICENSE for license information.
*
*/
#include <xcb/xcb.h>
#include "data.h"
#include "tree.h"

View File

@ -44,32 +44,9 @@
XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | /* …subwindows get notifies */ \
XCB_EVENT_MASK_ENTER_WINDOW) /* …user moves cursor inside our window */
enum {
_NET_SUPPORTED = 0,
_NET_SUPPORTING_WM_CHECK,
_NET_WM_NAME,
_NET_WM_STATE_FULLSCREEN,
_NET_WM_STATE,
_NET_WM_WINDOW_TYPE,
_NET_WM_WINDOW_TYPE_DOCK,
_NET_WM_WINDOW_TYPE_DIALOG,
_NET_WM_WINDOW_TYPE_UTILITY,
_NET_WM_WINDOW_TYPE_TOOLBAR,
_NET_WM_WINDOW_TYPE_SPLASH,
_NET_WM_DESKTOP,
_NET_WM_STRUT_PARTIAL,
WM_PROTOCOLS,
WM_DELETE_WINDOW,
UTF8_STRING,
WM_STATE,
WM_CLIENT_LEADER,
_NET_CURRENT_DESKTOP,
_NET_ACTIVE_WINDOW,
_NET_WORKAREA,
WM_TAKE_FOCUS,
NUM_ATOMS
};
#define xmacro(atom) xcb_atom_t A_ ## atom;
#include "atoms.xmacro"
#undef xmacro
extern unsigned int xcb_numlock_mask;

24
include/xcb_compat.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef _XCB_COMPAT_H
#define _XCB_COMPAT_H
#define xcb_icccm_get_wm_protocols_reply_t xcb_get_wm_protocols_reply_t
#define xcb_icccm_get_wm_protocols_unchecked xcb_get_wm_protocols_unchecked
#define xcb_icccm_get_wm_protocols_reply xcb_get_wm_protocols_reply
#define xcb_icccm_get_wm_protocols_reply_wipe xcb_get_wm_protocols_reply_wipe
#define XCB_ICCCM_WM_STATE_NORMAL XCB_WM_STATE_NORMAL
#define XCB_ICCCM_WM_STATE_WITHDRAWN XCB_WM_STATE_WITHDRAWN
#define xcb_icccm_get_wm_size_hints_from_reply xcb_get_wm_size_hints_from_reply
#define xcb_icccm_get_wm_normal_hints_reply xcb_get_wm_normal_hints_reply
#define xcb_icccm_get_wm_normal_hints_unchecked xcb_get_wm_normal_hints_unchecked
#define XCB_ICCCM_SIZE_HINT_P_MIN_SIZE XCB_SIZE_HINT_P_MIN_SIZE
#define XCB_ICCCM_SIZE_HINT_P_RESIZE_INC XCB_SIZE_HINT_P_RESIZE_INC
#define XCB_ICCCM_SIZE_HINT_BASE_SIZE XCB_SIZE_HINT_BASE_SIZE
#define XCB_ICCCM_SIZE_HINT_P_ASPECT XCB_SIZE_HINT_P_ASPECT
#define xcb_icccm_wm_hints_t xcb_wm_hints_t
#define xcb_icccm_get_wm_hints_from_reply xcb_get_wm_hints_from_reply
#define xcb_icccm_get_wm_hints_reply xcb_get_wm_hints_reply
#define xcb_icccm_get_wm_hints_unchecked xcb_get_wm_hints_unchecked
#define xcb_icccm_wm_hints_get_urgency xcb_wm_hints_get_urgency
#define xcb_icccm_get_wm_transient_for_from_reply xcb_get_wm_transient_for_from_reply
#endif

View File

@ -504,10 +504,10 @@ void con_toggle_fullscreen(Con *con) {
unsigned int num = 0;
if (con->fullscreen_mode != CF_NONE)
values[num++] = atoms[_NET_WM_STATE_FULLSCREEN];
values[num++] = A__NET_WM_STATE_FULLSCREEN;
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, con->window->id,
atoms[_NET_WM_STATE], ATOM, 32, num, values);
A__NET_WM_STATE, A_ATOM, 32, num, values);
}
/*

View File

@ -31,7 +31,7 @@ void ewmh_update_current_desktop() {
TAILQ_FOREACH(ws, &(output_get_content(output)->nodes_head), nodes) {
if (ws == focused_ws) {
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root,
atoms[_NET_CURRENT_DESKTOP], CARDINAL, 32, 1, &idx);
A__NET_CURRENT_DESKTOP, A_CARDINAL, 32, 1, &idx);
return;
}
++idx;
@ -48,7 +48,7 @@ void ewmh_update_current_desktop() {
*/
void ewmh_update_active_window(xcb_window_t window) {
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root,
atoms[_NET_ACTIVE_WINDOW], WINDOW, 32, 1, &window);
A__NET_ACTIVE_WINDOW, A_WINDOW, 32, 1, &window);
}
/*
@ -104,7 +104,7 @@ void ewmh_update_workarea() {
}
}
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root,
atoms[_NET_WORKAREA], CARDINAL, 32,
A__NET_WORKAREA, A_CARDINAL, 32,
num_workspaces * (sizeof(Rect) / sizeof(uint32_t)),
workarea);
free(workarea);

View File

@ -374,19 +374,15 @@ void drag_pointer(Con *con, xcb_button_press_event_t *event, xcb_window_t
while ((inside_event = xcb_wait_for_event(conn))) {
/* We now handle all events we can get using xcb_poll_for_event */
do {
/* Same as get_event_handler in xcb */
int nr = inside_event->response_type;
if (nr == 0) {
/* An error occured */
//handle_event(NULL, conn, inside_event);
/* skip x11 errors */
if (inside_event->response_type == 0) {
free(inside_event);
continue;
}
assert(nr < 256);
nr &= XCB_EVENT_RESPONSE_TYPE_MASK;
assert(nr >= 2);
/* Strip off the highest bit (set if the event is generated) */
int type = (inside_event->response_type & 0x7F);
switch (nr) {
switch (type) {
case XCB_BUTTON_RELEASE:
goto done;
@ -398,13 +394,13 @@ void drag_pointer(Con *con, xcb_button_press_event_t *event, xcb_window_t
case XCB_UNMAP_NOTIFY:
DLOG("Unmap-notify, aborting\n");
xcb_event_handle(&evenths, inside_event);
handle_event(type, inside_event);
goto done;
default:
DLOG("Passing to original handler\n");
/* Use original handler */
xcb_event_handle(&evenths, inside_event);
handle_event(type, inside_event);
break;
}
if (last_motion_notify != inside_event)

View File

@ -6,14 +6,19 @@
*
*/
#include <time.h>
#include <limits.h>
#include <xcb/xcb_atom.h>
#include <xcb/randr.h>
#include <X11/XKBlib.h>
#include "all.h"
int randr_base = -1;
/* forward declaration for property_notify */
static int property_notify(uint8_t state, xcb_window_t window, xcb_atom_t atom);
/* After mapping/unmapping windows, a notify event is generated. However, we dont want it,
since itd trigger an infinite loop of switching between the different windows when
changing workspaces */
@ -59,6 +64,143 @@ static bool event_is_ignored(const int sequence) {
return false;
}
/*
* Takes an xcb_generic_event_t and calls the appropriate handler, based on the
* event type.
*
*/
void handle_event(int type, xcb_generic_event_t *event) {
/* XXX: remove the NULL and conn parameters as soon as this version of libxcb is required */
if (randr_base > -1 &&
type == randr_base + XCB_RANDR_SCREEN_CHANGE_NOTIFY) {
handle_screen_change(NULL, conn, event);
return;
}
switch (type) {
case XCB_KEY_PRESS:
handle_key_press(NULL, conn, (xcb_key_press_event_t*)event);
break;
case XCB_BUTTON_PRESS:
handle_button_press(NULL, conn, (xcb_button_press_event_t*)event);
break;
case XCB_MAP_REQUEST:
handle_map_request(NULL, conn, (xcb_map_request_event_t*)event);
break;
case XCB_UNMAP_NOTIFY:
handle_unmap_notify_event(NULL, conn, (xcb_unmap_notify_event_t*)event);
break;
case XCB_DESTROY_NOTIFY:
handle_destroy_notify_event(NULL, conn, (xcb_destroy_notify_event_t*)event);
break;
case XCB_EXPOSE:
handle_expose_event(NULL, conn, (xcb_expose_event_t*)event);
break;
case XCB_MOTION_NOTIFY:
handle_motion_notify(NULL, conn, (xcb_motion_notify_event_t*)event);
break;
/* Enter window = user moved his mouse over the window */
case XCB_ENTER_NOTIFY:
handle_enter_notify(NULL, conn, (xcb_enter_notify_event_t*)event);
break;
/* Client message are sent to the root window. The only interesting
* client message for us is _NET_WM_STATE, we honour
* _NET_WM_STATE_FULLSCREEN */
case XCB_CLIENT_MESSAGE:
handle_client_message(NULL, conn, (xcb_client_message_event_t*)event);
break;
/* Configure request = window tried to change size on its own */
case XCB_CONFIGURE_REQUEST:
handle_configure_request(NULL, conn, (xcb_configure_request_event_t*)event);
break;
/* Mapping notify = keyboard mapping changed (Xmodmap), re-grab bindings */
case XCB_MAPPING_NOTIFY:
handle_mapping_notify(NULL, conn, (xcb_mapping_notify_event_t*)event);
break;
case XCB_PROPERTY_NOTIFY:
DLOG("Property notify\n");
xcb_property_notify_event_t *e = (xcb_property_notify_event_t*)event;
property_notify(e->state, e->window, e->atom);
break;
default:
DLOG("Unhandled event of type %d\n", type);
break;
}
}
typedef int (*cb_property_handler_t)(void *data, xcb_connection_t *c, uint8_t state, xcb_window_t window, xcb_atom_t atom, xcb_get_property_reply_t *property);
struct property_handler_t {
xcb_atom_t atom;
uint32_t long_len;
cb_property_handler_t cb;
};
static struct property_handler_t property_handlers[] = {
{ 0, 128, handle_windowname_change },
{ 0, UINT_MAX, handle_hints },
{ 0, 128, handle_windowname_change_legacy },
{ 0, UINT_MAX, handle_normal_hints },
{ 0, UINT_MAX, handle_clientleader_change },
{ 0, UINT_MAX, handle_transient_for }
};
#define NUM_HANDLERS (sizeof(property_handlers) / sizeof(struct property_handler_t))
/*
* Sets the appropriate atoms for the property handlers after the atoms were
* received from X11
*
*/
void property_handlers_init() {
property_handlers[0].atom = A__NET_WM_NAME;
property_handlers[1].atom = A_WM_HINTS;
property_handlers[2].atom = A_WM_NAME;
property_handlers[3].atom = A_WM_NORMAL_HINTS;
property_handlers[4].atom = A_WM_CLIENT_LEADER;
property_handlers[5].atom = A_WM_TRANSIENT_FOR;
}
static int property_notify(uint8_t state, xcb_window_t window, xcb_atom_t atom) {
struct property_handler_t *handler = NULL;
xcb_get_property_reply_t *propr = NULL;
int ret;
for (int c = 0; c < sizeof(property_handlers) / sizeof(struct property_handler_t); c++) {
if (property_handlers[c].atom != atom)
continue;
handler = &property_handlers[c];
break;
}
if (handler == NULL) {
DLOG("Unhandled property notify for atom %d (0x%08x)\n", atom, atom);
return 0;
}
if (state != XCB_PROPERTY_DELETE) {
xcb_get_property_cookie_t cookie = xcb_get_property(conn, 0, window, atom, XCB_GET_PROPERTY_TYPE_ANY, 0, handler->long_len);
propr = xcb_get_property_reply(conn, cookie, 0);
}
ret = handler->cb(NULL, conn, state, window, atom, propr);
FREE(propr);
return ret;
}
/*
* There was a key press. We compare this key code with our bindings table and pass
* the bound action to parse_command().
@ -627,10 +769,10 @@ int handle_expose_event(void *data, xcb_connection_t *conn, xcb_expose_event_t *
*/
int handle_client_message(void *data, xcb_connection_t *conn, xcb_client_message_event_t *event) {
LOG("ClientMessage for window 0x%08x\n", event->window);
if (event->type == atoms[_NET_WM_STATE]) {
if (event->format != 32 || event->data.data32[1] != atoms[_NET_WM_STATE_FULLSCREEN]) {
if (event->type == A__NET_WM_STATE) {
if (event->format != 32 || event->data.data32[1] != A__NET_WM_STATE_FULLSCREEN) {
DLOG("atom in clientmessage is %d, fullscreen is %d\n",
event->data.data32[1], atoms[_NET_WM_STATE_FULLSCREEN]);
event->data.data32[1], A__NET_WM_STATE_FULLSCREEN);
DLOG("not about fullscreen atom\n");
return 0;
}
@ -693,17 +835,17 @@ int handle_normal_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_w
/* If the hints were already in this event, use them, if not, request them */
if (reply != NULL)
xcb_get_wm_size_hints_from_reply(&size_hints, reply);
xcb_icccm_get_wm_size_hints_from_reply(&size_hints, reply);
else
xcb_get_wm_normal_hints_reply(conn, xcb_get_wm_normal_hints_unchecked(conn, con->window->id), &size_hints, NULL);
xcb_icccm_get_wm_normal_hints_reply(conn, xcb_icccm_get_wm_normal_hints_unchecked(conn, con->window->id), &size_hints, NULL);
if ((size_hints.flags & XCB_SIZE_HINT_P_MIN_SIZE)) {
if ((size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE)) {
// TODO: Minimum size is not yet implemented
DLOG("Minimum size: %d (width) x %d (height)\n", size_hints.min_width, size_hints.min_height);
}
bool changed = false;
if ((size_hints.flags & XCB_SIZE_HINT_P_RESIZE_INC)) {
if ((size_hints.flags & XCB_ICCCM_SIZE_HINT_P_RESIZE_INC)) {
if (size_hints.width_inc > 0 && size_hints.width_inc < 0xFFFF)
if (con->width_increment != size_hints.width_inc) {
con->width_increment = size_hints.width_inc;
@ -724,10 +866,10 @@ int handle_normal_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_w
/* base_width/height are the desired size of the window.
We check if either the program-specified size or the program-specified
min-size is available */
if (size_hints.flags & XCB_SIZE_HINT_BASE_SIZE) {
if (size_hints.flags & XCB_ICCCM_SIZE_HINT_BASE_SIZE) {
base_width = size_hints.base_width;
base_height = size_hints.base_height;
} else if (size_hints.flags & XCB_SIZE_HINT_P_MIN_SIZE) {
} else if (size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) {
/* TODO: is this right? icccm says not */
base_width = size_hints.min_width;
base_height = size_hints.min_height;
@ -742,7 +884,7 @@ int handle_normal_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_w
}
/* If no aspect ratio was set or if it was invalid, we ignore the hints */
if (!(size_hints.flags & XCB_SIZE_HINT_P_ASPECT) ||
if (!(size_hints.flags & XCB_ICCCM_SIZE_HINT_P_ASPECT) ||
(size_hints.min_aspect_num <= 0) ||
(size_hints.min_aspect_den <= 0)) {
goto render_and_return;
@ -788,13 +930,13 @@ int handle_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t
return 1;
}
xcb_wm_hints_t hints;
xcb_icccm_wm_hints_t hints;
if (reply != NULL) {
if (!xcb_get_wm_hints_from_reply(&hints, reply))
if (!xcb_icccm_get_wm_hints_from_reply(&hints, reply))
return 1;
} else {
if (!xcb_get_wm_hints_reply(conn, xcb_get_wm_hints_unchecked(conn, con->window->id), &hints, NULL))
if (!xcb_icccm_get_wm_hints_reply(conn, xcb_icccm_get_wm_hints_unchecked(conn, con->window->id), &hints, NULL))
return 1;
}
@ -804,7 +946,7 @@ int handle_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t
}
/* Update the flag on the client directly */
con->urgent = (xcb_wm_hints_get_urgency(&hints) != 0);
con->urgent = (xcb_icccm_wm_hints_get_urgency(&hints) != 0);
//CLIENT_LOG(con);
LOG("Urgency flag changed to %d\n", con->urgent);
@ -841,7 +983,7 @@ int handle_transient_for(void *data, xcb_connection_t *conn, uint8_t state, xcb_
if (prop == NULL) {
prop = xcb_get_property_reply(conn, xcb_get_property_unchecked(conn,
false, window, WM_TRANSIENT_FOR, WINDOW, 0, 32), NULL);
false, window, A_WM_TRANSIENT_FOR, A_WINDOW, 0, 32), NULL);
if (prop == NULL)
return 1;
}
@ -872,7 +1014,7 @@ int handle_clientleader_change(void *data, xcb_connection_t *conn, uint8_t state
if (prop == NULL) {
prop = xcb_get_property_reply(conn, xcb_get_property_unchecked(conn,
false, window, WM_CLIENT_LEADER, WINDOW, 0, 32), NULL);
false, window, A_WM_CLIENT_LEADER, A_WINDOW, 0, 32), NULL);
if (prop == NULL)
return 1;
}

View File

@ -15,9 +15,6 @@ extern Con *focused;
char **start_argv;
xcb_connection_t *conn;
xcb_event_handlers_t evenths;
xcb_property_handlers_t prophs;
xcb_atom_t atoms[NUM_ATOMS];
xcb_window_t root;
uint8_t root_depth;
@ -66,8 +63,17 @@ static void xcb_check_cb(EV_P_ ev_check *w, int revents) {
xcb_generic_event_t *event;
while ((event = xcb_poll_for_event(conn)) != NULL) {
xcb_event_handle(&evenths, event);
free(event);
if (event->response_type == 0) {
ELOG("X11 Error received! sequence %x\n", event->sequence);
continue;
}
/* Strip off the highest bit (set if the event is generated) */
int type = (event->response_type & 0x7F);
handle_event(type, event);
free(event);
}
}
@ -149,7 +155,6 @@ int main(int argc, char *argv[]) {
bool only_check_config = false;
bool force_xinerama = false;
bool disable_signalhandler = false;
xcb_intern_atom_cookie_t atom_cookies[NUM_ATOMS];
static struct option long_options[] = {
{"no-autostart", no_argument, 0, 'a'},
{"config", required_argument, 0, 'c'},
@ -272,30 +277,10 @@ int main(int argc, char *argv[]) {
check_error(conn, cookie, "Another window manager seems to be running");
/* Place requests for the atoms we need as soon as possible */
#define REQUEST_ATOM(name) atom_cookies[name] = xcb_intern_atom(conn, 0, strlen(#name), #name);
REQUEST_ATOM(_NET_SUPPORTED);
REQUEST_ATOM(_NET_WM_STATE_FULLSCREEN);
REQUEST_ATOM(_NET_SUPPORTING_WM_CHECK);
REQUEST_ATOM(_NET_WM_NAME);
REQUEST_ATOM(_NET_WM_STATE);
REQUEST_ATOM(_NET_WM_WINDOW_TYPE);
REQUEST_ATOM(_NET_WM_DESKTOP);
REQUEST_ATOM(_NET_WM_WINDOW_TYPE_DOCK);
REQUEST_ATOM(_NET_WM_WINDOW_TYPE_DIALOG);
REQUEST_ATOM(_NET_WM_WINDOW_TYPE_UTILITY);
REQUEST_ATOM(_NET_WM_WINDOW_TYPE_TOOLBAR);
REQUEST_ATOM(_NET_WM_WINDOW_TYPE_SPLASH);
REQUEST_ATOM(_NET_WM_STRUT_PARTIAL);
REQUEST_ATOM(WM_PROTOCOLS);
REQUEST_ATOM(WM_DELETE_WINDOW);
REQUEST_ATOM(UTF8_STRING);
REQUEST_ATOM(WM_STATE);
REQUEST_ATOM(WM_CLIENT_LEADER);
REQUEST_ATOM(_NET_CURRENT_DESKTOP);
REQUEST_ATOM(_NET_ACTIVE_WINDOW);
REQUEST_ATOM(_NET_WORKAREA);
REQUEST_ATOM(WM_TAKE_FOCUS);
#define xmacro(atom) \
xcb_intern_atom_cookie_t atom ## _cookie = xcb_intern_atom(conn, 0, strlen(#atom), #atom);
#include "atoms.xmacro"
#undef xmacro
/* Initialize the Xlib connection */
xlibdpy = xkbdpy = XOpenDisplay(NULL);
@ -338,95 +323,32 @@ int main(int argc, char *argv[]) {
}
}
memset(&evenths, 0, sizeof(xcb_event_handlers_t));
memset(&prophs, 0, sizeof(xcb_property_handlers_t));
xcb_event_handlers_init(conn, &evenths);
xcb_property_handlers_init(&prophs, &evenths);
xcb_event_set_key_press_handler(&evenths, handle_key_press, NULL);
xcb_event_set_button_press_handler(&evenths, handle_button_press, NULL);
xcb_event_set_map_request_handler(&evenths, handle_map_request, NULL);
xcb_event_set_unmap_notify_handler(&evenths, handle_unmap_notify_event, NULL);
xcb_event_set_destroy_notify_handler(&evenths, handle_destroy_notify_event, NULL);
xcb_event_set_expose_handler(&evenths, handle_expose_event, NULL);
xcb_event_set_motion_notify_handler(&evenths, handle_motion_notify, NULL);
/* Enter window = user moved his mouse over the window */
xcb_event_set_enter_notify_handler(&evenths, handle_enter_notify, NULL);
/* Client message are sent to the root window. The only interesting client message
for us is _NET_WM_STATE, we honour _NET_WM_STATE_FULLSCREEN */
xcb_event_set_client_message_handler(&evenths, handle_client_message, NULL);
/* Configure request = window tried to change size on its own */
xcb_event_set_configure_request_handler(&evenths, handle_configure_request, NULL);
/* Setup NetWM atoms */
#define GET_ATOM(name) \
#define xmacro(name) \
do { \
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, atom_cookies[name], NULL); \
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, name ## _cookie, NULL); \
if (!reply) { \
ELOG("Could not get atom " #name "\n"); \
exit(-1); \
} \
atoms[name] = reply->atom; \
A_ ## name = reply->atom; \
free(reply); \
} while (0)
} while (0);
#include "atoms.xmacro"
#undef xmacro
GET_ATOM(_NET_SUPPORTED);
GET_ATOM(_NET_WM_STATE_FULLSCREEN);
GET_ATOM(_NET_SUPPORTING_WM_CHECK);
GET_ATOM(_NET_WM_NAME);
GET_ATOM(_NET_WM_STATE);
GET_ATOM(_NET_WM_WINDOW_TYPE);
GET_ATOM(_NET_WM_DESKTOP);
GET_ATOM(_NET_WM_WINDOW_TYPE_DOCK);
GET_ATOM(_NET_WM_WINDOW_TYPE_DIALOG);
GET_ATOM(_NET_WM_WINDOW_TYPE_UTILITY);
GET_ATOM(_NET_WM_WINDOW_TYPE_TOOLBAR);
GET_ATOM(_NET_WM_WINDOW_TYPE_SPLASH);
GET_ATOM(_NET_WM_STRUT_PARTIAL);
GET_ATOM(WM_PROTOCOLS);
GET_ATOM(WM_DELETE_WINDOW);
GET_ATOM(UTF8_STRING);
GET_ATOM(WM_STATE);
GET_ATOM(WM_CLIENT_LEADER);
GET_ATOM(_NET_CURRENT_DESKTOP);
GET_ATOM(_NET_ACTIVE_WINDOW);
GET_ATOM(_NET_WORKAREA);
GET_ATOM(WM_TAKE_FOCUS);
/* Watch _NET_WM_NAME (title of the window encoded in UTF-8) */
xcb_property_set_handler(&prophs, atoms[_NET_WM_NAME], 128, handle_windowname_change, NULL);
/* Watch WM_HINTS (contains the urgent property) */
xcb_property_set_handler(&prophs, WM_HINTS, UINT_MAX, handle_hints, NULL);
/* Watch WM_NAME (title of the window encoded in COMPOUND_TEXT) */
xcb_watch_wm_name(&prophs, 128, handle_windowname_change_legacy, NULL);
/* Watch WM_NORMAL_HINTS (aspect ratio, size increments, …) */
xcb_property_set_handler(&prophs, WM_NORMAL_HINTS, UINT_MAX, handle_normal_hints, NULL);
/* Watch WM_CLIENT_LEADER (= logical parent window for toolbars etc.) */
xcb_property_set_handler(&prophs, atoms[WM_CLIENT_LEADER], UINT_MAX, handle_clientleader_change, NULL);
/* Watch WM_TRANSIENT_FOR property (to which client this popup window belongs) */
xcb_property_set_handler(&prophs, WM_TRANSIENT_FOR, UINT_MAX, handle_transient_for, NULL);
/* Mapping notify = keyboard mapping changed (Xmodmap), re-grab bindings */
xcb_event_set_mapping_notify_handler(&evenths, handle_mapping_notify, NULL);
property_handlers_init();
/* Set up the atoms we support */
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, atoms[_NET_SUPPORTED], ATOM, 32, 7, atoms);
xcb_atom_t supported_atoms[] = {
#define xmacro(atom) A_ ## atom,
#include "atoms.xmacro"
#undef xmacro
};
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, A_ATOM, 32, 7, supported_atoms);
/* Set up the window managers name */
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, atoms[_NET_SUPPORTING_WM_CHECK], WINDOW, 32, 1, &root);
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, atoms[_NET_WM_NAME], atoms[UTF8_STRING], 8, strlen("i3"), "i3");
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTING_WM_CHECK, A_WINDOW, 32, 1, &root);
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_WM_NAME, A_UTF8_STRING, 8, strlen("i3"), "i3");
keysyms = xcb_key_symbols_alloc(conn);
@ -446,17 +368,11 @@ int main(int argc, char *argv[]) {
if (needs_tree_init)
tree_init();
int randr_base;
if (force_xinerama) {
xinerama_init();
} else {
DLOG("Checking for XRandR...\n");
randr_init(&randr_base);
xcb_event_set_handler(&evenths,
randr_base + XCB_RANDR_SCREEN_CHANGE_NOTIFY,
handle_screen_change,
NULL);
}
tree_render();

View File

@ -85,15 +85,6 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
utf8_title_cookie, title_cookie,
class_cookie, leader_cookie, transient_cookie;
wm_type_cookie = xcb_get_any_property_unchecked(conn, false, window, atoms[_NET_WM_WINDOW_TYPE], UINT32_MAX);
strut_cookie = xcb_get_any_property_unchecked(conn, false, window, atoms[_NET_WM_STRUT_PARTIAL], UINT32_MAX);
state_cookie = xcb_get_any_property_unchecked(conn, false, window, atoms[_NET_WM_STATE], UINT32_MAX);
utf8_title_cookie = xcb_get_any_property_unchecked(conn, false, window, atoms[_NET_WM_NAME], 128);
leader_cookie = xcb_get_any_property_unchecked(conn, false, window, atoms[WM_CLIENT_LEADER], UINT32_MAX);
transient_cookie = xcb_get_any_property_unchecked(conn, false, window, WM_TRANSIENT_FOR, UINT32_MAX);
title_cookie = xcb_get_any_property_unchecked(conn, false, window, WM_NAME, 128);
class_cookie = xcb_get_any_property_unchecked(conn, false, window, WM_CLASS, 128);
/* TODO: also get wm_normal_hints here. implement after we got rid of xcb-event */
geomc = xcb_get_geometry(conn, d);
@ -126,6 +117,18 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
goto out;
}
#define GET_PROPERTY(atom, len) xcb_get_property_unchecked(conn, false, window, atom, XCB_GET_PROPERTY_TYPE_ANY, 0, len)
wm_type_cookie = GET_PROPERTY(A__NET_WM_WINDOW_TYPE, UINT32_MAX);
strut_cookie = GET_PROPERTY(A__NET_WM_STRUT_PARTIAL, UINT32_MAX);
state_cookie = GET_PROPERTY(A__NET_WM_STATE, UINT32_MAX);
utf8_title_cookie = GET_PROPERTY(A__NET_WM_NAME, 128);
leader_cookie = GET_PROPERTY(A_WM_CLIENT_LEADER, UINT32_MAX);
transient_cookie = GET_PROPERTY(A_WM_TRANSIENT_FOR, UINT32_MAX);
title_cookie = GET_PROPERTY(A_WM_NAME, 128);
class_cookie = GET_PROPERTY(A_WM_CLASS, 128);
/* TODO: also get wm_normal_hints here. implement after we got rid of xcb-event */
DLOG("reparenting!\n");
uint32_t mask = 0;
uint32_t values[1];
@ -157,7 +160,7 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
Con *search_at = croot;
xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, wm_type_cookie, NULL);
if (xcb_reply_contains_atom(reply, atoms[_NET_WM_WINDOW_TYPE_DOCK])) {
if (xcb_reply_contains_atom(reply, A__NET_WM_WINDOW_TYPE_DOCK)) {
LOG("This window is of type dock\n");
Output *output = get_output_containing(geom->x, geom->y);
if (output != NULL) {
@ -254,10 +257,10 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
/* set floating if necessary */
bool want_floating = false;
if (xcb_reply_contains_atom(reply, atoms[_NET_WM_WINDOW_TYPE_DIALOG]) ||
xcb_reply_contains_atom(reply, atoms[_NET_WM_WINDOW_TYPE_UTILITY]) ||
xcb_reply_contains_atom(reply, atoms[_NET_WM_WINDOW_TYPE_TOOLBAR]) ||
xcb_reply_contains_atom(reply, atoms[_NET_WM_WINDOW_TYPE_SPLASH])) {
if (xcb_reply_contains_atom(reply, A__NET_WM_WINDOW_TYPE_DIALOG) ||
xcb_reply_contains_atom(reply, A__NET_WM_WINDOW_TYPE_UTILITY) ||
xcb_reply_contains_atom(reply, A__NET_WM_WINDOW_TYPE_TOOLBAR) ||
xcb_reply_contains_atom(reply, A__NET_WM_WINDOW_TYPE_SPLASH)) {
LOG("This window is a dialog window, setting floating\n");
want_floating = true;
}
@ -308,7 +311,7 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
xcb_change_window_attributes(conn, window, mask, values);
reply = xcb_get_property_reply(conn, state_cookie, NULL);
if (xcb_reply_contains_atom(reply, atoms[_NET_WM_STATE_FULLSCREEN]))
if (xcb_reply_contains_atom(reply, A__NET_WM_STATE_FULLSCREEN))
con_toggle_fullscreen(nc);
/* Put the client inside the save set. Upon termination (whether killed or

View File

@ -26,12 +26,7 @@
#include <X11/keysym.h>
#include "i3.h"
#include "util.h"
#include "xcb.h"
#include "log.h"
#include "config.h"
#include "randr.h"
#include "all.h"
static xcb_gcontext_t pixmap_gc;
static xcb_pixmap_t pixmap;
@ -159,12 +154,6 @@ void handle_signal(int sig, siginfo_t *info, void *data) {
sigaction(sig, &action, NULL);
raised_signal = sig;
/* setup event handler for key presses */
xcb_event_handlers_t sig_evenths;
memset(&sig_evenths, 0, sizeof(xcb_event_handlers_t));
xcb_event_handlers_init(conn, &sig_evenths);
xcb_event_set_key_press_handler(&sig_evenths, sig_handle_key_press, NULL);
/* width and height of the popup window, so that the text fits in */
int crash_text_num = sizeof(crash_text) / sizeof(char*);
int height = 13 + (crash_text_num * config.font.height);
@ -203,7 +192,16 @@ void handle_signal(int sig, siginfo_t *info, void *data) {
xcb_flush(conn);
}
xcb_event_wait_for_event_loop(&sig_evenths);
xcb_generic_event_t *event;
/* Yay, more own eventhandlers… */
while ((event = xcb_wait_for_event(conn))) {
/* Strip off the highest bit (set if the event is generated) */
int type = (event->response_type & 0x7F);
if (type == XCB_KEY_PRESS) {
sig_handle_key_press(NULL, conn, (xcb_key_press_event_t*)event);
}
free(event);
}
}
/*

View File

@ -136,7 +136,7 @@ void window_update_transient_for(i3Window *win, xcb_get_property_reply_t *prop)
}
xcb_window_t transient_for;
if (!xcb_get_wm_transient_for_from_reply(&transient_for, prop))
if (!xcb_icccm_get_wm_transient_for_from_reply(&transient_for, prop))
return;
DLOG("Transient for changed to %08x\n", transient_for);

28
src/x.c
View File

@ -180,11 +180,11 @@ void x_con_kill(Con *con) {
*/
static bool window_supports_protocol(xcb_window_t window, xcb_atom_t atom) {
xcb_get_property_cookie_t cookie;
xcb_get_wm_protocols_reply_t protocols;
xcb_icccm_get_wm_protocols_reply_t protocols;
bool result = false;
cookie = xcb_get_wm_protocols_unchecked(conn, window, atoms[WM_PROTOCOLS]);
if (xcb_get_wm_protocols_reply(conn, cookie, &protocols, NULL) != 1)
cookie = xcb_icccm_get_wm_protocols_unchecked(conn, window, A_WM_PROTOCOLS);
if (xcb_icccm_get_wm_protocols_reply(conn, cookie, &protocols, NULL) != 1)
return false;
/* Check if the clients protocols have the requested atom set */
@ -192,7 +192,7 @@ static bool window_supports_protocol(xcb_window_t window, xcb_atom_t atom) {
if (protocols.atoms[i] == atom)
result = true;
xcb_get_wm_protocols_reply_wipe(&protocols);
xcb_icccm_get_wm_protocols_reply_wipe(&protocols);
return result;
}
@ -203,7 +203,7 @@ static bool window_supports_protocol(xcb_window_t window, xcb_atom_t atom) {
*/
void x_window_kill(xcb_window_t window) {
/* if this window does not support WM_DELETE_WINDOW, we kill it the hard way */
if (!window_supports_protocol(window, atoms[WM_DELETE_WINDOW])) {
if (!window_supports_protocol(window, A_WM_DELETE_WINDOW)) {
LOG("Killing window the hard way\n");
xcb_kill_client(conn, window);
return;
@ -215,9 +215,9 @@ void x_window_kill(xcb_window_t window) {
ev.response_type = XCB_CLIENT_MESSAGE;
ev.window = window;
ev.type = atoms[WM_PROTOCOLS];
ev.type = A_WM_PROTOCOLS;
ev.format = 32;
ev.data.data32[0] = atoms[WM_DELETE_WINDOW];
ev.data.data32[0] = A_WM_DELETE_WINDOW;
ev.data.data32[1] = XCB_CURRENT_TIME;
LOG("Sending WM_DELETE to the client\n");
@ -389,7 +389,7 @@ static void x_push_node(Con *con) {
DLOG("pushing name %s for con %p\n", state->name, con);
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, con->frame,
WM_NAME, STRING, 8, strlen(state->name), state->name);
A_WM_NAME, A_STRING, 8, strlen(state->name), state->name);
FREE(state->name);
}
@ -468,9 +468,9 @@ static void x_push_node(Con *con) {
if (con->window != NULL) {
/* Set WM_STATE_NORMAL because GTK applications dont want to
* drag & drop if we dont. Also, xprop(1) needs it. */
long data[] = { XCB_WM_STATE_NORMAL, XCB_NONE };
long data[] = { XCB_ICCCM_WM_STATE_NORMAL, XCB_NONE };
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, con->window->id,
atoms[WM_STATE], atoms[WM_STATE], 32, 2, data);
A_WM_STATE, A_WM_STATE, 32, 2, data);
}
if (!state->child_mapped && con->window != NULL) {
@ -528,9 +528,9 @@ static void x_push_node_unmaps(Con *con) {
xcb_void_cookie_t cookie;
if (con->window != NULL) {
/* Set WM_STATE_WITHDRAWN, it seems like Java apps need it */
long data[] = { XCB_WM_STATE_WITHDRAWN, XCB_NONE };
long data[] = { XCB_ICCCM_WM_STATE_WITHDRAWN, XCB_NONE };
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, con->window->id,
atoms[WM_STATE], atoms[WM_STATE], 32, 2, data);
A_WM_STATE, A_WM_STATE, 32, 2, data);
}
cookie = xcb_unmap_window(conn, con->frame);
@ -624,9 +624,9 @@ void x_push_changes(Con *con) {
ev.response_type = XCB_CLIENT_MESSAGE;
ev.window = to_focus;
ev.type = atoms[WM_PROTOCOLS];
ev.type = A_WM_PROTOCOLS;
ev.format = 32;
ev.data.data32[0] = atoms[WM_TAKE_FOCUS];
ev.data.data32[0] = A_WM_TAKE_FOCUS;
ev.data.data32[1] = XCB_CURRENT_TIME;
DLOG("Sending WM_TAKE_FOCUS to the client\n");