Compare commits
1 Commits
dwm-patche
...
patch-anyb
Author | SHA1 | Date | |
---|---|---|---|
89f4f0fd7e |
17
config.def.h
17
config.def.h
@ -5,13 +5,17 @@ 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[] = "#606060";
|
||||
static const char col_cyan[] = "#005577";
|
||||
static const char *colors[][3] = {
|
||||
/* fg bg border */
|
||||
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
|
||||
@ -45,7 +49,7 @@ static const Layout layouts[] = {
|
||||
};
|
||||
|
||||
/* key definitions */
|
||||
#define MODKEY Mod4Mask
|
||||
#define MODKEY Mod1Mask
|
||||
#define TAGKEYS(KEY,TAG) \
|
||||
{ MODKEY, KEY, view, {.ui = 1 << TAG} }, \
|
||||
{ MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
|
||||
@ -58,17 +62,12 @@ 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[] = { "alacritty", NULL };
|
||||
static const char *scrotcmd[] = { "scrot", "-s", NULL };
|
||||
static const char *lockcmd[] = { "xsecurelock", NULL };
|
||||
static const char *termcmd[] = { "st", 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_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 } },
|
||||
@ -76,8 +75,6 @@ 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} },
|
||||
|
445
dwm-anybar-polybar-tray-fix-20200810-bb2e722.diff
Normal file
445
dwm-anybar-polybar-tray-fix-20200810-bb2e722.diff
Normal file
@ -0,0 +1,445 @@
|
||||
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
|
||||
|
@ -1,179 +0,0 @@
|
||||
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
|
||||
|
@ -1,39 +0,0 @@
|
||||
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);
|
@ -1,95 +0,0 @@
|
||||
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
|
||||
|
@ -1,166 +0,0 @@
|
||||
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
23
dwm.1
@ -30,14 +30,6 @@ 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
|
||||
@ -160,21 +152,6 @@ 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.
|
||||
|
409
dwm.c
409
dwm.c
@ -29,7 +29,6 @@
|
||||
#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>
|
||||
@ -48,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)
|
||||
@ -117,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;
|
||||
@ -130,6 +130,7 @@ struct Monitor {
|
||||
Client *stack;
|
||||
Monitor *next;
|
||||
Window barwin;
|
||||
Window traywin;
|
||||
const Layout *lt[2];
|
||||
};
|
||||
|
||||
@ -164,7 +165,6 @@ 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,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);
|
||||
@ -196,8 +198,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);
|
||||
@ -210,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 *);
|
||||
@ -219,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);
|
||||
@ -233,18 +238,15 @@ 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 const char dwmdir[] = "dwm";
|
||||
static const char localshare[] = ".local/share";
|
||||
static char stext[1024];
|
||||
static char stext[256];
|
||||
static int screen;
|
||||
static int sw, sh; /* X display screen geometry width, height */
|
||||
static int bh, blw = 0; /* bar geometry */
|
||||
@ -439,15 +441,9 @@ buttonpress(XEvent *e)
|
||||
}
|
||||
if (ev->window == selmon->barwin) {
|
||||
i = x = 0;
|
||||
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;
|
||||
do
|
||||
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;
|
||||
@ -498,7 +494,7 @@ cleanup(void)
|
||||
cleanupmon(mons);
|
||||
for (i = 0; i < CurLast; i++)
|
||||
drw_cur_free(drw, cursor[i]);
|
||||
for (i = 0; i < LENGTH(colors) + 1; i++)
|
||||
for (i = 0; i < LENGTH(colors); i++)
|
||||
free(scheme[i]);
|
||||
XDestroyWindow(dpy, wmcheckwin);
|
||||
drw_free(drw);
|
||||
@ -518,8 +514,10 @@ 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);
|
||||
}
|
||||
free(mon);
|
||||
}
|
||||
|
||||
@ -581,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);
|
||||
@ -652,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);
|
||||
@ -662,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
|
||||
@ -706,117 +710,12 @@ 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;
|
||||
@ -828,7 +727,9 @@ drawbar(Monitor *m)
|
||||
|
||||
/* draw status first so it can be overdrawn by tags later */
|
||||
if (m == selmon) { /* status is only drawn on selected monitor */
|
||||
tw = m->ww - drawstatusbar(m, bh, stext);
|
||||
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);
|
||||
}
|
||||
|
||||
for (c = m->clients; c; c = c->next) {
|
||||
@ -838,12 +739,13 @@ 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);
|
||||
@ -1198,6 +1100,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)
|
||||
{
|
||||
@ -1218,7 +1159,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);
|
||||
}
|
||||
|
||||
@ -1502,83 +1445,6 @@ 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)
|
||||
{
|
||||
@ -1591,7 +1457,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 */
|
||||
@ -1606,6 +1474,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)
|
||||
{
|
||||
@ -1744,7 +1635,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);
|
||||
@ -1766,8 +1657,7 @@ setup(void)
|
||||
cursor[CurResize] = drw_cur_create(drw, XC_sizing);
|
||||
cursor[CurMove] = drw_cur_create(drw, XC_fleur);
|
||||
/* init appearance */
|
||||
scheme = ecalloc(LENGTH(colors) + 1, sizeof(Clr *));
|
||||
scheme[LENGTH(colors)] = drw_scm_create(drw, colors[0], 3);
|
||||
scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
|
||||
for (i = 0; i < LENGTH(colors); i++)
|
||||
scheme[i] = drw_scm_create(drw, colors[i], 3);
|
||||
/* init bars */
|
||||
@ -1794,6 +1684,7 @@ setup(void)
|
||||
XSelectInput(dpy, root, wa.event_mask);
|
||||
grabkeys();
|
||||
focus(NULL);
|
||||
spawnbar();
|
||||
}
|
||||
|
||||
|
||||
@ -1852,6 +1743,13 @@ spawn(const Arg *arg)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
spawnbar()
|
||||
{
|
||||
if (*altbarcmd)
|
||||
system(altbarcmd);
|
||||
}
|
||||
|
||||
void
|
||||
tag(const Arg *arg)
|
||||
{
|
||||
@ -1901,9 +1799,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);
|
||||
}
|
||||
|
||||
@ -1986,10 +1893,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))) {
|
||||
@ -1997,12 +1935,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,
|
||||
@ -2028,11 +1972,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
|
||||
@ -2269,13 +2213,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. */
|
||||
@ -2344,7 +2310,6 @@ main(int argc, char *argv[])
|
||||
die("pledge");
|
||||
#endif /* __OpenBSD__ */
|
||||
scan();
|
||||
runautostart();
|
||||
run();
|
||||
cleanup();
|
||||
XCloseDisplay(dpy);
|
||||
|
48
movestack.c
48
movestack.c
@ -1,48 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user