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:
M | config.h | 9 | +++++---- |
M | inaban.1 | 6 | +++++- |
M | inaban.c | 147 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------- |
M | inaban.h | 20 | ++++++++++++++++++++ |
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