wiebel
9 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