From 83ae7d4816a49f46063ab16ffecd32b2e7e61784 Mon Sep 17 00:00:00 2001 From: choc Date: Fri, 15 Sep 2023 11:45:16 +0800 Subject: [PATCH] dragresize: implement rio-like window resizing select window to resize then drag out an area for it to occupy --- dwl.c | 132 +++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 98 insertions(+), 34 deletions(-) diff --git a/dwl.c b/dwl.c index dc0437e..843aa7a 100644 --- a/dwl.c +++ b/dwl.c @@ -80,7 +80,7 @@ #define LISTEN_STATIC(E, H) do { static struct wl_listener _l = {.notify = (H)}; wl_signal_add((E), &_l); } while (0) /* enums */ -enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ +enum { CurNormal, CurPressed, CurSelect, CurMove, CurResize, CurBind }; /* cursor */ enum { XDGShell, LayerShell, X11 }; /* client types */ enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrTop, LyrFS, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */ #ifdef XWAYLAND @@ -603,15 +603,21 @@ buttonpress(struct wl_listener *listener, void *data) switch (event->state) { case WLR_BUTTON_PRESSED: - cursor_mode = CurPressed; selmon = xytomon(cursor->x, cursor->y); - if (locked) + if (locked) { + cursor_mode = CurPressed; break; + } - /* Change focus if the button was _pressed_ over a client */ - xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL); - if (c && (!client_is_unmanaged(c) || client_wants_focus(c))) - focusclient(c, 1); + if (cursor_mode == CurNormal) + cursor_mode = CurPressed; + + if (cursor_mode != CurResize) { + /* Change focus if the button was _pressed_ over a client */ + xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL); + if (c && (!client_is_unmanaged(c) || client_wants_focus(c))) + focusclient(c, 1); + } keyboard = wlr_seat_get_keyboard(seat); mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; @@ -624,17 +630,42 @@ buttonpress(struct wl_listener *listener, void *data) } break; case WLR_BUTTON_RELEASED: + if (locked) { + cursor_mode = CurNormal; + break; + } /* If you released any buttons, we exit interactive move/resize mode. */ - /* TODO should reset to the pointer focus's current setcursor */ - if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) { - wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); + switch (cursor_mode) { + case CurPressed: cursor_mode = CurNormal; - /* Drop the window off on its new monitor */ - selmon = xytomon(cursor->x, cursor->y); - setmon(grabc, selmon, 0); + case CurNormal: + break; + case CurSelect: return; - } else { + case CurResize: + /* a label can only be part of a statement - Wpedantic */ + { + int nw = abs((int) cursor->x - grabcx); + int nh = abs((int) cursor->y - grabcy); + if (nw > 1 && nh > 1) { + setfloating(grabc, 1); + resize(grabc, (struct wlr_box){.x = MIN(ROUND(cursor->x), grabcx), + .y = MIN(ROUND(cursor->y), grabcy), + .width = nw, .height = nh}, 1); + } + } + /* fallthrough */ + default: + /* TODO should reset to the pointer focus's current setcursor */ + wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); + /* Drop the window off on its new monitor */ + if (grabc && cursor_mode != CurBind) { + selmon = xytomon(cursor->x, cursor->y); + setmon(grabc, selmon, 0); + grabc = NULL; + } cursor_mode = CurNormal; + return; } break; } @@ -1815,15 +1846,33 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), (int)round(cursor->y)); /* If we are currently grabbing the mouse, handle and return */ - if (cursor_mode == CurMove) { + switch (cursor_mode) { + case CurSelect: + return; + case CurMove: /* Move the grabbed client to the new position. */ resize(grabc, (struct wlr_box){.x = (int)round(cursor->x) - grabcx, .y = (int)round(cursor->y) - grabcy, .width = grabc->geom.width, .height = grabc->geom.height}, 1); return; - } else if (cursor_mode == CurResize) { - resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y, - .width = (int)round(cursor->x) - grabc->geom.x, .height = (int)round(cursor->y) - grabc->geom.y}, 1); - return; + case CurResize: + { + int w, h, x, y; + if (!grabc) + return; + w = abs(grabcx - (int)round(cursor->x)); + h = abs(grabcy - (int)round(cursor->y)); + x = MIN(grabcx, (int)round(cursor->x)) - grabc->geom.x; + y = MIN(grabcy, (int)round(cursor->y)) - grabc->geom.y; + wlr_scene_rect_set_size(grabc->border[0], w, grabc->bw); + wlr_scene_rect_set_size(grabc->border[1], w, grabc->bw); + wlr_scene_rect_set_size(grabc->border[2], grabc->bw, h - 2 * grabc->bw); + wlr_scene_rect_set_size(grabc->border[3], grabc->bw, h - 2 * grabc->bw); + wlr_scene_node_set_position(&grabc->border[0]->node, x, y); + wlr_scene_node_set_position(&grabc->border[1]->node, x, y + h - grabc->bw); + wlr_scene_node_set_position(&grabc->border[2]->node, x, y + grabc->bw); + wlr_scene_node_set_position(&grabc->border[3]->node, x + w - grabc->bw, y + grabc->bw); + return; + } } /* If there's no client surface under the cursor, set the cursor image to a @@ -1853,29 +1902,43 @@ motionrelative(struct wl_listener *listener, void *data) void moveresize(const Arg *arg) { - if (cursor_mode != CurNormal && cursor_mode != CurPressed) - return; - xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL); - if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen) + /* Consider global select bool instead of this + CurSelect enum */ + bool selected = (cursor_mode == CurSelect); + if (!selected) { + if (cursor_mode != CurNormal && cursor_mode != CurPressed) + return; + xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL); + } + + if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen) { + grabc = NULL; + cursor_mode = CurNormal; return; + } - /* Float the window and tell motionnotify to grab it */ - setfloating(grabc, 1); + /* TODO: factor out selected bool */ switch (cursor_mode = arg->ui) { + case CurResize: + if (!selected) break; + grabcx = ROUND(cursor->x); + grabcy = ROUND(cursor->y); + wlr_cursor_set_xcursor(cursor, cursor_mgr, "tcross"); + return; case CurMove: grabcx = (int)round(cursor->x) - grabc->geom.x; grabcy = (int)round(cursor->y) - grabc->geom.y; + setfloating(grabc, 1); wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur"); - break; - case CurResize: - /* Doesn't work for X11 output - the next absolute motion event - * returns the cursor to where it started */ - wlr_cursor_warp_closest(cursor, NULL, - grabc->geom.x + grabc->geom.width, - grabc->geom.y + grabc->geom.height); - wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize"); - break; + return; + default: + grabc = NULL; + cursor_mode = CurNormal; + wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); + return; } + + cursor_mode = CurSelect; + wlr_cursor_set_xcursor(cursor, cursor_mgr, "crosshair"); } void @@ -2149,6 +2212,7 @@ resize(Client *c, struct wlr_box geo, int interact) wlr_scene_rect_set_size(c->border[1], c->geom.width, c->bw); wlr_scene_rect_set_size(c->border[2], c->bw, c->geom.height - 2 * c->bw); wlr_scene_rect_set_size(c->border[3], c->bw, c->geom.height - 2 * c->bw); + wlr_scene_node_set_position(&c->border[0]->node, 0, 0); wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - c->bw); wlr_scene_node_set_position(&c->border[2]->node, 0, c->bw); wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw); -- 2.43.0