commit a33f910b951f6aa6f2ef1d85f89daa5129a4adb1
parent 84dfbc2d7dcea9e59d1f9adb51a4f25845a7ebad
Author: Kebigon <git@kebigon.xyz>
Date: Tue, 10 Aug 2021 07:26:21 +0900
Extract list from client struct
Diffstat:
| M | Makefile | | | 2 | +- |
| M | client.c | | | 79 | ++++++++++++++++++++++--------------------------------------------------------- |
| M | client.h | | | 2 | -- |
| M | events.c | | | 18 | +++++++++++------- |
| M | kbgwm.c | | | 72 | ++++++++++++++++++++++++++++++++++++++++++------------------------------ |
| M | kbgwm.h | | | 2 | +- |
| A | list.c | | | 105 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | list.h | | | 51 | +++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | xcbutils.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)))
{