commit d529d70d8505cd01e4455a3a2aa21a3633204904
parent f9ca3e38c03ef7aedc53e65ea7e10f8907623c76
Author: Kebigon <git@kebigon.xyz>
Date: Sat, 18 Jul 2020 14:24:44 +0900
Working implementation
Diffstat:
| M | Makefile | | | 2 | +- |
| M | config.h | | | 56 | ++++++++++++++++++++++++-------------------------------- |
| M | kbgwm.c | | | 413 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------- |
| M | types.h | | | 29 | +++++++++++------------------ |
| M | xcbutils.c | | | 103 | ++++++++++++++++++++++--------------------------------------------------------- |
| M | xcbutils.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_ */