kbgwm

sucklessy floating window manager
git clone https://git.neuralcrash.com/kbgwm.git
Log | Files | Refs | README | LICENSE

commit d529d70d8505cd01e4455a3a2aa21a3633204904
parent f9ca3e38c03ef7aedc53e65ea7e10f8907623c76
Author: Kebigon <git@kebigon.xyz>
Date:   Sat, 18 Jul 2020 14:24:44 +0900

Working implementation

Diffstat:
MMakefile | 2+-
Mconfig.h | 56++++++++++++++++++++++++--------------------------------
Mkbgwm.c | 413++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Mtypes.h | 29+++++++++++------------------
Mxcbutils.c | 103++++++++++++++++++++++---------------------------------------------------------
Mxcbutils.h | 37++++++++-----------------------------
6 files changed, 364 insertions(+), 276 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,7 +1,7 @@ OBJ = kbgwm.o xcbutils.o CFLAGS+=-g -std=c99 -Wall -Wextra -I/usr/local/include -LDFLAGS+=-L/usr/local/lib -lxcb -lxcb-keysyms +LDFLAGS+=-L/usr/local/lib -lxcb -lxcb-icccm -lxcb-keysyms all: clean format kbgwm diff --git a/config.h b/config.h @@ -12,45 +12,37 @@ */ #define NB_WORKSPACES 10 -static const char* termcmd [] = { "alacritty", - NULL }; -static const char* menucmd [] = { "dmenu_run", - NULL }; +static const char* termcmd[] = { "xterm", NULL }; +static const char* menucmd[] = { "dmenu_run", NULL }; #define WORKSPACEKEYS(KEY,WORKSPACE) \ - { MODKEY|XCB_MOD_MASK_SHIFT, KEY, workspace_send, {.i = WORKSPACE} }, \ + { MODKEY|XCB_MOD_MASK_SHIFT, KEY, workspace_send, {.i = WORKSPACE} }, \ { MODKEY, KEY, workspace_change, {.i = WORKSPACE} }, -static Key keys [] = +static Key keys[] = { - { MODKEY, XK_Return, start, { .cmd = termcmd }}, - { MODKEY, XK_p, start, { .cmd = menucmd }}, - { MODKEY, XK_Page_Up, workspace_previous, { 0 }}, - { MODKEY, XK_Page_Down, workspace_next, { 0 }}, - { MODKEY|SHIFT, XK_Tab, focus_next, { .b = true }}, - { MODKEY, XK_Tab, focus_next, { .b = false }}, + { MODKEY, XK_Return, start, { .cmd = termcmd } }, + { MODKEY, XK_p, start, { .cmd = menucmd } }, + { MODKEY, XK_Page_Up, workspace_previous, { 0 } }, + { MODKEY, XK_Page_Down, workspace_next, { 0 } }, + { MODKEY | SHIFT, XK_Tab, focus_next, { .b = true } }, + { MODKEY, XK_Tab, focus_next, { .b = false } }, WORKSPACEKEYS(XK_Home, 0) - WORKSPACEKEYS(XK_1, 0) - WORKSPACEKEYS(XK_2, 1) - WORKSPACEKEYS(XK_3, 2) - WORKSPACEKEYS(XK_4, 3) - WORKSPACEKEYS(XK_5, 4) - WORKSPACEKEYS(XK_6, 5) - WORKSPACEKEYS(XK_7, 6) - WORKSPACEKEYS(XK_8, 7) - WORKSPACEKEYS(XK_9, 8) - WORKSPACEKEYS(XK_0, 9) - WORKSPACEKEYS(XK_End, 9) + WORKSPACEKEYS(XK_1, 0) + WORKSPACEKEYS(XK_2, 1) + WORKSPACEKEYS(XK_3, 2) + WORKSPACEKEYS(XK_4, 3) + WORKSPACEKEYS(XK_5, 4) + WORKSPACEKEYS(XK_6, 5) + WORKSPACEKEYS(XK_7, 6) + WORKSPACEKEYS(XK_8, 7) + WORKSPACEKEYS(XK_9, 8) + WORKSPACEKEYS(XK_0, 9) + WORKSPACEKEYS(XK_End, 9) }; -static Button buttons [] = +static Button buttons[] = { - { MODKEY, - XCB_BUTTON_INDEX_1, - mousemove, - { 0 }}, - { MODKEY, - XCB_BUTTON_INDEX_3, - mouseresize, - { 0 }}, + { MODKEY, XCB_BUTTON_INDEX_1, mousemove, { 0 } }, + { MODKEY, XCB_BUTTON_INDEX_3, mouseresize, { 0 } }, }; diff --git a/kbgwm.c b/kbgwm.c @@ -3,8 +3,9 @@ #include <stdint.h> #include <unistd.h> #include <assert.h> - +#include <math.h> #include <xcb/xcb.h> +#include <xcb/xcb_icccm.h> #include <X11/keysym.h> #include <inttypes.h> #include "xcbutils.h" @@ -19,22 +20,33 @@ static void mouseresize(const Arg* arg); static void client_add(client*); static void client_add_workspace(client*, uint_fast8_t); static client* client_find(xcb_window_t); +static client* client_find_workspace(xcb_window_t, uint_fast8_t); static client* client_remove(); static client* client_remove_workspace(uint_fast8_t); -static void focus_apply(client*); +static void client_create(xcb_window_t); +static void client_sanitize_position(client*); +static void client_sanitize_dimensions(client*); +static void focus_apply(); static void focus_next(const Arg*); +static void focus_unfocus(); static void handle_button_press(xcb_button_press_event_t*); static void handle_button_release(xcb_button_release_event_t*); +static void handle_destroy_notify(xcb_destroy_notify_event_t*); static void handle_key_press(xcb_key_press_event_t*); static void handle_map_request(xcb_map_request_event_t*); static void handle_mapping_notify(xcb_mapping_notify_event_t*); static void handle_motion_notify(xcb_motion_notify_event_t*); +static void handle_unmap_notify(xcb_unmap_notify_event_t*); static void workspace_change(const Arg*); static void workspace_next(const Arg*); static void workspace_previous(const Arg*); static void workspace_send(const Arg*); static void workspace_set(uint_fast8_t); +static inline int16_t int16_in_range(int16_t, int16_t, int16_t); +static inline uint16_t uint16_in_range(uint16_t, uint16_t, uint16_t); +static inline void debug_print_globals(); + #include "config.h" #define BORDER_WIDTH_X2 (BORDER_WIDTH << 1) @@ -48,55 +60,66 @@ xcb_screen_t* screen; uint_least16_t previous_x; uint_least16_t previous_y; -#define focusedWindow workspaces[current_workspace] +#define focused_client workspaces[current_workspace] uint_fast8_t current_workspace = 0; static client* workspaces[NB_WORKSPACES]; -void setupEvents() +inline int16_t int16_in_range(int16_t value, int16_t min, int16_t max) { - uint32_t values[] = { XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT - | XCB_EVENT_MASK_STRUCTURE_NOTIFY - | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY }; - - xcb_change_window_attributes_checked(c, root, XCB_CW_EVENT_MASK, values); - - xcb_grab_button(c, 1, root, XCB_EVENT_MASK_BUTTON_PRESS, - XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, root, - XCB_NONE, XCB_BUTTON_INDEX_1, 0 | XCB_MOD_MASK_2); - xcb_grab_button(c, 1, root, XCB_EVENT_MASK_BUTTON_PRESS, - XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, root, - XCB_NONE, XCB_BUTTON_INDEX_3, 0 | XCB_MOD_MASK_2); - - for (uint_fast8_t i = 0; i != LENGTH(keys); i++) - xcb_register_key_events(keys[i]); - - for (uint_fast8_t i = 0; i != LENGTH(buttons); i++) - xcb_register_button_events(buttons[i]); + if (value < min) + return min; + else if (value > max) + return max; + else + return value; +} +inline uint16_t uint16_in_range(uint16_t value, uint16_t min, uint16_t max) +{ + if (value < min) + return min; + else if (value > max) + return max; + else + return value; +} +inline void debug_print_globals() +{ + printf("current_workspace=%d\n", current_workspace); - xcb_flush(c); + for (int workspace = 0; workspace != NB_WORKSPACES; workspace++) + { + if (workspaces[workspace] == NULL) + printf("%d\tNULL\n", workspace); + else + { + client* client = workspaces[workspace]; + do + { + printf("%d\tid=%d\n", workspace, client->id); + } while ((client = client->next) != workspaces[workspace]); + } + } } -void mousemove(__attribute__((unused)) const Arg* arg) +void mousemove(__attribute__((unused)) const Arg* arg) { printf("mousemove\n"); moving = true; - xcb_grab_pointer(c, 0, screen->root, - XCB_EVENT_MASK_BUTTON_MOTION | XCB_EVENT_MASK_BUTTON_RELEASE, - XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, screen->root, + xcb_grab_pointer(c, 0, screen->root, XCB_EVENT_MASK_BUTTON_MOTION | XCB_EVENT_MASK_BUTTON_RELEASE, XCB_GRAB_MODE_ASYNC, + XCB_GRAB_MODE_ASYNC, screen->root, XCB_NONE, XCB_CURRENT_TIME); xcb_flush(c); } -void mouseresize(__attribute__((unused)) const Arg* arg) +void mouseresize(__attribute__((unused)) const Arg* arg) { printf("mouseresize\n"); resizing = true; - xcb_grab_pointer(c, 0, screen->root, - XCB_EVENT_MASK_BUTTON_MOTION | XCB_EVENT_MASK_BUTTON_RELEASE, - XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, screen->root, + xcb_grab_pointer(c, 0, screen->root, XCB_EVENT_MASK_BUTTON_MOTION | XCB_EVENT_MASK_BUTTON_RELEASE, XCB_GRAB_MODE_ASYNC, + XCB_GRAB_MODE_ASYNC, screen->root, XCB_NONE, XCB_CURRENT_TIME); xcb_flush(c); @@ -107,10 +130,13 @@ void eventLoop() while (!quit) { xcb_generic_event_t* event = xcb_wait_for_event(c); - printf("event: received\n"); switch (event->response_type & ~0x80) { + case XCB_KEY_PRESS: + handle_key_press((xcb_key_press_event_t*) event); + break; + case XCB_BUTTON_PRESS: handle_button_press((xcb_button_press_event_t*) event); break; @@ -119,8 +145,16 @@ void eventLoop() handle_button_release((xcb_button_release_event_t*) event); break; - case XCB_KEY_PRESS: - handle_key_press((xcb_key_press_event_t*) event); + case XCB_MOTION_NOTIFY: + handle_motion_notify((xcb_motion_notify_event_t*) event); + break; + + case XCB_DESTROY_NOTIFY: + handle_destroy_notify((xcb_destroy_notify_event_t*) event); + break; + + case XCB_UNMAP_NOTIFY: + handle_unmap_notify((xcb_unmap_notify_event_t*) event); break; case XCB_MAP_REQUEST: @@ -131,19 +165,12 @@ void eventLoop() handle_mapping_notify((xcb_mapping_notify_event_t*) event); break; - case XCB_MOTION_NOTIFY: - handle_motion_notify((xcb_motion_notify_event_t*) event); - break; - default: - printf("Received event, response type %d\n", - event->response_type & ~0x80); + printf("Received unhandled event, response type %d\n", event->response_type & ~0x80); break; } - printf("event: handled\n"); free(event); - printf("event: freed\n"); printf("\n"); } } @@ -186,7 +213,8 @@ void client_add_workspace(client* client, uint_fast8_t workspace) client->next = client; client->previous = client; } - else { + else + { client->next = workspaces[workspace]; client->previous = workspaces[workspace]->previous; client->next->previous = client; @@ -196,18 +224,68 @@ void client_add_workspace(client* client, uint_fast8_t workspace) workspaces[workspace] = client; } +void client_create(xcb_window_t id) +{ + printf("client_create: id=%d\n", id); + + // Request the information for the window + + xcb_get_geometry_reply_t* geometry = xcb_get_geometry_reply(c, xcb_get_geometry_unchecked(c, id), NULL); + xcb_size_hints_t hints; + xcb_icccm_get_wm_normal_hints_reply(c, xcb_icccm_get_wm_normal_hints_unchecked(c, id), &hints, + NULL); + + client* new_client = emalloc(sizeof(client)); + + new_client->id = id; + new_client->x = hints.flags & XCB_ICCCM_SIZE_HINT_P_POSITION ? hints.x : geometry->x; + new_client->y = hints.flags & XCB_ICCCM_SIZE_HINT_P_POSITION ? hints.y : geometry->y; + new_client->width = hints.flags & XCB_ICCCM_SIZE_HINT_P_SIZE ? hints.width : geometry->width; + new_client->height = hints.flags & XCB_ICCCM_SIZE_HINT_P_SIZE ? hints.height : geometry->height; + new_client->min_width = hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE ? hints.min_width : 0; + new_client->min_height = hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE ? hints.min_height : 0; + new_client->max_width = hints.flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE ? hints.max_width : 0xFFFF; + new_client->max_height = hints.flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE ? hints.max_height : 0xFFFF; + + client_sanitize_dimensions(new_client); + + focus_unfocus(); + client_add(new_client); + focus_apply(); + + printf("new window: id=%d x=%d y=%d width=%d height=%d min_width=%d min_height=%d max_width=%d max_height=%d\n", id, + new_client->x, new_client->y, new_client->width, new_client->height, new_client->min_width, new_client->min_height, + new_client->max_width, new_client->max_height); + + xcb_configure_window(c, id, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT | XCB_CONFIG_WINDOW_BORDER_WIDTH, (uint32_t[] ) + { new_client->width, new_client->height, BORDER_WIDTH }); + + // Display the client + xcb_map_window(c, new_client->id); + xcb_flush(c); + + free(geometry); + printf("client_create: done\n"); +} + // Find a client in the current workspace list client* client_find(xcb_window_t id) { - client* client = workspaces[current_workspace]; + return client_find_workspace(id, current_workspace); +} + +client* client_find_workspace(xcb_window_t id, uint_fast8_t workspace) +{ + assert(workspace < NB_WORKSPACES); + + client* client = workspaces[workspace]; if (client != NULL) do { if (client->id == id) return client; - } - while ((client = client->next) != workspaces[current_workspace]); + } while ((client = client->next) != workspaces[current_workspace]); return NULL; } @@ -227,7 +305,8 @@ client* client_remove_workspace(uint_fast8_t workspace) client* client = workspaces[workspace]; if (client->next == client) workspaces[workspace] = NULL; - else { + else + { client->previous->next = client->next; client->next->previous = client->previous; workspaces[workspace] = client->next; @@ -236,31 +315,69 @@ client* client_remove_workspace(uint_fast8_t workspace) return client; } +void client_remove_all_workspaces(xcb_window_t id) +{ + for (uint_fast8_t workspace = 0; workspace != NB_WORKSPACES; workspace++) + { + client* client = client_find_workspace(id, workspace); + if (client != NULL) + { + if (client->next == client) + workspaces[workspace] = NULL; + else + { + client->previous->next = client->next; + client->next->previous = client->previous; + + if (workspaces[workspace] == client) + workspaces[workspace] = client->next; + } + } + } +} + +void client_sanitize_position(client* client) +{ + int16_t x = int16_in_range(client->x, 0, screen->width_in_pixels - client->width - BORDER_WIDTH_X2); + if (client->x != x) + client->x = x; + + int16_t y = int16_in_range(client->y, 0, screen->height_in_pixels - client->height - BORDER_WIDTH_X2); + if (client->y != y) + client->y = y; +} + +void client_sanitize_dimensions(client* client) +{ + uint16_t width = uint16_in_range(client->width, client->min_width, client->max_width); + width = uint16_in_range(width, 0, screen->width_in_pixels - client->x - BORDER_WIDTH_X2); + if (client->width != width) + client->width = width; + + uint16_t height = uint16_in_range(client->height, client->min_height, client->max_height); + height = uint16_in_range(height, 0, screen->height_in_pixels - client->y - BORDER_WIDTH_X2); + if (client->height != height) + client->height = height; +} + /* * Focus */ -void focus_apply(client* new_focus) +void focus_apply() { assert(workspaces[current_workspace] != NULL); - assert(new_focus != NULL); - - printf("focus_apply: old=%d new=%d\n", workspaces[current_workspace]->id, new_focus->id); - - uint32_t values[1]; - - // We change the color of the previously focused client - xcb_change_window_attributes(c, workspaces[current_workspace]->id, XCB_CW_BORDER_PIXEL, (uint32_t[]) { 0xFF000000 | UNFOCUS_COLOR }); // We change the color of the focused client - xcb_change_window_attributes(c, new_focus->id, XCB_CW_BORDER_PIXEL, (uint32_t[]) { 0xFF000000 | FOCUS_COLOR }); + xcb_change_window_attributes(c, workspaces[current_workspace]->id, XCB_CW_BORDER_PIXEL, (uint32_t[] ) + { 0xFF000000 | FOCUS_COLOR }); // Raise the window so it is on top - values[0] = XCB_STACK_MODE_TOP_IF; - xcb_configure_window(c, new_focus->id, XCB_CONFIG_WINDOW_STACK_MODE, values); + xcb_configure_window(c, workspaces[current_workspace]->id, XCB_CONFIG_WINDOW_STACK_MODE, (uint32_t[] ) + { XCB_STACK_MODE_ABOVE }); // Set the keyboard on the focused window - xcb_set_input_focus(c, XCB_NONE, new_focus->id, XCB_CURRENT_TIME); + xcb_set_input_focus(c, XCB_INPUT_FOCUS_POINTER_ROOT, workspaces[current_workspace]->id, XCB_CURRENT_TIME); xcb_flush(c); printf("focus_apply: done\n"); @@ -277,10 +394,21 @@ void focus_next(const Arg* arg) client* new_focus = arg->b ? workspaces[current_workspace]->previous : workspaces[current_workspace]->next; + focus_unfocus(); + workspaces[current_workspace] = new_focus; focus_apply(new_focus); +} - // Move the newly focused window to the front of the list - workspaces[current_workspace] = new_focus; +// Remove the focus from the current client +void focus_unfocus() +{ + // No client are focused + if (workspaces[current_workspace] == NULL) + return; // Nothing to be done + + // Change the border color to UNFOCUS_COLOR + xcb_change_window_attributes(c, workspaces[current_workspace]->id, XCB_CW_BORDER_PIXEL, (uint32_t[] ) + { 0xFF000000 | UNFOCUS_COLOR }); } /* @@ -290,18 +418,26 @@ void focus_next(const Arg* arg) void handle_button_press(xcb_button_press_event_t* event) { printf("handle_button_press: client=%d modifier=%d button=%d\n", event->child, event->state, event->detail); + debug_print_globals(); // Click on the root window if (event->child == 0) return; // Nothing to be done // The window clicked is not the one in focus, we have to focus it - if (focusedWindow == NULL || event->child != focusedWindow->id) - focus_apply(client_find(event->child)); + if (workspaces[current_workspace] == NULL || event->child != workspaces[current_workspace]->id) + { + client* client = client_find(event->child); + assert(client != NULL); + + focus_unfocus(); + workspaces[current_workspace] = client; + focus_apply(); + } for (uint_fast8_t i = 0; i < LENGTH(buttons); i++) { - if (event->detail == buttons[i].keysym && MATCH_MODIFIERS(buttons[i].modifiers,event->state)) + if (event->detail == buttons[i].keysym && MATCH_MODIFIERS(buttons[i].modifiers, event->state)) { previous_x = event->root_x; previous_y = event->root_y; @@ -327,6 +463,14 @@ void handle_button_release(__attribute__((unused)) xcb_button_release_event_t* e resizing = false; } +void handle_destroy_notify(xcb_destroy_notify_event_t* event) +{ + printf("XCB_DESTROY_NOTIFY: window=%d\n", event->window); + client_remove_all_workspaces(event->window); + if (focused_client != NULL) + focus_apply(); +} + void handle_key_press(xcb_key_press_event_t* event) { printf("XCB_KEY_PRESS: detail=%d state=%d\n", event->detail, event->state); @@ -346,28 +490,7 @@ void handle_map_request(xcb_map_request_event_t* event) { printf("handle_map_request: parent %d xcb_window_t %d\n", event->parent, event->window); - xcb_get_geometry_reply_t* geometry = xcb_get_geometry_reply(c, xcb_get_geometry_unchecked(c, event->window), NULL); - - client* new_client = emalloc(sizeof(client)); - - new_client->id = event->window; - new_client->x = geometry->x; - new_client->y = geometry->y; - new_client->width = geometry->width; - new_client->height = geometry->height; - - focus_apply(new_client); - client_add(new_client); - - printf("new window: id=%d x=%d y=%d width=%d height=%d\n", new_client->id, new_client->x, new_client->y, new_client->width, new_client->height); - - xcb_configure_window(c, new_client->id, XCB_CONFIG_WINDOW_BORDER_WIDTH, (uint32_t[]) { BORDER_WIDTH }); - - // Display the client - xcb_map_window(c, new_client->id); - xcb_flush(c); - - free(geometry); + client_create(event->window); printf("handle_map_request: done\n"); } @@ -383,47 +506,94 @@ void handle_mapping_notify(xcb_mapping_notify_event_t* event) void handle_motion_notify(xcb_motion_notify_event_t* event) { assert(moving || resizing); - assert(focusedWindow != NULL); - assert(focusedWindow->id != root); + assert(focused_client != NULL); + assert(focused_client->id != root); - printf("handle_motionnotify: root_x=%d root_y=%d event_x=%d event_y=%d\n", - event->root_x, event->root_y, event->event_x, event->event_y); + printf("handle_motionnotify: root_x=%d root_y=%d event_x=%d event_y=%d\n", event->root_x, event->root_y, event->event_x, + event->event_y); - uint16_t diff_x = event->root_x - previous_x; - uint16_t diff_y = event->root_y - previous_y; + int16_t diff_x = event->root_x - previous_x; + int16_t diff_y = event->root_y - previous_y; previous_x = event->root_x; previous_y = event->root_y; if (moving) { - focusedWindow->x += diff_x; - focusedWindow->y += diff_y; - - if (focusedWindow->x < 0) - focusedWindow->x = 0; - else if (focusedWindow->x + focusedWindow->width + BORDER_WIDTH_X2 > screen->width_in_pixels) - focusedWindow->x = screen->width_in_pixels - focusedWindow->width - BORDER_WIDTH_X2; + focused_client->x += diff_x; + focused_client->y += diff_y; + client_sanitize_position(focused_client); - if (focusedWindow->y < 0) - focusedWindow->y = 0; - else if (focusedWindow->y + focusedWindow->height + BORDER_WIDTH_X2 > screen->height_in_pixels) - focusedWindow->y = screen->height_in_pixels - focusedWindow->height - BORDER_WIDTH_X2; - - uint32_t values[2] = { focusedWindow->x, focusedWindow->y }; - xcb_configure_window(c, focusedWindow->id, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values); + uint32_t values[2] = + { focused_client->x, focused_client->y}; + xcb_configure_window(c, focused_client->id, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values); } else if (resizing) { - focusedWindow->width += diff_x; - focusedWindow->height += diff_y; + focused_client->width += diff_x; + focused_client->height += diff_y; + client_sanitize_dimensions(focused_client); - uint32_t values[2] = { focusedWindow->width, focusedWindow->height }; - xcb_configure_window(c, focusedWindow->id, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values); + uint32_t values[2] = + { focused_client->width, focused_client->height}; + xcb_configure_window(c, focused_client->id, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values); } xcb_flush(c); } +void handle_unmap_notify(xcb_unmap_notify_event_t* event) +{ + printf("XCB_UNMAP_NOTIFY: window=%d\n", event->window); + client_remove_all_workspaces(event->window); + if (focused_client != NULL) + focus_apply(); +} + +/* + * Setup + */ + +void setup_events() +{ + uint32_t values[] = { XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_STRUCTURE_NOTIFY + | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY }; + + xcb_change_window_attributes_checked(c, root, XCB_CW_EVENT_MASK, values); + + xcb_grab_button(c, 1, root, XCB_EVENT_MASK_BUTTON_PRESS, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE, + XCB_BUTTON_INDEX_1, 0 | XCB_MOD_MASK_2); + xcb_grab_button(c, 1, root, XCB_EVENT_MASK_BUTTON_PRESS, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE, + XCB_BUTTON_INDEX_3, 0 | XCB_MOD_MASK_2); + + for (uint_fast8_t i = 0; i != LENGTH(keys); i++) + xcb_register_key_events(keys[i]); + + for (uint_fast8_t i = 0; i != LENGTH(buttons); i++) + xcb_register_button_events(buttons[i]); + + xcb_flush(c); +} + +void setup_screen() +{ + // Retrieve the children of the root window + xcb_query_tree_reply_t* reply = xcb_query_tree_reply(c, xcb_query_tree(c, screen->root), 0); + if (NULL == reply) + { + printf("Unable to retrieve the root window's children"); + exit(-1); + } + + int len = xcb_query_tree_children_length(reply); + xcb_window_t* children = xcb_query_tree_children(reply); + + // Create the corresponding clients + for (int i = 0; i != len; i++) + client_create(children[i]); + + free(reply); +} + /* * Workspaces */ @@ -435,14 +605,14 @@ void workspace_change(const Arg* arg) printf("workspace_change: done\n"); } -void workspace_next(__attribute__((unused)) const Arg* arg) +void workspace_next(__attribute__((unused)) const Arg* arg) { printf("workspace_next\n"); - workspace_set(current_workspace + 1 == NB_WORKSPACES ? 0 : current_workspace + 1 ); + workspace_set(current_workspace + 1 == NB_WORKSPACES ? 0 : current_workspace + 1); printf("workspace_next: done\n"); } -void workspace_previous(__attribute__((unused)) const Arg* arg) +void workspace_previous(__attribute__((unused)) const Arg* arg) { printf("workspace_previous\n"); workspace_set(current_workspace == 0 ? NB_WORKSPACES - 1 : current_workspace - 1); @@ -475,18 +645,18 @@ void workspace_set(uint_fast8_t new_workspace) // Unmap the clients of the current workspace (if any) client* client = workspaces[current_workspace]; if (client != NULL) - do { + do + { xcb_unmap_window(c, client->id); - } - while ((client = client->next) != workspaces[current_workspace]); + } while ((client = client->next) != workspaces[current_workspace]); // Map the clients of the new workspace (if any) client = workspaces[new_workspace]; if (client != NULL) - do { + do + { xcb_map_window(c, client->id); - } - while ((client = client->next) != workspaces[new_workspace]); + } while ((client = client->next) != workspaces[new_workspace]); xcb_flush(c); current_workspace = new_workspace; @@ -543,7 +713,8 @@ int main(void) for (uint_fast8_t i = 0; i != NB_WORKSPACES; i++) workspaces[i] = NULL; - setupEvents(); + setup_screen(); + setup_events(); // Event loop eventLoop(); diff --git a/types.h b/types.h @@ -8,39 +8,32 @@ typedef union const bool b; const uint_least8_t i; const char** cmd; -} -Arg; +} Arg; typedef struct { uint16_t modifiers; xcb_keysym_t keysym; - void (*func) - ( - const Arg* - ); + void (* func)(const Arg*); const Arg arg; -} -Key; +} Key; typedef struct { uint16_t modifiers; xcb_button_t keysym; - void (*func) - ( - const Arg* - ); + void (* func)(const Arg*); const Arg arg; -} -Button; +} Button; -typedef struct clientstruct client; -struct clientstruct +typedef struct client_t client; +struct client_t { xcb_window_t id; - int_least16_t x, y; - uint_least16_t width, height; + int16_t x, y; + uint16_t width, height; + int32_t min_width, min_height; + int32_t max_width, max_height; client* previous; client* next; }; diff --git a/xcbutils.c b/xcbutils.c @@ -12,9 +12,9 @@ void* emalloc(size_t size) printf("client size=%zd\n", size); - if (!(p = malloc( size ))) + if (!(p = malloc(size))) { - printf ("Out of memory" ); + printf("Out of memory"); exit(-1); } @@ -28,115 +28,68 @@ void* emalloc(size_t size) // TODO: understand why XCB_MOD_MASK_2 is always present #define IGNORED_MODIFIERS XCB_MOD_MASK_2 -void xcb_register_key_events -( - Key key -) +void xcb_register_key_events(Key key) { xcb_keycode_t* keycodes; xcb_keycode_t keycode; - printf ( - "Registering key press event for key %d / key %d\n", - key.modifiers, - key.keysym ); + printf("Registering key press event for key %d / key %d\n", key.modifiers, + key.keysym); - keycodes = xcb_get_keycodes ( - key.keysym ); + keycodes = xcb_get_keycodes(key.keysym); - for ( int i = 0; (keycode = keycodes [ i ]) != XCB_NO_SYMBOL; i++ ) + for (int i = 0; (keycode = keycodes[i]) != XCB_NO_SYMBOL; i++) { - xcb_grab_key ( - c, - 1, - root, - key.modifiers | IGNORED_MODIFIERS, - keycode, - XCB_GRAB_MODE_ASYNC, - XCB_GRAB_MODE_ASYNC ); + xcb_grab_key(c, 1, root, key.modifiers | IGNORED_MODIFIERS, keycode, + XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); } - free ( - keycodes ); + free(keycodes); } -void xcb_register_button_events -( - Button button -) +void xcb_register_button_events(Button button) { - xcb_grab_button ( - c, - 0, - root, - BUTTON_EVENT_MASK, - XCB_GRAB_MODE_ASYNC, - XCB_GRAB_MODE_ASYNC, - root, - XCB_NONE, - button.keysym, - button.modifiers | IGNORED_MODIFIERS ); + xcb_grab_button(c, 0, root, + BUTTON_EVENT_MASK, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, root, + XCB_NONE, button.keysym, button.modifiers | IGNORED_MODIFIERS); } /* * Get keycodes from a keysym * TODO: check if there's a way to keep keysyms */ -xcb_keycode_t* xcb_get_keycodes -( - xcb_keysym_t keysym -) +xcb_keycode_t* xcb_get_keycodes(xcb_keysym_t keysym) { xcb_key_symbols_t* keysyms; - if ( !(keysyms = xcb_key_symbols_alloc ( - c )) - ) + if (!(keysyms = xcb_key_symbols_alloc(c))) { - perror ( - "Not able to retrieve symbols" ); - return - (NULL); + perror("Not able to retrieve symbols"); + return (NULL); } - xcb_keycode_t* keycode = xcb_key_symbols_get_keycode ( - keysyms, - keysym ); + xcb_keycode_t* keycode = xcb_key_symbols_get_keycode(keysyms, keysym); - xcb_key_symbols_free ( - keysyms ); - return - (keycode); + xcb_key_symbols_free(keysyms); + return (keycode); } /* * Get keysym from a keycode * TODO: check if there's a way to keep keysyms */ -xcb_keysym_t xcb_get_keysym -( - xcb_keycode_t keycode -) +xcb_keysym_t xcb_get_keysym(xcb_keycode_t keycode) { xcb_key_symbols_t* keysyms; - if ( !(keysyms = xcb_key_symbols_alloc ( - c )) - ) + if (!(keysyms = xcb_key_symbols_alloc(c))) { - perror ( - "Not able to retrieve symbols" ); - return - (0); + perror("Not able to retrieve symbols"); + return (0); } - xcb_keysym_t keysym = xcb_key_symbols_get_keysym ( - keysyms, - keycode, - 0 ); + xcb_keysym_t keysym = xcb_key_symbols_get_keysym(keysyms, keycode, 0); - xcb_key_symbols_free ( - keysyms ); - return - (keysym); + xcb_key_symbols_free(keysyms); + return (keysym); } diff --git a/xcbutils.h b/xcbutils.h @@ -10,35 +10,15 @@ #define BUTTON_EVENT_MASK XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE -void* -emalloc -( - size_t size -); +void* emalloc(size_t size); /* * registering events */ -void -xcb_register_key_events -( - Key key -); -void -xcb_register_button_events -( - Button button -); - -xcb_keycode_t* -xcb_get_keycodes -( - xcb_keysym_t -); -xcb_keysym_t -xcb_get_keysym -( - xcb_keycode_t -); - -#endif /* XCBUTILS_H_ */ -\ No newline at end of file +void xcb_register_key_events(Key key); +void xcb_register_button_events(Button button); + +xcb_keycode_t* xcb_get_keycodes(xcb_keysym_t); +xcb_keysym_t xcb_get_keysym(xcb_keycode_t); + +#endif /* XCBUTILS_H_ */