13 Commits

9 changed files with 785 additions and 642 deletions

View File

@ -5,17 +5,13 @@ static const unsigned int borderpx = 1; /* border pixel of windows */
static const unsigned int snap = 32; /* snap pixel */
static const int showbar = 1; /* 0 means no bar */
static const int topbar = 1; /* 0 means bottom bar */
static const int usealtbar = 1; /* 1 means use non-dwm status bar */
static const char *altbarclass = "Polybar"; /* Alternate bar class name */
static const char *alttrayname = "tray"; /* Polybar tray instance name */
static const char *altbarcmd = "$HOME/bar.sh"; /* Alternate bar launch command */
static const char *fonts[] = { "monospace:size=10" };
static const char dmenufont[] = "monospace:size=10";
static const char col_gray1[] = "#222222";
static const char col_gray2[] = "#444444";
static const char col_gray3[] = "#bbbbbb";
static const char col_gray4[] = "#eeeeee";
static const char col_cyan[] = "#005577";
static const char col_cyan[] = "#606060";
static const char *colors[][3] = {
/* fg bg border */
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
@ -49,7 +45,7 @@ static const Layout layouts[] = {
};
/* key definitions */
#define MODKEY Mod1Mask
#define MODKEY Mod4Mask
#define TAGKEYS(KEY,TAG) \
{ MODKEY, KEY, view, {.ui = 1 << TAG} }, \
{ MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
@ -62,12 +58,17 @@ static const Layout layouts[] = {
/* commands */
static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
static const char *termcmd[] = { "st", NULL };
static const char *termcmd[] = { "alacritty", NULL };
static const char *scrotcmd[] = { "scrot", "-s", NULL };
static const char *lockcmd[] = { "xsecurelock", NULL };
#include "movestack.c"
static Key keys[] = {
/* modifier key function argument */
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
{ MODKEY|ShiftMask, XK_Escape, spawn, {.v = scrotcmd } },
{ MODKEY, XK_Escape, spawn, {.v = lockcmd } },
{ MODKEY, XK_b, togglebar, {0} },
{ MODKEY, XK_j, focusstack, {.i = +1 } },
{ MODKEY, XK_k, focusstack, {.i = -1 } },
@ -75,6 +76,8 @@ static Key keys[] = {
{ MODKEY, XK_d, incnmaster, {.i = -1 } },
{ MODKEY, XK_h, setmfact, {.f = -0.05} },
{ MODKEY, XK_l, setmfact, {.f = +0.05} },
{ MODKEY|ShiftMask, XK_j, movestack, {.i = +1 } },
{ MODKEY|ShiftMask, XK_k, movestack, {.i = -1 } },
{ MODKEY, XK_Return, zoom, {0} },
{ MODKEY, XK_Tab, view, {0} },
{ MODKEY|ShiftMask, XK_c, killclient, {0} },

View File

@ -1,445 +0,0 @@
From 9b5719969ce85c3ecc0238d49c0255c5c2cc79f0 Mon Sep 17 00:00:00 2001
From: mihirlad55 <mihirlad55@gmail.com>
Date: Mon, 10 Aug 2020 01:39:28 +0000
Subject: [PATCH] Add support for managing external status bars
This patch allows dwm to manage other status bars such as
polybar/lemonbar without them needing to set override-redirect. For
all intents and purposes, DWM treats this bar as if it were its own
and as a result helps the status bar and DWM live in harmony.
This has a few advantages
* The bar does not block fullscreen windows
* DWM makes room for the status bar, so windows do not overlap the bar
* The bar can be hidden/killed and DWM will not keep an unsightly gap
where the bar was
* DWM receives EnterNotify events when your cursor enters the bar
To use another status bar, set usealtbar to 1 in your config.h and set
altbarclass to the class name (can be found using xprop) to the class
name of your status bar. Also make sure that if your status bar will
be displayed on top, topbar is set to 1 in your config, and if it will
be displayed on bottom, topbar is set to 0. This patch does not
support bars that are not docked at the top or at the bottom of your
monitor.
This verison of the patch fixes handling of polybar's tray.
The patch is developed at https://github.com/mihirlad55/dwm-anybar
---
config.def.h | 4 ++
dwm.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++----
2 files changed, 181 insertions(+), 15 deletions(-)
diff --git a/config.def.h b/config.def.h
index 1c0b587..f45211b 100644
--- a/config.def.h
+++ b/config.def.h
@@ -5,6 +5,10 @@ static const unsigned int borderpx = 1; /* border pixel of windows */
static const unsigned int snap = 32; /* snap pixel */
static const int showbar = 1; /* 0 means no bar */
static const int topbar = 1; /* 0 means bottom bar */
+static const int usealtbar = 1; /* 1 means use non-dwm status bar */
+static const char *altbarclass = "Polybar"; /* Alternate bar class name */
+static const char *alttrayname = "tray"; /* Polybar tray instance name */
+static const char *altbarcmd = "$HOME/bar.sh"; /* Alternate bar launch command */
static const char *fonts[] = { "monospace:size=10" };
static const char dmenufont[] = "monospace:size=10";
static const char col_gray1[] = "#222222";
diff --git a/dwm.c b/dwm.c
index 9fd0286..c1d8ce0 100644
--- a/dwm.c
+++ b/dwm.c
@@ -47,8 +47,8 @@
/* macros */
#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
-#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
- * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
+#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->mx+(m)->mw) - MAX((x),(m)->mx)) \
+ * MAX(0, MIN((y)+(h),(m)->my+(m)->mh) - MAX((y),(m)->my)))
#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
#define LENGTH(X) (sizeof X / sizeof X[0])
#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
@@ -116,7 +116,8 @@ struct Monitor {
float mfact;
int nmaster;
int num;
- int by; /* bar geometry */
+ int by, bh; /* bar geometry */
+ int tx, tw; /* bar tray geometry */
int mx, my, mw, mh; /* screen size */
int wx, wy, ww, wh; /* window area */
unsigned int seltags;
@@ -129,6 +130,7 @@ struct Monitor {
Client *stack;
Monitor *next;
Window barwin;
+ Window traywin;
const Layout *lt[2];
};
@@ -179,6 +181,8 @@ static void incnmaster(const Arg *arg);
static void keypress(XEvent *e);
static void killclient(const Arg *arg);
static void manage(Window w, XWindowAttributes *wa);
+static void managealtbar(Window win, XWindowAttributes *wa);
+static void managetray(Window win, XWindowAttributes *wa);
static void mappingnotify(XEvent *e);
static void maprequest(XEvent *e);
static void monocle(Monitor *m);
@@ -195,6 +199,7 @@ static void resizemouse(const Arg *arg);
static void restack(Monitor *m);
static void run(void);
static void scan(void);
+static void scantray(void);
static int sendevent(Client *c, Atom proto);
static void sendmon(Client *c, Monitor *m);
static void setclientstate(Client *c, long state);
@@ -207,6 +212,7 @@ static void seturgent(Client *c, int urg);
static void showhide(Client *c);
static void sigchld(int unused);
static void spawn(const Arg *arg);
+static void spawnbar();
static void tag(const Arg *arg);
static void tagmon(const Arg *arg);
static void tile(Monitor *);
@@ -216,6 +222,8 @@ static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg);
static void unfocus(Client *c, int setfocus);
static void unmanage(Client *c, int destroyed);
+static void unmanagealtbar(Window w);
+static void unmanagetray(Window w);
static void unmapnotify(XEvent *e);
static void updatebarpos(Monitor *m);
static void updatebars(void);
@@ -230,6 +238,7 @@ static void updatewmhints(Client *c);
static void view(const Arg *arg);
static Client *wintoclient(Window w);
static Monitor *wintomon(Window w);
+static int wmclasscontains(Window win, const char *class, const char *name);
static int xerror(Display *dpy, XErrorEvent *ee);
static int xerrordummy(Display *dpy, XErrorEvent *ee);
static int xerrorstart(Display *dpy, XErrorEvent *ee);
@@ -505,8 +514,10 @@ cleanupmon(Monitor *mon)
for (m = mons; m && m->next != mon; m = m->next);
m->next = mon->next;
}
- XUnmapWindow(dpy, mon->barwin);
- XDestroyWindow(dpy, mon->barwin);
+ if (!usealtbar) {
+ XUnmapWindow(dpy, mon->barwin);
+ XDestroyWindow(dpy, mon->barwin);
+ }
free(mon);
}
@@ -568,7 +579,7 @@ configurenotify(XEvent *e)
for (c = m->clients; c; c = c->next)
if (c->isfullscreen)
resizeclient(c, m->mx, m->my, m->mw, m->mh);
- XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
+ XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, m->bh);
}
focus(NULL);
arrange(NULL);
@@ -639,6 +650,7 @@ createmon(void)
m->nmaster = nmaster;
m->showbar = showbar;
m->topbar = topbar;
+ m->bh = bh;
m->lt[0] = &layouts[0];
m->lt[1] = &layouts[1 % LENGTH(layouts)];
strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
@@ -649,10 +661,15 @@ void
destroynotify(XEvent *e)
{
Client *c;
+ Monitor *m;
XDestroyWindowEvent *ev = &e->xdestroywindow;
if ((c = wintoclient(ev->window)))
unmanage(c, 1);
+ else if ((m = wintomon(ev->window)) && m->barwin == ev->window)
+ unmanagealtbar(ev->window);
+ else if (m->traywin == ev->window)
+ unmanagetray(ev->window);
}
void
@@ -696,6 +713,9 @@ dirtomon(int dir)
void
drawbar(Monitor *m)
{
+ if (usealtbar)
+ return;
+
int x, w, tw = 0;
int boxs = drw->fonts->h / 9;
int boxw = drw->fonts->h / 6 + 2;
@@ -1077,6 +1097,45 @@ manage(Window w, XWindowAttributes *wa)
focus(NULL);
}
+void
+managealtbar(Window win, XWindowAttributes *wa)
+{
+ Monitor *m;
+ if (!(m = recttomon(wa->x, wa->y, wa->width, wa->height)))
+ return;
+
+ m->barwin = win;
+ m->by = wa->y;
+ bh = m->bh = wa->height;
+ updatebarpos(m);
+ arrange(m);
+ XSelectInput(dpy, win, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
+ XMoveResizeWindow(dpy, win, wa->x, wa->y, wa->width, wa->height);
+ XMapWindow(dpy, win);
+ XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
+ (unsigned char *) &win, 1);
+}
+
+void
+managetray(Window win, XWindowAttributes *wa)
+{
+ Monitor *m;
+ if (!(m = recttomon(wa->x, wa->y, wa->width, wa->height)))
+ return;
+
+ m->traywin = win;
+ m->tx = wa->x;
+ m->tw = wa->width;
+ updatebarpos(m);
+ arrange(m);
+ XSelectInput(dpy, win, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
+ XMoveResizeWindow(dpy, win, wa->x, wa->y, wa->width, wa->height);
+ XMapWindow(dpy, win);
+ XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
+ (unsigned char *) &win, 1);
+}
+
+
void
mappingnotify(XEvent *e)
{
@@ -1097,7 +1156,9 @@ maprequest(XEvent *e)
return;
if (wa.override_redirect)
return;
- if (!wintoclient(ev->window))
+ if (wmclasscontains(ev->window, altbarclass, ""))
+ managealtbar(ev->window, &wa);
+ else if (!wintoclient(ev->window))
manage(ev->window, &wa);
}
@@ -1393,7 +1454,9 @@ scan(void)
if (!XGetWindowAttributes(dpy, wins[i], &wa)
|| wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
continue;
- if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
+ if (wmclasscontains(wins[i], altbarclass, ""))
+ managealtbar(wins[i], &wa);
+ else if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
manage(wins[i], &wa);
}
for (i = 0; i < num; i++) { /* now the transients */
@@ -1408,6 +1471,29 @@ scan(void)
}
}
+void
+scantray(void)
+{
+ unsigned int num;
+ Window d1, d2, *wins = NULL;
+ XWindowAttributes wa;
+
+ if (XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
+ for (unsigned int i = 0; i < num; i++) {
+ if (wmclasscontains(wins[i], altbarclass, alttrayname)) {
+ if (!XGetWindowAttributes(dpy, wins[i], &wa))
+ break;
+ managetray(wins[i], &wa);
+ }
+ }
+ }
+
+ if (wins)
+ XFree(wins);
+}
+
+
+
void
sendmon(Client *c, Monitor *m)
{
@@ -1546,7 +1632,7 @@ setup(void)
if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
die("no fonts could be loaded.");
lrpad = drw->fonts->h;
- bh = drw->fonts->h + 2;
+ bh = usealtbar ? 0 : drw->fonts->h + 2;
updategeom();
/* init atoms */
utf8string = XInternAtom(dpy, "UTF8_STRING", False);
@@ -1595,6 +1681,7 @@ setup(void)
XSelectInput(dpy, root, wa.event_mask);
grabkeys();
focus(NULL);
+ spawnbar();
}
@@ -1653,6 +1740,13 @@ spawn(const Arg *arg)
}
}
+void
+spawnbar()
+{
+ if (*altbarcmd)
+ system(altbarcmd);
+}
+
void
tag(const Arg *arg)
{
@@ -1702,9 +1796,18 @@ tile(Monitor *m)
void
togglebar(const Arg *arg)
{
+ /**
+ * Polybar tray does not raise maprequest event. It must be manually scanned
+ * for. Scanning it too early while the tray is being populated would give
+ * wrong dimensions.
+ */
+ if (!selmon->traywin)
+ scantray();
+
selmon->showbar = !selmon->showbar;
updatebarpos(selmon);
- XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
+ XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, selmon->bh);
+ XMoveResizeWindow(dpy, selmon->traywin, selmon->tx, selmon->by, selmon->tw, selmon->bh);
arrange(selmon);
}
@@ -1787,10 +1890,41 @@ unmanage(Client *c, int destroyed)
arrange(m);
}
+void
+unmanagealtbar(Window w)
+{
+ Monitor *m = wintomon(w);
+
+ if (!m)
+ return;
+
+ m->barwin = 0;
+ m->by = 0;
+ m->bh = 0;
+ updatebarpos(m);
+ arrange(m);
+}
+
+void
+unmanagetray(Window w)
+{
+ Monitor *m = wintomon(w);
+
+ if (!m)
+ return;
+
+ m->traywin = 0;
+ m->tx = 0;
+ m->tw = 0;
+ updatebarpos(m);
+ arrange(m);
+}
+
void
unmapnotify(XEvent *e)
{
Client *c;
+ Monitor *m;
XUnmapEvent *ev = &e->xunmap;
if ((c = wintoclient(ev->window))) {
@@ -1798,12 +1932,18 @@ unmapnotify(XEvent *e)
setclientstate(c, WithdrawnState);
else
unmanage(c, 0);
- }
+ } else if ((m = wintomon(ev->window)) && m->barwin == ev->window)
+ unmanagealtbar(ev->window);
+ else if (m->traywin == ev->window)
+ unmanagetray(ev->window);
}
void
updatebars(void)
{
+ if (usealtbar)
+ return;
+
Monitor *m;
XSetWindowAttributes wa = {
.override_redirect = True,
@@ -1829,11 +1969,11 @@ updatebarpos(Monitor *m)
m->wy = m->my;
m->wh = m->mh;
if (m->showbar) {
- m->wh -= bh;
+ m->wh -= m->bh;
m->by = m->topbar ? m->wy : m->wy + m->wh;
- m->wy = m->topbar ? m->wy + bh : m->wy;
+ m->wy = m->topbar ? m->wy + m->bh : m->wy;
} else
- m->by = -bh;
+ m->by = -m->bh;
}
void
@@ -2070,13 +2210,35 @@ wintomon(Window w)
if (w == root && getrootptr(&x, &y))
return recttomon(x, y, 1, 1);
for (m = mons; m; m = m->next)
- if (w == m->barwin)
+ if (w == m->barwin || w == m->traywin)
return m;
if ((c = wintoclient(w)))
return c->mon;
return selmon;
}
+int
+wmclasscontains(Window win, const char *class, const char *name)
+{
+ XClassHint ch = { NULL, NULL };
+ int res = 1;
+
+ if (XGetClassHint(dpy, win, &ch)) {
+ if (ch.res_name && strstr(ch.res_name, name) == NULL)
+ res = 0;
+ if (ch.res_class && strstr(ch.res_class, class) == NULL)
+ res = 0;
+ } else
+ res = 0;
+
+ if (ch.res_class)
+ XFree(ch.res_class);
+ if (ch.res_name)
+ XFree(ch.res_name);
+
+ return res;
+}
+
/* There's no way to check accesses to destroyed windows, thus those cases are
* ignored (especially on UnmapNotify's). Other types of errors call Xlibs
* default error handler, which may call exit. */
--
2.28.0

