summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZachIR <zachir@librem.one>2022-08-31 17:51:22 -0500
committerZachIR <zachir@librem.one>2022-08-31 17:51:22 -0500
commite45f978faab039be7bfab3865e1e2a5f0794f4d1 (patch)
treeb5d5521c752dd65ca5c5eb2555e9da377b5894de
parent55ee442c3cf8833f93626ab1a9a59c9e3f758778 (diff)
patched files
-rw-r--r--config.def.h48
-rw-r--r--config.mk6
-rw-r--r--dwl.c249
3 files changed, 281 insertions, 22 deletions
diff --git a/config.def.h b/config.def.h
index 29c6dbf..639f92c 100644
--- a/config.def.h
+++ b/config.def.h
@@ -2,21 +2,35 @@
static const int sloppyfocus = 1; /* focus follows mouse */
static const unsigned int borderpx = 1; /* border pixel of windows */
static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
+static const int smartborders = 1;
static const float rootcolor[] = {0.3, 0.3, 0.3, 1.0};
static const float bordercolor[] = {0.5, 0.5, 0.5, 1.0};
static const float focuscolor[] = {1.0, 0.0, 0.0, 1.0};
/* To conform the xdg-protocol, set the alpha to zero to restore the old behavior */
static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0};
+/* cursor warping */
+static const bool cursor_warp = true;
+
/* tagging */
static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
static const Rule rules[] = {
- /* app_id title tags mask isfloating monitor */
+ /* app_id title tags mask isfloating isterm noswallow monitor scratchkey */
/* examples:
- { "Gimp", NULL, 0, 1, -1 },
++ { "Gimp", NULL, 0, 1, 0, 1, -1, 0 },
+ { "firefox", NULL, 1 << 8, 0, 0, 1, -1, 0 },
*/
- { "firefox", NULL, 1 << 8, 0, -1 },
+ { NULL, "sphtop", 0, 1, 0, 1, -1, 'z' },
+ { NULL, "spterm", 0, 1, 0, 1, -1, 'x' },
+ { NULL, "sppmxr", 0, 1, 0, 1, -1, 'c' },
+ { NULL, "spblue", 0, 1, 0, 1, -1, 'v' },
+ { NULL, "spncmp", 0, 1, 0, 1, -1, 'b' },
+ { NULL, "spmutt", 0, 1, 0, 1, -1, 'a' },
+ { NULL, "spprof", 0, 1, 0, 1, -1, 's' },
+ { NULL, "spircc", 0, 1, 0, 1, -1, 'd' },
+ { NULL, "sptodo", 0, 1, 0, 1, -1, 'f' },
+ { NULL, "sptrem", 0, 1, 0, 1, -1, 'g' },
};
/* layout(s) */
@@ -86,6 +100,12 @@ LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE
static const enum libinput_config_accel_profile accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE;
static const double accel_speed = 0.0;
+/* Autostart */
+static const char *const autostart[] = {
+ "sh", "-c", "swaybg --image /xap/local/background", NULL,
+ NULL /* terminate */
+};
+
/* If you want to use the windows key change this to WLR_MODIFIER_LOGO */
#define MODKEY WLR_MODIFIER_ALT
#define TAGKEYS(KEY,SKEY,TAG) \
@@ -101,11 +121,33 @@ static const double accel_speed = 0.0;
static const char *termcmd[] = { "alacritty", NULL };
static const char *menucmd[] = { "bemenu-run", NULL };
+/* named scratchpads - First arg only serves to match against key in rules*/
+static const char *scratchpadcmd0[] = { "z", "alacritty", "-t", "sphtop", "htop", NULL };
+static const char *scratchpadcmd1[] = { "x", "alacritty", "-t", "spterm", "zsh", NULL };
+static const char *scratchpadcmd2[] = { "c", "alacritty", "-t", "sppmxr", "pulsemixer", NULL };
+static const char *scratchpadcmd3[] = { "v", "alacritty", "-t", "spblue", "bluetoothctl", NULL };
+static const char *scratchpadcmd4[] = { "b", "alacritty", "-t", "spncmp", "ncmpcpp", NULL };
+static const char *scratchpadcmd5[] = { "a", "alacritty", "-t", "spmutt", "neomutt", NULL };
+static const char *scratchpadcmd6[] = { "s", "alacritty", "-t", "spprof", "profanity", NULL };
+static const char *scratchpadcmd7[] = { "d", "alacritty", "-t", "spircc", "irssi", NULL };
+static const char *scratchpadcmd8[] = { "f", "alacritty", "-t", "sptodo", "todo", NULL };
+static const char *scratchpadcmd9[] = { "g", "alacritty", "-t", "sptrem", "tremc", NULL };
+
static const Key keys[] = {
/* Note that Shift changes certain key codes: c -> C, 2 -> at, etc. */
/* modifier key function argument */
{ MODKEY, XKB_KEY_p, spawn, {.v = menucmd} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} },
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_z, togglescratch, {.v = scratchpadcmd0 } },
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_x, togglescratch, {.v = scratchpadcmd1 } },
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_c, togglescratch, {.v = scratchpadcmd2 } },
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_v, togglescratch, {.v = scratchpadcmd3 } },
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_b, togglescratch, {.v = scratchpadcmd4 } },
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_a, togglescratch, {.v = scratchpadcmd5 } },
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_s, togglescratch, {.v = scratchpadcmd6 } },
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_d, togglescratch, {.v = scratchpadcmd7 } },
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_f, togglescratch, {.v = scratchpadcmd8 } },
+ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_g, togglescratch, {.v = scratchpadcmd9 } },
{ MODKEY, XKB_KEY_j, focusstack, {.i = +1} },
{ MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
{ MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },
diff --git a/config.mk b/config.mk
index 4638d5f..b6a5015 100644
--- a/config.mk
+++ b/config.mk
@@ -6,10 +6,10 @@ PREFIX = /usr/local
MANDIR = $(PREFIX)/share/man
# Compile flags that can be used
-#CFLAGS = -pedantic -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare -Wno-unused-function -Wno-unused-variable -Wno-unused-result -Wdeclaration-after-statement
+CFLAGS = -pedantic -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare -Wno-unused-function -Wno-unused-variable -Wno-unused-result -Wdeclaration-after-statement
XWAYLAND =
XLIBS =
# Uncomment to build XWayland support
-#XWAYLAND = -DXWAYLAND
-#XLIBS = xcb
+XWAYLAND = -DXWAYLAND
+XLIBS = xcb
diff --git a/dwl.c b/dwl.c
index 8556cba..227e1c4 100644
--- a/dwl.c
+++ b/dwl.c
@@ -90,7 +90,8 @@ typedef struct {
} Button;
typedef struct Monitor Monitor;
-typedef struct {
+typedef struct Client Client;
+struct Client{
/* Must keep these three elements in this order */
unsigned int type; /* XDGShell or X11* */
struct wlr_box geom; /* layout-relative, includes border */
@@ -119,9 +120,12 @@ typedef struct {
#endif
unsigned int bw;
unsigned int tags;
- int isfloating, isurgent, isfullscreen;
+ int isfloating, isurgent, isfullscreen, isterm, noswallow;
uint32_t resize; /* configure serial of a pending resize */
-} Client;
+ pid_t pid;
+ Client *swallowing, *swallowedby;
+ char scratchkey;
+};
typedef struct {
uint32_t singular_anchor;
@@ -200,7 +204,10 @@ typedef struct {
const char *title;
unsigned int tags;
int isfloating;
+ int isterm;
+ int noswallow;
int monitor;
+ const char scratchkey;
} Rule;
/* function declarations */
@@ -213,6 +220,7 @@ static void arrange(Monitor *m);
static void arrangelayer(Monitor *m, struct wl_list *list,
struct wlr_box *usable_area, int exclusive);
static void arrangelayers(Monitor *m);
+static void autostartexec(void);
static void axisnotify(struct wl_listener *listener, void *data);
static void buttonpress(struct wl_listener *listener, void *data);
static void chvt(const Arg *arg);
@@ -263,7 +271,7 @@ static void quit(const Arg *arg);
static void quitsignal(int signo);
static void rendermon(struct wl_listener *listener, void *data);
static void requeststartdrag(struct wl_listener *listener, void *data);
-static void resize(Client *c, struct wlr_box geo, int interact);
+static void resize(Client *c, struct wlr_box geo, int interact, int draw_borders);
static void run(char *startup_cmd);
static Client *selclient(void);
static void setcursor(struct wl_listener *listener, void *data);
@@ -277,12 +285,14 @@ static void setsel(struct wl_listener *listener, void *data);
static void setup(void);
static void sigchld(int unused);
static void spawn(const Arg *arg);
+static void spawnscratch(const Arg *arg);
static void startdrag(struct wl_listener *listener, void *data);
static void tag(const Arg *arg);
static void tagmon(const Arg *arg);
static void tile(Monitor *m);
static void togglefloating(const Arg *arg);
static void togglefullscreen(const Arg *arg);
+static void togglescratch(const Arg *arg);
static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg);
static void unmaplayersurfacenotify(struct wl_listener *listener, void *data);
@@ -292,10 +302,15 @@ static void updatetitle(struct wl_listener *listener, void *data);
static void urgent(struct wl_listener *listener, void *data);
static void view(const Arg *arg);
static void virtualkeyboard(struct wl_listener *listener, void *data);
+static void warpcursor(const Client *c);
static Monitor *xytomon(double x, double y);
static struct wlr_scene_node *xytonode(double x, double y, struct wlr_surface **psurface,
Client **pc, LayerSurface **pl, double *nx, double *ny);
static void zoom(const Arg *arg);
+static pid_t getparentprocess(pid_t p);
+static int isdescprocess(pid_t p, pid_t c);
+static Client *termforwin(Client *w);
+static void swallow(Client *c, Client *w);
/* variables */
static const char broken[] = "broken";
@@ -372,7 +387,9 @@ static Atom netatom[NetLast];
#endif
/* configuration, allows nested code to access above variables */
+#include "push.h"
#include "config.h"
+#include "push.c"
/* attempt to encapsulate suck into one file */
#include "client.h"
@@ -380,6 +397,9 @@ static Atom netatom[NetLast];
/* compile-time check if all tags fit into an unsigned int bit array. */
struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
+static pid_t *autostart_pids;
+static size_t autostart_len;
+
/* function implementations */
void
applybounds(Client *c, struct wlr_box *bbox)
@@ -407,6 +427,29 @@ applybounds(Client *c, struct wlr_box *bbox)
}
void
+autostartexec(void) {
+ const char *const *p;
+ size_t i = 0;
+
+ /* count entries */
+ for (p = autostart; *p; autostart_len++, p++)
+ while (*++p);
+
+ autostart_pids = calloc(autostart_len, sizeof(pid_t));
+ for (p = autostart; *p; i++, p++) {
+ if ((autostart_pids[i] = fork()) == 0) {
+ setsid();
+ execvp(*p, (char *const *)p);
+ fprintf(stderr, "dwl: execvp %s\n", *p);
+ perror(" failed");
+ _exit(EXIT_FAILURE);
+ }
+ /* skip arguments */
+ while (*++p);
+ }
+}
+
+void
applyexclusive(struct wlr_box *usable_area,
uint32_t anchor, int32_t exclusive,
int32_t margin_top, int32_t margin_right,
@@ -471,6 +514,7 @@ applyrules(Client *c)
Monitor *mon = selmon, *m;
c->isfloating = client_is_float_type(c);
+ c->scratchkey = 0;
if (!(appid = client_get_appid(c)))
appid = broken;
if (!(title = client_get_title(c)))
@@ -480,6 +524,9 @@ applyrules(Client *c)
if ((!r->title || strstr(title, r->title))
&& (!r->id || strstr(appid, r->id))) {
c->isfloating = r->isfloating;
+ c->scratchkey = r->scratchkey;
+ c->isterm = r->isterm;
+ c->noswallow = r->noswallow;
newtags |= r->tags;
i = 0;
wl_list_for_each(m, &mons, link)
@@ -487,6 +534,8 @@ applyrules(Client *c)
mon = m;
}
}
+ c->geom.x = (mon->w.width - c->geom.width) / 2 + mon->m.x;
+ c->geom.y = (mon->w.height - c->geom.height) / 2 + mon->m.y;
wlr_scene_node_reparent(c->scene, layers[c->isfloating ? LyrFloat : LyrTile]);
setmon(c, mon, newtags);
}
@@ -501,6 +550,9 @@ arrange(Monitor *m)
if (m->lt[m->sellt]->arrange)
m->lt[m->sellt]->arrange(m);
motionnotify(0);
+ c = selclient();
+ if (cursor_warp && c)
+ warpcursor(c);
}
void
@@ -771,7 +823,7 @@ closemon(Monitor *m)
wl_list_for_each(c, &clients, link) {
if (c->isfloating && c->geom.x > m->m.width)
resize(c, (struct wlr_box){.x = c->geom.x - m->w.width, .y = c->geom.y,
- .width = c->geom.width, .height = c->geom.height}, 0);
+ .width = c->geom.width, .height = c->geom.height}, 0, 1);
if (c->mon == m)
setmon(c, selmon, c->tags);
}
@@ -992,6 +1044,8 @@ createnotify(struct wl_listener *listener, void *data)
c->surface.xdg = xdg_surface;
c->bw = borderpx;
+ wl_client_get_credentials(c->surface.xdg->client->client, &c->pid, NULL, NULL);
+
LISTEN(&xdg_surface->events.map, &c->map, mapnotify);
LISTEN(&xdg_surface->events.unmap, &c->unmap, unmapnotify);
LISTEN(&xdg_surface->events.destroy, &c->destroy, destroynotify);
@@ -1131,6 +1185,10 @@ focusclient(Client *c, int lift)
if (exclusive_focus)
return;
+ /* Warp cursor to center of client if it is outside */
+ if (cursor_warp && c)
+ warpcursor(c);
+
/* Raise client in stacking order if requested */
if (c && lift)
wlr_scene_node_raise_to_top(c->scene);
@@ -1253,6 +1311,61 @@ fullscreennotify(struct wl_listener *listener, void *data)
setfullscreen(c, fullscreen);
}
+pid_t
+getparentprocess(pid_t p)
+{
+ unsigned int v = 0;
+
+ FILE *f;
+ char buf[256];
+ snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p);
+
+ if (!(f = fopen(buf, "r")))
+ return 0;
+
+ fscanf(f, "%*u %*s %*c %u", &v);
+ fclose(f);
+
+ return (pid_t)v;
+}
+
+int
+isdescprocess(pid_t p, pid_t c)
+{
+ while (p != c && c != 0)
+ c = getparentprocess(c);
+
+ return (int)c;
+}
+
+Client *
+termforwin(Client *w)
+{
+ Client *c;
+
+ if (!w->pid || w->isterm || w->noswallow)
+ return NULL;
+
+ wl_list_for_each(c, &clients, link)
+ if (c->isterm && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid))
+ return c;
+
+ return NULL;
+}
+
+void
+swallow(Client *c, Client *w) {
+ c->bw = w->bw;
+ c->isfloating = w->isfloating;
+ c->isurgent = w->isurgent;
+ c->isfullscreen = w->isfullscreen;
+ resize(c, w->geom, 0, 0);
+ wl_list_insert(&w->link, &c->link);
+ wl_list_insert(&w->flink, &c->flink);
+ wlr_scene_node_set_enabled(w->scene, 0);
+ wlr_scene_node_set_enabled(c->scene, 1);
+}
+
void
incnmaster(const Arg *arg)
{
@@ -1442,6 +1555,19 @@ mapnotify(struct wl_listener *listener, void *data)
setfullscreen(c, 1);
c->mon->un_map = 1;
+ if (!c->noswallow) {
+ Client *p = termforwin(c);
+ if (p) {
+ c->swallowedby = p;
+ p->swallowing = c;
+ wl_list_remove(&c->link);
+ wl_list_remove(&c->flink);
+ swallow(c,p);
+ wl_list_remove(&p->link);
+ wl_list_remove(&p->flink);
+ }
+ arrange(c->mon);
+ }
}
void
@@ -1452,7 +1578,7 @@ monocle(Monitor *m)
wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
continue;
- resize(c, m->w, 0);
+ resize(c, m->w, 0, !smartborders);
}
focusclient(focustop(m), 1);
}
@@ -1495,11 +1621,11 @@ motionnotify(uint32_t time)
if (cursor_mode == CurMove) {
/* Move the grabbed client to the new position. */
resize(grabc, (struct wlr_box){.x = cursor->x - grabcx, .y = cursor->y - grabcy,
- .width = grabc->geom.width, .height = grabc->geom.height}, 1);
+ .width = grabc->geom.width, .height = grabc->geom.height}, 1, 1);
return;
} else if (cursor_mode == CurResize) {
resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y,
- .width = cursor->x - grabc->geom.x, .height = cursor->y - grabc->geom.y}, 1);
+ .width = cursor->x - grabc->geom.x, .height = cursor->y - grabc->geom.y}, 1, 1);
return;
}
@@ -1717,6 +1843,16 @@ printstatus(void)
void
quit(const Arg *arg)
{
+ size_t i;
+
+ /* kill child processes */
+ for (i = 0; i < autostart_len; i++) {
+ if (0 < autostart_pids[i]) {
+ kill(autostart_pids[i], SIGTERM);
+ waitpid(autostart_pids[i], NULL, 0);
+ }
+ }
+
wl_display_terminate(dpy);
}
@@ -1772,10 +1908,11 @@ requeststartdrag(struct wl_listener *listener, void *data)
}
void
-resize(Client *c, struct wlr_box geo, int interact)
+resize(Client *c, struct wlr_box geo, int interact, int draw_borders)
{
struct wlr_box *bbox = interact ? &sgeom : &c->mon->w;
c->geom = geo;
+ c->bw = draw_borders ? borderpx : 0;
applybounds(c, bbox);
/* Update scene-graph, including borders */
@@ -1804,6 +1941,7 @@ run(char *startup_cmd)
setenv("WAYLAND_DISPLAY", socket, 1);
/* Now that the socket exists, run the startup command */
+ autostartexec();
if (startup_cmd) {
int piperw[2];
if (pipe(piperw) < 0)
@@ -1881,6 +2019,8 @@ setfloating(Client *c, int floating)
{
c->isfloating = floating;
wlr_scene_node_reparent(c->scene, layers[c->isfloating ? LyrFloat : LyrTile]);
+ if (c->isfloating && !c->bw)
+ resize(c, c->mon->m, 0, 1);
arrange(c->mon);
printstatus();
}
@@ -1894,7 +2034,7 @@ setfullscreen(Client *c, int fullscreen)
if (fullscreen) {
c->prev = c->geom;
- resize(c, c->mon->m, 0);
+ resize(c, c->mon->m, 0, 0);
/* The xdg-protocol specifies:
*
* If the fullscreened surface is not opaque, the compositor must make
@@ -1912,7 +2052,7 @@ setfullscreen(Client *c, int fullscreen)
} else {
/* restore previous size instead of arrange for floating windows since
* client positions are set by the user and cannot be recalculated */
- resize(c, c->prev, 0);
+ resize(c, c->prev, 0, 1);
if (c->fullscreen_bg) {
wlr_scene_node_destroy(&c->fullscreen_bg->node);
c->fullscreen_bg = NULL;
@@ -1929,6 +2069,12 @@ setlayout(const Arg *arg)
selmon->sellt ^= 1;
if (arg && arg->v)
selmon->lt[selmon->sellt] = (Layout *)arg->v;
+ if (!selmon->lt[selmon->sellt]->arrange) {
+ /* floating layout, draw borders around all clients */
+ Client *c;
+ wl_list_for_each(c, &clients, link)
+ resize(c, c->mon->m, 0, 1);
+ }
/* TODO change layout symbol? */
arrange(selmon);
printstatus();
@@ -1965,7 +2111,7 @@ setmon(Client *c, Monitor *m, unsigned int newtags)
}
if (m) {
/* Make sure window actually overlaps with the monitor */
- resize(c, c->geom, 0);
+ resize(c, c->geom, 0, 1);
wlr_surface_send_enter(client_surface(c), m->wlr_output);
c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */
arrange(m);
@@ -2179,11 +2325,24 @@ sigchld(int unused)
* setting our own disposition for SIGCHLD.
*/
pid_t pid;
+
if (signal(SIGCHLD, sigchld) == SIG_ERR)
die("can't install SIGCHLD handler:");
- while (0 < (pid = waitpid(-1, NULL, WNOHANG)))
+ while (0 < (pid = waitpid(-1, NULL, WNOHANG))) {
+ pid_t *p, *lim;
if (pid == child_pid)
child_pid = -1;
+ if (!(p = autostart_pids))
+ continue;
+ lim = &p[autostart_len];
+
+ for (; p < lim; p++) {
+ if (*p == pid) {
+ *p = -1;
+ break;
+ }
+ }
+ }
}
void
@@ -2197,6 +2356,16 @@ spawn(const Arg *arg)
}
}
+void spawnscratch(const Arg *arg)
+{
+ if (fork() == 0) {
+ dup2(STDERR_FILENO, STDOUT_FILENO);
+ setsid();
+ execvp(((char **)arg->v)[1], ((char **)arg->v)+1);
+ die("dwl: execvp %s failed:", ((char **)arg->v)[1]);
+ }
+}
+
void
startdrag(struct wl_listener *listener, void *data)
{
@@ -2234,7 +2403,7 @@ tagmon(const Arg *arg)
void
tile(Monitor *m)
{
- unsigned int i, n = 0, mw, my, ty;
+ unsigned int i, n = 0, mw, my, ty, draw_borders = 1;
Client *c;
wl_list_for_each(c, &clients, link)
@@ -2243,6 +2412,9 @@ tile(Monitor *m)
if (n == 0)
return;
+ if (n == smartborders)
+ draw_borders = 0;
+
if (n > m->nmaster)
mw = m->nmaster ? m->w.width * m->mfact : 0;
else
@@ -2253,11 +2425,11 @@ tile(Monitor *m)
continue;
if (i < m->nmaster) {
resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + my, .width = mw,
- .height = (m->w.height - my) / (MIN(n, m->nmaster) - i)}, 0);
+ .height = (m->w.height - my) / (MIN(n, m->nmaster) - i)}, 0, draw_borders);
my += c->geom.height;
} else {
resize(c, (struct wlr_box){.x = m->w.x + mw, .y = m->w.y + ty,
- .width = m->w.width - mw, .height = (m->w.height - ty) / (n - i)}, 0);
+ .width = m->w.width - mw, .height = (m->w.height - ty) / (n - i)}, 0, draw_borders);
ty += c->geom.height;
}
i++;
@@ -2282,6 +2454,29 @@ togglefullscreen(const Arg *arg)
}
void
+togglescratch(const Arg *arg)
+{
+ Client *c;
+ unsigned int found = 0;
+
+ /* search for first window that matches the scratchkey */
+ wl_list_for_each(c, &clients, link)
+ if (c->scratchkey == ((char**)arg->v)[0][0]) {
+ found = 1;
+ break;
+ }
+
+ if (found) {
+ c->tags = VISIBLEON(c, selmon) ? 0 : selmon->tagset[selmon->seltags];
+
+ focusclient(c->tags == 0 ? focustop(selmon) : c, 1);
+ arrange(selmon);
+ } else{
+ spawnscratch(arg);
+ }
+}
+
+void
toggletag(const Arg *arg)
{
unsigned int newtags;
@@ -2334,6 +2529,16 @@ unmapnotify(struct wl_listener *listener, void *data)
cursor_mode = CurNormal;
grabc = NULL;
}
+ if (c->swallowing) {
+ c->swallowing->swallowedby = NULL;
+ c->swallowing = NULL;
+ }
+
+ if (c->swallowedby) {
+ swallow(c->swallowedby, c);
+ c->swallowedby->swallowing = NULL;
+ c->swallowedby = NULL;
+ }
if (c->mon)
c->mon->un_map = 1;
@@ -2435,6 +2640,18 @@ virtualkeyboard(struct wl_listener *listener, void *data)
createkeyboard(device);
}
+void
+warpcursor(const Client *c) {
+ if (cursor->x < c->geom.x ||
+ cursor->x > c->geom.x + c->geom.width ||
+ cursor->y < c->geom.y ||
+ cursor->y > c->geom.y + c->geom.height)
+ wlr_cursor_warp_closest(cursor,
+ NULL,
+ c->geom.x + c->geom.width / 2.0,
+ c->geom.y + c->geom.height / 2.0);
+}
+
Monitor *
xytomon(double x, double y)
{