logo

inaban

Unnamed repository; edit this file 'description' to name the repository.
commit: a0dae91a5fc725b18791987a24ed0923f948d9b0
parent 29cf9b2036dbe2b5449f3dd03df1ece5a61efacd
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Wed,  2 Dec 2020 08:12:03 +0100

Add resizing and moving windows via ModKey

Diffstat:

Mconfig.h9+++++----
Minaban.16+++++-
Minaban.c147+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Minaban.h20++++++++++++++++++++
4 files changed, 140 insertions(+), 42 deletions(-)

diff --git a/config.h b/config.h @@ -5,14 +5,15 @@ static const char *menucmd[] = {"bemenu-run", NULL}; static const char *termcmd[] = {"cage", "-d", "st", NULL}; // See `enum wlr_keyboard_modifier` in `<wlr/types/wlr_keyboard.h>` -#define MODKEY WLR_MODIFIER_ALT +#define ModMask WLR_MODIFIER_ALT #define ShiftMask WLR_MODIFIER_SHIFT +#define ModKey XKB_KEY_Alt_L // clang-format off static Shortcut shortcuts[] = { /* modifier, keysym, function, argument */ - {MODKEY, XKB_KEY_p, spawn, {.v = menucmd}}, - {MODKEY | ShiftMask, XKB_KEY_Return, spawn, {.v = termcmd}}, - {MODKEY | ShiftMask, XKB_KEY_q, quit, {0}}, + {ModMask, XKB_KEY_p, spawn, {.v = menucmd}}, + {ModMask | ShiftMask, XKB_KEY_Return, spawn, {.v = termcmd}}, + {ModMask | ShiftMask, XKB_KEY_q, quit, {0}}, // {MODKEY | ShiftMask, XKB_KEY_c, killclient, {0}}, // {MODKEY, XKB_KEY_j, focusstack, {.i = +1}}, // {MODKEY, XKB_KEY_k, focusstack, {.i = -1}}, diff --git a/inaban.1 b/inaban.1 @@ -10,7 +10,7 @@ .Nm .Op Fl h .Op Fl s Ar startup command -.Sh KEYBINDINGS +.Sh BINDINGS Mod defaults to Alt. .Bl -width Ds -tag .It Mod+Escape @@ -21,6 +21,10 @@ Switches to the next view. Executes an application launcher (defaults to bemenu). .It Mod+Enter Executes the terminal (defaults to wlterm). +.It Mod+Button1 +Moves the window under the cursor around. (ignores focus) +.It Mod+Button2 +Resizes the window under the cursor. (ignores focus) .El .Sh BUGS You can submit contributions or tickets to diff --git a/inaban.c b/inaban.c @@ -24,16 +24,10 @@ keyboard_handle_modifiers(struct wl_listener *listener, void *data) { (void)data; struct inaban_keyboard *keyboard = wl_container_of(listener, keyboard, modifiers); - /* - * A seat can only have one keyboard, but this is a limitation of the - * Wayland protocol - not wlroots. We assign all connected keyboards to the - * same seat. You can swap out the underlying wlr_keyboard like this and - * wlr_seat handles this transparently. - */ - wlr_seat_set_keyboard(keyboard->server->seat, keyboard->device); - /* Send modifiers to the client. */ - wlr_seat_keyboard_notify_modifiers(keyboard->server->seat, - &keyboard->device->keyboard->modifiers); + struct wlr_seat *seat = keyboard->server->seat; + + wlr_seat_set_keyboard(seat, keyboard->device); + wlr_seat_keyboard_notify_modifiers(seat, &keyboard->device->keyboard->modifiers); } /* event raised when a key is pressed or released. */ @@ -52,8 +46,9 @@ keyboard_handle_key(struct wl_listener *listener, void *data) bool handled = false; uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard); - if(event->state == WLR_KEY_PRESSED) + switch(event->state) { + case WLR_KEY_PRESSED: wlr_log(WLR_DEBUG, "key_pressed: {modifiers: %x, keycode: %x, keysym: %x}", modifiers, @@ -66,6 +61,22 @@ keyboard_handle_key(struct wl_listener *listener, void *data) shortcuts[i].func(&(shortcuts[i].arg)); handled = true; } + + if(!handled && keysym == ModKey) + { + wlr_log(WLR_DEBUG, "InputMode: ModKey"); + server->input_mode = INABAN_INPUT_MODKEY; + handled = true; + } + break; + case WLR_KEY_RELEASED: + if(keysym == ModKey && server->input_mode == INABAN_INPUT_MODKEY) + { + wlr_log(WLR_DEBUG, "InputMode: Normal"); + server->input_mode = INABAN_INPUT_NORMAL; + handled = true; + } + break; } /* Otherwise, we pass it along to the client. */ @@ -203,20 +214,45 @@ desktop_view_at(struct inaban_server *server, static void process_cursor_motion(struct inaban_server *server, uint32_t time) { - /* Otherwise, find the view under the pointer and send the event along. */ - double sx, sy; - struct wlr_seat *seat = server->seat; - struct wlr_surface *surface = NULL; - struct inaban_view *view = - desktop_view_at(server, server->cursor->x, server->cursor->y, &surface, &sx, &sy); - /* If there's no view under the cursor, set the cursor image to a + if(server->cursor_mode == INABAN_CURSOR_MOVE) + { + struct inaban_view *view = server->grabbed_view; + + view->x = server->cursor->x - server->grab_x; + view->y = server->cursor->y - server->grab_y; + } + else if(server->cursor_mode == INABAN_CURSOR_RESIZE) + { + struct inaban_view *view = server->grabbed_view; + int width = server->grab_width; + int height = server->grab_height; + + width = server->cursor->x - server->grab_x; + height = server->cursor->y - server->grab_y; + + wlr_xdg_toplevel_set_size(view->xdg_surface, width, height); + } + else if(server->cursor_mode == INABAN_CURSOR_IGNORE) + { + /* noop */ + } + else + { + double sx, sy; + struct wlr_seat *seat = server->seat; + struct wlr_surface *surface = NULL; + struct inaban_view *view = + desktop_view_at(server, server->cursor->x, server->cursor->y, &surface, &sx, &sy); + + /* If there's no view under the cursor, set the cursor image to a * default. This is what makes the cursor image appear when you move it * around the screen, not over any views. */ - if(!view) wlr_xcursor_manager_set_cursor_image(server->cursor_mgr, "left_ptr", server->cursor); - if(surface) - { - bool focus_changed = seat->pointer_state.focused_surface != surface; - /* + if(!view) wlr_xcursor_manager_set_cursor_image(server->cursor_mgr, "left_ptr", server->cursor); + + if(surface) + { + bool focus_changed = seat->pointer_state.focused_surface != surface; + /* * "Enter" the surface if necessary. This lets the client know that the * cursor has entered one of its surfaces. * @@ -224,16 +260,17 @@ process_cursor_motion(struct inaban_server *server, uint32_t time) * from keyboard focus. You get pointer focus by moving the pointer over * a window. */ - wlr_seat_pointer_notify_enter(seat, surface, sx, sy); - /* The enter event contains coordinates, so we only need to notify + wlr_seat_pointer_notify_enter(seat, surface, sx, sy); + /* The enter event contains coordinates, so we only need to notify * on motion if the focus did not change. */ - if(!focus_changed) wlr_seat_pointer_notify_motion(seat, time, sx, sy); - } - else - { - /* Clear pointer focus so future button events and such are not sent to + if(!focus_changed) wlr_seat_pointer_notify_motion(seat, time, sx, sy); + } + else + { + /* Clear pointer focus so future button events and such are not sent to * the last client to have the cursor over it. */ - wlr_seat_pointer_clear_focus(seat); + wlr_seat_pointer_clear_focus(seat); + } } } @@ -268,20 +305,56 @@ server_cursor_motion_absolute(struct wl_listener *listener, void *data) process_cursor_motion(server, event->time_msec); } +/* event forwarded by the cursor when a pointer emits a button event */ static void server_cursor_button(struct wl_listener *listener, void *data) { - /* This event is forwarded by the cursor when a pointer emits a button - * event. */ struct inaban_server *server = wl_container_of(listener, server, cursor_button); struct wlr_event_pointer_button *event = data; - /* Notify the client with pointer focus that a button press has occurred */ - wlr_seat_pointer_notify_button(server->seat, event->time_msec, event->button, event->state); double sx, sy; - struct wlr_surface *surface; // TODO: initialize + struct wlr_surface *surface = NULL; struct inaban_view *view = desktop_view_at(server, server->cursor->x, server->cursor->y, &surface, &sx, &sy); - focus_view(view, surface); /* Focus that client if the button was _pressed_ */ + + if((server->input_mode == INABAN_INPUT_MODKEY) && (server->cursor_mode == INABAN_CURSOR_NORMAL) && + (event->state == WLR_BUTTON_PRESSED) && (view != NULL)) + { + struct wlr_box geo_box; + wlr_xdg_surface_get_geometry(view->xdg_surface, &geo_box); + + switch(event->button) + { + case 272: /* for some reason this is button 1 */ + server->cursor_mode = INABAN_CURSOR_MOVE; + server->grabbed_view = view; + server->grab_x = server->cursor->x - view->x; + server->grab_y = server->cursor->y - view->y; + wlr_log(WLR_DEBUG, "server->cursor_mode = move"); + break; + case 273: /* for some reason this is button 2 */ + server->cursor_mode = INABAN_CURSOR_RESIZE; + server->grabbed_view = view; + + server->grab_x = view->x; + server->grab_y = view->y; + server->grab_width = geo_box.width; + server->grab_height = geo_box.height; + wlr_log(WLR_DEBUG, "server->cursor_mode = resize"); + break; + default: server->cursor_mode = INABAN_CURSOR_IGNORE; break; + } + } + else if((server->cursor_mode != INABAN_CURSOR_NORMAL) && (event->state == WLR_BUTTON_RELEASED)) + { + server->cursor_mode = INABAN_CURSOR_NORMAL; + } + else + { + /* Notify the client with pointer focus that a button press has occurred */ + wlr_seat_pointer_notify_button(server->seat, event->time_msec, event->button, event->state); + /* Focus that client if the button was _pressed_ */ + focus_view(view, surface); + } } static void diff --git a/inaban.h b/inaban.h @@ -23,6 +23,20 @@ #include <wlr/util/log.h> #include <xkbcommon/xkbcommon.h> +enum inaban_input_mode +{ + INABAN_INPUT_NORMAL, + INABAN_INPUT_MODKEY, +}; + +enum inaban_cursor_mode +{ + INABAN_CURSOR_NORMAL, + INABAN_CURSOR_MOVE, + INABAN_CURSOR_RESIZE, + INABAN_CURSOR_IGNORE, +}; + struct inaban_server { struct wl_display *wl_display; @@ -49,6 +63,12 @@ struct inaban_server struct wlr_output_layout *output_layout; struct wl_list outputs; struct wl_listener new_output; + + enum inaban_input_mode input_mode; + enum inaban_cursor_mode cursor_mode; + + struct inaban_view *grabbed_view; + int grab_x, grab_y, grab_width, grab_height; }; struct inaban_output