Compare commits

...

15 Commits
main ... config

6 changed files with 476 additions and 101 deletions

View File

@ -1,25 +1,55 @@
/* See LICENSE file for copyright and license details. */
/* sEe LICENSE file for copyright and license details. */
/* For media keys */
#include <X11/XF86keysym.h>
/* appearance */
static const unsigned int borderpx = 1; /* border pixel of windows */
static const unsigned int borderpx = 0; /* border pixel of windows */
static const unsigned int snap = 32; /* snap pixel */
static const unsigned int gappih = 10; /* horiz inner gap between windows */
static const unsigned int gappiv = 10; /* vert inner gap between windows */
static const unsigned int gappoh = 10; /* horiz outer gap between windows and screen edge */
static const unsigned int gappov = 10; /* vert outer gap between windows and screen edge */
static const int smartgaps = 0; /* 1 means no outer gap when there is only one window */
static const int showbar = 1; /* 0 means no bar */
static const int topbar = 1; /* 0 means bottom bar */
static const char *fonts[] = { "monospace:size=10" };
static const char dmenufont[] = "monospace:size=10";
static const int vertpad = 10; /* vertical padding of bar */
static const int sidepad = 10; /* horizontal padding of bar */
static const int horizontal_magin = 20; /* horizontal margin of bar */
static const char *fonts[] = { "GoMono Nerd Font:size=10" };
static const char dmenucols[] = "4";
static const char dmenulines[] = "30";
static const char dmenufont[] = "GoMono Nerd Font: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_black[] = "#000000";
static const char col_cyan[] = "#005577";
static const char col_pink_red[] = "#99000f";
static const unsigned int baralpha = 0x0b;
static const unsigned int borderalpha = OPAQUE;
static const char *colors[][3] = {
/* fg bg border */
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
[SchemeSel] = { col_gray4, col_cyan, col_cyan },
[SchemeNorm] = { col_gray3, col_black, col_gray2 },
[SchemeSel] = { col_gray4, col_black, col_gray2 },
};
static const unsigned int alphas[][3] = {
/* fg bg border */
[SchemeNorm] = { OPAQUE, baralpha, borderalpha },
[SchemeSel] = { OPAQUE, baralpha, borderalpha },
};
/* Volume control using amixer */
static const char *upvol[] = { "/home/vtimofei/scripts/volup", NULL };
static const char *downvol[] = { "/home/vtimofei/scripts/voldown", NULL };
static const char *mutevol[] = { "/home/vtimofei/scripts/mutetog", NULL };
static const char *lock_screen[] = { "slock", NULL };
/* tagging */
static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
static const char *tags[] = { "", "", "", "", "", "", "", "", "", };
static const Rule rules[] = {
/* xprop(1):
@ -28,7 +58,14 @@ static const Rule rules[] = {
*/
/* class instance title tags mask isfloating monitor */
{ "Gimp", NULL, NULL, 0, 1, -1 },
{ "Firefox", NULL, NULL, 1 << 8, 0, -1 },
{ "Firefox", NULL, NULL, 1 << 2, 0, -1 },
{ "firefox", NULL, NULL, 1 << 2, 0, -1 },
{ "Slack", NULL, NULL, 1 << 3, 0, -1 },
{ "Microsoft Teams", NULL, NULL, 1 << 4, 0, -1 },
{ "jetbrains-goland", NULL, NULL, 1 << 5, 0, -1 },
{ "jetbrains-pycharm", NULL, NULL, 1 << 6, 0, -1 },
{ "jetbrains-webstorm", NULL, NULL, 1 << 7, 0, -1 },
{ "jetbrains-clion", NULL, NULL, 1 << 8, 0, -1 },
};
/* layout(s) */
@ -44,7 +81,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} }, \
@ -56,12 +93,26 @@ 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 *dmenucmd[] = { "dmenu_run",
"-g", dmenucols,
"-l", dmenulines,
"-m", dmenumon,
"-fn", dmenufont,
"-nb", col_black,
"-nf", col_gray3,
"-sb", col_cyan,
"-sf", col_gray4,
NULL };
static const char *termcmd[] = { "alacritty", NULL };
static const char *togglelang[] = { "/home/vtimofei/scripts/toggle-language", NULL };
static const char *poweroff[] = { "/home/vtimofei/scripts/poweroff", NULL };
static const char *reboot[] = { "/home/vtimofei/scripts/reboot", NULL };
static Key keys[] = {
/* modifier key function argument */
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
{ MODKEY|ShiftMask, XK_p, spawn, {.v = poweroff } },
{ MODKEY|ShiftMask, XK_r, spawn, {.v = reboot } },
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
{ MODKEY, XK_b, togglebar, {0} },
{ MODKEY, XK_j, focusstack, {.i = +1 } },
@ -70,13 +121,30 @@ static Key keys[] = {
{ MODKEY, XK_d, incnmaster, {.i = -1 } },
{ MODKEY, XK_h, setmfact, {.f = -0.05} },
{ MODKEY, XK_l, setmfact, {.f = +0.05} },
{ MODKEY|Mod4Mask, XK_h, incrgaps, {.i = +1 } },
{ MODKEY|Mod4Mask, XK_l, incrgaps, {.i = -1 } },
{ MODKEY|Mod4Mask|ShiftMask, XK_h, incrogaps, {.i = +1 } },
{ MODKEY|Mod4Mask|ShiftMask, XK_l, incrogaps, {.i = -1 } },
{ MODKEY|Mod4Mask|ControlMask, XK_h, incrigaps, {.i = +1 } },
{ MODKEY|Mod4Mask|ControlMask, XK_l, incrigaps, {.i = -1 } },
{ MODKEY|Mod4Mask, XK_0, togglegaps, {0} },
{ MODKEY|Mod4Mask|ShiftMask, XK_0, defaultgaps, {0} },
{ MODKEY, XK_y, incrihgaps, {.i = +1 } },
{ MODKEY, XK_o, incrihgaps, {.i = -1 } },
{ MODKEY|ControlMask, XK_y, incrivgaps, {.i = +1 } },
{ MODKEY|ControlMask, XK_o, incrivgaps, {.i = -1 } },
{ MODKEY|Mod4Mask, XK_y, incrohgaps, {.i = +1 } },
{ MODKEY|Mod4Mask, XK_o, incrohgaps, {.i = -1 } },
{ MODKEY|ShiftMask, XK_y, incrovgaps, {.i = +1 } },
{ MODKEY|ShiftMask, XK_o, incrovgaps, {.i = -1 } },
{ MODKEY, XK_Return, zoom, {0} },
{ MODKEY, XK_Tab, view, {0} },
{ MODKEY|ShiftMask, XK_c, killclient, {0} },
{ MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
{ MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
{ MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
{ MODKEY, XK_space, setlayout, {0} },
{ MODKEY, XK_z, setlayout, {0} },
{ MODKEY, XK_space, spawn, {.v = togglelang} },
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} },
{ MODKEY, XK_0, view, {.ui = ~0 } },
{ MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
@ -94,6 +162,11 @@ static Key keys[] = {
TAGKEYS( XK_8, 7)
TAGKEYS( XK_9, 8)
{ MODKEY|ShiftMask, XK_q, quit, {0} },
{ MODKEY|ShiftMask, XK_l, spawn, {.v = lock_screen } },
/* Volume control */
{ 0, XF86XK_AudioLowerVolume, spawn, {.v = downvol } },
{ 0, XF86XK_AudioMute, spawn, {.v = mutevol } },
{ 0, XF86XK_AudioRaiseVolume, spawn, {.v = upvol } },
};
/* button definitions */

View File

@ -22,7 +22,7 @@ FREETYPEINC = /usr/include/freetype2
# includes and libs
INCS = -I${X11INC} -I${FREETYPEINC}
LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lXrender
# flags
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}

26
drw.c
View File

@ -61,7 +61,7 @@ utf8decode(const char *c, long *u, size_t clen)
}
Drw *
drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap)
{
Drw *drw = ecalloc(1, sizeof(Drw));
@ -70,8 +70,11 @@ drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h
drw->root = root;
drw->w = w;
drw->h = h;
drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
drw->gc = XCreateGC(dpy, root, 0, NULL);
drw->visual = visual;
drw->depth = depth;
drw->cmap = cmap;
drw->drawable = XCreatePixmap(dpy, root, w, h, depth);
drw->gc = XCreateGC(dpy, drw->drawable, 0, NULL);
XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
return drw;
@ -87,7 +90,7 @@ drw_resize(Drw *drw, unsigned int w, unsigned int h)
drw->h = h;
if (drw->drawable)
XFreePixmap(drw->dpy, drw->drawable);
drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen));
drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, drw->depth);
}
void
@ -194,21 +197,22 @@ drw_fontset_free(Fnt *font)
}
void
drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
drw_clr_create(Drw *drw, Clr *dest, const char *clrname, unsigned int alpha)
{
if (!drw || !dest || !clrname)
return;
if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
DefaultColormap(drw->dpy, drw->screen),
if (!XftColorAllocName(drw->dpy, drw->visual, drw->cmap,
clrname, dest))
die("error, cannot allocate color '%s'", clrname);
dest->pixel = (dest->pixel & 0x00ffffffU) | (alpha << 24);
}
/* Wrapper to create color schemes. The caller has to call free(3) on the
* returned color scheme when done using it. */
Clr *
drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
drw_scm_create(Drw *drw, const char *clrnames[], const unsigned int alphas[], size_t clrcount)
{
size_t i;
Clr *ret;
@ -218,7 +222,7 @@ drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
return NULL;
for (i = 0; i < clrcount; i++)
drw_clr_create(drw, &ret[i], clrnames[i]);
drw_clr_create(drw, &ret[i], clrnames[i], alphas[i]);
return ret;
}
@ -274,9 +278,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
} else {
XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
d = XftDrawCreate(drw->dpy, drw->drawable,
DefaultVisual(drw->dpy, drw->screen),
DefaultColormap(drw->dpy, drw->screen));
d = XftDrawCreate(drw->dpy, drw->drawable, drw->visual, drw->cmap);
x += lpad;
w -= lpad;
}

