tRefactor window grabbing code - spkp - Stacking wayland compositor
 (HTM) git clone git://git.z3bra.org/spkp.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
 (DIR) commit fc214f1bdbd96f8c8f6518120db23768668042ab
 (DIR) parent cf4434bc0566759fbf2d1abf96cc6c2555673896
 (HTM) Author: Willy Goiffon <dev@z3bra.org>
       Date:   Mon, 16 Nov 2020 16:04:59 +0100
       
       Refactor window grabbing code
       
       Diffstat:
         M sp:kp.c                             |     186 +++++++++++++++----------------
       
       1 file changed, 89 insertions(+), 97 deletions(-)
       ---
 (DIR) diff --git a/sp:kp.c b/sp:kp.c
       t@@ -33,18 +33,15 @@
        
        #define MAX(a,b) ((a)>(b)?(a):(b))
        #define MIN(a,b) ((a)<(b)?(a):(b))
       +#define DELTA(a,b) ((a)>(b)?(a)-(b):(b)-(a))
       +
        #define CLEANMASK(mask) (mask & ~(WLR_MODIFIER_CAPS|WLR_MODIFIER_SHIFT))
        
        enum {
                NORMAL,
       +        UNGRAB,
                MOVE,
                RESIZE,
       -        TELEPORT,
       -};
       -
       -enum {
       -        CONTENT,
       -        BORDER,
        };
        
        /* Internal compositor state */
       t@@ -59,10 +56,11 @@ struct spkp {
        
                int desktop; /* wether desktop is visible */
        
       -        int grabmode;
       -        double gx, gy;
       -        struct wlr_box grabbox;
       -        struct window *grabbed;
       +        struct {
       +                int mode;
       +                struct wlr_box box;
       +                struct window *window;
       +        } grab;
        
                struct wlr_cursor *cursor;
                struct wlr_xcursor_manager *cursor_mgr;
       t@@ -111,7 +109,6 @@ struct window {
                int mapped;
        
                double sx, sy;
       -        int area;
        
                struct wl_listener map;
                struct wl_listener unmap;
       t@@ -200,6 +197,8 @@ static void add_pointer(struct spkp *, struct wlr_input_device *);
        static void render(struct wlr_surface *, int, int, void *);
        static void render_border(struct wlr_box *, struct rdata *, float *);
        static void focus(struct window *);
       +static void grab(struct window *, int, const char *);
       +
        static int dropprivilege();
        static int keybinding(struct spkp *, uint32_t, uint32_t, enum wlr_key_state);
        static struct window *underneath(struct spkp *, double, double);
       t@@ -366,8 +365,8 @@ cb_frame_output(struct wl_listener *listener, void *data)
                        wlr_xdg_surface_for_each_surface(window->xdg, render, &rdata);
                }
        
       -        if (server->grabmode != NORMAL)
       -                render_border(&server->grabbox, &rdata, drawcolor);
       +        if (server->grab.mode != NORMAL)
       +                render_border(&server->grab.box, &rdata, drawcolor);
        
                /* render cursor by software in case the GPU doesn't handle it */
                wlr_output_render_software_cursors(wlr_output, NULL);
       t@@ -656,38 +655,33 @@ cb_motion(struct spkp *server, uint32_t time)
        
                seat = server->seat;
        
       -        w = server->grabbed;
       -
       -        switch(server->grabmode) {
       -        case MOVE:
       -                server->grabbox.x = server->cursor->x - server->gx;
       -                server->grabbox.y = server->cursor->y - server->gy;
       -                return; /* NOTREACHED */;
       -                break;
       -        case RESIZE: /* FALLTHROUGH */
       -        case TELEPORT:
       -                server->grabbox.width = MAX(server->cursor->x - server->grabbox.x, 1);
       -                server->grabbox.height = MAX(server->cursor->y - server->grabbox.y, 1);
       -                return;
       -        }
       -
                /*
                 * reset focus and cursor image when no window is under the
                 * pointer
                 */
       -        w = underneath(server, server->cursor->x, server->cursor->y);
       -        if (!w) {
       -                wlr_seat_pointer_clear_focus(seat);
       +        switch(server->grab.mode) {
       +        case MOVE:
       +                server->grab.box.x = server->cursor->x - server->grab.window->sx;
       +                server->grab.box.y = server->cursor->y - server->grab.window->sy;
       +                break;
       +        case RESIZE:
       +                server->grab.box.width = MAX(server->cursor->x - server->grab.box.x, 1);
       +                server->grab.box.height = MAX(server->cursor->y - server->grab.box.y, 1);
       +                break;
       +        case NORMAL:
                        wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
                                "left_ptr", server->cursor);
       -                return;
       -        }
       +                w = underneath(server, server->cursor->x, server->cursor->y);
       +                if (!w) {
       +                        wlr_seat_pointer_clear_focus(seat);
       +                        return;
       +                }
        
       -        if (w->surface) {
       -                if (seat->pointer_state.focused_surface == w->surface)
       -                        wlr_seat_pointer_notify_motion(seat, time, w->sx, w->sy);
       -                else
       +                /* focus pointer when moving to a different surface */
       +                if (seat->pointer_state.focused_surface != w->surface)
                                wlr_seat_pointer_notify_enter(seat, w->surface, w->sx, w->sy);
       +
       +                wlr_seat_pointer_notify_motion(seat, time, w->sx, w->sy);
                }
        }
        
       t@@ -763,28 +757,25 @@ cb_click(struct wl_listener *listener, void *data)
        void
        cb_click_release(struct spkp *server, struct wlr_event_pointer_button *ev)
        {
       -        struct wlr_box geom;
       -
       -        switch(server->grabmode) {
       -        case TELEPORT:
       +        switch(server->grab.mode) {
                case RESIZE:
       -                geom.width = server->grabbox.width;
       -                geom.height = server->grabbox.height;
       -                wlr_xdg_toplevel_set_size(server->grabbed->xdg, geom.width, geom.height);
       -                /* FALLTHROUGH */
       +                wlr_xdg_toplevel_set_size(server->grab.window->xdg,
       +                        server->grab.box.width,
       +                        server->grab.box.height);
       +                break;
                case MOVE:
       -                server->grabbed->x = server->grabbox.x;
       -                server->grabbed->y = server->grabbox.y;
       +                server->grab.window->x = server->grab.box.x;
       +                server->grab.window->y = server->grab.box.y;
                        break;
       -
                default:
                        /* pass down event when not grabbing a window */
                        wlr_seat_pointer_notify_button(server->seat,
       -                                ev->time_msec, ev->button, ev->state);
       -
       +                        ev->time_msec, ev->button, ev->state);
       +                return;
                }
        
       -        server->grabmode = NORMAL;
       +        if (server->grab.mode != NORMAL)
       +                grab(server->grab.window, UNGRAB, "left_ptr");
        }
        
        /*
       t@@ -797,34 +788,22 @@ cb_click_press(struct spkp *server, struct wlr_event_pointer_button *ev)
        {
                struct window *w;
                struct wlr_keyboard *kb;
       -        struct wlr_box geom;
        
                /* Ignore all press events when a window is grabbed */
       -        if (server->grabmode != NORMAL)
       +        if (server->grab.mode != NORMAL)
                        return;
        
                kb = wlr_seat_get_keyboard(server->seat);
        
                w = underneath(server, server->cursor->x, server->cursor->y);
       +        if (!w)
       +                return;
        
       -        /* pass down event when not grabbing a window */
       -        if (w) {
       -                /*
       -                 * 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;
       -
       -                /* bring window to the front */
       -                wl_list_remove(&w->link);
       -                wl_list_insert(&server->windows, &w->link);
       +        /* bring window to the front */
       +        wl_list_remove(&w->link);
       +        wl_list_insert(&server->windows, &w->link);
        
       -                focus(w);
       -        }
       +        focus(w);
        
                if (kb->modifiers.depressed != mousemod) {
                        wlr_seat_pointer_notify_button(server->seat,
       t@@ -834,23 +813,11 @@ cb_click_press(struct spkp *server, struct wlr_event_pointer_button *ev)
                }
        
                switch (ev->button) {
       -        case BTN_MIDDLE:
       -                server->grabmode = TELEPORT;
       -                server->grabbox.x = server->cursor->x;
       -                server->grabbox.y = server->cursor->y;
       -                server->grabbox.width = 1;
       -                server->grabbox.height = 1;
       -                break;
                case BTN_LEFT:
       -                wlr_xdg_surface_get_geometry(w->xdg, &geom);
       -                server->grabmode = MOVE;
       -                server->grabbox.width = geom.width;
       -                server->grabbox.height = geom.height;
       +                grab(w, MOVE, "hand2");
                        break;
                case BTN_RIGHT:
       -                server->grabmode = RESIZE;
       -                server->grabbox.width = w->sx + 2 * bordersize;
       -                server->grabbox.height = w->sy + 2 * bordersize;
       +                grab(w, RESIZE, "bottom_right_corner");
                        break;
                }
        }
       t@@ -1036,13 +1003,47 @@ focus(struct window *window)
                        wlr_xdg_toplevel_set_activated(toplevel, false);
                }
        
       -        server->grabbed = window;
       -
                /* give keyboard focus to the toplevel window */
                wlr_seat_keyboard_notify_enter(seat, window->xdg->surface,
                        kb->keycodes, kb->num_keycodes, &kb->modifiers);
        }
        
       +void
       +grab(struct window *window, int mode, const char *cursor)
       +{
       +        struct spkp *server;
       +
       +        server = window->server;
       +
       +        if (mode == UNGRAB) {
       +                server->grab.mode = NORMAL;
       +                server->grab.window = NULL;
       +                wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
       +                        cursor, server->cursor);
       +                return;
       +        }
       +
       +        if (server->grab.mode != NORMAL)
       +                return;
       +
       +        server->grab.mode = mode;
       +        server->grab.window = window;
       +        wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
       +                cursor, server->cursor);
       +
       +        switch (mode) {
       +        case MOVE:
       +                wlr_xdg_surface_get_geometry(window->xdg, &(server->grab.box));
       +                server->grab.box.x = window->x;
       +                server->grab.box.y = window->y;
       +                break;
       +        case RESIZE:
       +                server->grab.box.x = window->x;
       +                server->grab.box.y = window->y;
       +                break;
       +        }
       +}
       +
        /*
         * Drop current privileges to run as current user.
         */
       t@@ -1107,18 +1108,8 @@ underneath(struct spkp *server, double x, double y)
                        w->surface = wlr_xdg_surface_surface_at(w->xdg,
                                x - w->x, y - w->y, &w->sx, &w->sy);
        
       -                if (w->surface) {
       -                        w->area = CONTENT;
       +                if (w->surface)
                                return w;
       -                }
       -
       -                if (server->cursor->x > w->x - bordersize
       -                 && server->cursor->y > w->y - bordersize
       -                 && server->cursor->x < w->x + w->xdg->surface->current.width + bordersize
       -                 && server->cursor->y < w->y + w->xdg->surface->current.height + bordersize) {
       -                        w->area = BORDER;
       -                        return w;
       -                }
                }
        
                return NULL;
       t@@ -1232,6 +1223,7 @@ main(int argc, char *argv[])
        
                server.cursor = wlr_cursor_create();
                server.cursor_mgr = wlr_xcursor_manager_create(NULL, 24);
       +        server.grab.mode = NORMAL;
        
                wl_list_init(&server.outputs);
                wl_list_init(&server.windows);