Compare commits
23 Commits
abab8fa1e2
...
441a8d1377
Author | SHA1 | Date | |
---|---|---|---|
441a8d1377 | |||
9a36cf50bb | |||
76c8899f89 | |||
281be69e37 | |||
d5b6c33917 | |||
96763b39fd | |||
7593a8515e | |||
2a78be05c0 | |||
92a69e5b0a | |||
6267613b37 | |||
55e73d314b | |||
b5d22bd962 | |||
2e2c9d12fa | |||
681199d175 | |||
62af801ea4 | |||
2944e7dec6 | |||
49f6cb939f | |||
b6089785c7 | |||
241f837e6b | |||
41e4daf644 | |||
|
cfb8627a80 | ||
|
fcb2476b69 | ||
|
8933ebcf50 |
71
config.def.h
71
config.def.h
@ -5,8 +5,9 @@ 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 char *fonts[] = { "monospace:size=10" };
|
||||
static const char dmenufont[] = "monospace:size=10";
|
||||
static const int focusonwheel = 0;
|
||||
static const char *fonts[] = { "Liberation Sans:style=regular:size=14:antialias=true:autohint=true", "Font Awesome 6 Free Regular:size=14:antialias=true:autohint=true", "Font Awesome 6 Brands:size=14:antialias=true:autohint=true", "Font Awesome 6 Free Solid:size=14:antialias=true:autohint=true" };
|
||||
static const char dmenufont[] = "Liberation Mono:size=14";
|
||||
static const char col_gray1[] = "#222222";
|
||||
static const char col_gray2[] = "#444444";
|
||||
static const char col_gray3[] = "#bbbbbb";
|
||||
@ -19,7 +20,7 @@ static const char *colors[][3] = {
|
||||
};
|
||||
|
||||
/* tagging */
|
||||
static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
|
||||
static const char *tags[] = { "", "", "", "", "", "", "7", "8", "" };
|
||||
|
||||
static const Rule rules[] = {
|
||||
/* xprop(1):
|
||||
@ -28,9 +29,24 @@ static const Rule rules[] = {
|
||||
*/
|
||||
/* class instance title tags mask isfloating monitor */
|
||||
{ "Gimp", NULL, NULL, 0, 1, -1 },
|
||||
{ "Firefox", NULL, NULL, 1 << 8, 0, -1 },
|
||||
{ "Pale moon", "Navigator", NULL, 2, 0, -1 },
|
||||
{ "Pale moon", "Browser", NULL, 2, 1, -1 },
|
||||
{ "Pale moon", "Places", NULL, 2, 1, -1 },
|
||||
{ "Pale moon", "Toplevel", NULL, 2, 1, -1 },
|
||||
{ "Pale moon", "Devtools", NULL, 2, 1, -1 },
|
||||
{ "Pale moon", "DTA", NULL, 2, 1, -1 },
|
||||
{ "Pale moon", "Global", NULL, 2, 1, -1 },
|
||||
{ "Chromium-browser-chromium", "chromium-browser-chromium", NULL, 1<<5, 0, -1 },
|
||||
{ "TelegramDesktop", "telegram-desktop", "Media viewer", 0, 1, -1 },
|
||||
{ "TelegramDesktop", "telegram-desktop", NULL, 4, 0, -1 },
|
||||
{ "keepassxc", "KeePassXC", NULL, 0, 1, -1 },
|
||||
{ "mpv", NULL, NULL, 1<<3, 0, -1 },
|
||||
{ "floatalsamxr", NULL, NULL, 0, 1, -1 },
|
||||
{ "QjackCtl", "qjackctl", NULL, 0, 1, -1 },
|
||||
{ "Nextcloud", "nextcloud", NULL, 0, 1, -1 },
|
||||
};
|
||||
|
||||
#include "layouts.c"
|
||||
/* layout(s) */
|
||||
static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
|
||||
static const int nmaster = 1; /* number of clients in master area */
|
||||
@ -42,10 +58,11 @@ static const Layout layouts[] = {
|
||||
{ "[]=", tile }, /* first entry is default */
|
||||
{ "><>", NULL }, /* no layout function means floating behavior */
|
||||
{ "[M]", monocle },
|
||||
{ "HHH", grid },
|
||||
};
|
||||
|
||||
/* 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} }, \
|
||||
@ -55,15 +72,44 @@ static const Layout layouts[] = {
|
||||
/* helper for spawning shell commands in the pre dwm-5.0 fashion */
|
||||
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
|
||||
|
||||
#include <X11/XF86keysym.h>
|
||||
|
||||
/* 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", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
|
||||
static const char *termcmd[] = { "st", NULL };
|
||||
/* alsa volume control */
|
||||
static const char *alsacmd[] = { "st", "-c", "floatalsamxr", "-e", "alsamixer", NULL };
|
||||
static const char *upvol[] = { "amixer", "set", "Master", "2+", NULL };
|
||||
static const char *downvol[] = { "amixer", "set", "Master", "2-", NULL };
|
||||
/* alsa muting/unmuting */
|
||||
static const char *mute[] = { "amixer", "-q", "set", "Master", "toggle", NULL };
|
||||
/* screenshot tools */
|
||||
static const char *scrallcmd[] = { "/home/kurk/sources/scripts/prtscr/prtscra.sh", NULL };
|
||||
static const char *scrcurcmd[] = { "/home/kurk/sources/scripts/prtscr/prtscrcr.sh", NULL };
|
||||
static const char *scrselcmd[] = { "/home/kurk/sources/scripts/prtscr/prtscrsel.sh", NULL };
|
||||
/* browsers */
|
||||
static const char *palemooncmd[] = { "palemoon", NULL };
|
||||
static const char *chromiumcmd[] = { "chromium", NULL };
|
||||
static const char *nextcloudcmd[] = { "nextcloud", NULL };
|
||||
static const char *xfecmd[] = { "xfe", NULL };
|
||||
static const char *keepassxccmd[] = { "keepassxc", NULL };
|
||||
|
||||
static const Key keys[] = {
|
||||
/* modifier key function argument */
|
||||
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
|
||||
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
|
||||
{ 0, XF86XK_AudioRaiseVolume, spawn, {.v = upvol } },
|
||||
{ 0, XF86XK_AudioLowerVolume, spawn, {.v = downvol } },
|
||||
{ 0, XF86XK_AudioMute, spawn, {.v = mute } },
|
||||
{ 0, XK_Print, spawn, {.v = scrallcmd } },
|
||||
{ ShiftMask, XK_Print, spawn, {.v = scrcurcmd } },
|
||||
{ ControlMask, XK_Print, spawn, {.v = scrselcmd } },
|
||||
{ MODKEY, XK_s, spawn, {.v = palemooncmd } },
|
||||
{ MODKEY, XK_n, spawn, {.v = nextcloudcmd } },
|
||||
{ MODKEY, XK_c, spawn, {.v = chromiumcmd } },
|
||||
{ MODKEY|ShiftMask, XK_x, spawn, {.v = xfecmd } },
|
||||
{ MODKEY, XK_x, spawn, {.v = keepassxccmd } },
|
||||
{ MODKEY, XK_b, togglebar, {0} },
|
||||
{ MODKEY, XK_j, focusstack, {.i = +1 } },
|
||||
{ MODKEY, XK_k, focusstack, {.i = -1 } },
|
||||
@ -77,14 +123,24 @@ static const Key keys[] = {
|
||||
{ MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
|
||||
{ MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
|
||||
{ MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
|
||||
{ MODKEY, XK_g, setlayout, {.v = &layouts[3]} },
|
||||
{ MODKEY, XK_space, setlayout, {0} },
|
||||
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} },
|
||||
{ MODKEY|ShiftMask, XK_f, togglefullscr, {0} },
|
||||
{ MODKEY, XK_0, view, {.ui = ~0 } },
|
||||
{ MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
|
||||
{ MODKEY, XK_comma, focusmon, {.i = -1 } },
|
||||
{ MODKEY, XK_period, focusmon, {.i = +1 } },
|
||||
{ MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
|
||||
{ MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
|
||||
{ MODKEY|ControlMask, XK_l, movekeyboard_x, {.i = 20}},
|
||||
{ MODKEY|ControlMask, XK_h, movekeyboard_x, {.i = -20}},
|
||||
{ MODKEY|ControlMask, XK_j, movekeyboard_y, {.i = 20}},
|
||||
{ MODKEY|ControlMask, XK_k, movekeyboard_y, {.i = -20}},
|
||||
{ MODKEY, XK_Right, viewnext, {0} },
|
||||
{ MODKEY, XK_Left, viewprev, {0} },
|
||||
{ MODKEY|ShiftMask, XK_Right, tagtonext, {0} },
|
||||
{ MODKEY|ShiftMask, XK_Left, tagtoprev, {0} },
|
||||
TAGKEYS( XK_1, 0)
|
||||
TAGKEYS( XK_2, 1)
|
||||
TAGKEYS( XK_3, 2)
|
||||
@ -105,6 +161,7 @@ static const Button buttons[] = {
|
||||
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
|
||||
{ ClkWinTitle, 0, Button2, zoom, {0} },
|
||||
{ ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
|
||||
{ ClkStatusText, 0, Button1, spawn, {.v = alsacmd } },
|
||||
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
|
||||
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} },
|
||||
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} },
|
||||
|
@ -4,11 +4,11 @@ VERSION = 6.5
|
||||
# Customize below to fit your system
|
||||
|
||||
# paths
|
||||
PREFIX = /usr/local
|
||||
PREFIX = /usr
|
||||
MANPREFIX = ${PREFIX}/share/man
|
||||
|
||||
X11INC = /usr/X11R6/include
|
||||
X11LIB = /usr/X11R6/lib
|
||||
X11INC = /usr/include/X11
|
||||
X11LIB = /usr/lib64
|
||||
|
||||
# Xinerama, comment if you don't want it
|
||||
XINERAMALIBS = -lXinerama
|
||||
|
116
drw.c
116
drw.c
@ -9,54 +9,40 @@
|
||||
#include "util.h"
|
||||
|
||||
#define UTF_INVALID 0xFFFD
|
||||
#define UTF_SIZ 4
|
||||
|
||||
static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
|
||||
static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
|
||||
static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
|
||||
static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
|
||||
|
||||
static long
|
||||
utf8decodebyte(const char c, size_t *i)
|
||||
static int
|
||||
utf8decode(const char *s_in, long *u, int *err)
|
||||
{
|
||||
for (*i = 0; *i < (UTF_SIZ + 1); ++(*i))
|
||||
if (((unsigned char)c & utfmask[*i]) == utfbyte[*i])
|
||||
return (unsigned char)c & ~utfmask[*i];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t
|
||||
utf8validate(long *u, size_t i)
|
||||
{
|
||||
if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF))
|
||||
*u = UTF_INVALID;
|
||||
for (i = 1; *u > utfmax[i]; ++i)
|
||||
;
|
||||
return i;
|
||||
}
|
||||
|
||||
static size_t
|
||||
utf8decode(const char *c, long *u, size_t clen)
|
||||
{
|
||||
size_t i, j, len, type;
|
||||
long udecoded;
|
||||
static const unsigned char lens[] = {
|
||||
/* 0XXXX */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
/* 10XXX */ 0, 0, 0, 0, 0, 0, 0, 0, /* invalid */
|
||||
/* 110XX */ 2, 2, 2, 2,
|
||||
/* 1110X */ 3, 3,
|
||||
/* 11110 */ 4,
|
||||
/* 11111 */ 0, /* invalid */
|
||||
};
|
||||
static const unsigned char leading_mask[] = { 0x7F, 0x1F, 0x0F, 0x07 };
|
||||
static const unsigned int overlong[] = { 0x0, 0x80, 0x0800, 0x10000 };
|
||||
|
||||
const unsigned char *s = (const unsigned char *)s_in;
|
||||
int len = lens[*s >> 3];
|
||||
*u = UTF_INVALID;
|
||||
if (!clen)
|
||||
return 0;
|
||||
udecoded = utf8decodebyte(c[0], &len);
|
||||
if (!BETWEEN(len, 1, UTF_SIZ))
|
||||
*err = 1;
|
||||
if (len == 0)
|
||||
return 1;
|
||||
for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
|
||||
udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type);
|
||||
if (type)
|
||||
return j;
|
||||
}
|
||||
if (j < len)
|
||||
return 0;
|
||||
*u = udecoded;
|
||||
utf8validate(u, len);
|
||||
|
||||
long cp = s[0] & leading_mask[len - 1];
|
||||
for (int i = 1; i < len; ++i) {
|
||||
if (s[i] == '\0' || (s[i] & 0xC0) != 0x80)
|
||||
return i;
|
||||
cp = (cp << 6) | (s[i] & 0x3F);
|
||||
}
|
||||
/* out of range, surrogate, overlong encoding */
|
||||
if (cp > 0x10FFFF || (cp >> 11) == 0x1B || cp < overlong[len - 1])
|
||||
return len;
|
||||
|
||||
*err = 0;
|
||||
*u = cp;
|
||||
return len;
|
||||
}
|
||||
|
||||
@ -238,11 +224,11 @@ drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int
|
||||
int
|
||||
drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert)
|
||||
{
|
||||
int i, ty, ellipsis_x = 0;
|
||||
unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len;
|
||||
int ty, ellipsis_x = 0;
|
||||
unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len, hash, h0, h1;
|
||||
XftDraw *d = NULL;
|
||||
Fnt *usedfont, *curfont, *nextfont;
|
||||
int utf8strlen, utf8charlen, render = x || y || w || h;
|
||||
int utf8strlen, utf8charlen, utf8err, render = x || y || w || h;
|
||||
long utf8codepoint = 0;
|
||||
const char *utf8str;
|
||||
FcCharSet *fccharset;
|
||||
@ -251,9 +237,8 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
||||
XftResult result;
|
||||
int charexists = 0, overflow = 0;
|
||||
/* keep track of a couple codepoints for which we have no match. */
|
||||
enum { nomatches_len = 64 };
|
||||
static struct { long codepoint[nomatches_len]; unsigned int idx; } nomatches;
|
||||
static unsigned int ellipsis_width = 0;
|
||||
static unsigned int nomatches[128], ellipsis_width, invalid_width;
|
||||
static const char invalid[] = "<EFBFBD>";
|
||||
|
||||
if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts)
|
||||
return 0;
|
||||
@ -263,6 +248,8 @@ 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);
|
||||
if (w < lpad)
|
||||
return x + w;
|
||||
d = XftDrawCreate(drw->dpy, drw->drawable,
|
||||
DefaultVisual(drw->dpy, drw->screen),
|
||||
DefaultColormap(drw->dpy, drw->screen));
|
||||
@ -273,12 +260,14 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
||||
usedfont = drw->fonts;
|
||||
if (!ellipsis_width && render)
|
||||
ellipsis_width = drw_fontset_getwidth(drw, "...");
|
||||
if (!invalid_width && render)
|
||||
invalid_width = drw_fontset_getwidth(drw, invalid);
|
||||
while (1) {
|
||||
ew = ellipsis_len = utf8strlen = 0;
|
||||
ew = ellipsis_len = utf8err = utf8charlen = utf8strlen = 0;
|
||||
utf8str = text;
|
||||
nextfont = NULL;
|
||||
while (*text) {
|
||||
utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ);
|
||||
utf8charlen = utf8decode(text, &utf8codepoint, &utf8err);
|
||||
for (curfont = drw->fonts; curfont; curfont = curfont->next) {
|
||||
charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
|
||||
if (charexists) {
|
||||
@ -300,9 +289,9 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
||||
else
|
||||
utf8strlen = ellipsis_len;
|
||||
} else if (curfont == usedfont) {
|
||||
utf8strlen += utf8charlen;
|
||||
text += utf8charlen;
|
||||
ew += tmpw;
|
||||
utf8strlen += utf8err ? 0 : utf8charlen;
|
||||
ew += utf8err ? 0 : tmpw;
|
||||
} else {
|
||||
nextfont = curfont;
|
||||
}
|
||||
@ -310,7 +299,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
||||
}
|
||||
}
|
||||
|
||||
if (overflow || !charexists || nextfont)
|
||||
if (overflow || !charexists || nextfont || utf8err)
|
||||
break;
|
||||
else
|
||||
charexists = 0;
|
||||
@ -325,6 +314,12 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
||||
x += ew;
|
||||
w -= ew;
|
||||
}
|
||||
if (utf8err && (!render || invalid_width < w)) {
|
||||
if (render)
|
||||
drw_text(drw, x, y, w, h, 0, invalid, invert);
|
||||
x += invalid_width;
|
||||
w -= invalid_width;
|
||||
}
|
||||
if (render && overflow)
|
||||
drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "...", invert);
|
||||
|
||||
@ -338,11 +333,14 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
||||
* character must be drawn. */
|
||||
charexists = 1;
|
||||
|
||||
for (i = 0; i < nomatches_len; ++i) {
|
||||
/* avoid calling XftFontMatch if we know we won't find a match */
|
||||
if (utf8codepoint == nomatches.codepoint[i])
|
||||
goto no_match;
|
||||
}
|
||||
hash = (unsigned int)utf8codepoint;
|
||||
hash = ((hash >> 16) ^ hash) * 0x21F0AAAD;
|
||||
hash = ((hash >> 15) ^ hash) * 0xD35A2D97;
|
||||
h0 = ((hash >> 15) ^ hash) % LENGTH(nomatches);
|
||||
h1 = (hash >> 17) % LENGTH(nomatches);
|
||||
/* avoid expensive XftFontMatch call when we know we won't find a match */
|
||||
if (nomatches[h0] == utf8codepoint || nomatches[h1] == utf8codepoint)
|
||||
goto no_match;
|
||||
|
||||
fccharset = FcCharSetCreate();
|
||||
FcCharSetAddChar(fccharset, utf8codepoint);
|
||||
@ -371,7 +369,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
||||
curfont->next = usedfont;
|
||||
} else {
|
||||
xfont_free(usedfont);
|
||||
nomatches.codepoint[++nomatches.idx % nomatches_len] = utf8codepoint;
|
||||
nomatches[nomatches[h0] ? h1 : h0] = utf8codepoint;
|
||||
no_match:
|
||||
usedfont = drw->fonts;
|
||||
}
|
||||
|
3
dwm.1
3
dwm.1
@ -116,6 +116,9 @@ Zooms/cycles focused window to/from master area (tiled layouts only).
|
||||
.B Mod1\-Shift\-c
|
||||
Close focused window.
|
||||
.TP
|
||||
.B Mod1\-Shift\-f
|
||||
Toggle fullscreen for focused window.
|
||||
.TP
|
||||
.B Mod1\-Shift\-space
|
||||
Toggle focused window between tiled and floating state.
|
||||
.TP
|
||||
|
282
dwm.c
282
dwm.c
@ -50,7 +50,6 @@
|
||||
#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)
|
||||
#define WIDTH(X) ((X)->w + 2 * (X)->bw)
|
||||
#define HEIGHT(X) ((X)->h + 2 * (X)->bw)
|
||||
@ -163,7 +162,6 @@ static void detachstack(Client *c);
|
||||
static Monitor *dirtomon(int dir);
|
||||
static void drawbar(Monitor *m);
|
||||
static void drawbars(void);
|
||||
static void enternotify(XEvent *e);
|
||||
static void expose(XEvent *e);
|
||||
static void focus(Client *c);
|
||||
static void focusin(XEvent *e);
|
||||
@ -182,10 +180,13 @@ static void manage(Window w, XWindowAttributes *wa);
|
||||
static void mappingnotify(XEvent *e);
|
||||
static void maprequest(XEvent *e);
|
||||
static void monocle(Monitor *m);
|
||||
static void motionnotify(XEvent *e);
|
||||
static void movemouse(const Arg *arg);
|
||||
static void movekeyboard_x(const Arg *arg);
|
||||
static void movekeyboard_y(const Arg *arg);
|
||||
static unsigned int nexttag(void);
|
||||
static Client *nexttiled(Client *c);
|
||||
static void pop(Client *c);
|
||||
static unsigned int prevtag(void);
|
||||
static void propertynotify(XEvent *e);
|
||||
static void quit(const Arg *arg);
|
||||
static Monitor *recttomon(int x, int y, int w, int h);
|
||||
@ -208,9 +209,12 @@ static void showhide(Client *c);
|
||||
static void spawn(const Arg *arg);
|
||||
static void tag(const Arg *arg);
|
||||
static void tagmon(const Arg *arg);
|
||||
static void tagtonext(const Arg *arg);
|
||||
static void tagtoprev(const Arg *arg);
|
||||
static void tile(Monitor *m);
|
||||
static void togglebar(const Arg *arg);
|
||||
static void togglefloating(const Arg *arg);
|
||||
static void togglefullscr(const Arg *arg);
|
||||
static void toggletag(const Arg *arg);
|
||||
static void toggleview(const Arg *arg);
|
||||
static void unfocus(Client *c, int setfocus);
|
||||
@ -227,6 +231,8 @@ static void updatetitle(Client *c);
|
||||
static void updatewindowtype(Client *c);
|
||||
static void updatewmhints(Client *c);
|
||||
static void view(const Arg *arg);
|
||||
static void viewnext(const Arg *arg);
|
||||
static void viewprev(const Arg *arg);
|
||||
static Client *wintoclient(Window w);
|
||||
static Monitor *wintomon(Window w);
|
||||
static int xerror(Display *dpy, XErrorEvent *ee);
|
||||
@ -249,13 +255,11 @@ static void (*handler[LASTEvent]) (XEvent *) = {
|
||||
[ConfigureRequest] = configurerequest,
|
||||
[ConfigureNotify] = configurenotify,
|
||||
[DestroyNotify] = destroynotify,
|
||||
[EnterNotify] = enternotify,
|
||||
[Expose] = expose,
|
||||
[FocusIn] = focusin,
|
||||
[KeyPress] = keypress,
|
||||
[MappingNotify] = mappingnotify,
|
||||
[MapRequest] = maprequest,
|
||||
[MotionNotify] = motionnotify,
|
||||
[PropertyNotify] = propertynotify,
|
||||
[UnmapNotify] = unmapnotify
|
||||
};
|
||||
@ -426,16 +430,23 @@ buttonpress(XEvent *e)
|
||||
|
||||
click = ClkRootWin;
|
||||
/* focus monitor if necessary */
|
||||
if ((m = wintomon(ev->window)) && m != selmon) {
|
||||
if ((m = wintomon(ev->window)) && m != selmon
|
||||
&& (focusonwheel || (ev->button != Button4 && ev->button != Button5))) {
|
||||
unfocus(selmon->sel, 1);
|
||||
selmon = m;
|
||||
focus(NULL);
|
||||
}
|
||||
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;
|
||||
@ -446,8 +457,8 @@ buttonpress(XEvent *e)
|
||||
else
|
||||
click = ClkWinTitle;
|
||||
} else if ((c = wintoclient(ev->window))) {
|
||||
focus(c);
|
||||
restack(selmon);
|
||||
if (focusonwheel || (ev->button != Button4 && ev->button != Button5))
|
||||
focus(c);
|
||||
XAllowEvents(dpy, ReplayPointer, CurrentTime);
|
||||
click = ClkClientWin;
|
||||
}
|
||||
@ -721,13 +732,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 = TEXTW(m->ltsymbol);
|
||||
@ -757,25 +767,6 @@ drawbars(void)
|
||||
drawbar(m);
|
||||
}
|
||||
|
||||
void
|
||||
enternotify(XEvent *e)
|
||||
{
|
||||
Client *c;
|
||||
Monitor *m;
|
||||
XCrossingEvent *ev = &e->xcrossing;
|
||||
|
||||
if ((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root)
|
||||
return;
|
||||
c = wintoclient(ev->window);
|
||||
m = c ? c->mon : wintomon(ev->window);
|
||||
if (m != selmon) {
|
||||
unfocus(selmon->sel, 1);
|
||||
selmon = m;
|
||||
} else if (!c || c == selmon->sel)
|
||||
return;
|
||||
focus(c);
|
||||
}
|
||||
|
||||
void
|
||||
expose(XEvent *e)
|
||||
{
|
||||
@ -1125,23 +1116,6 @@ monocle(Monitor *m)
|
||||
resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0);
|
||||
}
|
||||
|
||||
void
|
||||
motionnotify(XEvent *e)
|
||||
{
|
||||
static Monitor *mon = NULL;
|
||||
Monitor *m;
|
||||
XMotionEvent *ev = &e->xmotion;
|
||||
|
||||
if (ev->window != root)
|
||||
return;
|
||||
if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) {
|
||||
unfocus(selmon->sel, 1);
|
||||
selmon = m;
|
||||
focus(NULL);
|
||||
}
|
||||
mon = m;
|
||||
}
|
||||
|
||||
void
|
||||
movemouse(const Arg *arg)
|
||||
{
|
||||
@ -1202,6 +1176,115 @@ movemouse(const Arg *arg)
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int
|
||||
nexttag(void)
|
||||
{
|
||||
unsigned int seltag = selmon->tagset[selmon->seltags];
|
||||
unsigned int usedtags = 0;
|
||||
Client *c = selmon->clients;
|
||||
|
||||
if (!c)
|
||||
return seltag;
|
||||
|
||||
/* skip vacant tags */
|
||||
do {
|
||||
usedtags |= c->tags;
|
||||
c = c->next;
|
||||
} while (c);
|
||||
|
||||
do {
|
||||
seltag = seltag == (1 << (LENGTH(tags) - 1)) ? 1 : seltag << 1;
|
||||
} while (!(seltag & usedtags));
|
||||
|
||||
return seltag;
|
||||
}
|
||||
|
||||
void
|
||||
movekeyboard_x(const Arg *arg){
|
||||
int ocx, ocy, nx, ny;
|
||||
Client *c;
|
||||
Monitor *m;
|
||||
|
||||
if (!(c = selmon->sel))
|
||||
return;
|
||||
|
||||
if (c->isfullscreen) /* no support moving fullscreen windows by mouse */
|
||||
return;
|
||||
|
||||
restack(selmon);
|
||||
|
||||
ocx = c->x;
|
||||
ocy = c->y;
|
||||
|
||||
nx = ocx + arg->i;
|
||||
ny = ocy;
|
||||
|
||||
if (abs(selmon->wx - nx) < snap)
|
||||
nx = selmon->wx;
|
||||
else if (abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap)
|
||||
nx = selmon->wx + selmon->ww - WIDTH(c);
|
||||
|
||||
if (abs(selmon->wy - ny) < snap)
|
||||
ny = selmon->wy;
|
||||
else if (abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap)
|
||||
ny = selmon->wy + selmon->wh - HEIGHT(c);
|
||||
|
||||
if (!c->isfloating)
|
||||
togglefloating(NULL);
|
||||
|
||||
if (!selmon->lt[selmon->sellt]->arrange || c->isfloating)
|
||||
resize(c, nx, ny, c->w, c->h, 1);
|
||||
|
||||
if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
|
||||
sendmon(c, m);
|
||||
selmon = m;
|
||||
focus(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
movekeyboard_y(const Arg *arg){
|
||||
int ocx, ocy, nx, ny;
|
||||
Client *c;
|
||||
Monitor *m;
|
||||
|
||||
if (!(c = selmon->sel))
|
||||
return;
|
||||
|
||||
if (c->isfullscreen) /* no support moving fullscreen windows by mouse */
|
||||
return;
|
||||
|
||||
restack(selmon);
|
||||
|
||||
ocx = c->x;
|
||||
ocy = c->y;
|
||||
|
||||
nx = ocx;
|
||||
ny = ocy + arg->i;
|
||||
|
||||
if (abs(selmon->wx - nx) < snap)
|
||||
nx = selmon->wx;
|
||||
else if (abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap)
|
||||
nx = selmon->wx + selmon->ww - WIDTH(c);
|
||||
|
||||
if (abs(selmon->wy - ny) < snap)
|
||||
ny = selmon->wy;
|
||||
else if (abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap)
|
||||
ny = selmon->wy + selmon->wh - HEIGHT(c);
|
||||
|
||||
if (!c->isfloating)
|
||||
togglefloating(NULL);
|
||||
|
||||
if (!selmon->lt[selmon->sellt]->arrange || c->isfloating)
|
||||
resize(c, nx, ny, c->w, c->h, 1);
|
||||
|
||||
if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
|
||||
sendmon(c, m);
|
||||
selmon = m;
|
||||
focus(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
Client *
|
||||
nexttiled(Client *c)
|
||||
{
|
||||
@ -1218,6 +1301,28 @@ pop(Client *c)
|
||||
arrange(c->mon);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
prevtag(void)
|
||||
{
|
||||
unsigned int seltag = selmon->tagset[selmon->seltags];
|
||||
unsigned int usedtags = 0;
|
||||
Client *c = selmon->clients;
|
||||
if (!c)
|
||||
return seltag;
|
||||
|
||||
/* skip vacant tags */
|
||||
do {
|
||||
usedtags |= c->tags;
|
||||
c = c->next;
|
||||
} while (c);
|
||||
|
||||
do {
|
||||
seltag = seltag == 1 ? (1 << (LENGTH(tags) - 1)) : seltag >> 1;
|
||||
} while (!(seltag & usedtags));
|
||||
|
||||
return seltag;
|
||||
}
|
||||
|
||||
void
|
||||
propertynotify(XEvent *e)
|
||||
{
|
||||
@ -1301,9 +1406,14 @@ void
|
||||
resizemouse(const Arg *arg)
|
||||
{
|
||||
int ocx, ocy, nw, nh;
|
||||
int ocx2, ocy2, nx, ny;
|
||||
Client *c;
|
||||
Monitor *m;
|
||||
XEvent ev;
|
||||
int horizcorner, vertcorner;
|
||||
int di;
|
||||
unsigned int dui;
|
||||
Window dummy;
|
||||
Time lasttime = 0;
|
||||
|
||||
if (!(c = selmon->sel))
|
||||
@ -1313,10 +1423,18 @@ resizemouse(const Arg *arg)
|
||||
restack(selmon);
|
||||
ocx = c->x;
|
||||
ocy = c->y;
|
||||
ocx2 = c->x + c->w;
|
||||
ocy2 = c->y + c->h;
|
||||
if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
|
||||
None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess)
|
||||
return;
|
||||
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
|
||||
if (!XQueryPointer (dpy, c->win, &dummy, &dummy, &di, &di, &nx, &ny, &dui))
|
||||
return;
|
||||
horizcorner = nx < c->w / 2;
|
||||
vertcorner = ny < c->h / 2;
|
||||
XWarpPointer (dpy, None, c->win, 0, 0, 0, 0,
|
||||
horizcorner ? (-c->bw) : (c->w + c->bw -1),
|
||||
vertcorner ? (-c->bw) : (c->h + c->bw -1));
|
||||
do {
|
||||
XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
|
||||
switch(ev.type) {
|
||||
@ -1330,8 +1448,11 @@ resizemouse(const Arg *arg)
|
||||
continue;
|
||||
lasttime = ev.xmotion.time;
|
||||
|
||||
nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1);
|
||||
nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1);
|
||||
nx = horizcorner ? ev.xmotion.x : c->x;
|
||||
ny = vertcorner ? ev.xmotion.y : c->y;
|
||||
nw = MAX(horizcorner ? (ocx2 - nx) : (ev.xmotion.x - ocx - 2 * c->bw + 1), 1);
|
||||
nh = MAX(vertcorner ? (ocy2 - ny) : (ev.xmotion.y - ocy - 2 * c->bw + 1), 1);
|
||||
|
||||
if (c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww
|
||||
&& c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh)
|
||||
{
|
||||
@ -1340,11 +1461,13 @@ resizemouse(const Arg *arg)
|
||||
togglefloating(NULL);
|
||||
}
|
||||
if (!selmon->lt[selmon->sellt]->arrange || c->isfloating)
|
||||
resize(c, c->x, c->y, nw, nh, 1);
|
||||
resize(c, nx, ny, nw, nh, 1);
|
||||
break;
|
||||
}
|
||||
} while (ev.type != ButtonRelease);
|
||||
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
|
||||
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0,
|
||||
horizcorner ? (-c->bw) : (c->w + c->bw - 1),
|
||||
vertcorner ? (-c->bw) : (c->h + c->bw - 1));
|
||||
XUngrabPointer(dpy, CurrentTime);
|
||||
while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
|
||||
if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
|
||||
@ -1684,6 +1807,36 @@ tagmon(const Arg *arg)
|
||||
sendmon(selmon->sel, dirtomon(arg->i));
|
||||
}
|
||||
|
||||
void
|
||||
tagtonext(const Arg *arg)
|
||||
{
|
||||
unsigned int tmp;
|
||||
|
||||
if (selmon->sel == NULL)
|
||||
return;
|
||||
|
||||
if ((tmp = nexttag()) == selmon->tagset[selmon->seltags])
|
||||
return;
|
||||
|
||||
tag(&(const Arg){.ui = tmp });
|
||||
view(&(const Arg){.ui = tmp });
|
||||
}
|
||||
|
||||
void
|
||||
tagtoprev(const Arg *arg)
|
||||
{
|
||||
unsigned int tmp;
|
||||
|
||||
if (selmon->sel == NULL)
|
||||
return;
|
||||
|
||||
if ((tmp = prevtag()) == selmon->tagset[selmon->seltags])
|
||||
return;
|
||||
|
||||
tag(&(const Arg){.ui = tmp });
|
||||
view(&(const Arg){.ui = tmp });
|
||||
}
|
||||
|
||||
void
|
||||
tile(Monitor *m)
|
||||
{
|
||||
@ -1735,6 +1888,13 @@ togglefloating(const Arg *arg)
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
void
|
||||
togglefullscr(const Arg *arg)
|
||||
{
|
||||
if(selmon->sel)
|
||||
setfullscreen(selmon->sel, !selmon->sel->isfullscreen);
|
||||
}
|
||||
|
||||
void
|
||||
toggletag(const Arg *arg)
|
||||
{
|
||||
@ -2062,6 +2222,18 @@ view(const Arg *arg)
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
void
|
||||
viewnext(const Arg *arg)
|
||||
{
|
||||
view(&(const Arg){.ui = nexttag()});
|
||||
}
|
||||
|
||||
void
|
||||
viewprev(const Arg *arg)
|
||||
{
|
||||
view(&(const Arg){.ui = prevtag()});
|
||||
}
|
||||
|
||||
Client *
|
||||
wintoclient(Window w)
|
||||
{
|
||||
|
27
layouts.c
Normal file
27
layouts.c
Normal file
@ -0,0 +1,27 @@
|
||||
void
|
||||
grid(Monitor *m) {
|
||||
unsigned int i, n, cx, cy, cw, ch, aw, ah, cols, rows;
|
||||
Client *c;
|
||||
|
||||
for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next))
|
||||
n++;
|
||||
|
||||
/* grid dimensions */
|
||||
for(rows = 0; rows <= n/2; rows++)
|
||||
if(rows*rows >= n)
|
||||
break;
|
||||
cols = (rows && (rows - 1) * rows >= n) ? rows - 1 : rows;
|
||||
|
||||
/* window geoms (cell height/width) */
|
||||
ch = m->wh / (rows ? rows : 1);
|
||||
cw = m->ww / (cols ? cols : 1);
|
||||
for(i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next)) {
|
||||
cx = m->wx + (i / rows) * cw;
|
||||
cy = m->wy + (i % rows) * ch;
|
||||
/* adjust height/width of last row/column's windows */
|
||||
ah = ((i + 1) % rows == 0) ? m->wh - ch * rows : 0;
|
||||
aw = (i >= rows * (cols - 1)) ? m->ww - cw * cols : 0;
|
||||
resize(c, cx, cy, cw - 2 * c->bw + aw, ch - 2 * c->bw + ah, False);
|
||||
i++;
|
||||
}
|
||||
}
|
13
util.c
13
util.c
@ -1,4 +1,5 @@
|
||||
/* See LICENSE file for copyright and license details. */
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -10,17 +11,17 @@ void
|
||||
die(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int saved_errno;
|
||||
|
||||
saved_errno = errno;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
|
||||
fputc(' ', stderr);
|
||||
perror(NULL);
|
||||
} else {
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
if (fmt[0] && fmt[strlen(fmt)-1] == ':')
|
||||
fprintf(stderr, " %s", strerror(saved_errno));
|
||||
fputc('\n', stderr);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user