diff --git a/Makefile b/Makefile index 6a21a7cd..dbe56b4b 100644 --- a/Makefile +++ b/Makefile @@ -14,8 +14,12 @@ CFLAGS += -I/usr/local/include CFLAGS += -DI3_VERSION=\"${GIT_VERSION}\" LDFLAGS += -lm -LDFLAGS += -lxcb-wm +LDFLAGS += -lxcb-event +LDFLAGS += -lxcb-property LDFLAGS += -lxcb-keysyms +LDFLAGS += -lxcb-atom +LDFLAGS += -lxcb-aux +LDFLAGS += -lxcb-icccm LDFLAGS += -lxcb-xinerama LDFLAGS += -lX11 LDFLAGS += -L/usr/local/lib -L/usr/pkg/lib diff --git a/include/data.h b/include/data.h index 87112ac2..dc7fd8ff 100644 --- a/include/data.h +++ b/include/data.h @@ -11,6 +11,7 @@ * */ #include +#include #include #ifndef _DATA_H @@ -116,6 +117,25 @@ struct Ignore_Event { SLIST_ENTRY(Ignore_Event) ignore_events; }; +/* + * Emulates the behaviour of tables of libxcb-wm, which in libxcb 0.3.4 suddenly vanished. + * + */ +struct keyvalue_element { + uint32_t key; + void *value; + + TAILQ_ENTRY(keyvalue_element) elements; +}; + +typedef struct { + enum xcb_atom_fast_tag_t tag; + union { + xcb_get_window_attributes_cookie_t cookie; + uint8_t override_redirect; + } u; +} window_attributes_t; + /****************************************************************************** * Major types *****************************************************************************/ diff --git a/include/i3.h b/include/i3.h index 7a104b21..6d6f9d74 100644 --- a/include/i3.h +++ b/include/i3.h @@ -9,11 +9,13 @@ * */ #include +#include #include #include #include "queue.h" +#include "data.h" #ifndef _I3_H #define _I3_H @@ -28,4 +30,9 @@ extern xcb_event_handlers_t evenths; extern int num_screens; extern xcb_atom_t atoms[NUM_ATOMS]; +void manage_window(xcb_property_handlers_t *prophs, xcb_connection_t *conn, xcb_window_t window, window_attributes_t wa); +void reparent_window(xcb_connection_t *conn, xcb_window_t child, + xcb_visualid_t visual, xcb_window_t root, uint8_t depth, + int16_t x, int16_t y, uint16_t width, uint16_t height); + #endif diff --git a/include/util.h b/include/util.h index 01d7af69..3ea2b3a7 100644 --- a/include/util.h +++ b/include/util.h @@ -36,6 +36,9 @@ while (0) delete the preceding comma */ #define LOG(fmt, ...) slog("%s:%s:%d - " fmt, __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__) +TAILQ_HEAD(keyvalue_table_head, keyvalue_element); +extern struct keyvalue_table_head by_parent; +extern struct keyvalue_table_head by_child; int min(int a, int b); int max(int a, int b); @@ -74,6 +77,24 @@ void *scalloc(size_t size); */ char *sstrdup(const char *str); +/** + * Inserts an element into the given keyvalue-table using the given key. + * + */ +bool table_put(struct keyvalue_table_head *head, uint32_t key, void *value); + +/** + * Removes the element from the given keyvalue-table with the given key and returns its value; + * + */ +void *table_remove(struct keyvalue_table_head *head, uint32_t key); + +/** + * Returns the value of the element of the given keyvalue-table with the given key. + * + */ +void *table_get(struct keyvalue_table_head *head, uint32_t key); + /** * Starts the given application by passing it through a shell. We use double fork * to avoid zombie processes. As the started application’s parent exits (immediately), diff --git a/src/handlers.c b/src/handlers.c index e92d062e..d31d0f33 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include @@ -149,10 +149,10 @@ int handle_enter_notify(void *ignored, xcb_connection_t *conn, xcb_enter_notify_ return 1; /* This was either a focus for a client’s parent (= titlebar)… */ - Client *client = table_get(byParent, event->event); + Client *client = table_get(&by_parent, event->event); /* …or the client itself */ if (client == NULL) - client = table_get(byChild, event->event); + client = table_get(&by_child, event->event); /* Check for stack windows */ if (client == NULL) { @@ -279,10 +279,10 @@ static bool button_press_bar(xcb_connection_t *conn, xcb_button_press_event_t *e int handle_button_press(void *ignored, xcb_connection_t *conn, xcb_button_press_event_t *event) { LOG("button press!\n"); /* This was either a focus for a client’s parent (= titlebar)… */ - Client *client = table_get(byChild, event->event); + Client *client = table_get(&by_child, event->event); bool border_click = false; if (client == NULL) { - client = table_get(byParent, event->event); + client = table_get(&by_parent, event->event); border_click = true; } if (client == NULL) { @@ -534,7 +534,7 @@ int handle_configure_request(void *prophs, xcb_connection_t *conn, xcb_configure LOG("event->window = %08x\n", event->window); LOG("application wants to be at %dx%d with %dx%d\n", event->x, event->y, event->width, event->height); - Client *client = table_get(byChild, event->window); + Client *client = table_get(&by_child, event->window); if (client == NULL) { LOG("This client is not mapped, so we don't care and just tell the client that he will get its size\n"); Rect rect = {event->x, event->y, event->width, event->height}; @@ -582,7 +582,7 @@ int handle_unmap_notify_event(void *data, xcb_connection_t *conn, xcb_unmap_noti add_ignore_event(event->sequence); - Client *client = table_get(byChild, event->window); + Client *client = table_get(&by_child, event->window); /* First, we need to check if the client is awaiting an unmap-request which was generated by us reparenting the window. In that case, we just ignore it. */ if (client != NULL && client->awaiting_useless_unmap) { @@ -598,7 +598,7 @@ int handle_unmap_notify_event(void *data, xcb_connection_t *conn, xcb_unmap_noti return 0; } - client = table_remove(byChild, event->window); + client = table_remove(&by_child, event->window); if (client->name != NULL) free(client->name); @@ -630,7 +630,7 @@ int handle_unmap_notify_event(void *data, xcb_connection_t *conn, xcb_unmap_noti xcb_reparent_window(conn, client->child, root, 0, 0); xcb_destroy_window(conn, client->frame); xcb_flush(conn); - table_remove(byParent, client->frame); + table_remove(&by_parent, client->frame); if (client->container != NULL) { cleanup_table(conn, client->container->workspace); @@ -673,7 +673,7 @@ int handle_windowname_change(void *data, xcb_connection_t *conn, uint8_t state, LOG("_NET_WM_NAME not specified, not changing\n"); return 1; } - Client *client = table_get(byChild, window); + Client *client = table_get(&by_child, window); if (client == NULL) return 1; @@ -736,7 +736,7 @@ int handle_windowname_change_legacy(void *data, xcb_connection_t *conn, uint8_t LOG("prop == NULL\n"); return 1; } - Client *client = table_get(byChild, window); + Client *client = table_get(&by_child, window); if (client == NULL) return 1; @@ -793,7 +793,7 @@ int handle_expose_event(void *data, xcb_connection_t *conn, xcb_expose_event_t * return 1; LOG("window = %08x\n", event->window); - Client *client = table_get(byParent, event->window); + Client *client = table_get(&by_parent, event->window); if (client == NULL) { /* There was no client in the table, so this is probably an expose event for one of our stack_windows. */ @@ -861,7 +861,7 @@ int handle_client_message(void *data, xcb_connection_t *conn, xcb_client_message LOG("fullscreen\n"); - Client *client = table_get(byChild, event->window); + Client *client = table_get(&by_child, event->window); if (client == NULL) return 0; @@ -899,7 +899,7 @@ int handle_window_type(void *data, xcb_connection_t *conn, uint8_t state, xcb_wi int handle_normal_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t window, xcb_atom_t name, xcb_get_property_reply_t *reply) { LOG("handle_normal_hints\n"); - Client *client = table_get(byChild, window); + Client *client = table_get(&by_child, window); if (client == NULL) { LOG("No such client\n"); return 1; diff --git a/src/mainx.c b/src/mainx.c index c94121fe..34daf04e 100644 --- a/src/mainx.c +++ b/src/mainx.c @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include @@ -91,7 +91,7 @@ void manage_window(xcb_property_handlers_t *prophs, xcb_connection_t *conn, xcb_ goto out; /* Check if the window is already managed */ - if (table_get(byChild, window)) + if (table_get(&by_child, window)) goto out; /* Get the initial geometry (position, size, …) */ @@ -124,8 +124,8 @@ out: * */ void reparent_window(xcb_connection_t *conn, xcb_window_t child, - xcb_visualid_t visual, xcb_window_t root, uint8_t depth, - int16_t x, int16_t y, uint16_t width, uint16_t height) { + xcb_visualid_t visual, xcb_window_t root, uint8_t depth, + int16_t x, int16_t y, uint16_t width, uint16_t height) { xcb_get_property_cookie_t wm_type_cookie, strut_cookie, state_cookie; uint32_t mask = 0; @@ -144,7 +144,7 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child, strut_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_STRUT_PARTIAL], UINT32_MAX); state_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_STATE], UINT32_MAX); - Client *new = table_get(byChild, child); + Client *new = table_get(&by_child, child); /* Events for already managed windows should already be filtered in manage_window() */ assert(new == NULL); @@ -207,8 +207,8 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child, } /* Put our data structure (Client) into the table */ - table_put(byParent, new->frame, new); - table_put(byChild, child, new); + table_put(&by_parent, new->frame, new); + table_put(&by_child, child, new); /* We need to grab the mouse buttons for click to focus */ xcb_grab_button(conn, false, child, XCB_EVENT_MASK_BUTTON_PRESS, @@ -362,9 +362,6 @@ int main(int argc, char *argv[], char *env[]) { memset(&evenths, 0, sizeof(xcb_event_handlers_t)); memset(&prophs, 0, sizeof(xcb_property_handlers_t)); - byChild = alloc_table(); - byParent = alloc_table(); - load_configuration(override_configpath); conn = xcb_connect(NULL, &screens); diff --git a/src/util.c b/src/util.c index 880be2d6..276f76f9 100644 --- a/src/util.c +++ b/src/util.c @@ -29,6 +29,8 @@ #include "xcb.h" static iconv_t conversion_descriptor = 0; +struct keyvalue_table_head by_parent = TAILQ_HEAD_INITIALIZER(by_parent); +struct keyvalue_table_head by_child = TAILQ_HEAD_INITIALIZER(by_child); int min(int a, int b) { return (a < b ? a : b); @@ -96,6 +98,44 @@ char *sstrdup(const char *str) { return result; } +/* + * The table_* functions emulate the behaviour of libxcb-wm, which in libxcb 0.3.4 suddenly + * vanished. Great. + * + */ +bool table_put(struct keyvalue_table_head *head, uint32_t key, void *value) { + struct keyvalue_element *element = scalloc(sizeof(struct keyvalue_element)); + element->key = key; + element->value = value; + + TAILQ_INSERT_TAIL(head, element, elements); + return true; +} + +void *table_remove(struct keyvalue_table_head *head, uint32_t key) { + struct keyvalue_element *element; + + TAILQ_FOREACH(element, head, elements) + if (element->key == key) { + void *value = element->value; + TAILQ_REMOVE(head, element, elements); + free(element); + return value; + } + + return NULL; +} + +void *table_get(struct keyvalue_table_head *head, uint32_t key) { + struct keyvalue_element *element; + + TAILQ_FOREACH(element, head, elements) + if (element->key == key) + return element->value; + + return NULL; +} + /* * Starts the given application by passing it through a shell. We use double fork * to avoid zombie processes. As the started application’s parent exits (immediately),