diff options
Diffstat (limited to 'dwl.c')
| -rw-r--r-- | dwl.c | 191 |
1 files changed, 167 insertions, 24 deletions
@@ -104,6 +104,7 @@ typedef struct { const Arg arg; } Button; +typedef struct Pertag Pertag; typedef struct Monitor Monitor; typedef struct { /* Must keep this field first */ @@ -201,6 +202,8 @@ struct Monitor { struct wlr_box w; /* window area, layout-relative */ struct wl_list layers[4]; /* LayerSurface.link */ const Layout *lt[2]; + int gaps; + Pertag *pertag; unsigned int seltags; unsigned int sellt; uint32_t tagset[2]; @@ -250,6 +253,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); @@ -340,6 +344,7 @@ 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 togglegaps(const Arg *arg); static void toggletag(const Arg *arg); static void toggleview(const Arg *arg); static void unlocksession(struct wl_listener *listener, void *data); @@ -430,6 +435,17 @@ static xcb_atom_t netatom[NetLast]; /* attempt to encapsulate suck into one file */ #include "client.h" +static pid_t *autostart_pids; +static size_t autostart_len; + +struct Pertag { + unsigned int curtag, prevtag; /* current and previous tag */ + int nmasters[TAGCOUNT + 1]; /* number of windows in master area */ + float mfacts[TAGCOUNT + 1]; /* mfacts per tag */ + unsigned int sellts[TAGCOUNT + 1]; /* selected layouts */ + const Layout *ltidxs[TAGCOUNT + 1][2]; /* matrix of tags and layouts indexes */ +}; + /* function implementations */ void applybounds(Client *c, struct wlr_box *bbox) @@ -474,6 +490,10 @@ applyrules(Client *c) } } } + if (mon) { + 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; + } setmon(c, mon, newtags); } @@ -575,6 +595,27 @@ arrangelayers(Monitor *m) } 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); + die("dwl: execvp %s:", *p); + } + /* skip arguments */ + while (*++p); + } +} + +void axisnotify(struct wl_listener *listener, void *data) { /* This event is forwarded by the cursor when a pointer emits an axis event, @@ -670,11 +711,21 @@ checkidleinhibitor(struct wlr_surface *exclude) void cleanup(void) { + size_t i; #ifdef XWAYLAND wlr_xwayland_destroy(xwayland); xwayland = NULL; #endif wl_display_destroy_clients(dpy); + + /* 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); + } + } + if (child_pid > 0) { kill(-child_pid, SIGTERM); waitpid(child_pid, NULL, 0); @@ -714,6 +765,7 @@ cleanupmon(struct wl_listener *listener, void *data) wlr_output_layout_remove(output_layout, m->wlr_output); wlr_scene_output_destroy(m->scene_output); + free(m->pertag); closemon(m); wlr_scene_node_destroy(&m->fullscreen_bg->node); free(m); @@ -987,6 +1039,8 @@ createmon(struct wl_listener *listener, void *data) wlr_output_state_init(&state); /* Initialize monitor state using configured rules */ + m->gaps = gaps; + m->tagset[0] = m->tagset[1] = 1; for (r = monrules; r < END(monrules); r++) { if (!r->name || strstr(wlr_output->name, r->name)) { @@ -1021,6 +1075,18 @@ createmon(struct wl_listener *listener, void *data) wl_list_insert(&mons, &m->link); printstatus(); + m->pertag = calloc(1, sizeof(Pertag)); + m->pertag->curtag = m->pertag->prevtag = 1; + + for (i = 0; i <= TAGCOUNT; i++) { + m->pertag->nmasters[i] = m->nmaster; + m->pertag->mfacts[i] = m->mfact; + + m->pertag->ltidxs[i][0] = m->lt[0]; + m->pertag->ltidxs[i][1] = m->lt[1]; + m->pertag->sellts[i] = m->sellt; + } + /* The xdg-protocol specifies: * * If the fullscreened surface is not opaque, the compositor must make @@ -1079,11 +1145,10 @@ createpointer(struct wlr_pointer *pointer) libinput_device_config_tap_set_drag_enabled(device, tap_and_drag); libinput_device_config_tap_set_drag_lock_enabled(device, drag_lock); libinput_device_config_tap_set_button_map(device, button_map); + if (libinput_device_config_scroll_has_natural_scroll(device)) + libinput_device_config_scroll_set_natural_scroll_enabled(device, natural_scrolling); } - if (libinput_device_config_scroll_has_natural_scroll(device)) - libinput_device_config_scroll_set_natural_scroll_enabled(device, natural_scrolling); - if (libinput_device_config_dwt_is_available(device)) libinput_device_config_dwt_set_enabled(device, disable_while_typing); @@ -1493,18 +1558,31 @@ void handlesig(int signo) { if (signo == SIGCHLD) { -#ifdef XWAYLAND siginfo_t in; /* wlroots expects to reap the XWayland process itself, so we * use WNOWAIT to keep the child waitable until we know it's not * XWayland. */ while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid - && (!xwayland || in.si_pid != xwayland->server->pid)) - waitpid(in.si_pid, NULL, 0); -#else - while (waitpid(-1, NULL, WNOHANG) > 0); +#ifdef XWAYLAND + && (!xwayland || in.si_pid != xwayland->server->pid) #endif + ) { + pid_t *p, *lim; + waitpid(in.si_pid, NULL, 0); + if (in.si_pid == child_pid) + child_pid = -1; + if (!(p = autostart_pids)) + continue; + lim = &p[autostart_len]; + + for (; p < lim; p++) { + if (*p == in.si_pid) { + *p = -1; + break; + } + } + } } else if (signo == SIGINT || signo == SIGTERM) { quit(NULL); } @@ -1515,7 +1593,7 @@ incnmaster(const Arg *arg) { if (!arg || !selmon) return; - selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0); arrange(selmon); } @@ -1722,7 +1800,11 @@ mapnotify(struct wl_listener *listener, void *data) c->geom.height += 2 * c->bw; /* Insert this client into client lists. */ - wl_list_insert(&clients, &c->link); + if (clients.prev) + // tile at the bottom + wl_list_insert(clients.prev, &c->link); + else + wl_list_insert(&clients, &c->link); wl_list_insert(&fstack, &c->flink); /* Set initial monitor, tags, floating status, and focus: @@ -1731,6 +1813,10 @@ mapnotify(struct wl_listener *listener, void *data) * try to apply rules for them */ if ((p = client_get_parent(c))) { c->isfloating = 1; + if (p->mon) { + c->geom.x = (p->mon->w.width - c->geom.width) / 2 + p->mon->m.x; + c->geom.y = (p->mon->w.height - c->geom.height) / 2 + p->mon->m.y; + } setmon(c, p->mon, p->tags); } else { applyrules(c); @@ -2194,6 +2280,7 @@ run(char *startup_cmd) die("startup: backend_start"); /* Now that the socket exists and the backend is started, run the startup command */ + autostartexec(); if (startup_cmd) { int piperw[2]; if (pipe(piperw) < 0) @@ -2316,9 +2403,9 @@ setlayout(const Arg *arg) if (!selmon) return; if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) - selmon->sellt ^= 1; + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; if (arg && arg->v) - selmon->lt[selmon->sellt] = (Layout *)arg->v; + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, LENGTH(selmon->ltsymbol)); arrange(selmon); printstatus(); @@ -2335,7 +2422,7 @@ setmfact(const Arg *arg) f = arg->f < 1.0f ? arg->f + selmon->mfact : arg->f - 1.0f; if (f < 0.1 || f > 0.9) return; - selmon->mfact = f; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; arrange(selmon); } @@ -2538,8 +2625,8 @@ setup(void) * Xcursor themes to source cursor images from and makes sure that cursor * images are available at all scale factors on the screen (necessary for * HiDPI support). Scaled cursors will be loaded with each output. */ - cursor_mgr = wlr_xcursor_manager_create(NULL, 24); - setenv("XCURSOR_SIZE", "24", 1); + cursor_mgr = wlr_xcursor_manager_create(NULL, 16); + setenv("XCURSOR_SIZE", "16", 1); /* * wlr_cursor *only* displays an image on screen. It does not move around @@ -2652,7 +2739,7 @@ tagmon(const Arg *arg) void tile(Monitor *m) { - unsigned int mw, my, ty; + unsigned int h, r, e = m->gaps, mw, my, ty; int i, n = 0; Client *c; @@ -2661,23 +2748,30 @@ tile(Monitor *m) n++; if (n == 0) return; + if (smartgaps == n) + e = 0; if (n > m->nmaster) - mw = m->nmaster ? (int)roundf(m->w.width * m->mfact) : 0; + mw = m->nmaster ? (int)roundf((m->w.width + gappx*e) * m->mfact) : 0; else mw = m->w.width; - i = my = ty = 0; + i = 0; + my = ty = gappx*e; wl_list_for_each(c, &clients, link) { if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) 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); - my += c->geom.height; + r = MIN(n, m->nmaster) - i; + h = (m->w.height - my - gappx*e - gappx*e * (r - 1)) / r; + resize(c, (struct wlr_box){.x = m->w.x + gappx*e, .y = m->w.y + my, + .width = mw - 2*gappx*e, .height = h}, 0); + my += c->geom.height + gappx*e; } else { + r = n - i; + h = (m->w.height - ty - gappx*e - gappx*e * (r - 1)) / r; 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); - ty += c->geom.height; + .width = m->w.width - mw - gappx*e, .height = h}, 0); + ty += c->geom.height + gappx*e; } i++; } @@ -2701,6 +2795,13 @@ togglefullscreen(const Arg *arg) } void +togglegaps(const Arg *arg) +{ + selmon->gaps = !selmon->gaps; + arrange(selmon); +} + +void toggletag(const Arg *arg) { uint32_t newtags; @@ -2718,9 +2819,29 @@ void toggleview(const Arg *arg) { uint32_t newtagset; + size_t i; if (!(newtagset = selmon ? selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK) : 0)) return; + if (newtagset == (uint32_t)~0) { + selmon->pertag->prevtag = selmon->pertag->curtag; + selmon->pertag->curtag = 0; + } + + /* test if the user did not select the same tag */ + if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) { + selmon->pertag->prevtag = selmon->pertag->curtag; + for (i = 0; !(newtagset & 1 << i); i++) ; + selmon->pertag->curtag = i + 1; + } + + /* apply settings for this view */ + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; + selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; + selmon->tagset[selmon->seltags] = newtagset; focusclient(focustop(selmon), 1); arrange(selmon); @@ -2909,11 +3030,33 @@ urgent(struct wl_listener *listener, void *data) void view(const Arg *arg) { + size_t i, tmptag; + if (!selmon || (arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) return; selmon->seltags ^= 1; /* toggle sel tagset */ - if (arg->ui & TAGMASK) + if (arg->ui & ~0) { selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; + selmon->pertag->prevtag = selmon->pertag->curtag; + + if (arg->ui == TAGMASK) + selmon->pertag->curtag = 0; + else { + for (i = 0; !(arg->ui & 1 << i); i++) ; + selmon->pertag->curtag = i + 1; + } + } else { + tmptag = selmon->pertag->prevtag; + selmon->pertag->prevtag = selmon->pertag->curtag; + selmon->pertag->curtag = tmptag; + } + + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; + selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; + focusclient(focustop(selmon), 1); arrange(selmon); printstatus(); |
