kbgwm

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

commit ea5c31b01e93542298adef1b487dd46cd58cccee
parent 0ca4b7d43224a7c861e230da0b164625446cd02a
Author: Kebigon <git@kebigon.xyz>
Date:   Mon,  6 Jul 2020 20:39:33 +0900

Move/resize windows

Diffstat:
Mconfig.h | 35+++++++++++++++++++++++++++++++----
Mkbgwm.c | 276+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Mtypes.h | 44++++++++++++++++++++++++++++++++++++++------
Mxcbutils.c | 141++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Mxcbutils.h | 36+++++++++++++++++++++++++++++++-----
5 files changed, 469 insertions(+), 63 deletions(-)

diff --git a/config.h b/config.h @@ -1,9 +1,35 @@ - #define MODKEY XCB_MOD_MASK_4 -static const char* termcmd[] = {"alacritty", NULL}; +#define FOCUS_COLOR 0xFF0000 +#define UNFOCUS_COLOR 0x005577 + +#define BORDER_WIDTH 1 + +static const char* termcmd [] = { "alacritty", + NULL }; +static const char* menucmd [] = { "dmenu_run", + NULL }; -Key keys[] = +static Key keys [] = { - { MODKEY, XK_Return, start, { .cmd = termcmd } } + { MODKEY, + XK_Return, + start, + { .cmd = termcmd }}, + { MODKEY, + XK_p, + start, + { .cmd = menucmd }} }; + +static Button buttons [] = +{ + { MODKEY, + XCB_BUTTON_INDEX_1, + mousemove, + { 0 }}, + { MODKEY, + XCB_BUTTON_INDEX_3, + mouseresize, + { 0 }}, +}; +\ No newline at end of file diff --git a/kbgwm.c b/kbgwm.c @@ -2,6 +2,7 @@ #include <stdlib.h> #include <stdbool.h> #include <unistd.h> +#include <assert.h> #include <xcb/xcb.h> #include <X11/keysym.h> @@ -9,37 +10,92 @@ #include "xcbutils.h" #define IGNORE_LOCK(modifier) (modifier & ~(XCB_MOD_MASK_LOCK)) +#define MATCH_MODIFIERS(expected, actual) ((actual & expected) == expected) static void start(const Arg* arg); +static void mousemove(const Arg* arg); +static void mouseresize(const Arg* arg); #include "config.h" +#define BORDER_WIDTH_X2 (BORDER_WIDTH << 1) + bool quit = false; +bool moving = false; +bool resizing = false; xcb_connection_t* c; xcb_window_t root; +xcb_screen_t* screen; +uint_least16_t previous_x; +uint_least16_t previous_y; -void setupEvents() +static window* focusedWindow; +window* windows; + +window* findWindow(xcb_window_t id) { - /* - * Get all the key symbols - */ + window* window = windows; -// xcb_grab_key(c, 1, root, XCB_MOD_MASK_ANY, XCB_GRAB_ANY, -// XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); + do + { + if (window->id == id) + return (window); + } + while ((window = window->next) != NULL); - xcb_grab_button(c, 0, root, XCB_EVENT_MASK_BUTTON_PRESS | - XCB_EVENT_MASK_BUTTON_RELEASE, XCB_GRAB_MODE_ASYNC, - XCB_GRAB_MODE_ASYNC, root, XCB_NONE, 1, XCB_MOD_MASK_ANY); + return NULL; +} - xcb_grab_button(c, 0, root, XCB_EVENT_MASK_BUTTON_PRESS | - XCB_EVENT_MASK_BUTTON_RELEASE, XCB_GRAB_MODE_ASYNC, - XCB_GRAB_MODE_ASYNC, root, XCB_NONE, 3, XCB_MOD_MASK_ANY); +void focus(xcb_window_t id) +{ + printf("focus: id=%d\n", id); - for (uint_fast8_t i = 0; i != LENGTH(keys); i++) + uint32_t values[1]; + + window* window = findWindow(id); + assert(window != NULL); + + // A window was previously focused -> we change its color + if (focusedWindow != NULL) { - xcb_register_key_press_events(keys[i]); + xcb_change_window_attributes(c, focusedWindow->id, XCB_CW_BORDER_PIXEL, (uint32_t[]) { 0xFF000000 | UNFOCUS_COLOR }); } + xcb_change_window_attributes(c, 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, id, XCB_CONFIG_WINDOW_STACK_MODE, values); + + // Set the keyboard on the focused window + xcb_set_input_focus(c, XCB_NONE, id, XCB_CURRENT_TIME); + xcb_flush(c); + + focusedWindow = window; + printf("focus set to: id=%d\n", focusedWindow->id); +} + +void setupEvents() +{ + 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); } @@ -59,9 +115,10 @@ void handle_keypress(xcb_key_press_event_t* event) for (uint_fast8_t i = 0; i < LENGTH(keys); i++) { - printf("testing key: mod %d key %d\n", keys[i].modifiers, keys[i].keysym); + printf("testing key: mod %d key %d\n", keys[i].modifiers, + keys[i].keysym); - if (keysym == keys[i].keysym && (event->state & keys[i].modifiers) == keys[i].modifiers) + if (keysym == keys[i].keysym && MATCH_MODIFIERS(keys[i].modifiers, event->state)) { printf("Key found !\n"); keys[i].func(&keys[i].arg); @@ -70,6 +127,148 @@ void handle_keypress(xcb_key_press_event_t* event) } } +void handle_maprequest(xcb_map_request_event_t* event) +{ + xcb_get_geometry_reply_t* geometry; + + printf("received map request: parent %d xcb_window_t %d\n", event->parent, event->window); + + geometry = xcb_get_geometry_reply(c, xcb_get_geometry(c, event->window), NULL); + + window* window = emalloc(sizeof window); + window->id = event->window; + window->x = geometry->x; + window->y = geometry->y; + window->width = geometry->width; + window->height = geometry->height; + + if (windows != NULL) + { + window->next = windows; + } + + windows = window; + + printf("new window: id=%d x=%d y=%d width=%d height=%d\n", window->id, window->x, window->y, window->width, window->height); + + focus(event->window); + + xcb_configure_window(c, window->id, XCB_CONFIG_WINDOW_BORDER_WIDTH, (uint32_t[]) { BORDER_WIDTH }); + + // Display the window + xcb_map_window(c, window->id); + xcb_flush(c); +} + +void handle_buttonpress(xcb_button_press_event_t* event) +{ + printf("handle_buttonpress: child=%d\n", event->child); + + // Click on the root window -> ignore + if (event->child == 0) + return; + + // Focus window if needed + if (event->child != focusedWindow->id) + focus(event->child); + + for (uint_fast8_t i = 0; i < LENGTH(buttons); i++) + { + if (event->detail == buttons[i].keysym && MATCH_MODIFIERS(buttons[i].modifiers,event->state)) + { + previous_x = event->root_x; + previous_y = event->root_y; + + printf("Button found !\n"); + buttons[i].func(&buttons[i].arg); + break; + } + } +} + +void handle_buttonrelease(xcb_button_release_event_t* event) +{ + assert(moving || resizing); + + printf("handle_buttonrelease: mod=%d button=%d\n", event->state, event->detail); + + xcb_ungrab_pointer(c, XCB_CURRENT_TIME); + xcb_flush(c); + + moving = false; + resizing = false; +} + +void mousemove(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_NONE, + XCB_CURRENT_TIME); + xcb_flush(c); +} + +void mouseresize(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_NONE, + XCB_CURRENT_TIME); + xcb_flush(c); +} + +void handle_motionnotify(xcb_motion_notify_event_t* event) +{ + assert(moving || resizing); + assert(focusedWindow != NULL); + assert(focusedWindow->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); + + uint16_t diff_x = event->root_x - previous_x; + uint16_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; + + 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); + } + else if (resizing) + { + focusedWindow->width += diff_x; + focusedWindow->height += diff_y; + + uint32_t values[2] = { focusedWindow->width, focusedWindow->height }; + xcb_configure_window(c, focusedWindow->id, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values); + } + + xcb_flush(c); +} + void eventLoop() { xcb_generic_event_t* event; @@ -85,13 +284,34 @@ void eventLoop() handle_keypress((xcb_key_press_event_t*) event); break; + case XCB_BUTTON_PRESS: + printf("\nXCB_BUTTON_PRESS\n"); + handle_buttonpress((xcb_button_press_event_t*) event); + break; + + case XCB_BUTTON_RELEASE: + printf("\nXCB_BUTTON_RELEASE\n"); + handle_buttonrelease((xcb_button_release_event_t*) event); + break; + + case XCB_MAP_REQUEST: + printf("\nXCB_MAP_REQUEST\n"); + handle_maprequest((xcb_map_request_event_t*) event); + break; + case XCB_MAPPING_NOTIFY: printf("\nXCB_MAPPING_NOTIFY\n"); onMappingNotify((xcb_mapping_notify_event_t*) event); break; + case XCB_MOTION_NOTIFY: + printf("\nXCB_MOTION_NOTIFY\n"); + handle_motionnotify((xcb_motion_notify_event_t*) event); + break; + default: - printf("Received event, response type %d\n", event->response_type & ~0x80); + printf("Received event, response type %d\n", + event->response_type & ~0x80); break; } @@ -101,11 +321,18 @@ void eventLoop() void start(const Arg* arg) { + printf("start %s\n", arg->cmd[0]); + if (fork() == 0) { // Child process setsid(); - execvp((char*)arg->cmd[0], (char**)arg->cmd); + + if (execvp((char*) arg->cmd[0], (char**) arg->cmd) == -1) + { + perror(arg->cmd[0]); + exit(-1); + } } } @@ -115,7 +342,9 @@ int main(void) * displayname = NULL -> use DISPLAY environment variable */ int screenp; - c = xcb_connect(NULL, &screenp); + c = xcb_connect( + NULL, &screenp); + if (xcb_connection_has_error(c)) { perror("xcb_connect"); @@ -126,12 +355,14 @@ int main(void) * Find the screen */ xcb_screen_iterator_t iter = xcb_setup_roots_iterator(xcb_get_setup(c)); + for (int i = 0; i < screenp; ++i) { xcb_screen_next(&iter); } - xcb_screen_t* screen = iter.data; + screen = iter.data; + if (!screen) { xcb_disconnect(c); @@ -141,6 +372,9 @@ int main(void) root = screen->root; + printf("White: %d\n", screen->white_pixel); + printf("Black: %d\n", screen->black_pixel); + xcb_flush(c); setupEvents(); @@ -150,5 +384,5 @@ int main(void) xcb_disconnect(c); - return 0; + return (0); } diff --git a/types.h b/types.h @@ -1,15 +1,46 @@ #ifndef TYPES_H_ #define TYPES_H_ -typedef union { +typedef union +{ + const char** cmd; -} Arg; +} +Arg; + +typedef struct +{ + uint16_t modifiers; + xcb_keysym_t keysym; + void (*func) + ( + const Arg* + ); + const Arg arg; +} +Key; -typedef struct { +typedef struct +{ uint16_t modifiers; xcb_keysym_t keysym; - void (* func)(const Arg*); + void (*func) + ( + const Arg* + ); const Arg arg; -} Key; +} +Button; + +typedef struct window window; +struct window +{ + xcb_window_t id; + int_least16_t x, + y; + uint_least16_t width, + height; + window* next; +}; -#endif /* TYPES_H_ */ +#endif /* TYPES_H_ */ +\ No newline at end of file diff --git a/xcbutils.c b/xcbutils.c @@ -6,57 +6,143 @@ extern xcb_connection_t* c; extern xcb_window_t root; +void* emalloc +( + size_t size +) +{ + void* p; + + if ( !(p = malloc ( + size )) + ) + { + printf ( + "Out of memory" ); + exit ( + -1 ); + } + + return + (p); +} + /* * */ -void xcb_register_key_press_events(Key key) +// TODO: understand why XCB_MOD_MASK_2 is always present +#define IGNORED_MODIFIERS XCB_MOD_MASK_2 + +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); - - keycodes = xcb_get_keycodes(key.keysym); - - for (int i = 0; (keycode = keycodes[i]) != XCB_NO_SYMBOL; i++) - xcb_grab_key(c, 1, root, key.modifiers, keycode, - XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); + printf ( + "Registering key press event for key %d / key %d\n", + key.modifiers, + key.keysym ); + + keycodes = xcb_get_keycodes ( + key.keysym ); + + 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 ); + } + + free ( + keycodes ); +} - free(keycodes); +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 ); } /* * 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; - // Not able to retrieve the keysyms somehow - if (!(keysyms = xcb_key_symbols_alloc(c))) - return NULL; - - xcb_keycode_t* keycode = xcb_key_symbols_get_keycode(keysyms, keysym); - - xcb_key_symbols_free(keysyms); - return keycode; + if ( !(keysyms = xcb_key_symbols_alloc ( + c )) + ) + { + perror ( + "Not able to retrieve symbols" ); + return + (NULL); + } + + xcb_keycode_t* keycode = xcb_key_symbols_get_keycode ( + keysyms, + keysym ); + + 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))) - return 0; - - xcb_keysym_t keysym = xcb_key_symbols_get_keysym(keysyms, keycode, 0); - - xcb_key_symbols_free(keysyms); - return keysym; -} + if ( !(keysyms = xcb_key_symbols_alloc ( + c )) + ) + { + perror ( + "Not able to retrieve symbols" ); + return + (0); + } + + xcb_keysym_t keysym = xcb_key_symbols_get_keysym ( + keysyms, + keycode, + 0 ); + + xcb_key_symbols_free ( + keysyms ); + return + (keysym); +} +\ No newline at end of file diff --git a/xcbutils.h b/xcbutils.h @@ -1,19 +1,44 @@ #ifndef XCBUTILS_H_ #define XCBUTILS_H_ -#define LENGTH(X) (sizeof X / sizeof X[0]) +#define LENGTH( X ) (sizeof X / sizeof X [ 0 ]) #include <xcb/xcb_keysyms.h> #include <xcb/xcb.h> #include "types.h" +#define BUTTON_EVENT_MASK XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE + +void* +emalloc +( + size_t size +); + /* * registering events */ -void xcb_register_key_press_events(Key key); +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); +xcb_keycode_t* +xcb_get_keycodes +( + xcb_keysym_t +); +xcb_keysym_t +xcb_get_keysym +( + xcb_keycode_t +); -#endif /* XCBUTILS_H_ */ +#endif /* XCBUTILS_H_ */ +\ No newline at end of file