wiebel
10 months ago
commit
84c06e3578
91 changed files with 8404 additions and 0 deletions
@ -0,0 +1,37 @@ |
|||
MIT/X Consortium License |
|||
|
|||
© 2006-2019 Anselm R Garbe <anselm@garbe.ca> |
|||
© 2006-2009 Jukka Salmi <jukka at salmi dot ch> |
|||
© 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com> |
|||
© 2007-2011 Peter Hartlich <sgkkr at hartlich dot com> |
|||
© 2007-2009 Szabolcs Nagy <nszabolcs at gmail dot com> |
|||
© 2007-2009 Christof Musik <christof at sendfax dot de> |
|||
© 2007-2009 Premysl Hruby <dfenze at gmail dot com> |
|||
© 2007-2008 Enno Gottox Boland <gottox at s01 dot de> |
|||
© 2008 Martin Hurton <martin dot hurton at gmail dot com> |
|||
© 2008 Neale Pickett <neale dot woozle dot org> |
|||
© 2009 Mate Nagy <mnagy at port70 dot net> |
|||
© 2010-2016 Hiltjo Posthuma <hiltjo@codemadness.org> |
|||
© 2010-2012 Connor Lane Smith <cls@lubutu.com> |
|||
© 2011 Christoph Lohmann <20h@r-36.net> |
|||
© 2015-2016 Quentin Rameau <quinq@fifth.space> |
|||
© 2015-2016 Eric Pruitt <eric.pruitt@gmail.com> |
|||
© 2016-2017 Markus Teich <markus.teich@stusta.mhn.de> |
|||
|
|||
Permission is hereby granted, free of charge, to any person obtaining a |
|||
copy of this software and associated documentation files (the "Software"), |
|||
to deal in the Software without restriction, including without limitation |
|||
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
|||
and/or sell copies of the Software, and to permit persons to whom the |
|||
Software is furnished to do so, subject to the following conditions: |
|||
|
|||
The above copyright notice and this permission notice shall be included in |
|||
all copies or substantial portions of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
|||
DEALINGS IN THE SOFTWARE. |
@ -0,0 +1,69 @@ |
|||
# dwm - dynamic window manager
|
|||
# See LICENSE file for copyright and license details.
|
|||
|
|||
include config.mk |
|||
|
|||
SRC = drw.c dwm.c util.c |
|||
OBJ = ${SRC:.c=.o} |
|||
|
|||
# FreeBSD users, prefix all ifdef, else and endif statements with a . for this to work (e.g. .ifdef)
|
|||
|
|||
ifdef YAJLLIBS |
|||
all: options dwm dwm-msg |
|||
else |
|||
all: options dwm |
|||
endif |
|||
|
|||
options: |
|||
@echo dwm build options: |
|||
@echo "CFLAGS = ${CFLAGS}" |
|||
@echo "LDFLAGS = ${LDFLAGS}" |
|||
@echo "CC = ${CC}" |
|||
|
|||
.c.o: |
|||
${CC} -c ${CFLAGS} $< |
|||
|
|||
${OBJ}: config.h config.mk |
|||
|
|||
config.h: |
|||
cp config.def.h $@ |
|||
|
|||
dwm: ${OBJ} |
|||
${CC} -o $@ ${OBJ} ${LDFLAGS} |
|||
|
|||
ifdef YAJLLIBS |
|||
dwm-msg: |
|||
${CC} -o $@ patch/ipc/dwm-msg.c ${LDFLAGS} |
|||
endif |
|||
|
|||
clean: |
|||
rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz |
|||
rm -f dwm-msg |
|||
|
|||
dist: clean |
|||
mkdir -p dwm-${VERSION} |
|||
cp -R LICENSE Makefile README config.def.h config.mk\
|
|||
dwm.1 drw.h util.h ${SRC} dwm.png transient.c dwm-${VERSION} |
|||
tar -cf dwm-${VERSION}.tar dwm-${VERSION} |
|||
gzip dwm-${VERSION}.tar |
|||
rm -rf dwm-${VERSION} |
|||
|
|||
install: all |
|||
mkdir -p ${DESTDIR}${PREFIX}/bin |
|||
cp -f dwm ${DESTDIR}${PREFIX}/bin |
|||
ifdef YAJLLIBS |
|||
cp -f dwm-msg ${DESTDIR}${PREFIX}/bin |
|||
endif |
|||
chmod 755 ${DESTDIR}${PREFIX}/bin/dwm |
|||
ifdef YAJLLIBS |
|||
chmod 755 ${DESTDIR}${PREFIX}/bin/dwm-msg |
|||
endif |
|||
mkdir -p ${DESTDIR}${MANPREFIX}/man1 |
|||
sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1 |
|||
chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1 |
|||
|
|||
uninstall: |
|||
rm -f ${DESTDIR}${PREFIX}/bin/dwm\
|
|||
${DESTDIR}${MANPREFIX}/man1/dwm.1 |
|||
|
|||
.PHONY: all options clean dist install uninstall |
@ -0,0 +1,48 @@ |
|||
dwm - dynamic window manager |
|||
============================ |
|||
dwm is an extremely fast, small, and dynamic window manager for X. |
|||
|
|||
|
|||
Requirements |
|||
------------ |
|||
In order to build dwm you need the Xlib header files. |
|||
|
|||
|
|||
Installation |
|||
------------ |
|||
Edit config.mk to match your local setup (dwm is installed into |
|||
the /usr/local namespace by default). |
|||
|
|||
Afterwards enter the following command to build and install dwm (if |
|||
necessary as root): |
|||
|
|||
make clean install |
|||
|
|||
|
|||
Running dwm |
|||
----------- |
|||
Add the following line to your .xinitrc to start dwm using startx: |
|||
|
|||
exec dwm |
|||
|
|||
In order to connect dwm to a specific display, make sure that |
|||
the DISPLAY environment variable is set correctly, e.g.: |
|||
|
|||
DISPLAY=foo.bar:1 exec dwm |
|||
|
|||
(This will start dwm on display :1 of the host foo.bar.) |
|||
|
|||
In order to display status info in the bar, you can do something |
|||
like this in your .xinitrc: |
|||
|
|||
while xsetroot -name "`date` `uptime | sed 's/.*,//'`" |
|||
do |
|||
sleep 1 |
|||
done & |
|||
exec dwm |
|||
|
|||
|
|||
Configuration |
|||
------------- |
|||
The configuration of dwm is done by creating a custom config.h |
|||
and (re)compiling the source code. |
@ -0,0 +1,345 @@ |
|||
/* See LICENSE file for copyright and license details. */ |
|||
|
|||
/* appearance */ |
|||
static const unsigned int borderpx = 1; /* border pixel of windows */ |
|||
static const unsigned int snap = 32; /* snap pixel */ |
|||
static const int swallowfloating = 0; /* 1 means swallow floating windows by default */ |
|||
static const unsigned int gappih = 20; /* 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 = 30; /* vert outer gap between windows and screen edge */ |
|||
static const int smartgaps_fact = 1; /* gap factor when there is only one client; 0 = no gaps, 3 = 3x outer gaps */ |
|||
static const char autostartblocksh[] = "autostart_blocking.sh"; |
|||
static const char autostartsh[] = "autostart.sh"; |
|||
static const char dwmdir[] = "dwm"; |
|||
static const char localshare[] = ".local/share"; |
|||
static const int showbar = 1; /* 0 means no bar */ |
|||
static const int topbar = 1; /* 0 means bottom bar */ |
|||
/* Status is to be shown on: -1 (all monitors), 0 (a specific monitor by index), 'A' (active monitor) */ |
|||
static const int statusmon = 'A'; |
|||
static const unsigned int systrayspacing = 2; /* systray spacing */ |
|||
static const int showsystray = 1; /* 0 means no systray */ |
|||
/* Indicators: see patch/bar_indicators.h for options */ |
|||
static int tagindicatortype = INDICATOR_TOP_LEFT_SQUARE; |
|||
static int tiledindicatortype = INDICATOR_NONE; |
|||
static int floatindicatortype = INDICATOR_TOP_LEFT_SQUARE; |
|||
static int fakefsindicatortype = INDICATOR_PLUS; |
|||
static int floatfakefsindicatortype = INDICATOR_PLUS_AND_LARGER_SQUARE; |
|||
static void (*bartabmonfns[])(Monitor *) = { monocle /* , customlayoutfn */ }; |
|||
static const char *fonts[] = { "monospace:size=10" }; |
|||
static const char dmenufont[] = "monospace:size=10"; |
|||
|
|||
static char c000000[] = "#000000"; // placeholder value
|
|||
|
|||
static char normfgcolor[] = "#bbbbbb"; |
|||
static char normbgcolor[] = "#222222"; |
|||
static char normbordercolor[] = "#444444"; |
|||
static char normfloatcolor[] = "#db8fd9"; |
|||
|
|||
static char selfgcolor[] = "#eeeeee"; |
|||
static char selbgcolor[] = "#005577"; |
|||
static char selbordercolor[] = "#005577"; |
|||
static char selfloatcolor[] = "#005577"; |
|||
|
|||
static char titlenormfgcolor[] = "#bbbbbb"; |
|||
static char titlenormbgcolor[] = "#222222"; |
|||
static char titlenormbordercolor[] = "#444444"; |
|||
static char titlenormfloatcolor[] = "#db8fd9"; |
|||
|
|||
static char titleselfgcolor[] = "#eeeeee"; |
|||
static char titleselbgcolor[] = "#005577"; |
|||
static char titleselbordercolor[] = "#005577"; |
|||
static char titleselfloatcolor[] = "#005577"; |
|||
|
|||
static char tagsnormfgcolor[] = "#bbbbbb"; |
|||
static char tagsnormbgcolor[] = "#222222"; |
|||
static char tagsnormbordercolor[] = "#444444"; |
|||
static char tagsnormfloatcolor[] = "#db8fd9"; |
|||
|
|||
static char tagsselfgcolor[] = "#eeeeee"; |
|||
static char tagsselbgcolor[] = "#005577"; |
|||
static char tagsselbordercolor[] = "#005577"; |
|||
static char tagsselfloatcolor[] = "#005577"; |
|||
|
|||
static char hidnormfgcolor[] = "#005577"; |
|||
static char hidselfgcolor[] = "#227799"; |
|||
static char hidnormbgcolor[] = "#222222"; |
|||
static char hidselbgcolor[] = "#222222"; |
|||
|
|||
static char urgfgcolor[] = "#bbbbbb"; |
|||
static char urgbgcolor[] = "#222222"; |
|||
static char urgbordercolor[] = "#ff0000"; |
|||
static char urgfloatcolor[] = "#db8fd9"; |
|||
|
|||
|
|||
static const unsigned int baralpha = 0xd0; |
|||
static const unsigned int borderalpha = OPAQUE; |
|||
static const unsigned int alphas[][3] = { |
|||
/* fg bg border */ |
|||
[SchemeNorm] = { OPAQUE, baralpha, borderalpha }, |
|||
[SchemeSel] = { OPAQUE, baralpha, borderalpha }, |
|||
[SchemeTitleNorm] = { OPAQUE, baralpha, borderalpha }, |
|||
[SchemeTitleSel] = { OPAQUE, baralpha, borderalpha }, |
|||
[SchemeTagsNorm] = { OPAQUE, baralpha, borderalpha }, |
|||
[SchemeTagsSel] = { OPAQUE, baralpha, borderalpha }, |
|||
[SchemeHidNorm] = { OPAQUE, baralpha, borderalpha }, |
|||
[SchemeHidSel] = { OPAQUE, baralpha, borderalpha }, |
|||
[SchemeUrg] = { OPAQUE, baralpha, borderalpha }, |
|||
}; |
|||
|
|||
static char *colors[][ColCount] = { |
|||
/* fg bg border float */ |
|||
[SchemeNorm] = { normfgcolor, normbgcolor, normbordercolor, normfloatcolor }, |
|||
[SchemeSel] = { selfgcolor, selbgcolor, selbordercolor, selfloatcolor }, |
|||
[SchemeTitleNorm] = { titlenormfgcolor, titlenormbgcolor, titlenormbordercolor, titlenormfloatcolor }, |
|||
[SchemeTitleSel] = { titleselfgcolor, titleselbgcolor, titleselbordercolor, titleselfloatcolor }, |
|||
[SchemeTagsNorm] = { tagsnormfgcolor, tagsnormbgcolor, tagsnormbordercolor, tagsnormfloatcolor }, |
|||
[SchemeTagsSel] = { tagsselfgcolor, tagsselbgcolor, tagsselbordercolor, tagsselfloatcolor }, |
|||
[SchemeHidNorm] = { hidnormfgcolor, hidnormbgcolor, c000000, c000000 }, |
|||
[SchemeHidSel] = { hidselfgcolor, hidselbgcolor, c000000, c000000 }, |
|||
[SchemeUrg] = { urgfgcolor, urgbgcolor, urgbordercolor, urgfloatcolor }, |
|||
}; |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
/* Tags
|
|||
* In a traditional dwm the number of tags in use can be changed simply by changing the number |
|||
* of strings in the tags array. This build does things a bit different which has some added |
|||
* benefits. If you need to change the number of tags here then change the NUMTAGS macro in dwm.c. |
|||
* |
|||
* Examples: |
|||
* |
|||
* 1) static char *tagicons[][NUMTAGS*2] = { |
|||
* [DEFAULT_TAGS] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I" }, |
|||
* } |
|||
* |
|||
* 2) static char *tagicons[][1] = { |
|||
* [DEFAULT_TAGS] = { "•" }, |
|||
* } |
|||
* |
|||
* The first example would result in the tags on the first monitor to be 1 through 9, while the |
|||
* tags for the second monitor would be named A through I. A third monitor would start again at |
|||
* 1 through 9 while the tags on a fourth monitor would also be named A through I. Note the tags |
|||
* count of NUMTAGS*2 in the array initialiser which defines how many tag text / icon exists in |
|||
* the array. This can be changed to *3 to add separate icons for a third monitor. |
|||
* |
|||
* For the second example each tag would be represented as a bullet point. Both cases work the |
|||
* same from a technical standpoint - the icon index is derived from the tag index and the monitor |
|||
* index. If the icon index is is greater than the number of tag icons then it will wrap around |
|||
* until it an icon matches. Similarly if there are two tag icons then it would alternate between |
|||
* them. This works seamlessly with alternative tags and alttagsdecoration patches. |
|||
*/ |
|||
static char *tagicons[][NUMTAGS] = { |
|||
[DEFAULT_TAGS] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }, |
|||
[ALTERNATIVE_TAGS] = { "A", "B", "C", "D", "E", "F", "G", "H", "I" }, |
|||
[ALT_TAGS_DECORATION] = { "<1>", "<2>", "<3>", "<4>", "<5>", "<6>", "<7>", "<8>", "<9>" }, |
|||
}; |
|||
|
|||
|
|||
/* There are two options when it comes to per-client rules:
|
|||
* - a typical struct table or |
|||
* - using the RULE macro |
|||
* |
|||
* A traditional struct table looks like this: |
|||
* // class instance title wintype tags mask isfloating monitor
|
|||
* { "Gimp", NULL, NULL, NULL, 1 << 4, 0, -1 }, |
|||
* { "Firefox", NULL, NULL, NULL, 1 << 7, 0, -1 }, |
|||
* |
|||
* The RULE macro has the default values set for each field allowing you to only |
|||
* specify the values that are relevant for your rule, e.g. |
|||
* |
|||
* RULE(.class = "Gimp", .tags = 1 << 4) |
|||
* RULE(.class = "Firefox", .tags = 1 << 7) |
|||
* |
|||
* Refer to the Rule struct definition for the list of available fields depending on |
|||
* the patches you enable. |
|||
*/ |
|||
static const Rule rules[] = { |
|||
/* xprop(1):
|
|||
* WM_CLASS(STRING) = instance, class |
|||
* WM_NAME(STRING) = title |
|||
* WM_WINDOW_ROLE(STRING) = role |
|||
* _NET_WM_WINDOW_TYPE(ATOM) = wintype |
|||
*/ |
|||
RULE(.wintype = WTYPE "DIALOG", .isfloating = 1) |
|||
RULE(.wintype = WTYPE "UTILITY", .isfloating = 1) |
|||
RULE(.wintype = WTYPE "TOOLBAR", .isfloating = 1) |
|||
RULE(.wintype = WTYPE "SPLASH", .isfloating = 1) |
|||
RULE(.class = "Gimp", .tags = 1 << 4) |
|||
RULE(.class = "Firefox", .tags = 1 << 7) |
|||
}; |
|||
|
|||
|
|||
|
|||
/* Bar rules allow you to configure what is shown where on the bar, as well as
|
|||
* introducing your own bar modules. |
|||
* |
|||
* monitor: |
|||
* -1 show on all monitors |
|||
* 0 show on monitor 0 |
|||
* 'A' show on active monitor (i.e. focused / selected) (or just -1 for active?) |
|||
* bar - bar index, 0 is default, 1 is extrabar |
|||
* alignment - how the module is aligned compared to other modules |
|||
* widthfunc, drawfunc, clickfunc - providing bar module width, draw and click functions |
|||
* name - does nothing, intended for visual clue and for logging / debugging |
|||
*/ |
|||
static const BarRule barrules[] = { |
|||
/* monitor bar alignment widthfunc drawfunc clickfunc name */ |
|||
{ 0, 0, BAR_ALIGN_LEFT, width_pwrl_tags, draw_pwrl_tags, click_pwrl_tags, "powerline_tags" }, |
|||
{ -1, 0, BAR_ALIGN_LEFT, width_tags, draw_tags, click_tags, "tags" }, |
|||
{ 0, 0, BAR_ALIGN_RIGHT, width_systray, draw_systray, click_systray, "systray" }, |
|||
{ -1, 0, BAR_ALIGN_LEFT, width_ltsymbol, draw_ltsymbol, click_ltsymbol, "layout" }, |
|||
{ statusmon, 0, BAR_ALIGN_RIGHT, width_status, draw_status, click_statuscmd, "status" }, |
|||
{ -1, 0, BAR_ALIGN_NONE, width_bartabgroups, draw_bartabgroups, click_bartabgroups, "bartabgroups" }, |
|||
}; |
|||
|
|||
/* 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 */ |
|||
static const int resizehints = 0; /* 1 means respect size hints in tiled resizals */ |
|||
static const int decorhints = 1; /* 1 means respect decoration hints */ |
|||
|
|||
#define FORCE_VSPLIT 1 |
|||
|
|||
|
|||
static const Layout layouts[] = { |
|||
/* symbol arrange function */ |
|||
{ "[]=", tile }, /* first entry is default */ |
|||
{ "><>", NULL }, /* no layout function means floating behavior */ |
|||
{ "[M]", monocle }, |
|||
{ "|M|", centeredmaster }, |
|||
{ ">M>", centeredfloatingmaster }, |
|||
{ "[\\]", dwindle }, |
|||
{ "###", nrowgrid }, |
|||
}; |
|||
|
|||
|
|||
/* key definitions */ |
|||
#define MODKEY Mod1Mask |
|||
#define TAGKEYS(KEY,TAG) \ |
|||
{ MODKEY, KEY, view, {.ui = 1 << TAG} }, \ |
|||
{ MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \ |
|||
{ MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \ |
|||
{ MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} }, |
|||
|
|||
|
|||
|
|||
/* helper for spawning shell commands in the pre dwm-5.0 fashion */ |
|||
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } |
|||
|
|||
/* commands */ |
|||
static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ |
|||
static const char *dmenucmd[] = { |
|||
"dmenu_run", |
|||
"-m", dmenumon, |
|||
"-fn", dmenufont, |
|||
"-nb", normbgcolor, |
|||
"-nf", normfgcolor, |
|||
"-sb", selbgcolor, |
|||
"-sf", selfgcolor, |
|||
NULL |
|||
}; |
|||
static const char *termcmd[] = { "st", NULL }; |
|||
|
|||
/* This defines the name of the executable that handles the bar (used for signalling purposes) */ |
|||
#define STATUSBAR "dwmblocks" |
|||
|
|||
|
|||
static Key keys[] = { |
|||
/* modifier key function argument */ |
|||
{ MODKEY, XK_p, spawn, {.v = dmenucmd } }, |
|||
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, |
|||
{ MODKEY, XK_b, togglebar, {0} }, |
|||
{ MODKEY, XK_j, focusstack, {.i = +1 } }, |
|||
{ MODKEY, XK_k, focusstack, {.i = -1 } }, |
|||
{ MODKEY|Mod4Mask, XK_j, inplacerotate, {.i = +2 } }, // same as rotatestack
|
|||
{ MODKEY|Mod4Mask, XK_k, inplacerotate, {.i = -2 } }, // same as reotatestack
|
|||
{ MODKEY|Mod4Mask|ShiftMask, XK_j, inplacerotate, {.i = +1} }, |
|||
{ MODKEY|Mod4Mask|ShiftMask, XK_k, inplacerotate, {.i = -1} }, |
|||
{ MODKEY, XK_i, incnmaster, {.i = +1 } }, |
|||
{ MODKEY, XK_d, incnmaster, {.i = -1 } }, |
|||
{ MODKEY, XK_h, setmfact, {.f = -0.05} }, |
|||
{ MODKEY, XK_l, setmfact, {.f = +0.05} }, |
|||
{ MODKEY, XK_x, transfer, {0} }, |
|||
{ MODKEY, XK_Return, zoom, {0} }, |
|||
{ MODKEY|Mod4Mask, XK_u, incrgaps, {.i = +1 } }, |
|||
{ MODKEY|Mod4Mask|ShiftMask, XK_u, incrgaps, {.i = -1 } }, |
|||
{ MODKEY|Mod4Mask, XK_i, incrigaps, {.i = +1 } }, |
|||
{ MODKEY|Mod4Mask|ShiftMask, XK_i, incrigaps, {.i = -1 } }, |
|||
{ MODKEY|Mod4Mask, XK_o, incrogaps, {.i = +1 } }, |
|||
{ MODKEY|Mod4Mask|ShiftMask, XK_o, incrogaps, {.i = -1 } }, |
|||
{ MODKEY|Mod4Mask, XK_6, incrihgaps, {.i = +1 } }, |
|||
{ MODKEY|Mod4Mask|ShiftMask, XK_6, incrihgaps, {.i = -1 } }, |
|||
{ MODKEY|Mod4Mask, XK_7, incrivgaps, {.i = +1 } }, |
|||
{ MODKEY|Mod4Mask|ShiftMask, XK_7, incrivgaps, {.i = -1 } }, |
|||
{ MODKEY|Mod4Mask, XK_8, incrohgaps, {.i = +1 } }, |
|||
{ MODKEY|Mod4Mask|ShiftMask, XK_8, incrohgaps, {.i = -1 } }, |
|||
{ MODKEY|Mod4Mask, XK_9, incrovgaps, {.i = +1 } }, |
|||
{ MODKEY|Mod4Mask|ShiftMask, XK_9, incrovgaps, {.i = -1 } }, |
|||
{ MODKEY|Mod4Mask, XK_0, togglegaps, {0} }, |
|||
{ MODKEY|Mod4Mask|ShiftMask, XK_0, defaultgaps, {0} }, |
|||
{ MODKEY, XK_Tab, view, {0} }, |
|||
{ MODKEY|ControlMask, XK_z, showhideclient, {0} }, |
|||
{ MODKEY|ShiftMask, XK_c, killclient, {0} }, |
|||
{ MODKEY|ShiftMask, XK_q, quit, {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|ShiftMask, XK_space, togglefloating, {0} }, |
|||
{ MODKEY|ShiftMask, XK_y, togglefakefullscreen, {0} }, |
|||
{ MODKEY|ShiftMask, XK_s, togglesticky, {0} }, |
|||
{ MODKEY, XK_minus, scratchpad_show, {0} }, |
|||
{ MODKEY|ShiftMask, XK_minus, scratchpad_hide, {0} }, |
|||
{ MODKEY, XK_equal, scratchpad_remove, {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, XK_Left, viewtoleft, {0} }, // note keybinding conflict with focusdir
|
|||
{ MODKEY, XK_Right, viewtoright, {0} }, // note keybinding conflict with focusdir
|
|||
{ MODKEY|ShiftMask, XK_Left, tagtoleft, {0} }, |
|||
{ MODKEY|ShiftMask, XK_Right, tagtoright, {0} }, |
|||
{ MODKEY|ControlMask, XK_Left, tagandviewtoleft, {0} }, |
|||
{ MODKEY|ControlMask, XK_Right, tagandviewtoright, {0} }, |
|||
{ MODKEY|Mod4Mask|ShiftMask, XK_comma, tagallmon, {.i = +1 } }, |
|||
{ MODKEY|Mod4Mask|ShiftMask, XK_period, tagallmon, {.i = -1 } }, |
|||
{ MODKEY|Mod4Mask|ControlMask, XK_comma, tagswapmon, {.i = +1 } }, |
|||
{ MODKEY|Mod4Mask|ControlMask, XK_period, tagswapmon, {.i = -1 } }, |
|||
TAGKEYS( XK_1, 0) |
|||
TAGKEYS( XK_2, 1) |
|||
TAGKEYS( XK_3, 2) |
|||
TAGKEYS( XK_4, 3) |
|||
TAGKEYS( XK_5, 4) |
|||
TAGKEYS( XK_6, 5) |
|||
TAGKEYS( XK_7, 6) |
|||
TAGKEYS( XK_8, 7) |
|||
TAGKEYS( XK_9, 8) |
|||
}; |
|||
|
|||
|
|||
/* button definitions */ |
|||
/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ |
|||
static Button buttons[] = { |
|||
/* click event mask button function argument */ |
|||
{ ClkLtSymbol, 0, Button1, setlayout, {0} }, |
|||
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, |
|||
{ ClkWinTitle, 0, Button1, togglewin, {0} }, |
|||
{ ClkWinTitle, 0, Button3, showhideclient, {0} }, |
|||
{ ClkWinTitle, 0, Button2, zoom, {0} }, |
|||
{ ClkStatusText, 0, Button1, sigstatusbar, {.i = 1 } }, |
|||
{ ClkStatusText, 0, Button2, sigstatusbar, {.i = 2 } }, |
|||
{ ClkStatusText, 0, Button3, sigstatusbar, {.i = 3 } }, |
|||
{ ClkClientWin, MODKEY, Button1, movemouse, {0} }, |
|||
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} }, |
|||
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} }, |
|||
{ ClkTagBar, 0, Button1, view, {0} }, |
|||
{ ClkTagBar, 0, Button3, toggleview, {0} }, |
|||
{ ClkTagBar, MODKEY, Button1, tag, {0} }, |
|||
{ ClkTagBar, MODKEY, Button3, toggletag, {0} }, |
|||
}; |
|||
|
|||
|
|||
|
@ -0,0 +1,416 @@ |
|||
/* See LICENSE file for copyright and license details. */ |
|||
|
|||
/* appearance */ |
|||
static const unsigned int borderpx = 2; /* border pixel of windows */ |
|||
static const unsigned int snap = 16; /* snap pixel */ |
|||
static const int swallowfloating = 0; /* 1 means swallow floating windows by default */ |
|||
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_fact = 0; /* 1 means no outer gap when there is only one window */ |
|||
static const char autostartblocksh[] = "autostart_blocking.sh"; |
|||
static const char autostartsh[] = "autostart.sh"; |
|||
static const char dwmdir[] = "dwm"; |
|||
static const char localshare[] = ".local/share"; |
|||
static const int showbar = 1; /* 0 means no bar */ |
|||
static const int topbar = 1; /* 0 means bottom bar */ |
|||
/* Status is to be shown on: -1 (all monitors), 0 (a specific monitor by index), 'A' (active monitor) */ |
|||
static const int statusmon = 'A'; |
|||
static const unsigned int systrayspacing = 2; /* systray spacing */ |
|||
static const int showsystray = 1; /* 0 means no systray */ |
|||
/* Indicators: see patch/bar_indicators.h for options */ |
|||
static int tagindicatortype = INDICATOR_TOP_LEFT_SQUARE; |
|||
static int tiledindicatortype = INDICATOR_NONE; |
|||
static int floatindicatortype = INDICATOR_TOP_LEFT_SQUARE; |
|||
static int fakefsindicatortype = INDICATOR_PLUS; |
|||
static int floatfakefsindicatortype = INDICATOR_PLUS_AND_LARGER_SQUARE; |
|||
static void (*bartabmonfns[])(Monitor *) = { monocle /* , customlayoutfn */ }; |
|||
static const char *fonts[] = { |
|||
"FontAwesome:size=12", |
|||
"mononoki:size=12", |
|||
}; |
|||
static const char dmenufont[] = "mononoki:size=12"; |
|||
|
|||
static char normfgcolor[] = "#bbbbbb"; |
|||
static char normbgcolor[] = "#222222"; |
|||
static char normbordercolor[] = "#444444"; |
|||
static char normfloatcolor[] = "#db8fd9"; |
|||
|
|||
static char selfgcolor[] = "#111111"; |
|||
static char selbgcolor[] = "#ffd700"; |
|||
static char selbordercolor[] = "#ffd700"; |
|||
static char selfloatcolor[] = "#ffd700"; |
|||
|
|||
static char titlenormfgcolor[] = "#bbbbbb"; |
|||
static char titlenormbgcolor[] = "#222222"; |
|||
static char titlenormbordercolor[] = "#444444"; |
|||
static char titlenormfloatcolor[] = "#db8fd9"; |
|||
|
|||
static char titleselfgcolor[] = "#111111"; |
|||
static char titleselbgcolor[] = "#ffd700"; |
|||
static char titleselbordercolor[] = "#ffd700"; |
|||
static char titleselfloatcolor[] = "#ffd700"; |
|||
|
|||
static char tagsnormfgcolor[] = "#bbbbbb"; |
|||
static char tagsnormbgcolor[] = "#222222"; |
|||
static char tagsnormbordercolor[] = "#444444"; |
|||
static char tagsnormfloatcolor[] = "#db8fd9"; |
|||
|
|||
static char tagsselfgcolor[] = "#111111"; |
|||
static char tagsselbgcolor[] = "#ffd700"; |
|||
static char tagsselbordercolor[] = "#ffd700"; |
|||
static char tagsselfloatcolor[] = "#ffd700"; |
|||
|
|||
static char hidnormfgcolor[] = "#ffd700"; |
|||
static char hidnormbgcolor[] = "#222222"; |
|||
static char hidselfgcolor[] = "#ffd700"; |
|||
static char hidselbgcolor[] = "#ffd700"; |
|||
static char hidbordercolor[] = "#ffd700"; |
|||
static char hidfloatcolor[] = "#f76e0c"; |
|||
|
|||
static char urgfgcolor[] = "#bbbbbb"; |
|||
static char urgbgcolor[] = "#222222"; |
|||
static char urgbordercolor[] = "#ff0000"; |
|||
static char urgfloatcolor[] = "#db8fd9"; |
|||
|
|||
|
|||
static const unsigned int baralpha = 0xd0; |
|||
static const unsigned int borderalpha = OPAQUE; |
|||
static const unsigned int alphas[][3] = { |
|||
/* fg bg border */ |
|||
[SchemeNorm] = { OPAQUE, baralpha, borderalpha }, |
|||
[SchemeSel] = { OPAQUE, baralpha, borderalpha }, |
|||
[SchemeTitleNorm] = { OPAQUE, baralpha, borderalpha }, |
|||
[SchemeTitleSel] = { OPAQUE, baralpha, borderalpha }, |
|||
[SchemeTagsNorm] = { OPAQUE, baralpha, borderalpha }, |
|||
[SchemeTagsSel] = { OPAQUE, baralpha, borderalpha }, |
|||
[SchemeHidNorm] = { OPAQUE, baralpha, borderalpha }, |
|||
[SchemeHidSel] = { OPAQUE, baralpha, borderalpha }, |
|||
[SchemeUrg] = { OPAQUE, baralpha, borderalpha }, |
|||
}; |
|||
|
|||
static char *colors[][ColCount] = { |
|||
/* fg bg border float */ |
|||
[SchemeNorm] = { normfgcolor, normbgcolor, normbordercolor, normfloatcolor }, |
|||
[SchemeSel] = { selfgcolor, selbgcolor, selbordercolor, selfloatcolor }, |
|||
[SchemeTitleNorm] = { titlenormfgcolor, titlenormbgcolor, titlenormbordercolor, titlenormfloatcolor }, |
|||
[SchemeTitleSel] = { titleselfgcolor, titleselbgcolor, titleselbordercolor, titleselfloatcolor }, |
|||
[SchemeTagsNorm] = { tagsnormfgcolor, tagsnormbgcolor, tagsnormbordercolor, tagsnormfloatcolor }, |
|||
[SchemeTagsSel] = { tagsselfgcolor, tagsselbgcolor, tagsselbordercolor, tagsselfloatcolor }, |
|||
[SchemeHidNorm] = { hidnormfgcolor, hidnormbgcolor, hidbordercolor, hidfloatcolor }, |
|||
[SchemeHidSel] = { hidselfgcolor, hidselbgcolor, hidbordercolor, hidfloatcolor }, |
|||
[SchemeUrg] = { urgfgcolor, urgbgcolor, urgbordercolor, urgfloatcolor }, |
|||
}; |
|||
|
|||
/*
|
|||
static char *statuscolors[][ColCount] = { |
|||
// fg bg border float
|
|||
[SchemeNorm] = { normfgcolor, normbgcolor, normbordercolor, normfloatcolor }, |
|||
[SchemeSel] = { selfgcolor, selbgcolor, selbordercolor, selfloatcolor }, |
|||
[SchemeTitleNorm] = { titlenormfgcolor, titlenormbgcolor, titlenormbordercolor, titlenormfloatcolor }, |
|||
[SchemeTitleSel] = { titleselfgcolor, titleselbgcolor, titleselbordercolor, titleselfloatcolor }, |
|||
[SchemeTagsNorm] = { tagsnormfgcolor, tagsnormbgcolor, tagsnormbordercolor, tagsnormfloatcolor }, |
|||
[SchemeTagsSel] = { tagsselfgcolor, tagsselbgcolor, tagsselbordercolor, tagsselfloatcolor }, |
|||
[SchemeHidNorm] = { hidnormfgcolor, hidnormbgcolor, hidbordercolor, hidfloatcolor }, |
|||
[SchemeHidSel] = { hidselfgcolor, hidselbgcolor, hidbordercolor, hidfloatcolor }, |
|||
[SchemeUrg] = { urgfgcolor, urgbgcolor, urgbordercolor, urgfloatcolor }, |
|||
}; |
|||
*/ |
|||
|
|||
|
|||
|
|||
/* Tags
|
|||
* In a traditional dwm the number of tags in use can be changed simply by changing the number |
|||
* of strings in the tags array. This build does things a bit different which has some added |
|||
* benefits. If you need to change the number of tags here then change the NUMTAGS macro in dwm.c. |
|||
* |
|||
* Examples: |
|||
* |
|||
* 1) static char *tagicons[][NUMTAGS*2] = { |
|||
* [DEFAULT_TAGS] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I" }, |
|||
* } |
|||
* |
|||
* 2) static char *tagicons[][1] = { |
|||
* [DEFAULT_TAGS] = { "•" }, |
|||
* } |
|||
* |
|||
* The first example would result in the tags on the first monitor to be 1 through 9, while the |
|||
* tags for the second monitor would be named A through I. A third monitor would start again at |
|||
* 1 through 9 while the tags on a fourth monitor would also be named A through I. Note the tags |
|||
* count of NUMTAGS*2 in the array initialiser which defines how many tag text / icon exists in |
|||
* the array. This can be changed to *3 to add separate icons for a third monitor. |
|||
* |
|||
* For the second example each tag would be represented as a bullet point. Both cases work the |
|||
* same from a technical standpoint - the icon index is derived from the tag index and the monitor |
|||
* index. If the icon index is is greater than the number of tag icons then it will wrap around |
|||
* until it an icon matches. Similarly if there are two tag icons then it would alternate between |
|||
* them. This works seamlessly with alternative tags and alttagsdecoration patches. |
|||
*/ |
|||
static char *tagicons[][NUMTAGS] = { |
|||
// [DEFAULT_TAGS] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" },
|
|||
[DEFAULT_TAGS] = { "₁", "₂", "₃", "₄", "₅", "₆", "₇", "₈", "₉" }, |
|||
[ALTERNATIVE_TAGS] = { "A", "B", "C", "D", "E", "F", "G", "H", "I" }, |
|||
[ALT_TAGS_DECORATION] = { "<1>", "<2>", "<3>", "<4>", "<5>", "<6>", "<7>", "<8>", "<9>" }, |
|||
}; |
|||
|
|||
|
|||
|
|||
|
|||
/* There are two options when it comes to per-client rules:
|
|||
* - a typical struct table or |
|||
* - using the RULE macro |
|||
* |
|||
* A traditional struct table looks like this: |
|||
* // class instance title wintype tags mask isfloating monitor
|
|||
* { "Gimp", NULL, NULL, NULL, 1 << 4, 0, -1 }, |
|||
* { "Firefox", NULL, NULL, NULL, 1 << 7, 0, -1 }, |
|||
* |
|||
* The RULE macro has the default values set for each field allowing you to only |
|||
* specify the values that are relevant for your rule, e.g. |
|||
* |
|||
* RULE(.class = "Gimp", .tags = 1 << 4) |
|||
* RULE(.class = "Firefox", .tags = 1 << 7) |
|||
* |
|||
* Refer to the Rule struct definition for the list of available fields depending on |
|||
* the patches you enable. |
|||
*/ |
|||
static const Rule rules[] = { |
|||
/* xprop(1):
|
|||
* WM_CLASS(STRING) = instance, class |
|||
* WM_NAME(STRING) = title |
|||
* WM_WINDOW_ROLE(STRING) = role |
|||
* _NET_WM_WINDOW_TYPE(ATOM) = wintype |
|||
*/ |
|||
RULE(.wintype = WTYPE "DIALOG", .isfloating = 1) |
|||
RULE(.wintype = WTYPE "UTILITY", .isfloating = 1) |
|||
RULE(.wintype = WTYPE "TOOLBAR", .isfloating = 1) |
|||
RULE(.wintype = WTYPE "SPLASH", .isfloating = 1) |
|||
RULE(.instance= "main", .class = "Psi+", .tags = 1 << 3) |
|||
RULE(.instance= "tabs", .class = "Psi+", .tags = 1 << 3) |
|||
RULE(.class = "Claws-mail", .tags = 1 << 3) |
|||
RULE(.class = "Zoiper", .tags = 1 << 3) |
|||
RULE(.class = "linphone", .tags = 1 << 3) |
|||
RULE(.class = "Skype", .tags = 1 << 3) |
|||
RULE(.class = "Mattermost", .tags = 1 << 3) |
|||
|
|||
RULE(.class = "pinentry-qt", .isfloating = 1) |
|||
RULE(.class = "pinentry-qt5", .isfloating = 1) |
|||
RULE(.class = "Nm-connection-editor", .isfloating = 1) |
|||
RULE(.class = "pavucontrol-qt", .isfloating = 0) |
|||
RULE(.class = "Firefox", .wintype = WTYPE "NORMAL", .tags = 1 << 2) |
|||
|
|||
RULE(.class = "Spotify", .tags = 1 << 8) |
|||
RULE(.class = "Kasts", .tags = 1 << 8) |
|||
|
|||
RULE(.class = "st-tilda", .isfloating = 1) |
|||
RULE(.class = "st-256color", .isterminal = 1) |
|||
}; |
|||
|
|||
|
|||
|
|||
/* Bar rules allow you to configure what is shown where on the bar, as well as
|
|||
* introducing your own bar modules. |
|||
* |
|||
* monitor: |
|||
* -1 show on all monitors |
|||
* 0 show on monitor 0 |
|||
* 'A' show on active monitor (i.e. focused / selected) (or just -1 for active?) |
|||
* bar - bar index, 0 is default, 1 is extrabar |
|||
* alignment - how the module is aligned compared to other modules |
|||
* widthfunc, drawfunc, clickfunc - providing bar module width, draw and click functions |
|||
* name - does nothing, intended for visual clue and for logging / debugging |
|||
*/ |
|||
static const BarRule barrules[] = { |
|||
/* monitor bar alignment widthfunc drawfunc clickfunc name */ |
|||
{ -1, 0, BAR_ALIGN_LEFT, width_pwrl_tags, draw_pwrl_tags, click_pwrl_tags, "powerline_tags" }, |
|||
//{ -1, 0, BAR_ALIGN_LEFT, width_tags, draw_tags, click_tags, "tags" },
|
|||
{ 'A', 0, BAR_ALIGN_RIGHT, width_systray, draw_systray, click_systray, "systray" }, |
|||
{ -1, 0, BAR_ALIGN_LEFT, width_ltsymbol, draw_ltsymbol, click_ltsymbol, "layout" }, |
|||
// { 'A', 0, BAR_ALIGN_RIGHT, width_pwrl_status, draw_pwrl_status, click_pwrl_status, "powerline_status" },
|
|||
{ statusmon, 0, BAR_ALIGN_RIGHT, width_status, draw_status, click_statuscmd, "status" }, |
|||
{ -1, 0, BAR_ALIGN_NONE, width_bartabgroups, draw_bartabgroups, click_bartabgroups, "bartabgroups" }, |
|||
}; |
|||
|
|||
/* 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 */ |
|||
static const int resizehints = 0; /* 1 means respect size hints in tiled resizals */ |
|||
static const int decorhints = 1; /* 1 means respect decoration hints */ |
|||
|
|||
#define FORCE_VSPLIT 1 |
|||
|
|||
|
|||
static const Layout layouts[] = { |
|||
/* symbol arrange function */ |
|||
{ "[]=", tile }, /* first entry is default */ |
|||
{ "><>", NULL }, /* no layout function means floating behavior */ |
|||
{ "[M]", monocle }, |
|||
{ "|M|", centeredmaster }, |
|||
{ ">M>", centeredfloatingmaster }, |
|||
{ "[\\]", dwindle }, |
|||
{ "###", nrowgrid }, |
|||
}; |
|||
|
|||
|
|||
/* key definitions */ |
|||
#define MODKEY Mod4Mask |
|||
#define AltMask Mod1Mask |
|||
#define ALTKEY Mod1Mask |
|||
#define TAGKEYS(KEY,TAG) \ |
|||
{ MODKEY, KEY, view, {.ui = 1 << TAG} }, \ |
|||
{ MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \ |
|||
{ MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \ |
|||
{ MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} }, |
|||
|
|||
|
|||
|
|||
/* helper for spawning shell commands in the pre dwm-5.0 fashion */ |
|||
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } |
|||
|
|||
/* commands */ |
|||
static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ |
|||
static const char *dmenucmd[] = { |
|||
"dmenu_run", |
|||
"-m", dmenumon, |
|||
"-fn", dmenufont, |
|||
"-nb", normbgcolor, |
|||
"-nf", normfgcolor, |
|||
"-sb", selbgcolor, |
|||
"-sf", selfgcolor, |
|||
NULL |
|||
}; |
|||
static const char *termcmd[] = { "st", NULL }; |
|||
static const char *tmuxcmd[] = { "st", "-c", "st-tmux", "-e", "/home/wiebel/sync/bin/tmux-spawn.sh", NULL }; |
|||
// static const char scratchpadname[] = "tilda";
|
|||
/* static const char *scratchpadcmd[] = { "st", "-t", scratchpadname, "-g", "120x34", NULL }; */ |
|||
// static const char *scratchpadcmd[] = { "st", "-t", scratchpadname, "-c", "st-tilda", "-g", "180x18", "-e", "tmux", "new-session", "-A", "-s", "tilda", NULL };
|
|||
|
|||
static const char *volup[] = { "/opt/pavolume/pavolume", "volup", "10", NULL }; |
|||
static const char *voldn[] = { "/opt/pavolume/pavolume", "voldown", "10", NULL }; |
|||
static const char *volmute[] = { "/opt/pavolume/pavolume", "mutetoggle", NULL }; |
|||
static const char *playpause[] = { "/usr/bin/playerctl", "play-pause", NULL }; |
|||
#include <X11/XF86keysym.h> |
|||
|
|||
/* This defines the name of the executable that handles the bar (used for signalling purposes) */ |
|||
#define STATUSBAR "dwmblocks" |
|||
|
|||
|
|||
static Key keys[] = { |
|||
/* modifier key function argument */ |
|||
{ MODKEY, XK_p, spawn, {.v = dmenucmd } }, |
|||
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = tmuxcmd } }, |
|||
{ MODKEY|ControlMask, XK_Return, spawn, {.v = termcmd } }, |
|||
{ MODKEY, XK_b, togglebar, {0} }, |
|||
{ MODKEY|ControlMask, XK_s, spawn, SHCMD("transset -a --dec .1") }, |
|||
{ MODKEY|ControlMask, XK_d, spawn, SHCMD("transset -a --inc .1") }, |
|||
{ ALTKEY, XK_w, spawn, SHCMD("pass-wrapper.sh") }, |
|||
{ MODKEY, XK_n, spawn, SHCMD("networkmanager_dmenu") }, |
|||
// { MODKEY, XK_grave, spawn, SHCMD("/home/wiebel/sync/bin/st-tilda.sh") },
|
|||
{ ALTKEY|ControlMask, XK_l, spawn, SHCMD("/usr/local/bin/lock.me") }, |
|||
/* Media Keys */ |
|||
{ 0, XF86XK_MonBrightnessUp, spawn, SHCMD("xbacklight -inc 5") }, |
|||
{ 0, XF86XK_MonBrightnessDown, spawn, SHCMD("xbacklight -dec 5") }, |
|||
{ 0, XF86XK_AudioRaiseVolume, spawn, {.v = volup } }, |
|||
{ 0, XF86XK_AudioLowerVolume, spawn, {.v = voldn } }, |
|||
{ 0, XF86XK_AudioMute, spawn, {.v = volmute } }, |
|||
{ 0, XF86XK_AudioPlay, spawn, {.v = playpause } }, |
|||
{ MODKEY, XK_j, focusstack, {.i = +1 } }, |
|||
{ MODKEY, XK_k, focusstack, {.i = -1 } }, |
|||
{ MODKEY|ShiftMask, XK_j, inplacerotate, {.i = +1} }, |
|||
{ MODKEY|ShiftMask, XK_k, inplacerotate, {.i = -1} }, |
|||
{ MODKEY, XK_i, incnmaster, {.i = +1 } }, |
|||
{ MODKEY, XK_d, incnmaster, {.i = -1 } }, |
|||
{ MODKEY, XK_h, setmfact, {.f = -0.05} }, |
|||
{ MODKEY, XK_l, setmfact, {.f = +0.05} }, |
|||
{ MODKEY, XK_x, transfer, {0} }, |
|||
{ MODKEY, XK_Return, zoom, {0} }, |
|||
// { MODKEY|AltMask, XK_u, incrgaps, {.i = +1 } },
|
|||
// { MODKEY|AltMask|ShiftMask, XK_u, incrgaps, {.i = -1 } },
|
|||
// { MODKEY|AltMask, XK_i, incrigaps, {.i = +1 } },
|
|||
// { MODKEY|AltMask|ShiftMask, XK_i, incrigaps, {.i = -1 } },
|
|||
// { MODKEY|AltMask, XK_o, incrogaps, {.i = +1 } },
|
|||
// { MODKEY|AltMask|ShiftMask, XK_o, incrogaps, {.i = -1 } },
|
|||
// { MODKEY|AltMask, XK_6, incrihgaps, {.i = +1 } },
|
|||
// { MODKEY|AltMask|ShiftMask, XK_6, incrihgaps, {.i = -1 } },
|
|||
// { MODKEY|AltMask, XK_7, incrivgaps, {.i = +1 } },
|
|||
// { MODKEY|AltMask|ShiftMask, XK_7, incrivgaps, {.i = -1 } },
|
|||
// { MODKEY|AltMask, XK_8, incrohgaps, {.i = +1 } },
|
|||
// { MODKEY|AltMask|ShiftMask, XK_8, incrohgaps, {.i = -1 } },
|
|||
// { MODKEY|AltMask, XK_9, incrovgaps, {.i = +1 } },
|
|||
// { MODKEY|AltMask|ShiftMask, XK_9, incrovgaps, {.i = -1 } },
|
|||
// { MODKEY|AltMask, XK_0, togglegaps, {0} },
|
|||
// { MODKEY|AltMask|ShiftMask, XK_0, defaultgaps, {0} },
|
|||
{ MODKEY, XK_Tab, view, {0} }, |
|||
{ MODKEY|ControlMask, XK_z, showhideclient, {0} }, |
|||
{ MODKEY, XK_q, killclient, {0} }, |
|||
{ MODKEY|ShiftMask, XK_c, killclient, {0} }, |
|||
{ MODKEY|ShiftMask, XK_q, quit, {0} }, |
|||
{ MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, |
|||
{ MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, |
|||
{ MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, |
|||
{ MODKEY, XK_u, setlayout, {.v = &layouts[3]} }, |
|||
{ MODKEY, XK_o, setlayout, {.v = &layouts[4]} }, |
|||
{ MODKEY|ShiftMask, XK_t, setlayout, {.v = &layouts[5]} }, |
|||
{ MODKEY, XK_g, setlayout, {.v = &layouts[6]} }, |
|||
{ MODKEY, XK_space, setlayout, {0} }, |
|||
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} }, |
|||
{ MODKEY|ShiftMask, XK_y, togglefakefullscreen, {0} }, |
|||
{ MODKEY|ShiftMask, XK_s, togglesticky, {0} }, |
|||
{ MODKEY, XK_grave, scratchpad_show, {0} }, |
|||
{ MODKEY, XK_Escape, scratchpad_show, {0} }, |
|||
{ MODKEY|ShiftMask, XK_grave, scratchpad_hide, {0} }, |
|||
{ MODKEY|ShiftMask, XK_Escape, scratchpad_hide, {0} }, |
|||
{ MODKEY|ShiftMask|ControlMask, XK_grave, scratchpad_remove, {0} }, |
|||
{ MODKEY|ShiftMask|ControlMask, XK_Escape, scratchpad_remove, {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, XK_Left, viewtoleft, {0} }, |
|||
{ MODKEY, XK_Right, viewtoright, {0} }, |
|||
{ MODKEY|ShiftMask, XK_Left, tagtoleft, {0} }, |
|||
{ MODKEY|ShiftMask, XK_Right, tagtoright, {0} }, |
|||
{ MODKEY|ControlMask, XK_Left, tagandviewtoleft, {0} }, |
|||
{ MODKEY|ControlMask, XK_Right, tagandviewtoright, {0} }, |
|||
{ MODKEY|ControlMask, XK_comma, tagallmon, {.i = +1 } }, |
|||
{ MODKEY|ControlMask, XK_period, tagallmon, {.i = -1 } }, |
|||
{ MODKEY|ShiftMask|ControlMask, XK_comma, tagswapmon, {.i = +1 } }, |
|||
{ MODKEY|ShiftMask|ControlMask, XK_period, tagswapmon, {.i = -1 } }, |
|||
|
|||
{ MODKEY, XK_0, view, {.ui = ~0 } }, |
|||
{ MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, |
|||
TAGKEYS( XK_1, 0) |
|||
TAGKEYS( XK_2, 1) |
|||
TAGKEYS( XK_3, 2) |
|||
TAGKEYS( XK_4, 3) |
|||
TAGKEYS( XK_5, 4) |
|||
TAGKEYS( XK_6, 5) |
|||
TAGKEYS( XK_7, 6) |
|||
TAGKEYS( XK_8, 7) |
|||
TAGKEYS( XK_9, 8) |
|||
}; |
|||
|
|||
|
|||
/* button definitions */ |
|||
/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ |
|||
static Button buttons[] = { |
|||
/* click event mask button function argument */ |
|||
{ ClkLtSymbol, 0, Button1, setlayout, {0} }, |
|||
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, |
|||
{ ClkWinTitle, 0, Button1, togglewin, {0} }, |
|||
{ ClkWinTitle, 0, Button3, showhideclient, {0} }, |
|||
{ ClkWinTitle, 0, Button2, zoom, {0} }, |
|||
{ ClkStatusText, 0, Button1, sigstatusbar, {.i = 1 } }, |
|||
{ ClkStatusText, 0, Button2, sigstatusbar, {.i = 2 } }, |
|||
{ ClkStatusText, 0, Button3, sigstatusbar, {.i = 3 } }, |
|||
{ ClkClientWin, MODKEY, Button1, movemouse, {0} }, |
|||
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} }, |
|||
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} }, |
|||
{ ClkTagBar, 0, Button1, view, {0} }, |
|||
{ ClkTagBar, 0, Button3, toggleview, {0} }, |
|||
{ ClkTagBar, MODKEY, Button1, tag, {0} }, |
|||
{ ClkTagBar, MODKEY, Button3, toggletag, {0} }, |
|||
}; |
|||
|
|||
|
@ -0,0 +1,416 @@ |
|||
/* See LICENSE file for copyright and license details. */ |
|||
|
|||
/* appearance */ |
|||
static const unsigned int borderpx = 2; /* border pixel of windows */ |
|||
static const unsigned int snap = 16; /* snap pixel */ |
|||
static const int swallowfloating = 0; /* 1 means swallow floating windows by default */ |
|||
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_fact = 0; /* 1 means no outer gap when there is only one window */ |
|||
static const char autostartblocksh[] = "autostart_blocking.sh"; |
|||
static const char autostartsh[] = "autostart.sh"; |
|||
static const char dwmdir[] = "dwm"; |
|||
static const char localshare[] = ".local/share"; |
|||
static const int showbar = 1; /* 0 means no bar */ |
|||
static const int topbar = 1; /* 0 means bottom bar */ |
|||
/* Status is to be shown on: -1 (all monitors), 0 (a specific monitor by index), 'A' (active monitor) */ |
|||
static const int statusmon = 'A'; |
|||
static const unsigned int systrayspacing = 2; /* systray spacing */ |
|||
static const int showsystray = 1; /* 0 means no systray */ |
|||
/* Indicators: see patch/bar_indicators.h for options */ |
|||
static int tagindicatortype = INDICATOR_TOP_LEFT_SQUARE; |
|||
static int tiledindicatortype = INDICATOR_NONE; |
|||
static int floatindicatortype = INDICATOR_TOP_LEFT_SQUARE; |
|||
static int fakefsindicatortype = INDICATOR_PLUS; |
|||
static int floatfakefsindicatortype = INDICATOR_PLUS_AND_LARGER_SQUARE; |
|||
static void (*bartabmonfns[])(Monitor *) = { monocle /* , customlayoutfn */ }; |
|||
static const char *fonts[] = { |
|||
"FontAwesome:size=12", |
|||
"mononoki:size=12", |
|||
}; |
|||
static const char dmenufont[] = "mononoki:size=12"; |
|||
|
|||
static char normfgcolor[] = "#bbbbbb"; |
|||
static char normbgcolor[] = "#222222"; |
|||
static char normbordercolor[] = "#444444"; |
|||
static char normfloatcolor[] = "#db8fd9"; |
|||
|
|||
static char selfgcolor[] = "#111111"; |
|||
static char selbgcolor[] = "#ffd700"; |
|||
static char selbordercolor[] = "#ffd700"; |
|||
static char selfloatcolor[] = "#ffd700"; |
|||
|
|||
static char titlenormfgcolor[] = "#bbbbbb"; |
|||
static char titlenormbgcolor[] = "#222222"; |
|||
static char titlenormbordercolor[] = "#444444"; |
|||
static char titlenormfloatcolor[] = "#db8fd9"; |
|||
|
|||
static char titleselfgcolor[] = "#111111"; |
|||
static char titleselbgcolor[] = "#ffd700"; |
|||
static char titleselbordercolor[] = "#ffd700"; |
|||
static char titleselfloatcolor[] = "#ffd700"; |
|||
|
|||
static char tagsnormfgcolor[] = "#bbbbbb"; |
|||
static char tagsnormbgcolor[] = "#222222"; |
|||
static char tagsnormbordercolor[] = "#444444"; |
|||
static char tagsnormfloatcolor[] = "#db8fd9"; |
|||
|
|||
static char tagsselfgcolor[] = "#111111"; |
|||
static char tagsselbgcolor[] = "#ffd700"; |
|||
static char tagsselbordercolor[] = "#ffd700"; |
|||
static char tagsselfloatcolor[] = "#ffd700"; |
|||
|
|||
static char hidnormfgcolor[] = "#ffd700"; |
|||
static char hidnormbgcolor[] = "#222222"; |
|||
static char hidselfgcolor[] = "#ffd700"; |
|||
static char hidselbgcolor[] = "#ffd700"; |
|||
static char hidbordercolor[] = "#ffd700"; |
|||
static char hidfloatcolor[] = "#f76e0c"; |
|||
|
|||
static char urgfgcolor[] = "#bbbbbb"; |
|||
static char urgbgcolor[] = "#222222"; |
|||
static char urgbordercolor[] = "#ff0000"; |
|||
static char urgfloatcolor[] = "#db8fd9"; |
|||
|
|||
|
|||
static const unsigned int baralpha = 0xd0; |
|||
static const unsigned int borderalpha = OPAQUE; |
|||
static const unsigned int alphas[][3] = { |
|||
/* fg bg border */ |
|||
[SchemeNorm] = { OPAQUE, baralpha, borderalpha }, |
|||
[SchemeSel] = { OPAQUE, baralpha, borderalpha }, |
|||
[SchemeTitleNorm] = { OPAQUE, baralpha, borderalpha }, |
|||
[SchemeTitleSel] = { OPAQUE, baralpha, borderalpha }, |
|||
[SchemeTagsNorm] = { OPAQUE, baralpha, borderalpha }, |
|||
[SchemeTagsSel] = { OPAQUE, baralpha, borderalpha }, |
|||
[SchemeHidNorm] = { OPAQUE, baralpha, borderalpha }, |
|||
[SchemeHidSel] = { OPAQUE, baralpha, borderalpha }, |
|||
[SchemeUrg] = { OPAQUE, baralpha, borderalpha }, |
|||
}; |
|||
|
|||
static char *colors[][ColCount] = { |
|||
/* fg bg border float */ |
|||
[SchemeNorm] = { normfgcolor, normbgcolor, normbordercolor, normfloatcolor }, |
|||
[SchemeSel] = { selfgcolor, selbgcolor, selbordercolor, selfloatcolor }, |
|||
[SchemeTitleNorm] = { titlenormfgcolor, titlenormbgcolor, titlenormbordercolor, titlenormfloatcolor }, |
|||
[SchemeTitleSel] = { titleselfgcolor, titleselbgcolor, titleselbordercolor, titleselfloatcolor }, |
|||
[SchemeTagsNorm] = { tagsnormfgcolor, tagsnormbgcolor, tagsnormbordercolor, tagsnormfloatcolor }, |
|||
[SchemeTagsSel] = { tagsselfgcolor, tagsselbgcolor, tagsselbordercolor, tagsselfloatcolor }, |
|||
[SchemeHidNorm] = { hidnormfgcolor, hidnormbgcolor, hidbordercolor, hidfloatcolor }, |
|||
[SchemeHidSel] = { hidselfgcolor, hidselbgcolor, hidbordercolor, hidfloatcolor }, |
|||
[SchemeUrg] = { urgfgcolor, urgbgcolor, urgbordercolor, urgfloatcolor }, |
|||
}; |
|||
|
|||
/* |
|||
static char *statuscolors[][ColCount] = { |
|||
// fg bg border float |
|||
[SchemeNorm] = { normfgcolor, normbgcolor, normbordercolor, normfloatcolor }, |
|||
[SchemeSel] = { selfgcolor, selbgcolor, selbordercolor, selfloatcolor }, |
|||
[SchemeTitleNorm] = { titlenormfgcolor, titlenormbgcolor, titlenormbordercolor, titlenormfloatcolor }, |
|||
[SchemeTitleSel] = { titleselfgcolor, titleselbgcolor, titleselbordercolor, titleselfloatcolor }, |
|||
[SchemeTagsNorm] = { tagsnormfgcolor, tagsnormbgcolor, tagsnormbordercolor, tagsnormfloatcolor }, |
|||
[SchemeTagsSel] = { tagsselfgcolor, tagsselbgcolor, tagsselbordercolor, tagsselfloatcolor }, |
|||
[SchemeHidNorm] = { hidnormfgcolor, hidnormbgcolor, hidbordercolor, hidfloatcolor }, |
|||
[SchemeHidSel] = { hidselfgcolor, hidselbgcolor, hidbordercolor, hidfloatcolor }, |
|||
[SchemeUrg] = { urgfgcolor, urgbgcolor, urgbordercolor, urgfloatcolor }, |
|||
}; |
|||
*/ |
|||
|
|||
|
|||
|
|||
/* Tags |
|||
* In a traditional dwm the number of tags in use can be changed simply by changing the number |
|||
* of strings in the tags array. This build does things a bit different which has some added |
|||
* benefits. If you need to change the number of tags here then change the NUMTAGS macro in dwm.c. |
|||
* |
|||
* Examples: |
|||
* |
|||
* 1) static char *tagicons[][NUMTAGS*2] = { |
|||
* [DEFAULT_TAGS] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I" }, |
|||
* } |
|||
* |
|||
* 2) static char *tagicons[][1] = { |
|||
* [DEFAULT_TAGS] = { "•" }, |
|||
* } |
|||
* |
|||
* The first example would result in the tags on the first monitor to be 1 through 9, while the |
|||
* tags for the second monitor would be named A through I. A third monitor would start again at |
|||
* 1 through 9 while the tags on a fourth monitor would also be named A through I. Note the tags |
|||
* count of NUMTAGS*2 in the array initialiser which defines how many tag text / icon exists in |
|||
* the array. This can be changed to *3 to add separate icons for a third monitor. |
|||
* |
|||
* For the second example each tag would be represented as a bullet point. Both cases work the |
|||
* same from a technical standpoint - the icon index is derived from the tag index and the monitor |
|||
* index. If the icon index is is greater than the number of tag icons then it will wrap around |
|||
* until it an icon matches. Similarly if there are two tag icons then it would alternate between |
|||
* them. This works seamlessly with alternative tags and alttagsdecoration patches. |
|||
*/ |
|||
static char *tagicons[][NUMTAGS] = { |
|||
// [DEFAULT_TAGS] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }, |
|||
[DEFAULT_TAGS] = { "₁", "₂", "₃", "₄", "₅", "₆", "₇", "₈", "₉" }, |
|||
[ALTERNATIVE_TAGS] = { "A", "B", "C", "D", "E", "F", "G", "H", "I" }, |
|||
[ALT_TAGS_DECORATION] = { "<1>", "<2>", "<3>", "<4>", "<5>", "<6>", "<7>", "<8>", "<9>" }, |
|||
}; |
|||
|
|||
|
|||
|
|||
|
|||
/* There are two options when it comes to per-client rules: |
|||
* - a typical struct table or |
|||
* - using the RULE macro |
|||
* |
|||
* A traditional struct table looks like this: |
|||
* // class instance title wintype tags mask isfloating monitor |
|||
* { "Gimp", NULL, NULL, NULL, 1 << 4, 0, -1 }, |
|||
* { "Firefox", NULL, NULL, NULL, 1 << 7, 0, -1 }, |
|||
* |
|||
* The RULE macro has the default values set for each field allowing you to only |
|||
* specify the values that are relevant for your rule, e.g. |
|||
* |
|||
* RULE(.class = "Gimp", .tags = 1 << 4) |
|||
* RULE(.class = "Firefox", .tags = 1 << 7) |
|||
* |
|||
* Refer to the Rule struct definition for the list of available fields depending on |
|||
* the patches you enable. |
|||
*/ |
|||
static const Rule rules[] = { |
|||
/* xprop(1): |
|||
* WM_CLASS(STRING) = instance, class |
|||
* WM_NAME(STRING) = title |
|||
* WM_WINDOW_ROLE(STRING) = role |
|||
* _NET_WM_WINDOW_TYPE(ATOM) = wintype |
|||
*/ |
|||
RULE(.wintype = WTYPE "DIALOG", .isfloating = 1) |
|||
RULE(.wintype = WTYPE "UTILITY", .isfloating = 1) |
|||
RULE(.wintype = WTYPE "TOOLBAR", .isfloating = 1) |
|||
RULE(.wintype = WTYPE "SPLASH", .isfloating = 1) |
|||
RULE(.instance= "main", .class = "Psi+", .tags = 1 << 2) |
|||
RULE(.instance= "tabs", .class = "Psi+", .tags = 1 << 2) |
|||
RULE(.class = "Claws-mail", .tags = 1 << 2) |
|||
RULE(.class = "Zoiper", .tags = 1 << 2) |
|||
RULE(.class = "linphone", .tags = 1 << 2) |
|||
RULE(.class = "Skype", .tags = 1 << 2) |
|||
RULE(.class = "Mattermost", .tags = 1 << 2) |
|||
|
|||
RULE(.class = "pinentry-qt", .isfloating = 1) |
|||
RULE(.class = "pinentry-qt5", .isfloating = 1) |
|||
RULE(.class = "Nm-connection-editor", .isfloating = 1) |
|||
RULE(.class = "pavucontrol-qt", .isfloating = 0) |
|||
RULE(.class = "Gimp", .tags = 1 << 4) |
|||
RULE(.class = "Firefox", .wintype = WTYPE "NORMAL", .tags = 1 << 1) |
|||
|
|||
RULE(.class = "Spotify", .tags = 1 << 7) |
|||
|
|||
RULE(.class = "st-tilda", .isfloating = 1) |
|||
RULE(.class = "st-256color", .isterminal = 1) |
|||
}; |
|||
|
|||
|
|||
|
|||
/* Bar rules allow you to configure what is shown where on the bar, as well as |
|||
* introducing your own bar modules. |
|||
* |
|||
* monitor: |
|||
* -1 show on all monitors |
|||
* 0 show on monitor 0 |
|||
* 'A' show on active monitor (i.e. focused / selected) (or just -1 for active?) |
|||
* bar - bar index, 0 is default, 1 is extrabar |
|||
* alignment - how the module is aligned compared to other modules |
|||
* widthfunc, drawfunc, clickfunc - providing bar module width, draw and click functions |
|||
* name - does nothing, intended for visual clue and for logging / debugging |
|||
*/ |
|||
static const BarRule barrules[] = { |
|||
/* monitor bar alignment widthfunc drawfunc clickfunc name */ |
|||
{ -1, 0, BAR_ALIGN_LEFT, width_pwrl_tags, draw_pwrl_tags, click_pwrl_tags, "powerline_tags" }, |
|||
//{ -1, 0, BAR_ALIGN_LEFT, width_tags, draw_tags, click_tags, "tags" }, |
|||
{ 'A', 0, BAR_ALIGN_RIGHT, width_systray, draw_systray, click_systray, "systray" }, |
|||
{ -1, 0, BAR_ALIGN_LEFT, width_ltsymbol, draw_ltsymbol, click_ltsymbol, "layout" }, |
|||
// { 'A', 0, BAR_ALIGN_RIGHT, width_pwrl_status, draw_pwrl_status, click_pwrl_status, "powerline_status" }, |
|||
{ statusmon, 0, BAR_ALIGN_RIGHT, width_status, draw_status, click_statuscmd, "status" }, |
|||
{ -1, 0, BAR_ALIGN_NONE, width_bartabgroups, draw_bartabgroups, click_bartabgroups, "bartabgroups" }, |
|||
}; |
|||
|
|||
/* 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 */ |
|||
static const int resizehints = 0; /* 1 means respect size hints in tiled resizals */ |
|||
static const int decorhints = 1; /* 1 means respect decoration hints */ |
|||
|
|||
#define FORCE_VSPLIT 1 |
|||
|
|||
|
|||
static const Layout layouts[] = { |
|||
/* symbol arrange function */ |
|||
{ "[]=", tile }, /* first entry is default */ |
|||
{ "><>", NULL }, /* no layout function means floating behavior */ |
|||
{ "[M]", monocle }, |
|||
{ "|M|", centeredmaster }, |
|||
{ ">M>", centeredfloatingmaster }, |
|||
{ "[\\]", dwindle }, |
|||
{ "###", nrowgrid }, |
|||
}; |
|||
|
|||
|
|||
/* key definitions */ |
|||
#define MODKEY Mod4Mask |
|||
#define AltMask Mod1Mask |
|||
#define ALTKEY Mod1Mask |
|||
#define TAGKEYS(KEY,TAG) \ |
|||
{ MODKEY, KEY, view, {.ui = 1 << TAG} }, \ |
|||
{ MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \ |
|||
{ MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \ |
|||
{ MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} }, |
|||
|
|||
|
|||
|
|||
/* helper for spawning shell commands in the pre dwm-5.0 fashion */ |
|||
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } |
|||
|
|||
/* commands */ |
|||
static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ |
|||
static const char *dmenucmd[] = { |
|||
"dmenu_run", |
|||
"-m", dmenumon, |
|||
"-fn", dmenufont, |
|||
"-nb", normbgcolor, |
|||
"-nf", normfgcolor, |
|||
"-sb", selbgcolor, |
|||
"-sf", selfgcolor, |
|||
NULL |
|||
}; |
|||
static const char *termcmd[] = { "st", NULL }; |
|||
static const char *tmuxcmd[] = { "st", "-c", "st-tmux", "-e", "/home/wiebel/sync/bin/tmux-spawn.sh", NULL }; |
|||
// static const char scratchpadname[] = "tilda"; |
|||
/* static const char *scratchpadcmd[] = { "st", "-t", scratchpadname, "-g", "120x34", NULL }; */ |
|||
// static const char *scratchpadcmd[] = { "st", "-t", scratchpadname, "-c", "st-tilda", "-g", "180x18", "-e", "tmux", "new-session", "-A", "-s", "tilda", NULL }; |
|||
|
|||
static const char *volup[] = { "/opt/pavolume/pavolume", "volup", "10", NULL }; |
|||
static const char *voldn[] = { "/opt/pavolume/pavolume", "voldown", "10", NULL }; |
|||
static const char *volmute[] = { "/opt/pavolume/pavolume", "mutetoggle", NULL }; |
|||
static const char *playpause[] = { "/usr/bin/playerctl", "play-pause", NULL }; |
|||
#include <X11/XF86keysym.h> |
|||
|
|||
/* This defines the name of the executable that handles the bar (used for signalling purposes) */ |
|||
#define STATUSBAR "dwmblocks" |
|||
|
|||
|
|||
static Key keys[] = { |
|||
/* modifier key function argument */ |
|||
{ MODKEY, XK_p, spawn, {.v = dmenucmd } }, |
|||
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = tmuxcmd } }, |
|||
{ MODKEY|ControlMask, XK_Return, spawn, {.v = termcmd } }, |
|||
{ MODKEY, XK_b, togglebar, {0} }, |
|||
{ MODKEY|ControlMask, XK_s, spawn, SHCMD("transset -a --dec .1") }, |
|||
{ MODKEY|ControlMask, XK_d, spawn, SHCMD("transset -a --inc .1") }, |
|||
{ ALTKEY, XK_w, spawn, SHCMD("pass-wrapper.sh") }, |
|||
{ MODKEY, XK_n, spawn, SHCMD("networkmanager_dmenu") }, |
|||
// { MODKEY, XK_grave, spawn, SHCMD("/home/wiebel/sync/bin/st-tilda.sh") }, |
|||
{ ALTKEY|ControlMask, XK_l, spawn, SHCMD("/usr/local/bin/lock.me") }, |
|||
/* Media Keys */ |
|||
{ 0, XF86XK_MonBrightnessUp, spawn, SHCMD("xbacklight -inc 5") }, |
|||
{ 0, XF86XK_MonBrightnessDown, spawn, SHCMD("xbacklight -dec 5") }, |
|||
{ 0, XF86XK_AudioRaiseVolume, spawn, {.v = volup } }, |
|||
{ 0, XF86XK_AudioLowerVolume, spawn, {.v = voldn } }, |
|||
{ 0, XF86XK_AudioMute, spawn, {.v = volmute } }, |
|||
{ 0, XF86XK_AudioPlay, spawn, {.v = playpause } }, |
|||
{ MODKEY, XK_j, focusstack, {.i = +1 } }, |
|||
{ MODKEY, XK_k, focusstack, {.i = -1 } }, |
|||
{ MODKEY|ShiftMask, XK_j, inplacerotate, {.i = +1} }, |
|||
{ MODKEY|ShiftMask, XK_k, inplacerotate, {.i = -1} }, |
|||
{ MODKEY, XK_i, incnmaster, {.i = +1 } }, |
|||
{ MODKEY, XK_d, incnmaster, {.i = -1 } }, |
|||
{ MODKEY, XK_h, setmfact, {.f = -0.05} }, |
|||
{ MODKEY, XK_l, setmfact, {.f = +0.05} }, |
|||
{ MODKEY, XK_x, transfer, {0} }, |
|||
{ MODKEY, XK_Return, zoom, {0} }, |
|||
// { MODKEY|AltMask, XK_u, incrgaps, {.i = +1 } }, |
|||
// { MODKEY|AltMask|ShiftMask, XK_u, incrgaps, {.i = -1 } }, |
|||
// { MODKEY|AltMask, XK_i, incrigaps, {.i = +1 } }, |
|||
// { MODKEY|AltMask|ShiftMask, XK_i, incrigaps, {.i = -1 } }, |
|||
// { MODKEY|AltMask, XK_o, incrogaps, {.i = +1 } }, |
|||
// { MODKEY|AltMask|ShiftMask, XK_o, incrogaps, {.i = -1 } }, |
|||
// { MODKEY|AltMask, XK_6, incrihgaps, {.i = +1 } }, |
|||
// { MODKEY|AltMask|ShiftMask, XK_6, incrihgaps, {.i = -1 } }, |
|||
// { MODKEY|AltMask, XK_7, incrivgaps, {.i = +1 } }, |
|||
// { MODKEY|AltMask|ShiftMask, XK_7, incrivgaps, {.i = -1 } }, |
|||
// { MODKEY|AltMask, XK_8, incrohgaps, {.i = +1 } }, |
|||
// { MODKEY|AltMask|ShiftMask, XK_8, incrohgaps, {.i = -1 } }, |
|||
// { MODKEY|AltMask, XK_9, incrovgaps, {.i = +1 } }, |
|||
// { MODKEY|AltMask|ShiftMask, XK_9, incrovgaps, {.i = -1 } }, |
|||
// { MODKEY|AltMask, XK_0, togglegaps, {0} }, |
|||
// { MODKEY|AltMask|ShiftMask, XK_0, defaultgaps, {0} }, |
|||
{ MODKEY, XK_Tab, view, {0} }, |
|||
{ MODKEY|ControlMask, XK_z, showhideclient, {0} }, |
|||
{ MODKEY, XK_q, killclient, {0} }, |
|||
{ MODKEY|ShiftMask, XK_c, killclient, {0} }, |
|||
{ MODKEY|ShiftMask, XK_q, quit, {0} }, |
|||
{ MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, |
|||
{ MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, |
|||
{ MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, |
|||
{ MODKEY, XK_u, setlayout, {.v = &layouts[3]} }, |
|||
{ MODKEY, XK_o, setlayout, {.v = &layouts[4]} }, |
|||
{ MODKEY|ShiftMask, XK_t, setlayout, {.v = &layouts[5]} }, |
|||
{ MODKEY, XK_g, setlayout, {.v = &layouts[6]} }, |
|||
{ MODKEY, XK_space, setlayout, {0} }, |
|||
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} }, |
|||
{ MODKEY|ShiftMask, XK_y, togglefakefullscreen, {0} }, |
|||
{ MODKEY|ShiftMask, XK_s, togglesticky, {0} }, |
|||
{ MODKEY, XK_grave, scratchpad_show, {0} }, |
|||
{ MODKEY, XK_Escape, scratchpad_show, {0} }, |
|||
{ MODKEY|ShiftMask, XK_grave, scratchpad_hide, {0} }, |
|||
{ MODKEY|ShiftMask, XK_Escape, scratchpad_hide, {0} }, |
|||
{ MODKEY|ShiftMask|ControlMask, XK_grave, scratchpad_remove, {0} }, |
|||
{ MODKEY|ShiftMask|ControlMask, XK_Escape, scratchpad_remove, {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, XK_Left, viewtoleft, {0} }, |
|||
{ MODKEY, XK_Right, viewtoright, {0} }, |
|||
{ MODKEY|ShiftMask, XK_Left, tagtoleft, {0} }, |
|||
{ MODKEY|ShiftMask, XK_Right, tagtoright, {0} }, |
|||
{ MODKEY|ControlMask, XK_Left, tagandviewtoleft, {0} }, |
|||
{ MODKEY|ControlMask, XK_Right, tagandviewtoright, {0} }, |
|||
{ MODKEY|ControlMask, XK_comma, tagallmon, {.i = +1 } }, |
|||
{ MODKEY|ControlMask, XK_period, tagallmon, {.i = -1 } }, |
|||
{ MODKEY|ShiftMask|ControlMask, XK_comma, tagswap:mon, {.i = +1 } }, |
|||
{ MODKEY|ShiftMask|ControlMask, XK_period, tagswapmon, {.i = -1 } }, |
|||
|
|||
{ MODKEY, XK_0, view, {.ui = ~0 } }, |
|||
{ MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, |
|||
TAGKEYS( XK_1, 0) |
|||
TAGKEYS( XK_2, 1) |
|||
TAGKEYS( XK_3, 2) |
|||
TAGKEYS( XK_4, 3) |
|||
TAGKEYS( XK_5, 4) |
|||
TAGKEYS( XK_6, 5) |
|||
TAGKEYS( XK_7, 6) |
|||
TAGKEYS( XK_8, 7) |
|||
TAGKEYS( XK_9, 8) |
|||
}; |
|||
|
|||
|
|||
/* button definitions */ |
|||
/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ |
|||
static Button buttons[] = { |
|||
/* click event mask button function argument */ |
|||
{ ClkLtSymbol, 0, Button1, setlayout, {0} }, |
|||
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, |
|||
{ ClkWinTitle, 0, Button1, togglewin, {0} }, |
|||
{ ClkWinTitle, 0, Button3, showhideclient, {0} }, |
|||
{ ClkWinTitle, 0, Button2, zoom, {0} }, |
|||
{ ClkStatusText, 0, Button1, sigstatusbar, {.i = 1 } }, |
|||
{ ClkStatusText, 0, Button2, sigstatusbar, {.i = 2 } }, |
|||
{ ClkStatusText, 0, Button3, sigstatusbar, {.i = 3 } }, |
|||
{ ClkClientWin, MODKEY, Button1, movemouse, {0} }, |
|||
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} }, |
|||
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} }, |
|||
{ ClkTagBar, 0, Button1, view, {0} }, |
|||
{ ClkTagBar, 0, Button3, toggleview, {0} }, |
|||
{ ClkTagBar, MODKEY, Button1, tag, {0} }, |
|||
{ ClkTagBar, MODKEY, Button3, toggletag, {0} }, |
|||
}; |
|||
|
|||
|
@ -0,0 +1,70 @@ |
|||
# dwm version
|
|||
VERSION = 6.2 |
|||
|
|||
# Customize below to fit your system
|
|||
|
|||
# paths
|
|||
PREFIX = /usr/local |
|||
MANPREFIX = ${PREFIX}/share/man |
|||
|
|||
X11INC = /usr/X11R6/include |
|||
X11LIB = /usr/X11R6/lib |
|||
|
|||
# FreeBSD (uncomment)
|
|||
#X11INC = /usr/local/include
|
|||
#X11LIB = /usr/local/lib
|
|||
|
|||
# Xinerama, comment if you don't want it
|
|||
XINERAMALIBS = -lXinerama |
|||
XINERAMAFLAGS = -DXINERAMA |
|||
|
|||
# freetype
|
|||
FREETYPELIBS = -lfontconfig -lXft |
|||
FREETYPEINC = /usr/include/freetype2 |
|||
# FreeBSD (uncomment)
|
|||
#FREETYPEINC = /usr/local/include/freetype2
|
|||
# OpenBSD (uncomment)
|
|||
#FREETYPEINC = ${X11INC}/freetype2
|
|||
# OpenBSD - Uncomment this for the swallow patch / SWALLOW_PATCH
|
|||
#KVMLIB = -lkvm
|
|||
|
|||
# Uncomment this for the alpha patch / BAR_ALPHA_PATCH
|
|||
XRENDER = -lXrender |
|||
|
|||
# Uncomment this for the mdpcontrol patch / MDPCONTROL_PATCH
|
|||
#MPDCLIENT = -lmpdclient
|
|||
|
|||
# Uncomment for the pango patch / BAR_PANGO_PATCH
|
|||
#PANGOINC = `pkg-config --cflags xft pango pangoxft`
|
|||
#PANGOLIB = `pkg-config --libs xft pango pangoxft`
|
|||
|
|||
# Uncomment for the ipc patch / IPC_PATCH
|
|||
#YAJLLIBS = -lyajl
|
|||
#YAJLINC = -I/usr/include/yajl
|
|||
|
|||
# Uncomment this for the rounded corners patch / ROUNDED_CORNERS_PATCH
|
|||
#XEXTLIB = -lXext
|
|||
|
|||
# Uncomment this for the swallow patch / SWALLOW_PATCH
|
|||
XCBLIBS = -lX11-xcb -lxcb -lxcb-res |
|||
|
|||
# This is needed for the winicon patch / BAR_WINICON_PATCH
|
|||
#IMLIB2LIBS = -lImlib2
|
|||
|
|||
# includes and libs
|
|||
INCS = -I${X11INC} -I${FREETYPEINC} ${YAJLINC} ${PANGOINC} |
|||
LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} ${XRENDER} ${MPDCLIENT} ${XEXTLIB} ${XCBLIBS} ${KVMLIB} ${PANGOLIB} ${YAJLLIBS} ${IMLIB2LIBS} |
|||
|
|||
# flags
|
|||
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} |
|||
#CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS}
|
|||
#CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS}
|
|||
CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -march=native -O3 -flto ${INCS} ${CPPFLAGS} |
|||
LDFLAGS = -flto ${LIBS} |
|||
|
|||
# Solaris
|
|||
#CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\"
|
|||
#LDFLAGS = ${LIBS}
|
|||
|
|||
# compiler and linker
|
|||
CC = cc |
@ -0,0 +1,490 @@ |
|||
/* See LICENSE file for copyright and license details. */ |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <X11/Xlib.h> |
|||
#include <X11/Xft/Xft.h> |
|||
|
|||
#include "drw.h" |
|||
#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}; |
|||
|
|||
Clr transcheme[3]; |
|||
|
|||
static long |
|||
utf8decodebyte(const char c, size_t *i) |
|||
{ |
|||
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; |
|||
|
|||
*u = UTF_INVALID; |
|||
if (!clen) |
|||
return 0; |
|||
udecoded = utf8decodebyte(c[0], &len); |
|||
if (!BETWEEN(len, 1, UTF_SIZ)) |
|||
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); |
|||
|
|||
return len; |
|||
} |
|||
|
|||
Drw * |
|||
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)); |
|||
|
|||
drw->dpy = dpy; |
|||
drw->screen = screen; |
|||
drw->root = root; |
|||
drw->w = w; |
|||
drw->h = h; |
|||
|
|||
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; |
|||
} |
|||
|
|||
void |
|||
drw_resize(Drw *drw, unsigned int w, unsigned int h) |
|||
{ |
|||
if (!drw) |
|||
return; |
|||
|
|||
drw->w = w; |
|||
drw->h = h; |
|||
if (drw->drawable) |
|||
XFreePixmap(drw->dpy, drw->drawable); |
|||
drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, drw->depth); |
|||
} |
|||
|
|||
void |
|||
drw_free(Drw *drw) |
|||
{ |
|||
XFreePixmap(drw->dpy, drw->drawable); |
|||
XFreeGC(drw->dpy, drw->gc); |
|||
drw_fontset_free(drw->fonts); |
|||
free(drw); |
|||
} |
|||
|
|||
/* This function is an implementation detail. Library users should use
|
|||
* drw_fontset_create instead. |
|||
*/ |
|||
static Fnt * |
|||
xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern) |
|||
{ |
|||
Fnt *font; |
|||
XftFont *xfont = NULL; |
|||
FcPattern *pattern = NULL; |
|||
|
|||
if (fontname) { |
|||
/* Using the pattern found at font->xfont->pattern does not yield the
|
|||
* same substitution results as using the pattern returned by |
|||
* FcNameParse; using the latter results in the desired fallback |
|||
* behaviour whereas the former just results in missing-character |
|||
* rectangles being drawn, at least with some fonts. */ |
|||
if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) { |
|||
fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname); |
|||
return NULL; |
|||
} |
|||
if (!(pattern = FcNameParse((FcChar8 *) fontname))) { |
|||
fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n", fontname); |
|||
XftFontClose(drw->dpy, xfont); |
|||
return NULL; |
|||
} |
|||
} else if (fontpattern) { |
|||
if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) { |
|||
fprintf(stderr, "error, cannot load font from pattern.\n"); |
|||
return NULL; |
|||
} |
|||
} else { |
|||
die("no font specified."); |
|||
} |
|||
|
|||
/* Do not allow using color fonts. This is a workaround for a BadLength
|
|||
* error from Xft with color glyphs. Modelled on the Xterm workaround. See |
|||
* https://bugzilla.redhat.com/show_bug.cgi?id=1498269
|
|||
* https://lists.suckless.org/dev/1701/30932.html
|
|||
* https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=916349
|
|||
* and lots more all over the internet. |
|||
*/ |
|||
FcBool iscol; |
|||
if (FcPatternGetBool(xfont->pattern, FC_COLOR, 0, &iscol) == FcResultMatch && iscol) { |
|||
XftFontClose(drw->dpy, xfont); |
|||
return NULL; |
|||
} |
|||
|
|||
font = ecalloc(1, sizeof(Fnt)); |
|||
font->xfont = xfont; |
|||
font->pattern = pattern; |
|||
font->h = xfont->ascent + xfont->descent; |
|||
font->dpy = drw->dpy; |
|||
|
|||
return font; |
|||
} |
|||
|
|||
static void |
|||
xfont_free(Fnt *font) |
|||
{ |
|||
if (!font) |
|||
return; |
|||
if (font->pattern) |
|||
FcPatternDestroy(font->pattern); |
|||
XftFontClose(font->dpy, font->xfont); |
|||
free(font); |
|||
} |
|||
|
|||
Fnt* |
|||
drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount) |
|||
{ |
|||
Fnt *cur, *ret = NULL; |
|||
size_t i; |
|||
|
|||
if (!drw || !fonts) |
|||
return NULL; |
|||
|
|||
for (i = 1; i <= fontcount; i++) { |
|||
if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) { |
|||
cur->next = ret; |
|||
ret = cur; |
|||
} |
|||
} |
|||
return (drw->fonts = ret); |
|||
} |
|||
|
|||
void |
|||
drw_fontset_free(Fnt *font) |
|||
{ |
|||
if (font) { |
|||
drw_fontset_free(font->next); |
|||
xfont_free(font); |
|||
} |
|||
} |
|||
|
|||
void |
|||
drw_clr_create( |
|||
Drw *drw, |
|||
Clr *dest, |
|||
const char *clrname |
|||
, unsigned int alpha |
|||
) { |
|||
if (!drw || !dest || !clrname) |
|||
return; |
|||
|
|||
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, |
|||
char *clrnames[], |
|||
const unsigned int alphas[], |
|||
size_t clrcount |
|||
) { |
|||
size_t i; |
|||
Clr *ret; |
|||
|
|||
/* need at least two colors for a scheme */ |
|||
if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor)))) |
|||
return NULL; |
|||
|
|||
for (i = 0; i < clrcount; i++) |
|||
drw_clr_create(drw, &ret[i], clrnames[i], alphas[i]); |
|||
return ret; |
|||
} |
|||
|
|||
void |
|||
drw_setfontset(Drw *drw, Fnt *set) |
|||
{ |
|||
if (drw) |
|||
drw->fonts = set; |
|||
} |
|||
|
|||
void |
|||
drw_setscheme(Drw *drw, Clr *scm) |
|||
{ |
|||
if (drw) |
|||
drw->scheme = scm; |
|||
} |
|||
|
|||
void |
|||
drw_settrans(Drw *drw, Clr *psc, Clr *nsc) |
|||
{ |
|||
if (drw) { |
|||
transcheme[0] = psc[ColBg]; transcheme[1] = nsc[ColBg]; transcheme[2] = psc[ColBorder]; |
|||
drw->scheme = transcheme; |
|||
} |
|||
} |
|||
|
|||
void |
|||
drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert) |
|||
{ |
|||
if (!drw || !drw->scheme) |
|||
return; |
|||
XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel); |
|||
if (filled) |
|||
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); |
|||
else |
|||
XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1); |
|||
} |
|||
|
|||
int |
|||
drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert, Bool ignored) |
|||
{ |
|||
char buf[1024]; |
|||
int ty; |
|||
unsigned int ew; |
|||
XftDraw *d = NULL; |
|||
Fnt *usedfont, *curfont, *nextfont; |
|||
size_t i, len; |
|||
int utf8strlen, utf8charlen, render = x || y || w || h; |
|||
long utf8codepoint = 0; |
|||
const char *utf8str; |
|||
FcCharSet *fccharset; |
|||
FcPattern *fcpattern; |
|||
FcPattern *match; |
|||
XftResult result; |
|||
int charexists = 0; |
|||
|
|||
if (!drw || (render && !drw->scheme) || !text || !drw->fonts) |
|||
return 0; |
|||
|
|||
if (!render) { |
|||
w = ~w; |
|||
} 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, drw->visual, drw->cmap); |
|||
x += lpad; |
|||
w -= lpad; |
|||
} |
|||
|
|||
usedfont = drw->fonts; |
|||
while (1) { |
|||
utf8strlen = 0; |
|||
utf8str = text; |
|||
nextfont = NULL; |
|||
while (*text) { |
|||
utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ); |
|||
for (curfont = drw->fonts; curfont; curfont = curfont->next) { |
|||
charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint); |
|||
if (charexists) { |
|||
if (curfont == usedfont) { |
|||
utf8strlen += utf8charlen; |
|||
text += utf8charlen; |
|||
} else { |
|||
nextfont = curfont; |
|||
} |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (!charexists || nextfont) |
|||
break; |
|||
else |
|||
charexists = 0; |
|||
} |
|||
|
|||
if (utf8strlen) { |
|||
drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL); |
|||
/* shorten text if necessary */ |
|||
for (len = MIN(utf8strlen, sizeof(buf) - 1); len && ew > w; len--) |
|||
drw_font_getexts(usedfont, utf8str, len, &ew, NULL); |
|||
|
|||
if (len) { |
|||
memcpy(buf, utf8str, len); |
|||
buf[len] = '\0'; |
|||
if (len < utf8strlen) |
|||
for (i = len; i && i > len - 3; buf[--i] = '.') |
|||
; /* NOP */ |
|||
|
|||
if (render) { |
|||
ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent; |
|||
XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg], |
|||
usedfont->xfont, x, ty, (XftChar8 *)buf, len); |
|||
} |
|||
x += ew; |
|||
w -= ew; |
|||
} |
|||
} |
|||
|
|||
if (!*text) { |
|||
break; |
|||
} else if (nextfont) { |
|||
charexists = 0; |
|||
usedfont = nextfont; |
|||
} else { |
|||
/* Regardless of whether or not a fallback font is found, the
|
|||
* character must be drawn. */ |
|||
charexists = 1; |
|||
|
|||
fccharset = FcCharSetCreate(); |
|||
FcCharSetAddChar(fccharset, utf8codepoint); |
|||
|
|||
if (!drw->fonts->pattern) { |
|||
/* Refer to the comment in xfont_create for more information. */ |
|||
die("the first font in the cache must be loaded from a font string."); |
|||
} |
|||
|
|||
fcpattern = FcPatternDuplicate(drw->fonts->pattern); |
|||
FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); |
|||
FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue); |
|||
FcPatternAddBool(fcpattern, FC_COLOR, FcFalse); |
|||
|
|||
FcConfigSubstitute(NULL, fcpattern, FcMatchPattern); |
|||
FcDefaultSubstitute(fcpattern); |
|||
match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result); |
|||
|
|||
FcCharSetDestroy(fccharset); |
|||
FcPatternDestroy(fcpattern); |
|||
|
|||
if (match) { |
|||
usedfont = xfont_create(drw, NULL, match); |
|||
if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) { |
|||
for (curfont = drw->fonts; curfont->next; curfont = curfont->next) |
|||
; /* NOP */ |
|||
curfont->next = usedfont; |
|||
} else { |
|||
xfont_free(usedfont); |
|||
usedfont = drw->fonts; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
if (d) |
|||
XftDrawDestroy(d); |
|||
|
|||
return x + (render ? w : 0); |
|||
} |
|||
|
|||
void |
|||
drw_arrow(Drw *drw, int x, int y, unsigned int w, unsigned int h, int direction, int slash) |
|||
{ |
|||
if (!drw || !drw->scheme) |
|||
return; |
|||
|
|||
/* direction=1 draws right arrow */ |
|||
x = direction ? x : x + w; |
|||
w = direction ? w : -w; |
|||
/* slash=1 draws slash instead of arrow */ |
|||
unsigned int hh = slash ? (direction ? 0 : h) : h/2; |
|||
|
|||
XPoint points[] = { |
|||
{x , y }, |
|||
{x + w, y + hh }, |
|||
{x , y + h }, |
|||
}; |
|||
|
|||
XPoint bg[] = { |
|||
{x , y }, |
|||
{x + w, y }, |
|||
{x + w, y + h}, |
|||
{x , y + h}, |
|||
}; |
|||
|
|||
XSetForeground(drw->dpy, drw->gc, drw->scheme[ColBg].pixel); |
|||
XFillPolygon(drw->dpy, drw->drawable, drw->gc, bg, 4, Convex, CoordModeOrigin); |
|||
XSetForeground(drw->dpy, drw->gc, drw->scheme[ColFg].pixel); |
|||
XFillPolygon(drw->dpy, drw->drawable, drw->gc, points, 3, Nonconvex, CoordModeOrigin); |
|||
} |
|||
|
|||
void |
|||
drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h) |
|||
{ |
|||
if (!drw) |
|||
return; |
|||
|
|||
XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y); |
|||
XSync(drw->dpy, False); |
|||
} |
|||
|
|||
unsigned int |
|||
drw_fontset_getwidth(Drw *drw, const char *text, Bool markup) |
|||
{ |
|||
if (!drw || !drw->fonts || !text) |
|||
return 0; |
|||
return drw_text(drw, 0, 0, 0, 0, 0, text, 0, markup); |
|||
} |
|||
|
|||
void |
|||
drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h) |
|||
{ |
|||
XGlyphInfo ext; |
|||
|
|||
if (!font || !text) |
|||
return; |
|||
|
|||
XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext); |
|||
if (w) |
|||
*w = ext.xOff; |
|||
if (h) |
|||
*h = font->h; |
|||
} |
|||
|
|||
Cur * |
|||
drw_cur_create(Drw *drw, int shape) |
|||
{ |
|||
Cur *cur; |
|||
|
|||
if (!drw || !(cur = ecalloc(1, sizeof(Cur)))) |
|||
return NULL; |
|||
|
|||
cur->cursor = XCreateFontCursor(drw->dpy, shape); |
|||
|
|||
return cur; |
|||
} |
|||
|
|||
void |
|||
drw_cur_free(Drw *drw, Cur *cursor) |
|||
{ |
|||
if (!cursor) |
|||
return; |
|||
|
|||
XFreeCursor(drw->dpy, cursor->cursor); |
|||
free(cursor); |
|||
} |
|||
|
@ -0,0 +1,74 @@ |
|||
/* See LICENSE file for copyright and license details. */ |
|||
|
|||
|
|||
typedef struct { |
|||
Cursor cursor; |
|||
} Cur; |
|||
|
|||
typedef struct Fnt { |
|||
Display *dpy; |
|||
unsigned int h; |
|||
XftFont *xfont; |
|||
FcPattern *pattern; |
|||
struct Fnt *next; |
|||
} Fnt; |
|||
|
|||
enum { ColFg, ColBg, ColBorder, ColFloat, ColCount }; /* Clr scheme index */ |
|||
typedef XftColor Clr; |
|||
|
|||
typedef struct { |
|||
unsigned int w, h; |
|||
Display *dpy; |
|||
int screen; |
|||
Window root; |
|||
Visual *visual; |
|||
unsigned int depth; |
|||
Colormap cmap; |
|||
Drawable drawable; |
|||
GC gc; |
|||
Clr *scheme; |
|||
Fnt *fonts; |
|||
} Drw; |
|||
|
|||
/* Drawable abstraction */ |
|||
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); |
|||
|
|||
/* Fnt abstraction */ |
|||
Fnt *drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount); |
|||
void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h); |
|||
void drw_fontset_free(Fnt* set); |
|||
unsigned int drw_fontset_getwidth(Drw *drw, const char *text, Bool markup); |
|||
|
|||
/* Colorscheme abstraction */ |
|||
void drw_clr_create( |
|||
Drw *drw, |
|||
Clr *dest, |
|||
const char *clrname |
|||
, unsigned int alpha |
|||
); |
|||
Clr *drw_scm_create( |
|||
Drw *drw, |
|||
char *clrnames[], |
|||
const unsigned int alphas[], |
|||
size_t clrcount |
|||
); |
|||
|
|||
/* Cursor abstraction */ |
|||
Cur *drw_cur_create(Drw *drw, int shape); |
|||
void drw_cur_free(Drw *drw, Cur *cursor); |
|||
|
|||
/* Drawing context manipulation */ |
|||
void drw_setfontset(Drw *drw, Fnt *set); |
|||
void drw_setscheme(Drw *drw, Clr *scm); |
|||
void drw_settrans(Drw *drw, Clr *psc, Clr *nsc); |
|||
|
|||
/* Drawing functions */ |
|||
void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert); |
|||
int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert, Bool markup); |
|||
void drw_arrow(Drw *drw, int x, int y, unsigned int w, unsigned int h, int direction, int slash); |
|||
|
|||
/* Map functions */ |
|||
void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h); |
|||
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,176 @@ |
|||
.TH DWM 1 dwm\-VERSION |
|||
.SH NAME |
|||
dwm \- dynamic window manager |
|||
.SH SYNOPSIS |
|||
.B dwm |
|||
.RB [ \-v ] |
|||
.SH DESCRIPTION |
|||
dwm is a dynamic window manager for X. It manages windows in tiled, monocle |
|||
and floating layouts. Either layout can be applied dynamically, optimising the |
|||
environment for the application in use and the task performed. |
|||
.P |
|||
In tiled layouts windows are managed in a master and stacking area. The master |
|||
area on the left contains one window by default, and the stacking area on the |
|||
right contains all other windows. The number of master area windows can be |
|||
adjusted from zero to an arbitrary number. In monocle layout all windows are |
|||
maximised to the screen size. In floating layout windows can be resized and |
|||
moved freely. Dialog windows are always managed floating, regardless of the |
|||
layout applied. |
|||
.P |
|||
Windows are grouped by tags. Each window can be tagged with one or multiple |
|||
tags. Selecting certain tags displays all windows with these tags. |
|||
.P |
|||
Each screen contains a small status bar which displays all available tags, the |
|||
layout, the title of the focused window, and the text read from the root window |
|||
name property, if the screen is focused. A floating window is indicated with an |
|||
empty square and a maximised floating window is indicated with a filled square |
|||
before the windows title. The selected tags are indicated with a different |
|||
color. The tags of the focused window are indicated with a filled square in the |
|||
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. |
|||
.SH OPTIONS |
|||
.TP |
|||
.B \-v |
|||
prints version information to stderr, then exits. |
|||
.SH USAGE |
|||
.SS Status bar |
|||
.TP |
|||
.B X root window name |
|||
is read and displayed in the status text area. It can be set with the |
|||
.BR xsetroot (1) |
|||
command. |
|||
.TP |
|||
.B Button1 |
|||
click on a tag label to display all windows with that tag, click on the layout |
|||
label toggles between tiled and floating layout. |
|||
.TP |
|||
.B Button3 |
|||
click on a tag label adds/removes all windows with that tag to/from the view. |
|||
.TP |
|||
.B Mod1\-Button1 |
|||
click on a tag label applies that tag to the focused window. |
|||
.TP |
|||
.B Mod1\-Button3 |
|||
click on a tag label adds/removes that tag to/from the focused window. |
|||
.SS Keyboard commands |
|||
.TP |
|||
.B Mod1\-Shift\-Return |
|||
Start |
|||
.BR st(1). |
|||
.TP |
|||
.B Mod1\-p |
|||
Spawn |
|||
.BR dmenu(1) |
|||
for launching other programs. |
|||
.TP |
|||
.B Mod1\-, |
|||
Focus previous screen, if any. |
|||
.TP |
|||
.B Mod1\-. |
|||
Focus next screen, if any. |
|||
.TP |
|||
.B Mod1\-Shift\-, |
|||
Send focused window to previous screen, if any. |
|||
.TP |
|||
.B Mod1\-Shift\-. |
|||
Send focused window to next screen, if any. |
|||
.TP |
|||
.B Mod1\-b |
|||
Toggles bar on and off. |
|||
.TP |
|||
.B Mod1\-t |
|||
Sets tiled layout. |
|||
.TP |
|||
.B Mod1\-f |
|||
Sets floating layout. |
|||
.TP |
|||
.B Mod1\-m |
|||
Sets monocle layout. |
|||
.TP |
|||
.B Mod1\-space |
|||
Toggles between current and previous layout. |
|||
.TP |
|||
.B Mod1\-j |
|||
Focus next window. |
|||
.TP |
|||
.B Mod1\-k |
|||
Focus previous window. |
|||
.TP |
|||
.B Mod1\-i |
|||
Increase number of windows in master area. |
|||
.TP |
|||
.B Mod1\-d |
|||
Decrease number of windows in master area. |
|||
.TP |
|||
.B Mod1\-l |
|||
Increase master area size. |
|||
.TP |
|||
.B Mod1\-h |
|||
Decrease master area size. |
|||
.TP |
|||
.B Mod1\-Return |
|||
Zooms/cycles focused window to/from master area (tiled layouts only). |
|||
.TP |
|||
.B Mod1\-Shift\-c |
|||
Close focused window. |
|||
.TP |
|||
.B Mod1\-Shift\-space |
|||
Toggle focused window between tiled and floating state. |
|||
.TP |
|||
.B Mod1\-Tab |
|||
Toggles to the previously selected tags. |
|||
.TP |
|||
.B Mod1\-Shift\-[1..n] |
|||
Apply nth tag to focused window. |
|||
.TP |
|||
.B Mod1\-Shift\-0 |
|||
Apply all tags to focused window. |
|||
.TP |
|||
.B Mod1\-Control\-Shift\-[1..n] |
|||
Add/remove nth tag to/from focused window. |
|||
.TP |
|||
.B Mod1\-[1..n] |
|||
View all windows with nth tag. |
|||
.TP |
|||
.B Mod1\-0 |
|||
View all windows with any tag. |
|||
.TP |
|||
.B Mod1\-Control\-[1..n] |
|||
Add/remove all windows with nth tag to/from the view. |
|||
.TP |
|||
.B Mod1\-Shift\-q |
|||
Quit dwm. |
|||
.SS Mouse commands |
|||
.TP |
|||
.B Mod1\-Button1 |
|||
Move focused window while dragging. Tiled windows will be toggled to the floating state. |
|||
.TP |
|||
.B Mod1\-Button2 |
|||
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 CUSTOMIZATION |
|||
dwm is customized by creating a custom config.h and (re)compiling the source |
|||
code. This keeps it fast, secure and simple. |
|||
.SH SEE ALSO |
|||
.BR dmenu (1), |
|||
.BR st (1) |
|||
.SH ISSUES |
|||
Java applications which use the XToolkit/XAWT backend may draw grey windows |
|||
only. The XToolkit/XAWT backend breaks ICCCM-compliance in recent JDK 1.5 and early |
|||
JDK 1.6 versions, because it assumes a reparenting window manager. Possible workarounds |
|||
are using JDK 1.4 (which doesn't contain the XToolkit/XAWT backend) or setting the |
|||
environment variable |
|||
.BR AWT_TOOLKIT=MToolkit |
|||
(to use the older Motif backend instead) or running |
|||
.B xprop -root -f _NET_WM_NAME 32a -set _NET_WM_NAME LG3D |
|||
or |
|||
.B wmname LG3D |
|||
(to pretend that a non-reparenting window manager is running that the |
|||
XToolkit/XAWT backend can recognize) or when using OpenJDK setting the environment variable |
|||
.BR _JAVA_AWT_WM_NONREPARENTING=1 . |
|||
.SH BUGS |
|||
Send all bug reports with a patch to hackers@suckless.org. |
File diff suppressed because it is too large
Binary file not shown.
After Width: | Height: | Size: 373 B |
@ -0,0 +1,84 @@ |
|||
void |
|||
runautostart(void) |
|||
{ |
|||
char *pathpfx; |
|||
char *path; |
|||
char *xdgdatahome; |
|||
char *home; |
|||
|
|||
if ((home = getenv("HOME")) == NULL) |
|||
/* this is almost impossible */ |
|||
return; |
|||
|
|||
/* if $XDG_DATA_HOME is defined, use $XDG_DATA_HOME/dwm,
|
|||
* otherwise use ~/.local/share/dwm as autostart script directory |
|||
*/ |
|||
if ((xdgdatahome = getenv("XDG_DATA_HOME")) != NULL) { |
|||
/* space for path segments, separators and nul */ |
|||
if ((pathpfx = malloc(strlen(xdgdatahome) + strlen(dwmdir) + 2)) == NULL) |
|||
return; |
|||
|
|||
if (sprintf(pathpfx, "%s/%s", xdgdatahome, dwmdir) <= 0) { |
|||
free(pathpfx); |
|||
return; |
|||
} |
|||
} else { |
|||
/* space for path segments, separators and nul */ |
|||
if ((pathpfx = malloc(strlen(home) + strlen(localshare) + strlen(dwmdir) + 3)) == NULL) |
|||
return; |
|||
|
|||
if (sprintf(pathpfx, "%s/%s/%s", home, localshare, dwmdir) < 0) { |
|||
free(pathpfx); |
|||
return; |
|||
} |
|||
} |
|||
|
|||
/* check if the autostart script directory exists */ |
|||
struct stat sb; |
|||
|
|||
if (! (stat(pathpfx, &sb) == 0 && S_ISDIR(sb.st_mode))) { |
|||
/* the XDG conformant path does not exist or are not directories
|
|||
* so we try ~/.dwm instead |
|||
*/ |
|||
if (realloc(pathpfx, strlen(home) + strlen(dwmdir) + 3) == NULL) { |
|||
free(pathpfx); |
|||
return; |
|||
} |
|||
|
|||
if (sprintf(pathpfx, "%s/.%s", home, dwmdir) <= 0) { |
|||
free(pathpfx); |
|||
return; |
|||
} |
|||
} |
|||
|
|||
/* try the blocking script first */ |
|||
if ((path = malloc(strlen(pathpfx) + strlen(autostartblocksh) + 2)) == NULL) { |
|||
free(pathpfx); |
|||
return; |
|||
} else |
|||
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 ((path = realloc(path, strlen(pathpfx) + strlen(autostartsh) + 4)) == NULL) { |
|||
free(pathpfx); |
|||
free(path); |
|||
return; |
|||
} else |
|||
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); |
|||
} |
|||
} |
|||
|
@ -0,0 +1,2 @@ |
|||
static void runautostart(void); |
|||
|
@ -0,0 +1,43 @@ |
|||
|
|||
static int useargb = 0; |
|||
static Visual *visual; |
|||
static int depth; |
|||
static Colormap cmap; |
|||
|
|||
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); |
|||
} |
|||
} |
|||
|
@ -0,0 +1,4 @@ |
|||
#define OPAQUE 0xffU |
|||
|
|||
static void xinitvisual(); |
|||
|
@ -0,0 +1,41 @@ |
|||
static int statussig; |
|||
pid_t statuspid = -1; |
|||
|
|||
pid_t |
|||
getstatusbarpid() |
|||
{ |
|||
char buf[32], *str = buf, *c; |
|||
FILE *fp; |
|||
|
|||
if (statuspid > 0) { |
|||
snprintf(buf, sizeof(buf), "/proc/%u/cmdline", statuspid); |
|||
if ((fp = fopen(buf, "r"))) { |
|||
fgets(buf, sizeof(buf), fp); |
|||
while ((c = strchr(str, '/'))) |
|||
str = c + 1; |
|||
fclose(fp); |
|||
if (!strcmp(str, STATUSBAR)) |
|||
return statuspid; |
|||
} |
|||
} |
|||
if (!(fp = popen("pgrep -o "STATUSBAR, "r"))) |
|||
return -1; |
|||
fgets(buf, sizeof(buf), fp); |
|||
pclose(fp); |
|||
return strtol(buf, NULL, 10); |
|||
} |
|||
|
|||
void |
|||
sigstatusbar(const Arg *arg) |
|||
{ |
|||
union sigval sv; |
|||
|
|||
if (!statussig) |
|||
return; |
|||
if ((statuspid = getstatusbarpid()) <= 0) |
|||
return; |
|||
|
|||
sv.sival_int = arg->i; |
|||
sigqueue(statuspid, SIGRTMIN+statussig, sv); |
|||
} |
|||
|
@ -0,0 +1,3 @@ |
|||
static int getstatusbarpid(); |
|||
static void sigstatusbar(const Arg *arg); |
|||
|
@ -0,0 +1,53 @@ |
|||
void |
|||
setcurrentdesktop(void) |
|||
{ |
|||
long data[] = { 0 }; |
|||
XChangeProperty(dpy, root, netatom[NetCurrentDesktop], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); |
|||
} |
|||
|
|||
void |
|||
setdesktopnames(void) |
|||
{ |
|||
int i; |
|||
XTextProperty text; |
|||
char *tags[NUMTAGS]; |
|||
for (i = 0; i < NUMTAGS; i++) |
|||
tags[i] = tagicon(selmon, i); |
|||
Xutf8TextListToTextProperty(dpy, tags, NUMTAGS, XUTF8StringStyle, &text); |
|||
XSetTextProperty(dpy, root, &text, netatom[NetDesktopNames]); |
|||
} |
|||
|
|||
void |
|||
setfloatinghint(Client *c) |
|||
{ |
|||
Atom target = XInternAtom(dpy, "_IS_FLOATING", 0); |
|||
unsigned int floating[1] = {c->isfloating}; |
|||
XChangeProperty(dpy, c->win, target, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)floating, 1); |
|||
} |
|||
|
|||
void |
|||
setnumdesktops(void) |
|||
{ |
|||
long data[] = { NUMTAGS }; |
|||
XChangeProperty(dpy, root, netatom[NetNumberOfDesktops], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); |
|||
} |
|||
|
|||
void |
|||
setviewport(void) |
|||
{ |
|||
long data[] = { 0, 0 }; |
|||
XChangeProperty(dpy, root, netatom[NetDesktopViewport], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 2); |
|||
} |
|||
|
|||
void |
|||
updatecurrentdesktop(void) |
|||
{ |
|||
long rawdata[] = { selmon->tagset[selmon->seltags] }; |
|||
int i = 0; |
|||
while (*rawdata >> (i + 1)) { |
|||
i++; |
|||
} |
|||
long data[] = { i }; |
|||
XChangeProperty(dpy, root, netatom[NetCurrentDesktop], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); |
|||
} |
|||
|
@ -0,0 +1,7 @@ |
|||
static void setcurrentdesktop(void); |
|||
static void setdesktopnames(void); |
|||
static void setfloatinghint(Client *c); |
|||
static void setnumdesktops(void); |
|||
static void setviewport(void); |
|||
static void updatecurrentdesktop(void); |
|||
|
@ -0,0 +1,109 @@ |
|||
/* Indicator properties, you can override these in your config.h if you want. */ |
|||
#ifndef TAGSINDICATOR |
|||
#define TAGSINDICATOR 1 // 0 = off, 1 = on if >1 client/view tag, 2 = always on
|
|||
#endif |
|||
#ifndef TAGSPX |
|||
#define TAGSPX 5 // # pixels for tag grid boxes
|
|||
#endif |
|||
#ifndef TAGSROWS |
|||
#define TAGSROWS 3 // # rows in tag grid (9 tags, e.g. 3x3)
|
|||
#endif |
|||
|
|||
void |
|||
drawindicator(Monitor *m, Client *c, unsigned int occ, int x, int y, int w, int h, unsigned int tag, int filled, int invert, int type) |
|||
{ |
|||
int i, boxw, boxs, indn = 0; |
|||
if (!(occ & 1 << tag) || type == INDICATOR_NONE) |
|||
return; |
|||
|
|||
boxs = drw->fonts->h / 9; |
|||
boxw = drw->fonts->h / 6 + 2; |
|||
if (filled == -1) |
|||
filled = m == selmon && m->sel && m->sel->tags & 1 << tag; |
|||
|
|||
switch (type) { |
|||
default: |
|||
case INDICATOR_TOP_LEFT_SQUARE: |
|||
drw_rect(drw, x + boxs, y + boxs, boxw, boxw, filled, invert); |
|||
break; |
|||
case INDICATOR_TOP_LEFT_LARGER_SQUARE: |
|||
drw_rect(drw, x + boxs + 2, y + boxs+1, boxw+1, boxw+1, filled, invert); |
|||
break; |
|||
case INDICATOR_TOP_BAR: |
|||
drw_rect(drw, x + boxw, y, w - ( 2 * boxw + 1), boxw/2, filled, invert); |
|||
break; |
|||
case INDICATOR_TOP_BAR_SLIM: |
|||
drw_rect(drw, x + boxw, y, w - ( 2 * boxw + 1), 1, 0, invert); |
|||
break; |
|||
case INDICATOR_BOTTOM_BAR: |
|||
drw_rect(drw, x + boxw, y + h - boxw/2, w - ( 2 * boxw + 1), boxw/2, filled, invert); |
|||
break; |
|||
case INDICATOR_BOTTOM_BAR_SLIM: |
|||
drw_rect(drw, x + boxw, y + h - 1, w - ( 2 * boxw + 1), 1, 0, invert); |
|||
break; |
|||
case INDICATOR_BOX: |
|||
drw_rect(drw, x + boxw, y, w - 2 * boxw, h, 0, invert); |
|||
break; |
|||
case INDICATOR_BOX_WIDER: |
|||
drw_rect(drw, x + boxw/2, y, w - boxw, h, 0, invert); |
|||
break; |
|||
case INDICATOR_BOX_FULL: |
|||
drw_rect(drw, x, y, w - 2, h, 0, invert); |
|||
break; |
|||
case INDICATOR_CLIENT_DOTS: |
|||
for (c = m->clients; c; c = c->next) { |
|||
if (c->tags & (1 << tag)) { |
|||
drw_rect(drw, x, 1 + (indn * 2), m->sel == c ? 6 : 1, 1, 1, invert); |
|||
indn++; |
|||
} |
|||
if (h <= 1 + (indn * 2)) { |
|||
indn = 0; |
|||
x += 2; |
|||
} |
|||
} |
|||
break; |
|||
case INDICATOR_RIGHT_TAGS: |
|||
if (!c) |
|||
break; |
|||
for (i = 0; i < NUMTAGS; i++) { |
|||
drw_rect(drw, |
|||
( x + w - 2 - ((NUMTAGS / TAGSROWS) * TAGSPX) |
|||
- (i % (NUMTAGS/TAGSROWS)) + ((i % (NUMTAGS / TAGSROWS)) * TAGSPX) |
|||
), |
|||
( y + 2 + ((i / (NUMTAGS/TAGSROWS)) * TAGSPX) |
|||
- ((i / (NUMTAGS/TAGSROWS))) |
|||
), |
|||
TAGSPX, TAGSPX, (c->tags >> i) & 1, 0 |
|||
); |
|||
} |
|||
break; |
|||
case INDICATOR_PLUS_AND_LARGER_SQUARE: |
|||
boxs += 2; |
|||
boxw += 2; |
|||
/* falls through */ |
|||
case INDICATOR_PLUS_AND_SQUARE: |
|||
drw_rect(drw, x + boxs, y + boxs, boxw % 2 ? boxw : boxw + 1, boxw % 2 ? boxw : boxw + 1, filled, invert); |
|||
/* falls through */ |
|||
case INDICATOR_PLUS: |
|||
if (!(boxw % 2)) |
|||
boxw += 1; |
|||
drw_rect(drw, x + boxs + boxw / 2, y + boxs, 1, boxw, filled, invert); // |
|
|||
drw_rect(drw, x + boxs, y + boxs + boxw / 2, boxw + 1, 1, filled, invert); // ‒
|
|||
break; |
|||
} |
|||
} |
|||
|
|||
void |
|||
drawstateindicator(Monitor *m, Client *c, unsigned int occ, int x, int y, int w, int h, unsigned int tag, int filled, int invert) |
|||
{ |
|||
if (c->fakefullscreen && c->isfloating) |
|||
drawindicator(m, c, occ, x, y, w, h, tag, filled, invert, floatfakefsindicatortype); |
|||
else if (c->fakefullscreen) |
|||
drawindicator(m, c, occ, x, y, w, h, tag, filled, invert, fakefsindicatortype); |
|||
else |
|||
if (c->isfloating) |
|||
drawindicator(m, c, occ, x, y, w, h, tag, filled, invert, floatindicatortype); |
|||
else |
|||
drawindicator(m, c, occ, x, y, w, h, tag, filled, invert, tiledindicatortype); |
|||
} |
|||
|
@ -0,0 +1,21 @@ |
|||
enum { |
|||
INDICATOR_NONE, |
|||
INDICATOR_TOP_LEFT_SQUARE, |
|||
INDICATOR_TOP_LEFT_LARGER_SQUARE, |
|||
INDICATOR_TOP_BAR, |
|||
INDICATOR_TOP_BAR_SLIM, |
|||
INDICATOR_BOTTOM_BAR, |
|||
INDICATOR_BOTTOM_BAR_SLIM, |
|||
INDICATOR_BOX, |
|||
INDICATOR_BOX_WIDER, |
|||
INDICATOR_BOX_FULL, |
|||
INDICATOR_CLIENT_DOTS, |
|||
INDICATOR_RIGHT_TAGS, |
|||
INDICATOR_PLUS, |
|||
INDICATOR_PLUS_AND_SQUARE, |
|||
INDICATOR_PLUS_AND_LARGER_SQUARE, |
|||
}; |
|||
|
|||
static void drawindicator(Monitor *m, Client *c, unsigned int occ, int x, int y, int w, int h, unsigned int tag, int filled, int invert, int type); |
|||
static void drawstateindicator(Monitor *m, Client *c, unsigned int occ, int x, int y, int w, int h, unsigned int tag, int filled, int invert); |
|||
|
@ -0,0 +1,18 @@ |
|||
int |
|||
width_ltsymbol(Bar *bar, BarArg *a) |
|||
{ |
|||
return TEXTW(bar->mon->ltsymbol); |
|||
} |
|||
|
|||
int |
|||
draw_ltsymbol(Bar *bar, BarArg *a) |
|||
{ |
|||
return drw_text(drw, a->x, a->y, a->w, a->h, lrpad / 2, bar->mon->ltsymbol, 0, False); |
|||
} |
|||
|
|||
int |
|||
click_ltsymbol(Bar *bar, Arg *arg, BarArg *a) |
|||
{ |
|||
return ClkLtSymbol; |
|||
} |
|||
|
@ -0,0 +1,4 @@ |
|||
static int width_ltsymbol(Bar *bar, BarArg *a); |
|||
static int draw_ltsymbol(Bar *bar, BarArg *a); |
|||
static int click_ltsymbol(Bar *bar, Arg *arg, BarArg *a); |
|||
|
@ -0,0 +1,85 @@ |
|||
int |
|||
width_pwrl_tags(Bar *bar, BarArg *a) |
|||
{ |
|||
int w, i; |
|||
int plw = drw->fonts->h / 2 + 1; |
|||
Client *c; |
|||
unsigned int occ = 0; |
|||
for (c = bar->mon->clients; c; c = c->next) |
|||
occ |= c->tags == 255 ? 0 : c->tags; |
|||
|
|||
for (w = 0, i = 0; i < NUMTAGS; i++) { |
|||
if (!(occ & 1 << i || bar->mon->tagset[bar->mon->seltags] & 1 << i)) |
|||
continue; |
|||
w += TEXTW(tagicon(bar->mon, i)) + plw; |
|||
} |
|||
return w + lrpad; |
|||
} |
|||
|
|||
int |
|||
draw_pwrl_tags(Bar *bar, BarArg *a) |
|||
{ |
|||
int x, w; |
|||
int invert; |
|||
int plw = drw->fonts->h / 2 + 1; |
|||
unsigned int i, occ = 0, urg = 0; |
|||
char *icon; |
|||
Client *c; |
|||
Clr *prevscheme, *nxtscheme; |
|||
|
|||
for (c = bar->mon->clients; c; c = c->next) { |
|||
occ |= c->tags == 255 ? 0 : c->tags; |
|||
if (c->isurgent) |
|||
urg |= c->tags; |
|||
} |
|||
x = a->x; |
|||
prevscheme = scheme[SchemeNorm]; |
|||
for (i = 0; i < NUMTAGS; i++) { |
|||
/* do not draw vacant tags */ |
|||
if (!(occ & 1 << i || bar->mon->tagset[bar->mon->seltags] & 1 << i)) |
|||
continue; |
|||
|
|||
icon = tagicon(bar->mon, i); |
|||
invert = 0; |
|||
w = TEXTW(icon); |
|||
if (urg & 1 << i) { |
|||
drw_settrans(drw, prevscheme, (nxtscheme = scheme[bar->mon->tagset[bar->mon->seltags] & 1 << i ? SchemeSel : SchemeUrg])); |
|||
} else { |
|||
drw_settrans(drw, prevscheme, (nxtscheme = scheme[bar->mon->tagset[bar->mon->seltags] & 1 << i ? SchemeSel : SchemeNorm])); |
|||
} |
|||
drw_arrow(drw, x, a->y, plw, a->h, 1, 1); |
|||
x += plw; |
|||
drw_setscheme(drw, nxtscheme); |
|||
drw_text(drw, x, a->y, w, a->h, lrpad / 2, icon, invert, False); |
|||
drawindicator(bar->mon, NULL, occ, x, a->y, w, a->h, i, -1, invert, tagindicatortype); |
|||
x += w; |
|||
prevscheme = nxtscheme; |
|||
} |
|||
nxtscheme = scheme[SchemeNorm]; |
|||
|
|||
drw_settrans(drw, prevscheme, nxtscheme); |
|||
drw_arrow(drw, x, a->y, plw, a->h, 1, 1); |
|||
return 1; |
|||
} |
|||
|
|||
int |
|||
click_pwrl_tags(Bar *bar, Arg *arg, BarArg *a) |
|||
{ |
|||
int i = 0, x = lrpad / 2; |
|||
int plw = drw->fonts->h / 2 + 1; |
|||
Client *c; |
|||
unsigned int occ = 0; |
|||
for (c = bar->mon->clients; c; c = c->next) |
|||
occ |= c->tags == 255 ? 0 : c->tags; |
|||
|
|||
do { |
|||
if (!(occ & 1 << i || bar->mon->tagset[bar->mon->seltags] & 1 << i)) |
|||
continue; |
|||
x += TEXTW(tagicon(bar->mon, i)) + plw; |
|||
} while (a->x >= x && ++i < NUMTAGS); |
|||
if (i < NUMTAGS) { |
|||
arg->ui = 1 << i; |
|||
} |
|||
return ClkTagBar; |
|||
} |
|||
|
@ -0,0 +1,4 @@ |
|||
static int width_pwrl_tags(Bar *bar, BarArg *a); |
|||
static int draw_pwrl_tags(Bar *bar, BarArg *a); |
|||
static int click_pwrl_tags(Bar *bar, Arg *arg, BarArg *a); |
|||
|
@ -0,0 +1,20 @@ |
|||
int |
|||
width_status(Bar *bar, BarArg *a) |
|||
{ |
|||
return TEXTWM(stext); |
|||
} |
|||
|
|||
|
|||
int |
|||
draw_status(Bar *bar, BarArg *a) |
|||
{ |
|||
return drw_text(drw, a->x, a->y, a->w, a->h, lrpad / 2, stext, 0, True); |
|||
} |
|||
|
|||
|
|||
int |
|||
click_status(Bar *bar, Arg *arg, BarArg *a) |
|||
{ |
|||
return ClkStatusText; |
|||
} |
|||
|
@ -0,0 +1,4 @@ |
|||
static int width_status(Bar *bar, BarArg *a); |
|||
static int draw_status(Bar *bar, BarArg *a); |
|||
static int click_status(Bar *bar, Arg *arg, BarArg *a); |
|||
|
@ -0,0 +1,46 @@ |
|||
|
|||
int |
|||
click_statuscmd(Bar *bar, Arg *arg, BarArg *a) |
|||
{ |
|||
return click_statuscmd_text(arg, a->x, rawstext); |
|||
} |
|||
|
|||
|
|||
int |
|||
click_statuscmd_text(Arg *arg, int rel_x, char *text) |
|||
{ |
|||
int i = -1; |
|||
int x = 0; |
|||
char ch; |
|||
statussig = -1; |
|||
while (text[++i]) { |
|||
if ((unsigned char)text[i] < ' ') { |
|||
ch = text[i]; |
|||
text[i] = '\0'; |
|||
x += TEXTWM(text) - lrpad; |
|||
text[i] = ch; |
|||
text += i+1; |
|||
i = -1; |
|||
if (x >= rel_x && statussig != -1) |
|||
break; |
|||
statussig = ch; |
|||
} |
|||
} |
|||
if (statussig == -1) |
|||
statussig = 0; |
|||
return ClkStatusText; |
|||
} |
|||
|
|||
void |
|||
copyvalidchars(char *text, char *rawtext) |
|||
{ |
|||
int i = -1, j = 0; |
|||
|
|||
while (rawtext[++i]) { |
|||
if ((unsigned char)rawtext[i] >= ' ') { |
|||
text[j++] = rawtext[i]; |
|||
} |
|||
} |
|||
text[j] = '\0'; |
|||
} |
|||
|
@ -0,0 +1,9 @@ |
|||
static int click_statuscmd(Bar *bar, Arg *arg, BarArg *a); |
|||
static int click_statuscmd_text(Arg *arg, int rel_x, char *text); |
|||
static void copyvalidchars(char *text, char *rawtext); |
|||
|
|||
typedef struct { |
|||
const char *cmd; |
|||
int id; |
|||
} StatusCmd; |
|||
|
@ -0,0 +1,186 @@ |
|||
static Systray *systray = NULL; |
|||
static unsigned long systrayorientation = _NET_SYSTEM_TRAY_ORIENTATION_HORZ; |
|||
|
|||
int |
|||
width_systray(Bar *bar, BarArg *a) |
|||
{ |
|||
unsigned int w = 0; |
|||
Client *i; |
|||
if (!systray) |
|||
return 1; |
|||
if (showsystray) |
|||
for (i = systray->icons; i; w += i->w + systrayspacing, i = i->next); |
|||
return w ? w + lrpad - systrayspacing : 0; |
|||
} |
|||
|
|||
int |
|||
draw_systray(Bar *bar, BarArg *a) |
|||
{ |
|||
if (!showsystray) |
|||
return 0; |
|||
|
|||
XSetWindowAttributes wa; |
|||
XWindowChanges wc; |
|||
Client *i; |
|||
unsigned int w; |
|||
|
|||
if (!systray) { |
|||
/* init systray */ |
|||
if (!(systray = (Systray *)calloc(1, sizeof(Systray)))) |
|||
die("fatal: could not malloc() %u bytes\n", sizeof(Systray)); |
|||
|
|||
wa.override_redirect = True; |
|||
wa.event_mask = ButtonPressMask|ExposureMask; |
|||
wa.border_pixel = 0; |
|||
systray->h = MIN(a->h, drw->fonts->h); |
|||
wa.background_pixel = 0; |
|||
wa.colormap = cmap; |
|||
systray->win = XCreateWindow(dpy, root, bar->bx + a->x + lrpad / 2, bar->by + a->y + (a->h - systray->h) / 2, MAX(a->w + 40, 1), systray->h, 0, depth, |
|||
InputOutput, visual, |
|||
CWOverrideRedirect|CWBorderPixel|CWBackPixel|CWColormap|CWEventMask, &wa); // CWBackPixmap
|
|||
|
|||
XSelectInput(dpy, systray->win, SubstructureNotifyMask); |
|||
XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32, |
|||
PropModeReplace, (unsigned char *)&systrayorientation, 1); |
|||
XChangeProperty(dpy, systray->win, netatom[NetSystemTrayVisual], XA_VISUALID, 32, |
|||
PropModeReplace, (unsigned char *)&visual->visualid, 1); |
|||
XChangeProperty(dpy, systray->win, netatom[NetWMWindowType], XA_ATOM, 32, |
|||
PropModeReplace, (unsigned char *)&netatom[NetWMWindowTypeDock], 1); |
|||
XMapRaised(dpy, systray->win); |
|||
XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime); |
|||
if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) { |
|||
sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0); |
|||
XSync(dpy, False); |
|||
} else { |
|||
fprintf(stderr, "dwm: unable to obtain system tray.\n"); |
|||
free(systray); |
|||
systray = NULL; |
|||
return 0; |
|||
} |
|||
} |
|||
|
|||
systray->bar = bar; |
|||
|
|||
wc.stack_mode = Above; |
|||
wc.sibling = bar->win; |
|||
XConfigureWindow(dpy, systray->win, CWSibling|CWStackMode, &wc); |
|||
|
|||
drw_setscheme(drw, scheme[SchemeNorm]); |
|||
for (w = 0, i = systray->icons; i; i = i->next) { |
|||
wa.background_pixel = 0; |
|||
XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa); |
|||
XMapRaised(dpy, i->win); |
|||
i->x = w; |
|||
XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h); |
|||
w += i->w; |
|||
if (i->next) |
|||
w += systrayspacing; |
|||
if (i->mon != bar->mon) |
|||
i->mon = bar->mon; |
|||
} |
|||
|
|||
XMoveResizeWindow(dpy, systray->win, bar->bx + a->x + lrpad / 2, (w ? bar->by + a->y + (a->h - systray->h) / 2: -bar->by - a->y), MAX(w, 1), systray->h); |
|||
return w; |
|||
} |
|||
|
|||
int |
|||
click_systray(Bar *bar, Arg *arg, BarArg *a) |
|||
{ |
|||
return -1; |
|||
} |
|||
|
|||
void |
|||
removesystrayicon(Client *i) |
|||
{ |
|||
Client **ii; |
|||
|
|||
if (!showsystray || !i) |
|||
return; |
|||
for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next); |
|||
if (ii) |
|||
*ii = i->next; |
|||
free(i); |
|||
drawbarwin(systray->bar); |
|||
} |
|||
|
|||
void |
|||
resizerequest(XEvent *e) |
|||
{ |
|||
XResizeRequestEvent *ev = &e->xresizerequest; |
|||
Client *i; |
|||
|
|||
if ((i = wintosystrayicon(ev->window))) { |
|||
updatesystrayicongeom(i, ev->width, ev->height); |
|||
drawbarwin(systray->bar); |
|||
} |
|||
} |
|||
|
|||
void |
|||
updatesystrayicongeom(Client *i, int w, int h) |
|||
{ |
|||
if (!systray) |
|||
return; |
|||
|
|||
int icon_height = systray->h; |
|||
if (i) { |
|||
i->h = icon_height; |
|||
if (w == h) |
|||
i->w = icon_height; |
|||
else if (h == icon_height) |
|||
i->w = w; |
|||
else |
|||
i->w = (int) ((float)icon_height * ((float)w / (float)h)); |
|||
applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False); |
|||
/* force icons into the systray dimensions if they don't want to */ |
|||
if (i->h > icon_height) { |
|||
if (i->w == i->h) |
|||
i->w = icon_height; |
|||
else |
|||
i->w = (int) ((float)icon_height * ((float)i->w / (float)i->h)); |
|||
i->h = icon_height; |
|||
} |
|||
if (i->w > 2 * icon_height) |
|||
i->w = icon_height; |
|||
} |
|||
} |
|||
|
|||
void |
|||
updatesystrayiconstate(Client *i, XPropertyEvent *ev) |
|||
{ |
|||
long flags; |
|||
int code = 0; |
|||
|
|||
if (!showsystray || !systray || !i || ev->atom != xatom[XembedInfo] || |
|||
!(flags = getatomprop(i, xatom[XembedInfo]))) |
|||
return; |
|||
|
|||
if (flags & XEMBED_MAPPED && !i->tags) { |
|||
i->tags = 1; |
|||
code = XEMBED_WINDOW_ACTIVATE; |
|||
XMapRaised(dpy, i->win); |
|||
setclientstate(i, NormalState); |
|||
} |
|||
else if (!(flags & XEMBED_MAPPED) && i->tags) { |
|||
i->tags = 0; |
|||
code = XEMBED_WINDOW_DEACTIVATE; |
|||
XUnmapWindow(dpy, i->win); |
|||
setclientstate(i, WithdrawnState); |
|||
} |
|||
else |
|||
return; |
|||
sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0, |
|||
systray->win, XEMBED_EMBEDDED_VERSION); |
|||
} |
|||
|
|||
Client * |
|||
wintosystrayicon(Window w) |
|||
{ |
|||
if (!systray) |
|||
return NULL; |
|||
Client *i = NULL; |
|||
if (!showsystray || !w) |
|||
return i; |
|||
for (i = systray->icons; i && i->win != w; i = i->next); |
|||
return i; |
|||
} |
|||
|
@ -0,0 +1,42 @@ |
|||
#define SYSTEM_TRAY_REQUEST_DOCK 0 |
|||
#define _NET_SYSTEM_TRAY_ORIENTATION_HORZ 0 |
|||
|
|||
/* XEMBED messages */ |
|||
#define XEMBED_EMBEDDED_NOTIFY 0 |
|||
#define XEMBED_WINDOW_ACTIVATE 1 |
|||
#define XEMBED_FOCUS_IN 4 |
|||
#define XEMBED_MODALITY_ON 10 |
|||
|
|||
#define XEMBED_MAPPED (1 << 0) |
|||
#define XEMBED_WINDOW_ACTIVATE 1 |
|||
#define XEMBED_WINDOW_DEACTIVATE 2 |
|||
|
|||
#define VERSION_MAJOR 0 |
|||
#define VERSION_MINOR 0 |
|||
#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR |
|||
|
|||
/* enums */ |
|||
enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */ |
|||
|
|||
typedef struct Systray Systray; |
|||
struct Systray { |
|||
Window win; |
|||
Client *icons; |
|||
Bar *bar; |
|||
int h; |
|||
}; |
|||
|
|||
/* bar integration */ |
|||
static int width_systray(Bar *bar, BarArg *a); |
|||
static int draw_systray(Bar *bar, BarArg *a); |
|||
static int click_systray(Bar *bar, Arg *arg, BarArg *a); |
|||
|
|||
/* function declarations */ |
|||
static Atom getatomprop(Client *c, Atom prop); |
|||
static void removesystrayicon(Client *i); |
|||
static void resizerequest(XEvent *e); |
|||
static void updatesystrayicongeom(Client *i, int w, int h); |
|||
static void updatesystrayiconstate(Client *i, XPropertyEvent *ev); |
|||
static Client *wintosystrayicon(Window w); |
|||
|
|||
|
@ -0,0 +1,223 @@ |
|||
/* Bartabgroups properties, you can override these in your config.h if you want. */ |
|||
#ifndef BARTAB_BORDERS |
|||
#define BARTAB_BORDERS 1 // 0 = off, 1 = on
|
|||
#endif |
|||
#ifndef BARTAB_SHOWFLOATING |
|||
#define BARTAB_SHOWFLOATING 0 // whether to show titles for floating windows, hidden clients are always shown
|
|||
#endif |
|||
#ifndef BARTAB_STACKWEIGHT |
|||
#define BARTAB_STACKWEIGHT 1 // stack weight compared to hidden and floating window titles
|
|||
#endif |
|||
#ifndef BARTAB_HIDDENWEIGHT |
|||
#define BARTAB_HIDDENWEIGHT 1 // hidden window title weight
|
|||
#endif |
|||
#ifndef BARTAB_FLOATWEIGHT |
|||
#define BARTAB_FLOATWEIGHT 1 // floating window title weight, set to 0 to not show floating windows
|
|||
#endif |
|||
|
|||
int |
|||
width_bartabgroups(Bar *bar, BarArg *a) |
|||
{ |
|||
return a->w; |
|||
} |
|||
|
|||
int |
|||
draw_bartabgroups(Bar *bar, BarArg *a) |
|||
{ |
|||
drw_rect(drw, a->x, a->y, a->w, a->h, 1, 1); |
|||
return bartabcalculate(bar->mon, a->x, a->w, -1, bartabdraw, NULL, a); |
|||
} |
|||
|
|||
int |
|||
click_bartabgroups(Bar *bar, Arg *arg, BarArg *a) |
|||
{ |
|||
bartabcalculate(bar->mon, 0, a->w, a->x, bartabclick, arg, a); |
|||
return ClkWinTitle; |
|||
} |
|||
|
|||
void |
|||
bartabdraw(Monitor *m, Client *c, int unused, int x, int w, int groupactive, Arg *arg, BarArg *barg) |
|||
{ |
|||
if (!c) |
|||
return; |
|||
int i, nclienttags = 0, nviewtags = 0, pad = lrpad / 2; |
|||
drw_setscheme(drw, scheme[ |
|||
m->sel == c |
|||
#ifdef HIDDEN |
|||
&& HIDDEN(c) |
|||
? SchemeHidSel |
|||
: HIDDEN(c) |
|||
? SchemeHidNorm |
|||
: m->sel == c |
|||
#endif |
|||
? SchemeSel |
|||
: groupactive |
|||
? SchemeTitleSel |
|||
: SchemeTitleNorm |
|||
]); |
|||
if (w <= TEXTW("A") - lrpad + pad) // reduce text padding if wintitle is too small
|
|||
pad = (w - TEXTW("A") + lrpad < 0 ? 0 : (w - TEXTW("A") + lrpad) / 2); |
|||
else if (TEXTW(c->name) < w) |
|||
pad = (w - TEXTW(c->name) + lrpad) / 2; |
|||
|
|||
drw_text(drw, x, barg->y, w, barg->h, pad, c->name, 0, False); |
|||
|
|||
drawstateindicator(m, c, 1, x, barg->y, w, barg->h, 0, 0, c->isfixed); |
|||
|
|||
if (BARTAB_BORDERS) { |
|||
XSetForeground(drw->dpy, drw->gc, scheme[SchemeSel][ColBorder].pixel); |
|||
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, barg->y, 1, barg->h); |
|||
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x + w - (x + w >= barg->w ? 1 : 0), barg->y, 1, barg->h); |
|||
} |
|||
/* Optional tags icons */ |
|||
for (i = 0; i < NUMTAGS; i++) { |
|||
if ((m->tagset[m->seltags] >> i) & 1) |
|||
nviewtags++; |
|||
if ((c->tags >> i) & 1) |
|||
nclienttags++; |
|||
} |
|||
|
|||
if (TAGSINDICATOR == 2 || nclienttags > 1 || nviewtags > 1) |
|||
drawindicator(m, c, 1, x, barg->y, w, barg->h, 0, 0, 0, INDICATOR_RIGHT_TAGS); |
|||
} |
|||
|
|||
#ifndef HIDDEN |
|||
#define HIDDEN(C) 0 |
|||
#endif |
|||
|
|||
void |
|||
bartabclick(Monitor *m, Client *c, int passx, int x, int w, int unused, Arg *arg, BarArg *barg) |
|||
{ |
|||
if (passx >= x && passx <= x + w) |
|||
arg->v = c; |
|||
} |
|||
|
|||
int |
|||
bartabcalculate( |
|||
Monitor *m, int offx, int tabw, int passx, |
|||
void(*tabfn)(Monitor *, Client *, int, int, int, int, Arg *arg, BarArg *barg), |
|||
Arg *arg, BarArg *barg |
|||
) { |
|||
Client *c; |
|||
int |
|||
i, clientsnmaster = 0, clientsnstack = 0, clientsnfloating = 0, clientsnhidden = 0, |
|||
masteractive = 0, fulllayout = 0, |
|||
x = offx, w, r, num = 0, den, tgactive; |
|||
|
|||
for (i = 0; i < LENGTH(bartabmonfns); i++) |
|||
if (m ->lt[m->sellt]->arrange == bartabmonfns[i]) { |
|||
fulllayout = 1; |
|||
break; |
|||
} |
|||
|
|||
for (i = 0, c = m->clients; c; c = c->next) { |
|||
if (!ISVISIBLE(c)) |
|||
continue; |
|||
if (HIDDEN(c)) { |
|||
clientsnhidden++; |
|||
continue; |
|||
} |
|||
if (c->isfloating) { |
|||
clientsnfloating++; |
|||
continue; |
|||
} |
|||
if (m->sel == c) |
|||
masteractive = i < m->nmaster; |
|||
if (i < m->nmaster) |
|||
clientsnmaster++; |
|||
else |
|||
clientsnstack++; |
|||
i++; |
|||
} |
|||
|
|||
if (clientsnmaster + clientsnstack + clientsnfloating + clientsnhidden == 0) |
|||
return 0; |
|||
|
|||
tgactive = 1; |
|||
num = tabw; |
|||
/* floating mode */ |
|||
if ((fulllayout && BARTAB_FLOATWEIGHT) || clientsnmaster + clientsnstack == 0 || !m->lt[m->sellt]->arrange) { |
|||
den = clientsnmaster + clientsnstack + clientsnfloating + clientsnhidden; |
|||
r = num % den; |
|||
w = num / den; |
|||
for (c = m->clients, i = 0; c; c = c->next) { |
|||
if (!ISVISIBLE(c)) |
|||
continue; |
|||
tabfn(m, c, passx, x, w + (i < r ? 1 : 0), tgactive, arg, barg); |
|||
x += w + (i < r ? 1 : 0); |
|||
i++; |
|||
} |
|||
/* no master and stack mode, e.g. monocole, grid layouts, fibonacci */ |
|||
} else if (fulllayout) { |
|||
den = clientsnmaster + clientsnstack + clientsnhidden; |
|||
r = num % den; |
|||
w = num / den; |
|||
for (c = m->clients, i = 0; c; c = c->next) { |
|||
if (!ISVISIBLE(c) || (c->isfloating && !HIDDEN(c))) |
|||
continue; |
|||
tabfn(m, c, passx, x, w + (i < r ? 1 : 0), tgactive, arg, barg); |
|||
x += w + (i < r ? 1 : 0); |
|||
i++; |
|||
} |
|||
/* tiled mode */ |
|||
} else { |
|||
den = clientsnmaster; |
|||
c = m->clients; |
|||
i = 0; |
|||
if (den) { |
|||
if (clientsnstack + clientsnfloating * BARTAB_FLOATWEIGHT + clientsnhidden) { |
|||
tgactive = masteractive; |
|||
num = tabw * m->mfact; |
|||
} |
|||
r = num % den; |
|||
w = num / den; |
|||
for (; c && i < m->nmaster; c = c->next) { // tiled master
|
|||
if (!ISVISIBLE(c) || c->isfloating || HIDDEN(c)) |
|||
continue; |
|||
tabfn(m, c, passx, x, w + (i < r ? 1 : 0), tgactive, arg, barg); |
|||
x += w + (i < r ? 1 : 0); |
|||
i++; |
|||
} |
|||
tgactive = !tgactive; |
|||
num = tabw - num; |
|||
} |
|||
|
|||
den = clientsnstack * BARTAB_STACKWEIGHT + clientsnfloating * BARTAB_FLOATWEIGHT + clientsnhidden * BARTAB_HIDDENWEIGHT; |
|||
if (!den) |
|||
return 1; |
|||
|
|||
r = num % den; |
|||
w = num / den; |
|||
#if BARTAB_STACKWEIGHT |
|||
for (; c; c = c->next) { // tiled stack
|
|||
if (!ISVISIBLE(c) || HIDDEN(c) || c->isfloating) |
|||
continue; |
|||
tabfn(m, c, passx, x, w * BARTAB_STACKWEIGHT + (i - m->nmaster < r ? 1 : 0), tgactive, arg, barg); |
|||
x += w * BARTAB_STACKWEIGHT + (i - m->nmaster < r ? 1 : 0); |
|||
i++; |
|||
} |
|||
#endif // BARTAB_STACKWEIGHT
|
|||
|
|||
#if BARTAB_HIDDENWEIGHT |
|||
for (c = m->clients; c; c = c->next) { // hidden windows
|
|||
if (!ISVISIBLE(c) || !HIDDEN(c)) |
|||
continue; |
|||
tabfn(m, c, passx, x, w * BARTAB_HIDDENWEIGHT + (i - m->nmaster < r ? 1 : 0), tgactive, arg, barg); |
|||
x += w * BARTAB_HIDDENWEIGHT + (i - m->nmaster < r ? 1 : 0); |
|||
i++; |
|||
} |
|||
#endif // BARTAB_HIDDENWEIGHT
|
|||
|
|||
#if BARTAB_FLOATWEIGHT |
|||
for (c = m->clients; c; c = c->next) { // floating windows
|
|||
if (!ISVISIBLE(c) || HIDDEN(c) || !c->isfloating) |
|||
continue; |
|||
tabfn(m, c, passx, x, w * BARTAB_FLOATWEIGHT + (i - m->nmaster < r ? 1 : 0), tgactive, arg, barg); |
|||
x += w * BARTAB_FLOATWEIGHT + (i - m->nmaster < r ? 1 : 0); |
|||
i++; |
|||
} |
|||
#endif // BARTAB_FLOATWEIGHT
|
|||
} |
|||
return 1; |
|||
} |
|||
|
@ -0,0 +1,8 @@ |
|||
static int width_bartabgroups(Bar *bar, BarArg *a); |
|||
static int draw_bartabgroups(Bar *bar, BarArg *a); |
|||
static int click_bartabgroups(Bar *bar, Arg *arg, BarArg *a); |
|||
|
|||
static void bartabdraw(Monitor *m, Client *c, int unused, int x, int w, int groupactive, Arg *arg, BarArg *barg); |
|||
static void bartabclick(Monitor *m, Client *c, int passx, int x, int w, int unused, Arg *arg, BarArg *barg); |
|||
static int bartabcalculate(Monitor *m, int offx, int w, int passx, void(*tabfn)(Monitor *, Client *, int, int, int, int, Arg *arg, BarArg *barg), Arg *arg, BarArg *barg); |
|||
|
@ -0,0 +1,9 @@ |
|||
char * |
|||
tagicon(Monitor *m, int tag) |
|||
{ |
|||
int tagindex = tag + NUMTAGS * m->index; |
|||
if (tagindex >= LENGTH(tagicons[DEFAULT_TAGS])) |
|||
tagindex = tagindex % LENGTH(tagicons[DEFAULT_TAGS]); |
|||
return tagicons[DEFAULT_TAGS][tagindex]; |
|||
} |
|||
|
@ -0,0 +1,8 @@ |
|||
enum { |
|||
DEFAULT_TAGS, |
|||
ALTERNATIVE_TAGS, |
|||
ALT_TAGS_DECORATION, |
|||
}; |
|||
|
|||
static char * tagicon(Monitor *m, int tag); |
|||
|
@ -0,0 +1,75 @@ |
|||
int |
|||
width_tags(Bar *bar, BarArg *a) |
|||
{ |
|||
int w, i; |
|||
Client *c; |
|||
unsigned int occ = 0; |
|||
for (c = bar->mon->clients; c; c = c->next) |
|||
occ |= c->tags == 255 ? 0 : c->tags; |
|||
|
|||
for (w = 0, i = 0; i < NUMTAGS; i++) { |
|||
if (!(occ & 1 << i || bar->mon->tagset[bar->mon->seltags] & 1 << i)) |
|||
continue; |
|||
w += TEXTW(tagicon(bar->mon, i)); |
|||
} |
|||
return w; |
|||
} |
|||
|
|||
int |
|||
draw_tags(Bar *bar, BarArg *a) |
|||
{ |
|||
int invert; |
|||
int w, x = a->x; |
|||
unsigned int i, occ = 0, urg = 0; |
|||
char *icon; |
|||
Client *c; |
|||
Monitor *m = bar->mon; |
|||
|
|||
for (c = m->clients; c; c = c->next) { |
|||
occ |= c->tags == 255 ? 0 : c->tags; |
|||
if (c->isurgent) |
|||
urg |= c->tags; |
|||
} |
|||
for (i = 0; i < NUMTAGS; i++) { |
|||
/* do not draw vacant tags */ |
|||
if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i)) |
|||
continue; |
|||
|
|||
icon = tagicon(bar->mon, i); |
|||
invert = 0; |
|||
w = TEXTW(icon); |
|||
drw_setscheme(drw, scheme[ |
|||
m->tagset[m->seltags] & 1 << i |
|||
? SchemeTagsSel |
|||
: urg & 1 << i |
|||
? SchemeUrg |
|||
: SchemeTagsNorm |
|||
]); |
|||
drw_text(drw, x, a->y, w, a->h, lrpad / 2, icon, invert, False); |
|||
drawindicator(m, NULL, occ, x, a->y, w, a->h, i, -1, invert, tagindicatortype); |
|||
x += w; |
|||
} |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
int |
|||
click_tags(Bar *bar, Arg *arg, BarArg *a) |
|||
{ |
|||
int i = 0, x = lrpad / 2; |
|||
Client *c; |
|||
unsigned int occ = 0; |
|||
for (c = bar->mon->clients; c; c = c->next) |
|||
occ |= c->tags == 255 ? 0 : c->tags; |
|||
|
|||
do { |
|||
if (!(occ & 1 << i || bar->mon->tagset[bar->mon->seltags] & 1 << i)) |
|||
continue; |
|||
x += TEXTW(tagicon(bar->mon, i)); |
|||
} while (a->x >= x && ++i < NUMTAGS); |
|||
if (i < NUMTAGS) { |
|||
arg->ui = 1 << i; |
|||
} |
|||
return ClkTagBar; |
|||
} |
|||
|
@ -0,0 +1,4 @@ |
|||
static int width_tags(Bar *bar, BarArg *a); |
|||
static int draw_tags(Bar *bar, BarArg *a); |
|||
static int click_tags(Bar *bar, Arg *arg, BarArg *a); |
|||
|
@ -0,0 +1,39 @@ |
|||
int |
|||
width_wintitle(Bar *bar, BarArg *a) |
|||
{ |
|||
return a->w; |
|||
} |
|||
|
|||
int |
|||
draw_wintitle(Bar *bar, BarArg *a) |
|||
{ |
|||
int x = a->x + lrpad / 2, w = a->w - lrpad / 2; |
|||
Monitor *m = bar->mon; |
|||
Client *c = m->sel; |
|||
int pad = lrpad / 2; |
|||
|
|||
if (!c) { |
|||
drw_setscheme(drw, scheme[SchemeTitleNorm]); |
|||
drw_rect(drw, x, a->y, w, a->h, 1, 1); |
|||
return 0; |
|||
} |
|||
|
|||
drw_setscheme(drw, scheme[m == selmon ? SchemeTitleSel : SchemeTitleNorm]); |
|||
XSetErrorHandler(xerrordummy); |
|||
if (TEXTW(c->name) < w) |
|||
pad = (w - TEXTW(c->name) + lrpad) / 2; |
|||
|
|||
drw_text(drw, x, a->y, w, a->h, pad, c->name, 0, False); |
|||
|
|||
XSync(dpy, False); |
|||
XSetErrorHandler(xerror); |
|||
drawstateindicator(m, c, 1, x, a->y, w, a->h, 0, 0, c->isfixed); |
|||
return 1; |
|||
} |
|||
|
|||
int |
|||
click_wintitle(Bar *bar, Arg *arg, BarArg *a) |
|||
{ |
|||
return ClkWinTitle; |
|||
} |
|||
|
@ -0,0 +1,4 @@ |
|||
static int width_wintitle(Bar *bar, BarArg *a); |
|||
static int draw_wintitle(Bar *bar, BarArg *a); |
|||
static int click_wintitle(Bar *bar, Arg *arg, BarArg *a); |
|||
|
@ -0,0 +1,91 @@ |
|||
void |
|||
hide(Client *c) { |
|||
|
|||
Client *n; |
|||
if (!c || HIDDEN(c)) |
|||
return; |
|||
|
|||
Window w = c->win; |
|||
static XWindowAttributes ra, ca; |
|||
|
|||
// more or less taken directly from blackbox's hide() function
|
|||
XGrabServer(dpy); |
|||
XGetWindowAttributes(dpy, root, &ra); |
|||
XGetWindowAttributes(dpy, w, &ca); |
|||
// prevent UnmapNotify events
|
|||
XSelectInput(dpy, root, ra.your_event_mask & ~SubstructureNotifyMask); |
|||
XSelectInput(dpy, w, ca.your_event_mask & ~StructureNotifyMask); |
|||
XUnmapWindow(dpy, w); |
|||
setclientstate(c, IconicState); |
|||
XSelectInput(dpy, root, ra.your_event_mask); |
|||
XSelectInput(dpy, w, ca.your_event_mask); |
|||
XUngrabServer(dpy); |
|||
|
|||
if (c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) { |
|||
for (n = c->snext; n && (!ISVISIBLE(n) || HIDDEN(n)); n = n->snext); |
|||
if (!n) |
|||
for (n = c->mon->stack; n && (!ISVISIBLE(n) || HIDDEN(n)); n = n->snext); |
|||
} else { |
|||
n = nexttiled(c); |
|||
if (!n) |
|||
n = prevtiled(c); |
|||
} |
|||
focus(n); |
|||
arrange(c->mon); |
|||
} |
|||
|
|||
void |
|||
show(Client *c) |
|||
{ |
|||
if (!c || !HIDDEN(c)) |
|||
return; |
|||
|
|||
XMapWindow(dpy, c->win); |
|||
setclientstate(c, NormalState); |
|||
arrange(c->mon); |
|||
} |
|||
|
|||
void |
|||
togglewin(const Arg *arg) |
|||
{ |
|||
Client *c = (Client*)arg->v; |
|||
if (!c) |
|||
return; |
|||
if (c == selmon->sel) |
|||
hide(c); |
|||
else { |
|||
if (HIDDEN(c)) |
|||
show(c); |
|||
focus(c); |
|||
restack(c->mon); |
|||
} |
|||
} |
|||
|
|||
Client * |
|||
prevtiled(Client *c) |
|||
{ |
|||
Client *p, *i; |
|||
for (p = NULL, i = c->mon->clients; c && i != c; i = i->next) |
|||
if (ISVISIBLE(i) && !HIDDEN(i)) |
|||
p = i; |
|||
return p; |
|||
} |
|||
|
|||
void |
|||
showhideclient(const Arg *arg) |
|||
{ |
|||
Client *c = (Client*)arg->v; |
|||
if (!c) |
|||
c = selmon->sel; |
|||
if (!c) |
|||
return; |
|||
|
|||
if (HIDDEN(c)) { |
|||
show(c); |
|||
focus(c); |
|||
restack(c->mon); |
|||
} else { |
|||
hide(c); |
|||
} |
|||
} |
|||
|
@ -0,0 +1,6 @@ |
|||
static void hide(Client *c); |
|||
static void show(Client *c); |
|||
static void togglewin(const Arg *arg); |
|||
static Client * prevtiled(Client *c); |
|||
static void showhideclient(const Arg *arg); |
|||
|
@ -0,0 +1,35 @@ |
|||
static Atom motifatom; |
|||
|
|||
void |
|||
updatemotifhints(Client *c) |
|||
{ |
|||
Atom real; |
|||
int format; |
|||
unsigned char *p = NULL; |
|||
unsigned long n, extra; |
|||
unsigned long *motif; |
|||
int width, height; |
|||
|
|||
if (!decorhints) |
|||
return; |
|||
|
|||
if (XGetWindowProperty(dpy, c->win, motifatom, 0L, 5L, False, motifatom, |
|||
&real, &format, &n, &extra, &p) == Success && p != NULL) { |
|||
motif = (unsigned long*)p; |
|||
if (motif[MWM_HINTS_FLAGS_FIELD] & MWM_HINTS_DECORATIONS) { |
|||
width = WIDTH(c); |
|||
height = HEIGHT(c); |
|||
|
|||
if (motif[MWM_HINTS_DECORATIONS_FIELD] & MWM_DECOR_ALL || |
|||
motif[MWM_HINTS_DECORATIONS_FIELD] & MWM_DECOR_BORDER || |
|||
motif[MWM_HINTS_DECORATIONS_FIELD] & MWM_DECOR_TITLE) |
|||
c->bw = c->oldbw = borderpx; |
|||
else |
|||
c->bw = c->oldbw = 0; |
|||
|
|||
resize(c, c->x, c->y, width - (2*c->bw), height - (2*c->bw), 0); |
|||
} |
|||
XFree(p); |
|||
} |
|||
} |
|||
|
@ -0,0 +1,9 @@ |
|||
#define MWM_HINTS_FLAGS_FIELD 0 |
|||
#define MWM_HINTS_DECORATIONS_FIELD 2 |
|||
#define MWM_HINTS_DECORATIONS (1 << 1) |
|||
#define MWM_DECOR_ALL (1 << 0) |
|||
#define MWM_DECOR_BORDER (1 << 1) |
|||
#define MWM_DECOR_TITLE (1 << 3) |
|||
|
|||
static void updatemotifhints(Client *c); |
|||
|
@ -0,0 +1,19 @@ |
|||
void |
|||
togglefakefullscreen(const Arg *arg) |
|||
{ |
|||
Client *c = selmon->sel; |
|||
if (!c) |
|||
return; |
|||
|
|||
if (c->fakefullscreen != 1 && c->isfullscreen) { // exit fullscreen --> fake fullscreen
|
|||
c->fakefullscreen = 2; |
|||
setfullscreen(c, 0); |
|||
} else if (c->fakefullscreen == 1) { |
|||
setfullscreen(c, 0); |
|||
c->fakefullscreen = 0; |
|||
} else { |
|||
c->fakefullscreen = 1; |
|||
setfullscreen(c, 1); |
|||
} |
|||
} |
|||
|
@ -0,0 +1,2 @@ |
|||
static void togglefakefullscreen(const Arg *arg); |
|||
|
@ -0,0 +1,80 @@ |
|||
void |
|||
tagtoleft(const Arg *arg) |
|||
{ |
|||
if (selmon->sel != NULL |
|||
&& __builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1 |
|||
&& selmon->tagset[selmon->seltags] > 1) { |
|||
selmon->sel->tags >>= 1; |
|||
focus(NULL); |
|||
arrange(selmon); |
|||
} |
|||
} |
|||
|
|||
void |
|||
tagtoright(const Arg *arg) |
|||
{ |
|||
if (selmon->sel != NULL |
|||
&& __builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1 |
|||
&& selmon->tagset[selmon->seltags] & (TAGMASK >> 1)) { |
|||
selmon->sel->tags <<= 1; |
|||
focus(NULL); |
|||
arrange(selmon); |
|||
} |
|||
} |
|||
|
|||
void |
|||
viewtoleft(const Arg *arg) |
|||
{ |
|||
if (__builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1 |
|||
&& selmon->tagset[selmon->seltags] > 1) { |
|||
selmon->seltags ^= 1; /* toggle sel tagset */ |
|||
pertagview(&((Arg) { .ui = selmon->tagset[selmon->seltags ^ 1] >> 1 })); |
|||
focus(NULL); |
|||
arrange(selmon); |
|||
updatecurrentdesktop(); |
|||
} |
|||
} |
|||
|
|||
void |
|||
viewtoright(const Arg *arg) |
|||
{ |
|||
if (__builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1 |
|||
&& selmon->tagset[selmon->seltags] & (TAGMASK >> 1)) { |
|||
selmon->seltags ^= 1; /* toggle sel tagset */ |
|||
pertagview(&((Arg) { .ui = selmon->tagset[selmon->seltags ^ 1] << 1 })); |
|||
focus(NULL); |
|||
arrange(selmon); |
|||
updatecurrentdesktop(); |
|||
} |
|||
} |
|||
|
|||
void |
|||
tagandviewtoleft(const Arg *arg) |
|||
{ |
|||
if (selmon->sel != NULL |
|||
&& __builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1 |
|||
&& selmon->tagset[selmon->seltags] > 1) { |
|||
selmon->sel->tags >>= 1; |
|||
selmon->seltags ^= 1; /* toggle sel tagset */ |
|||
pertagview(&((Arg) { .ui = selmon->tagset[selmon->seltags ^ 1] >> 1 })); |
|||
focus(selmon->sel); |
|||
arrange(selmon); |
|||
updatecurrentdesktop(); |
|||
} |
|||
} |
|||
|
|||
void |
|||
tagandviewtoright(const Arg *arg) |
|||
{ |
|||
if (selmon->sel != NULL |
|||
&& __builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1 |
|||
&& selmon->tagset[selmon->seltags] & (TAGMASK >> 1)) { |
|||
selmon->sel->tags <<= 1; |
|||
selmon->seltags ^= 1; /* toggle sel tagset */ |
|||
pertagview(&((Arg) { .ui = selmon->tagset[selmon->seltags ^ 1] << 1 })); |
|||
focus(selmon->sel); |
|||
arrange(selmon); |
|||
updatecurrentdesktop(); |
|||
} |
|||
} |
|||
|
@ -0,0 +1,7 @@ |
|||
static void tagtoleft(const Arg *arg); |
|||
static void tagtoright(const Arg *arg); |
|||
static void viewtoleft(const Arg *arg); |
|||
static void viewtoright(const Arg *arg); |
|||
static void tagandviewtoleft(const Arg *arg); |
|||
static void tagandviewtoright(const Arg *arg); |
|||
|
@ -0,0 +1,40 @@ |
|||
/* Bar functionality */ |
|||
#include "bar_indicators.c" |
|||
#include "bar_tagicons.c" |
|||
|
|||
#include "bar_alpha.c" |
|||
#include "bar_dwmblocks.c" |
|||
#include "bar_ewmhtags.c" |
|||
#include "bar_ltsymbol.c" |
|||
#include "bar_powerline_tags.c" |
|||
#include "bar_status.c" |
|||
#include "bar_statuscmd.c" |
|||
#include "bar_tabgroups.c" |
|||
#include "bar_tags.c" |
|||
#include "bar_wintitle.c" |
|||
#include "bar_systray.c" |
|||
#include "bar_wintitleactions.c" |
|||
|
|||
/* Other patches */ |
|||
#include "autostart.c" |
|||
#include "decorationhints.c" |
|||
#include "fakefullscreenclient.c" |
|||
#include "focusadjacenttag.c" |
|||
#include "inplacerotate.c" |
|||
#include "pertag.c" |
|||
#include "scratchpad_alt_1.c" |
|||
#include "sticky.c" |
|||
#include "swallow.c" |
|||
#include "tagallmon.c" |
|||
#include "tagswapmon.c" |
|||
#include "transfer.c" |
|||
#include "vanitygaps.c" |
|||
/* Layouts */ |
|||
#include "layout_facts.c" |
|||
#include "layout_centeredmaster.c" |
|||
#include "layout_centeredfloatingmaster.c" |
|||
#include "layout_fibonacci.c" |
|||
#include "layout_monocle.c" |
|||
#include "layout_nrowgrid.c" |
|||
#include "layout_tile.c" |
|||
|
@ -0,0 +1,39 @@ |
|||
/* Bar functionality */ |
|||
#include "bar_indicators.h" |
|||
#include "bar_tagicons.h" |
|||
|
|||
#include "bar_alpha.h" |
|||
#include "bar_dwmblocks.h" |
|||
#include "bar_ewmhtags.h" |
|||
#include "bar_ltsymbol.h" |
|||
#include "bar_powerline_tags.h" |
|||
#include "bar_status.h" |
|||
#include "bar_statuscmd.h" |
|||
#include "bar_tabgroups.h" |
|||
#include "bar_tags.h" |
|||
#include "bar_wintitle.h" |
|||
#include "bar_systray.h" |
|||
#include "bar_wintitleactions.h" |
|||
|
|||
/* Other patches */ |
|||
#include "autostart.h" |
|||
#include "decorationhints.h" |
|||
#include "fakefullscreenclient.h" |
|||
#include "focusadjacenttag.h" |
|||
#include "inplacerotate.h" |
|||
#include "pertag.h" |
|||
#include "scratchpad_alt_1.h" |
|||
#include "sticky.h" |
|||
#include "swallow.h" |
|||
#include "tagallmon.h" |
|||
#include "tagswapmon.h" |
|||
#include "transfer.h" |
|||
#include "vanitygaps.h" |
|||
/* Layouts */ |
|||
#include "layout_centeredmaster.h" |
|||
#include "layout_centeredfloatingmaster.h" |
|||
#include "layout_fibonacci.h" |
|||
#include "layout_monocle.h" |
|||
#include "layout_nrowgrid.h" |
|||
#include "layout_tile.h" |
|||
|
@ -0,0 +1,84 @@ |
|||
void |
|||
insertclient(Client *item, Client *insertItem, int after) |
|||
{ |
|||
Client *c; |
|||
if (item == NULL || insertItem == NULL || item == insertItem) |
|||
return; |
|||
detach(insertItem); |
|||
if (!after && selmon->clients == item) { |
|||
attach(insertItem); |
|||
return; |
|||
} |
|||
if (after) { |
|||
c = item; |
|||
} else { |
|||
for (c = selmon->clients; c; c = c->next) { |
|||
if (c->next == item) |
|||
break; |
|||
} |
|||
} |
|||
insertItem->next = c->next; |
|||
c->next = insertItem; |
|||
} |
|||
|
|||
void |
|||
inplacerotate(const Arg *arg) |
|||
{ |
|||
if (!selmon->sel || (selmon->sel->isfloating && !arg->f)) |
|||
return; |
|||
|
|||
unsigned int selidx = 0, i = 0; |
|||
Client *c = NULL, *stail = NULL, *mhead = NULL, *mtail = NULL, *shead = NULL; |
|||
|
|||
// Determine positionings for insertclient
|
|||
for (c = selmon->clients; c; c = c->next) { |
|||
if (ISVISIBLE(c) && !(c->isfloating)) { |
|||
if (selmon->sel == c) |
|||
selidx = i; |
|||
if (i == selmon->nmaster - 1) |
|||
mtail = c; |
|||
if (i == selmon->nmaster) |
|||
shead = c; |
|||
if (mhead == NULL) |
|||
mhead = c; |
|||
stail = c; |
|||
i++; |
|||
} |
|||
} |
|||
|
|||
switch(arg->i) { |
|||
case 1: |
|||
if (selidx >= selmon->nmaster) |
|||
insertclient(shead, stail, 0); |
|||
else |
|||
insertclient(mhead, mtail, 0); |
|||
break; |
|||
case -1: |
|||
if (selidx >= selmon->nmaster) |
|||
insertclient(stail, shead, 1); |
|||
else |
|||
insertclient(mtail, mhead, 1); |
|||
break; |
|||
case 2: |
|||
insertclient(selmon->clients, stail, 0); |
|||
break; |
|||
case -2: |
|||
insertclient(stail, selmon->clients, 1); |
|||
break; |
|||
} |
|||
|
|||
// Restore focus position
|
|||
i = 0; |
|||
for (c = selmon->clients; c; c = c->next) { |
|||
if (!ISVISIBLE(c) || (c->isfloating)) |
|||
continue; |
|||
if (i == selidx) { |
|||
focus(c); |
|||
break; |
|||
} |
|||
i++; |
|||
} |
|||
arrange(selmon); |
|||
focus(c); |
|||
} |
|||
|
@ -0,0 +1,2 @@ |
|||
static void inplacerotate(const Arg *arg); |
|||
|
@ -0,0 +1,62 @@ |
|||
#ifndef IPC_CLIENT_H_ |
|||
#define IPC_CLIENT_H_ |
|||
|
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <sys/epoll.h> |
|||
|
|||
typedef struct IPCClient IPCClient; |
|||
/**
|
|||
* This structure contains the details of an IPC Client and pointers for a |
|||
* linked list |
|||
*/ |
|||
struct IPCClient { |
|||
int fd; |
|||
int subscriptions; |
|||
|
|||
char *buffer; |
|||
uint32_t buffer_size; |
|||
|
|||
struct epoll_event event; |
|||
IPCClient *next; |
|||
IPCClient *prev; |
|||
}; |
|||
|
|||
typedef IPCClient *IPCClientList; |
|||
|
|||
/**
|
|||
* Allocate memory for new IPCClient with the specified file descriptor and |
|||
* initialize struct. |
|||
* |
|||
* @param fd File descriptor of IPC client |
|||
* |
|||
* @return Address to allocated IPCClient struct |
|||
*/ |
|||
IPCClient *ipc_client_new(int fd); |
|||
|
|||
/**
|
|||
* Add an IPC Client to the specified list |
|||
* |
|||
* @param list Address of the list to add the client to |
|||
* @param nc Address of the IPCClient |
|||
*/ |
|||
void ipc_list_add_client(IPCClientList *list, IPCClient *nc); |
|||
|
|||
/**
|
|||
* Remove an IPCClient from the specified list |
|||
* |
|||
* @param list Address of the list to remove the client from |
|||
* @param c Address of the IPCClient |
|||
*/ |
|||
void ipc_list_remove_client(IPCClientList *list, IPCClient *c); |
|||
|
|||
/**
|
|||
* Get an IPCClient from the specified IPCClient list |
|||
* |
|||
* @param list List to remove the client from |
|||
* @param fd File descriptor of the IPCClient |
|||
*/ |
|||
IPCClient *ipc_list_get_client(IPCClientList list, int fd); |
|||
|
|||
#endif // IPC_CLIENT_H_
|
|||
|
@ -0,0 +1,549 @@ |
|||
#include <ctype.h> |
|||
#include <errno.h> |
|||
#include <inttypes.h> |
|||
#include <stdarg.h> |
|||
#include <stdint.h> |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <sys/socket.h> |
|||
#include <sys/un.h> |
|||
#include <unistd.h> |
|||
#include <yajl/yajl_gen.h> |
|||
|
|||
#define IPC_MAGIC "DWM-IPC" |
|||
// clang-format off
|
|||
#define IPC_MAGIC_ARR { 'D', 'W', 'M', '-', 'I', 'P', 'C' } |
|||
// clang-format on
|
|||
#define IPC_MAGIC_LEN 7 // Not including null char
|
|||
|
|||
#define IPC_EVENT_TAG_CHANGE "tag_change_event" |
|||
#define IPC_EVENT_CLIENT_FOCUS_CHANGE "client_focus_change_event" |
|||
#define IPC_EVENT_LAYOUT_CHANGE "layout_change_event" |
|||
#define IPC_EVENT_MONITOR_FOCUS_CHANGE "monitor_focus_change_event" |
|||
#define IPC_EVENT_FOCUSED_TITLE_CHANGE "focused_title_change_event" |
|||
#define IPC_EVENT_FOCUSED_STATE_CHANGE "focused_state_change_event" |
|||
|
|||
#define YSTR(str) yajl_gen_string(gen, (unsigned char *)str, strlen(str)) |
|||
#define YINT(num) yajl_gen_integer(gen, num) |
|||
#define YDOUBLE(num) yajl_gen_double(gen, num) |
|||
#define YBOOL(v) yajl_gen_bool(gen, v) |
|||
#define YNULL() yajl_gen_null(gen) |
|||
#define YARR(body) \ |
|||
{ \ |
|||
yajl_gen_array_open(gen); \ |
|||
body; \ |
|||
yajl_gen_array_close(gen); \ |
|||
} |
|||
#define YMAP(body) \ |
|||
{ \ |
|||
yajl_gen_map_open(gen); \ |
|||
body; \ |
|||
yajl_gen_map_close(gen); \ |
|||
} |
|||
|
|||
typedef unsigned long Window; |
|||
|
|||
const char *DEFAULT_SOCKET_PATH = "/tmp/dwm.sock"; |
|||
static int sock_fd = -1; |
|||
static unsigned int ignore_reply = 0; |
|||
|
|||
typedef enum IPCMessageType { |
|||
IPC_TYPE_RUN_COMMAND = 0, |
|||
IPC_TYPE_GET_MONITORS = 1, |
|||
IPC_TYPE_GET_TAGS = 2, |
|||
IPC_TYPE_GET_LAYOUTS = 3, |
|||
IPC_TYPE_GET_DWM_CLIENT = 4, |
|||
IPC_TYPE_SUBSCRIBE = 5, |
|||
IPC_TYPE_EVENT = 6 |
|||
} IPCMessageType; |
|||
|
|||
// Every IPC message must begin with this
|
|||
typedef struct dwm_ipc_header { |
|||
uint8_t magic[IPC_MAGIC_LEN]; |
|||
uint32_t size; |
|||
uint8_t type; |
|||
} __attribute((packed)) dwm_ipc_header_t; |
|||
|
|||
static int |
|||
recv_message(uint8_t *msg_type, uint32_t *reply_size, uint8_t **reply) |
|||
{ |
|||
uint32_t read_bytes = 0; |
|||
const int32_t to_read = sizeof(dwm_ipc_header_t); |
|||
char header[to_read]; |
|||
char *walk = header; |
|||
|
|||
// Try to read header
|
|||
while (read_bytes < to_read) { |
|||
ssize_t n = read(sock_fd, header + read_bytes, to_read - read_bytes); |
|||
|
|||
if (n == 0) { |
|||
if (read_bytes == 0) { |
|||
fprintf(stderr, "Unexpectedly reached EOF while reading header."); |
|||
fprintf(stderr, |
|||
"Read %" PRIu32 " bytes, expected %" PRIu32 " total bytes.\n", |
|||
read_bytes, to_read); |
|||
return -2; |
|||
} else { |
|||
fprintf(stderr, "Unexpectedly reached EOF while reading header."); |
|||
fprintf(stderr, |
|||
"Read %" PRIu32 " bytes, expected %" PRIu32 " total bytes.\n", |
|||
read_bytes, to_read); |
|||
return -3; |
|||
} |
|||
} else if (n == -1) { |
|||
return -1; |
|||
} |
|||
|
|||
read_bytes += n; |
|||
} |
|||
|
|||
// Check if magic string in header matches
|
|||
if (memcmp(walk, IPC_MAGIC, IPC_MAGIC_LEN) != 0) { |
|||
fprintf(stderr, "Invalid magic string. Got '%.*s', expected '%s'\n", |
|||
IPC_MAGIC_LEN, walk, IPC_MAGIC); |
|||
return -3; |
|||
} |
|||
|
|||
walk += IPC_MAGIC_LEN; |
|||
|
|||
// Extract reply size
|
|||
memcpy(reply_size, walk, sizeof(uint32_t)); |
|||
walk += sizeof(uint32_t); |
|||
|
|||
// Extract message type
|
|||
memcpy(msg_type, walk, sizeof(uint8_t)); |
|||
walk += sizeof(uint8_t); |
|||
|
|||
(*reply) = malloc(*reply_size); |
|||
|
|||
// Extract payload
|
|||
read_bytes = 0; |
|||
while (read_bytes < *reply_size) { |
|||
ssize_t n = read(sock_fd, *reply + read_bytes, *reply_size - read_bytes); |
|||
|
|||
if (n == 0) { |
|||
fprintf(stderr, "Unexpectedly reached EOF while reading payload."); |
|||
fprintf(stderr, "Read %" PRIu32 " bytes, expected %" PRIu32 " bytes.\n", |
|||
read_bytes, *reply_size); |
|||
free(*reply); |
|||
return -2; |
|||
} else if (n == -1) { |
|||
if (errno == EINTR || errno == EAGAIN) continue; |
|||
free(*reply); |
|||
return -1; |
|||
} |
|||
|
|||
read_bytes += n; |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static int |
|||
read_socket(IPCMessageType *msg_type, uint32_t *msg_size, char **msg) |
|||
{ |
|||
int ret = -1; |
|||
|
|||
while (ret != 0) { |
|||
ret = recv_message((uint8_t *)msg_type, msg_size, (uint8_t **)msg); |
|||
|
|||
if (ret < 0) { |
|||
// Try again (non-fatal error)
|
|||
if (ret == -1 && (errno == EINTR || errno == EAGAIN)) continue; |
|||
|
|||
fprintf(stderr, "Error receiving response from socket. "); |
|||
fprintf(stderr, "The connection might have been lost.\n"); |
|||
exit(2); |
|||
} |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static ssize_t |
|||
write_socket(const void *buf, size_t count) |
|||
{ |
|||
size_t written = 0; |
|||
|
|||
while (written < count) { |
|||
const ssize_t n = |
|||
write(sock_fd, ((uint8_t *)buf) + written, count - written); |
|||
|
|||
if (n == -1) { |
|||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) |
|||
continue; |
|||
else |
|||
return n; |
|||
} |
|||
written += n; |
|||
} |
|||
return written; |
|||
} |
|||
|
|||
static void |
|||
connect_to_socket() |
|||
{ |
|||
struct sockaddr_un addr; |
|||
|
|||
int sock = socket(AF_UNIX, SOCK_STREAM, 0); |
|||
|
|||
// Initialize struct to 0
|
|||
memset(&addr, 0, sizeof(struct sockaddr_un)); |
|||
|
|||
addr.sun_family = AF_UNIX; |
|||
strcpy(addr.sun_path, DEFAULT_SOCKET_PATH); |
|||
|
|||
connect(sock, (const struct sockaddr *)&addr, sizeof(struct sockaddr_un)); |
|||
|
|||
sock_fd = sock; |
|||
} |
|||
|
|||
static int |
|||
send_message(IPCMessageType msg_type, uint32_t msg_size, uint8_t *msg) |
|||
{ |
|||
dwm_ipc_header_t header = { |
|||
.magic = IPC_MAGIC_ARR, .size = msg_size, .type = msg_type}; |
|||
|
|||
size_t header_size = sizeof(dwm_ipc_header_t); |
|||
size_t total_size = header_size + msg_size; |
|||
|
|||
uint8_t buffer[total_size]; |
|||
|
|||
// Copy header to buffer
|
|||
memcpy(buffer, &header, header_size); |
|||
// Copy message to buffer
|
|||
memcpy(buffer + header_size, msg, header.size); |
|||
|
|||
write_socket(buffer, total_size); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static int |
|||
is_float(const char *s) |
|||
{ |
|||
size_t len = strlen(s); |
|||
int is_dot_used = 0; |
|||
int is_minus_used = 0; |
|||
|
|||
// Floats can only have one decimal point in between or digits
|
|||
// Optionally, floats can also be below zero (negative)
|
|||
for (int i = 0; i < len; i++) { |
|||
if (isdigit(s[i])) |
|||
continue; |
|||
else if (!is_dot_used && s[i] == '.' && i != 0 && i != len - 1) { |
|||
is_dot_used = 1; |
|||
continue; |
|||
} else if (!is_minus_used && s[i] == '-' && i == 0) { |
|||
is_minus_used = 1; |
|||
continue; |
|||
} else |
|||
return 0; |
|||
} |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
static int |
|||
is_unsigned_int(const char *s) |
|||
{ |
|||
size_t len = strlen(s); |
|||
|
|||
// Unsigned int can only have digits
|
|||
for (int i = 0; i < len; i++) { |
|||
if (isdigit(s[i])) |
|||
continue; |
|||
else |
|||
return 0; |
|||
} |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
static int |
|||
is_signed_int(const char *s) |
|||
{ |
|||
size_t len = strlen(s); |
|||
|
|||
// Signed int can only have digits and a negative sign at the start
|
|||
for (int i = 0; i < len; i++) { |
|||
if (isdigit(s[i])) |
|||
continue; |
|||
else if (i == 0 && s[i] == '-') { |
|||
continue; |
|||
} else |
|||
return 0; |
|||
} |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
static void |
|||
flush_socket_reply() |
|||
{ |
|||
IPCMessageType reply_type; |
|||
uint32_t reply_size; |
|||
char *reply; |
|||
|
|||
read_socket(&reply_type, &reply_size, &reply); |
|||
|
|||
free(reply); |
|||
} |
|||
|
|||
static void |
|||
print_socket_reply() |
|||
{ |
|||
IPCMessageType reply_type; |
|||
uint32_t reply_size; |
|||
char *reply; |
|||
|
|||
read_socket(&reply_type, &reply_size, &reply); |
|||
|
|||
printf("%.*s\n", reply_size, reply); |
|||
fflush(stdout); |
|||
free(reply); |
|||
} |
|||
|
|||
static int |
|||
run_command(const char *name, char *args[], int argc) |
|||
{ |
|||
const unsigned char *msg; |
|||
size_t msg_size; |
|||
|
|||
yajl_gen gen = yajl_gen_alloc(NULL); |
|||
|
|||
// Message format:
|
|||
// {
|
|||
// "command": "<name>",
|
|||
// "args": [ ... ]
|
|||
// }
|
|||
// clang-format off
|
|||
YMAP( |
|||
YSTR("command"); YSTR(name); |
|||
YSTR("args"); YARR( |
|||
for (int i = 0; i < argc; i++) { |
|||
if (is_signed_int(args[i])) { |
|||
long long num = atoll(args[i]); |
|||
YINT(num); |
|||
} else if (is_float(args[i])) { |
|||
float num = atof(args[i]); |
|||
YDOUBLE(num); |
|||
} else { |
|||
YSTR(args[i]); |
|||
} |
|||
} |
|||
) |
|||
) |
|||
// clang-format on
|
|||
|
|||
yajl_gen_get_buf(gen, &msg, &msg_size); |
|||
|
|||
send_message(IPC_TYPE_RUN_COMMAND, msg_size, (uint8_t *)msg); |
|||
|
|||
if (!ignore_reply) |
|||
print_socket_reply(); |
|||
else |
|||
flush_socket_reply(); |
|||
|
|||
yajl_gen_free(gen); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static int |
|||
get_monitors() |
|||
{ |
|||
send_message(IPC_TYPE_GET_MONITORS, 1, (uint8_t *)""); |
|||
print_socket_reply(); |
|||
return 0; |
|||
} |
|||
|
|||
static int |
|||
get_tags() |
|||
{ |
|||
send_message(IPC_TYPE_GET_TAGS, 1, (uint8_t *)""); |
|||
print_socket_reply(); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static int |
|||
get_layouts() |
|||
{ |
|||
send_message(IPC_TYPE_GET_LAYOUTS, 1, (uint8_t *)""); |
|||
print_socket_reply(); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static int |
|||
get_dwm_client(Window win) |
|||
{ |
|||
const unsigned char *msg; |
|||
size_t msg_size; |
|||
|
|||
yajl_gen gen = yajl_gen_alloc(NULL); |
|||
|
|||
// Message format:
|
|||
// {
|
|||
// "client_window_id": "<win>"
|
|||
// }
|
|||
// clang-format off
|
|||
YMAP( |
|||
YSTR("client_window_id"); YINT(win); |
|||
) |
|||
// clang-format on
|
|||
|
|||
yajl_gen_get_buf(gen, &msg, &msg_size); |
|||
|
|||
send_message(IPC_TYPE_GET_DWM_CLIENT, msg_size, (uint8_t *)msg); |
|||
|
|||
print_socket_reply(); |
|||
|
|||
yajl_gen_free(gen); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static int |
|||
subscribe(const char *event) |
|||
{ |
|||
const unsigned char *msg; |
|||
size_t msg_size; |
|||
|
|||
yajl_gen gen = yajl_gen_alloc(NULL); |
|||
|
|||
// Message format:
|
|||
// {
|
|||
// "event": "<event>",
|
|||
// "action": "subscribe"
|
|||
// }
|
|||
// clang-format off
|
|||
YMAP( |
|||
YSTR("event"); YSTR(event); |
|||
YSTR("action"); YSTR("subscribe"); |
|||
) |
|||
// clang-format on
|
|||
|
|||
yajl_gen_get_buf(gen, &msg, &msg_size); |
|||
|
|||
send_message(IPC_TYPE_SUBSCRIBE, msg_size, (uint8_t *)msg); |
|||
|
|||
if (!ignore_reply) |
|||
print_socket_reply(); |
|||
else |
|||
flush_socket_reply(); |
|||
|
|||
yajl_gen_free(gen); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static void |
|||
usage_error(const char *prog_name, const char *format, ...) |
|||
{ |
|||
va_list args; |
|||
va_start(args, format); |
|||
|
|||
fprintf(stderr, "Error: "); |
|||
vfprintf(stderr, format, args); |
|||
fprintf(stderr, "\nusage: %s <command> [...]\n", prog_name); |
|||
fprintf(stderr, "Try '%s help'\n", prog_name); |
|||
|
|||
va_end(args); |
|||
exit(1); |
|||
} |
|||
|
|||
static void |
|||
print_usage(const char *name) |
|||
{ |
|||
printf("usage: %s [options] <command> [...]\n", name); |
|||
puts(""); |
|||
puts("Commands:"); |
|||
puts(" run_command <name> [args...] Run an IPC command"); |
|||
puts(""); |
|||
puts(" get_monitors Get monitor properties"); |
|||
puts(""); |
|||
puts(" get_tags Get list of tags"); |
|||
puts(""); |
|||
puts(" get_layouts Get list of layouts"); |
|||
puts(""); |
|||
puts(" get_dwm_client <window_id> Get dwm client proprties"); |
|||
puts(""); |
|||
puts(" subscribe [events...] Subscribe to specified events"); |
|||
puts(" Options: " IPC_EVENT_TAG_CHANGE ","); |
|||
puts(" " IPC_EVENT_LAYOUT_CHANGE ","); |
|||
puts(" " IPC_EVENT_CLIENT_FOCUS_CHANGE ","); |
|||
puts(" " IPC_EVENT_MONITOR_FOCUS_CHANGE ","); |
|||
puts(" " IPC_EVENT_FOCUSED_TITLE_CHANGE ","); |
|||
puts(" " IPC_EVENT_FOCUSED_STATE_CHANGE); |
|||
puts(""); |
|||
puts(" help Display this message"); |
|||
puts(""); |
|||
puts("Options:"); |
|||
puts(" --ignore-reply Don't print reply messages from"); |
|||
puts(" run_command and subscribe."); |
|||
puts(""); |
|||
} |
|||
|
|||
int |
|||
main(int argc, char *argv[]) |
|||
{ |
|||
const char *prog_name = argv[0]; |
|||
|
|||
connect_to_socket(); |
|||
if (sock_fd == -1) { |
|||
fprintf(stderr, "Failed to connect to socket\n"); |
|||
return 1; |
|||
} |
|||
|
|||
int i = 1; |
|||
if (i < argc && strcmp(argv[i], "--ignore-reply") == 0) { |
|||
ignore_reply = 1; |
|||
i++; |
|||
} |
|||
|
|||
if (i >= argc) usage_error(prog_name, "Expected an argument, got none"); |
|||
|
|||
if (!argc || strcmp(argv[i], "help") == 0) |
|||
print_usage(prog_name); |
|||
else if (strcmp(argv[i], "run_command") == 0) { |
|||
if (++i >= argc) usage_error(prog_name, "No command specified"); |
|||
// Command name
|
|||
char *command = argv[i]; |
|||
// Command arguments are everything after command name
|
|||
char **command_args = argv + ++i; |
|||
// Number of command arguments
|
|||
int command_argc = argc - i; |
|||
run_command(command, command_args, command_argc); |
|||
} else if (strcmp(argv[i], "get_monitors") == 0) { |
|||
get_monitors(); |
|||
} else if (strcmp(argv[i], "get_tags") == 0) { |
|||
get_tags(); |
|||
} else if (strcmp(argv[i], "get_layouts") == 0) { |
|||
get_layouts(); |
|||
} else if (strcmp(argv[i], "get_dwm_client") == 0) { |
|||
if (++i < argc) { |
|||
if (is_unsigned_int(argv[i])) { |
|||
Window win = atol(argv[i]); |
|||
get_dwm_client(win); |
|||
} else |
|||
usage_error(prog_name, "Expected unsigned integer argument"); |
|||
} else |
|||
usage_error(prog_name, "Expected the window id"); |
|||
} else if (strcmp(argv[i], "subscribe") == 0) { |
|||
if (++i < argc) { |
|||
for (int j = i; j < argc; j++) subscribe(argv[j]); |
|||
} else |
|||
usage_error(prog_name, "Expected event name"); |
|||
// Keep listening for events forever
|
|||
while (1) { |
|||
print_socket_reply(); |
|||
} |
|||
} else |
|||
usage_error(prog_name, "Invalid argument '%s'", argv[i]); |
|||
|
|||
return 0; |
|||
} |
|||
|
@ -0,0 +1,66 @@ |
|||
#ifndef YAJL_DUMPS_H_ |
|||
#define YAJL_DUMPS_H_ |
|||
|
|||
#include <string.h> |
|||
#include <yajl/yajl_gen.h> |
|||
|
|||
#define YSTR(str) yajl_gen_string(gen, (unsigned char *)str, strlen(str)) |
|||
#define YINT(num) yajl_gen_integer(gen, num) |
|||
#define YDOUBLE(num) yajl_gen_double(gen, num) |
|||
#define YBOOL(v) yajl_gen_bool(gen, v) |
|||
#define YNULL() yajl_gen_null(gen) |
|||
#define YARR(body) \ |
|||
{ \ |
|||
yajl_gen_array_open(gen); \ |
|||
body; \ |
|||
yajl_gen_array_close(gen); \ |
|||
} |
|||
#define YMAP(body) \ |
|||
{ \ |
|||
yajl_gen_map_open(gen); \ |
|||
body; \ |
|||
yajl_gen_map_close(gen); \ |
|||
} |
|||
|
|||
int dump_tag(yajl_gen gen, const char *name, const int tag_mask); |
|||
|
|||
int dump_tags(yajl_gen gen, int tags_len); |
|||
|
|||
int dump_client(yajl_gen gen, Client *c); |
|||
|
|||
int dump_monitor(yajl_gen gen, Monitor *mon, int is_selected); |
|||
|
|||
int dump_monitors(yajl_gen gen, Monitor *mons, Monitor *selmon); |
|||
|
|||
int dump_layouts(yajl_gen gen, const Layout layouts[], const int layouts_len); |
|||
|
|||
int dump_tag_state(yajl_gen gen, TagState state); |
|||
|
|||
int dump_tag_event(yajl_gen gen, int mon_num, TagState old_state, |
|||
TagState new_state); |
|||
|
|||
int dump_client_focus_change_event(yajl_gen gen, Client *old_client, |
|||
Client *new_client, int mon_num); |
|||
|
|||
int dump_layout_change_event(yajl_gen gen, const int mon_num, |
|||
const char *old_symbol, const Layout *old_layout, |
|||
const char *new_symbol, const Layout *new_layout); |
|||
|
|||
int dump_monitor_focus_change_event(yajl_gen gen, const int last_mon_num, |
|||
const int new_mon_num); |
|||
|
|||
int dump_focused_title_change_event(yajl_gen gen, const int mon_num, |
|||
const Window client_id, |
|||
const char *old_name, const char *new_name); |
|||
|
|||
int dump_client_state(yajl_gen gen, const ClientState *state); |
|||
|
|||
int dump_focused_state_change_event(yajl_gen gen, const int mon_num, |
|||
const Window client_id, |
|||
const ClientState *old_state, |
|||
const ClientState *new_state); |
|||
|
|||
int dump_error_message(yajl_gen gen, const char *reason); |
|||
|
|||
#endif // YAJL_DUMPS_H_
|
|||
|
@ -0,0 +1,55 @@ |
|||
void |
|||
centeredfloatingmaster(Monitor *m) |
|||
{ |
|||
unsigned int i, n; |
|||
float mfacts, sfacts; |
|||
int mrest, srest; |
|||
int mx = 0, my = 0, mh = 0, mw = 0; |
|||
int sx = 0, sy = 0, sh = 0, sw = 0; |
|||
Client *c; |
|||
|
|||
float mivf = 1.0; // master inner vertical gap factor
|
|||
int oh, ov, ih, iv; |
|||
getgaps(m, &oh, &ov, &ih, &iv, &n); |
|||
|
|||
if (n == 0) |
|||
return; |
|||
|
|||
sx = mx = m->wx + ov; |
|||
sy = my = m->wy + oh; |
|||
sh = mh = m->wh - 2*oh; |
|||
mw = m->ww - 2*ov - iv*(n - 1); |
|||
sw = m->ww - 2*ov - iv*(n - m->nmaster - 1); |
|||
|
|||
if (m->nmaster && n > m->nmaster) { |
|||
mivf = 0.8; |
|||
/* go mfact box in the center if more than nmaster clients */ |
|||
if (m->ww > m->wh) { |
|||
mw = m->ww * m->mfact - iv*mivf*(MIN(n, m->nmaster) - 1); |
|||
mh = m->wh * 0.9; |
|||
} else { |
|||
mw = m->ww * 0.9 - iv*mivf*(MIN(n, m->nmaster) - 1); |
|||
mh = m->wh * m->mfact; |
|||
} |
|||
mx = m->wx + (m->ww - mw) / 2; |
|||
my = m->wy + (m->wh - mh - 2*oh) / 2; |
|||
|
|||
sx = m->wx + ov; |
|||
sy = m->wy + oh; |
|||
sh = m->wh - 2*oh; |
|||
} |
|||
|
|||
getfacts(m, mw, sw, &mfacts, &sfacts, &mrest, &srest); |
|||
|
|||
for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) |
|||
if (i < m->nmaster) { |
|||
/* nmaster clients are stacked horizontally, in the center of the screen */ |
|||
resize(c, mx, my, (mw / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0); |
|||
mx += WIDTH(c) + iv*mivf; |
|||
} else { |
|||
/* stack clients are stacked horizontally */ |
|||
resize(c, sx, sy, (sw / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0); |
|||
sx += WIDTH(c) + iv; |
|||
} |
|||
} |
|||
|
@ -0,0 +1,2 @@ |
|||
static void centeredfloatingmaster(Monitor *m); |
|||
|
@ -0,0 +1,85 @@ |
|||
void |
|||
centeredmaster(Monitor *m) |
|||
{ |
|||
unsigned int i, n; |
|||
int mx = 0, my = 0, mh = 0, mw = 0; |
|||
int lx = 0, ly = 0, lw = 0, lh = 0; |
|||
int rx = 0, ry = 0, rw = 0, rh = 0; |
|||
float mfacts = 0, lfacts = 0, rfacts = 0; |
|||
int mtotal = 0, ltotal = 0, rtotal = 0; |
|||
int mrest = 0, lrest = 0, rrest = 0; |
|||
Client *c; |
|||
|
|||
int oh, ov, ih, iv; |
|||
getgaps(m, &oh, &ov, &ih, &iv, &n); |
|||
|
|||
if (n == 0) |
|||
return; |
|||
|
|||
/* initialize areas */ |
|||
mx = m->wx + ov; |
|||
my = m->wy + oh; |
|||
mh = m->wh - 2*oh - ih * ((!m->nmaster ? n : MIN(n, m->nmaster)) - 1); |
|||
mw = m->ww - 2*ov; |
|||
lh = m->wh - 2*oh - ih * (((n - m->nmaster) / 2) - 1); |
|||
rh = m->wh - 2*oh - ih * (((n - m->nmaster) / 2) - ((n - m->nmaster) % 2 ? 0 : 1)); |
|||
|
|||
if (m->nmaster && n > m->nmaster) { |
|||
/* go mfact box in the center if more than nmaster clients */ |
|||
if (n - m->nmaster > 1) { |
|||
/* ||<-S->|<---M--->|<-S->|| */ |
|||
mw = (m->ww - 2*ov - 2*iv) * m->mfact; |
|||
lw = (m->ww - mw - 2*ov - 2*iv) / 2; |
|||
mx += lw + iv; |
|||
} else { |
|||
/* ||<---M--->|<-S->|| */ |
|||
mw = (mw - iv) * m->mfact; |
|||
lw = m->ww - mw - iv - 2*ov; |
|||
} |
|||
rw = lw; |
|||
lx = m->wx + ov; |
|||
ly = m->wy + oh; |
|||
rx = mx + mw + iv; |
|||
ry = m->wy + oh; |
|||
} |
|||
|
|||
/* calculate facts */ |
|||
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) { |
|||
if (!m->nmaster || n < m->nmaster) |
|||
mfacts += 1; |
|||
else if ((n - m->nmaster) % 2) |
|||
lfacts += 1; // total factor of left hand stack area
|
|||
else |
|||
rfacts += 1; // total factor of right hand stack area
|
|||
} |
|||
|
|||
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) |
|||
if (!m->nmaster || n < m->nmaster) |
|||
mtotal += mh / mfacts; |
|||
else if ((n - m->nmaster) % 2) |
|||
ltotal += lh / lfacts; |
|||
else |
|||
rtotal += rh / rfacts; |
|||
|
|||
mrest = mh - mtotal; |
|||
lrest = lh - ltotal; |
|||
rrest = rh - rtotal; |
|||
|
|||
for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) { |
|||
if (!m->nmaster || i < m->nmaster) { |
|||
/* nmaster clients are stacked vertically, in the center of the screen */ |
|||
resize(c, mx, my, mw - (2*c->bw), (mh / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0); |
|||
my += HEIGHT(c) + ih; |
|||
} else { |
|||
/* stack clients are stacked vertically */ |
|||
if ((i - m->nmaster) % 2 ) { |
|||
resize(c, lx, ly, lw - (2*c->bw), (lh / lfacts) + ((i - 2*m->nmaster) < 2*lrest ? 1 : 0) - (2*c->bw), 0); |
|||
ly += HEIGHT(c) + ih; |
|||
} else { |
|||
resize(c, rx, ry, rw - (2*c->bw), (rh / rfacts) + ((i - 2*m->nmaster) < 2*rrest ? 1 : 0) - (2*c->bw), 0); |
|||
ry += HEIGHT(c) + ih; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
@ -0,0 +1,2 @@ |
|||
static void centeredmaster(Monitor *m); |
|||
|
@ -0,0 +1,24 @@ |
|||
void |
|||
getfacts(Monitor *m, int msize, int ssize, float *mf, float *sf, int *mr, int *sr) |
|||
{ |
|||
unsigned int n; |
|||
float mfacts, sfacts; |
|||
int mtotal = 0, stotal = 0; |
|||
Client *c; |
|||
|
|||
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); |
|||
mfacts = MIN(n, m->nmaster); |
|||
sfacts = n - m->nmaster; |
|||
|
|||
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) |
|||
if (n < m->nmaster) |
|||
mtotal += msize / mfacts; |
|||
else |
|||
stotal += ssize / sfacts; |
|||
|
|||
*mf = mfacts; // total factor of master area
|
|||
*sf = sfacts; // total factor of stack area
|
|||
*mr = msize - mtotal; // the remainder (rest) of pixels after an even master split
|
|||
*sr = ssize - stotal; // the remainder (rest) of pixels after an even stack split
|
|||
} |
|||
|
@ -0,0 +1,94 @@ |
|||
void |
|||
fibonacci(Monitor *m, int s) |
|||
{ |
|||
unsigned int i, n; |
|||
int nx, ny, nw, nh; |
|||
int oh, ov, ih, iv; |
|||
int nv, hrest = 0, wrest = 0, r = 1; |
|||
Client *c; |
|||
|
|||
getgaps(m, &oh, &ov, &ih, &iv, &n); |
|||
if (n == 0) |
|||
return; |
|||
|
|||
nx = m->wx + ov; |
|||
ny = oh; |
|||
nw = m->ww - 2*ov; |
|||
nh = m->wh - 2*oh; |
|||
|
|||
for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next)) { |
|||
if (r) { |
|||
if ((i % 2 && (nh - ih) / 2 <= (bh + 2*c->bw)) |
|||
|| (!(i % 2) && (nw - iv) / 2 <= (bh + 2*c->bw))) { |
|||
r = 0; |
|||
} |
|||
if (r && i < n - 1) { |
|||
if (i % 2) { |
|||
nv = (nh - ih) / 2; |
|||
hrest = nh - 2*nv - ih; |
|||
nh = nv; |
|||
} else { |
|||
nv = (nw - iv) / 2; |
|||
wrest = nw - 2*nv - iv; |
|||
nw = nv; |
|||
} |
|||
|
|||
if ((i % 4) == 2 && !s) |
|||
nx += nw + iv; |
|||
else if ((i % 4) == 3 && !s) |
|||
ny += nh + ih; |
|||
} |
|||
|
|||
if ((i % 4) == 0) { |
|||
if (s) { |
|||
ny += nh + ih; |
|||
nh += hrest; |
|||
} |
|||
else { |
|||
nh -= hrest; |
|||
ny -= nh + ih; |
|||
} |
|||
} |
|||
else if ((i % 4) == 1) { |
|||
nx += nw + iv; |
|||
nw += wrest; |
|||
} |
|||
else if ((i % 4) == 2) { |
|||
ny += nh + ih; |
|||
nh += hrest; |
|||
if (i < n - 1) |
|||
nw += wrest; |
|||
} |
|||
else if ((i % 4) == 3) { |
|||
if (s) { |
|||
nx += nw + iv; |
|||
nw -= wrest; |
|||
} else { |
|||
nw -= wrest; |
|||
nx -= nw + iv; |
|||
nh += hrest; |
|||
} |
|||
} |
|||
if (i == 0) { |
|||
if (n != 1) { |
|||
nw = (m->ww - iv - 2*ov) - (m->ww - iv - 2*ov) * (1 - m->mfact); |
|||
wrest = 0; |
|||
} |
|||
ny = m->wy + oh; |
|||
} |
|||
else if (i == 1) |
|||
nw = m->ww - nw - iv - 2*ov; |
|||
i++; |
|||
} |
|||
|
|||
resize(c, nx, ny, nw - (2*c->bw), nh - (2*c->bw), False); |
|||
} |
|||
} |
|||
|
|||
static void |
|||
dwindle(Monitor *m) |
|||
{ |
|||
fibonacci(m, 1); |
|||
} |
|||
|
|||
|
@ -0,0 +1,3 @@ |
|||
static void dwindle(Monitor *m); |
|||
static void fibonacci(Monitor *m, int s); |
|||
|
@ -0,0 +1,15 @@ |
|||
void |
|||
monocle(Monitor *m) |
|||
{ |
|||
unsigned int n = 0; |
|||
Client *c; |
|||
|
|||
for (c = m->clients; c; c = c->next) |
|||
if (ISVISIBLE(c)) |
|||
n++; |
|||
if (n > 0) /* override layout symbol */ |
|||
snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n); |
|||
for (c = nexttiled(m->clients); c; c = nexttiled(c->next)) |
|||
resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0); |
|||
} |
|||
|
@ -0,0 +1,2 @@ |
|||
static void monocle(Monitor *m); |
|||
|
@ -0,0 +1,53 @@ |
|||
void |
|||
nrowgrid(Monitor *m) |
|||
{ |
|||
unsigned int n = 0, i = 0, ri = 0, ci = 0; /* counters */ |
|||
int oh, ov, ih, iv; /* vanitygap settings */ |
|||
unsigned int cx, cy, cw, ch; /* client geometry */ |
|||
unsigned int uw = 0, uh = 0, uc = 0; /* utilization trackers */ |
|||
unsigned int cols, rows = m->nmaster + 1; |
|||
Client *c; |
|||
|
|||
/* count clients */ |
|||
getgaps(m, &oh, &ov, &ih, &iv, &n); |
|||
|
|||
/* nothing to do here */ |
|||
if (n == 0) |
|||
return; |
|||
|
|||
/* force 2 clients to always split vertically */ |
|||
if (FORCE_VSPLIT && n == 2) |
|||
rows = 1; |
|||
|
|||
/* never allow empty rows */ |
|||
if (n < rows) |
|||
rows = n; |
|||
|
|||
/* define first row */ |
|||
cols = n / rows; |
|||
uc = cols; |
|||
cy = m->wy + oh; |
|||
ch = (m->wh - 2*oh - ih*(rows - 1)) / rows; |
|||
uh = ch; |
|||
|
|||
for (c = nexttiled(m->clients); c; c = nexttiled(c->next), i++, ci++) { |
|||
if (ci == cols) { |
|||
uw = 0; |
|||
ci = 0; |
|||
ri++; |
|||
|
|||
/* next row */ |
|||
cols = (n - uc) / (rows - ri); |
|||
uc += cols; |
|||
cy = m->wy + oh + uh + ih; |
|||
uh += ch + ih; |
|||
} |
|||
|
|||
cx = m->wx + ov + uw; |
|||
cw = (m->ww - 2*ov - uw) / (cols - ci); |
|||
uw += cw + iv; |
|||
|
|||
resize(c, cx, cy, cw - (2*c->bw), ch - (2*c->bw), 0); |
|||
} |
|||
} |
|||
|
@ -0,0 +1,2 @@ |
|||
static void nrowgrid(Monitor *m); |
|||
|
@ -0,0 +1,41 @@ |
|||
static void |
|||
tile(Monitor *m) |
|||
{ |
|||
unsigned int i, n; |
|||
int mx = 0, my = 0, mh = 0, mw = 0; |
|||
int sx = 0, sy = 0, sh = 0, sw = 0; |
|||
float mfacts, sfacts; |
|||
int mrest, srest; |
|||
Client *c; |
|||
|
|||
|
|||
int oh, ov, ih, iv; |
|||
getgaps(m, &oh, &ov, &ih, &iv, &n); |
|||
|
|||
if (n == 0) |
|||
return; |
|||
|
|||
sx = mx = m->wx + ov; |
|||
sy = my = m->wy + oh; |
|||
mh = m->wh - 2*oh - ih * (MIN(n, m->nmaster) - 1); |
|||
sh = m->wh - 2*oh - ih * (n - m->nmaster - 1); |
|||
sw = mw = m->ww - 2*ov; |
|||
|
|||
if (m->nmaster && n > m->nmaster) { |
|||
sw = (mw - iv) * (1 - m->mfact); |
|||
mw = (mw - iv) * m->mfact; |
|||
sx = mx + mw + iv; |
|||
} |
|||
|
|||
getfacts(m, mh, sh, &mfacts, &sfacts, &mrest, &srest); |
|||
|
|||
for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) |
|||
if (i < m->nmaster) { |
|||
resize(c, mx, my, mw - (2*c->bw), (mh / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0); |
|||
my += HEIGHT(c) + ih; |
|||
} else { |
|||
resize(c, sx, sy, sw - (2*c->bw), (sh / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0); |
|||
sy += HEIGHT(c) + ih; |
|||
} |
|||
} |
|||
|
@ -0,0 +1,2 @@ |
|||
static void tile(Monitor *); |
|||
|
@ -0,0 +1,36 @@ |
|||
struct Pertag { |
|||
unsigned int curtag, prevtag; /* current and previous tag */ |
|||
int nmasters[NUMTAGS + 1]; /* number of windows in master area */ |
|||
const Layout *ltidxs[NUMTAGS + 1][2]; /* matrix of tags and layouts indexes */ |
|||
float mfacts[NUMTAGS + 1]; /* mfacts per tag */ |
|||
unsigned int sellts[NUMTAGS + 1]; /* selected layouts */ |
|||
}; |
|||
|
|||
void |
|||
pertagview(const Arg *arg) |
|||
{ |
|||
int i; |
|||
unsigned int tmptag; |
|||
if (arg->ui & TAGMASK) { |
|||
selmon->pertag->prevtag = selmon->pertag->curtag; |
|||
selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; |
|||
if (arg->ui == ~0) |
|||
selmon->pertag->curtag = 0; |
|||
else { |
|||
for (i = 0; !(arg->ui & 1 << i); i++) ; |
|||
selmon->pertag->curtag = i + 1; |
|||
} |
|||
} else { |
|||
tmptag = selmon->pertag->prevtag; |
|||
selmon->pertag->prevtag = selmon->pertag->curtag; |
|||
selmon->pertag->curtag = tmptag; |
|||
} |
|||
selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; |
|||
selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; |
|||
selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; |
|||
selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; |
|||
selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; |
|||
|
|||
|
|||
} |
|||
|
@ -0,0 +1,2 @@ |
|||
static void pertagview(const Arg *arg); |
|||
|
@ -0,0 +1,72 @@ |
|||
static Client * scratchpad_last_showed = NULL; |
|||
|
|||
void |
|||
scratchpad_hide() |
|||
{ |
|||
if (selmon->sel) { |
|||
selmon->sel->tags = SCRATCHPAD_MASK; |
|||
selmon->sel->isfloating = 1; |
|||
focus(NULL); |
|||
arrange(selmon); |
|||
} |
|||
} |
|||
|
|||
_Bool |
|||
scratchpad_last_showed_is_killed(void) |
|||
{ |
|||
Client *c; |
|||
for (c = selmon->clients; c && c != scratchpad_last_showed; c = c->next); |
|||
return (c == NULL); |
|||
} |
|||
|
|||
void |
|||
scratchpad_remove() |
|||
{ |
|||
if (selmon->sel && scratchpad_last_showed != NULL && selmon->sel == scratchpad_last_showed) |
|||
scratchpad_last_showed = NULL; |
|||
} |
|||
|
|||
void |
|||
scratchpad_show() |
|||
{ |
|||
if (scratchpad_last_showed == NULL || scratchpad_last_showed_is_killed()) { |
|||
scratchpad_show_first(); |
|||
return; |
|||
} |
|||
|
|||
if (scratchpad_last_showed->tags != SCRATCHPAD_MASK) { |
|||
scratchpad_last_showed->tags = SCRATCHPAD_MASK; |
|||
focus(NULL); |
|||
arrange(selmon); |
|||
return; |
|||
} |
|||
|
|||
Client *c; |
|||
|
|||
for (c = selmon->clients; c && c != scratchpad_last_showed; c = c->next); |
|||
for (c = (c ? c->next : NULL); c && c->tags != SCRATCHPAD_MASK; c = c->next); |
|||
|
|||
if (c) |
|||
scratchpad_show_client(c); |
|||
else |
|||
scratchpad_show_first(); |
|||
} |
|||
|
|||
void |
|||
scratchpad_show_client(Client* c) |
|||
{ |
|||
scratchpad_last_showed = c; |
|||
c->tags = selmon->tagset[selmon->seltags]; |
|||
focus(c); |
|||
arrange(selmon); |
|||
} |
|||
|
|||
void |
|||
scratchpad_show_first(void) |
|||
{ |
|||
Client *c; |
|||
for (c = selmon->clients; c && c->tags != SCRATCHPAD_MASK; c = c->next); |
|||
if (c) |
|||
scratchpad_show_client(c); |
|||
} |
|||
|
@ -0,0 +1,9 @@ |
|||
#define SCRATCHPAD_MASK (1u << NUMTAGS) |
|||
|
|||
static void scratchpad_hide(); |
|||
static _Bool scratchpad_last_showed_is_killed(void); |
|||
static void scratchpad_remove(); |
|||
static void scratchpad_show(); |
|||
static void scratchpad_show_client(Client *c); |
|||
static void scratchpad_show_first(void); |
|||
|
@ -0,0 +1,9 @@ |
|||
void |
|||
togglesticky(const Arg *arg) |
|||
{ |
|||
if (!selmon->sel) |
|||
return; |
|||
selmon->sel->issticky = !selmon->sel->issticky; |
|||
arrange(selmon); |
|||
} |
|||
|
@ -0,0 +1,2 @@ |
|||
static void togglesticky(const Arg *arg); |
|||
|
@ -0,0 +1,214 @@ |
|||
#include <X11/Xlib-xcb.h> |
|||
#include <xcb/res.h> |
|||
#ifdef __OpenBSD__ |
|||
#include <sys/sysctl.h> |
|||
#include <kvm.h> |
|||
#endif /* __OpenBSD__ */ |
|||
|
|||
static int scanner; |
|||
static xcb_connection_t *xcon; |
|||
|
|||
int |
|||
swallow(Client *p, Client *c) |
|||
{ |
|||
Client *s; |
|||
XWindowChanges wc; |
|||
|
|||
if (c->noswallow > 0 || c->isterminal) |
|||
return 0; |
|||
if (c->noswallow < 0 && !swallowfloating && c->isfloating) |
|||
return 0; |
|||
|
|||
XMapWindow(dpy, c->win); |
|||
|
|||
detach(c); |
|||
detachstack(c); |
|||
|
|||
setclientstate(c, WithdrawnState); |
|||
XUnmapWindow(dpy, p->win); |
|||
|
|||
p->swallowing = c; |
|||
c->mon = p->mon; |
|||
|
|||
Window w = p->win; |
|||
p->win = c->win; |
|||
c->win = w; |
|||
|
|||
XChangeProperty(dpy, c->win, netatom[NetClientList], XA_WINDOW, 32, PropModeReplace, |
|||
(unsigned char *) &(p->win), 1); |
|||
|
|||
updatetitle(p); |
|||
s = scanner ? c : p; |
|||
setfloatinghint(s); |
|||
|
|||
wc.border_width = p->bw; |
|||
XConfigureWindow(dpy, p->win, CWBorderWidth, &wc); |
|||
XMoveResizeWindow(dpy, p->win, s->x, s->y, s->w, s->h); |
|||
XSetWindowBorder(dpy, p->win, scheme[SchemeNorm][ColBorder].pixel); |
|||
|
|||
arrange(p->mon); |
|||
configure(p); |
|||
updateclientlist(); |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
void |
|||
unswallow(Client *c) |
|||
{ |
|||
XWindowChanges wc; |
|||
c->win = c->swallowing->win; |
|||
|
|||
free(c->swallowing); |
|||
c->swallowing = NULL; |
|||
|
|||
XDeleteProperty(dpy, c->win, netatom[NetClientList]); |
|||
|
|||
/* unfullscreen the client */ |
|||
setfullscreen(c, 0); |
|||
updatetitle(c); |
|||
arrange(c->mon); |
|||
XMapWindow(dpy, c->win); |
|||
|
|||
wc.border_width = c->bw; |
|||
XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); |
|||
XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); |
|||
XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel); |
|||
|
|||
setfloatinghint(c); |
|||
setclientstate(c, NormalState); |
|||
focus(NULL); |
|||
arrange(c->mon); |
|||
} |
|||
|
|||
pid_t |
|||
winpid(Window w) |
|||
{ |
|||
pid_t result = 0; |
|||
|
|||
#ifdef __linux__ |
|||
xcb_res_client_id_spec_t spec = {0}; |
|||
spec.client = w; |
|||
spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID; |
|||
|
|||
xcb_generic_error_t *e = NULL; |
|||
xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec); |
|||
xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e); |
|||
|
|||
if (!r) |
|||
return (pid_t)0; |
|||
|
|||
xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r); |
|||
for (; i.rem; xcb_res_client_id_value_next(&i)) { |
|||
spec = i.data->spec; |
|||
if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) { |
|||
uint32_t *t = xcb_res_client_id_value_value(i.data); |
|||
result = *t; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
free(r); |
|||
|
|||
if (result == (pid_t)-1) |
|||
result = 0; |
|||
|
|||
#endif /* __linux__ */ |
|||
#ifdef __OpenBSD__ |
|||
Atom type; |
|||
int format; |
|||
unsigned long len, bytes; |
|||
unsigned char *prop; |
|||
pid_t ret; |
|||
|
|||
if (XGetWindowProperty(dpy, w, XInternAtom(dpy, "_NET_WM_PID", 1), 0, 1, False, AnyPropertyType, &type, &format, &len, &bytes, &prop) != Success || !prop) |
|||
return 0; |
|||
|
|||
ret = *(pid_t*)prop; |
|||
XFree(prop); |
|||
result = ret; |
|||
#endif /* __OpenBSD__ */ |
|||
|
|||
return result; |
|||
} |
|||
|
|||
pid_t |
|||
getparentprocess(pid_t p) |
|||
{ |
|||
unsigned int v = 0; |
|||
|
|||
#ifdef __linux__ |
|||
FILE *f; |
|||
char buf[256]; |
|||
snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p); |
|||
|
|||
if (!(f = fopen(buf, "r"))) |
|||
return (pid_t)0; |
|||
|
|||
if (fscanf(f, "%*u %*s %*c %u", (unsigned *)&v) != 1) |
|||
v = (pid_t)0; |
|||
fclose(f); |
|||
#endif /* __linux__ */ |
|||
#ifdef __OpenBSD__ |
|||
int n; |
|||
kvm_t *kd; |
|||
struct kinfo_proc *kp; |
|||
|
|||
kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL); |
|||
if (!kd) |
|||
return 0; |
|||
|
|||
kp = kvm_getprocs(kd, KERN_PROC_PID, p, sizeof(*kp), &n); |
|||
v = kp->p_ppid; |
|||
#endif /* __OpenBSD__ */ |
|||
return (pid_t)v; |
|||
} |
|||
|
|||
int |
|||
isdescprocess(pid_t p, pid_t c) |
|||
{ |
|||
while (p != c && c != 0) |
|||
c = getparentprocess(c); |
|||
|
|||
return (int)c; |
|||
} |
|||
|
|||
Client * |
|||
termforwin(const Client *w) |
|||
{ |
|||
Client *c; |
|||
Monitor *m; |
|||
|
|||
if (!w->pid || w->isterminal) |
|||
return NULL; |
|||
|
|||
c = selmon->sel; |
|||
if (c && c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid)) |
|||
return c; |
|||
|
|||
for (m = mons; m; m = m->next) { |
|||
for (c = m->clients; c; c = c->next) { |
|||
if (c->isterminal && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid)) |
|||
return c; |
|||
} |
|||
} |
|||
|
|||
return NULL; |
|||
} |
|||
|
|||
Client * |
|||
swallowingclient(Window w) |
|||
{ |
|||
Client *c; |
|||
Monitor *m; |
|||
|
|||
for (m = mons; m; m = m->next) { |
|||
for (c = m->clients; c; c = c->next) { |
|||
if (c->swallowing && c->swallowing->win == w) |
|||
return c; |
|||
} |
|||
} |
|||
|
|||
return NULL; |
|||
} |
|||
|
@ -0,0 +1,8 @@ |
|||
static pid_t getparentprocess(pid_t p); |
|||
static int isdescprocess(pid_t p, pid_t c); |
|||
static int swallow(Client *p, Client *c); |
|||
static Client *swallowingclient(Window w); |
|||
static Client *termforwin(const Client *c); |
|||
static void unswallow(Client *c); |
|||
static pid_t winpid(Window w); |
|||
|
@ -0,0 +1,44 @@ |
|||
void |
|||
tagallmon(const Arg *arg) |
|||
{ |
|||
Monitor *m; |
|||
Client *c, *last, *slast, *next; |
|||
|
|||
if (!mons->next) |
|||
return; |
|||
|
|||
m = dirtomon(arg->i); |
|||
for (last = m->clients; last && last->next; last = last->next); |
|||
for (slast = m->stack; slast && slast->snext; slast = slast->snext); |
|||
|
|||
for (c = selmon->clients; c; c = next) { |
|||
next = c->next; |
|||
if (!ISVISIBLE(c)) |
|||
continue; |
|||
unfocus(c, 1, NULL); |
|||
detach(c); |
|||
detachstack(c); |
|||
c->mon = m; |
|||
c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ |
|||
c->next = NULL; |
|||
c->snext = NULL; |
|||
if (last) |
|||
last = last->next = c; |
|||
else |
|||
m->clients = last = c; |
|||
if (slast) |
|||
slast = slast->snext = c; |
|||
else |
|||
m->stack = slast = c; |
|||
if (c->isfullscreen) { |
|||
if (c->fakefullscreen != 1) { |
|||
resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); |
|||
XRaiseWindow(dpy, c->win); |
|||
} |
|||
} |
|||
} |
|||
|
|||
focus(NULL); |
|||
arrange(NULL); |
|||
} |
|||
|
@ -0,0 +1,2 @@ |
|||
static void tagallmon(const Arg *arg); |
|||
|
@ -0,0 +1,65 @@ |
|||
void |
|||
tagswapmon(const Arg *arg) |
|||
{ |
|||
Monitor *m; |
|||
Client *c, *sc = NULL, *mc = NULL, *next; |
|||
|
|||
if (!mons->next) |
|||
return; |
|||
|
|||
m = dirtomon(arg->i); |
|||
|
|||
for (c = selmon->clients; c; c = next) { |
|||
next = c->next; |
|||
if (!ISVISIBLE(c)) |
|||
continue; |
|||
unfocus(c, 1, NULL); |
|||
detach(c); |
|||
detachstack(c); |
|||
c->next = sc; |
|||
sc = c; |
|||
} |
|||
|
|||
for (c = m->clients; c; c = next) { |
|||
next = c->next; |
|||
if (!ISVISIBLE(c)) |
|||
continue; |
|||
unfocus(c, 1, NULL); |
|||
detach(c); |
|||
detachstack(c); |
|||
c->next = mc; |
|||
mc = c; |
|||
} |
|||
|
|||
for (c = sc; c; c = next) { |
|||
next = c->next; |
|||
c->mon = m; |
|||
c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ |
|||
attach(c); |
|||
attachstack(c); |
|||
if (c->isfullscreen) { |
|||
if (c->fakefullscreen != 1) { |
|||
resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); |
|||
XRaiseWindow(dpy, c->win); |
|||
} |
|||
} |
|||
} |
|||
|
|||
for (c = mc; c; c = next) { |
|||
next = c->next; |
|||
c->mon = selmon; |
|||
c->tags = selmon->tagset[selmon->seltags]; /* assign tags of target monitor */ |
|||
attach(c); |
|||
attachstack(c); |
|||
if (c->isfullscreen) { |
|||
if (c->fakefullscreen != 1) { |
|||
resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); |
|||
XRaiseWindow(dpy, c->win); |
|||
} |
|||
} |
|||
} |
|||
|
|||
focus(NULL); |
|||
arrange(NULL); |
|||
} |
|||
|
@ -0,0 +1,2 @@ |
|||
static void tagswapmon(const Arg *arg); |
|||
|
@ -0,0 +1,34 @@ |
|||
void |
|||
transfer(const Arg *arg) |
|||
{ |
|||
Client *c, *mtail = selmon->clients, *stail = NULL, *insertafter; |
|||
int transfertostack = 0, i, nmasterclients; |
|||
|
|||
for (i = 0, c = selmon->clients; c; c = c->next) { |
|||
if (!ISVISIBLE(c) || c->isfloating) continue; |
|||
if (selmon->sel == c) { transfertostack = i < selmon->nmaster && selmon->nmaster != 0; } |
|||
if (i < selmon->nmaster) { nmasterclients++; mtail = c; } |
|||
stail = c; |
|||
i++; |
|||
} |
|||
if (!selmon->sel || selmon->sel->isfloating || i == 0) { |
|||
return; |
|||
} else if (transfertostack) { |
|||
selmon->nmaster = MIN(i, selmon->nmaster) - 1; |
|||
insertafter = stail; |
|||
} else { |
|||
selmon->nmaster = selmon->nmaster + 1; |
|||
insertafter = mtail; |
|||
} |
|||
if (insertafter != selmon->sel) { |
|||
detach(selmon->sel); |
|||
if (selmon->nmaster == 1 && !transfertostack) { |
|||
attach(selmon->sel); // Head prepend case
|
|||
} else { |
|||
selmon->sel->next = insertafter->next; |
|||
insertafter->next = selmon->sel; |
|||
} |
|||
} |
|||
arrange(selmon); |
|||
} |
|||
|
@ -0,0 +1,2 @@ |
|||
static void transfer(const Arg *arg); |
|||
|
@ -0,0 +1,130 @@ |
|||
/* Settings */ |
|||
static int enablegaps = 1; |
|||
|
|||
static 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); |
|||
} |
|||
|
|||
|
|||
static void |
|||
togglegaps(const Arg *arg) |
|||
{ |
|||
enablegaps = !enablegaps; |
|||
arrange(NULL); |
|||
} |
|||
|
|||
static void |
|||
defaultgaps(const Arg *arg) |
|||
{ |
|||
setgaps(gappoh, gappov, gappih, gappiv); |
|||
} |
|||
|
|||
static void |
|||
incrgaps(const Arg *arg) |
|||
{ |
|||
setgaps( |
|||
selmon->gappoh + arg->i, |
|||
selmon->gappov + arg->i, |
|||
selmon->gappih + arg->i, |
|||
selmon->gappiv + arg->i |
|||
); |
|||
} |
|||
|
|||
static void |
|||
incrigaps(const Arg *arg) |
|||
{ |
|||
setgaps( |
|||
selmon->gappoh, |
|||
selmon->gappov, |
|||
selmon->gappih + arg->i, |
|||
selmon->gappiv + arg->i |
|||
); |
|||
} |
|||
|
|||
static void |
|||
incrogaps(const Arg *arg) |
|||
{ |
|||
setgaps( |
|||
selmon->gappoh + arg->i, |
|||
selmon->gappov + arg->i, |
|||
selmon->gappih, |
|||
selmon->gappiv |
|||
); |
|||
} |
|||
|
|||
static void |
|||
incrohgaps(const Arg *arg) |
|||
{ |
|||
setgaps( |
|||
selmon->gappoh + arg->i, |
|||
selmon->gappov, |
|||
selmon->gappih, |
|||
selmon->gappiv |
|||
); |
|||
} |
|||
|
|||
static void |
|||
incrovgaps(const Arg *arg) |
|||
{ |
|||
setgaps( |
|||
selmon->gappoh, |
|||
selmon->gappov + arg->i, |
|||
selmon->gappih, |
|||
selmon->gappiv |
|||
); |
|||
} |
|||
|
|||
static void |
|||
incrihgaps(const Arg *arg) |
|||
{ |
|||
setgaps( |
|||
selmon->gappoh, |
|||
selmon->gappov, |
|||
selmon->gappih + arg->i, |
|||
selmon->gappiv |
|||
); |
|||
} |
|||
|
|||
static void |
|||
incrivgaps(const Arg *arg) |
|||
{ |
|||
setgaps( |
|||
selmon->gappoh, |
|||
selmon->gappov, |
|||
selmon->gappih, |
|||
selmon->gappiv + arg->i |
|||
); |
|||
} |
|||
|
|||
static void |
|||
getgaps(Monitor *m, int *oh, int *ov, int *ih, int *iv, unsigned int *nc) |
|||
{ |
|||
unsigned int n, oe, ie; |
|||
oe = ie = enablegaps; |
|||
Client *c; |
|||
|
|||
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); |
|||
if (n == 1) { |
|||
oe *= smartgaps_fact; // outer gaps disabled or multiplied when only one client
|
|||
} |
|||
|
|||
*oh = m->gappoh*oe; // outer horizontal gap
|
|||
*ov = m->gappov*oe; // outer vertical gap
|
|||
*ih = m->gappih*ie; // inner horizontal gap
|
|||
*iv = m->gappiv*ie; // inner vertical gap
|
|||
*nc = n; // number of clients
|
|||
} |
|||
|
@ -0,0 +1,15 @@ |
|||
/* Key binding functions */ |
|||
static void defaultgaps(const Arg *arg); |
|||
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); |
|||
|
|||
/* Internals */ |
|||
static void getgaps(Monitor *m, int *oh, int *ov, int *ih, int *iv, unsigned int *nc); |
|||
static void setgaps(int oh, int ov, int ih, int iv); |
|||
|
@ -0,0 +1,43 @@ |
|||
/* cc transient.c -o transient -lX11 */ |
|||
|
|||
#include <stdlib.h> |
|||
#include <unistd.h> |
|||
#include <X11/Xlib.h> |
|||
#include <X11/Xutil.h> |
|||
|
|||
int main(void) { |
|||
Display *d; |
|||
Window r, f, t = None; |
|||
XSizeHints h; |
|||
XEvent e; |
|||
|
|||
d = XOpenDisplay(NULL); |
|||
if (!d) |
|||
exit(1); |
|||
r = DefaultRootWindow(d); |
|||
|
|||
f = XCreateSimpleWindow(d, r, 100, 100, 400, 400, 0, 0, 0); |
|||
h.min_width = h.max_width = h.min_height = h.max_height = 400; |
|||
h.flags = PMinSize | PMaxSize; |
|||
XSetWMNormalHints(d, f, &h); |
|||
XStoreName(d, f, "floating"); |
|||
XMapWindow(d, f); |
|||
|
|||
XSelectInput(d, f, ExposureMask); |
|||
while (1) { |
|||
XNextEvent(d, &e); |
|||
|
|||
if (t == None) { |
|||
sleep(5); |
|||
t = XCreateSimpleWindow(d, r, 50, 50, 100, 100, 0, 0, 0); |
|||
XSetTransientForHint(d, t, f); |
|||
XStoreName(d, t, "transient"); |
|||
XMapWindow(d, t); |
|||
XSelectInput(d, t, ExposureMask); |
|||
} |
|||
} |
|||
|
|||
XCloseDisplay(d); |
|||
exit(0); |
|||
} |
|||
|
@ -0,0 +1,36 @@ |
|||
/* See LICENSE file for copyright and license details. */ |
|||
#include <stdarg.h> |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
|
|||
#include "util.h" |
|||
|
|||
void * |
|||
ecalloc(size_t nmemb, size_t size) |
|||
{ |
|||
void *p; |
|||
|
|||
if (!(p = calloc(nmemb, size))) |
|||
die("calloc:"); |
|||
return p; |
|||
} |
|||
|
|||
void |
|||
die(const char *fmt, ...) { |
|||
va_list ap; |
|||
|
|||
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); |
|||
} |
|||
|
|||
exit(1); |
|||
} |
|||
|
@ -0,0 +1,19 @@ |
|||
/* See LICENSE file for copyright and license details. */ |
|||
|
|||
#ifndef MAX |
|||
#define MAX(A, B) ((A) > (B) ? (A) : (B)) |
|||
#endif |
|||
#ifndef MIN |
|||
#define MIN(A, B) ((A) < (B) ? (A) : (B)) |
|||
#endif |
|||
#define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B)) |
|||
|
|||
#ifdef _DEBUG |
|||
#define DEBUG(...) fprintf(stderr, __VA_ARGS__) |
|||
#else |
|||
#define DEBUG(...) |
|||
#endif |
|||
|
|||
void die(const char *fmt, ...); |
|||
void *ecalloc(size_t nmemb, size_t size); |
|||
|
Binary file not shown.
Loading…
Reference in new issue