commit 115466a0696a6fe361692e5a9959157afdb1b996
parent 7c3b8732108cf0ebff8ae70a0dccfe08b491907d
Author: Kebigon <git@kebigon.xyz>
Date: Sun, 30 Aug 2020 20:24:38 +0900
Start splitting source files, add license header and update README
Diffstat:
| M | Makefile | | | 2 | +- |
| M | README.md | | | 6 | +++--- |
| A | client.c | | | 309 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | client.h | | | 54 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | config.h | | | 39 | +++++++++++++++++++++++++++++++++++---- |
| A | events.c | | | 284 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | events.h | | | 27 | +++++++++++++++++++++++++++ |
| M | kbgwm.c | | | 657 | ++++++------------------------------------------------------------------------- |
| A | kbgwm.h | | | 64 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | types.h | | | 39 | +++++++++++++++++++++++---------------- |
| M | xcbutils.c | | | 18 | ++++++++++++++++++ |
| M | xcbutils.h | | | 25 | ++++++++++++++++++++++--- |
12 files changed, 888 insertions(+), 636 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,4 +1,4 @@
-OBJ = kbgwm.o xcbutils.o
+OBJ = kbgwm.o xcbutils.o events.o client.o
CFLAGS+=-g -std=c99 -Wall -Wextra -I/usr/local/include
LDFLAGS+=-L/usr/local/lib -lxcb -lxcb-icccm -lxcb-keysyms
diff --git a/README.md b/README.md
@@ -40,6 +40,6 @@ You can edit all those settings via the config.h file.
## Thanks
-Thanks to the [suckless](https://suckless.org) project
-Thanks to venam for creating [2bwm](https://github.com/venam/2bwm)
-Thanks to Michael Cardell for creating [mcwm](https://hack.org/mc/projects/mcwm)
+- Thanks to the [suckless](https://suckless.org) project
+- Thanks to venam for creating [2bwm](https://github.com/venam/2bwm)
+- Thanks to Michael Cardell for creating [mcwm](https://hack.org/mc/projects/mcwm)
diff --git a/client.c b/client.c
@@ -0,0 +1,309 @@
+/*
+ * kbgwm, a sucklessy floating window manager
+ * Copyright (C) 2020 Kebigon
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "client.h"
+#include "kbgwm.h"
+#include "xcbutils.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <xcb/xcb_icccm.h>
+
+static inline int16_t int16_in_range(int16_t value, int16_t min, int16_t max)
+{
+ if (value < min)
+ return min;
+ else if (value > max)
+ return max;
+ else
+ return value;
+}
+
+static 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;
+}
+
+// Add a client to the current workspace list
+void client_add(client* client)
+{
+ client_add_workspace(client, current_workspace);
+}
+
+// Add a client to a workspace list
+void client_add_workspace(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;
+}
+
+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 = geometry->x;
+ new_client->y = geometry->y;
+ new_client->width = geometry->width;
+ new_client->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;
+ new_client->maximized = false;
+
+ client_sanitize_dimensions(new_client);
+
+ 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);
+
+ focus_unfocus();
+ client_add(new_client);
+ focus_apply();
+
+ printf("client_create: done\n");
+}
+
+// Find a client in the current workspace list
+client* client_find(xcb_window_t id)
+{
+ return client_find_workspace(id, current_workspace);
+}
+
+client* client_find_all_workspaces(xcb_window_t id)
+{
+ for (uint_fast8_t workspace = 0; workspace != workspaces_length; workspace++)
+ {
+ client* client = client_find_workspace(id, workspace);
+ if (client != NULL)
+ return client;
+ }
+
+ return NULL;
+}
+
+client* client_find_workspace(xcb_window_t id, uint_fast8_t workspace)
+{
+ assert(workspace < workspaces_length);
+
+ client* client = workspaces[workspace];
+
+ if (client != NULL)
+ do
+ {
+ if (client->id == id)
+ return client;
+ } while ((client = client->next) != workspaces[workspace]);
+
+ return NULL;
+}
+
+// Remove the focused client from the current workspace list
+client* client_remove()
+{
+ return client_remove_workspace(current_workspace);
+}
+
+// Remove the focused client from a workspace list
+client* client_remove_workspace(uint_fast8_t workspace)
+{
+ assert(workspace < workspaces_length);
+ assert(workspaces[workspace] != NULL);
+
+ 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;
+ }
+
+ return client;
+}
+
+void client_remove_all_workspaces(xcb_window_t id)
+{
+ for (uint_fast8_t workspace = 0; workspace != workspaces_length; 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;
+}
+
+void client_kill(__attribute__((unused))const Arg* arg)
+{
+ printf("=======[ user action: client_kill ]=======\n");
+
+ // No client are focused
+ if (workspaces[current_workspace] == NULL)
+ return; // Nothing to be done
+
+ if (!xcb_send_atom(workspaces[current_workspace], wm_delete_window))
+ {
+ // The client does not support WM_DELETE, let's kill it
+ xcb_kill_client(c, workspaces[current_workspace]->id);
+ }
+
+ xcb_flush(c);
+}
+
+void client_toggle_maximize(__attribute__((unused))const Arg* arg)
+{
+ printf("=======[ user action: client_toggle_maximize ]=======\n");
+
+ // No client are focused
+ if (workspaces[current_workspace] == NULL)
+ return; // Nothing to be done
+
+ client* client = workspaces[current_workspace];
+
+ if (client->maximized)
+ client_unmaximize(client);
+ else
+ client_maximize(client);
+
+ xcb_flush(c);
+}
+
+void client_maximize(client* client)
+{
+ assert(client != NULL);
+ assert(!client->maximized);
+
+ 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_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT | XCB_CONFIG_WINDOW_BORDER_WIDTH, values);
+}
+
+void client_unmaximize(client* client)
+{
+ assert(client != NULL);
+ assert(client->maximized);
+
+ client->maximized = false;
+
+ uint32_t values[] = { client->x, client->y, client->width, client->height, border_width };
+ xcb_configure_window(c, focused_client->id, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT | XCB_CONFIG_WINDOW_BORDER_WIDTH, values);
+}
+
+void client_grab_buttons(client* client, bool focused)
+{
+ uint16_t modifiers[] = { 0, numlockmask, XCB_MOD_MASK_LOCK, numlockmask | XCB_MOD_MASK_LOCK };
+
+ xcb_ungrab_button(c, XCB_BUTTON_INDEX_ANY, client->id, XCB_MOD_MASK_ANY);
+
+ // The client is not the focused one -> grab everything
+ if (!focused)
+ {
+ xcb_grab_button(c, 1, client->id, BUTTON_EVENT_MASK, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE,
+ XCB_BUTTON_INDEX_ANY, XCB_MOD_MASK_ANY);
+ }
+
+ // The client is the focused one -> grab only the configured buttons
+ else
+ {
+ for (unsigned int i = 0; i != buttons_length; i++)
+ {
+ Button button = buttons[i];
+
+ for (unsigned int j = 0; j != LENGTH(modifiers); j++)
+ {
+ xcb_grab_button(c, 0, client->id, BUTTON_EVENT_MASK, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE,
+ button.keysym, button.modifiers | modifiers[j]);
+ }
+ }
+ }
+}
diff --git a/client.h b/client.h
@@ -0,0 +1,54 @@
+/*
+ * kbgwm, a sucklessy floating window manager
+ * Copyright (C) 2020 Kebigon
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef KBGWM_CLIENT_H
+#define KBGWM_CLIENT_H
+
+#include "types.h"
+#include <stdbool.h>
+
+typedef struct client_t client;
+struct client_t
+{
+ xcb_window_t id;
+ int16_t x, y;
+ uint16_t width, height;
+ int32_t min_width, min_height;
+ int32_t max_width, max_height;
+ bool maximized;
+ client* previous;
+ client* next;
+};
+
+void client_grab_buttons(client*, bool);
+void client_kill(const Arg*);
+void client_create(xcb_window_t);
+void client_toggle_maximize(const Arg*);
+client* client_remove();
+void client_add_workspace(client*, uint_fast8_t);
+client* client_remove_workspace(uint_fast8_t);
+client* client_find(xcb_window_t);
+void client_maximize(client*);
+void client_unmaximize(client*);
+void client_sanitize_position(client*);
+void client_sanitize_dimensions(client*);
+void client_remove_all_workspaces(xcb_window_t);
+client* client_find_all_workspaces(xcb_window_t);
+client* client_find_workspace(xcb_window_t, uint_fast8_t);
+
+#endif /* KBGWM_CLIENT_H */
diff --git a/config.h b/config.h
@@ -1,3 +1,28 @@
+/*
+ * kbgwm, a sucklessy floating window manager
+ * Copyright (C) 2020 Kebigon
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef KBGWM_CONFIG_H
+#define KBGWM_CONFIG_H
+
+#include "client.h"
+#include "types.h"
+#include <X11/keysym.h>
+
#define MODKEY XCB_MOD_MASK_1
#define SHIFT XCB_MOD_MASK_SHIFT
@@ -19,8 +44,7 @@ static const char* menucmd[] = { "dmenu_run", NULL };
{ MODKEY|XCB_MOD_MASK_SHIFT, KEY, workspace_send, {.i = WORKSPACE} }, \
{ MODKEY, KEY, workspace_change, {.i = WORKSPACE} },
-static Key keys[] =
-{
+const Key keys[] = {
{ MODKEY, XK_Return, start, { .cmd = termcmd } },
{ MODKEY, XK_p, start, { .cmd = menucmd } },
{ MODKEY, XK_Page_Up, workspace_previous, { 0 } },
@@ -44,8 +68,15 @@ static Key keys[] =
WORKSPACEKEYS(XK_End, 9)
};
-static Button buttons[] =
-{
+const Button buttons[] = {
{ MODKEY, XCB_BUTTON_INDEX_1, mousemove, { 0 } },
{ MODKEY, XCB_BUTTON_INDEX_3, mouseresize, { 0 } },
};
+
+const uint_least8_t keys_length = LENGTH(keys);
+const uint_least8_t buttons_length = LENGTH(buttons);
+const uint_least8_t workspaces_length = NB_WORKSPACES;
+const uint_least8_t border_width = BORDER_WIDTH;
+const uint_least8_t border_width_x2 = (border_width << 1);
+
+#endif /* KBGWM_CONFIG_H */
diff --git a/events.c b/events.c
@@ -0,0 +1,284 @@
+/*
+ * kbgwm, a sucklessy floating window manager
+ * Copyright (C) 2020 Kebigon
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "events.h"
+#include "client.h"
+#include "xcbutils.h"
+#include "kbgwm.h"
+
+#include <assert.h>
+#include <stdio.h>
+
+#define CLEANMASK(mask) (mask & ~(numlockmask|XCB_MOD_MASK_LOCK))
+
+#define EVENT_HANDLERS_SIZE XCB_CONFIGURE_REQUEST + 1
+static void (* event_handlers[EVENT_HANDLERS_SIZE])(xcb_generic_event_t*);
+
+static void handle_key_press(xcb_generic_event_t* e)
+{
+ xcb_key_press_event_t* event = (xcb_key_press_event_t*) e;
+ xcb_keysym_t keysym = xcb_get_keysym(event->detail);
+
+ for (uint_fast8_t i = 0; i < keys_length; i++)
+ {
+ if (keysym == keys[i].keysym && CLEANMASK(keys[i].modifiers) == CLEANMASK(event->state))
+ {
+ keys[i].func(&keys[i].arg);
+ break;
+ }
+ }
+}
+
+static void handle_button_press(xcb_generic_event_t* e)
+{
+ xcb_button_press_event_t* event = (xcb_button_press_event_t*) e;
+
+ // Click on the root window
+ if (event->event == event->root && event->child == 0)
+ return; // Nothing to be done
+
+ xcb_window_t window = event->event == event->root ? event->child : event->event;
+
+ // The window clicked is not the one in focus, we have to focus it
+ if (workspaces[current_workspace] == NULL || window != workspaces[current_workspace]->id)
+ {
+ client* client = client_find(window);
+ assert(client != NULL);
+
+ focus_unfocus();
+ workspaces[current_workspace] = client;
+ focus_apply();
+ }
+
+ for (uint_fast8_t i = 0; i < buttons_length; i++)
+ {
+ if (event->detail == buttons[i].keysym && CLEANMASK(buttons[i].modifiers) == CLEANMASK(event->state))
+ {
+ previous_x = event->root_x;
+ previous_y = event->root_y;
+
+ buttons[i].func(&buttons[i].arg);
+ break;
+ }
+ }
+}
+
+static void handle_button_release(__attribute__((unused)) xcb_generic_event_t* event)
+{
+ // We were not moving or resizing the focused client
+ if (!moving && !resizing)
+ return; // Nothing to be done
+
+ xcb_ungrab_pointer(c, XCB_CURRENT_TIME);
+ xcb_flush(c);
+
+ moving = false;
+ resizing = false;
+}
+
+static void handle_motion_notify(xcb_generic_event_t* e)
+{
+ xcb_motion_notify_event_t* event = (xcb_motion_notify_event_t*) e;
+ client* client = workspaces[current_workspace];
+
+ assert(moving || resizing);
+ assert(client != NULL);
+ assert(client->id != root);
+
+ if (client->maximized)
+ client_unmaximize(client);
+
+ 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)
+ {
+ client->x += diff_x;
+ client->y += diff_y;
+ client_sanitize_position(client);
+
+ uint32_t values[2] = { client->x, client->y };
+ xcb_configure_window(c, client->id, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values);
+ }
+ else if (resizing)
+ {
+ client->width += diff_x;
+ client->height += diff_y;
+ client_sanitize_dimensions(client);
+
+ uint32_t values[2] = { client->width, client->height };
+ xcb_configure_window(c, client->id, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values);
+ }
+
+ xcb_flush(c);
+}
+
+static void handle_destroy_notify(xcb_generic_event_t* e)
+{
+ xcb_destroy_notify_event_t* event = (xcb_destroy_notify_event_t*) e;
+
+ client_remove_all_workspaces(event->window);
+ if (focused_client != NULL)
+ focus_apply();
+}
+
+static void handle_unmap_notify(xcb_generic_event_t* e)
+{
+ xcb_unmap_notify_event_t* event = (xcb_unmap_notify_event_t*) e;
+ client* client = client_find_all_workspaces(event->window);
+
+ // We don't know this client
+ if (client == NULL)
+ return; // Nothing to be done
+
+ // true if this came from a SendEvent request
+ bool send_event = event->response_type & 0x80;
+ if (!send_event)
+ return; // Nothing to be done
+
+ client_remove_all_workspaces(event->window);
+ if (focused_client != NULL)
+ focus_apply();
+}
+
+static void handle_map_request(xcb_generic_event_t* e)
+{
+ xcb_map_request_event_t* event = (xcb_map_request_event_t*) e;
+
+ client_create(event->window);
+}
+
+static void handle_configure_request(xcb_generic_event_t* e)
+{
+ xcb_configure_request_event_t* event = (xcb_configure_request_event_t*) e;
+ client* client = client_find_all_workspaces(event->window);
+
+ if (client != NULL)
+ {
+ // The client is maximized
+ if (client->maximized)
+ return; // Nothing to be done
+
+ if (event->value_mask & XCB_CONFIG_WINDOW_X)
+ client->x = event->x;
+ if (event->value_mask & XCB_CONFIG_WINDOW_Y)
+ client->y = event->y;
+ if (event->value_mask & XCB_CONFIG_WINDOW_WIDTH)
+ client->width = event->width;
+ if (event->value_mask & XCB_CONFIG_WINDOW_HEIGHT)
+ client->height = event->height;
+
+ // Ignored: XCB_CONFIG_WINDOW_BORDER_WIDTH, XCB_CONFIG_WINDOW_SIBLING, XCB_CONFIG_WINDOW_STACK_MODE
+
+ client_sanitize_position(client);
+ client_sanitize_dimensions(client);
+
+ uint32_t values[4] = { client->x, client->y, client->width, client->height };
+ xcb_configure_window(c, client->id,
+ XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values);
+ xcb_flush(c);
+ }
+
+ // We don't know the client -> apply the requested change
+ else
+ {
+ uint16_t value_mask = 0;
+ uint32_t value_list[7];
+ int8_t i = 0;
+
+ if (event->value_mask & XCB_CONFIG_WINDOW_X)
+ {
+ value_mask |= XCB_CONFIG_WINDOW_X;
+ value_list[i++] = event->x;
+ }
+ if (event->value_mask & XCB_CONFIG_WINDOW_Y)
+ {
+ value_mask |= XCB_CONFIG_WINDOW_Y;
+ value_list[i++] = event->y;
+ }
+ if (event->value_mask & XCB_CONFIG_WINDOW_WIDTH)
+ {
+ value_mask |= XCB_CONFIG_WINDOW_WIDTH;
+ value_list[i++] = event->width;
+ }
+ if (event->value_mask & XCB_CONFIG_WINDOW_HEIGHT)
+ {
+ value_mask |= XCB_CONFIG_WINDOW_HEIGHT;
+ value_list[i++] = event->height;
+ }
+ if (event->value_mask & XCB_CONFIG_WINDOW_SIBLING)
+ {
+ value_mask |= XCB_CONFIG_WINDOW_SIBLING;
+ value_list[i++] = event->sibling;
+ }
+ if (event->value_mask & XCB_CONFIG_WINDOW_STACK_MODE)
+ {
+ value_mask |= XCB_CONFIG_WINDOW_STACK_MODE;
+ value_list[i++] = event->stack_mode;
+ }
+ if (i != 0)
+ {
+ xcb_configure_window(c, event->window, value_mask, value_list);
+ xcb_flush(c);
+ }
+ }
+}
+
+void handle_event(xcb_generic_event_t* event)
+{
+ void (* event_handler)(xcb_generic_event_t*) = event_handlers[event->response_type & ~0x80];
+ if (event_handler == NULL)
+ printf("Received unhandled event, response type %d\n", event->response_type & ~0x80);
+ else
+ event_handler(event);
+}
+
+void setup_events()
+{
+ /*
+ * Initialize event_handlers
+ */
+
+ for (uint_fast8_t i = 0; i != EVENT_HANDLERS_SIZE; i++)
+ event_handlers[i] = NULL;
+
+ event_handlers[XCB_KEY_PRESS] = handle_key_press;
+ event_handlers[XCB_BUTTON_PRESS] = handle_button_press;
+ event_handlers[XCB_BUTTON_RELEASE] = handle_button_release;
+ event_handlers[XCB_MOTION_NOTIFY] = handle_motion_notify;
+ event_handlers[XCB_DESTROY_NOTIFY] = handle_destroy_notify;
+ event_handlers[XCB_UNMAP_NOTIFY] = handle_unmap_notify;
+ event_handlers[XCB_MAP_REQUEST] = handle_map_request;
+ event_handlers[XCB_CONFIGURE_REQUEST] = handle_configure_request;
+
+ /*
+ * Register X11 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);
+
+ for (uint_fast8_t i = 0; i != keys_length; i++)
+ xcb_register_key_events(keys[i]);
+
+ xcb_flush(c);
+}
diff --git a/events.h b/events.h
@@ -0,0 +1,27 @@
+/*
+ * kbgwm, a sucklessy floating window manager
+ * Copyright (C) 2020 Kebigon
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef KBGWM_EVENTS_H
+#define KBGWM_EVENTS_H
+
+#include <xcb/xcb.h>
+
+void handle_event(xcb_generic_event_t*);
+void setup_events();
+
+#endif /* KBGWM_EVENTS_H */
diff --git a/kbgwm.c b/kbgwm.c
@@ -1,3 +1,21 @@
+/*
+ * kbgwm, a sucklessy floating window manager
+ * Copyright (C) 2020 Kebigon
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
@@ -9,53 +27,14 @@
#include <X11/keysym.h>
#include <inttypes.h>
#include "xcbutils.h"
+#include "client.h"
+#include "events.h"
+#include "types.h"
+#include <X11/keysym.h>
-#define CLEANMASK(mask) (mask & ~(numlockmask|XCB_MOD_MASK_LOCK))
-
-static void start(const Arg* arg);
-static void mousemove(const Arg* arg);
-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 client_kill(const Arg*);
-static void client_create(xcb_window_t);
-static void client_sanitize_position(client*);
-static void client_sanitize_dimensions(client*);
-static void client_toggle_maximize(const Arg*);
-static void client_maximize(client*);
-static void client_unmaximize(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_configure_request(xcb_configure_request_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_motion_notify(xcb_motion_notify_event_t*);
-static void handle_unmap_notify(xcb_unmap_notify_event_t*);
-static void quit(const Arg*);
-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_event();
-static inline void debug_print_globals();
-
+#include "kbgwm.h"
#include "config.h"
-#define BORDER_WIDTH_X2 (BORDER_WIDTH << 1)
-
bool running = true;
bool moving = false;
bool resizing = false;
@@ -68,30 +47,31 @@ uint16_t numlockmask = 0;
xcb_atom_t wm_protocols;
xcb_atom_t wm_delete_window;
-#define focused_client workspaces[current_workspace]
uint_fast8_t current_workspace = 0;
-static client* workspaces[NB_WORKSPACES];
+client* workspaces[NB_WORKSPACES];
-inline int16_t int16_in_range(int16_t value, int16_t min, int16_t max)
-{
- 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)
+static inline void debug_print_globals()
{
- if (value < min)
- return min;
- else if (value > max)
- return max;
- else
- return value;
+ printf("current_workspace=%d\n", current_workspace);
+
+ for (int workspace = 0; workspace != workspaces_length; workspace++)
+ {
+ if (workspaces[workspace] == NULL)
+ printf("%d\tNULL\n", workspace);
+ else
+ {
+ client* client = workspaces[workspace];
+ do
+ {
+ 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]);
+ }
+ }
}
-void debug_print_event(xcb_generic_event_t* event)
+static void debug_print_event(xcb_generic_event_t* event)
{
switch (event->response_type & ~0x80)
{
@@ -185,27 +165,6 @@ void debug_print_event(xcb_generic_event_t* event)
}
}
-inline void debug_print_globals()
-{
- printf("current_workspace=%d\n", current_workspace);
-
- 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 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]);
- }
- }
-}
-
void mousemove(__attribute__((unused))const Arg* arg)
{
printf("=======[ user action: mousemove ]=======\n");
@@ -237,44 +196,7 @@ void eventLoop()
xcb_generic_event_t* event = xcb_wait_for_event(c);
debug_print_event(event);
- 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;
-
- case XCB_BUTTON_RELEASE:
- handle_button_release((xcb_button_release_event_t*) event);
- break;
-
- 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:
- handle_map_request((xcb_map_request_event_t*) event);
- break;
-
- case XCB_CONFIGURE_REQUEST:
- handle_configure_request((xcb_configure_request_event_t*) event);
- break;
-
- default:
- printf("Received unhandled event, response type %d\n", event->response_type & ~0x80);
- break;
- }
+ handle_event(event);
free(event);
printf("=======[ event: DONE ]=======\n\n");
@@ -300,274 +222,6 @@ void start(const Arg* arg)
}
/*
- * Clients
- */
-
-// Add a client to the current workspace list
-void client_add(client* client)
-{
- client_add_workspace(client, current_workspace);
-}
-
-// Add a client to a workspace list
-void client_add_workspace(client* client, uint_fast8_t workspace)
-{
- assert(client != NULL);
- assert(workspace < NB_WORKSPACES);
-
- 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;
-}
-
-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 = geometry->x;
- new_client->y = geometry->y;
- new_client->width = geometry->width;
- new_client->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;
- new_client->maximized = false;
-
- client_sanitize_dimensions(new_client);
-
- 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);
-
- focus_unfocus();
- client_add(new_client);
- focus_apply();
-
- printf("client_create: done\n");
-}
-
-// Find a client in the current workspace list
-client* client_find(xcb_window_t id)
-{
- return client_find_workspace(id, current_workspace);
-}
-
-client* client_find_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)
- return client;
- }
-
- return NULL;
-}
-
-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[workspace]);
-
- return NULL;
-}
-
-// Remove the focused client from the current workspace list
-client* client_remove()
-{
- return client_remove_workspace(current_workspace);
-}
-
-// Remove the focused client from a workspace list
-client* client_remove_workspace(uint_fast8_t workspace)
-{
- assert(workspace < NB_WORKSPACES);
- assert(workspaces[workspace] != NULL);
-
- 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;
- }
-
- 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;
-}
-
-void client_kill(__attribute__((unused))const Arg* arg)
-{
- printf("=======[ user action: client_kill ]=======\n");
-
- // No client are focused
- if (workspaces[current_workspace] == NULL)
- return; // Nothing to be done
-
- if (!xcb_send_atom(workspaces[current_workspace], wm_delete_window))
- {
- // The client does not support WM_DELETE, let's kill it
- xcb_kill_client(c, workspaces[current_workspace]->id);
- }
-
- xcb_flush(c);
-}
-
-void client_toggle_maximize(__attribute__((unused))const Arg* arg)
-{
- printf("=======[ user action: client_toggle_maximize ]=======\n");
-
- // No client are focused
- if (workspaces[current_workspace] == NULL)
- return; // Nothing to be done
-
- client* client = workspaces[current_workspace];
-
- if (client->maximized)
- client_unmaximize(client);
- else
- client_maximize(client);
-
- xcb_flush(c);
-}
-
-void client_maximize(client* client)
-{
- assert(client != NULL);
- assert(!client->maximized);
-
- 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_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT | XCB_CONFIG_WINDOW_BORDER_WIDTH, values);
-}
-
-void client_unmaximize(client* client)
-{
- assert(client != NULL);
- assert(client->maximized);
-
- client->maximized = false;
-
- uint32_t values[] = { client->x, client->y, client->width, client->height, BORDER_WIDTH };
- xcb_configure_window(c, focused_client->id, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT | XCB_CONFIG_WINDOW_BORDER_WIDTH, values);
-}
-
-void client_grab_buttons(client* client, bool focused)
-{
- uint16_t modifiers[] = { 0, numlockmask, XCB_MOD_MASK_LOCK, numlockmask | XCB_MOD_MASK_LOCK };
-
- xcb_ungrab_button(c, XCB_BUTTON_INDEX_ANY, client->id, XCB_MOD_MASK_ANY);
-
- // The client is not the focused one -> grab everything
- if (!focused)
- {
- xcb_grab_button(c, 1, client->id, BUTTON_EVENT_MASK, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE,
- XCB_BUTTON_INDEX_ANY, XCB_MOD_MASK_ANY);
- }
-
- // The client is the focused one -> grab only the configured buttons
- else
- {
- for (unsigned int i = 0; i != LENGTH(buttons); i++)
- {
- Button button = buttons[i];
-
- for (unsigned int j = 0; j != LENGTH(modifiers); j++)
- {
- xcb_grab_button(c, 0, client->id, BUTTON_EVENT_MASK, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE,
- button.keysym, button.modifiers | modifiers[j]);
- }
- }
- }
-}
-
-/*
* Focus
*/
@@ -628,208 +282,6 @@ void focus_unfocus()
* Handling events from the event loop
*/
-void handle_button_press(xcb_button_press_event_t* event)
-{
- // Click on the root window
- if (event->event == event->root && event->child == 0)
- return; // Nothing to be done
-
- xcb_window_t window = event->event == event->root ? event->child : event->event;
-
- // The window clicked is not the one in focus, we have to focus it
- if (workspaces[current_workspace] == NULL || window != workspaces[current_workspace]->id)
- {
- client* client = client_find(window);
- 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 && CLEANMASK(buttons[i].modifiers) == CLEANMASK(event->state))
- {
- previous_x = event->root_x;
- previous_y = event->root_y;
-
- buttons[i].func(&buttons[i].arg);
- break;
- }
- }
-}
-
-void handle_button_release(__attribute__((unused)) xcb_button_release_event_t* event)
-{
- // We were not moving or resizing the focused client
- if (!moving && !resizing)
- return; // Nothing to be done
-
- xcb_ungrab_pointer(c, XCB_CURRENT_TIME);
- xcb_flush(c);
-
- moving = false;
- resizing = false;
-}
-
-void handle_configure_request(xcb_configure_request_event_t* event)
-{
- client* client = client_find_all_workspaces(event->window);
-
- if (client != NULL)
- {
- // The client is maximized
- if (client->maximized)
- return; // Nothing to be done
-
- if (event->value_mask & XCB_CONFIG_WINDOW_X)
- client->x = event->x;
- if (event->value_mask & XCB_CONFIG_WINDOW_Y)
- client->y = event->y;
- if (event->value_mask & XCB_CONFIG_WINDOW_WIDTH)
- client->width = event->width;
- if (event->value_mask & XCB_CONFIG_WINDOW_HEIGHT)
- client->height = event->height;
-
- // Ignored: XCB_CONFIG_WINDOW_BORDER_WIDTH, XCB_CONFIG_WINDOW_SIBLING, XCB_CONFIG_WINDOW_STACK_MODE
-
- client_sanitize_position(client);
- client_sanitize_dimensions(client);
-
- uint32_t values[4] = { client->x, client->y, client->width, client->height };
- xcb_configure_window(c, client->id,
- XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values);
- xcb_flush(c);
- }
-
- // We don't know the client -> apply the requested change
- else
- {
- uint16_t value_mask = 0;
- uint32_t value_list[7];
- int8_t i = 0;
-
- if (event->value_mask & XCB_CONFIG_WINDOW_X)
- {
- value_mask |= XCB_CONFIG_WINDOW_X;
- value_list[i++] = event->x;
- }
- if (event->value_mask & XCB_CONFIG_WINDOW_Y)
- {
- value_mask |= XCB_CONFIG_WINDOW_Y;
- value_list[i++] = event->y;
- }
- if (event->value_mask & XCB_CONFIG_WINDOW_WIDTH)
- {
- value_mask |= XCB_CONFIG_WINDOW_WIDTH;
- value_list[i++] = event->width;
- }
- if (event->value_mask & XCB_CONFIG_WINDOW_HEIGHT)
- {
- value_mask |= XCB_CONFIG_WINDOW_HEIGHT;
- value_list[i++] = event->height;
- }
- if (event->value_mask & XCB_CONFIG_WINDOW_SIBLING)
- {
- value_mask |= XCB_CONFIG_WINDOW_SIBLING;
- value_list[i++] = event->sibling;
- }
- if (event->value_mask & XCB_CONFIG_WINDOW_STACK_MODE)
- {
- value_mask |= XCB_CONFIG_WINDOW_STACK_MODE;
- value_list[i++] = event->stack_mode;
- }
- if (i != 0)
- {
- xcb_configure_window(c, event->window, value_mask, value_list);
- xcb_flush(c);
- }
- }
-}
-
-void handle_destroy_notify(xcb_destroy_notify_event_t* event)
-{
- client_remove_all_workspaces(event->window);
- if (focused_client != NULL)
- focus_apply();
-}
-
-void handle_key_press(xcb_key_press_event_t* event)
-{
- xcb_keysym_t keysym = xcb_get_keysym(event->detail);
-
- for (uint_fast8_t i = 0; i < LENGTH(keys); i++)
- {
- if (keysym == keys[i].keysym && CLEANMASK(keys[i].modifiers) == CLEANMASK(event->state))
- {
- keys[i].func(&keys[i].arg);
- break;
- }
- }
-}
-
-void handle_map_request(xcb_map_request_event_t* event)
-{
- client_create(event->window);
-}
-
-void handle_unmap_notify(xcb_unmap_notify_event_t* event)
-{
- client* client = client_find_all_workspaces(event->window);
-
- // We don't know this client
- if (client == NULL)
- return; // Nothing to be done
-
- // true if this came from a SendEvent request
- bool send_event = event->response_type & 0x80;
- if (!send_event)
- return; // Nothing to be done
-
- client_remove_all_workspaces(event->window);
- if (focused_client != NULL)
- focus_apply();
-}
-
-void handle_motion_notify(xcb_motion_notify_event_t* event)
-{
- client* client = workspaces[current_workspace];
-
- assert(moving || resizing);
- assert(client != NULL);
- assert(client->id != root);
-
- if (client->maximized)
- client_unmaximize(client);
-
- 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)
- {
- client->x += diff_x;
- client->y += diff_y;
- client_sanitize_position(client);
-
- uint32_t values[2] = { client->x, client->y };
- xcb_configure_window(c, client->id, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values);
- }
- else if (resizing)
- {
- client->width += diff_x;
- client->height += diff_y;
- client_sanitize_dimensions(client);
-
- uint32_t values[2] = { client->width, client->height };
- xcb_configure_window(c, client->id, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values);
- }
-
- xcb_flush(c);
-}
-
void quit(__attribute__((unused))const Arg* arg)
{
printf("=======[ user action: quit ]=======\n");
@@ -877,19 +329,6 @@ void setup_keyboard()
free(reply);
}
-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);
-
- for (uint_fast8_t i = 0; i != LENGTH(keys); i++)
- xcb_register_key_events(keys[i]);
-
- xcb_flush(c);
-}
-
void setup_screen()
{
// Retrieve the children of the root window
@@ -926,13 +365,13 @@ void workspace_next(__attribute__((unused))const Arg* arg)
{
printf("=======[ user action: workspace_next ]=======\n");
- workspace_set(current_workspace + 1 == NB_WORKSPACES ? 0 : current_workspace + 1);
+ workspace_set(current_workspace + 1 == workspaces_length ? 0 : current_workspace + 1);
}
void workspace_previous(__attribute__((unused))const Arg* arg)
{
printf("=======[ user action: workspace_previous ]=======\n");
- workspace_set(current_workspace == 0 ? NB_WORKSPACES - 1 : current_workspace - 1);
+ workspace_set(current_workspace == 0 ? workspaces_length - 1 : current_workspace - 1);
}
void workspace_send(const Arg* arg)
@@ -1031,7 +470,7 @@ int main(void)
* Initialize variables
*/
- for (uint_fast8_t i = 0; i != NB_WORKSPACES; i++)
+ for (uint_fast8_t i = 0; i != workspaces_length; i++)
workspaces[i] = NULL;
wm_protocols = xcb_get_atom(WM_PROTOCOLS);
@@ -1044,7 +483,7 @@ int main(void)
// Event loop
eventLoop();
- for (uint_fast8_t i = 0; i != NB_WORKSPACES; i++)
+ for (uint_fast8_t i = 0; i != workspaces_length; i++)
{
while (workspaces[i] != NULL)
{
diff --git a/kbgwm.h b/kbgwm.h
@@ -0,0 +1,64 @@
+/*
+ * kbgwm, a sucklessy floating window manager
+ * Copyright (C) 2020 Kebigon
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef KBGWM_KBGWM_H
+#define KBGWM_KBGWM_H
+
+void start(const Arg* arg);
+void mousemove(const Arg* arg);
+void mouseresize(const Arg* arg);
+
+void focus_apply();
+void focus_next(const Arg*);
+void focus_unfocus();
+void quit(const Arg*);
+void workspace_change(const Arg*);
+void workspace_next(const Arg*);
+void workspace_previous(const Arg*);
+void workspace_send(const Arg*);
+void workspace_set(uint_fast8_t);
+
+#include <stdbool.h>
+#include "types.h"
+
+#define focused_client workspaces[current_workspace]
+
+extern bool running;
+extern bool moving;
+extern bool resizing;
+extern xcb_connection_t* c;
+extern xcb_window_t root;
+extern xcb_screen_t* screen;
+extern uint_least16_t previous_x;
+extern uint_least16_t previous_y;
+extern uint16_t numlockmask;
+extern xcb_atom_t wm_protocols;
+extern xcb_atom_t wm_delete_window;
+extern uint_fast8_t current_workspace;
+extern client* workspaces[];
+
+extern const Key keys[];
+extern const Button buttons[];
+
+extern const uint_least8_t keys_length;
+extern const uint_least8_t buttons_length;
+extern const uint_least8_t workspaces_length;
+extern const uint_least8_t border_width;
+extern const uint_least8_t border_width_x2;
+
+#endif /* KBGWM_KBGWM_H */
diff --git a/types.h b/types.h
@@ -1,7 +1,27 @@
-#ifndef TYPES_H_
-#define TYPES_H_
+/*
+ * kbgwm, a sucklessy floating window manager
+ * Copyright (C) 2020 Kebigon
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+#ifndef KBGWM_TYPES_H
+#define KBGWM_TYPES_H
+
+#include <stdint.h>
#include <stdbool.h>
+#include <xcb/xproto.h>
typedef union
{
@@ -26,17 +46,4 @@ typedef struct
const Arg arg;
} Button;
-typedef struct client_t client;
-struct client_t
-{
- xcb_window_t id;
- int16_t x, y;
- uint16_t width, height;
- int32_t min_width, min_height;
- int32_t max_width, max_height;
- bool maximized;
- client* previous;
- client* next;
-};
-
-#endif /* TYPES_H_ */
+#endif /* KBGWM_TYPES_H */
diff --git a/xcbutils.c b/xcbutils.c
@@ -1,3 +1,21 @@
+/*
+ * kbgwm, a sucklessy floating window manager
+ * Copyright (C) 2020 Kebigon
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
#include "xcbutils.h"
#include <assert.h>
diff --git a/xcbutils.h b/xcbutils.h
@@ -1,5 +1,23 @@
-#ifndef XCBUTILS_H_
-#define XCBUTILS_H_
+/*
+ * kbgwm, a sucklessy floating window manager
+ * Copyright (C) 2020 Kebigon
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef KBGWM_XCBUTILS_H
+#define KBGWM_XCBUTILS_H
#define LENGTH( X ) (sizeof X / sizeof X [ 0 ])
@@ -7,6 +25,7 @@
#include <xcb/xcb.h>
#include "types.h"
+#include "client.h"
#define BUTTON_EVENT_MASK XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE
@@ -30,4 +49,4 @@ xcb_keysym_t xcb_get_keysym(xcb_keycode_t);
xcb_atom_t xcb_get_atom(const char*);
bool xcb_send_atom(client*, xcb_atom_t);
-#endif /* XCBUTILS_H_ */
+#endif /* KBGWM_XCBUTILS_H */