remove flexipatch stuff
This commit is contained in:
parent
1da188203b
commit
c56caa61e1
|
@ -1,63 +0,0 @@
|
|||
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
|
||||
name: Build/Publish XBPS
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "config**"
|
||||
|
||||
jobs:
|
||||
build-and-publish:
|
||||
runs-on: docker
|
||||
container: git.snaile.de/snailed/xbps-builder:2024.0502.1733@sha256:0ca263f8a97fbd29f88349e731153f60569d19ddd7320f2c7c80047a35260c9b
|
||||
env:
|
||||
LICENSE: "GPL-2.0"
|
||||
SHORT_DESCRIPTION: "Customized DWM"
|
||||
DEPENDENCIES: "pango>=1.44,glibc>=2.32,libX11>=1.2,libXft>=2.3.8,libXinerama>=1.0.3,fontconfig>=2.6.0"
|
||||
MAINTAINER: "Luca Bilke <luca@bil.ke>"
|
||||
NAME: "dwm-custom"
|
||||
ARCH: "x86_64"
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: https://code.forgejo.org/actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Generate tag and package name
|
||||
run: |
|
||||
set -xeu
|
||||
MAJOR=$(date +%Y)
|
||||
MINOR=$(date +%m%d)
|
||||
PATCH=$(date +%H%M)
|
||||
echo "PACKAGE_NAME=${{ env.NAME }}-${MAJOR}.${MINOR}.${PATCH}_1" >> $GITHUB_ENV
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
set -xeu
|
||||
make clean install DESTDIR="${GITHUB_WORKSPACE}/pkg" PREFIX="/usr"
|
||||
|
||||
- name: Create package
|
||||
run: |
|
||||
set -xeu
|
||||
export XBPS_TARGET_ARCH=${{ env.ARCH }}
|
||||
mkdir /target
|
||||
cd /target || exit 1
|
||||
xbps-create -A ${{ env.ARCH }} \
|
||||
-H "${{ github.server_url }}/${{ github.repository }}" \
|
||||
-l "${{ env.LICENSE }}" \
|
||||
-n "${{ env.PACKAGE_NAME }}" \
|
||||
-m "${{ env.MAINTAINER }}" \
|
||||
-s "${{ env.SHORT_DESCRIPTION }}" \
|
||||
-D "${{ env.DEPENDENCIES }}" \
|
||||
"${GITHUB_WORKSPACE}/pkg"
|
||||
|
||||
- name: Push Package
|
||||
run: |
|
||||
set -xeu
|
||||
curl -so "/target/${{ env.ARCH }}-repodata" "https://xbps.snaile.de/${{ env.ARCH }}-repodata"
|
||||
xbps-rindex --add "/target/${{ env.PACKAGE_NAME }}.${{ env.ARCH }}.xbps"
|
||||
echo '${{ secrets.XBPS_SIGNING_KEY }}' >/tmp/privkey.pem
|
||||
XBPS_PASSPHRASE=${{ secrets.XBPS_SIGNING_PASSPHRASE }} xbps-rindex --privkey /tmp/privkey.pem --sign-pkg --signedby "${{ env.MAINTAINER }}" "/target/${{ env.PACKAGE_NAME }}.${{ env.ARCH }}.xbps"
|
||||
rm /tmp/privkey.pem
|
||||
ls -lAH /target
|
||||
find /target -type f -exec sh -c 'curl -X PUT --digest -u "${{ vars.XBPS_WEBDAV_USER }}:${{ secrets.XBPS_WEBDAV_KEY }}" -T "${1}" "https://xbps.snaile.de/$(basename $1)"' find-shell {} \;
|
|
@ -1,23 +0,0 @@
|
|||
dwm-final
|
||||
dwm-dev-1.0.0_1.x86_64.xbps
|
||||
pkg/usr
|
||||
patch
|
||||
LICENSE
|
||||
README
|
||||
config.def.h
|
||||
config.h
|
||||
config.mk
|
||||
drw.c
|
||||
drw.h
|
||||
dwm.1
|
||||
dwm.c
|
||||
dwm.c.orig
|
||||
dwm.desktop
|
||||
dwm.png
|
||||
transient.c
|
||||
util.c
|
||||
util.h
|
||||
util.o
|
||||
drw.o
|
||||
dwm.o
|
||||
dwm
|
|
@ -1,6 +0,0 @@
|
|||
[submodule "dwm-flexipatch"]
|
||||
path = dwm-flexipatch
|
||||
url = https://github.com/bakkeby/dwm-flexipatch
|
||||
[submodule "flexipatch-finalizer"]
|
||||
path = flexipatch-finalizer
|
||||
url = https://github.com/bakkeby/flexipatch-finalizer
|
|
@ -0,0 +1,38 @@
|
|||
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>
|
||||
© 2020-2022 Chris Down <chris@chrisdown.name>
|
||||
|
||||
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.
|
49
Makefile
49
Makefile
|
@ -1,50 +1,57 @@
|
|||
# dwm - dynamic window manager
|
||||
# See LICENSE file for copyright and license details.
|
||||
.PHONY: all submodule clean dist install uninstall
|
||||
|
||||
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: dwm dwm-msg
|
||||
else
|
||||
all: dwm
|
||||
endif
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $<
|
||||
|
||||
config.mk:
|
||||
cp config/config.mk config.mk
|
||||
${OBJ}: config.h config.mk
|
||||
|
||||
config.h:
|
||||
cp config/config.h config.h
|
||||
|
||||
${SRC}: buildroot
|
||||
|
||||
${OBJ}: config.h config.mk
|
||||
cp config.def.h $@
|
||||
|
||||
dwm: ${OBJ}
|
||||
${CC} -o $@ ${OBJ} ${LDFLAGS}
|
||||
|
||||
submodule:
|
||||
git submodule update --init
|
||||
ifdef YAJLLIBS
|
||||
dwm-msg:
|
||||
${CC} -o $@ patch/ipc/dwm-msg.c ${LDFLAGS}
|
||||
endif
|
||||
|
||||
clean:
|
||||
find . -maxdepth 1 -type f | grep -Pv "^\./\.|Makefile$$" | xargs -r rm
|
||||
rm -r tmp patch 2>/dev/null || true
|
||||
git -C dwm-flexipatch reset --hard HEAD
|
||||
git -C dwm-flexipatch clean -ffdx
|
||||
rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz
|
||||
rm -f dwm-msg
|
||||
|
||||
buildroot: submodule
|
||||
cp config/patches.h dwm-flexipatch/patches.h
|
||||
flexipatch-finalizer/flexipatch-finalizer.sh -r -d dwm-flexipatch -o tmp
|
||||
rm -r tmp/Makefile tmp/config.mk patch 2>/dev/null || true
|
||||
mv tmp/* ./
|
||||
for patch in config/patches/*.diff; do patch <"$$patch"; done
|
||||
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
|
||||
|
@ -56,3 +63,5 @@ uninstall:
|
|||
rm -f ${DESTDIR}${PREFIX}/bin/dwm\
|
||||
${DESTDIR}${MANPREFIX}/man1/dwm.1\
|
||||
${DESTDIR}${PREFIX}/share/xsessions/dwm.desktop
|
||||
|
||||
.PHONY: all 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,341 @@
|
|||
/* 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 showbar = 1; /* 0 means no bar */
|
||||
static const int topbar = 1; /* 0 means bottom bar */
|
||||
static const int focusonwheel = 0;
|
||||
static int floatposgrid_x = 5; /* float grid columns */
|
||||
static int floatposgrid_y = 5; /* float grid rows */
|
||||
/* Status is to be shown on: -1 (all monitors), 0 (a specific monitor by index), 'A' (active monitor) */
|
||||
static const int statusmon = 'A';
|
||||
|
||||
/* 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 const char font[] = "monospace 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 char scratchselfgcolor[] = "#FFF7D4";
|
||||
static char scratchselbgcolor[] = "#77547E";
|
||||
static char scratchselbordercolor[] = "#894B9F";
|
||||
static char scratchselfloatcolor[] = "#894B9F";
|
||||
|
||||
static char scratchnormfgcolor[] = "#FFF7D4";
|
||||
static char scratchnormbgcolor[] = "#664C67";
|
||||
static char scratchnormbordercolor[] = "#77547E";
|
||||
static char scratchnormfloatcolor[] = "#77547E";
|
||||
|
||||
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 },
|
||||
[SchemeScratchSel] = { scratchselfgcolor, scratchselbgcolor, scratchselbordercolor, scratchselfloatcolor },
|
||||
[SchemeScratchNorm] = { scratchnormfgcolor, scratchnormbgcolor, scratchnormbordercolor, scratchnormfloatcolor },
|
||||
};
|
||||
|
||||
static const char *const autostart[] = {
|
||||
"st", NULL,
|
||||
NULL /* terminate */
|
||||
};
|
||||
|
||||
static const char *scratchpadcmd[] = {"s", "st", "-n", "spterm", NULL};
|
||||
|
||||
/* 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)
|
||||
RULE(.instance = "spterm", .scratchkey = 's', .isfloating = 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 hoverfunc name */
|
||||
{ -1, 0, BAR_ALIGN_LEFT, width_tags, draw_tags, click_tags, hover_tags, "tags" },
|
||||
{ -1, 0, BAR_ALIGN_LEFT, width_ltsymbol, draw_ltsymbol, click_ltsymbol, NULL, "layout" },
|
||||
{ statusmon, 0, BAR_ALIGN_RIGHT, width_status, draw_status, click_statuscmd, NULL, "status" },
|
||||
{ -1, 0, BAR_ALIGN_NONE, width_wintitle, draw_wintitle, click_wintitle, NULL, "wintitle" },
|
||||
};
|
||||
|
||||
/* 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 lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
|
||||
|
||||
static const Layout layouts[] = {
|
||||
/* symbol arrange function */
|
||||
{ "[]=", tile }, /* first entry is default */
|
||||
{ "><>", NULL }, /* no layout function means floating behavior */
|
||||
{ "[M]", monocle },
|
||||
{ "TTT", bstack },
|
||||
{ "|M|", centeredmaster },
|
||||
{ "[D]", deck },
|
||||
{ ":::", gaplessgrid },
|
||||
};
|
||||
|
||||
/* 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} },
|
||||
|
||||
#define STACKKEYS(MOD,ACTION) \
|
||||
{ MOD, XK_j, ACTION##stack, {.i = INC(+1) } }, \
|
||||
{ MOD, XK_k, ACTION##stack, {.i = INC(-1) } }, \
|
||||
{ MOD, XK_s, ACTION##stack, {.i = PREVSEL } }, \
|
||||
{ MOD, XK_w, ACTION##stack, {.i = 0 } }, \
|
||||
{ MOD, XK_e, ACTION##stack, {.i = 1 } }, \
|
||||
{ MOD, XK_a, ACTION##stack, {.i = 2 } }, \
|
||||
{ MOD, XK_z, ACTION##stack, {.i = -1 } },
|
||||
|
||||
/* 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 const char *dmenucmd[] = {
|
||||
"dmenu_run",
|
||||
"-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 const Key keys[] = {
|
||||
/* modifier key function argument */
|
||||
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
|
||||
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
|
||||
{ MODKEY, XK_b, togglebar, {0} },
|
||||
STACKKEYS(MODKEY, focus)
|
||||
STACKKEYS(MODKEY|ShiftMask, push)
|
||||
{ MODKEY, XK_Left, focusdir, {.i = 0 } }, // left
|
||||
{ MODKEY, XK_Right, focusdir, {.i = 1 } }, // right
|
||||
{ MODKEY, XK_Up, focusdir, {.i = 2 } }, // up
|
||||
{ MODKEY, XK_Down, focusdir, {.i = 3 } }, // down
|
||||
{ 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_Return, zoom, {0} },
|
||||
{ MODKEY, XK_Tab, view, {0} },
|
||||
{ MODKEY|ShiftMask, XK_c, killclient, {0} },
|
||||
{ MODKEY|ShiftMask, XK_q, quit, {0} },
|
||||
{ MODKEY|ControlMask|ShiftMask, XK_q, quit, {1} },
|
||||
{ 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, XK_grave, togglescratch, {.v = scratchpadcmd } },
|
||||
{ MODKEY|ControlMask, XK_grave, setscratch, {.v = scratchpadcmd } },
|
||||
{ MODKEY|ShiftMask, XK_grave, removescratch, {.v = scratchpadcmd } },
|
||||
{ MODKEY|Mod4Mask, XK_space, unfloatvisible, {0} },
|
||||
{ MODKEY|ShiftMask, XK_t, unfloatvisible, {.v = &layouts[0]} },
|
||||
{ MODKEY, XK_y, togglefullscreen, {0} },
|
||||
{ MODKEY, XK_0, view, {.ui = ~0 } },
|
||||
{ MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
|
||||
{ MODKEY, XK_comma, focusmon, {.i = -1 } },
|
||||
{ MODKEY, XK_period, focusmon, {.i = +1 } },
|
||||
{ MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
|
||||
{ MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
|
||||
/* Note that due to key limitations the below example kybindings are defined with a Mod3Mask,
|
||||
* which is not always readily available. Refer to the patch wiki for more details. */
|
||||
/* Client position is limited to monitor window area */
|
||||
{ Mod3Mask, XK_u, floatpos, {.v = "-26x -26y" } }, // ↖
|
||||
{ Mod3Mask, XK_i, floatpos, {.v = " 0x -26y" } }, // ↑
|
||||
{ Mod3Mask, XK_o, floatpos, {.v = " 26x -26y" } }, // ↗
|
||||
{ Mod3Mask, XK_j, floatpos, {.v = "-26x 0y" } }, // ←
|
||||
{ Mod3Mask, XK_l, floatpos, {.v = " 26x 0y" } }, // →
|
||||
{ Mod3Mask, XK_m, floatpos, {.v = "-26x 26y" } }, // ↙
|
||||
{ Mod3Mask, XK_comma, floatpos, {.v = " 0x 26y" } }, // ↓
|
||||
{ Mod3Mask, XK_period, floatpos, {.v = " 26x 26y" } }, // ↘
|
||||
/* Absolute positioning (allows moving windows between monitors) */
|
||||
{ Mod3Mask|ControlMask, XK_u, floatpos, {.v = "-26a -26a" } }, // ↖
|
||||
{ Mod3Mask|ControlMask, XK_i, floatpos, {.v = " 0a -26a" } }, // ↑
|
||||
{ Mod3Mask|ControlMask, XK_o, floatpos, {.v = " 26a -26a" } }, // ↗
|
||||
{ Mod3Mask|ControlMask, XK_j, floatpos, {.v = "-26a 0a" } }, // ←
|
||||
{ Mod3Mask|ControlMask, XK_l, floatpos, {.v = " 26a 0a" } }, // →
|
||||
{ Mod3Mask|ControlMask, XK_m, floatpos, {.v = "-26a 26a" } }, // ↙
|
||||
{ Mod3Mask|ControlMask, XK_comma, floatpos, {.v = " 0a 26a" } }, // ↓
|
||||
{ Mod3Mask|ControlMask, XK_period, floatpos, {.v = " 26a 26a" } }, // ↘
|
||||
/* Resize client, client center position is fixed which means that client expands in all directions */
|
||||
{ Mod3Mask|ShiftMask, XK_u, floatpos, {.v = "-26w -26h" } }, // ↖
|
||||
{ Mod3Mask|ShiftMask, XK_i, floatpos, {.v = " 0w -26h" } }, // ↑
|
||||
{ Mod3Mask|ShiftMask, XK_o, floatpos, {.v = " 26w -26h" } }, // ↗
|
||||
{ Mod3Mask|ShiftMask, XK_j, floatpos, {.v = "-26w 0h" } }, // ←
|
||||
{ Mod3Mask|ShiftMask, XK_k, floatpos, {.v = "800W 800H" } }, // ·
|
||||
{ Mod3Mask|ShiftMask, XK_l, floatpos, {.v = " 26w 0h" } }, // →
|
||||
{ Mod3Mask|ShiftMask, XK_m, floatpos, {.v = "-26w 26h" } }, // ↙
|
||||
{ Mod3Mask|ShiftMask, XK_comma, floatpos, {.v = " 0w 26h" } }, // ↓
|
||||
{ Mod3Mask|ShiftMask, XK_period, floatpos, {.v = " 26w 26h" } }, // ↘
|
||||
/* Client is positioned in a floating grid, movement is relative to client's current position */
|
||||
{ Mod3Mask|Mod1Mask, XK_u, floatpos, {.v = "-1p -1p" } }, // ↖
|
||||
{ Mod3Mask|Mod1Mask, XK_i, floatpos, {.v = " 0p -1p" } }, // ↑
|
||||
{ Mod3Mask|Mod1Mask, XK_o, floatpos, {.v = " 1p -1p" } }, // ↗
|
||||
{ Mod3Mask|Mod1Mask, XK_j, floatpos, {.v = "-1p 0p" } }, // ←
|
||||
{ Mod3Mask|Mod1Mask, XK_k, floatpos, {.v = " 0p 0p" } }, // ·
|
||||
{ Mod3Mask|Mod1Mask, XK_l, floatpos, {.v = " 1p 0p" } }, // →
|
||||
{ Mod3Mask|Mod1Mask, XK_m, floatpos, {.v = "-1p 1p" } }, // ↙
|
||||
{ Mod3Mask|Mod1Mask, XK_comma, floatpos, {.v = " 0p 1p" } }, // ↓
|
||||
{ Mod3Mask|Mod1Mask, XK_period, floatpos, {.v = " 1p 1p" } }, // ↘
|
||||
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 const Button buttons[] = {
|
||||
/* click event mask button function argument */
|
||||
{ ClkLtSymbol, 0, Button1, setlayout, {0} },
|
||||
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
|
||||
{ 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} },
|
||||
};
|
||||
|
1499
config/patches.h
1499
config/patches.h
File diff suppressed because it is too large
Load Diff
|
@ -1,11 +0,0 @@
|
|||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -693,7 +693,7 @@ cleanup(void)
|
||||
/* kill child processes */
|
||||
for (i = 0; i < autostart_len; i++) {
|
||||
if (0 < autostart_pids[i]) {
|
||||
- kill(autostart_pids[i], SIGTERM);
|
||||
+ kill(autostart_pids[i], autostart_kill_signal);
|
||||
waitpid(autostart_pids[i], NULL, 0);
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -393,8 +393,8 @@ static void zoom(const Arg *arg);
|
||||
|
||||
/* variables */
|
||||
static const char broken[] = "broken";
|
||||
-static char stext[1024];
|
||||
-static char rawstext[512];
|
||||
+static char stext[2048];
|
||||
+static char rawstext[1024];
|
||||
|
||||
static int screen;
|
||||
static int sw, sh; /* X display screen geometry width, height */
|
|
@ -1,13 +0,0 @@
|
|||
--- a/dwm.c
|
||||
+++ b/dwm.c
|
||||
@@ -2179,6 +2179,10 @@ tagmon(const Arg *arg)
|
||||
c->isfullscreen = 1;
|
||||
resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
|
||||
XRaiseWindow(dpy, c->win);
|
||||
+ } else if (c->isfloating && c->scratchkey != 0) {
|
||||
+ sendmon(c, dest);
|
||||
+ applyrules(c);
|
||||
+ XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
|
||||
} else
|
||||
sendmon(c, dest);
|
||||
}
|
|
@ -0,0 +1,297 @@
|
|||
/* 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"
|
||||
|
||||
Drw *
|
||||
drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
|
||||
{
|
||||
Drw *drw = ecalloc(1, sizeof(Drw));
|
||||
|
||||
drw->dpy = dpy;
|
||||
drw->screen = screen;
|
||||
drw->root = root;
|
||||
drw->w = w;
|
||||
drw->h = h;
|
||||
|
||||
drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
|
||||
drw->gc = XCreateGC(dpy, root, 0, NULL);
|
||||
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, DefaultDepth(drw->dpy, drw->screen));
|
||||
}
|
||||
|
||||
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_font_create instead.
|
||||
*/
|
||||
static Fnt *
|
||||
xfont_create(Drw *drw, const char *fontname)
|
||||
{
|
||||
Fnt *font;
|
||||
PangoFontMap *fontmap;
|
||||
PangoContext *context;
|
||||
PangoFontDescription *desc;
|
||||
PangoFontMetrics *metrics;
|
||||
|
||||
if (!fontname) {
|
||||
die("no font specified.");
|
||||
}
|
||||
|
||||
font = ecalloc(1, sizeof(Fnt));
|
||||
font->dpy = drw->dpy;
|
||||
|
||||
fontmap = pango_xft_get_font_map(drw->dpy, drw->screen);
|
||||
context = pango_font_map_create_context(fontmap);
|
||||
desc = pango_font_description_from_string(fontname);
|
||||
font->layout = pango_layout_new(context);
|
||||
pango_layout_set_font_description(font->layout, desc);
|
||||
|
||||
metrics = pango_context_get_metrics(context, desc, pango_language_from_string ("en-us"));
|
||||
font->h = pango_font_metrics_get_height(metrics) / PANGO_SCALE;
|
||||
|
||||
pango_font_metrics_unref(metrics);
|
||||
g_object_unref(context);
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
static void
|
||||
xfont_free(Fnt *font)
|
||||
{
|
||||
if (!font)
|
||||
return;
|
||||
if (font->layout)
|
||||
g_object_unref(font->layout);
|
||||
free(font);
|
||||
}
|
||||
|
||||
Fnt*
|
||||
drw_font_create(Drw* drw, const char font[])
|
||||
{
|
||||
Fnt *fnt = NULL;
|
||||
|
||||
if (!drw || !font)
|
||||
return NULL;
|
||||
|
||||
fnt = xfont_create(drw, font);
|
||||
|
||||
return (drw->fonts = fnt);
|
||||
}
|
||||
|
||||
void
|
||||
drw_fontset_free(Fnt *font)
|
||||
{
|
||||
if (font) {
|
||||
xfont_free(font);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
drw_clr_create(
|
||||
Drw *drw,
|
||||
Clr *dest,
|
||||
const char *clrname
|
||||
) {
|
||||
if (!drw || !dest || !clrname)
|
||||
return;
|
||||
|
||||
if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
|
||||
DefaultColormap(drw->dpy, drw->screen),
|
||||
clrname, dest))
|
||||
die("error, cannot allocate color '%s'", clrname);
|
||||
|
||||
dest->pixel |= 0xff << 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[],
|
||||
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]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
drw_setscheme(Drw *drw, Clr *scm)
|
||||
{
|
||||
if (drw)
|
||||
drw->scheme = scm;
|
||||
}
|
||||
|
||||
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 markup)
|
||||
{
|
||||
char buf[1024];
|
||||
int i, ty, th;
|
||||
unsigned int ew, eh;
|
||||
XftDraw *d = NULL;
|
||||
size_t len;
|
||||
int render = x || y || w || h;
|
||||
|
||||
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,
|
||||
DefaultVisual(drw->dpy, drw->screen),
|
||||
DefaultColormap(drw->dpy, drw->screen));
|
||||
x += lpad;
|
||||
w -= lpad;
|
||||
}
|
||||
|
||||
len = strlen(text);
|
||||
|
||||
if (len) {
|
||||
drw_font_getexts(drw->fonts, text, len, &ew, &eh, markup);
|
||||
th = eh;
|
||||
/* shorten text if necessary */
|
||||
for (len = MIN(len, sizeof(buf) - 1); len && ew > w; len--) {
|
||||
drw_font_getexts(drw->fonts, text, len, &ew, &eh, markup);
|
||||
if (eh > th)
|
||||
th = eh;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
memcpy(buf, text, len);
|
||||
buf[len] = '\0';
|
||||
if (len < strlen(text))
|
||||
for (i = len; i && i > len - 3; buf[--i] = '.')
|
||||
; /* NOP */
|
||||
|
||||
if (render) {
|
||||
ty = y + (h - th) / 2;
|
||||
if (markup)
|
||||
pango_layout_set_markup(drw->fonts->layout, buf, len);
|
||||
else
|
||||
pango_layout_set_text(drw->fonts->layout, buf, len);
|
||||
pango_xft_render_layout(d, &drw->scheme[invert ? ColBg : ColFg],
|
||||
drw->fonts->layout, x * PANGO_SCALE, ty * PANGO_SCALE);
|
||||
if (markup) /* clear markup attributes */
|
||||
pango_layout_set_attributes(drw->fonts->layout, NULL);
|
||||
}
|
||||
x += ew;
|
||||
w -= ew;
|
||||
}
|
||||
}
|
||||
if (d)
|
||||
XftDrawDestroy(d);
|
||||
|
||||
return x + (render ? w : 0);
|
||||
}
|
||||
|
||||
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, Bool markup)
|
||||
{
|
||||
if (!font || !text)
|
||||
return;
|
||||
|
||||
PangoRectangle r;
|
||||
if (markup)
|
||||
pango_layout_set_markup(font->layout, text, len);
|
||||
else
|
||||
pango_layout_set_text(font->layout, text, len);
|
||||
pango_layout_get_extents(font->layout, 0, &r);
|
||||
if (markup) /* clear markup attributes */
|
||||
pango_layout_set_attributes(font->layout, NULL);
|
||||
if (w)
|
||||
*w = r.width / PANGO_SCALE;
|
||||
if (h)
|
||||
*h = r.height / PANGO_SCALE;
|
||||
}
|
||||
|
||||
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,66 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
|
||||
#include <pango/pango.h>
|
||||
#include <pango/pangoxft.h>
|
||||
|
||||
typedef struct {
|
||||
Cursor cursor;
|
||||
} Cur;
|
||||
|
||||
typedef struct Fnt {
|
||||
Display *dpy;
|
||||
unsigned int h;
|
||||
PangoLayout *layout;
|
||||
} 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;
|
||||
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);
|
||||
void drw_resize(Drw *drw, unsigned int w, unsigned int h);
|
||||
void drw_free(Drw *drw);
|
||||
|
||||
/* Fnt abstraction */
|
||||
Fnt *drw_font_create(Drw* drw, const char font[]);
|
||||
void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h, Bool markup);
|
||||
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
|
||||
);
|
||||
Clr *drw_scm_create(
|
||||
Drw *drw,
|
||||
char *clrnames[],
|
||||
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_setscheme(Drw *drw, Clr *scm);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Map functions */
|
||||
void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h);
|
||||
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 66770cfbccceb562279ad7f8c700622b42776281
|
|
@ -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.
|
|
@ -0,0 +1,7 @@
|
|||
[Desktop Entry]
|
||||
Encoding=UTF-8
|
||||
Name=Dwm
|
||||
Comment=Dynamic window manager
|
||||
Exec=dwm
|
||||
Icon=dwm
|
||||
Type=XSession
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 37e8cb6145f189b805aa58c7d560b1adf51377a7
|
|
@ -0,0 +1,28 @@
|
|||
void
|
||||
attachx(Client *c)
|
||||
{
|
||||
Client *at;
|
||||
|
||||
if (c->idx > 0) { /* then the client has a designated position in the client list */
|
||||
for (at = c->mon->clients; at; at = at->next) {
|
||||
if (c->idx < at->idx) {
|
||||
c->next = at;
|
||||
c->mon->clients = c;
|
||||
return;
|
||||
} else if (at->idx <= c->idx && (!at->next || c->idx <= at->next->idx)) {
|
||||
c->next = at->next;
|
||||
at->next = c;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (at = c->mon->clients; at && at->next; at = at->next);
|
||||
if (at) {
|
||||
at->next = c;
|
||||
c->next = NULL;
|
||||
return;
|
||||
}
|
||||
attach(c); // master (default)
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
static void attachx(Client *c);
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
void
|
||||
barhover(XEvent *e, Bar *bar)
|
||||
{
|
||||
const BarRule *br;
|
||||
Monitor *m = bar->mon;
|
||||
XMotionEvent *ev = &e->xmotion;
|
||||
BarArg barg = { 0, 0, 0, 0 };
|
||||
int r;
|
||||
|
||||
for (r = 0; r < LENGTH(barrules); r++) {
|
||||
br = &barrules[r];
|
||||
if (br->bar != bar->idx || (br->monitor == 'A' && m != selmon) || br->hoverfunc == NULL)
|
||||
continue;
|
||||
if (br->monitor != 'A' && br->monitor != -1 && br->monitor != bar->mon->num)
|
||||
continue;
|
||||
if (bar->x[r] > ev->x || ev->x > bar->x[r] + bar->w[r])
|
||||
continue;
|
||||
|
||||
barg.x = ev->x - bar->x[r];
|
||||
barg.y = ev->y - bar->borderpx;
|
||||
barg.w = bar->w[r];
|
||||
barg.h = bar->bh - 2 * bar->borderpx;
|
||||
|
||||
br->hoverfunc(bar, &barg, ev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Bar *
|
||||
wintobar(Window win)
|
||||
{
|
||||
Monitor *m;
|
||||
Bar *bar;
|
||||
for (m = mons; m; m = m->next)
|
||||
for (bar = m->bar; bar; bar = bar->next)
|
||||
if (bar->win == win)
|
||||
return bar;
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
static void barhover(XEvent *e, Bar *bar);
|
||||
static Bar *wintobar(Window win);
|
|
@ -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,52 @@
|
|||
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,104 @@
|
|||
/* 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->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,18 @@
|
|||
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,44 @@
|
|||
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,9 @@
|
|||
char *
|
||||
tagicon(Monitor *m, int tag)
|
||||
{
|
||||
int tagindex = tag + NUMTAGS * m->num;
|
||||
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,81 @@
|
|||
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 = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
int
|
||||
hover_tags(Bar *bar, BarArg *a, XMotionEvent *ev)
|
||||
{
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -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);
|
||||
static int hover_tags(Bar *bar, BarArg *a, XMotionEvent *ev);
|
|
@ -0,0 +1,49 @@
|
|||
int
|
||||
width_wintitle(Bar *bar, BarArg *a)
|
||||
{
|
||||
return a->w;
|
||||
}
|
||||
|
||||
int
|
||||
draw_wintitle(Bar *bar, BarArg *a)
|
||||
{
|
||||
int x = a->x, w = a->w;
|
||||
Monitor *m = bar->mon;
|
||||
Client *c = m->sel;
|
||||
|
||||
if (!c) {
|
||||
drw_setscheme(drw, scheme[SchemeTitleNorm]);
|
||||
drw_rect(drw, x, a->y, w, a->h, 1, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tpad = lrpad / 2;
|
||||
int tx = x;
|
||||
int tw = w;
|
||||
|
||||
drw_setscheme(drw, scheme[m == selmon ? SchemeTitleSel : SchemeTitleNorm]);
|
||||
XSetErrorHandler(xerrordummy);
|
||||
|
||||
if (w <= TEXTW("A") - lrpad + tpad) // reduce text padding if wintitle is too small
|
||||
tpad = (w - TEXTW("A") + lrpad < 0 ? 0 : (w - TEXTW("A") + lrpad) / 2);
|
||||
|
||||
XSetForeground(drw->dpy, drw->gc, drw->scheme[ColBg].pixel);
|
||||
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, a->y, w, a->h);
|
||||
|
||||
tx += tpad;
|
||||
tw -= lrpad;
|
||||
|
||||
drw_text(drw, tx, a->y, tw, a->h, 0, 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,37 @@
|
|||
/* dwm will keep pid's of processes from autostart array and kill them at quit */
|
||||
static pid_t *autostart_pids;
|
||||
static size_t autostart_len;
|
||||
|
||||
/* execute command from autostart array */
|
||||
static void
|
||||
autostart_exec()
|
||||
{
|
||||
const char *const *p;
|
||||
struct sigaction sa;
|
||||
size_t i = 0;
|
||||
|
||||
/* count entries */
|
||||
for (p = autostart; *p; autostart_len++, p++)
|
||||
while (*++p);
|
||||
|
||||
autostart_pids = malloc(autostart_len * sizeof(pid_t));
|
||||
for (p = autostart; *p; i++, p++) {
|
||||
if ((autostart_pids[i] = fork()) == 0) {
|
||||
setsid();
|
||||
|
||||
/* Restore SIGCHLD sighandler to default before spawning a program */
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
sa.sa_handler = SIG_DFL;
|
||||
sigaction(SIGCHLD, &sa, NULL);
|
||||
|
||||
execvp(*p, (char *const *)p);
|
||||
fprintf(stderr, "dwm: execvp %s\n", *p);
|
||||
perror(" failed");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
/* skip arguments */
|
||||
while (*++p);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
static void autostart_exec(void);
|
||||
|
|
@ -0,0 +1,179 @@
|
|||
void
|
||||
floatpos(const Arg *arg)
|
||||
{
|
||||
Client *c = selmon->sel;
|
||||
|
||||
if (!c || (selmon->lt[selmon->sellt]->arrange && !c->isfloating))
|
||||
return;
|
||||
|
||||
setfloatpos(c, (char *)arg->v);
|
||||
resizeclient(c, c->x, c->y, c->w, c->h);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
setfloatpos(Client *c, const char *floatpos)
|
||||
{
|
||||
char xCh, yCh, wCh, hCh;
|
||||
int x, y, w, h, wx, ww, wy, wh;
|
||||
|
||||
if (!c || !floatpos)
|
||||
return;
|
||||
if (selmon->lt[selmon->sellt]->arrange && !c->isfloating)
|
||||
return;
|
||||
|
||||
switch(sscanf(floatpos, "%d%c %d%c %d%c %d%c", &x, &xCh, &y, &yCh, &w, &wCh, &h, &hCh)) {
|
||||
case 4:
|
||||
if (xCh == 'w' || xCh == 'W') {
|
||||
w = x; wCh = xCh;
|
||||
h = y; hCh = yCh;
|
||||
x = -1; xCh = 'C';
|
||||
y = -1; yCh = 'C';
|
||||
} else if (xCh == 'p' || xCh == 'P') {
|
||||
w = x; wCh = xCh;
|
||||
h = y; hCh = yCh;
|
||||
x = 0; xCh = 'G';
|
||||
y = 0; yCh = 'G';
|
||||
} else if (xCh == 'm' || xCh == 'M') {
|
||||
getrootptr(&x, &y);
|
||||
} else {
|
||||
w = 0; wCh = 0;
|
||||
h = 0; hCh = 0;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
if (xCh == 'm' || xCh == 'M')
|
||||
getrootptr(&x, &y);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
wx = c->mon->wx;
|
||||
wy = c->mon->wy;
|
||||
ww = c->mon->ww;
|
||||
wh = c->mon->wh;
|
||||
|
||||
getfloatpos(x, xCh, w, wCh, wx, ww, c->x, c->w, c->bw, floatposgrid_x, &c->x, &c->w);
|
||||
getfloatpos(y, yCh, h, hCh, wy, wh, c->y, c->h, c->bw, floatposgrid_y, &c->y, &c->h);
|
||||
}
|
||||
|
||||
/* p - position, s - size, cp and cs represents current position and size */
|
||||
void
|
||||
getfloatpos(int pos, char pCh, int size, char sCh, int min_p, int max_s, int cp, int cs, int cbw, int defgrid, int *out_p, int *out_s)
|
||||
{
|
||||
int abs_p, abs_s, i, delta, rest;
|
||||
|
||||
abs_p = pCh == 'A' || pCh == 'a';
|
||||
abs_s = sCh == 'A' || sCh == 'a';
|
||||
|
||||
cs += 2*cbw;
|
||||
|
||||
switch(pCh) {
|
||||
case 'A': // absolute position
|
||||
cp = pos;
|
||||
break;
|
||||
case 'a': // absolute relative position
|
||||
cp += pos;
|
||||
break;
|
||||
case 'y':
|
||||
case 'x': // client relative position
|
||||
cp = MIN(cp + pos, min_p + max_s);
|
||||
break;
|
||||
case 'Y':
|
||||
case 'X': // client position relative to monitor
|
||||
cp = min_p + MIN(pos, max_s);
|
||||
break;
|
||||
case 'S': // fixed client position (sticky)
|
||||
case 'C': // fixed client position (center)
|
||||
case 'Z': // fixed client right-hand position (position + size)
|
||||
if (pos == -1)
|
||||
break;
|
||||
pos = MAX(MIN(pos, max_s), 0);
|
||||
if (pCh == 'Z')
|
||||
cs = abs((cp + cs) - (min_p + pos));
|
||||
else if (pCh == 'C')
|
||||
cs = abs((cp + cs / 2) - (min_p + pos));
|
||||
else
|
||||
cs = abs(cp - (min_p + pos));
|
||||
cp = min_p + pos;
|
||||
sCh = 0; // size determined by position, override defined size
|
||||
break;
|
||||
case 'G': // grid
|
||||
if (pos <= 0)
|
||||
pos = defgrid; // default configurable
|
||||
if (size == 0 || pos < 2 || (sCh != 'p' && sCh != 'P'))
|
||||
break;
|
||||
delta = (max_s - cs) / (pos - 1);
|
||||
rest = max_s - cs - delta * (pos - 1);
|
||||
if (sCh == 'P') {
|
||||
if (size < 1 || size > pos)
|
||||
break;
|
||||
cp = min_p + delta * (size - 1);
|
||||
} else {
|
||||
for (i = 0; i < pos && cp >= min_p + delta * i + (i > pos - rest ? i + rest - pos + 1 : 0); i++);
|
||||
cp = min_p + delta * (MAX(MIN(i + size, pos), 1) - 1) + (i > pos - rest ? i + rest - pos + 1 : 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch(sCh) {
|
||||
case 'A': // absolute size
|
||||
cs = size;
|
||||
break;
|
||||
case 'a': // absolute relative size
|
||||
cs = MAX(1, cs + size);
|
||||
break;
|
||||
case '%': // client size percentage in relation to monitor window area size
|
||||
if (size <= 0)
|
||||
break;
|
||||
size = max_s * MIN(size, 100) / 100;
|
||||
/* falls through */
|
||||
case 'h':
|
||||
case 'w': // size relative to client
|
||||
if (sCh == 'w' || sCh == 'h') {
|
||||
if (size == 0)
|
||||
break;
|
||||
size += cs;
|
||||
}
|
||||
/* falls through */
|
||||
case 'H':
|
||||
case 'W': // normal size, position takes precedence
|
||||
if (pCh == 'S' && cp + size > min_p + max_s)
|
||||
size = min_p + max_s - cp;
|
||||
else if (size > max_s)
|
||||
size = max_s;
|
||||
|
||||
if (pCh == 'C') { // fixed client center, expand or contract client
|
||||
delta = size - cs;
|
||||
if (delta < 0 || (cp - delta / 2 + size <= min_p + max_s))
|
||||
cp -= delta / 2;
|
||||
else if (cp - delta / 2 < min_p)
|
||||
cp = min_p;
|
||||
else if (delta)
|
||||
cp = min_p + max_s;
|
||||
} else if (pCh == 'Z')
|
||||
cp -= size - cs;
|
||||
|
||||
cs = size;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pCh == '%') // client mid-point position in relation to monitor window area size
|
||||
cp = min_p + max_s * MAX(MIN(pos, 100), 0) / 100 - (cs) / 2;
|
||||
if (pCh == 'm' || pCh == 'M')
|
||||
cp = pos - cs / 2;
|
||||
|
||||
if (!abs_p && cp < min_p)
|
||||
cp = min_p;
|
||||
if (cp + cs > min_p + max_s && !(abs_p && abs_s)) {
|
||||
if (abs_p || cp == min_p)
|
||||
cs = min_p + max_s - cp;
|
||||
else
|
||||
cp = min_p + max_s - cs;
|
||||
}
|
||||
|
||||
*out_p = cp;
|
||||
*out_s = MAX(cs - 2*cbw, 1);
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
static void floatpos(const Arg *arg);
|
||||
static void setfloatpos(Client *c, const char *floatpos);
|
||||
static void getfloatpos(int pos, char pCh, int size, char sCh, int min_p, int max_s, int cp, int cs, int cbw, int defgrid, int *out_p, int *out_s);
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
void
|
||||
focusdir(const Arg *arg)
|
||||
{
|
||||
Client *s = selmon->sel, *f = NULL, *c, *next;
|
||||
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
unsigned int score = -1;
|
||||
unsigned int client_score;
|
||||
int dist;
|
||||
int dirweight = 20;
|
||||
int isfloating = s->isfloating;
|
||||
|
||||
next = s->next;
|
||||
if (!next)
|
||||
next = s->mon->clients;
|
||||
for (c = next; c != s; c = next) {
|
||||
|
||||
next = c->next;
|
||||
if (!next)
|
||||
next = s->mon->clients;
|
||||
|
||||
if (!ISVISIBLE(c) || c->isfloating != isfloating) // || HIDDEN(c)
|
||||
continue;
|
||||
|
||||
switch (arg->i) {
|
||||
case 0: // left
|
||||
dist = s->x - c->x - c->w;
|
||||
client_score =
|
||||
dirweight * MIN(abs(dist), abs(dist + s->mon->ww)) +
|
||||
abs(s->y - c->y);
|
||||
break;
|
||||
case 1: // right
|
||||
dist = c->x - s->x - s->w;
|
||||
client_score =
|
||||
dirweight * MIN(abs(dist), abs(dist + s->mon->ww)) +
|
||||
abs(c->y - s->y);
|
||||
break;
|
||||
case 2: // up
|
||||
dist = s->y - c->y - c->h;
|
||||
client_score =
|
||||
dirweight * MIN(abs(dist), abs(dist + s->mon->wh)) +
|
||||
abs(s->x - c->x);
|
||||
break;
|
||||
default:
|
||||
case 3: // down
|
||||
dist = c->y - s->y - s->h;
|
||||
client_score =
|
||||
dirweight * MIN(abs(dist), abs(dist + s->mon->wh)) +
|
||||
abs(c->x - s->x);
|
||||
break;
|
||||
}
|
||||
|
||||
if (((arg->i == 0 || arg->i == 2) && client_score <= score) || client_score < score) {
|
||||
score = client_score;
|
||||
f = c;
|
||||
}
|
||||
}
|
||||
|
||||
if (f && f != s) {
|
||||
focus(f);
|
||||
restack(f->mon);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
static void focusdir(const Arg *arg);
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/* Bar functionality */
|
||||
#include "bar_indicators.c"
|
||||
#include "bar_tagicons.c"
|
||||
#include "bar.c"
|
||||
|
||||
#include "bar_dwmblocks.c"
|
||||
#include "bar_ewmhtags.c"
|
||||
#include "bar_ltsymbol.c"
|
||||
#include "bar_status.c"
|
||||
#include "bar_statuscmd.c"
|
||||
#include "bar_tags.c"
|
||||
#include "bar_wintitle.c"
|
||||
|
||||
/* Other patches */
|
||||
#include "attachx.c"
|
||||
#include "cool_autostart.c"
|
||||
#include "floatpos.c"
|
||||
#include "focusdir.c"
|
||||
#include "pertag.c"
|
||||
#include "restartsig.c"
|
||||
#include "renamed_scratchpads.c"
|
||||
#include "sizehints_ruled.c"
|
||||
#include "stacker.c"
|
||||
#include "togglefullscreen.c"
|
||||
#include "unfloatvisible.c"
|
||||
#include "seamless_restart.c"
|
||||
/* Layouts */
|
||||
#include "layout_facts.c"
|
||||
#include "layout_bstack.c"
|
||||
#include "layout_centeredmaster.c"
|
||||
#include "layout_deck.c"
|
||||
#include "layout_gapplessgrid.c"
|
||||
#include "layout_monocle.c"
|
||||
#include "layout_tile.c"
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/* Bar functionality */
|
||||
#include "bar_indicators.h"
|
||||
#include "bar_tagicons.h"
|
||||
#include "bar.h"
|
||||
|
||||
#include "bar_dwmblocks.h"
|
||||
#include "bar_ewmhtags.h"
|
||||
#include "bar_ltsymbol.h"
|
||||
#include "bar_status.h"
|
||||
#include "bar_statuscmd.h"
|
||||
#include "bar_tags.h"
|
||||
#include "bar_wintitle.h"
|
||||
|
||||
/* Other patches */
|
||||
#include "attachx.h"
|
||||
#include "cool_autostart.h"
|
||||
#include "floatpos.h"
|
||||
#include "focusdir.h"
|
||||
#include "pertag.h"
|
||||
#include "restartsig.h"
|
||||
#include "renamed_scratchpads.h"
|
||||
#include "seamless_restart.h"
|
||||
#include "sizehints_ruled.h"
|
||||
#include "stacker.h"
|
||||
#include "togglefullscreen.h"
|
||||
#include "unfloatvisible.h"
|
||||
/* Layouts */
|
||||
#include "layout_bstack.h"
|
||||
#include "layout_centeredmaster.h"
|
||||
#include "layout_deck.h"
|
||||
#include "layout_gapplessgrid.h"
|
||||
#include "layout_monocle.h"
|
||||
#include "layout_tile.h"
|
||||
|
|
@ -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,39 @@
|
|||
static void
|
||||
bstack(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;
|
||||
|
||||
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
|
||||
|
||||
if (n == 0)
|
||||
return;
|
||||
|
||||
sx = mx = m->wx;
|
||||
sy = my = m->wy;
|
||||
sh = mh = m->wh;
|
||||
sw = mw = m->ww;
|
||||
|
||||
if (m->nmaster && n > m->nmaster) {
|
||||
sh = mh * (1 - m->mfact);
|
||||
mh = mh * m->mfact;
|
||||
sy = my + mh;
|
||||
}
|
||||
|
||||
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) {
|
||||
resize(c, mx, my, (mw / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0);
|
||||
mx += WIDTH(c);
|
||||
} else {
|
||||
resize(c, sx, sy, (sw / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0);
|
||||
sx += WIDTH(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
static void bstack(Monitor *m);
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
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;
|
||||
|
||||
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
|
||||
|
||||
if (n == 0)
|
||||
return;
|
||||
|
||||
/* initialize areas */
|
||||
mx = m->wx;
|
||||
my = m->wy;
|
||||
mh = m->wh;
|
||||
mw = m->ww;
|
||||
lh = m->wh;
|
||||
rh = m->wh;
|
||||
|
||||
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 * m->mfact;
|
||||
lw = (m->ww - mw) / 2;
|
||||
mx += lw;
|
||||
} else {
|
||||
/* ||<---M--->|<-S->|| */
|
||||
mw = mw * m->mfact;
|
||||
lw = m->ww - mw;
|
||||
}
|
||||
rw = lw;
|
||||
lx = m->wx;
|
||||
ly = m->wy;
|
||||
rx = mx + mw;
|
||||
ry = m->wy;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
} 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);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
static void centeredmaster(Monitor *m);
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
static void
|
||||
deck(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;
|
||||
|
||||
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
|
||||
|
||||
if (n == 0)
|
||||
return;
|
||||
|
||||
sx = mx = m->wx;
|
||||
sy = my = m->wy;
|
||||
sh = mh = m->wh;
|
||||
sw = mw = m->ww;
|
||||
|
||||
if (m->nmaster && n > m->nmaster) {
|
||||
sw = mw * (1 - m->mfact);
|
||||
mw = mw * m->mfact;
|
||||
sx = mx + mw;
|
||||
}
|
||||
|
||||
getfacts(m, mh, sh, &mfacts, &sfacts, &mrest, &srest);
|
||||
|
||||
if (n - m->nmaster > 0) /* override layout symbol */
|
||||
snprintf(m->ltsymbol, sizeof m->ltsymbol, "D %d", n - m->nmaster);
|
||||
|
||||
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);
|
||||
} else {
|
||||
resize(c, sx, sy, sw - (2*c->bw), sh - (2*c->bw), 0);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
static void deck(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,48 @@
|
|||
void
|
||||
gaplessgrid(Monitor *m)
|
||||
{
|
||||
unsigned int i, n;
|
||||
int x, y, cols, rows, ch, cw, cn, rn, rrest, crest; // counters
|
||||
Client *c;
|
||||
|
||||
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
|
||||
if (n == 0)
|
||||
return;
|
||||
|
||||
/* grid dimensions */
|
||||
for (cols = 0; cols <= n/2; cols++)
|
||||
if (cols*cols >= n)
|
||||
break;
|
||||
if (n == 5) /* set layout against the general calculation: not 1:2:2, but 2:3 */
|
||||
cols = 2;
|
||||
rows = n/cols;
|
||||
cn = rn = 0; // reset column no, row no, client count
|
||||
|
||||
ch = m->wh / rows;
|
||||
cw = m->ww / cols;
|
||||
rrest = m->wh - ch * rows;
|
||||
crest = m->ww - cw * cols;
|
||||
x = m->wx;
|
||||
y = m->wy;
|
||||
|
||||
for (i = 0, c = nexttiled(m->clients); c; i++, c = nexttiled(c->next)) {
|
||||
if (i/rows + 1 > cols - n%cols) {
|
||||
rows = n/cols + 1;
|
||||
ch = m->wh / rows;
|
||||
rrest = m->wh - ch * rows;
|
||||
}
|
||||
resize(c,
|
||||
x,
|
||||
y + rn*ch + MIN(rn, rrest),
|
||||
cw + (cn < crest ? 1 : 0) - 2*c->bw,
|
||||
ch + (rn < rrest ? 1 : 0) - 2*c->bw,
|
||||
0);
|
||||
rn++;
|
||||
if (rn >= rows) {
|
||||
rn = 0;
|
||||
x += cw + (cn < crest ? 1 : 0);
|
||||
cn++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
static void gaplessgrid(Monitor *m);
|
||||
|
|
@ -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,38 @@
|
|||
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;
|
||||
|
||||
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
|
||||
|
||||
if (n == 0)
|
||||
return;
|
||||
|
||||
sx = mx = m->wx;
|
||||
sy = my = m->wy;
|
||||
sh = mh = m->wh;
|
||||
sw = mw = m->ww;
|
||||
|
||||
if (m->nmaster && n > m->nmaster) {
|
||||
sw = mw * (1 - m->mfact);
|
||||
mw = mw * m->mfact;
|
||||
sx = mx + mw;
|
||||
}
|
||||
|
||||
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);
|
||||
} else {
|
||||
resize(c, sx, sy, sw - (2*c->bw), (sh / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0);
|
||||
sy += HEIGHT(c);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
static void tile(Monitor *m);
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
struct Pertag {
|
||||
unsigned int curtag; /* current tag index */
|
||||
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;
|
||||
|
||||
if (arg->ui == ~0)
|
||||
selmon->pertag->curtag = 0;
|
||||
else {
|
||||
for (i = 0; !(selmon->tagset[selmon->seltags] & 1 << i); i++);
|
||||
selmon->pertag->curtag = i + 1;
|
||||
}
|
||||
|
||||
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,144 @@
|
|||
void
|
||||
removescratch(const Arg *arg)
|
||||
{
|
||||
Client *c = selmon->sel;
|
||||
if (!c)
|
||||
return;
|
||||
c->scratchkey = 0;
|
||||
}
|
||||
|
||||
void
|
||||
setscratch(const Arg *arg)
|
||||
{
|
||||
Client *c = selmon->sel;
|
||||
if (!c)
|
||||
return;
|
||||
|
||||
c->scratchkey = ((char**)arg->v)[0][0];
|
||||
}
|
||||
|
||||
void spawnscratch(const Arg *arg)
|
||||
{
|
||||
if (fork() == 0) {
|
||||
if (dpy)
|
||||
close(ConnectionNumber(dpy));
|
||||
setsid();
|
||||
execvp(((char **)arg->v)[1], ((char **)arg->v)+1);
|
||||
fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[1]);
|
||||
perror(" failed");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
togglescratch(const Arg *arg)
|
||||
{
|
||||
Client *c, *next, *last = NULL, *found = NULL, *monclients = NULL;
|
||||
Monitor *mon;
|
||||
int scratchvisible = 0; // whether the scratchpads are currently visible or not
|
||||
int multimonscratch = 0; // whether we have scratchpads that are placed on multiple monitors
|
||||
int scratchmon = -1; // the monitor where the scratchpads exist
|
||||
int numscratchpads = 0; // count of scratchpads
|
||||
|
||||
/* Looping through monitors and client's twice, the first time to work out whether we need
|
||||
to move clients across from one monitor to another or not */
|
||||
for (mon = mons; mon; mon = mon->next)
|
||||
for (c = mon->clients; c; c = c->next) {
|
||||
if (c->scratchkey != ((char**)arg->v)[0][0])
|
||||
continue;
|
||||
if (scratchmon != -1 && scratchmon != mon->num)
|
||||
multimonscratch = 1;
|
||||
if (c->mon->tagset[c->mon->seltags] & c->tags) // && !HIDDEN(c)
|
||||
++scratchvisible;
|
||||
scratchmon = mon->num;
|
||||
++numscratchpads;
|
||||
}
|
||||
|
||||
/* Now for the real deal. The logic should go like:
|
||||
- hidden scratchpads will be shown
|
||||
- shown scratchpads will be hidden, unless they are being moved to the current monitor
|
||||
- the scratchpads will be moved to the current monitor if they all reside on the same monitor
|
||||
- multiple scratchpads residing on separate monitors will be left in place
|
||||
*/
|
||||
for (mon = mons; mon; mon = mon->next) {
|
||||
for (c = mon->stack; c; c = next) {
|
||||
next = c->snext;
|
||||
if (c->scratchkey != ((char**)arg->v)[0][0])
|
||||
continue;
|
||||
|
||||
/* Record the first found scratchpad client for focus purposes, but prioritise the
|
||||
scratchpad on the current monitor if one exists */
|
||||
if (!found || (mon == selmon && found->mon != selmon))
|
||||
found = c;
|
||||
|
||||
/* If scratchpad clients reside on another monitor and we are moving them across then
|
||||
as we are looping through monitors we could be moving a client to a monitor that has
|
||||
not been processed yet, hence we could be processing a scratchpad twice. To avoid
|
||||
this we detach them and add them to a temporary list (monclients) which is to be
|
||||
processed later. */
|
||||
if (!multimonscratch && c->mon != selmon) {
|
||||
detach(c);
|
||||
detachstack(c);
|
||||
c->next = NULL;
|
||||
/* Note that we are adding clients at the end of the list, this is to preserve the
|
||||
order of clients as they were on the adjacent monitor (relevant when tiled) */
|
||||
if (last)
|
||||
last = last->next = c;
|
||||
else
|
||||
last = monclients = c;
|
||||
} else if (scratchvisible == numscratchpads) {
|
||||
c->tags = 0;
|
||||
} else {
|
||||
XSetWindowBorder(dpy, c->win, scheme[SchemeScratchNorm][ColBorder].pixel);
|
||||
c->tags = c->mon->tagset[c->mon->seltags];
|
||||
if (c->isfloating)
|
||||
XRaiseWindow(dpy, c->win);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Attach moved scratchpad clients on the selected monitor */
|
||||
for (c = monclients; c; c = next) {
|
||||
next = c->next;
|
||||
mon = c->mon;
|
||||
c->mon = selmon;
|
||||
c->tags = selmon->tagset[selmon->seltags];
|
||||
/* Attach scratchpad clients from other monitors at the bottom of the stack */
|
||||
if (selmon->clients) {
|
||||
for (last = selmon->clients; last && last->next; last = last->next);
|
||||
last->next = c;
|
||||
} else
|
||||
selmon->clients = c;
|
||||
c->next = NULL;
|
||||
attachstack(c);
|
||||
|
||||
/* Center floating scratchpad windows when moved from one monitor to another */
|
||||
if (c->isfloating) {
|
||||
if (c->w > selmon->ww)
|
||||
c->w = selmon->ww - c->bw * 2;
|
||||
if (c->h > selmon->wh)
|
||||
c->h = selmon->wh - c->bw * 2;
|
||||
|
||||
if (numscratchpads > 1) {
|
||||
c->x = c->mon->wx + (c->x - mon->wx) * ((double)(abs(c->mon->ww - WIDTH(c))) / MAX(abs(mon->ww - WIDTH(c)), 1));
|
||||
c->y = c->mon->wy + (c->y - mon->wy) * ((double)(abs(c->mon->wh - HEIGHT(c))) / MAX(abs(mon->wh - HEIGHT(c)), 1));
|
||||
} else if (c->x < c->mon->mx || c->x > c->mon->mx + c->mon->mw ||
|
||||
c->y < c->mon->my || c->y > c->mon->my + c->mon->mh) {
|
||||
c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2);
|
||||
c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2);
|
||||
}
|
||||
resizeclient(c, c->x, c->y, c->w, c->h);
|
||||
XRaiseWindow(dpy, c->win);
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
focus(ISVISIBLE(found) ? found : NULL);
|
||||
arrange(NULL);
|
||||
if (found->isfloating)
|
||||
XRaiseWindow(dpy, found->win);
|
||||
} else {
|
||||
spawnscratch(arg);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
static void removescratch(const Arg *arg);
|
||||
static void setscratch(const Arg *arg);
|
||||
static void spawnscratch(const Arg *arg);
|
||||
static void togglescratch(const Arg *arg);
|
|
@ -0,0 +1,16 @@
|
|||
static int restart = 0;
|
||||
|
||||
void
|
||||
sighup(int unused)
|
||||
{
|
||||
Arg a = {.i = 1};
|
||||
quit(&a);
|
||||
}
|
||||
|
||||
void
|
||||
sigterm(int unused)
|
||||
{
|
||||
Arg a = {.i = 0};
|
||||
quit(&a);
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
static void sighup(int unused);
|
||||
static void sigterm(int unused);
|
||||
|
|
@ -0,0 +1,314 @@
|
|||
void
|
||||
persistmonitorstate(Monitor *m)
|
||||
{
|
||||
Client *c;
|
||||
unsigned int i;
|
||||
|
||||
setmonitortags(m);
|
||||
setmonitorfields(m);
|
||||
|
||||
/* Set client atoms */
|
||||
for (i = 1, c = m->clients; c; c = c->next, ++i) {
|
||||
c->idx = i;
|
||||
persistclientstate(c);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
restoremonitorstate(Monitor *m)
|
||||
{
|
||||
return getmonitortags(m) | getmonitorfields(m);
|
||||
}
|
||||
|
||||
void
|
||||
persistclientstate(Client *c)
|
||||
{
|
||||
setclienttags(c);
|
||||
setclientfields(c);
|
||||
savewindowfloatposition(c, c->mon);
|
||||
}
|
||||
|
||||
int
|
||||
restoreclientstate(Client *c)
|
||||
{
|
||||
int restored = getclientfields(c);
|
||||
getclienttags(c);
|
||||
restorewindowfloatposition(c, c->mon ? c->mon : selmon);
|
||||
return restored;
|
||||
}
|
||||
|
||||
void setmonitorfields(Monitor *m)
|
||||
{
|
||||
unsigned int i;
|
||||
char atom[22] = {0};
|
||||
Atom monitor_fields;
|
||||
|
||||
sprintf(atom, "_DWM_MONITOR_FIELDS_%u", m->num);
|
||||
monitor_fields = XInternAtom(dpy, atom, False);
|
||||
|
||||
/* Perists workspace information in 32 bits laid out like this:
|
||||
*
|
||||
* |0|0000|0|0000|0000|0000|0000|0000|000|000
|
||||
* | | | | | | | | | |-- nmaster
|
||||
* | | | | | | | | |-- nstack
|
||||
* | | | | | | | |-- layout
|
||||
* | | | | | | |-- flextile LAYOUT (split)
|
||||
* | | | | | |-- flextile MASTER
|
||||
* | | | | |-- flextile STACK1
|
||||
* | | | |-- flextile STACK2
|
||||
* | | |-- flextile mirror layout (indicated by negative layout)
|
||||
* | |
|
||||
* | |-- reserved
|
||||
* |-- showbar
|
||||
*/
|
||||
for (i = 0; i <= NUMTAGS; i++) {
|
||||
uint32_t data[] = {
|
||||
(m->pertag->nmasters[i] & 0x7) |
|
||||
(getlayoutindex(m->pertag->ltidxs[i][m->pertag->sellts[i]]) & 0xF) << 6 |
|
||||
m->showbar << 31
|
||||
};
|
||||
|
||||
XChangeProperty(dpy, root, monitor_fields, XA_CARDINAL, 32,
|
||||
i ? PropModeAppend : PropModeReplace, (unsigned char *)data, 1);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
getlayoutindex(const Layout *layout)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < LENGTH(layouts) && &layouts[i] != layout; i++);
|
||||
if (i == LENGTH(layouts))
|
||||
i = 0;
|
||||
return i;
|
||||
}
|
||||
|
||||
int
|
||||
getmonitorfields(Monitor *m)
|
||||
{
|
||||
int di, layout_index;
|
||||
unsigned int i, restored = 0;
|
||||
unsigned int tags = m->tagset[m->seltags] << 1;
|
||||
unsigned long dl, nitems;
|
||||
unsigned char *p = NULL;
|
||||
char atom[22] = {0};
|
||||
Atom da, state = None;
|
||||
|
||||
sprintf(atom, "_DWM_MONITOR_FIELDS_%u", m->num);
|
||||
Atom dwm_monitor = XInternAtom(dpy, atom, False);
|
||||
if (!dwm_monitor)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i <= NUMTAGS; i++) {
|
||||
if (!(XGetWindowProperty(dpy, root, dwm_monitor, i, (NUMTAGS + 1) * sizeof dl,
|
||||
False, AnyPropertyType, &da, &di, &nitems, &dl, &p) == Success && p)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!nitems) {
|
||||
XFree(p);
|
||||
break;
|
||||
}
|
||||
|
||||
/* See bit layout in the persistmonitorstate function */
|
||||
state = *(Atom *)p;
|
||||
|
||||
m->pertag->nmasters[i] = state & 0x7;
|
||||
layout_index = (state >> 6) & 0xF;
|
||||
if (layout_index < LENGTH(layouts))
|
||||
m->pertag->ltidxs[i][m->pertag->sellts[i]] = &layouts[layout_index];
|
||||
|
||||
if (!restored && i && (tags & (1 << i))) {
|
||||
m->nmaster = m->pertag->nmasters[i];
|
||||
m->sellt = m->pertag->sellts[i];
|
||||
m->lt[m->sellt] = m->pertag->ltidxs[i][m->sellt];
|
||||
m->showbar = (state >> 31) & 0x1;
|
||||
restored = 1;
|
||||
}
|
||||
|
||||
XFree(p);
|
||||
}
|
||||
|
||||
return restored;
|
||||
}
|
||||
|
||||
void
|
||||
setmonitortags(Monitor *m)
|
||||
{
|
||||
char atom[22] = {0};
|
||||
Atom monitor_tags;
|
||||
|
||||
sprintf(atom, "_DWM_MONITOR_TAGS_%u", m->num);
|
||||
monitor_tags = XInternAtom(dpy, atom, False);
|
||||
|
||||
uint32_t data[] = { m->tagset[m->seltags] };
|
||||
XChangeProperty(dpy, root, monitor_tags, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1);
|
||||
}
|
||||
|
||||
int
|
||||
getmonitortags(Monitor *m)
|
||||
{
|
||||
int di;
|
||||
unsigned long dl, nitems;
|
||||
unsigned char *p = NULL;
|
||||
char atom[22] = {0};
|
||||
Atom da, monitor_tags = None, tags;
|
||||
|
||||
sprintf(atom, "_DWM_MONITOR_TAGS_%u", m->num);
|
||||
monitor_tags = XInternAtom(dpy, atom, False);
|
||||
|
||||
if (!(XGetWindowProperty(dpy, root, monitor_tags, 0L, sizeof dl,
|
||||
False, AnyPropertyType, &da, &di, &nitems, &dl, &p) == Success && p)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (nitems) {
|
||||
tags = *(Atom *)p;
|
||||
m->tagset[m->seltags] = tags & TAGMASK;
|
||||
}
|
||||
|
||||
XFree(p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
setclientfields(Client *c)
|
||||
{
|
||||
/* Perists client information in 32 bits laid out like this:
|
||||
*
|
||||
* |00000000|00000|0|0|0|0|0|0|0|0|00000000|000
|
||||
* | | | | | | | | | | | |-- monitor index
|
||||
* | | | | | | | | | | |-- client index
|
||||
* | | | | | | | | | |-- isfloating
|
||||
* | | | | | | | | |-- ispermanent
|
||||
* | | | | | | | |-- isterminal
|
||||
* | | | | | | |-- noswallow
|
||||
* | | | | | |-- issteam
|
||||
* | | | | |-- issticky
|
||||
* | | | |-- fakefullscreen
|
||||
* | | |-- isfreesize
|
||||
* | |
|
||||
* | |-- reserved
|
||||
* |-- scratchkey (for scratchpads)
|
||||
*/
|
||||
uint32_t data[] = {
|
||||
(c->mon->num & 0x7)
|
||||
| (c->idx & 0xFF) << 3
|
||||
| (c->isfloating & 0x1) << 11
|
||||
| (c->scratchkey & 0xFF) << 24
|
||||
};
|
||||
XChangeProperty(dpy, c->win, clientatom[ClientFields], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1);
|
||||
}
|
||||
|
||||
int
|
||||
getclientfields(Client *c)
|
||||
{
|
||||
Monitor *m;
|
||||
Atom fields = getatomprop(c, clientatom[ClientFields], AnyPropertyType);
|
||||
if (fields == None)
|
||||
return 0;
|
||||
|
||||
/* See bit layout in the setclientfields function */
|
||||
for (m = mons; m; m = m->next)
|
||||
if (m->num == (fields & 0x7)) {
|
||||
c->mon = m;
|
||||
break;
|
||||
}
|
||||
c->idx = (fields >> 3) & 0xFF;
|
||||
c->isfloating = (fields >> 11) & 0x1;
|
||||
c->scratchkey = (fields >> 24) & 0xFF;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
setclienttags(Client *c)
|
||||
{
|
||||
uint32_t data[] = { c->tags };
|
||||
XChangeProperty(dpy, c->win, clientatom[ClientTags], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1);
|
||||
}
|
||||
|
||||
int
|
||||
getclienttags(Client *c)
|
||||
{
|
||||
Atom tags = getatomprop(c, clientatom[ClientTags], AnyPropertyType);
|
||||
if (tags == None)
|
||||
return 0;
|
||||
|
||||
c->tags = tags & TAGMASK;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
savewindowfloatposition(Client *c, Monitor *m)
|
||||
{
|
||||
char atom[22] = {0};
|
||||
if (c->sfx == -9999)
|
||||
return;
|
||||
|
||||
sprintf(atom, "_DWM_FLOATPOS_%u", m->num);
|
||||
uint32_t pos[] = { (MAX(c->sfx - m->mx, 0) & 0xffff) | ((MAX(c->sfy - m->my, 0) & 0xffff) << 16) };
|
||||
XChangeProperty(dpy, c->win, XInternAtom(dpy, atom, False), XA_CARDINAL, 32, PropModeReplace, (unsigned char *)pos, 1);
|
||||
|
||||
sprintf(atom, "_DWM_FLOATSIZE_%u", m->num);
|
||||
uint32_t size[] = { (c->sfw & 0xffff) | ((c->sfh & 0xffff) << 16) };
|
||||
XChangeProperty(dpy, c->win, XInternAtom(dpy, atom, False), XA_CARDINAL, 32, PropModeReplace, (unsigned char *)size, 1);
|
||||
|
||||
XSync(dpy, False);
|
||||
}
|
||||
|
||||
int
|
||||
restorewindowfloatposition(Client *c, Monitor *m)
|
||||
{
|
||||
char atom[22] = {0};
|
||||
Atom key, value;
|
||||
int x, y, w, h;
|
||||
|
||||
if (m == NULL)
|
||||
return 0;
|
||||
|
||||
sprintf(atom, "_DWM_FLOATPOS_%u", m->num);
|
||||
|
||||
key = XInternAtom(dpy, atom, False);
|
||||
if (!key)
|
||||
return 0;
|
||||
|
||||
value = getatomprop(c, key, AnyPropertyType);
|
||||
if (!value)
|
||||
return 0;
|
||||
|
||||
x = value & 0xffff;
|
||||
y = value >> 16;
|
||||
|
||||
sprintf(atom, "_DWM_FLOATSIZE_%u", m->num);
|
||||
|
||||
key = XInternAtom(dpy, atom, False);
|
||||
if (!key)
|
||||
return 0;
|
||||
|
||||
value = getatomprop(c, key, AnyPropertyType);
|
||||
if (!value)
|
||||
return 0;
|
||||
|
||||
w = value & 0xffff;
|
||||
h = value >> 16;
|
||||
|
||||
if (w <= 0 || h <= 0) {
|
||||
fprintf(stderr, "restorewindowfloatposition: bad float values x = %d, y = %d, w = %d, h = %d for client = %s\n", x, y, w, h, c->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
c->sfx = m->mx + x;
|
||||
c->sfy = m->my + y;
|
||||
c->sfw = w;
|
||||
c->sfh = h;
|
||||
|
||||
if (c->isfloating) {
|
||||
c->x = c->sfx;
|
||||
c->y = c->sfy;
|
||||
c->w = c->sfw;
|
||||
c->h = c->sfh;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#include <stdint.h>
|
||||
|
||||
static void persistmonitorstate(Monitor *m);
|
||||
static int restoremonitorstate(Monitor *m);
|
||||
static void persistclientstate(Client *c);
|
||||
static int restoreclientstate(Client *c);
|
||||
static void setmonitorfields(Monitor *m);
|
||||
static int getmonitorfields(Monitor *m);
|
||||
static void setmonitortags(Monitor *m);
|
||||
static int getmonitortags(Monitor *m);
|
||||
static void setclientfields(Client *c);
|
||||
static int getclientfields(Client *c);
|
||||
static void setclienttags(Client *c);
|
||||
static int getclienttags(Client *c);
|
||||
static int getlayoutindex(const Layout *layout);
|
||||
static void savewindowfloatposition(Client *c, Monitor *m);
|
||||
static int restorewindowfloatposition(Client *c, Monitor *m);
|
|
@ -0,0 +1,33 @@
|
|||
void
|
||||
checkfloatingrules(Client *c)
|
||||
{
|
||||
const char *class, *instance;
|
||||
Atom wintype;
|
||||
char role[64];
|
||||
unsigned int i;
|
||||
const Rule *r;
|
||||
XClassHint ch = { NULL, NULL };
|
||||
|
||||
XGetClassHint(dpy, c->win, &ch);
|
||||
class = ch.res_class ? ch.res_class : broken;
|
||||
instance = ch.res_name ? ch.res_name : broken;
|
||||
wintype = getatomprop(c, netatom[NetWMWindowType], XA_ATOM);
|
||||
gettextprop(c->win, wmatom[WMWindowRole], role, sizeof(role));
|
||||
|
||||
for (i = 0; i < LENGTH(rules); i++) {
|
||||
r = &rules[i];
|
||||
if ((!r->title || strstr(c->name, r->title))
|
||||
&& (!r->class || strstr(class, r->class))
|
||||
&& (!r->role || strstr(role, r->role))
|
||||
&& (!r->instance || strstr(instance, r->instance))
|
||||
&& (!r->wintype || wintype == XInternAtom(dpy, r->wintype, False)))
|
||||
{
|
||||
c->isfloating = r->isfloating;
|
||||
}
|
||||
}
|
||||
if (ch.res_class)
|
||||
XFree(ch.res_class);
|
||||
if (ch.res_name)
|
||||
XFree(ch.res_name);
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
static void checkfloatingrules(Client *c);
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
void
|
||||
focusstack(const Arg *arg)
|
||||
{
|
||||
int i = stackpos(arg);
|
||||
Client *c, *p;
|
||||
|
||||
if (i < 0)
|
||||
return;
|
||||
|
||||
if (!selmon->sel)
|
||||
return;
|
||||
|
||||
for (p = NULL, c = selmon->clients; c && (i || !ISVISIBLE(c));
|
||||
i -= (ISVISIBLE(c) ? 1 : 0), p = c, c = c->next);
|
||||
focus(c ? c : p);
|
||||
restack(selmon);
|
||||
}
|
||||
|
||||
void
|
||||
pushstack(const Arg *arg)
|
||||
{
|
||||
int i = stackpos(arg);
|
||||
Client *sel = selmon->sel, *c, *p;
|
||||
|
||||
if (i < 0)
|
||||
return;
|
||||
else if (i == 0) {
|
||||
detach(sel);
|
||||
attach(sel);
|
||||
}
|
||||
else {
|
||||
for (p = NULL, c = selmon->clients; c; p = c, c = c->next)
|
||||
if (!(i -= (ISVISIBLE(c) && c != sel)))
|
||||
break;
|
||||
c = c ? c : p;
|
||||
detach(sel);
|
||||
sel->next = c->next;
|
||||
c->next = sel;
|
||||
}
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
int
|
||||
stackpos(const Arg *arg)
|
||||
{
|
||||
int n, i;
|
||||
Client *c, *l;
|
||||
|
||||
if (!selmon->clients)
|
||||
return -1;
|
||||
|
||||
if (arg->i == PREVSEL) {
|
||||
for (l = selmon->stack; l && (!ISVISIBLE(l) || l == selmon->sel); l = l->snext);
|
||||
if (!l)
|
||||
return -1;
|
||||
for (i = 0, c = selmon->clients; c != l; i += (ISVISIBLE(c) ? 1 : 0), c = c->next);
|
||||
return i;
|
||||
}
|
||||
else if (ISINC(arg->i)) {
|
||||
if (!selmon->sel)
|
||||
return -1;
|
||||
for (i = 0, c = selmon->clients; c != selmon->sel; i += (ISVISIBLE(c) ? 1 : 0), c = c->next);
|
||||
for (n = i; c; n += (ISVISIBLE(c) ? 1 : 0), c = c->next);
|
||||
return MOD(i + GETINC(arg->i), n);
|
||||
}
|
||||
else if (arg->i < 0) {
|
||||
for (i = 0, c = selmon->clients; c; i += (ISVISIBLE(c) ? 1 : 0), c = c->next);
|
||||
return MAX(i + arg->i, 0);
|
||||
}
|
||||
else
|
||||
return arg->i;
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#define GETINC(X) ((X) - 2000)
|
||||
#define INC(X) ((X) + 2000)
|
||||
#define ISINC(X) ((X) > 1000 && (X) < 3000)
|
||||
#define PREVSEL 3000
|
||||
#define MOD(N,M) ((N)%(M) < 0 ? (N)%(M) + (M) : (N)%(M))
|
||||
#define TRUNC(X,A,B) (MAX((A), MIN((X), (B))))
|
||||
|
||||
static void focusstack(const Arg *arg);
|
||||
static void pushstack(const Arg *arg);
|
||||
static int stackpos(const Arg *arg);
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
void
|
||||
togglefullscreen(const Arg *arg)
|
||||
{
|
||||
Client *c = selmon->sel;
|
||||
if (!c)
|
||||
return;
|
||||
|
||||
setfullscreen(c, !c->isfullscreen);
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
static void togglefullscreen(const Arg *arg);
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
void
|
||||
unfloatvisible(const Arg *arg)
|
||||
{
|
||||
Client *c;
|
||||
|
||||
for (c = selmon->clients; c; c = c->next)
|
||||
if (ISVISIBLE(c) && c->isfloating)
|
||||
c->isfloating = c->isfixed;
|
||||
|
||||
if (arg && arg->v)
|
||||
setlayout(arg);
|
||||
else
|
||||
arrange(selmon);
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
static void unfloatvisible(const Arg *arg);
|
||||
|
|
@ -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
|
||||
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);
|
||||
}
|
||||
|
||||
void *
|
||||
ecalloc(size_t nmemb, size_t size)
|
||||
{
|
||||
void *p;
|
||||
|
||||
if (!(p = calloc(nmemb, size)))
|
||||
die("calloc:");
|
||||
return p;
|
||||
}
|
|
@ -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);
|
||||
|
Loading…
Reference in New Issue