diff --git a/config.def.h b/config.def.h index 8164359..d0a4f1c 100644 --- a/config.def.h +++ b/config.def.h @@ -4,7 +4,7 @@ ((hex >> 8) & 0xFF) / 255.0f, \ (hex & 0xFF) / 255.0f } /* appearance */ -static const int sloppyfocus = 1; /* focus follows mouse */ +static const int sloppyfocus = 0; /* focus follows mouse */ static const int bypass_surface_visibility = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */ static const int smartgaps = 0; /* 1 means no outer gap when there is only one window */ static const int monoclegaps = 1; /* 1 means outer gaps in monocle layout */ @@ -64,6 +64,7 @@ static int log_level = WLR_DEBUG; /* Autostart */ static const char *const autostart[] = { + "/usr/lib/pam_kwallet_init", NULL, "dbus-update-activation-environment", "DISPLAY", "MOZ_DBUS_REMOTE", "WAYLAND_DISPLAY", "XDG_CURRENT_DESKTOP", NULL, "dinit", "-q", NULL, // "pkexec", "swayosd-libinput-backend", NULL, @@ -74,17 +75,19 @@ static const char *const autostart[] = { /* NOTE: ALWAYS keep a rule declared even if you don't use rules (e.g leave at least one example) */ static const Rule rules[] = { - /* app_id title tags mask isfloating isterm noswallow monitor */ + /* app_id title tags mask isfloating isterm noswallow monitor */ /* examples: */ - { "Gimp_EXAMPLE", NULL, 0, 1, 0, 0, -1 }, /* Start on currently visible tags floating, not tiled */ - { "firefox_EXAMPLE", NULL, 1 << 8, 0, 0, 0, -1 }, /* Start on ONLY tag "9" */ - { "zoom", NULL, 0, 1, 0, 0, -1 }, - { "teams", NULL, 0, 1, 0, 0, -1 }, - { "wezterm", NULL, 0, 0, 1, 1, -1 }, /* make wezterm swallow clients that are not wezterm */ - { "foot", NULL, 0, 0, 1, 1, -1 }, /* make foot swallow clients that are not foot */ - { "thesaurus-syn", NULL, 0, 1, 1, 1, -1 }, /* make foot swallow clients that are not foot */ - { NULL, "wev", 0, 0, 0, 1, -1 }, /* xev */ - { NULL, "Event Tester", 0, 0, 0, 1, -1 }, /* xev */ + { "Gimp_EXAMPLE", NULL, 0, 1, 0, 0, -1 }, /* Start on currently visible tags floating, not tiled */ + { "firefox_EXAMPLE", NULL, 1 << 8, 0, 0, 0, -1 }, /* Start on ONLY tag "9" */ + { "zoom", NULL, 0, 1, 0, 0, -1 }, + { "teams", NULL, 0, 1, 0, 0, -1 }, + { "wezterm", NULL, 0, 0, 1, 1, -1 }, /* make wezterm swallow clients that are not wezterm */ + { "foot", NULL, 0, 0, 1, 1, -1 }, /* make foot swallow clients that are not foot */ + { "thesaurus-syn", NULL, 0, 1, 1, 1, -1 }, + { "xdg-desktop-portal-gtk", "Open File", 0, 1, 0, 1, -1 }, + { "org.freedesktop.impl.portal.desktop.kde", "Open File", 0, 1, 0, 1, -1 }, + { NULL, "wev", 0, 0, 0, 1, -1 }, + { NULL, "Event Tester", 0, 0, 0, 1, -1 }, /* xev */ }; /* layout(s) */ @@ -227,15 +230,20 @@ static const Key keys[] = { { MODKEY, XKB_KEY_Return, spawn, {.v = termcmd} }, // { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_B, togglebar, {0} }, - { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_J, focusstack, {.i = +1} }, - { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_K, focusstack, {.i = -1} }, - { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_j, relativeswap, {.i = +1} }, - { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_k, relativeswap, {.i = -1} }, + { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_j, focusstack, {.i = +1} }, + { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_k, focusstack, {.i = -1} }, + // { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_j, relativeswap, {.i = +1} }, + // { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_k, relativeswap, {.i = -1} }, { MODKEY, XKB_KEY_h, focusdir, {.ui = 0} }, { MODKEY, XKB_KEY_l, focusdir, {.ui = 1} }, { MODKEY, XKB_KEY_k, focusdir, {.ui = 2} }, { MODKEY, XKB_KEY_j, focusdir, {.ui = 3} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_H, swapdir, {.ui = 0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_L, swapdir, {.ui = 1} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_K, swapdir, {.ui = 2} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_J, swapdir, {.ui = 3} }, + { MODKEY, XKB_KEY_i, incnmaster, {.i = +1} }, { MODKEY, XKB_KEY_d, incnmaster, {.i = -1} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_H, setmfact, {.f = -0.05f} }, @@ -267,7 +275,7 @@ static const Key keys[] = { TAGKEYS( XKB_KEY_8, XKB_KEY_asterisk, 7), TAGKEYS( XKB_KEY_9, XKB_KEY_parenleft, 8), TAGKEYS( XKB_KEY_0, XKB_KEY_parenright, 9), - { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_R, quit, {0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_bar, quit, {0} }, // { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_R, spawn, KILL_DWL }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_E, spawn, SHCMD("killall dbus-run-session") }, @@ -299,9 +307,11 @@ static const Key keys[] = { { 0, XKB_KEY_XF86MonBrightnessDown, spawn, {.v = decreasebrightnesscmd } }, // screenshot - { MODKEY, XKB_KEY_Print, spawn, SCREENSHOTDIR_CMD }, - { MODKEY, XKB_KEY_o, spawn, SCREENSHOTDIR_CMD }, - { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_O, spawn, SCREENSHOTCLIPBOARD_CMD }, + { MODKEY, XKB_KEY_Print, regions, SCREENSHOTDIR_CMD }, + { MODKEY, XKB_KEY_o, regions, SCREENSHOTDIR_CMD }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_O, regions, SCREENSHOTCLIPBOARD_CMD }, + // { MODKEY, XKB_KEY_r, regions, SCREENSHOTDIR_CMD }, + // { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_R, regions, SCREENSHOTCLIPBOARD_CMD }, // Apps { MODKEY, XKB_KEY_m, spawn, TERM("neomutt") }, diff --git a/dwl.c b/dwl.c index a7af796..876f15e 100644 --- a/dwl.c +++ b/dwl.c @@ -281,6 +281,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); @@ -351,6 +356,7 @@ static void focusto(const Arg *arg); 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 gpureset(struct wl_listener *listener, void *data); @@ -436,6 +442,7 @@ static void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, LayerSurface **pl, double *nx, double *ny); static void wl_list_swap(struct wl_list *a, struct wl_list *b); static void zoom(const Arg *arg); +static void regions(const Arg *arg); static pid_t getparentprocess(pid_t p); static int isdescprocess(pid_t p, pid_t c); static Client *termforwin(Client *w); @@ -2057,48 +2064,205 @@ focusstack(const Arg *arg) focusclient(c, 1); } -void focusdir(const Arg *arg) +// void focusdir(const Arg *arg) +// { +// /* Focus the left, right, up, down client relative to the current focused client on selmon */ +// Client *c, *sel = focustop(selmon); +// if (!sel || sel->isfullscreen) +// return; +// +// int dist=INT_MAX; +// Client *newsel = NULL; +// int newdist=INT_MAX; +// wl_list_for_each(c, &clients, link) { +// if (!VISIBLEON(c, selmon)) +// continue; /* skip non visible windows */ +// +// if (arg->ui == 0 && sel->geom.x <= c->geom.x) { +// /* Client isn't on our left */ +// continue; +// } +// if (arg->ui == 1 && sel->geom.x >= c->geom.x) { +// /* Client isn't on our right */ +// continue; +// } +// if (arg->ui == 2 && sel->geom.y <= c->geom.y) { +// /* Client isn't above us */ +// continue; +// } +// if (arg->ui == 3 && sel->geom.y >= c->geom.y) { +// /* Client isn't below us */ +// continue; +// } +// +// dist=abs(sel->geom.x-c->geom.x)+abs(sel->geom.y-c->geom.y); +// if (dist < newdist){ +// newdist = dist; +// newsel=c; +// } +// } +// if (newsel != NULL){ +// focusclient(newsel, 1); +// } +// } + + +Vector +position_of_box(const struct wlr_box *box) { - /* Focus the left, right, up, down client relative to the current focused client on selmon */ - Client *c, *sel = focustop(selmon); - if (!sel || sel->isfullscreen) - return; - - int dist=INT_MAX; - Client *newsel = NULL; - int newdist=INT_MAX; - wl_list_for_each(c, &clients, link) { - if (!VISIBLEON(c, selmon)) - continue; /* skip non visible windows */ - - if (arg->ui == 0 && sel->geom.x <= c->geom.x) { - /* Client isn't on our left */ - continue; - } - if (arg->ui == 1 && sel->geom.x >= c->geom.x) { - /* Client isn't on our right */ - continue; - } - if (arg->ui == 2 && sel->geom.y <= c->geom.y) { - /* Client isn't above us */ - continue; - } - if (arg->ui == 3 && sel->geom.y >= c->geom.y) { - /* Client isn't below us */ - continue; - } - - dist=abs(sel->geom.x-c->geom.x)+abs(sel->geom.y-c->geom.y); - if (dist < newdist){ - newdist = dist; - newsel=c; - } - } - if (newsel != NULL){ - focusclient(newsel, 1); - } + 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 @@ -4042,28 +4206,28 @@ xytomon(double x, double y) return o ? o->data : NULL; } -void -wl_list_swap(struct wl_list *a, struct wl_list *b) -{ - struct wl_list *prev_a = a->prev; - struct wl_list *prev_b = b->prev; - - if (prev_b == a) { - wl_list_remove(a); - wl_list_insert(b, a); - return; - } - if (prev_a == b) { - wl_list_remove(b); - wl_list_insert(a, b); - return; - } - wl_list_remove(a); - wl_list_insert(prev_b, a); - - wl_list_remove(b); - wl_list_insert(prev_a, b); -} +// void +// wl_list_swap(struct wl_list *a, struct wl_list *b) +// { +// struct wl_list *prev_a = a->prev; +// struct wl_list *prev_b = b->prev; +// +// if (prev_b == a) { +// wl_list_remove(a); +// wl_list_insert(b, a); +// return; +// } +// if (prev_a == b) { +// wl_list_remove(b); +// wl_list_insert(a, b); +// return; +// } +// wl_list_remove(a); +// wl_list_insert(prev_b, a); +// +// wl_list_remove(b); +// wl_list_insert(prev_a, b); +// } void xytonode(double x, double y, struct wlr_surface **psurface, @@ -4177,6 +4341,33 @@ fdestroynotify(struct wl_listener *listener, void *data) wl_list_remove(&c->fdestroy.link); } +void +regions(const Arg *arg) +{ + int pipefd[2]; + Client *c; + Monitor *m; + + if (pipe(pipefd) == -1) + return; + if (fork() == 0) { + close(pipefd[1]); + dup2(pipefd[0], STDIN_FILENO); + close(pipefd[0]); + setsid(); + execvp(((char **)arg->v)[0], (char **)arg->v); + die("dwl: execvp %s failed:", ((char **)arg->v)[0]); + } + + close(pipefd[0]); + wl_list_for_each(m, &mons, link) + wl_list_for_each(c, &clients, link) + if (VISIBLEON(c, m)) + dprintf(pipefd[1], "%d,%d %dx%d\n", + c->geom.x, c->geom.y, c->geom.width, c->geom.height); + close(pipefd[1]); +} + #ifdef XWAYLAND void activatex11(struct wl_listener *listener, void *data)