View File

@ -0,0 +1,179 @@
From 37e970479dc5d40e57fc0cbfeaa5e39941483237 Mon Sep 17 00:00:00 2001
From: Gan Ainm <gan.ainm.riomhphost@gmail.com>
Date: Wed, 10 Jun 2020 10:59:02 +0000
Subject: [PATCH] dwm-xdgautostart-6.2.diff
===================================================================
---
dwm.1 | 23 +++++++++++++++++
dwm.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 105 insertions(+)
diff --git a/dwm.1 b/dwm.1
index 13b3729..9533aa6 100644
--- a/dwm.1
+++ b/dwm.1
@@ -30,6 +30,14 @@ top left corner. The tags which are applied to one or more windows are
indicated with an empty square in the top left corner.
.P
dwm draws a small border around windows to indicate the focus state.
+.P
+On start, dwm can start additional programs that may be specified in two special
+shell scripts (see the FILES section below), autostart_blocking.sh and
+autostart.sh. The former is executed first and dwm will wait for its
+termination before starting. The latter is executed in the background before
+dwm enters its handler loop.
+.P
+Either of these files may be omitted.
.SH OPTIONS
.TP
.B \-v
@@ -152,6 +160,21 @@ Toggles focused window between floating and tiled state.
.TP
.B Mod1\-Button3
Resize focused window while dragging. Tiled windows will be toggled to the floating state.
+.SH FILES
+The files containing programs to be started along with dwm are searched for in
+the following directories:
+.IP "1. $XDG_DATA_HOME/dwm"
+.IP "2. $HOME/.local/share/dwm"
+.IP "3. $HOME/.dwm"
+.P
+The first existing directory is scanned for any of the autostart files below.
+.TP 15
+autostart.sh
+This file is started as a shell background process before dwm enters its handler
+loop.
+.TP 15
+autostart_blocking.sh
+This file is started before any autostart.sh; dwm waits for its termination.
.SH CUSTOMIZATION
dwm is customized by creating a custom config.h and (re)compiling the source
code. This keeps it fast, secure and simple.
diff --git a/dwm.c b/dwm.c
index 4465af1..2156b49 100644
--- a/dwm.c
+++ b/dwm.c
@@ -29,6 +29,7 @@
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
+#include <sys/stat.h>
#include <sys/wait.h>
#include <X11/cursorfont.h>
#include <X11/keysym.h>
@@ -193,6 +194,7 @@ static void resizeclient(Client *c, int x, int y, int w, int h);
static void resizemouse(const Arg *arg);
static void restack(Monitor *m);
static void run(void);
+static void runautostart(void);
static void scan(void);
static int sendevent(Client *c, Atom proto);
static void sendmon(Client *c, Monitor *m);
@@ -235,7 +237,11 @@ static int xerrorstart(Display *dpy, XErrorEvent *ee);
static void zoom(const Arg *arg);
/* variables */
+static const char autostartblocksh[] = "autostart_blocking.sh";
+static const char autostartsh[] = "autostart.sh";
static const char broken[] = "broken";
+static const char dwmdir[] = "dwm";
+static const char localshare[] = ".local/share";
static char stext[256];
static int screen;
static int sw, sh; /* X display screen geometry width, height */
@@ -1380,6 +1386,83 @@ run(void)
handler[ev.type](&ev); /* call handler */
}
+void
+runautostart(void)
+{
+ char *pathpfx;
+ char *path;
+ char *xdgdatahome;
+ char *home;
+ struct stat sb;
+
+ if ((home = getenv("HOME")) == NULL)
+ /* this is almost impossible */
+ return;
+
+ /* if $XDG_DATA_HOME is set and not empty, use $XDG_DATA_HOME/dwm,
+ * otherwise use ~/.local/share/dwm as autostart script directory
+ */
+ xdgdatahome = getenv("XDG_DATA_HOME");
+ if (xdgdatahome != NULL && *xdgdatahome != '\0') {
+ /* space for path segments, separators and nul */
+ pathpfx = ecalloc(1, strlen(xdgdatahome) + strlen(dwmdir) + 2);
+
+ if (sprintf(pathpfx, "%s/%s", xdgdatahome, dwmdir) <= 0) {
+ free(pathpfx);
+ return;
+ }
+ } else {
+ /* space for path segments, separators and nul */
+ pathpfx = ecalloc(1, strlen(home) + strlen(localshare)
+ + strlen(dwmdir) + 3);
+
+ if (sprintf(pathpfx, "%s/%s/%s", home, localshare, dwmdir) < 0) {
+ free(pathpfx);
+ return;
+ }
+ }
+
+ /* check if the autostart script directory exists */
+ if (! (stat(pathpfx, &sb) == 0 && S_ISDIR(sb.st_mode))) {
+ /* the XDG conformant path does not exist or is no directory
+ * so we try ~/.dwm instead
+ */
+ char *pathpfx_new = realloc(pathpfx, strlen(home) + strlen(dwmdir) + 3);
+ if(pathpfx_new == NULL) {
+ free(pathpfx);
+ return;
+ }
+ pathpfx = pathpfx_new;
+
+ if (sprintf(pathpfx, "%s/.%s", home, dwmdir) <= 0) {
+ free(pathpfx);
+ return;
+ }
+ }
+
+ /* try the blocking script first */
+ path = ecalloc(1, strlen(pathpfx) + strlen(autostartblocksh) + 2);
+ if (sprintf(path, "%s/%s", pathpfx, autostartblocksh) <= 0) {
+ free(path);
+ free(pathpfx);
+ }
+
+ if (access(path, X_OK) == 0)
+ system(path);
+
+ /* now the non-blocking script */
+ if (sprintf(path, "%s/%s", pathpfx, autostartsh) <= 0) {
+ free(path);
+ free(pathpfx);
+ }
+
+ if (access(path, X_OK) == 0)
+ system(strcat(path, " &"));
+
+ free(pathpfx);
+ free(path);
+}
+
void
scan(void)
{
@@ -2142,6 +2223,7 @@ main(int argc, char *argv[])
die("pledge");
#endif /* __OpenBSD__ */
scan();
+ runautostart();
run();
cleanup();
XCloseDisplay(dpy);
--
2.27.0

View File

@ -0,0 +1,39 @@
diff --git a/dwm.c b/dwm.c
index a96f33c..f2da729 100644
--- a/dwm.c
+++ b/dwm.c
@@ -432,9 +432,15 @@ buttonpress(XEvent *e)
}
if (ev->window == selmon->barwin) {
i = x = 0;
- do
+ unsigned int occ = 0;
+ for(c = m->clients; c; c=c->next)
+ occ |= c->tags;
+ do {
+ /* Do not reserve space for vacant tags */
+ if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i))
+ continue;
x += TEXTW(tags[i]);
- while (ev->x >= x && ++i < LENGTH(tags));
+ } while (ev->x >= x && ++i < LENGTH(tags));
if (i < LENGTH(tags)) {
click = ClkTagBar;
arg.ui = 1 << i;
@@ -719,13 +725,12 @@ drawbar(Monitor *m)
}
x = 0;
for (i = 0; i < LENGTH(tags); i++) {
+ /* Do not draw vacant tags */
+ if(!(occ & 1 << i || m->tagset[m->seltags] & 1 << i))
+ continue;
w = TEXTW(tags[i]);
drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i);
- if (occ & 1 << i)
- drw_rect(drw, x + boxs, boxs, boxw, boxw,
- m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
- urg & 1 << i);
x += w;
}
w = blw = TEXTW(m->ltsymbol);

