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:
parent
f5afe2f67e
commit
86117db434
|
@ -40,8 +40,13 @@ LDFLAGS += -lm
|
||||||
LDFLAGS += -lxcb-event
|
LDFLAGS += -lxcb-event
|
||||||
LDFLAGS += -lxcb-property
|
LDFLAGS += -lxcb-property
|
||||||
LDFLAGS += -lxcb-keysyms
|
LDFLAGS += -lxcb-keysyms
|
||||||
|
ifeq ($(shell pkg-config --exists xcb-util || echo 1),1)
|
||||||
|
CFLAGS += -DXCB_COMPAT
|
||||||
LDFLAGS += -lxcb-atom
|
LDFLAGS += -lxcb-atom
|
||||||
LDFLAGS += -lxcb-aux
|
LDFLAGS += -lxcb-aux
|
||||||
|
else
|
||||||
|
LDFLAGS += -lxcb-util
|
||||||
|
endif
|
||||||
LDFLAGS += -lxcb-icccm
|
LDFLAGS += -lxcb-icccm
|
||||||
LDFLAGS += -lxcb-xinerama
|
LDFLAGS += -lxcb-xinerama
|
||||||
LDFLAGS += -lxcb-randr
|
LDFLAGS += -lxcb-randr
|
||||||
|
|
|
@ -308,13 +308,6 @@ int main(int argc, char *argv[]) {
|
||||||
die("Cannot open display\n");
|
die("Cannot open display\n");
|
||||||
|
|
||||||
/* Set up event handlers for key press and key release */
|
/* Set up event handlers for key press and key release */
|
||||||
xcb_event_handlers_t evenths;
|
|
||||||
memset(&evenths, 0, sizeof(xcb_event_handlers_t));
|
|
||||||
xcb_event_handlers_init(conn, &evenths);
|
|
||||||
xcb_event_set_key_press_handler(&evenths, handle_key_press, NULL);
|
|
||||||
xcb_event_set_key_release_handler(&evenths, handle_key_release, NULL);
|
|
||||||
xcb_event_set_expose_handler(&evenths, handle_expose, NULL);
|
|
||||||
|
|
||||||
modeswitchmask = get_mod_mask(conn, XK_Mode_switch);
|
modeswitchmask = get_mod_mask(conn, XK_Mode_switch);
|
||||||
numlockmask = get_mod_mask(conn, XK_Num_Lock);
|
numlockmask = get_mod_mask(conn, XK_Num_Lock);
|
||||||
symbols = xcb_key_symbols_alloc(conn);
|
symbols = xcb_key_symbols_alloc(conn);
|
||||||
|
@ -362,7 +355,33 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
xcb_flush(conn);
|
xcb_flush(conn);
|
||||||
|
|
||||||
xcb_event_wait_for_event_loop(&evenths);
|
xcb_generic_event_t *event;
|
||||||
|
while ((event = xcb_wait_for_event(conn)) != NULL) {
|
||||||
|
if (event->response_type == 0) {
|
||||||
|
fprintf(stderr, "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);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case XCB_KEY_PRESS:
|
||||||
|
handle_key_press(NULL, conn, (xcb_key_press_event_t*)event);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case XCB_KEY_RELEASE:
|
||||||
|
handle_key_release(NULL, conn, (xcb_key_release_event_t*)event);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case XCB_EXPOSE:
|
||||||
|
handle_expose(NULL, conn, (xcb_expose_event_t*)event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
|
@ -13,6 +13,28 @@
|
||||||
|
|
||||||
#include <xcb/randr.h>
|
#include <xcb/randr.h>
|
||||||
|
|
||||||
|
extern int randr_base;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests the property and invokes the appropriate callback.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int property_notify(uint8_t state, xcb_window_t window, xcb_atom_t atom);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
* There was a key press. We compare this key code with our bindings table and
|
||||||
* pass the bound action to parse_command().
|
* pass the bound action to parse_command().
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
*/
|
*/
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <xcb/xcb_property.h>
|
#include <xcb/xcb_property.h>
|
||||||
#include <xcb/xcb_event.h>
|
|
||||||
#include <xcb/xcb_keysyms.h>
|
#include <xcb/xcb_keysyms.h>
|
||||||
|
|
||||||
#include <X11/XKBlib.h>
|
#include <X11/XKBlib.h>
|
||||||
|
@ -21,8 +20,6 @@
|
||||||
#ifndef _I3_H
|
#ifndef _I3_H
|
||||||
#define _I3_H
|
#define _I3_H
|
||||||
|
|
||||||
#define NUM_ATOMS 22
|
|
||||||
|
|
||||||
extern xcb_connection_t *global_conn;
|
extern xcb_connection_t *global_conn;
|
||||||
extern xcb_key_symbols_t *keysyms;
|
extern xcb_key_symbols_t *keysyms;
|
||||||
extern char **start_argv;
|
extern char **start_argv;
|
||||||
|
@ -32,10 +29,8 @@ extern TAILQ_HEAD(bindings_head, Binding) *bindings;
|
||||||
extern TAILQ_HEAD(autostarts_head, Autostart) autostarts;
|
extern TAILQ_HEAD(autostarts_head, Autostart) autostarts;
|
||||||
extern TAILQ_HEAD(assignments_head, Assignment) assignments;
|
extern TAILQ_HEAD(assignments_head, Assignment) assignments;
|
||||||
extern SLIST_HEAD(stack_wins_head, Stack_Window) stack_wins;
|
extern SLIST_HEAD(stack_wins_head, Stack_Window) stack_wins;
|
||||||
extern xcb_event_handlers_t evenths;
|
|
||||||
extern uint8_t root_depth;
|
extern uint8_t root_depth;
|
||||||
extern bool xkb_supported;
|
extern bool xkb_supported;
|
||||||
extern xcb_atom_t atoms[NUM_ATOMS];
|
|
||||||
extern xcb_window_t root;
|
extern xcb_window_t root;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -20,8 +20,7 @@
|
||||||
* manage them
|
* manage them
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void manage_existing_windows(xcb_connection_t *conn, xcb_property_handlers_t
|
void manage_existing_windows(xcb_connection_t *conn, xcb_window_t root);
|
||||||
*prophs, xcb_window_t root);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restores the geometry of each window by reparenting it to the root window
|
* Restores the geometry of each window by reparenting it to the root window
|
||||||
|
@ -37,7 +36,7 @@ void restore_geometry(xcb_connection_t *conn);
|
||||||
* Do some sanity checks and then reparent the window.
|
* Do some sanity checks and then reparent the window.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void manage_window(xcb_property_handlers_t *prophs, xcb_connection_t *conn,
|
void manage_window(xcb_connection_t *conn,
|
||||||
xcb_window_t window,
|
xcb_window_t window,
|
||||||
xcb_get_window_attributes_cookie_t cookie,
|
xcb_get_window_attributes_cookie_t cookie,
|
||||||
bool needs_to_be_mapped);
|
bool needs_to_be_mapped);
|
||||||
|
|
|
@ -43,30 +43,9 @@
|
||||||
XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | /* …subwindows get notifies */ \
|
XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | /* …subwindows get notifies */ \
|
||||||
XCB_EVENT_MASK_ENTER_WINDOW) /* …user moves cursor inside our window */
|
XCB_EVENT_MASK_ENTER_WINDOW) /* …user moves cursor inside our window */
|
||||||
|
|
||||||
|
#define xmacro(atom) xcb_atom_t A_ ## atom;
|
||||||
enum { _NET_SUPPORTED = 0,
|
#include "atoms.xmacro"
|
||||||
_NET_SUPPORTING_WM_CHECK,
|
#undef xmacro
|
||||||
_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
|
|
||||||
};
|
|
||||||
|
|
||||||
extern unsigned int xcb_numlock_mask;
|
extern unsigned int xcb_numlock_mask;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
#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
|
||||||
|
#define xcb_icccm_get_wm_transient_for_reply xcb_get_wm_transient_for_reply
|
||||||
|
#define xcb_icccm_get_wm_transient_for_unchecked xcb_get_wm_transient_for_unchecked
|
||||||
|
|
||||||
|
#endif
|
|
@ -19,6 +19,11 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
/* Contains compatibility definitions for old libxcb versions */
|
||||||
|
#ifdef XCB_COMPAT
|
||||||
|
#include "xcb_compat.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <xcb/xcb_atom.h>
|
#include <xcb/xcb_atom.h>
|
||||||
#include <xcb/xcb_icccm.h>
|
#include <xcb/xcb_icccm.h>
|
||||||
|
|
33
src/client.c
33
src/client.c
|
@ -15,6 +15,11 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
|
/* Contains compatibility definitions for old libxcb versions */
|
||||||
|
#ifdef XCB_COMPAT
|
||||||
|
#include "xcb_compat.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <xcb/xcb_icccm.h>
|
#include <xcb/xcb_icccm.h>
|
||||||
|
|
||||||
|
@ -71,11 +76,11 @@ void client_warp_pointer_into(xcb_connection_t *conn, Client *client) {
|
||||||
*/
|
*/
|
||||||
static bool client_supports_protocol(xcb_connection_t *conn, Client *client, xcb_atom_t atom) {
|
static bool client_supports_protocol(xcb_connection_t *conn, Client *client, xcb_atom_t atom) {
|
||||||
xcb_get_property_cookie_t cookie;
|
xcb_get_property_cookie_t cookie;
|
||||||
xcb_get_wm_protocols_reply_t protocols;
|
xcb_icccm_get_wm_protocols_reply_t protocols;
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
cookie = xcb_get_wm_protocols_unchecked(conn, client->child, atoms[WM_PROTOCOLS]);
|
cookie = xcb_icccm_get_wm_protocols_unchecked(conn, client->child, A_WM_PROTOCOLS);
|
||||||
if (xcb_get_wm_protocols_reply(conn, cookie, &protocols, NULL) != 1)
|
if (xcb_icccm_get_wm_protocols_reply(conn, cookie, &protocols, NULL) != 1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Check if the client’s protocols have the requested atom set */
|
/* Check if the client’s protocols have the requested atom set */
|
||||||
|
@ -83,7 +88,7 @@ static bool client_supports_protocol(xcb_connection_t *conn, Client *client, xcb
|
||||||
if (protocols.atoms[i] == atom)
|
if (protocols.atoms[i] == atom)
|
||||||
result = true;
|
result = true;
|
||||||
|
|
||||||
xcb_get_wm_protocols_reply_wipe(&protocols);
|
xcb_icccm_get_wm_protocols_reply_wipe(&protocols);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -94,7 +99,7 @@ static bool client_supports_protocol(xcb_connection_t *conn, Client *client, xcb
|
||||||
*/
|
*/
|
||||||
void client_kill(xcb_connection_t *conn, Client *window) {
|
void client_kill(xcb_connection_t *conn, Client *window) {
|
||||||
/* If the client does not support WM_DELETE_WINDOW, we kill it the hard way */
|
/* If the client does not support WM_DELETE_WINDOW, we kill it the hard way */
|
||||||
if (!client_supports_protocol(conn, window, atoms[WM_DELETE_WINDOW])) {
|
if (!client_supports_protocol(conn, window, A_WM_DELETE_WINDOW)) {
|
||||||
LOG("Killing window the hard way\n");
|
LOG("Killing window the hard way\n");
|
||||||
xcb_kill_client(conn, window->child);
|
xcb_kill_client(conn, window->child);
|
||||||
return;
|
return;
|
||||||
|
@ -106,9 +111,9 @@ void client_kill(xcb_connection_t *conn, Client *window) {
|
||||||
|
|
||||||
ev.response_type = XCB_CLIENT_MESSAGE;
|
ev.response_type = XCB_CLIENT_MESSAGE;
|
||||||
ev.window = window->child;
|
ev.window = window->child;
|
||||||
ev.type = atoms[WM_PROTOCOLS];
|
ev.type = A_WM_PROTOCOLS;
|
||||||
ev.format = 32;
|
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;
|
ev.data.data32[1] = XCB_CURRENT_TIME;
|
||||||
|
|
||||||
LOG("Sending WM_DELETE to the client\n");
|
LOG("Sending WM_DELETE to the client\n");
|
||||||
|
@ -229,8 +234,8 @@ void client_enter_fullscreen(xcb_connection_t *conn, Client *client, bool global
|
||||||
xcb_configure_window(conn, client->frame, XCB_CONFIG_WINDOW_STACK_MODE, values);
|
xcb_configure_window(conn, client->frame, XCB_CONFIG_WINDOW_STACK_MODE, values);
|
||||||
|
|
||||||
/* Update _NET_WM_STATE */
|
/* Update _NET_WM_STATE */
|
||||||
values[0] = atoms[_NET_WM_STATE_FULLSCREEN];
|
values[0] = A__NET_WM_STATE_FULLSCREEN;
|
||||||
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, client->child, atoms[_NET_WM_STATE], ATOM, 32, 1, values);
|
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, client->child, A__NET_WM_STATE, A_ATOM, 32, 1, values);
|
||||||
|
|
||||||
fake_configure_notify(conn, r, client->child);
|
fake_configure_notify(conn, r, client->child);
|
||||||
|
|
||||||
|
@ -267,7 +272,7 @@ void client_leave_fullscreen(xcb_connection_t *conn, Client *client) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update _NET_WM_STATE */
|
/* Update _NET_WM_STATE */
|
||||||
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, client->child, atoms[_NET_WM_STATE], ATOM, 32, 0, NULL);
|
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, client->child, A__NET_WM_STATE, A_ATOM, 32, 0, NULL);
|
||||||
|
|
||||||
xcb_flush(conn);
|
xcb_flush(conn);
|
||||||
}
|
}
|
||||||
|
@ -401,8 +406,8 @@ void client_change_border(xcb_connection_t *conn, Client *client, char border_ty
|
||||||
*/
|
*/
|
||||||
void client_unmap(xcb_connection_t *conn, Client *client) {
|
void client_unmap(xcb_connection_t *conn, Client *client) {
|
||||||
/* Set WM_STATE_WITHDRAWN, it seems like Java apps need it */
|
/* 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, client->child, atoms[WM_STATE], atoms[WM_STATE], 32, 2, data);
|
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, client->child, A_WM_STATE, A_WM_STATE, 32, 2, data);
|
||||||
|
|
||||||
xcb_unmap_window(conn, client->frame);
|
xcb_unmap_window(conn, client->frame);
|
||||||
}
|
}
|
||||||
|
@ -414,8 +419,8 @@ void client_unmap(xcb_connection_t *conn, Client *client) {
|
||||||
void client_map(xcb_connection_t *conn, Client *client) {
|
void client_map(xcb_connection_t *conn, Client *client) {
|
||||||
/* Set WM_STATE_NORMAL because GTK applications don’t want to drag & drop if we don’t.
|
/* Set WM_STATE_NORMAL because GTK applications don’t want to drag & drop if we don’t.
|
||||||
* Also, xprop(1) needs that to work. */
|
* Also, xprop(1) needs that to work. */
|
||||||
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, client->child, atoms[WM_STATE], atoms[WM_STATE], 32, 2, data);
|
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, client->child, A_WM_STATE, A_WM_STATE, 32, 2, data);
|
||||||
|
|
||||||
xcb_map_window(conn, client->frame);
|
xcb_map_window(conn, client->frame);
|
||||||
}
|
}
|
||||||
|
|
|
@ -245,6 +245,6 @@ int format_event(xcb_generic_event_t *e) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int handle_event(void *ignored, xcb_connection_t *c, xcb_generic_event_t *e) {
|
int dbg_handle_event(void *ignored, xcb_connection_t *c, xcb_generic_event_t *e) {
|
||||||
return format_event(e);
|
return format_event(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
void ewmh_update_current_desktop() {
|
void ewmh_update_current_desktop() {
|
||||||
uint32_t current_desktop = c_ws->num;
|
uint32_t current_desktop = c_ws->num;
|
||||||
xcb_change_property(global_conn, XCB_PROP_MODE_REPLACE, root,
|
xcb_change_property(global_conn, XCB_PROP_MODE_REPLACE, root,
|
||||||
atoms[_NET_CURRENT_DESKTOP], CARDINAL, 32, 1,
|
A__NET_CURRENT_DESKTOP, A_CARDINAL, 32, 1,
|
||||||
¤t_desktop);
|
¤t_desktop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ void ewmh_update_current_desktop() {
|
||||||
*/
|
*/
|
||||||
void ewmh_update_active_window(xcb_window_t window) {
|
void ewmh_update_active_window(xcb_window_t window) {
|
||||||
xcb_change_property(global_conn, XCB_PROP_MODE_REPLACE, root,
|
xcb_change_property(global_conn, XCB_PROP_MODE_REPLACE, root,
|
||||||
atoms[_NET_ACTIVE_WINDOW], WINDOW, 32, 1, &window);
|
A__NET_ACTIVE_WINDOW, A_WINDOW, 32, 1, &window);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -95,7 +95,7 @@ void ewmh_update_workarea() {
|
||||||
memcpy(&last_rect, &(ws->rect), sizeof(Rect));
|
memcpy(&last_rect, &(ws->rect), sizeof(Rect));
|
||||||
}
|
}
|
||||||
xcb_change_property(global_conn, XCB_PROP_MODE_REPLACE, root,
|
xcb_change_property(global_conn, XCB_PROP_MODE_REPLACE, root,
|
||||||
atoms[_NET_WORKAREA], CARDINAL, 32,
|
A__NET_WORKAREA, A_CARDINAL, 32,
|
||||||
num_workspaces * (sizeof(Rect) / sizeof(uint32_t)),
|
num_workspaces * (sizeof(Rect) / sizeof(uint32_t)),
|
||||||
workarea);
|
workarea);
|
||||||
free(workarea);
|
free(workarea);
|
||||||
|
|
|
@ -15,19 +15,18 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <xcb/xcb_event.h>
|
|
||||||
|
|
||||||
#include "i3.h"
|
#include "i3.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "data.h"
|
#include "data.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "xcb.h"
|
#include "xcb.h"
|
||||||
#include "debug.h"
|
|
||||||
#include "layout.h"
|
#include "layout.h"
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "floating.h"
|
#include "floating.h"
|
||||||
#include "workspace.h"
|
#include "workspace.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "handlers.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Toggles floating mode for the given client.
|
* Toggles floating mode for the given client.
|
||||||
|
@ -404,19 +403,15 @@ void drag_pointer(xcb_connection_t *conn, Client *client, xcb_button_press_event
|
||||||
while ((inside_event = xcb_wait_for_event(conn))) {
|
while ((inside_event = xcb_wait_for_event(conn))) {
|
||||||
/* We now handle all events we can get using xcb_poll_for_event */
|
/* We now handle all events we can get using xcb_poll_for_event */
|
||||||
do {
|
do {
|
||||||
/* Same as get_event_handler in xcb */
|
/* skip x11 errors */
|
||||||
int nr = inside_event->response_type;
|
if (inside_event->response_type == 0) {
|
||||||
if (nr == 0) {
|
|
||||||
/* An error occured */
|
|
||||||
handle_event(NULL, conn, inside_event);
|
|
||||||
free(inside_event);
|
free(inside_event);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
assert(nr < 256);
|
/* Strip off the highest bit (set if the event is generated) */
|
||||||
nr &= XCB_EVENT_RESPONSE_TYPE_MASK;
|
int type = (inside_event->response_type & 0x7F);
|
||||||
assert(nr >= 2);
|
|
||||||
|
|
||||||
switch (nr) {
|
switch (type) {
|
||||||
case XCB_BUTTON_RELEASE:
|
case XCB_BUTTON_RELEASE:
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
@ -428,13 +423,13 @@ void drag_pointer(xcb_connection_t *conn, Client *client, xcb_button_press_event
|
||||||
|
|
||||||
case XCB_UNMAP_NOTIFY:
|
case XCB_UNMAP_NOTIFY:
|
||||||
DLOG("Unmap-notify, aborting\n");
|
DLOG("Unmap-notify, aborting\n");
|
||||||
xcb_event_handle(&evenths, inside_event);
|
handle_event(type, inside_event);
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
DLOG("Passing to original handler\n");
|
DLOG("Passing to original handler\n");
|
||||||
/* Use original handler */
|
/* Use original handler */
|
||||||
xcb_event_handle(&evenths, inside_event);
|
handle_event(type, inside_event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (last_motion_notify != inside_event)
|
if (last_motion_notify != inside_event)
|
||||||
|
|
194
src/handlers.c
194
src/handlers.c
|
@ -13,6 +13,12 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
/* Contains compatibility definitions for old libxcb versions */
|
||||||
|
#ifdef XCB_COMPAT
|
||||||
|
#include "xcb_compat.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <xcb/xcb_atom.h>
|
#include <xcb/xcb_atom.h>
|
||||||
|
@ -22,7 +28,7 @@
|
||||||
#include <X11/XKBlib.h>
|
#include <X11/XKBlib.h>
|
||||||
|
|
||||||
#include "i3.h"
|
#include "i3.h"
|
||||||
#include "debug.h"
|
#include "handlers.h"
|
||||||
#include "table.h"
|
#include "table.h"
|
||||||
#include "layout.h"
|
#include "layout.h"
|
||||||
#include "commands.h"
|
#include "commands.h"
|
||||||
|
@ -41,6 +47,8 @@
|
||||||
#include "container.h"
|
#include "container.h"
|
||||||
#include "ipc.h"
|
#include "ipc.h"
|
||||||
|
|
||||||
|
int randr_base = -1;
|
||||||
|
|
||||||
/* After mapping/unmapping windows, a notify event is generated. However, we don’t want it,
|
/* After mapping/unmapping windows, a notify event is generated. However, we don’t want it,
|
||||||
since it’d trigger an infinite loop of switching between the different windows when
|
since it’d trigger an infinite loop of switching between the different windows when
|
||||||
changing workspaces */
|
changing workspaces */
|
||||||
|
@ -82,6 +90,154 @@ static bool event_is_ignored(const int sequence) {
|
||||||
return false;
|
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, global_conn, event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case XCB_KEY_PRESS:
|
||||||
|
handle_key_press(NULL, global_conn, (xcb_key_press_event_t*)event);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case XCB_BUTTON_PRESS:
|
||||||
|
handle_button_press(NULL, global_conn, (xcb_button_press_event_t*)event);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case XCB_MAP_REQUEST:
|
||||||
|
handle_map_request(NULL, global_conn, (xcb_map_request_event_t*)event);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case XCB_UNMAP_NOTIFY:
|
||||||
|
handle_unmap_notify_event(NULL, global_conn, (xcb_unmap_notify_event_t*)event);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case XCB_DESTROY_NOTIFY:
|
||||||
|
handle_destroy_notify_event(NULL, global_conn, (xcb_destroy_notify_event_t*)event);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case XCB_EXPOSE:
|
||||||
|
handle_expose_event(NULL, global_conn, (xcb_expose_event_t*)event);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case XCB_MOTION_NOTIFY:
|
||||||
|
handle_motion_notify(NULL, global_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, global_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, global_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, global_conn, (xcb_configure_request_event_t*)event);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case XCB_CONFIGURE_NOTIFY:
|
||||||
|
handle_configure_event(NULL, global_conn, (xcb_configure_notify_event_t*)event);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Mapping notify = keyboard mapping changed (Xmodmap), re-grab bindings */
|
||||||
|
case XCB_MAPPING_NOTIFY:
|
||||||
|
handle_mapping_notify(NULL, global_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 },
|
||||||
|
{ 0, UINT_MAX, handle_windowclass_change }
|
||||||
|
};
|
||||||
|
#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;
|
||||||
|
property_handlers[6].atom = A_WM_CLASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Requests the property and invokes the appropriate callback.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
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(global_conn, 0, window, atom, XCB_GET_PROPERTY_TYPE_ANY, 0, handler->long_len);
|
||||||
|
propr = xcb_get_property_reply(global_conn, cookie, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = handler->cb(NULL, global_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
|
* There was a key press. We compare this key code with our bindings table and pass
|
||||||
* the bound action to parse_command().
|
* the bound action to parse_command().
|
||||||
|
@ -271,7 +427,7 @@ int handle_mapping_notify(void *ignored, xcb_connection_t *conn, xcb_mapping_not
|
||||||
* A new window appeared on the screen (=was mapped), so let’s manage it.
|
* A new window appeared on the screen (=was mapped), so let’s manage it.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int handle_map_request(void *prophs, xcb_connection_t *conn, xcb_map_request_event_t *event) {
|
int handle_map_request(void *invalid, xcb_connection_t *conn, xcb_map_request_event_t *event) {
|
||||||
xcb_get_window_attributes_cookie_t cookie;
|
xcb_get_window_attributes_cookie_t cookie;
|
||||||
|
|
||||||
cookie = xcb_get_window_attributes_unchecked(conn, event->window);
|
cookie = xcb_get_window_attributes_unchecked(conn, event->window);
|
||||||
|
@ -279,7 +435,7 @@ int handle_map_request(void *prophs, xcb_connection_t *conn, xcb_map_request_eve
|
||||||
DLOG("window = 0x%08x, serial is %d.\n", event->window, event->sequence);
|
DLOG("window = 0x%08x, serial is %d.\n", event->window, event->sequence);
|
||||||
add_ignore_event(event->sequence);
|
add_ignore_event(event->sequence);
|
||||||
|
|
||||||
manage_window(prophs, conn, event->window, cookie, false);
|
manage_window(conn, event->window, cookie, false);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -836,8 +992,8 @@ 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) {
|
int handle_client_message(void *data, xcb_connection_t *conn, xcb_client_message_event_t *event) {
|
||||||
if (event->type == atoms[_NET_WM_STATE]) {
|
if (event->type == A__NET_WM_STATE) {
|
||||||
if (event->format != 32 || event->data.data32[1] != atoms[_NET_WM_STATE_FULLSCREEN])
|
if (event->format != 32 || event->data.data32[1] != A__NET_WM_STATE_FULLSCREEN)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
Client *client = table_get(&by_child, event->window);
|
Client *client = table_get(&by_child, event->window);
|
||||||
|
@ -888,17 +1044,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 the hints were already in this event, use them, if not, request them */
|
||||||
if (reply != NULL)
|
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
|
else
|
||||||
xcb_get_wm_normal_hints_reply(conn, xcb_get_wm_normal_hints_unchecked(conn, client->child), &size_hints, NULL);
|
xcb_icccm_get_wm_normal_hints_reply(conn, xcb_icccm_get_wm_normal_hints_unchecked(conn, client->child), &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
|
// TODO: Minimum size is not yet implemented
|
||||||
DLOG("Minimum size: %d (width) x %d (height)\n", size_hints.min_width, size_hints.min_height);
|
DLOG("Minimum size: %d (width) x %d (height)\n", size_hints.min_width, size_hints.min_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool changed = false;
|
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 (size_hints.width_inc > 0 && size_hints.width_inc < 0xFFFF)
|
||||||
if (client->width_increment != size_hints.width_inc) {
|
if (client->width_increment != size_hints.width_inc) {
|
||||||
client->width_increment = size_hints.width_inc;
|
client->width_increment = size_hints.width_inc;
|
||||||
|
@ -919,10 +1075,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.
|
/* base_width/height are the desired size of the window.
|
||||||
We check if either the program-specified size or the program-specified
|
We check if either the program-specified size or the program-specified
|
||||||
min-size is available */
|
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_width = size_hints.base_width;
|
||||||
base_height = size_hints.base_height;
|
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 */
|
/* TODO: is this right? icccm says not */
|
||||||
base_width = size_hints.min_width;
|
base_width = size_hints.min_width;
|
||||||
base_height = size_hints.min_height;
|
base_height = size_hints.min_height;
|
||||||
|
@ -947,7 +1103,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 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_num <= 0) ||
|
||||||
(size_hints.min_aspect_den <= 0)) {
|
(size_hints.min_aspect_den <= 0)) {
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -996,13 +1152,13 @@ int handle_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t
|
||||||
DLOG("Received WM_HINTS for unknown client\n");
|
DLOG("Received WM_HINTS for unknown client\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
xcb_wm_hints_t hints;
|
xcb_icccm_wm_hints_t hints;
|
||||||
|
|
||||||
if (reply != NULL) {
|
if (reply != NULL) {
|
||||||
if (!xcb_get_wm_hints_from_reply(&hints, reply))
|
if (!xcb_icccm_get_wm_hints_from_reply(&hints, reply))
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
if (!xcb_get_wm_hints_reply(conn, xcb_get_wm_hints_unchecked(conn, client->child), &hints, NULL))
|
if (!xcb_icccm_get_wm_hints_reply(conn, xcb_icccm_get_wm_hints_unchecked(conn, client->child), &hints, NULL))
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1013,7 +1169,7 @@ int handle_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update the flag on the client directly */
|
/* Update the flag on the client directly */
|
||||||
client->urgent = (xcb_wm_hints_get_urgency(&hints) != 0);
|
client->urgent = (xcb_icccm_wm_hints_get_urgency(&hints) != 0);
|
||||||
CLIENT_LOG(client);
|
CLIENT_LOG(client);
|
||||||
LOG("Urgency flag changed to %d\n", client->urgent);
|
LOG("Urgency flag changed to %d\n", client->urgent);
|
||||||
|
|
||||||
|
@ -1050,10 +1206,10 @@ int handle_transient_for(void *data, xcb_connection_t *conn, uint8_t state, xcb_
|
||||||
xcb_window_t transient_for;
|
xcb_window_t transient_for;
|
||||||
|
|
||||||
if (reply != NULL) {
|
if (reply != NULL) {
|
||||||
if (!xcb_get_wm_transient_for_from_reply(&transient_for, reply))
|
if (!xcb_icccm_get_wm_transient_for_from_reply(&transient_for, reply))
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
if (!xcb_get_wm_transient_for_reply(conn, xcb_get_wm_transient_for_unchecked(conn, window),
|
if (!xcb_icccm_get_wm_transient_for_reply(conn, xcb_icccm_get_wm_transient_for_unchecked(conn, window),
|
||||||
&transient_for, NULL))
|
&transient_for, NULL))
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -1075,7 +1231,7 @@ int handle_clientleader_change(void *data, xcb_connection_t *conn, uint8_t state
|
||||||
xcb_atom_t name, xcb_get_property_reply_t *prop) {
|
xcb_atom_t name, xcb_get_property_reply_t *prop) {
|
||||||
if (prop == NULL) {
|
if (prop == NULL) {
|
||||||
prop = xcb_get_property_reply(conn, xcb_get_property_unchecked(conn,
|
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)
|
if (prop == NULL)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
154
src/mainx.c
154
src/mainx.c
|
@ -26,8 +26,6 @@
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <xcb/xcb_atom.h>
|
#include <xcb/xcb_atom.h>
|
||||||
#include <xcb/xcb_aux.h>
|
#include <xcb/xcb_aux.h>
|
||||||
#include <xcb/xcb_event.h>
|
|
||||||
#include <xcb/xcb_property.h>
|
|
||||||
#include <xcb/xcb_keysyms.h>
|
#include <xcb/xcb_keysyms.h>
|
||||||
#include <xcb/xcb_icccm.h>
|
#include <xcb/xcb_icccm.h>
|
||||||
|
|
||||||
|
@ -35,7 +33,6 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "data.h"
|
#include "data.h"
|
||||||
#include "debug.h"
|
|
||||||
#include "handlers.h"
|
#include "handlers.h"
|
||||||
#include "click.h"
|
#include "click.h"
|
||||||
#include "i3.h"
|
#include "i3.h"
|
||||||
|
@ -77,11 +74,6 @@ struct assignments_head assignments = TAILQ_HEAD_INITIALIZER(assignments);
|
||||||
/* This is a list of Stack_Windows, global, for easier/faster access on expose events */
|
/* This is a list of Stack_Windows, global, for easier/faster access on expose events */
|
||||||
struct stack_wins_head stack_wins = SLIST_HEAD_INITIALIZER(stack_wins);
|
struct stack_wins_head stack_wins = SLIST_HEAD_INITIALIZER(stack_wins);
|
||||||
|
|
||||||
/* The event handlers need to be global because they are accessed by our custom event handler
|
|
||||||
in handle_button_press(), needed for graphical resizing */
|
|
||||||
xcb_event_handlers_t evenths;
|
|
||||||
xcb_atom_t atoms[NUM_ATOMS];
|
|
||||||
|
|
||||||
xcb_window_t root;
|
xcb_window_t root;
|
||||||
int num_screens = 0;
|
int num_screens = 0;
|
||||||
|
|
||||||
|
@ -105,7 +97,7 @@ static void xcb_got_event(EV_P_ struct ev_io *w, int revents) {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static void xcb_prepare_cb(EV_P_ ev_prepare *w, int revents) {
|
static void xcb_prepare_cb(EV_P_ ev_prepare *w, int revents) {
|
||||||
xcb_flush(evenths.c);
|
xcb_flush(global_conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -116,8 +108,17 @@ static void xcb_prepare_cb(EV_P_ ev_prepare *w, int revents) {
|
||||||
static void xcb_check_cb(EV_P_ ev_check *w, int revents) {
|
static void xcb_check_cb(EV_P_ ev_check *w, int revents) {
|
||||||
xcb_generic_event_t *event;
|
xcb_generic_event_t *event;
|
||||||
|
|
||||||
while ((event = xcb_poll_for_event(evenths.c)) != NULL) {
|
while ((event = xcb_poll_for_event(global_conn)) != NULL) {
|
||||||
xcb_event_handle(&evenths, 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);
|
free(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,14 +192,12 @@ static void xkb_got_event(EV_P_ struct ev_io *w, int revents) {
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char *argv[], char *env[]) {
|
int main(int argc, char *argv[], char *env[]) {
|
||||||
int i, screens, opt;
|
int screens, opt;
|
||||||
char *override_configpath = NULL;
|
char *override_configpath = NULL;
|
||||||
bool autostart = true;
|
bool autostart = true;
|
||||||
bool only_check_config = false;
|
bool only_check_config = false;
|
||||||
bool force_xinerama = false;
|
bool force_xinerama = false;
|
||||||
xcb_connection_t *conn;
|
xcb_connection_t *conn;
|
||||||
xcb_property_handlers_t prophs;
|
|
||||||
xcb_intern_atom_cookie_t atom_cookies[NUM_ATOMS];
|
|
||||||
static struct option long_options[] = {
|
static struct option long_options[] = {
|
||||||
{"no-autostart", no_argument, 0, 'a'},
|
{"no-autostart", no_argument, 0, 'a'},
|
||||||
{"config", required_argument, 0, 'c'},
|
{"config", required_argument, 0, 'c'},
|
||||||
|
@ -275,9 +274,6 @@ int main(int argc, char *argv[], char *env[]) {
|
||||||
/* Initialize the table data structures for each workspace */
|
/* Initialize the table data structures for each workspace */
|
||||||
init_table();
|
init_table();
|
||||||
|
|
||||||
memset(&evenths, 0, sizeof(xcb_event_handlers_t));
|
|
||||||
memset(&prophs, 0, sizeof(xcb_property_handlers_t));
|
|
||||||
|
|
||||||
conn = global_conn = xcb_connect(NULL, &screens);
|
conn = global_conn = xcb_connect(NULL, &screens);
|
||||||
|
|
||||||
if (xcb_connection_has_error(conn))
|
if (xcb_connection_has_error(conn))
|
||||||
|
@ -303,30 +299,10 @@ int main(int argc, char *argv[], char *env[]) {
|
||||||
expand_table_rows(TAILQ_FIRST(workspaces));
|
expand_table_rows(TAILQ_FIRST(workspaces));
|
||||||
|
|
||||||
/* Place requests for the atoms we need as soon as possible */
|
/* 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);
|
#define xmacro(atom) \
|
||||||
|
xcb_intern_atom_cookie_t atom ## _cookie = xcb_intern_atom(conn, 0, strlen(#atom), #atom);
|
||||||
REQUEST_ATOM(_NET_SUPPORTED);
|
#include "atoms.xmacro"
|
||||||
REQUEST_ATOM(_NET_WM_STATE_FULLSCREEN);
|
#undef xmacro
|
||||||
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);
|
|
||||||
|
|
||||||
/* TODO: this has to be more beautiful somewhen */
|
/* TODO: this has to be more beautiful somewhen */
|
||||||
int major, minor, error;
|
int major, minor, error;
|
||||||
|
@ -392,15 +368,7 @@ int main(int argc, char *argv[], char *env[]) {
|
||||||
/* Grab the server to delay any events until we enter the eventloop */
|
/* Grab the server to delay any events until we enter the eventloop */
|
||||||
xcb_grab_server(conn);
|
xcb_grab_server(conn);
|
||||||
|
|
||||||
xcb_event_handlers_init(conn, &evenths);
|
#if 0
|
||||||
|
|
||||||
/* DEBUG: Trap all events and print them */
|
|
||||||
for (i = 2; i < 128; ++i)
|
|
||||||
xcb_event_set_handler(&evenths, i, handle_event, 0);
|
|
||||||
|
|
||||||
for (i = 0; i < 256; ++i)
|
|
||||||
xcb_event_set_error_handler(&evenths, i, (xcb_generic_error_handler_t)handle_event, 0);
|
|
||||||
|
|
||||||
/* Expose = an Application should redraw itself, in this case it’s our titlebars. */
|
/* Expose = an Application should redraw itself, in this case it’s our titlebars. */
|
||||||
xcb_event_set_expose_handler(&evenths, handle_expose_event, NULL);
|
xcb_event_set_expose_handler(&evenths, handle_expose_event, NULL);
|
||||||
|
|
||||||
|
@ -440,12 +408,7 @@ int main(int argc, char *argv[], char *env[]) {
|
||||||
/* Client message are sent to the root window. The only interesting client message
|
/* 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 */
|
for us is _NET_WM_STATE, we honour _NET_WM_STATE_FULLSCREEN */
|
||||||
xcb_event_set_client_message_handler(&evenths, handle_client_message, NULL);
|
xcb_event_set_client_message_handler(&evenths, handle_client_message, NULL);
|
||||||
|
#endif
|
||||||
/* Initialize the property handlers */
|
|
||||||
xcb_property_handlers_init(&prophs, &evenths);
|
|
||||||
|
|
||||||
/* Watch size hints (to obey correct aspect ratio) */
|
|
||||||
xcb_property_set_handler(&prophs, WM_NORMAL_HINTS, UINT_MAX, handle_normal_hints, NULL);
|
|
||||||
|
|
||||||
/* set event mask */
|
/* set event mask */
|
||||||
uint32_t mask = XCB_CW_EVENT_MASK;
|
uint32_t mask = XCB_CW_EVENT_MASK;
|
||||||
|
@ -461,66 +424,34 @@ int main(int argc, char *argv[], char *env[]) {
|
||||||
check_error(conn, cookie, "Another window manager seems to be running");
|
check_error(conn, cookie, "Another window manager seems to be running");
|
||||||
|
|
||||||
/* Setup NetWM atoms */
|
/* Setup NetWM atoms */
|
||||||
#define GET_ATOM(name) { \
|
#define xmacro(name) \
|
||||||
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, atom_cookies[name], NULL); \
|
do { \
|
||||||
|
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, name ## _cookie, NULL); \
|
||||||
if (!reply) { \
|
if (!reply) { \
|
||||||
ELOG("Could not get atom " #name "\n"); \
|
ELOG("Could not get atom " #name "\n"); \
|
||||||
exit(-1); \
|
exit(-1); \
|
||||||
} \
|
} \
|
||||||
atoms[name] = reply->atom; \
|
A_ ## name = reply->atom; \
|
||||||
free(reply); \
|
free(reply); \
|
||||||
}
|
} while (0);
|
||||||
|
#include "atoms.xmacro"
|
||||||
|
#undef xmacro
|
||||||
|
|
||||||
GET_ATOM(_NET_SUPPORTED);
|
property_handlers_init();
|
||||||
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);
|
|
||||||
|
|
||||||
xcb_property_set_handler(&prophs, atoms[_NET_WM_WINDOW_TYPE], UINT_MAX, handle_window_type, NULL);
|
|
||||||
/* TODO: In order to comply with EWMH, we have to watch _NET_WM_STRUT_PARTIAL */
|
|
||||||
|
|
||||||
/* Watch _NET_WM_NAME (= title of the window in UTF-8) property */
|
|
||||||
xcb_property_set_handler(&prophs, atoms[_NET_WM_NAME], 128, handle_windowname_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);
|
|
||||||
|
|
||||||
/* Watch WM_NAME (= title of the window in compound text) property for legacy applications */
|
|
||||||
xcb_watch_wm_name(&prophs, 128, handle_windowname_change_legacy, NULL);
|
|
||||||
|
|
||||||
/* Watch WM_CLASS (= class of the window) */
|
|
||||||
xcb_property_set_handler(&prophs, WM_CLASS, 128, handle_windowclass_change, 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_HINTS (contains the urgent property) */
|
|
||||||
xcb_property_set_handler(&prophs, WM_HINTS, UINT_MAX, handle_hints, NULL);
|
|
||||||
|
|
||||||
/* Set up the atoms we support */
|
/* Set up the atoms we support */
|
||||||
check_error(conn, xcb_change_property_checked(conn, XCB_PROP_MODE_REPLACE, root, atoms[_NET_SUPPORTED],
|
xcb_atom_t supported_atoms[] = {
|
||||||
ATOM, 32, 7, atoms), "Could not set _NET_SUPPORTED");
|
#define xmacro(atom) A_ ## atom,
|
||||||
|
#include "atoms.xmacro"
|
||||||
|
#undef xmacro
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Set up the atoms we support */
|
||||||
|
check_error(conn, xcb_change_property_checked(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED,
|
||||||
|
A_ATOM, 32, 7, supported_atoms), "Could not set _NET_SUPPORTED");
|
||||||
/* Set up the window manager’s name */
|
/* Set up the window manager’s 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, A__NET_SUPPORTING_WM_CHECK, A_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_WM_NAME, A_UTF8_STRING, 8, strlen("i3"), "i3");
|
||||||
|
|
||||||
keysyms = xcb_key_symbols_alloc(conn);
|
keysyms = xcb_key_symbols_alloc(conn);
|
||||||
|
|
||||||
|
@ -529,18 +460,11 @@ int main(int argc, char *argv[], char *env[]) {
|
||||||
translate_keysyms();
|
translate_keysyms();
|
||||||
grab_all_keys(conn, false);
|
grab_all_keys(conn, false);
|
||||||
|
|
||||||
int randr_base = -1;
|
|
||||||
if (force_xinerama) {
|
if (force_xinerama) {
|
||||||
initialize_xinerama(conn);
|
initialize_xinerama(conn);
|
||||||
} else {
|
} else {
|
||||||
DLOG("Checking for XRandR...\n");
|
DLOG("Checking for XRandR...\n");
|
||||||
initialize_randr(conn, &randr_base);
|
initialize_randr(conn, &randr_base);
|
||||||
|
|
||||||
if (randr_base != -1)
|
|
||||||
xcb_event_set_handler(&evenths,
|
|
||||||
randr_base + XCB_RANDR_SCREEN_CHANGE_NOTIFY,
|
|
||||||
handle_screen_change,
|
|
||||||
NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
xcb_flush(conn);
|
xcb_flush(conn);
|
||||||
|
@ -562,7 +486,7 @@ int main(int argc, char *argv[], char *env[]) {
|
||||||
DLOG("Starting on %p\n", screen->current_workspace);
|
DLOG("Starting on %p\n", screen->current_workspace);
|
||||||
c_ws = screen->current_workspace;
|
c_ws = screen->current_workspace;
|
||||||
|
|
||||||
manage_existing_windows(conn, &prophs, root);
|
manage_existing_windows(conn, root);
|
||||||
|
|
||||||
/* Create the UNIX domain socket for IPC */
|
/* Create the UNIX domain socket for IPC */
|
||||||
if (config.ipc_socket_path != NULL) {
|
if (config.ipc_socket_path != NULL) {
|
||||||
|
|
54
src/manage.c
54
src/manage.c
|
@ -37,7 +37,7 @@
|
||||||
* Go through all existing windows (if the window manager is restarted) and manage them
|
* Go through all existing windows (if the window manager is restarted) and manage them
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void manage_existing_windows(xcb_connection_t *conn, xcb_property_handlers_t *prophs, xcb_window_t root) {
|
void manage_existing_windows(xcb_connection_t *conn, xcb_window_t root) {
|
||||||
xcb_query_tree_reply_t *reply;
|
xcb_query_tree_reply_t *reply;
|
||||||
int i, len;
|
int i, len;
|
||||||
xcb_window_t *children;
|
xcb_window_t *children;
|
||||||
|
@ -57,7 +57,7 @@ void manage_existing_windows(xcb_connection_t *conn, xcb_property_handlers_t *pr
|
||||||
|
|
||||||
/* Call manage_window with the attributes for every window */
|
/* Call manage_window with the attributes for every window */
|
||||||
for (i = 0; i < len; ++i)
|
for (i = 0; i < len; ++i)
|
||||||
manage_window(prophs, conn, children[i], cookies[i], true);
|
manage_window(conn, children[i], cookies[i], true);
|
||||||
|
|
||||||
free(reply);
|
free(reply);
|
||||||
free(cookies);
|
free(cookies);
|
||||||
|
@ -89,7 +89,7 @@ void restore_geometry(xcb_connection_t *conn) {
|
||||||
* Do some sanity checks and then reparent the window.
|
* Do some sanity checks and then reparent the window.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void manage_window(xcb_property_handlers_t *prophs, xcb_connection_t *conn,
|
void manage_window(xcb_connection_t *conn,
|
||||||
xcb_window_t window, xcb_get_window_attributes_cookie_t cookie,
|
xcb_window_t window, xcb_get_window_attributes_cookie_t cookie,
|
||||||
bool needs_to_be_mapped) {
|
bool needs_to_be_mapped) {
|
||||||
xcb_drawable_t d = { window };
|
xcb_drawable_t d = { window };
|
||||||
|
@ -127,13 +127,13 @@ void manage_window(xcb_property_handlers_t *prophs, xcb_connection_t *conn,
|
||||||
geom->border_width);
|
geom->border_width);
|
||||||
|
|
||||||
/* Generate callback events for every property we watch */
|
/* Generate callback events for every property we watch */
|
||||||
xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_CLASS);
|
property_notify(XCB_PROPERTY_NEW_VALUE, window, A_WM_CLASS);
|
||||||
xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_NAME);
|
property_notify(XCB_PROPERTY_NEW_VALUE, window, A_WM_NAME);
|
||||||
xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_NORMAL_HINTS);
|
property_notify(XCB_PROPERTY_NEW_VALUE, window, A_WM_NORMAL_HINTS);
|
||||||
xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_HINTS);
|
property_notify(XCB_PROPERTY_NEW_VALUE, window, A_WM_HINTS);
|
||||||
xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_TRANSIENT_FOR);
|
property_notify(XCB_PROPERTY_NEW_VALUE, window, A_WM_TRANSIENT_FOR);
|
||||||
xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, atoms[WM_CLIENT_LEADER]);
|
property_notify(XCB_PROPERTY_NEW_VALUE, window, A_WM_CLIENT_LEADER);
|
||||||
xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, atoms[_NET_WM_NAME]);
|
property_notify(XCB_PROPERTY_NEW_VALUE, window, A__NET_WM_NAME);
|
||||||
|
|
||||||
free(geom);
|
free(geom);
|
||||||
out:
|
out:
|
||||||
|
@ -167,13 +167,13 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
|
||||||
xcb_change_window_attributes(conn, child, mask, values);
|
xcb_change_window_attributes(conn, child, mask, values);
|
||||||
|
|
||||||
/* Place requests for properties ASAP */
|
/* Place requests for properties ASAP */
|
||||||
wm_type_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_WINDOW_TYPE], UINT32_MAX);
|
wm_type_cookie = xcb_get_any_property_unchecked(conn, false, child, A__NET_WM_WINDOW_TYPE, UINT32_MAX);
|
||||||
strut_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_STRUT_PARTIAL], UINT32_MAX);
|
strut_cookie = xcb_get_any_property_unchecked(conn, false, child, A__NET_WM_STRUT_PARTIAL, UINT32_MAX);
|
||||||
state_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_STATE], UINT32_MAX);
|
state_cookie = xcb_get_any_property_unchecked(conn, false, child, A__NET_WM_STATE, UINT32_MAX);
|
||||||
utf8_title_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_NAME], 128);
|
utf8_title_cookie = xcb_get_any_property_unchecked(conn, false, child, A__NET_WM_NAME, 128);
|
||||||
leader_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[WM_CLIENT_LEADER], UINT32_MAX);
|
leader_cookie = xcb_get_any_property_unchecked(conn, false, child, A_WM_CLIENT_LEADER, UINT32_MAX);
|
||||||
title_cookie = xcb_get_any_property_unchecked(conn, false, child, WM_NAME, 128);
|
title_cookie = xcb_get_any_property_unchecked(conn, false, child, A_WM_NAME, 128);
|
||||||
class_cookie = xcb_get_any_property_unchecked(conn, false, child, WM_CLASS, 128);
|
class_cookie = xcb_get_any_property_unchecked(conn, false, child, A_WM_CLASS, 128);
|
||||||
|
|
||||||
Client *new = table_get(&by_child, child);
|
Client *new = table_get(&by_child, child);
|
||||||
|
|
||||||
|
@ -270,7 +270,7 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
|
||||||
xcb_get_property_reply_t *preply = xcb_get_property_reply(conn, wm_type_cookie, NULL);
|
xcb_get_property_reply_t *preply = xcb_get_property_reply(conn, wm_type_cookie, NULL);
|
||||||
if (preply != NULL && preply->value_len > 0 && (atom = xcb_get_property_value(preply))) {
|
if (preply != NULL && preply->value_len > 0 && (atom = xcb_get_property_value(preply))) {
|
||||||
for (int i = 0; i < xcb_get_property_value_length(preply); i++)
|
for (int i = 0; i < xcb_get_property_value_length(preply); i++)
|
||||||
if (atom[i] == atoms[_NET_WM_WINDOW_TYPE_DOCK]) {
|
if (atom[i] == A__NET_WM_WINDOW_TYPE_DOCK) {
|
||||||
DLOG("Window is a dock.\n");
|
DLOG("Window is a dock.\n");
|
||||||
Output *t_out = get_output_containing(x, y);
|
Output *t_out = get_output_containing(x, y);
|
||||||
if (t_out == NULL)
|
if (t_out == NULL)
|
||||||
|
@ -289,10 +289,10 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
|
||||||
/* If it’s a dock we can’t make it float, so we break */
|
/* If it’s a dock we can’t make it float, so we break */
|
||||||
new->floating = FLOATING_AUTO_OFF;
|
new->floating = FLOATING_AUTO_OFF;
|
||||||
break;
|
break;
|
||||||
} else if (atom[i] == atoms[_NET_WM_WINDOW_TYPE_DIALOG] ||
|
} else if (atom[i] == A__NET_WM_WINDOW_TYPE_DIALOG ||
|
||||||
atom[i] == atoms[_NET_WM_WINDOW_TYPE_UTILITY] ||
|
atom[i] == A__NET_WM_WINDOW_TYPE_UTILITY ||
|
||||||
atom[i] == atoms[_NET_WM_WINDOW_TYPE_TOOLBAR] ||
|
atom[i] == A__NET_WM_WINDOW_TYPE_TOOLBAR ||
|
||||||
atom[i] == atoms[_NET_WM_WINDOW_TYPE_SPLASH]) {
|
atom[i] == A__NET_WM_WINDOW_TYPE_SPLASH) {
|
||||||
/* Set the dialog window to automatically floating, will be used below */
|
/* Set the dialog window to automatically floating, will be used below */
|
||||||
new->floating = FLOATING_AUTO_ON;
|
new->floating = FLOATING_AUTO_ON;
|
||||||
DLOG("dialog/utility/toolbar/splash window, automatically floating\n");
|
DLOG("dialog/utility/toolbar/splash window, automatically floating\n");
|
||||||
|
@ -337,16 +337,16 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
|
||||||
* changes. It is important that the client was already inserted into the by_child table,
|
* changes. It is important that the client was already inserted into the by_child table,
|
||||||
* because the callbacks won’t work otherwise. */
|
* because the callbacks won’t work otherwise. */
|
||||||
preply = xcb_get_property_reply(conn, utf8_title_cookie, NULL);
|
preply = xcb_get_property_reply(conn, utf8_title_cookie, NULL);
|
||||||
handle_windowname_change(NULL, conn, 0, new->child, atoms[_NET_WM_NAME], preply);
|
handle_windowname_change(NULL, conn, 0, new->child, A__NET_WM_NAME, preply);
|
||||||
|
|
||||||
preply = xcb_get_property_reply(conn, title_cookie, NULL);
|
preply = xcb_get_property_reply(conn, title_cookie, NULL);
|
||||||
handle_windowname_change_legacy(NULL, conn, 0, new->child, WM_NAME, preply);
|
handle_windowname_change_legacy(NULL, conn, 0, new->child, A_WM_NAME, preply);
|
||||||
|
|
||||||
preply = xcb_get_property_reply(conn, class_cookie, NULL);
|
preply = xcb_get_property_reply(conn, class_cookie, NULL);
|
||||||
handle_windowclass_change(NULL, conn, 0, new->child, WM_CLASS, preply);
|
handle_windowclass_change(NULL, conn, 0, new->child, A_WM_CLASS, preply);
|
||||||
|
|
||||||
preply = xcb_get_property_reply(conn, leader_cookie, NULL);
|
preply = xcb_get_property_reply(conn, leader_cookie, NULL);
|
||||||
handle_clientleader_change(NULL, conn, 0, new->child, atoms[WM_CLIENT_LEADER], preply);
|
handle_clientleader_change(NULL, conn, 0, new->child, A_WM_CLIENT_LEADER, preply);
|
||||||
|
|
||||||
/* if WM_CLIENT_LEADER is set, we put the new window on the
|
/* if WM_CLIENT_LEADER is set, we put the new window on the
|
||||||
* same window as its leader. This might be overwritten by
|
* same window as its leader. This might be overwritten by
|
||||||
|
@ -485,7 +485,7 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
|
||||||
(state = xcb_get_property_value(preply)) != NULL)
|
(state = xcb_get_property_value(preply)) != NULL)
|
||||||
/* Check all set _NET_WM_STATEs */
|
/* Check all set _NET_WM_STATEs */
|
||||||
for (int i = 0; i < xcb_get_property_value_length(preply); i++) {
|
for (int i = 0; i < xcb_get_property_value_length(preply); i++) {
|
||||||
if (state[i] != atoms[_NET_WM_STATE_FULLSCREEN])
|
if (state[i] != A__NET_WM_STATE_FULLSCREEN)
|
||||||
continue;
|
continue;
|
||||||
/* If the window got the fullscreen state, we just toggle fullscreen
|
/* If the window got the fullscreen state, we just toggle fullscreen
|
||||||
and don’t event bother to redraw the layout – that would not change
|
and don’t event bother to redraw the layout – that would not change
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <xcb/xcb_event.h>
|
|
||||||
|
|
||||||
#include "i3.h"
|
#include "i3.h"
|
||||||
#include "data.h"
|
#include "data.h"
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
|
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <xcb/xcb_aux.h>
|
#include <xcb/xcb_aux.h>
|
||||||
#include <xcb/xcb_event.h>
|
|
||||||
#include <xcb/xcb_keysyms.h>
|
#include <xcb/xcb_keysyms.h>
|
||||||
|
|
||||||
#include <X11/keysym.h>
|
#include <X11/keysym.h>
|
||||||
|
|
|
@ -233,9 +233,9 @@ void take_focus(xcb_connection_t *conn, Client *client) {
|
||||||
|
|
||||||
ev.response_type = XCB_CLIENT_MESSAGE;
|
ev.response_type = XCB_CLIENT_MESSAGE;
|
||||||
ev.window = client->child;
|
ev.window = client->child;
|
||||||
ev.type = atoms[WM_PROTOCOLS];
|
ev.type = A_WM_PROTOCOLS;
|
||||||
ev.format = 32;
|
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;
|
ev.data.data32[1] = XCB_CURRENT_TIME;
|
||||||
|
|
||||||
DLOG("Sending WM_TAKE_FOCUS to the client\n");
|
DLOG("Sending WM_TAKE_FOCUS to the client\n");
|
||||||
|
|
Loading…
Reference in New Issue