tUse a drawing box to move/resize windows - spkp - Stacking wayland compositor
 (HTM) git clone git://git.z3bra.org/spkp.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
 (DIR) commit 1813f99552e6c439f35ea791a67b413734820345
 (DIR) parent 2d59a0706e0f4c00478a50b3b7e027a179bf7a78
 (HTM) Author: Willy Goiffon <dev@z3bra.org>
       Date:   Fri, 13 Nov 2020 15:49:07 +0100
       
       Use a drawing box to move/resize windows
       
       Diffstat:
         M compositor.c                        |      85 +++++++++++++++++++------------
       
       1 file changed, 52 insertions(+), 33 deletions(-)
       ---
 (DIR) diff --git a/compositor.c b/compositor.c
       t@@ -29,6 +29,7 @@
        
        #include "arg.h"
        
       +#define MAX(a,b) ((a)>(b)?(a):(b))
        #define CLEANMASK(mask) (mask & ~(WLR_MODIFIER_CAPS|WLR_MODIFIER_SHIFT))
        
        enum {
       t@@ -54,6 +55,7 @@ struct state {
        
                int grabmode;
                double gx, gy;
       +        struct wlr_box grabbox;
                struct window *grabbed;
        
                struct wlr_cursor *cursor;
       t@@ -335,17 +337,22 @@ cb_frame_output(struct wl_listener *listener, void *data)
                wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height);
                wlr_renderer_clear(renderer, background);
        
       +        rdata.output = wlr_output;
       +        rdata.renderer = renderer;
       +
                wl_list_for_each_reverse(window, &output->server->windows, link) {
                        if (!window->mapped)
                                continue;
        
       -                rdata.output = wlr_output;
                        rdata.window = window;
       -                rdata.renderer = renderer;
                        clock_gettime(CLOCK_MONOTONIC, &rdata.when);
                        wlr_xdg_surface_for_each_surface(window->toplevel, render, &rdata);
                }
        
       +        struct state *server = output->server;
       +        if (server->grabmode != NORMAL)
       +                render_border(&server->grabbox, &rdata, 1);
       +
                /* render cursor by software in case the GPU doesn't handle it */
                wlr_output_render_software_cursors(wlr_output, NULL);
        
       t@@ -585,21 +592,16 @@ cb_motion(struct state *server, uint32_t time)
        
                w = server->grabbed;
        
       -        struct wlr_box geom;
                switch(server->grabmode) {
                case MOVE:
       -                wlr_xdg_surface_get_geometry(w->toplevel, &geom);
       -                w->x = server->cursor->x - server->gx;
       -                w->y = server->cursor->y - server->gy;
       +                server->grabbox.x = server->cursor->x - server->gx;
       +                server->grabbox.y = server->cursor->y - server->gy;
                        return; /* NOTREACHED */;
                        break;
                case RESIZE:
       -                wlr_xdg_surface_get_geometry(w->toplevel, &geom);
       -                geom.width = server->cursor->x - geom.x - w->x;
       -                geom.height = server->cursor->y - geom.y - w->y;
       -                wlr_xdg_toplevel_set_size(w->toplevel, geom.width, geom.height);
       -                return; /* NOTREACHED */;
       -                break;
       +                server->grabbox.width = MAX(server->cursor->x - server->grabbox.x, 100);
       +                server->grabbox.height = MAX(server->cursor->y - server->grabbox.y, 100);
       +                return;
                }
        
                /*
       t@@ -672,52 +674,69 @@ cb_click(struct wl_listener *listener, void *data)
                struct wlr_event_pointer_button *ev;
                struct window *w;
                struct wlr_keyboard *kb;
       +        struct wlr_box geom;
        
                server = wl_container_of(listener, server, click);
                kb = wlr_seat_get_keyboard(server->seat);
                ev = data;
        
       +        if (ev->state == WLR_BUTTON_RELEASED) {
       +                switch(server->grabmode) {
       +                case MOVE:
       +                        server->grabbed->x = server->grabbox.x;
       +                        server->grabbed->y = server->grabbox.y;
       +                        break;
       +                case RESIZE:
       +                        geom.width = server->grabbox.width;
       +                        geom.height = server->grabbox.height;
       +                        wlr_xdg_toplevel_set_size(server->grabbed->toplevel, geom.width, geom.height);
       +                        break;
       +                case NORMAL:
       +                        /* pass down event when not grabbing a window */
       +                        wlr_seat_pointer_notify_button(server->seat,
       +                                        ev->time_msec, ev->button, ev->state);
       +
       +                }
       +                server->grabmode = NORMAL;
       +                return;
       +        }
       +
                w = underneath(server, server->cursor->x, server->cursor->y);
        
                /* don't enter grab mode when there is no window under the pointer */
                if (!w) {
       -                wlr_seat_pointer_clear_focus(server->seat);
       -                server->grabmode = NORMAL;
                        return;
                }
        
                if ((w->area == BORDER || (kb->modifiers.depressed & WLR_MODIFIER_LOGO))
                 && ev->state == WLR_BUTTON_PRESSED
                 && server->grabmode == NORMAL) {
       +
       +                /*
       +                 * Save which window was clicked, and the coordinates
       +                 * of the event on that surface.
       +                 */
       +                server->grabbed = w;
       +                server->gx = w->sx;
       +                server->gy = w->sy;
       +                server->grabbox.x = w->x;
       +                server->grabbox.y = w->y;
       +
                        switch (ev->button) {
                        case BTN_LEFT:
       +                        wlr_xdg_surface_get_geometry(w->toplevel, &geom);
       +                        server->grabbox.width = geom.width;
       +                        server->grabbox.height = geom.height;
                                server->grabmode = MOVE;
                                break;
                        case BTN_RIGHT:
                                server->grabmode = RESIZE;
       +                        server->grabbox.width = w->sx + 2 * bordersize;
       +                        server->grabbox.height = w->sy + 2 * bordersize;
                                break;
                        }
                }
        
       -        /* pass down event when not grabbing a window */
       -        if (server->grabmode == NORMAL)
       -                wlr_seat_pointer_notify_button(server->seat,
       -                        ev->time_msec, ev->button, ev->state);
       -
       -        /* every release event would reset the grab mode */
       -        if (ev->state == WLR_BUTTON_RELEASED) {
       -                server->grabmode = NORMAL;
       -                return;
       -        }
       -
       -        /*
       -         * Save which window was clicked, and the coordinates
       -         * of the event on that surface.
       -         */
       -        server->grabbed = w;
       -        server->gx = w->sx;
       -        server->gy = w->sy;
       -
                /* bring window to the front */
                wl_list_remove(&w->link);
                wl_list_insert(&server->windows, &w->link);