View File

@ -0,0 +1,95 @@
From 9a4037dc0ef56f91c009317e78e9e3790dafbb58 Mon Sep 17 00:00:00 2001
From: BrunoCooper17 <BrunoCooper17@outlook.com>
Date: Mon, 15 Nov 2021 14:04:53 -0600
Subject: [PATCH] MoveStack patch
This plugin allows you to move clients around in the stack and swap them
with the master. It emulates the behavior off mod+shift+j and mod+shift+k
in Xmonad. movestack(+1) will swap the client with the current focus with
the next client. movestack(-1) will swap the client with the current focus
with the previous client.
---
config.def.h | 3 +++
movestack.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 51 insertions(+)
create mode 100644 movestack.c
diff --git a/config.def.h b/config.def.h
index a2ac963..33efa5b 100644
--- a/config.def.h
+++ b/config.def.h
@@ -60,6 +60,7 @@ static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn()
static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
static const char *termcmd[] = { "st", NULL };
+#include "movestack.c"
static Key keys[] = {
/* modifier key function argument */
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
@@ -71,6 +72,8 @@ static Key keys[] = {
{ MODKEY, XK_d, incnmaster, {.i = -1 } },
{ MODKEY, XK_h, setmfact, {.f = -0.05} },
{ MODKEY, XK_l, setmfact, {.f = +0.05} },
+ { MODKEY|ShiftMask, XK_j, movestack, {.i = +1 } },
+ { MODKEY|ShiftMask, XK_k, movestack, {.i = -1 } },
{ MODKEY, XK_Return, zoom, {0} },
{ MODKEY, XK_Tab, view, {0} },
{ MODKEY|ShiftMask, XK_c, killclient, {0} },
diff --git a/movestack.c b/movestack.c
new file mode 100644
index 0000000..520f4ae
--- /dev/null
+++ b/movestack.c
@@ -0,0 +1,48 @@
+void
+movestack(const Arg *arg) {
+ Client *c = NULL, *p = NULL, *pc = NULL, *i;
+
+ if(arg->i > 0) {
+ /* find the client after selmon->sel */
+ for(c = selmon->sel->next; c && (!ISVISIBLE(c) || c->isfloating); c = c->next);
+ if(!c)
+ for(c = selmon->clients; c && (!ISVISIBLE(c) || c->isfloating); c = c->next);
+
+ }
+ else {
+ /* find the client before selmon->sel */
+ for(i = selmon->clients; i != selmon->sel; i = i->next)
+ if(ISVISIBLE(i) && !i->isfloating)
+ c = i;
+ if(!c)
+ for(; i; i = i->next)
+ if(ISVISIBLE(i) && !i->isfloating)
+ c = i;
+ }
+ /* find the client before selmon->sel and c */
+ for(i = selmon->clients; i && (!p || !pc); i = i->next) {
+ if(i->next == selmon->sel)
+ p = i;
+ if(i->next == c)
+ pc = i;
+ }
+
+ /* swap c and selmon->sel selmon->clients in the selmon->clients list */
+ if(c && c != selmon->sel) {
+ Client *temp = selmon->sel->next==c?selmon->sel:selmon->sel->next;
+ selmon->sel->next = c->next==selmon->sel?c:c->next;
+ c->next = temp;
+
+ if(p && p != c)
+ p->next = c;
+ if(pc && pc != selmon->sel)
+ pc->next = selmon->sel;
+
+ if(selmon->sel == selmon->clients)
+ selmon->clients = c;
+ else if(c == selmon->clients)
+ selmon->clients = selmon->sel;
+
+ arrange(selmon);
+ }
+}
\ No newline at end of file
--
2.33.1

166
dwm-status2d-6.3.diff Normal file
View File

@ -0,0 +1,166 @@
diff --git a/dwm.c b/dwm.c
index a96f33c..24b1eeb 100644
--- a/dwm.c
+++ b/dwm.c
@@ -163,6 +163,7 @@ static void detachstack(Client *c);
static Monitor *dirtomon(int dir);
static void drawbar(Monitor *m);
static void drawbars(void);
+static int drawstatusbar(Monitor *m, int bh, char* text);
static void enternotify(XEvent *e);
static void expose(XEvent *e);
static void focus(Client *c);
@@ -237,7 +238,7 @@ static void zoom(const Arg *arg);
/* variables */
static const char broken[] = "broken";
-static char stext[256];
+static char stext[1024];
static int screen;
static int sw, sh; /* X display screen geometry width, height */
static int bh, blw = 0; /* bar geometry */
@@ -485,7 +486,7 @@ cleanup(void)
cleanupmon(mons);
for (i = 0; i < CurLast; i++)
drw_cur_free(drw, cursor[i]);
- for (i = 0; i < LENGTH(colors); i++)
+ for (i = 0; i < LENGTH(colors) + 1; i++)
free(scheme[i]);
XDestroyWindow(dpy, wmcheckwin);
drw_free(drw);
@@ -693,6 +694,114 @@ dirtomon(int dir)
return m;
}
+int
+drawstatusbar(Monitor *m, int bh, char* stext) {
+ int ret, i, w, x, len;
+ short isCode = 0;
+ char *text;
+ char *p;
+
+ len = strlen(stext) + 1 ;
+ if (!(text = (char*) malloc(sizeof(char)*len)))
+ die("malloc");
+ p = text;
+ memcpy(text, stext, len);
+
+ /* compute width of the status text */
+ w = 0;
+ i = -1;
+ while (text[++i]) {
+ if (text[i] == '^') {
+ if (!isCode) {
+ isCode = 1;
+ text[i] = '\0';
+ w += TEXTW(text) - lrpad;
+ text[i] = '^';
+ if (text[++i] == 'f')
+ w += atoi(text + ++i);
+ } else {
+ isCode = 0;
+ text = text + i + 1;
+ i = -1;
+ }
+ }
+ }
+ if (!isCode)
+ w += TEXTW(text) - lrpad;
+ else
+ isCode = 0;
+ text = p;
+
+ w += 2; /* 1px padding on both sides */
+ ret = x = m->ww - w;
+
+ drw_setscheme(drw, scheme[LENGTH(colors)]);
+ drw->scheme[ColFg] = scheme[SchemeNorm][ColFg];
+ drw->scheme[ColBg] = scheme[SchemeNorm][ColBg];
+ drw_rect(drw, x, 0, w, bh, 1, 1);
+ x++;
+
+ /* process status text */
+ i = -1;
+ while (text[++i]) {
+ if (text[i] == '^' && !isCode) {
+ isCode = 1;
+
+ text[i] = '\0';
+ w = TEXTW(text) - lrpad;
+ drw_text(drw, x, 0, w, bh, 0, text, 0);
+
+ x += w;
+
+ /* process code */
+ while (text[++i] != '^') {
+ if (text[i] == 'c') {
+ char buf[8];
+ memcpy(buf, (char*)text+i+1, 7);
+ buf[7] = '\0';
+ drw_clr_create(drw, &drw->scheme[ColFg], buf);
+ i += 7;
+ } else if (text[i] == 'b') {
+ char buf[8];
+ memcpy(buf, (char*)text+i+1, 7);
+ buf[7] = '\0';
+ drw_clr_create(drw, &drw->scheme[ColBg], buf);
+ i += 7;
+ } else if (text[i] == 'd') {
+ drw->scheme[ColFg] = scheme[SchemeNorm][ColFg];
+ drw->scheme[ColBg] = scheme[SchemeNorm][ColBg];
+ } else if (text[i] == 'r') {
+ int rx = atoi(text + ++i);
+ while (text[++i] != ',');
+ int ry = atoi(text + ++i);
+ while (text[++i] != ',');
+ int rw = atoi(text + ++i);
+ while (text[++i] != ',');
+ int rh = atoi(text + ++i);
+
+ drw_rect(drw, rx + x, ry, rw, rh, 1, 0);
+ } else if (text[i] == 'f') {
+ x += atoi(text + ++i);
+ }
+ }
+
+ text = text + i + 1;
+ i=-1;
+ isCode = 0;
+ }
+ }
+
+ if (!isCode) {
+ w = TEXTW(text) - lrpad;
+ drw_text(drw, x, 0, w, bh, 0, text, 0);
+ }
+
+ drw_setscheme(drw, scheme[SchemeNorm]);
+ free(p);
+
+ return ret;
+}
+
void
drawbar(Monitor *m)
{
@@ -707,9 +816,7 @@ drawbar(Monitor *m)
/* draw status first so it can be overdrawn by tags later */
if (m == selmon) { /* status is only drawn on selected monitor */
- drw_setscheme(drw, scheme[SchemeNorm]);
- tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
- drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
+ tw = m->ww - drawstatusbar(m, bh, stext);
}
for (c = m->clients; c; c = c->next) {
@@ -1571,7 +1678,8 @@ setup(void)
cursor[CurResize] = drw_cur_create(drw, XC_sizing);
cursor[CurMove] = drw_cur_create(drw, XC_fleur);
/* init appearance */
- scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
+ scheme = ecalloc(LENGTH(colors) + 1, sizeof(Clr *));
+ scheme[LENGTH(colors)] = drw_scm_create(drw, colors[0], 3);
for (i = 0; i < LENGTH(colors); i++)
scheme[i] = drw_scm_create(drw, colors[i], 3);
/* init bars */

23
dwm.1
View File

@ -30,6 +30,14 @@ top left corner. The tags which are applied to one or more windows are
indicated with an empty square in the top left corner.
.P
dwm draws a small border around windows to indicate the focus state.
.P
On start, dwm can start additional programs that may be specified in two special
shell scripts (see the FILES section below), autostart_blocking.sh and
autostart.sh. The former is executed first and dwm will wait for its
termination before starting. The latter is executed in the background before
dwm enters its handler loop.
.P
Either of these files may be omitted.
.SH OPTIONS
.TP
.B \-v
@ -152,6 +160,21 @@ Toggles focused window between floating and tiled state.
.TP
.B Mod1\-Button3
Resize focused window while dragging. Tiled windows will be toggled to the floating state.
.SH FILES
The files containing programs to be started along with dwm are searched for in
the following directories:
.IP "1. $XDG_DATA_HOME/dwm"
.IP "2. $HOME/.local/share/dwm"
.IP "3. $HOME/.dwm"
.P
The first existing directory is scanned for any of the autostart files below.
.TP 15
autostart.sh
This file is started as a shell background process before dwm enters its handler
loop.
.TP 15
autostart_blocking.sh
This file is started before any autostart.sh; dwm waits for its termination.
.SH CUSTOMIZATION
dwm is customized by creating a custom config.h and (re)compiling the source
code. This keeps it fast, secure and simple.

413
dwm.c
View File

@ -29,6 +29,7 @@
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <X11/cursorfont.h>
#include <X11/keysym.h>
@ -47,8 +48,8 @@
/* macros */
#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->mx+(m)->mw) - MAX((x),(m)->mx)) \
* MAX(0, MIN((y)+(h),(m)->my+(m)->mh) - MAX((y),(m)->my)))
#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
* MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
#define LENGTH(X) (sizeof X / sizeof X[0])
#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
@ -116,8 +117,7 @@ struct Monitor {
float mfact;
int nmaster;
int num;
int by, bh; /* bar geometry */
int tx, tw; /* bar tray geometry */
int by; /* bar geometry */
int mx, my, mw, mh; /* screen size */
int wx, wy, ww, wh; /* window area */
unsigned int seltags;
@ -130,7 +130,6 @@ struct Monitor {
Client *stack;
Monitor *next;
Window barwin;
Window traywin;
const Layout *lt[2];
};
@ -165,6 +164,7 @@ static void detachstack(Client *c);
static Monitor *dirtomon(int dir);
static void drawbar(Monitor *m);
static void drawbars(void);
static int drawstatusbar(Monitor *m, int bh, char* text);
static void enternotify(XEvent *e);
static void expose(XEvent *e);
static void focus(Client *c);
@ -181,8 +181,6 @@ static void incnmaster(const Arg *arg);
static void keypress(XEvent *e);
static void killclient(const Arg *arg);
static void manage(Window w, XWindowAttributes *wa);
static void managealtbar(Window win, XWindowAttributes *wa);
static void managetray(Window win, XWindowAttributes *wa);
static void mappingnotify(XEvent *e);
static void maprequest(XEvent *e);
static void monocle(Monitor *m);
@ -198,8 +196,8 @@ static void resizeclient(Client *c, int x, int y, int w, int h);
static void resizemouse(const Arg *arg);
static void restack(Monitor *m);
static void run(void);
static void runautostart(void);
static void scan(void);
static void scantray(void);
static int sendevent(Client *c, Atom proto);
static void sendmon(Client *c, Monitor *m);
static void setclientstate(Client *c, long state);
@ -212,7 +210,6 @@ static void seturgent(Client *c, int urg);
static void showhide(Client *c);
static void sigchld(int unused);
static void spawn(const Arg *arg);
static void spawnbar();
static void tag(const Arg *arg);
static void tagmon(const Arg *arg);
static void tile(Monitor *);
@ -222,8 +219,6 @@ static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg);
static void unfocus(Client *c, int setfocus);
static void unmanage(Client *c, int destroyed);
static void unmanagealtbar(Window w);
static void unmanagetray(Window w);
static void unmapnotify(XEvent *e);
static void updatebarpos(Monitor *m);
static void updatebars(void);
@ -238,15 +233,18 @@ static void updatewmhints(Client *c);
static void view(const Arg *arg);
static Client *wintoclient(Window w);
static Monitor *wintomon(Window w);
static int wmclasscontains(Window win, const char *class, const char *name);
static int xerror(Display *dpy, XErrorEvent *ee);
static int xerrordummy(Display *dpy, XErrorEvent *ee);
static int xerrorstart(Display *dpy, XErrorEvent *ee);
static void zoom(const Arg *arg);
/* variables */
static const char autostartblocksh[] = "autostart_blocking.sh";
static const char autostartsh[] = "autostart.sh";
static const char broken[] = "broken";
static char stext[256];
static const char dwmdir[] = "dwm";
static const char localshare[] = ".local/share";
static char stext[1024];
static int screen;
static int sw, sh; /* X display screen geometry width, height */
static int bh, blw = 0; /* bar geometry */
@ -441,9 +439,15 @@ buttonpress(XEvent *e)
}
if (ev->window == selmon->barwin) {
i = x = 0;
do
unsigned int occ = 0;
for(c = m->clients; c; c=c->next)
occ |= c->tags;
do {
/* Do not reserve space for vacant tags */
if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i))
continue;
x += TEXTW(tags[i]);
while (ev->x >= x && ++i < LENGTH(tags));
} while (ev->x >= x && ++i < LENGTH(tags));
if (i < LENGTH(tags)) {
click = ClkTagBar;
arg.ui = 1 << i;
@ -494,7 +498,7 @@ cleanup(void)
cleanupmon(mons);
for (i = 0; i < CurLast; i++)
drw_cur_free(drw, cursor[i]);
for (i = 0; i < LENGTH(colors); i++)
for (i = 0; i < LENGTH(colors) + 1; i++)
free(scheme[i]);
XDestroyWindow(dpy, wmcheckwin);
drw_free(drw);
@ -514,10 +518,8 @@ cleanupmon(Monitor *mon)
for (m = mons; m && m->next != mon; m = m->next);
m->next = mon->next;
}
if (!usealtbar) {
XUnmapWindow(dpy, mon->barwin);
XDestroyWindow(dpy, mon->barwin);
}
XUnmapWindow(dpy, mon->barwin);
XDestroyWindow(dpy, mon->barwin);
free(mon);
}
@ -579,7 +581,7 @@ configurenotify(XEvent *e)
for (c = m->clients; c; c = c->next)
if (c->isfullscreen)
resizeclient(c, m->mx, m->my, m->mw, m->mh);
XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, m->bh);
XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
}
focus(NULL);
arrange(NULL);
@ -650,7 +652,6 @@ createmon(void)
m->nmaster = nmaster;
m->showbar = showbar;
m->topbar = topbar;
m->bh = bh;
m->lt[0] = &layouts[0];
m->lt[1] = &layouts[1 % LENGTH(layouts)];
strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
@ -661,15 +662,10 @@ void
destroynotify(XEvent *e)
{
Client *c;
Monitor *m;
XDestroyWindowEvent *ev = &e->xdestroywindow;
if ((c = wintoclient(ev->window)))
unmanage(c, 1);
else if ((m = wintomon(ev->window)) && m->barwin == ev->window)
unmanagealtbar(ev->window);
else if (m->traywin == ev->window)
unmanagetray(ev->window);
}
void
@ -710,12 +706,117 @@ dirtomon(int dir)
return m;
}
int
drawstatusbar(Monitor *m, int bh, char* stext) {
int ret, i, w, x, len;
short isCode = 0;
char *text;
char *p;
len = strlen(stext) + 1 ;
if (!(text = (char*) malloc(sizeof(char)*len)))
die("malloc");
p = text;
memcpy(text, stext, len);
/* compute width of the status text */
w = 0;
i = -1;
while (text[++i]) {
if (text[i] == '^') {
if (!isCode) {
isCode = 1;
text[i] = '\0';
w += TEXTW(text) - lrpad;
text[i] = '^';
if (text[++i] == 'f')
w += atoi(text + ++i);
} else {
isCode = 0;
text = text + i + 1;
i = -1;
}
}
}
if (!isCode)
w += TEXTW(text) - lrpad;
else
isCode = 0;
text = p;
w += 2; /* 1px padding on both sides */
ret = x = m->ww - w;
drw_setscheme(drw, scheme[LENGTH(colors)]);
drw->scheme[ColFg] = scheme[SchemeNorm][ColFg];
drw->scheme[ColBg] = scheme[SchemeNorm][ColBg];
drw_rect(drw, x, 0, w, bh, 1, 1);
x++;
/* process status text */
i = -1;
while (text[++i]) {
if (text[i] == '^' && !isCode) {
isCode = 1;
text[i] = '\0';
w = TEXTW(text) - lrpad;
drw_text(drw, x, 0, w, bh, 0, text, 0);
x += w;
/* process code */
while (text[++i] != '^') {
if (text[i] == 'c') {
char buf[8];
memcpy(buf, (char*)text+i+1, 7);
buf[7] = '\0';
drw_clr_create(drw, &drw->scheme[ColFg], buf);
i += 7;
} else if (text[i] == 'b') {
char buf[8];
memcpy(buf, (char*)text+i+1, 7);
buf[7] = '\0';
drw_clr_create(drw, &drw->scheme[ColBg], buf);
i += 7;
} else if (text[i] == 'd') {
drw->scheme[ColFg] = scheme[SchemeNorm][ColFg];
drw->scheme[ColBg] = scheme[SchemeNorm][ColBg];
} else if (text[i] == 'r') {
int rx = atoi(text + ++i);
while (text[++i] != ',');
int ry = atoi(text + ++i);
while (text[++i] != ',');
int rw = atoi(text + ++i);
while (text[++i] != ',');
int rh = atoi(text + ++i);
drw_rect(drw, rx + x, ry, rw, rh, 1, 0);
} else if (text[i] == 'f') {
x += atoi(text + ++i);
}
}
text = text + i + 1;
i=-1;
isCode = 0;
}
}
if (!isCode) {
w = TEXTW(text) - lrpad;
drw_text(drw, x, 0, w, bh, 0, text, 0);
}
drw_setscheme(drw, scheme[SchemeNorm]);
free(p);
return ret;
}
void
drawbar(Monitor *m)
{
if (usealtbar)
return;
int x, w, tw = 0;
int boxs = drw->fonts->h / 9;
int boxw = drw->fonts->h / 6 + 2;
@ -727,9 +828,7 @@ drawbar(Monitor *m)
/* draw status first so it can be overdrawn by tags later */
if (m == selmon) { /* status is only drawn on selected monitor */
drw_setscheme(drw, scheme[SchemeNorm]);
tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
tw = m->ww - drawstatusbar(m, bh, stext);
}
for (c = m->clients; c; c = c->next) {
@ -739,13 +838,12 @@ drawbar(Monitor *m)
}
x = 0;
for (i = 0; i < LENGTH(tags); i++) {
/* Do not draw vacant tags */
if(!(occ & 1 << i || m->tagset[m->seltags] & 1 << i))
continue;
w = TEXTW(tags[i]);
drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i);
if (occ & 1 << i)
drw_rect(drw, x + boxs, boxs, boxw, boxw,
m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
urg & 1 << i);
x += w;
}
w = blw = TEXTW(m->ltsymbol);
@ -1100,45 +1198,6 @@ manage(Window w, XWindowAttributes *wa)
focus(NULL);
}
void
managealtbar(Window win, XWindowAttributes *wa)
{
Monitor *m;
if (!(m = recttomon(wa->x, wa->y, wa->width, wa->height)))
return;
m->barwin = win;
m->by = wa->y;
bh = m->bh = wa->height;
updatebarpos(m);
arrange(m);
XSelectInput(dpy, win, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
XMoveResizeWindow(dpy, win, wa->x, wa->y, wa->width, wa->height);
XMapWindow(dpy, win);
XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
(unsigned char *) &win, 1);
}
void
managetray(Window win, XWindowAttributes *wa)
{
Monitor *m;
if (!(m = recttomon(wa->x, wa->y, wa->width, wa->height)))
return;
m->traywin = win;
m->tx = wa->x;
m->tw = wa->width;
updatebarpos(m);
arrange(m);
XSelectInput(dpy, win, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
XMoveResizeWindow(dpy, win, wa->x, wa->y, wa->width, wa->height);
XMapWindow(dpy, win);
XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
(unsigned char *) &win, 1);
}
void
mappingnotify(XEvent *e)
{
@ -1159,9 +1218,7 @@ maprequest(XEvent *e)
return;
if (wa.override_redirect)
return;
if (wmclasscontains(ev->window, altbarclass, ""))
managealtbar(ev->window, &wa);
else if (!wintoclient(ev->window))
if (!wintoclient(ev->window))
manage(ev->window, &wa);
}
@ -1445,6 +1502,83 @@ run(void)
handler[ev.type](&ev); /* call handler */
}
void
runautostart(void)
{
char *pathpfx;
char *path;
char *xdgdatahome;
char *home;
struct stat sb;
if ((home = getenv("HOME")) == NULL)
/* this is almost impossible */
return;
/* if $XDG_DATA_HOME is set and not empty, use $XDG_DATA_HOME/dwm,
* otherwise use ~/.local/share/dwm as autostart script directory
*/
xdgdatahome = getenv("XDG_DATA_HOME");
if (xdgdatahome != NULL && *xdgdatahome != '\0') {
/* space for path segments, separators and nul */
pathpfx = ecalloc(1, strlen(xdgdatahome) + strlen(dwmdir) + 2);
if (sprintf(pathpfx, "%s/%s", xdgdatahome, dwmdir) <= 0) {
free(pathpfx);
return;
}
} else {
/* space for path segments, separators and nul */
pathpfx = ecalloc(1, strlen(home) + strlen(localshare)
+ strlen(dwmdir) + 3);
if (sprintf(pathpfx, "%s/%s/%s", home, localshare, dwmdir) < 0) {
free(pathpfx);
return;
}
}
/* check if the autostart script directory exists */
if (! (stat(pathpfx, &sb) == 0 && S_ISDIR(sb.st_mode))) {
/* the XDG conformant path does not exist or is no directory
* so we try ~/.dwm instead
*/
char *pathpfx_new = realloc(pathpfx, strlen(home) + strlen(dwmdir) + 3);
if(pathpfx_new == NULL) {
free(pathpfx);
return;
}
pathpfx = pathpfx_new;
if (sprintf(pathpfx, "%s/.%s", home, dwmdir) <= 0) {
free(pathpfx);
return;
}
}
/* try the blocking script first */
path = ecalloc(1, strlen(pathpfx) + strlen(autostartblocksh) + 2);
if (sprintf(path, "%s/%s", pathpfx, autostartblocksh) <= 0) {
free(path);
free(pathpfx);
}
if (access(path, X_OK) == 0)
system(path);
/* now the non-blocking script */
if (sprintf(path, "%s/%s", pathpfx, autostartsh) <= 0) {
free(path);
free(pathpfx);
}
if (access(path, X_OK) == 0)
system(strcat(path, " &"));
free(pathpfx);
free(path);
}
void
scan(void)
{
@ -1457,9 +1591,7 @@ scan(void)
if (!XGetWindowAttributes(dpy, wins[i], &wa)
|| wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
continue;
if (wmclasscontains(wins[i], altbarclass, ""))
managealtbar(wins[i], &wa);
else if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
manage(wins[i], &wa);
}
for (i = 0; i < num; i++) { /* now the transients */
@ -1474,29 +1606,6 @@ scan(void)
}
}
void
scantray(void)
{
unsigned int num;
Window d1, d2, *wins = NULL;
XWindowAttributes wa;
if (XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
for (unsigned int i = 0; i < num; i++) {
if (wmclasscontains(wins[i], altbarclass, alttrayname)) {
if (!XGetWindowAttributes(dpy, wins[i], &wa))
break;
managetray(wins[i], &wa);
}
}
}
if (wins)
XFree(wins);
}
void
sendmon(Client *c, Monitor *m)
{
@ -1635,7 +1744,7 @@ setup(void)
if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
die("no fonts could be loaded.");
lrpad = drw->fonts->h;
bh = usealtbar ? 0 : drw->fonts->h + 2;
bh = drw->fonts->h + 2;
updategeom();
/* init atoms */
utf8string = XInternAtom(dpy, "UTF8_STRING", False);
@ -1657,7 +1766,8 @@ setup(void)
cursor[CurResize] = drw_cur_create(drw, XC_sizing);
cursor[CurMove] = drw_cur_create(drw, XC_fleur);
/* init appearance */
scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
scheme = ecalloc(LENGTH(colors) + 1, sizeof(Clr *));
scheme[LENGTH(colors)] = drw_scm_create(drw, colors[0], 3);
for (i = 0; i < LENGTH(colors); i++)
scheme[i] = drw_scm_create(drw, colors[i], 3);
/* init bars */
@ -1684,7 +1794,6 @@ setup(void)
XSelectInput(dpy, root, wa.event_mask);
grabkeys();
focus(NULL);
spawnbar();
}
@ -1743,13 +1852,6 @@ spawn(const Arg *arg)
}
}
void
spawnbar()
{
if (*altbarcmd)
system(altbarcmd);
}
void
tag(const Arg *arg)
{
@ -1799,18 +1901,9 @@ tile(Monitor *m)
void
togglebar(const Arg *arg)
{
/**
* Polybar tray does not raise maprequest event. It must be manually scanned
* for. Scanning it too early while the tray is being populated would give
* wrong dimensions.
*/
if (!selmon->traywin)
scantray();
selmon->showbar = !selmon->showbar;
updatebarpos(selmon);
XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, selmon->bh);
XMoveResizeWindow(dpy, selmon->traywin, selmon->tx, selmon->by, selmon->tw, selmon->bh);
XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
arrange(selmon);
}
@ -1893,41 +1986,10 @@ unmanage(Client *c, int destroyed)
arrange(m);
}
void
unmanagealtbar(Window w)
{
Monitor *m = wintomon(w);
if (!m)
return;
m->barwin = 0;
m->by = 0;
m->bh = 0;
updatebarpos(m);
arrange(m);
}
void
unmanagetray(Window w)
{
Monitor *m = wintomon(w);
if (!m)
return;
m->traywin = 0;
m->tx = 0;
m->tw = 0;
updatebarpos(m);
arrange(m);
}
void
unmapnotify(XEvent *e)
{
Client *c;
Monitor *m;
XUnmapEvent *ev = &e->xunmap;
if ((c = wintoclient(ev->window))) {
@ -1935,18 +1997,12 @@ unmapnotify(XEvent *e)
setclientstate(c, WithdrawnState);
else
unmanage(c, 0);
} else if ((m = wintomon(ev->window)) && m->barwin == ev->window)
unmanagealtbar(ev->window);
else if (m->traywin == ev->window)
unmanagetray(ev->window);
}
}
void
updatebars(void)
{
if (usealtbar)
return;
Monitor *m;
XSetWindowAttributes wa = {
.override_redirect = True,
@ -1972,11 +2028,11 @@ updatebarpos(Monitor *m)
m->wy = m->my;
m->wh = m->mh;
if (m->showbar) {
m->wh -= m->bh;
m->wh -= bh;
m->by = m->topbar ? m->wy : m->wy + m->wh;
m->wy = m->topbar ? m->wy + m->bh : m->wy;
m->wy = m->topbar ? m->wy + bh : m->wy;
} else
m->by = -m->bh;
m->by = -bh;
}
void
@ -2213,35 +2269,13 @@ wintomon(Window w)
if (w == root && getrootptr(&x, &y))
return recttomon(x, y, 1, 1);
for (m = mons; m; m = m->next)
if (w == m->barwin || w == m->traywin)
if (w == m->barwin)
return m;
if ((c = wintoclient(w)))
return c->mon;
return selmon;
}
int
wmclasscontains(Window win, const char *class, const char *name)
{
XClassHint ch = { NULL, NULL };
int res = 1;
if (XGetClassHint(dpy, win, &ch)) {
if (ch.res_name && strstr(ch.res_name, name) == NULL)
res = 0;
if (ch.res_class && strstr(ch.res_class, class) == NULL)
res = 0;
} else
res = 0;
if (ch.res_class)
XFree(ch.res_class);
if (ch.res_name)
XFree(ch.res_name);
return res;
}
/* There's no way to check accesses to destroyed windows, thus those cases are
* ignored (especially on UnmapNotify's). Other types of errors call Xlibs
* default error handler, which may call exit. */
@ -2310,6 +2344,7 @@ main(int argc, char *argv[])
die("pledge");
#endif /* __OpenBSD__ */
scan();
runautostart();
run();
cleanup();
XCloseDisplay(dpy);

