From 285470897406b653e77d732a77356aaf9a70b799 Mon Sep 17 00:00:00 2001 From: wochap Date: Fri, 5 Jul 2024 12:37:39 -0500 Subject: [PATCH] implement swapandfocusdir --- config.def.h | 8 +++ dwl.c | 164 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) diff --git a/config.def.h b/config.def.h index 22d2171..724e15e 100644 --- a/config.def.h +++ b/config.def.h @@ -129,6 +129,14 @@ static const Key keys[] = { { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} }, { MODKEY, XKB_KEY_j, focusstack, {.i = +1} }, { MODKEY, XKB_KEY_k, focusstack, {.i = -1} }, + { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Left, focusdir, {.ui = 0} }, + { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Right, focusdir, {.ui = 1} }, + { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Up, focusdir, {.ui = 2} }, + { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_Down, focusdir, {.ui = 3} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Left, swapdir, {.ui = 0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Right, swapdir, {.ui = 1} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Up, swapdir, {.ui = 2} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Down, swapdir, {.ui = 3} }, { MODKEY, XKB_KEY_i, incnmaster, {.i = +1} }, { MODKEY, XKB_KEY_d, incnmaster, {.i = -1} }, { MODKEY, XKB_KEY_h, setmfact, {.f = -0.05f} }, diff --git a/dwl.c b/dwl.c index dc0437e..844c1f5 100644 --- a/dwl.c +++ b/dwl.c @@ -241,6 +241,11 @@ typedef struct { struct wl_listener destroy; } SessionLock; +typedef struct { + int x; + int y; +} Vector; + /* function declarations */ static void applybounds(Client *c, struct wlr_box *bbox); static void applyrules(Client *c); @@ -285,6 +290,8 @@ static Monitor *dirtomon(enum wlr_direction dir); static void focusclient(Client *c, int lift); static void focusmon(const Arg *arg); static void focusstack(const Arg *arg); +static void focusdir(const Arg *arg); +static void swapdir(const Arg *arg); static Client *focustop(Monitor *m); static void fullscreennotify(struct wl_listener *listener, void *data); static void handlesig(int signo); @@ -1425,6 +1432,163 @@ focusstack(const Arg *arg) focusclient(c, 1); } +Vector +position_of_box(const struct wlr_box *box) +{ + return (Vector){ + .x = box->x + box->width / 2, + .y = box->y + box->height / 2, + }; +} + +Vector +diff_of_vectors(Vector *a, Vector *b) +{ + return (Vector){ + .x = b->x - a->x, + .y = b->y - a->y, + }; +} + +const char * +direction_of_vector(Vector *vector) +{ + // A zero length vector has no direction + if (vector->x == 0 && vector->y == 0) return ""; + + if (abs(vector->y) > abs(vector->x)) { + // Careful: We are operating in a Y-inverted coordinate system. + return (vector->y > 0) ? "bottom" : "top"; + } else { + return (vector->x > 0) ? "right" : "left"; + } +} + +uint32_t +vector_length(Vector *vector) +{ + // Euclidean distance formula + return (uint32_t)sqrt(vector->x * vector->x + vector->y * vector->y); +} + +// Spatial direction, based on focused client position. +Client * +client_in_direction(const char *direction, const int *skipfloat) +{ + Client *cfocused = focustop(selmon); + Vector cfocusedposition; + Client *ctarget = NULL; + double targetdistance = INFINITY; + Client *c; + + if (!cfocused || cfocused->isfullscreen || (skipfloat && cfocused->isfloating)) + return NULL; + + cfocusedposition = position_of_box(&cfocused->geom); + + wl_list_for_each(c, &clients, link) { + Vector cposition; + Vector positiondiff; + uint32_t distance; + + if (c == cfocused) + continue; + + if (skipfloat && c->isfloating) + continue; + + if (!VISIBLEON(c, selmon)) + continue; + + cposition = position_of_box(&c->geom); + positiondiff = diff_of_vectors(&cfocusedposition, &cposition); + + if (strcmp(direction, direction_of_vector(&positiondiff)) != 0) + continue; + + distance = vector_length(&positiondiff); + + if (distance < targetdistance) { + ctarget = c; + targetdistance = distance; + } + } + + return ctarget; +} + +void +focusdir(const Arg *arg) +{ + Client *c = NULL; + + if (arg->ui == 0) + c = client_in_direction("left", (int *)0); + if (arg->ui == 1) + c = client_in_direction("right", (int *)0); + if (arg->ui == 2) + c = client_in_direction("top", (int *)0); + if (arg->ui == 3) + c = client_in_direction("bottom", (int *)0); + + if (c != NULL) + focusclient(c, 1); +} + +void +wl_list_swap(struct wl_list *list1, struct wl_list *list2) +{ + struct wl_list *prev1, *next1, *prev2, *next2; + struct wl_list temp; + + if (list1 == list2) { + // No need to swap the same list + return; + } + + // Get the lists before and after list1 + prev1 = list1->prev; + next1 = list1->next; + + // Get the lists before and after list2 + prev2 = list2->prev; + next2 = list2->next; + + // Update the next and previous pointers of adjacent lists + prev1->next = list2; + next1->prev = list2; + prev2->next = list1; + next2->prev = list1; + + // Swap the next and previous pointers of the lists to actually swap them + temp = *list1; + *list1 = *list2; + *list2 = temp; +} + +void +swapdir(const Arg *arg) +{ + Client *c = NULL; + Client *cfocused; + + if (arg->ui == 0) + c = client_in_direction("left", (int *)1); + if (arg->ui == 1) + c = client_in_direction("right", (int *)1); + if (arg->ui == 2) + c = client_in_direction("top", (int *)1); + if (arg->ui == 3) + c = client_in_direction("bottom", (int *)1); + + if (c == NULL) + return; + + cfocused = focustop(selmon); + wl_list_swap(&cfocused->link, &c->link); + arrange(selmon); +} + /* We probably should change the name of this, it sounds like * will focus the topmost client of this mon, when actually will * only return that client */ -- 2.45.1