9
drw.h
View File

@ -20,6 +20,9 @@ typedef struct {
Display *dpy;
int screen;
Window root;
Visual *visual;
unsigned int depth;
Colormap cmap;
Drawable drawable;
GC gc;
Clr *scheme;
@ -27,7 +30,7 @@ typedef struct {
} Drw;
/* Drawable abstraction */
Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h);
Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap);
void drw_resize(Drw *drw, unsigned int w, unsigned int h);
void drw_free(Drw *drw);
@ -38,8 +41,8 @@ unsigned int drw_fontset_getwidth(Drw *drw, const char *text);
void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h);
/* Colorscheme abstraction */
void drw_clr_create(Drw *drw, Clr *dest, const char *clrname);
Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount);
void drw_clr_create(Drw *drw, Clr *dest, const char *clrname, unsigned int alpha);
Clr *drw_scm_create(Drw *drw, const char *clrnames[], const unsigned int alphas[], size_t clrcount);
/* Cursor abstraction */
Cur *drw_cur_create(Drw *drw, int shape);

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.

332
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>
@ -57,6 +58,8 @@
#define TAGMASK ((1 << LENGTH(tags)) - 1)
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
#define OPAQUE 0xffU
/* enums */
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
enum { SchemeNorm, SchemeSel }; /* color schemes */
@ -119,6 +122,10 @@ struct Monitor {
int by; /* bar geometry */
int mx, my, mw, mh; /* screen size */
int wx, wy, ww, wh; /* window area */
int gappih; /* horizontal gap between windows */
int gappiv; /* vertical gap between windows */
int gappoh; /* horizontal outer gaps */
int gappov; /* vertical outer gaps */
unsigned int seltags;
unsigned int sellt;
unsigned int tagset[2];
@ -194,12 +201,23 @@ 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);
static void setclientstate(Client *c, long state);
static void setfocus(Client *c);
static void setfullscreen(Client *c, int fullscreen);
static void setgaps(int oh, int ov, int ih, int iv);
static void incrgaps(const Arg *arg);
static void incrigaps(const Arg *arg);
static void incrogaps(const Arg *arg);
static void incrohgaps(const Arg *arg);
static void incrovgaps(const Arg *arg);
static void incrihgaps(const Arg *arg);
static void incrivgaps(const Arg *arg);
static void togglegaps(const Arg *arg);
static void defaultgaps(const Arg *arg);
static void setlayout(const Arg *arg);
static void setmfact(const Arg *arg);
static void setup(void);
@ -233,15 +251,23 @@ static Monitor *wintomon(Window w);
static int xerror(Display *dpy, XErrorEvent *ee);
static int xerrordummy(Display *dpy, XErrorEvent *ee);
static int xerrorstart(Display *dpy, XErrorEvent *ee);
static void xinitvisual();
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 */
static int bh, blw = 0; /* bar geometry */
static int enablegaps = 1; /* enables gaps, used by togglegaps */
static int lrpad; /* sum of left and right padding for text */
static int vp; /* vertical padding for bar */
static int sp; /* side padding for bar */
static int (*xerrorxlib)(Display *, XErrorEvent *);
static unsigned int numlockmask = 0;
static void (*handler[LASTEvent]) (XEvent *) = {
@ -269,6 +295,11 @@ static Drw *drw;
static Monitor *mons, *selmon;
static Window root, wmcheckwin;
static int useargb = 0;
static Visual *visual;
static int depth;
static Colormap cmap;
/* configuration, allows nested code to access above variables */
#include "config.h"
@ -568,7 +599,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 + sp, m->by + vp, m->ww - 2 * sp, bh);
}
focus(NULL);
arrange(NULL);
@ -639,6 +670,10 @@ createmon(void)
m->nmaster = nmaster;
m->showbar = showbar;
m->topbar = topbar;
m->gappih = gappih;
m->gappiv = gappiv;
m->gappoh = gappoh;
m->gappov = gappov;
m->lt[0] = &layouts[0];
m->lt[1] = &layouts[1 % LENGTH(layouts)];
strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
@ -702,11 +737,17 @@ drawbar(Monitor *m)
unsigned int i, occ = 0, urg = 0;
Client *c;
/* Draw margins */
char* empty = "";
drw_setscheme(drw, scheme[SchemeNorm]);
drw_text(drw, 0, 0, horizontal_magin, bh, 0, empty, 0);
drw_text(drw, m->ww - 2 * sp - horizontal_magin, 0, horizontal_magin, bh, 0, empty, 0);
/* 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]);
drw_setscheme(drw, scheme[SchemeSel]);
tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
drw_text(drw, m->ww - tw - 2 * sp -horizontal_magin, 0, tw, bh, 0, stext, 0);
}
for (c = m->clients; c; c = c->next) {
@ -718,26 +759,26 @@ drawbar(Monitor *m)
for (i = 0; i < LENGTH(tags); i++) {
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);
drw_text(drw, x + horizontal_magin, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i);
if (occ & 1 << i)
drw_rect(drw, x + boxs, boxs, boxw, boxw,
drw_rect(drw, x + boxs + horizontal_magin, boxs, boxw, boxw,
m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
urg & 1 << i);
x += w;
}
w = blw = TEXTW(m->ltsymbol);
drw_setscheme(drw, scheme[SchemeNorm]);
x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
x = drw_text(drw, x + horizontal_magin, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
if ((w = m->ww - tw - x) > bh) {
if (m->sel) {
drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
drw_text(drw, x, 0, w - 2 * sp - horizontal_magin, bh, lrpad / 2, m->sel->name, 0);
if (m->sel->isfloating)
drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0);
} else {
drw_setscheme(drw, scheme[SchemeNorm]);
drw_rect(drw, x, 0, w, bh, 1, 1);
drw_rect(drw, x, 0, w - 2 * sp - horizontal_magin, bh, 1, 1);
}
}
drw_map(drw, m->barwin, 0, 0, m->ww, bh);
@ -1381,6 +1422,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)
{
@ -1498,6 +1616,111 @@ setfullscreen(Client *c, int fullscreen)
}
}
void
setgaps(int oh, int ov, int ih, int iv)
{
if (oh < 0) oh = 0;
if (ov < 0) ov = 0;
if (ih < 0) ih = 0;
if (iv < 0) iv = 0;
selmon->gappoh = oh;
selmon->gappov = ov;
selmon->gappih = ih;
selmon->gappiv = iv;
arrange(selmon);
}
void
togglegaps(const Arg *arg)
{
enablegaps = !enablegaps;
arrange(selmon);
}
void
defaultgaps(const Arg *arg)
{
setgaps(gappoh, gappov, gappih, gappiv);
}
void
incrgaps(const Arg *arg)
{
setgaps(
selmon->gappoh + arg->i,
selmon->gappov + arg->i,
selmon->gappih + arg->i,
selmon->gappiv + arg->i
);
}
void
incrigaps(const Arg *arg)
{
setgaps(
selmon->gappoh,
selmon->gappov,
selmon->gappih + arg->i,
selmon->gappiv + arg->i
);
}
void
incrogaps(const Arg *arg)
{
setgaps(
selmon->gappoh + arg->i,
selmon->gappov + arg->i,
selmon->gappih,
selmon->gappiv
);
}
void
incrohgaps(const Arg *arg)
{
setgaps(
selmon->gappoh + arg->i,
selmon->gappov,
selmon->gappih,
selmon->gappiv
);
}
void
incrovgaps(const Arg *arg)
{
setgaps(
selmon->gappoh,
selmon->gappov + arg->i,
selmon->gappih,
selmon->gappiv
);
}
void
incrihgaps(const Arg *arg)
{
setgaps(
selmon->gappoh,
selmon->gappov,
selmon->gappih + arg->i,
selmon->gappiv
);
}
void
incrivgaps(const Arg *arg)
{
setgaps(
selmon->gappoh,
selmon->gappov,
selmon->gappih,
selmon->gappiv + arg->i
);
}
void
setlayout(const Arg *arg)
{
@ -1542,12 +1765,16 @@ setup(void)
sw = DisplayWidth(dpy, screen);
sh = DisplayHeight(dpy, screen);
root = RootWindow(dpy, screen);
drw = drw_create(dpy, screen, root, sw, sh);
xinitvisual();
drw = drw_create(dpy, screen, root, sw, sh, visual, depth, cmap);
if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
die("no fonts could be loaded.");
lrpad = drw->fonts->h;
bh = drw->fonts->h + 2;
updategeom();
sp = sidepad;
vp = (topbar == 1) ? vertpad : - vertpad;
/* init atoms */
utf8string = XInternAtom(dpy, "UTF8_STRING", False);
wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
@ -1570,10 +1797,11 @@ setup(void)
/* init appearance */
scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
for (i = 0; i < LENGTH(colors); i++)
scheme[i] = drw_scm_create(drw, colors[i], 3);
scheme[i] = drw_scm_create(drw, colors[i], alphas[i], 3);
/* init bars */
updatebars();
updatestatus();
updatebarpos(selmon);
/* supporting window for NetWMCheck */
wmcheckwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0);
XChangeProperty(dpy, wmcheckwin, netatom[NetWMCheck], XA_WINDOW, 32,
@ -1674,28 +1902,34 @@ tagmon(const Arg *arg)
void
tile(Monitor *m)
{
unsigned int i, n, h, mw, my, ty;
unsigned int i, n, h, r, oe = enablegaps, ie = enablegaps, mw, my, ty;
Client *c;
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
if (n == 0)
return;
if (smartgaps == n) {
oe = 0; // outer gaps disabled
}
if (n > m->nmaster)
mw = m->nmaster ? m->ww * m->mfact : 0;
mw = m->nmaster ? (m->ww + m->gappiv*ie) * m->mfact : 0;
else
mw = m->ww;
for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
mw = m->ww - 2*m->gappov*oe + m->gappiv*ie;
for (i = 0, my = ty = m->gappoh*oe, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
if (i < m->nmaster) {
h = (m->wh - my) / (MIN(n, m->nmaster) - i);
resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0);
r = MIN(n, m->nmaster) - i;
h = (m->wh - my - m->gappoh*oe - m->gappih*ie * (r - 1)) / r;
resize(c, m->wx + m->gappov*oe, m->wy + my, mw - (2*c->bw) - m->gappiv*ie, h - (2*c->bw), 0);
if (my + HEIGHT(c) < m->wh)
my += HEIGHT(c);
my += HEIGHT(c) + m->gappih*ie;
} else {
h = (m->wh - ty) / (n - i);
resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0);
r = n - i;
h = (m->wh - ty - m->gappoh*oe - m->gappih*ie * (r - 1)) / r;
resize(c, m->wx + mw + m->gappov*oe, m->wy + ty, m->ww - mw - (2*c->bw) - 2*m->gappov*oe, h - (2*c->bw), 0);
if (ty + HEIGHT(c) < m->wh)
ty += HEIGHT(c);
ty += HEIGHT(c) + m->gappih*ie;
}
}
@ -1704,7 +1938,7 @@ togglebar(const Arg *arg)
{
selmon->showbar = !selmon->showbar;
updatebarpos(selmon);
XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
XMoveResizeWindow(dpy, selmon->barwin, selmon->wx + sp, selmon->by + vp, selmon->ww - 2 * sp, bh);
arrange(selmon);
}
@ -1807,16 +2041,18 @@ updatebars(void)
Monitor *m;
XSetWindowAttributes wa = {
.override_redirect = True,
.background_pixmap = ParentRelative,
.background_pixel = 0,
.border_pixel = 0,
.colormap = cmap,
.event_mask = ButtonPressMask|ExposureMask
};
XClassHint ch = {"dwm", "dwm"};
for (m = mons; m; m = m->next) {
if (m->barwin)
continue;
m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
CopyFromParent, DefaultVisual(dpy, screen),
CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
m->barwin = XCreateWindow(dpy, root, m->wx + sp, m->by + vp, m->ww - 2 * sp, bh, 0, depth,
InputOutput, visual,
CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa);
XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
XMapRaised(dpy, m->barwin);
XSetClassHint(dpy, m->barwin, &ch);
@ -1829,11 +2065,11 @@ updatebarpos(Monitor *m)
m->wy = m->my;
m->wh = m->mh;
if (m->showbar) {
m->wh -= bh;
m->by = m->topbar ? m->wy : m->wy + m->wh;
m->wy = m->topbar ? m->wy + bh : m->wy;
m->wh = m->wh - vertpad - bh;
m->by = m->topbar ? m->wy : m->wy + m->wh + vertpad;
m->wy = m->topbar ? m->wy + bh + vp : m->wy;
} else
m->by = -bh;
m->by = -bh - vp;
}
void
@ -2113,6 +2349,43 @@ xerrorstart(Display *dpy, XErrorEvent *ee)
return -1;
}
void
xinitvisual()
{
XVisualInfo *infos;
XRenderPictFormat *fmt;
int nitems;
int i;
XVisualInfo tpl = {
.screen = screen,
.depth = 32,
.class = TrueColor
};
long masks = VisualScreenMask | VisualDepthMask | VisualClassMask;
infos = XGetVisualInfo(dpy, masks, &tpl, &nitems);
visual = NULL;
for(i = 0; i < nitems; i ++) {
fmt = XRenderFindVisualFormat(dpy, infos[i].visual);
if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) {
visual = infos[i].visual;
depth = infos[i].depth;
cmap = XCreateColormap(dpy, root, visual, AllocNone);
useargb = 1;
break;
}
}
XFree(infos);
if (! visual) {
visual = DefaultVisual(dpy, screen);
depth = DefaultDepth(dpy, screen);
cmap = DefaultColormap(dpy, screen);
}
}
void
zoom(const Arg *arg)
{
@ -2145,6 +2418,7 @@ main(int argc, char *argv[])
die("pledge");
#endif /* __OpenBSD__ */
scan();
runautostart();
run();
cleanup();
XCloseDisplay(dpy);