48
movestack.c Normal file
View File

@ -0,0 +1,48 @@
void
movestack(const Arg *arg) {
Client *c = NULL, *p = NULL, *pc = NULL, *i;
if(arg->i > 0) {
/* find the client after selmon->sel */
for(c = selmon->sel->next; c && (!ISVISIBLE(c) || c->isfloating); c = c->next);
if(!c)
for(c = selmon->clients; c && (!ISVISIBLE(c) || c->isfloating); c = c->next);
}
else {
/* find the client before selmon->sel */
for(i = selmon->clients; i != selmon->sel; i = i->next)
if(ISVISIBLE(i) && !i->isfloating)
c = i;
if(!c)
for(; i; i = i->next)
if(ISVISIBLE(i) && !i->isfloating)
c = i;
}
/* find the client before selmon->sel and c */
for(i = selmon->clients; i && (!p || !pc); i = i->next) {
if(i->next == selmon->sel)
p = i;
if(i->next == c)
pc = i;
}
/* swap c and selmon->sel selmon->clients in the selmon->clients list */
if(c && c != selmon->sel) {
Client *temp = selmon->sel->next==c?selmon->sel:selmon->sel->next;
selmon->sel->next = c->next==selmon->sel?c:c->next;
c->next = temp;
if(p && p != c)
p->next = c;
if(pc && pc != selmon->sel)
pc->next = selmon->sel;
if(selmon->sel == selmon->clients)
selmon->clients = c;
else if(c == selmon->clients)
selmon->clients = selmon->sel;
arrange(selmon);
}
}