kbgwm

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

commit a33f910b951f6aa6f2ef1d85f89daa5129a4adb1
parent 84dfbc2d7dcea9e59d1f9adb51a4f25845a7ebad
Author: Kebigon <git@kebigon.xyz>
Date:   Tue, 10 Aug 2021 07:26:21 +0900

Extract list from client struct

Diffstat:
MMakefile | 2+-
Mclient.c | 79++++++++++++++++++++++---------------------------------------------------------
Mclient.h | 2--
Mevents.c | 18+++++++++++-------
Mkbgwm.c | 72++++++++++++++++++++++++++++++++++++++++++------------------------------
Mkbgwm.h | 2+-
Alist.c | 105+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alist.h | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Mxcbutils.c | 2+-
9 files changed, 234 insertions(+), 99 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,4 +1,4 @@ -OBJ = kbgwm.o xcbutils.o events.o client.o +OBJ = kbgwm.o xcbutils.o events.o client.o list.o CFLAGS+=-g -std=c99 -Wall -Wextra -pedantic -Wstrict-overflow -fno-strict-aliasing -I/usr/local/include -I/usr/X11R6/include -march=native LDFLAGS+=-L/usr/local/lib -L/usr/X11R6/lib -lxcb -lxcb-icccm -lxcb-keysyms diff --git a/client.c b/client.c @@ -17,6 +17,7 @@ #include "client.h" #include "kbgwm.h" +#include "list.h" #include "xcbutils.h" #include <assert.h> @@ -56,20 +57,7 @@ void client_add_workspace(struct client *client, uint_fast8_t workspace) assert(client != NULL); assert(workspace < workspaces_length); - if (workspaces[workspace] == NULL) - { - client->next = client; - client->previous = client; - } - else - { - client->next = workspaces[workspace]; - client->previous = workspaces[workspace]->previous; - client->next->previous = client; - client->previous->next = client; - } - - workspaces[workspace] = client; + list_add(&workspaces[workspace], client); } void client_create(xcb_window_t id) @@ -153,16 +141,8 @@ struct client *client_find_workspace(xcb_window_t id, uint_fast8_t workspace) { assert(workspace < workspaces_length); - struct client *client = workspaces[workspace]; - - if (client != NULL) - do - { - if (client->id == id) - return client; - } while ((client = client->next) != workspaces[workspace]); - - return NULL; + struct item *item = list_find(&workspaces[workspace], id); + return item == NULL ? NULL : item->data; } // Remove the focused client from the current workspace list @@ -175,39 +155,20 @@ struct client *client_remove() struct client *client_remove_workspace(uint_fast8_t workspace) { assert(workspace < workspaces_length); - assert(workspaces[workspace] != NULL); - - struct client *client = workspaces[workspace]; - if (client->next == client) - workspaces[workspace] = NULL; - else - { - client->previous->next = client->next; - client->next->previous = client->previous; - workspaces[workspace] = client->next; - } + assert(!list_is_empty(&workspaces[workspace])); - return client; + return list_remove_head(&workspaces[workspace]); } void client_remove_all_workspaces(xcb_window_t id) { + struct item *item; + for (uint_fast8_t workspace = 0; workspace != workspaces_length; workspace++) { - struct 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; - } - } + item = list_find(&workspaces[workspace], id); + if (item != NULL) + list_remove(&workspaces[workspace], item); } } @@ -241,14 +202,16 @@ void client_kill(__attribute__((unused)) const union Arg *arg) { printf("=======[ user action: client_kill ]=======\n"); + struct item *item = list_head(&workspaces[current_workspace]); + // No client are focused - if (workspaces[current_workspace] == NULL) + if (item == NULL) return; // Nothing to be done - if (!xcb_send_atom(workspaces[current_workspace], wm_delete_window)) + if (!xcb_send_atom(item->data, wm_delete_window)) { // The client does not support WM_DELETE, let's kill it - xcb_kill_client(c, workspaces[current_workspace]->id); + xcb_kill_client(c, item->data->id); } xcb_flush(c); @@ -258,11 +221,13 @@ void client_toggle_maximize(__attribute__((unused)) const union Arg *arg) { printf("=======[ user action: client_toggle_maximize ]=======\n"); + struct item *item = list_head(&workspaces[current_workspace]); + // No client are focused - if (workspaces[current_workspace] == NULL) + if (item == NULL) return; // Nothing to be done - struct client *client = workspaces[current_workspace]; + struct client *client = item->data; if (client->maximized) client_unmaximize(client); @@ -280,7 +245,7 @@ void client_maximize(struct client *client) client->maximized = true; uint32_t values[] = {0, 0, screen->width_in_pixels, screen->height_in_pixels, 0}; - xcb_configure_window(c, focused_client->id, + xcb_configure_window(c, client->id, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT | XCB_CONFIG_WINDOW_BORDER_WIDTH, values); @@ -294,7 +259,7 @@ void client_unmaximize(struct client *client) client->maximized = false; uint32_t values[] = {client->x, client->y, client->width, client->height, border_width}; - xcb_configure_window(c, focused_client->id, + xcb_configure_window(c, client->id, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT | XCB_CONFIG_WINDOW_BORDER_WIDTH, values); diff --git a/client.h b/client.h @@ -28,8 +28,6 @@ struct client int32_t min_width, min_height; int32_t max_width, max_height; bool maximized; - struct client *previous; - struct client *next; }; void client_grab_buttons(struct client *, bool); diff --git a/events.c b/events.c @@ -18,6 +18,7 @@ #include "events.h" #include "client.h" #include "kbgwm.h" +#include "list.h" #include "xcbutils.h" #include <assert.h> @@ -52,15 +53,16 @@ static void handle_button_press(xcb_generic_event_t *e) return; // Nothing to be done xcb_window_t window = event->event == event->root ? event->child : event->event; + struct item *focused = list_head(&workspaces[current_workspace]); // The window clicked is not the one in focus, we have to focus it - if (workspaces[current_workspace] == NULL || window != workspaces[current_workspace]->id) + if (focused == NULL || window != focused->data->id) { - struct client *client = client_find(window); - assert(client != NULL); + struct item *to_focus = list_find(&workspaces[current_workspace], window); + assert(to_focus != NULL); focus_unfocus(); - workspaces[current_workspace] = client; + list_move_to_head(&workspaces[current_workspace], to_focus); focus_apply(); } @@ -94,11 +96,13 @@ static void handle_button_release(__attribute__((unused)) xcb_generic_event_t *e static void handle_motion_notify(xcb_generic_event_t *e) { xcb_motion_notify_event_t *event = (xcb_motion_notify_event_t *)e; - struct client *client = workspaces[current_workspace]; + struct item *focused = list_head(&workspaces[current_workspace]); assert(moving || resizing); - assert(client != NULL); - assert(client->id != root); + assert(focused != NULL); + assert(focused->data->id != root); + + struct client *client = focused->data; if (client->maximized) client_unmaximize(client); diff --git a/kbgwm.c b/kbgwm.c @@ -17,6 +17,7 @@ #include "kbgwm.h" #include "events.h" +#include "list.h" #include "xcbutils.h" #include <X11/keysym.h> #include <assert.h> @@ -44,28 +45,31 @@ xcb_atom_t wm_protocols; xcb_atom_t wm_delete_window; uint_fast8_t current_workspace = 0; -struct client *workspaces[NB_WORKSPACES]; +struct item *workspaces[NB_WORKSPACES]; static inline void debug_print_globals() { printf("current_workspace=%d\n", current_workspace); + struct item *item; + struct client *client; + for (uint_fast8_t workspace = 0; workspace != workspaces_length; workspace++) { - if (workspaces[workspace] == NULL) - printf("%d\tNULL\n", workspace); - else + if ((item = list_head(&workspaces[workspace])) != NULL) { - struct client *client = workspaces[workspace]; do { + client = item->data; printf("%d\tid=%d x=%d y=%d width=%d height=%d min_width=%d min_height=%d " "max_width=%d max_height=%d\n", workspace, client->id, client->x, client->y, client->width, client->height, client->min_width, client->min_height, client->max_width, client->max_height); - } while ((client = client->next) != workspaces[workspace]); + } while ((item = item->next) != NULL); } + else + printf("%d\tNULL\n", workspace); } } @@ -215,20 +219,22 @@ void start(const union Arg *arg) void focus_apply() { - assert(workspaces[current_workspace] != NULL); + struct item *item = list_head(&workspaces[current_workspace]); + assert(item != NULL); + + struct client *client = item->data; // We change the color of the focused client - xcb_change_window_attributes(c, workspaces[current_workspace]->id, XCB_CW_BORDER_PIXEL, + xcb_change_window_attributes(c, client->id, XCB_CW_BORDER_PIXEL, (uint32_t[]){0xFF000000 | FOCUS_COLOR}); // Raise the window so it is on top - xcb_configure_window(c, workspaces[current_workspace]->id, XCB_CONFIG_WINDOW_STACK_MODE, + xcb_configure_window(c, client->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_INPUT_FOCUS_POINTER_ROOT, workspaces[current_workspace]->id, - XCB_CURRENT_TIME); - client_grab_buttons(workspaces[current_workspace], true); + xcb_set_input_focus(c, XCB_INPUT_FOCUS_POINTER_ROOT, client->id, XCB_CURRENT_TIME); + client_grab_buttons(client, true); xcb_flush(c); printf("focus_apply: done\n"); @@ -242,31 +248,33 @@ void focus_next(const union Arg *arg) // No clients in the current workspace list // Only one client in the current workspace list - if (workspaces[current_workspace] == NULL || - workspaces[current_workspace]->next == workspaces[current_workspace]) + if (list_is_empty(&workspaces[current_workspace]) || + list_head(&workspaces[current_workspace])->next == NULL) return; // Nothing to be done - struct client *new_focus = - arg->b ? workspaces[current_workspace]->previous : workspaces[current_workspace]->next; + struct item *new_focus = arg->b ? list_tail(&workspaces[current_workspace]) + : list_head(&workspaces[current_workspace])->next; focus_unfocus(); - workspaces[current_workspace] = new_focus; + list_move_to_head(&workspaces[current_workspace], new_focus); focus_apply(); } // Remove the focus from the current client void focus_unfocus() { - struct client *client = workspaces[current_workspace]; + struct item *item = list_head(&workspaces[current_workspace]); // No client are focused - if (client == NULL) + if (item == NULL) return; // Nothing to be done + struct client *client = item->data; + // Change the border color to UNFOCUS_COLOR xcb_change_window_attributes(c, client->id, XCB_CW_BORDER_PIXEL, (uint32_t[]){0xFF000000 | UNFOCUS_COLOR}); - client_grab_buttons(workspaces[current_workspace], false); + client_grab_buttons(client, false); } /* @@ -374,7 +382,7 @@ void workspace_send(const union Arg *arg) uint_fast8_t new_workspace = arg->i; - if (current_workspace == new_workspace || workspaces[current_workspace] == NULL) + if (current_workspace == new_workspace || list_is_empty(&workspaces[current_workspace])) return; // Nothing to be done struct client *client = client_remove(); @@ -392,26 +400,30 @@ void workspace_set(uint_fast8_t new_workspace) if (current_workspace == new_workspace) return; // Nothing to be done + struct item *item; + // Unmap the clients of the current workspace (if any) - struct client *client = workspaces[current_workspace]; - if (client != NULL) + if ((item = list_head(&workspaces[current_workspace])) != NULL) + { do { - xcb_unmap_window(c, client->id); - } while ((client = client->next) != workspaces[current_workspace]); + xcb_unmap_window(c, item->data->id); + } while ((item = item->next) != NULL); + } // Map the clients of the new workspace (if any) - client = workspaces[new_workspace]; - if (client != NULL) + if ((item = list_head(&workspaces[new_workspace])) != NULL) + { do { - xcb_map_window(c, client->id); - } while ((client = client->next) != workspaces[new_workspace]); + xcb_map_window(c, item->data->id); + } while ((item = item->next) != NULL); + } xcb_flush(c); current_workspace = new_workspace; - if (workspaces[current_workspace] != NULL) + if (!list_is_empty(&workspaces[current_workspace])) focus_apply(); printf("workspace_set: done\n"); diff --git a/kbgwm.h b/kbgwm.h @@ -49,7 +49,7 @@ extern uint16_t numlockmask; extern xcb_atom_t wm_protocols; extern xcb_atom_t wm_delete_window; extern uint_fast8_t current_workspace; -extern struct client *workspaces[]; +extern struct item *workspaces[]; extern const struct Key keys[]; extern const struct Button buttons[]; diff --git a/list.c b/list.c @@ -0,0 +1,105 @@ +/* + * kbgwm, a sucklessy floating window manager + * Copyright (c) 2020-2021, Kebigon <git@kebigon.xyz> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "list.h" + +#include <stdio.h> +#include <stdlib.h> + +#include "xcbutils.h" + +struct item *list_tail(struct item **list) +{ + if (list_is_empty(list)) + return NULL; + struct item *item = *list; + + while (item->next != NULL) + item = item->next; + return item; +} + +void list_move_to_head(struct item **list, struct item *item) +{ + if (list_is_empty(list)) + return; + + if (item->previous != NULL) + item->previous->next = item->next; + if (item->next != NULL) + item->next->previous = item->previous; + + item->previous = NULL; + item->next = *list; + item->next->previous = item; + *list = item; +} + +// Add a client to the head of the list +void list_add(struct item **list, struct client *e) +{ + struct item *item = emalloc(sizeof(struct item)); + item->data = e; + item->previous = NULL; + item->next = *list; + + if (item->next != NULL) + item->next->previous = item; + + *list = item; +} + +// Remove an item from the list +struct client *list_remove(struct item **list, struct item *item) +{ + if (list_is_empty(list)) + return NULL; + + struct client *data = item->data; + + if (item->previous != NULL) + item->previous->next = item->next; + if (item->next != NULL) + item->next->previous = item->previous; + if (item == *list) + *list = item->next; + + free(item); + return data; +} + +// Remove the client from the head of the list +struct client *list_remove_head(struct item **list) +{ + return list_is_empty(list) ? NULL : list_remove(list, *list); +} + +struct item *list_find(struct item **list, xcb_window_t id) +{ + if (list_is_empty(list)) + return NULL; + + struct item *item = *list; + + do + { + if (item->data->id == id) + return item; + } while ((item = item->next) != NULL); + + return NULL; +} diff --git a/list.h b/list.h @@ -0,0 +1,51 @@ +/* + * kbgwm, a sucklessy floating window manager + * Copyright (c) 2020-2021, Kebigon <git@kebigon.xyz> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#pragma once + +#include <stdbool.h> +#include <xcb/xproto.h> + +struct item +{ + struct client *data; + struct item *previous; + struct item *next; +}; + +struct item *list_tail(struct item **); +void list_move_to_head(struct item **, struct item *); + +void list_add(struct item **, struct client *); +struct client *list_remove(struct item **, struct item *); +struct client *list_remove_head(struct item **); + +struct item *list_find(struct item **, xcb_window_t); + +// returns true if the list contains no items +// the goal of this function is to make the intent explicit +static inline bool list_is_empty(struct item **list) +{ + return *list == NULL; +} + +// returns the head of the list +// the goal of this function is to make the intent explicit +static inline struct item *list_head(struct item **list) +{ + return *list; +} diff --git a/xcbutils.c b/xcbutils.c @@ -33,7 +33,7 @@ void *emalloc(size_t size) { void *p; - printf("client size=%zu\n", size); + printf("emalloc size=%zu\n", size); if (!(p = malloc(size))) {