void-packages

Void Source Packages
git clone git://ezup.dev/void-packages.git
Log | Files | Refs | README | LICENSE

commit 8e9755c73d4ec8b2a355a17e2c1772cc74c636b1
parent 8025f6ea3dbe127caf38801dabaa435e06c0ab2e
Author: Dash Eclipse <dash@ezup.dev>
Date:   Wed, 15 Jul 2020 13:49:21 +0000

dwm: systray patch and nordtheme based color

Diffstat:
AREADME | 21+++++++++++++++++++++
DREADME.md | 521-------------------------------------------------------------------------------
Asrcpkgs/dwm/files/config.h | 129+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrcpkgs/dwm/files/dwm.desktop | 7+++++++
Asrcpkgs/dwm/patches/dwm-systray-6.2.diff | 746+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrcpkgs/dwm/template | 26++++++++++++++++++++++++++
6 files changed, 929 insertions(+), 521 deletions(-)

diff --git a/README b/README @@ -0,0 +1,21 @@ +Dash Eclipse's Void Linux Repository +------------------------------------ + +Packages: dwm, st + + +st +-- + +Font: Fira Code Medium + +https://st.suckless.org/patches/scrollback/ +https://st.suckless.org/patches/nordtheme/ + + +dwm +--- + +Color: nordtheme based + +https://dwm.suckless.org/patches/systray/ diff --git a/README.md b/README.md @@ -1,521 +0,0 @@ -## The XBPS source packages collection - -This repository contains the XBPS source packages collection to build binary packages -for the Void Linux distribution. - -The included `xbps-src` script will fetch and compile the sources, and install its -files into a `fake destdir` to generate XBPS binary packages that can be installed -or queried through the `xbps-install(1)` and `xbps-query(1)` utilities, respectively. - -See [Contributing](./CONTRIBUTING.md) for a general overview of how to contribute and the -[Manual](./Manual.md) for details of how to create source packages. - -### Table of Contents - -- [Requirements](#requirements) -- [Quick start](#quick-start) -- [chroot methods](#chroot-methods) -- [Install the bootstrap packages](#install-bootstrap) -- [Configuration](#configuration) -- [Directory hierarchy](#directory-hierarchy) -- [Building packages](#building-packages) -- [Package build options](#build-options) -- [Sharing and signing your local repositories](#sharing-and-signing) -- [Rebuilding and overwriting existing local packages](#rebuilding) -- [Enabling distcc for distributed compilation](#distcc) -- [Distfiles mirrors](#distfiles-mirrors) -- [Cross compiling packages for a target architecture](#cross-compiling) -- [Using xbps-src in a foreign Linux distribution](#foreign) -- [Remaking the masterdir](#remaking-masterdir) -- [Keeping your masterdir uptodate](#updating-masterdir) -- [Building 32bit packages on x86_64](#building-32bit) -- [Building packages natively for the musl C library](#building-for-musl) -- [Building void base-system from scratch](#building-base-system) - -### Requirements - -- GNU bash -- xbps >= 0.56 -- curl(1) - required by `xbps-src update-check` -- flock(1) - util-linux -- bsdtar or GNU tar (in that order of preference) -- install(1) - GNU coreutils -- objcopy(1), objdump(1), strip(1): binutils -- other common POSIX utilities included by default in almost all UNIX systems. - -`xbps-src` requires a utility to chroot and bind mount existing directories -into a `masterdir` that is used as its main `chroot` directory. `xbps-src` supports -multiple utilities to accomplish this task: - - - `bwrap` - bubblewrap, see https://github.com/projectatomic/bubblewrap. - - `ethereal` - only useful for one-shot containers, i.e docker (used with travis). - - `xbps-uunshare(1)` - XBPS utility that uses `user_namespaces(7)` (part of xbps, default). - - `xbps-uchroot(1)` - XBPS utility that uses `namespaces` and must be `setgid` (part of xbps). - - `proot(1)` - utility that implements chroot/bind mounts in user space, see https://proot-me.github.io/. - -> NOTE: `xbps-src` does not allow building as root anymore. Use one of the chroot -methods shown above. - -<a name="quick-start"></a> -### Quick start - -Clone the `void-packages` git repository and install the bootstrap packages: - -``` -$ git clone git://github.com/void-linux/void-packages.git -$ cd void-packages -$ ./xbps-src binary-bootstrap -``` - -Build a package by specifying the `pkg` target and the package name: - -``` -$ ./xbps-src pkg <package_name> -``` - -Use `./xbps-src -h` to list all available targets and options. - -To build packages marked as 'restricted', modify `etc/conf`: - -``` -$ echo XBPS_ALLOW_RESTRICTED=yes >> etc/conf -``` - -Once built, the package will be available in `hostdir/binpkgs` or an appropriate subdirectory (e.g. `hostdir/binpkgs/nonfree`). To install the package: - -``` -# xbps-install --repository hostdir/binpkgs <package_name> -``` - -Alternatively, packages can be installed with the `xi` utility, from the `xtools` package. `xi` takes the repository of the current working directory into account. - -``` -# xi <package_name> -``` - -<a name="chroot-methods"></a> -### chroot methods - -#### xbps-uunshare(1) (default) - -This utility requires these Linux kernel options: - -- CONFIG\_NAMESPACES -- CONFIG\_IPC\_NS -- CONFIG\_UTS\_NS -- CONFIG\_USER\_NS - -This is the default method, and if your system does not support any of the required kernel -options it will fail with `EINVAL (Invalid argument)`. - -#### xbps-uchroot(1) - -This utility requires these Linux kernel options: - -- CONFIG\_NAMESPACES -- CONFIG\_IPC\_NS -- CONFIG\_PID\_NS -- CONFIG\_UTS\_NS - -Your user must be added to a special group to be able to use `xbps-uchroot(1)` and the -executable must be `setgid`: - - # chown root:<group> xbps-uchroot - # chmod 4750 xbps-uchroot - # usermod -a -G <group> <user> - -> NOTE: by default in void you shouldn't do this manually, your user must be a member of -the `xbuilder` group. - -To enable it: - - $ cd void-packages - $ echo XBPS_CHROOT_CMD=uchroot >> etc/conf - -If for some reason it's erroring out as `ERROR clone (Operation not permitted)`, check that -your user is a member of the required `group` and that `xbps-uchroot(1)` utility has the -proper permissions and owner/group as explained above. - -#### proot(1) - -The `proot(1)` utility implements chroot and bind mounts support completely in user space, -and can be used if your Linux kernel does not have support for namespaces. See https://proot-me.github.io/. -for more information. - -To enable it: - - $ cd void-packages - $ echo XBPS_CHROOT_CMD=proot >> etc/conf - -<a name="install-bootstrap"></a> -### Install the bootstrap packages - -There is a set of packages that makes up the initial build container, called the `bootstrap`. -These packages are installed into the `masterdir` in order to create the container. - -The primary and recommended way to set up this container is using the `binary-bootstrap` -command. This will use pre-existing binary packages, either from remote `xbps` repositories -or from your local repository. - -There is also the `bootstrap` command, which will build all necessary `bootstrap` packages from -scratch. This is usually not recommended, since those packages are built using your host system's -toolchain and are neither fully featured nor reproducible (your host system may influence the -build) and thus should only be used as a stage 0 for bootstrapping new Void systems. - -If you still choose to use `bootstrap`, use the resulting stage 0 container to rebuild all -`bootstrap` packages again, then use `binary-bootstrap` (stage 1) and rebuild the `bootstrap` -packages once more (to gain stage 2, and then use `binary-bootstrap` again). Once you've done -that, you will have a `bootstrap` set equivalent to using `binary-bootstrap` in the first place. - -Also keep in mind that a full source `bootstrap` is time consuming and will require having an -assortment of utilities installed in your host system, such as `binutils`, `gcc`, `perl`, -`texinfo` and others. - -### Configuration - -The `etc/defaults.conf` file contains the possible settings that can be overridden -through the `etc/conf` configuration file for the `xbps-src` utility; if that file -does not exist, will try to read configuration settings from `$XDG_CONFIG_HOME/xbps-src.conf`, `~/.config/xbps-src.conf`, `~/.xbps-src.conf`. - -If you want to customize default `CFLAGS`, `CXXFLAGS` and `LDFLAGS`, don't override -those defined in `etc/defaults.conf`, set them on `etc/conf` instead i.e: - - $ echo 'XBPS_CFLAGS="your flags here"' >> etc/conf - $ echo 'XBPS_LDFLAGS="your flags here"' >> etc/conf - -Native and cross compiler/linker flags are set per architecture in `common/build-profiles` -and `common/cross-profiles` respectively. Ideally those settings are good enough by default, -and there's no need to set your own unless you know what you are doing. - -#### Virtual packages - -The `etc/defaults.virtual` file contains the default replacements for virtual packages, -used as dependencies in the source packages tree. - -If you want to customize those replacements, copy `etc/defaults.virtual` to `etc/virtual` -and edit it accordingly to your needs. - -<a name="directory-hierarchy"></a> -### Directory hierarchy - -The following directory hierarchy is used with a default configuration file: - - /void-packages - |- common - |- etc - |- srcpkgs - | |- xbps - | |- template - | - |- hostdir - | |- binpkgs ... - | |- ccache ... - | |- distcc-<arch> ... - | |- repocache ... - | |- sources ... - | - |- masterdir - | |- builddir -> ... - | |- destdir -> ... - | |- host -> bind mounted from <hostdir> - | |- void-packages -> bind mounted from <void-packages> - - -The description of these directories is as follows: - - - `masterdir`: master directory to be used as rootfs to build/install packages. - - `builddir`: to unpack package source tarballs and where packages are built. - - `destdir`: to install packages, aka **fake destdir**. - - `hostdir/ccache`: to store ccache data if the `XBPS_CCACHE` option is enabled. - - `hostdir/distcc-<arch>`: to store distcc data if the `XBPS_DISTCC` option is enabled. - - `hostdir/repocache`: to store binary packages from remote repositories. - - `hostdir/sources`: to store package sources. - - `hostdir/binpkgs`: local repository to store generated binary packages. - -<a name="building-packages"></a> -### Building packages - -The simplest form of building package is accomplished by running the `pkg` target in `xbps-src`: - -``` -$ cd void-packages -$ ./xbps-src pkg <pkgname> -``` - -When the package and its required dependencies are built, the binary packages will be created -and registered in the default local repository at `hostdir/binpkgs`; the path to this local repository can be added to -any xbps configuration file (see xbps.d(5)) or by explicitly appending them via cmdline, i.e: - - $ xbps-install --repository=hostdir/binpkgs ... - $ xbps-query --repository=hostdir/binpkgs ... - -By default **xbps-src** will try to resolve package dependencies in this order: - - - If a dependency exists in the local repository, use it (`hostdir/binpkgs`). - - If a dependency exists in a remote repository, use it. - - If a dependency exists in a source package, use it. - -It is possible to avoid using remote repositories completely by using the `-N` flag. - -> The default local repository may contain multiple *sub-repositories*: `debug`, `multilib`, etc. - -<a name="build-options"></a> -### Package build options - -The supported build options for a source package can be shown with `xbps-src show-options`: - - $ ./xbps-src show-options foo - -Build options can be enabled with the `-o` flag of `xbps-src`: - - $ ./xbps-src -o option,option1 pkg foo - -Build options can be disabled by prefixing them with `~`: - - $ ./xbps-src -o ~option,~option1 pkg foo - -Both ways can be used together to enable and/or disable multiple options -at the same time with `xbps-src`: - - $ ./xbps-src -o option,~option1,~option2 pkg foo - -The build options can also be shown for binary packages via `xbps-query(1)`: - - $ xbps-query -R --property=build-options foo - -> NOTE: if you build a package with a custom option, and that package is available -in an official void repository, an update will ignore those options. Put that package -on `hold` mode via `xbps-pkgdb(1)`, i.e `xbps-pkgdb -m hold foo` to ignore updates -with `xbps-install -u`. Once the package is on `hold`, the only way to update it -is by declaring it explicitly: `xbps-install -u foo`. - -Permanent global package build options can be set via `XBPS_PKG_OPTIONS` variable in the -`etc/conf` configuration file. Per package build options can be set via -`XBPS_PKG_OPTIONS_<pkgname>`. - -> NOTE: if `pkgname` contains `dashes`, those should be replaced by `underscores` -i.e `XBPS_PKG_OPTIONS_xorg_server=opt`. - -The list of supported package build options and its description is defined in the -`common/options.description` file or in the `template` file. - -<a name="sharing-and-signing"></a> -### Sharing and signing your local repositories - -To share a local repository remotely it's mandatory to sign it and the binary packages -stored on it. This is accomplished with the `xbps-rindex(1)` utility. - -First a RSA key must be created with `openssl(1)` or `ssh-keygen(1)`: - - $ openssl genrsa -des3 -out privkey.pem 4096 - -or - - $ ssh-keygen -t rsa -b 4096 -m PEM -f privkey.pem - -> Only RSA keys in PEM format are currently accepted by xbps. - -Once the RSA private key is ready you can use it to initialize the repository metadata: - - $ xbps-rindex --sign --signedby "I'm Groot" --privkey privkey.pem $PWD/hostdir/binpkgs - -And then make a signature per package: - - $ xbps-rindex --sign-pkg --privkey privkey.pem $PWD/hostdir/binpkgs/*.xbps - -> If --privkey is unset, it defaults to `~/.ssh/id_rsa`. - -If the RSA key was protected with a passphrase you'll have to type it, or alternatively set -it via the `XBPS_PASSPHRASE` environment variable. - -Once the binary packages have been signed, check the repository contains the appropriate `hex fingerprint`: - - $ xbps-query --repository=hostdir/binpkgs -vL - ... - -Each time a binary package is created, a package signature must be created with `--sign-pkg`. - -> It is not possible to sign a repository with multiple RSA keys. - -<a name="rebuilding"></a> -### Rebuilding and overwriting existing local packages - -If for whatever reason a package has been built and it is available in your local repository -and you have to rebuild it without bumping its `version` or `revision` fields, it is possible -to accomplish this task easily with `xbps-src`: - - $ ./xbps-src -f pkg xbps - -Reinstalling this package in your target `rootdir` can be easily done too: - - $ xbps-install --repository=/path/to/local/repo -yff xbps-0.25_1 - -> Please note that the `package expression` must be properly defined to explicitly pick up -the package from the desired repository. - -<a name="distcc"></a> -### Enabling distcc for distributed compilation - -Setup the slaves (machines that will compile the code): - - # xbps-install -Sy distcc - -Modify the configuration to allow your local network machines to use distcc (e.g. `192.168.2.0/24`): - - # echo "192.168.2.0/24" >> /etc/distcc/clients.allow - -Enable and start the `distccd` service: - - # ln -s /etc/sv/distccd /var/service - -Install distcc on the host (machine that executes xbps-src) as well. -Unless you want to use the host as slave from other machines, there is no need -to modify the configuration. - -On the host you can now enable distcc in the `void-packages/etc/conf` file: - - XBPS_DISTCC=yes - XBPS_DISTCC_HOSTS="localhost/2 --localslots_cpp=24 192.168.2.101/9 192.168.2.102/2" - XBPS_MAKEJOBS=16 - -The example values assume a localhost CPU with 4 cores of which at most 2 are used for compiler jobs. -The number of slots for preprocessor jobs is set to 24 in order to have enough preprocessed data for other CPUs to compile. -The slave 192.168.2.101 has a CPU with 8 cores and the /9 for the number of jobs is a saturating choice. -The slave 192.168.2.102 is set to run at most 2 compile jobs to keep its load low, even if its CPU has 4 cores. -The XBPS_MAKEJOBS setting is increased to 16 to account for the possible parallelism (2 + 9 + 2 + some slack). - -<a name="distfiles-mirrors"></a> -### Distfiles mirror(s) - -In etc/conf you may optionally define a mirror or a list of mirrors to search for distfiles. - - $ echo 'XBPS_DISTFILES_MIRROR="ftp://192.168.100.5/gentoo/distfiles"' >> etc/conf - -If more than one mirror is to be searched, you can either specify multiple URLs separated -with blanks, or add to the variable like this - - $ echo 'XBPS_DISTFILES_MIRROR+=" https://sources.voidlinux.org/"' >> etc/conf - -Make sure to put the blank after the first double quote in this case. - -The mirrors are searched in order for the distfiles to build a package until the -checksum of the downloaded file matches the one specified in the template. - -Ultimately, if no mirror carries the distfile, or in case all downloads failed the -checksum verification, the original download location is used. - -If you use `proot` or `uchroot` for your XBPS_CHROOT_CMD, you may also specify a local path -using the `file://` prefix or simply an absolute path on your build host (e.g. /mnt/distfiles). -Mirror locations specified this way are bind mounted inside the chroot environment -under $XBPS_MASTERDIR and searched for distfiles just the same as remote locations. - -<a name="cross-compiling"></a> -### Cross compiling packages for a target architecture - -Currently `xbps-src` can cross build packages for some target architectures with a cross compiler. -The supported target is shown with `./xbps-src -h`. - -If a source package has been adapted to be **cross buildable** `xbps-src` will automatically build the binary package(s) with a simple command: - - $ ./xbps-src -a <target> pkg <pkgname> - -If the build for whatever reason fails, might be a new build issue or simply because it hasn't been adapted to be **cross compiled**. - -<a name="foreign"></a> -### Using xbps-src in a foreign Linux distribution - -xbps-src can be used in any recent Linux distribution matching the CPU architecture. - -To use xbps-src in your Linux distribution use the following instructions. Let's start downloading the xbps static binaries: - - $ wget http://alpha.de.repo.voidlinux.org/static/xbps-static-latest.<arch>-musl.tar.xz - $ mkdir ~/XBPS - $ tar xvf xbps-static-latest.<arch>.tar.xz -C ~/XBPS - $ export PATH=~/XBPS/usr/bin:$PATH - -If your system does not support `user namespaces`, a privileged group is required to be able to use -`xbps-uchroot(1)` with xbps-src, by default it's set to the `xbuilder` group, change this to your desired group: - - # chown root:<group> ~/XBPS/usr/bin/xbps-uchroot.static - # chmod 4750 ~/XBPS/usr/bin/xbps-uchroot.static - -Clone the `void-packages` git repository: - - $ git clone git://github.com/void-linux/void-packages - -and `xbps-src` should be fully functional; just start the `bootstrap` process, i.e: - - $ ./xbps-src binary-bootstrap - -The default masterdir is created in the current working directory, i.e `void-packages/masterdir`. - -<a name="remaking-masterdir"></a> -### Remaking the masterdir - -If for some reason you must update xbps-src and the `bootstrap-update` target is not enough, it's possible to recreate a masterdir with two simple commands (please note that `zap` keeps your `ccache/distcc/host` directories intact): - - $ ./xbps-src zap - $ ./xbps-src binary-bootstrap - -<a name="updating-masterdir"></a> -### Keeping your masterdir uptodate - -Sometimes the bootstrap packages must be updated to the latest available version in repositories, this is accomplished with the `bootstrap-update` target: - - $ ./xbps-src bootstrap-update - -<a name="building-32bit"></a> -### Building 32bit packages on x86_64 - -Two ways are available to build 32bit packages on x86\_64: - - - cross compilation mode - - native mode with a 32bit masterdir - -The first mode (cross compilation) is as easy as: - - $ ./xbps-src -a i686 pkg ... - -The second mode (native) needs a new x86 `masterdir`: - - $ ./xbps-src -m masterdir-x86 binary-bootstrap i686 - $ ./xbps-src -m masterdir-x86 ... - -<a name="building-for-musl"></a> -### Building packages natively for the musl C library - -A native build environment is required to be able to cross compile the bootstrap packages for the musl C library; this is accomplished by installing them via `binary-bootstrap`: - - $ ./xbps-src binary-bootstrap - -Now cross compile `base-chroot-musl` for your native architecture: - - $ ./xbps-src -a x86_64-musl pkg base-chroot-musl - -Wait until all packages are built and when ready, prepare a new masterdir with the musl packages: - - $ ./xbps-src -m masterdir-x86_64-musl binary-bootstrap x86_64-musl - -Your new masterdir is now ready to build packages natively for the musl C library. Try: - - $ ./xbps-src -m masterdir-x86_64-musl chroot - $ ldd - -To see if the musl C dynamic linker is working as expected. - -<a name="building-base-system"></a> -### Building void base-system from scratch - -To rebuild all packages in `base-system` for your native architecture: - - $ ./xbps-src -N pkg base-system - -It's also possible to cross compile everything from scratch: - - $ ./xbps-src -a <target> -N pkg base-system - -Once the build has finished, you can specify the path to the local repository to `void-mklive`, i.e: - - # cd void-mklive - # make - # ./mklive.sh ... -r /path/to/hostdir/binpkgs diff --git a/srcpkgs/dwm/files/config.h b/srcpkgs/dwm/files/config.h @@ -0,0 +1,129 @@ +/* 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 unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ +static const unsigned int systrayspacing = 2; /* systray spacing */ +static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/ +static const int showsystray = 1; /* 0 means no systray */ +static const int showbar = 1; /* 0 means no bar */ +static const int topbar = 1; /* 0 means bottom bar */ +static const char *fonts[] = { "monospace:size=10" }; +static const char dmenufont[] = "monospace:size=10"; +static const char col_gray1[] = "#2e3440"; +static const char col_gray2[] = "#2e3440"; +static const char col_gray3[] = "#81a1c1"; +static const char col_gray4[] = "#e5e9f0"; +static const char col_cyan[] = "#4c566a"; +static const char *colors[][3] = { + /* fg bg border */ + [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, + [SchemeSel] = { col_gray4, col_cyan, col_cyan }, +}; + +/* tagging */ +static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; + +static const Rule rules[] = { + /* xprop(1): + * WM_CLASS(STRING) = instance, class + * WM_NAME(STRING) = title + */ + /* class instance title tags mask isfloating monitor */ + { "Gimp", NULL, NULL, 0, 1, -1 }, + { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, + { "Fcitx-config-gtk3", NULL, NULL, 0, 1, -1 }, + /* { "TelegramDesktop", NULL, NULL, 1 << 3, 0, -1 }, */ + { "SimpleScreenRecorder", NULL, NULL, 0, 1, -1 }, + { "Audacity", NULL, NULL, 0, 1, -1 }, +}; + +/* 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 = 1; /* 1 means respect size hints in tiled resizals */ + +static const Layout layouts[] = { + /* symbol arrange function */ + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, +}; + +/* key definitions */ +#define MODKEY Mod4Mask +#define TAGKEYS(KEY,TAG) \ + { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ + { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \ + { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \ + { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} }, + +/* helper for spawning shell commands in the pre dwm-5.0 fashion */ +#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } + +/* commands */ +static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ +static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; +static const char *termcmd[] = { "st", NULL }; +static const char *mutecmd[] = {"amixer","-c","1","-q","sset","Master","toggle",NULL}; +static const char *lowervolcmd[] = {"amixer","-c","1","-q","sset","Master","1%-",NULL}; +static const char *raisevolcmd[] = {"amixer","-c","1","-q","sset","Master","1%+",NULL}; + +static Key keys[] = { + /* modifier key function argument */ + { MODKEY, XK_p, spawn, {.v = dmenucmd } }, + { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, + { MODKEY, XK_b, togglebar, {0} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY, 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, 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_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 } }, + TAGKEYS( XK_parenleft, 0) + TAGKEYS( XK_parenright, 1) + TAGKEYS( XK_braceright, 2) + TAGKEYS( XK_plus, 3) + TAGKEYS( XK_braceleft, 4) + TAGKEYS( XK_bracketright, 5) + TAGKEYS( XK_bracketleft, 6) + TAGKEYS( XK_exclam, 7) + TAGKEYS( XK_equal, 8) + { MODKEY|ShiftMask, XK_q, quit, {0} }, + { 0, 0x1008ff12,spawn, {.v = mutecmd } }, + { 0, 0x1008ff11,spawn, {.v = lowervolcmd } }, + { 0, 0x1008ff13,spawn, {.v = raisevolcmd } }, +}; + +/* button definitions */ +/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ +static Button buttons[] = { + /* click event mask button function argument */ + { ClkLtSymbol, 0, Button1, setlayout, {0} }, + { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, + { ClkWinTitle, 0, Button2, zoom, {0} }, + { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, + { 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} }, +}; + diff --git a/srcpkgs/dwm/files/dwm.desktop b/srcpkgs/dwm/files/dwm.desktop @@ -0,0 +1,7 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Dwm +Comment=Dynamic window manager +Exec=dwm +Icon=dwm +Type=XSession diff --git a/srcpkgs/dwm/patches/dwm-systray-6.2.diff b/srcpkgs/dwm/patches/dwm-systray-6.2.diff @@ -0,0 +1,746 @@ +From 4001ccae7b1a41bdcb247b0cf095a51af7b68c28 Mon Sep 17 00:00:00 2001 +From: Igor Gevka <igor.gevka@gmail.com> +Date: Sun, 16 Feb 2020 15:03:10 -0800 +Subject: [PATCH] [PATCH] Implements a system tray for dwm. + +Original author: Jan Christoph Ebersbach <jceb@e-jc.de>, inspired by http://code.google.com/p/dwm-plus +URL: http://dwm.suckless.org/patches/systray +dwm 6.2 port by Igor Gevka <igor.gevka@gmail.com> +--- + config.def.h | 4 + + dwm.c | 404 +++++++++++++++++++++++++++++++++++++++++++++++---- + 2 files changed, 382 insertions(+), 26 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 1c0b587..2d824d1 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -3,6 +3,10 @@ + /* appearance */ + static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ ++static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ ++static const unsigned int systrayspacing = 2; /* systray spacing */ ++static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/ ++static const int showsystray = 1; /* 0 means no systray */ + static const int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 means bottom bar */ + static const char *fonts[] = { "monospace:size=10" }; +diff --git a/dwm.c b/dwm.c +index 4465af1..3e361fa 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -57,12 +57,30 @@ + #define TAGMASK ((1 << LENGTH(tags)) - 1) + #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) + ++#define SYSTEM_TRAY_REQUEST_DOCK 0 ++ ++/* XEMBED messages */ ++#define XEMBED_EMBEDDED_NOTIFY 0 ++#define XEMBED_WINDOW_ACTIVATE 1 ++#define XEMBED_FOCUS_IN 4 ++#define XEMBED_MODALITY_ON 10 ++ ++#define XEMBED_MAPPED (1 << 0) ++#define XEMBED_WINDOW_ACTIVATE 1 ++#define XEMBED_WINDOW_DEACTIVATE 2 ++ ++#define VERSION_MAJOR 0 ++#define VERSION_MINOR 0 ++#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR ++ + /* enums */ + enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ + enum { SchemeNorm, SchemeSel }; /* color schemes */ + enum { NetSupported, NetWMName, NetWMState, NetWMCheck, ++ NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ ++enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */ + enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ + enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, + ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ +@@ -141,6 +159,12 @@ typedef struct { + int monitor; + } Rule; + ++typedef struct Systray Systray; ++struct Systray { ++ Window win; ++ Client *icons; ++}; ++ + /* function declarations */ + static void applyrules(Client *c); + static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); +@@ -169,8 +193,10 @@ static void focus(Client *c); + static void focusin(XEvent *e); + static void focusmon(const Arg *arg); + static void focusstack(const Arg *arg); ++static Atom getatomprop(Client *c, Atom prop); + static int getrootptr(int *x, int *y); + static long getstate(Window w); ++static unsigned int getsystraywidth(); + static int gettextprop(Window w, Atom atom, char *text, unsigned int size); + static void grabbuttons(Client *c, int focused); + static void grabkeys(void); +@@ -188,13 +214,16 @@ static void pop(Client *); + static void propertynotify(XEvent *e); + static void quit(const Arg *arg); + static Monitor *recttomon(int x, int y, int w, int h); ++static void removesystrayicon(Client *i); + static void resize(Client *c, int x, int y, int w, int h, int interact); ++static void resizebarwin(Monitor *m); + static void resizeclient(Client *c, int x, int y, int w, int h); + static void resizemouse(const Arg *arg); ++static void resizerequest(XEvent *e); + static void restack(Monitor *m); + static void run(void); + static void scan(void); +-static int sendevent(Client *c, Atom proto); ++static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4); + static void sendmon(Client *c, Monitor *m); + static void setclientstate(Client *c, long state); + static void setfocus(Client *c); +@@ -206,6 +235,7 @@ static void seturgent(Client *c, int urg); + static void showhide(Client *c); + static void sigchld(int unused); + static void spawn(const Arg *arg); ++static Monitor *systraytomon(Monitor *m); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); + static void tile(Monitor *); +@@ -223,18 +253,23 @@ static int updategeom(void); + static void updatenumlockmask(void); + static void updatesizehints(Client *c); + static void updatestatus(void); ++static void updatesystray(void); ++static void updatesystrayicongeom(Client *i, int w, int h); ++static void updatesystrayiconstate(Client *i, XPropertyEvent *ev); + static void updatetitle(Client *c); + static void updatewindowtype(Client *c); + static void updatewmhints(Client *c); + static void view(const Arg *arg); + static Client *wintoclient(Window w); + static Monitor *wintomon(Window w); ++static Client *wintosystrayicon(Window w); + static int xerror(Display *dpy, XErrorEvent *ee); + static int xerrordummy(Display *dpy, XErrorEvent *ee); + static int xerrorstart(Display *dpy, XErrorEvent *ee); + static void zoom(const Arg *arg); + + /* variables */ ++static Systray *systray = NULL; + static const char broken[] = "broken"; + static char stext[256]; + static int screen; +@@ -257,9 +292,10 @@ static void (*handler[LASTEvent]) (XEvent *) = { + [MapRequest] = maprequest, + [MotionNotify] = motionnotify, + [PropertyNotify] = propertynotify, ++ [ResizeRequest] = resizerequest, + [UnmapNotify] = unmapnotify + }; +-static Atom wmatom[WMLast], netatom[NetLast]; ++static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast]; + static int running = 1; + static Cur *cursor[CurLast]; + static Clr **scheme; +@@ -439,7 +475,7 @@ buttonpress(XEvent *e) + arg.ui = 1 << i; + } else if (ev->x < x + blw) + click = ClkLtSymbol; +- else if (ev->x > selmon->ww - TEXTW(stext)) ++ else if (ev->x > selmon->ww - TEXTW(stext) - getsystraywidth()) + click = ClkStatusText; + else + click = ClkWinTitle; +@@ -482,6 +518,11 @@ cleanup(void) + XUngrabKey(dpy, AnyKey, AnyModifier, root); + while (mons) + cleanupmon(mons); ++ if (showsystray) { ++ XUnmapWindow(dpy, systray->win); ++ XDestroyWindow(dpy, systray->win); ++ free(systray); ++ } + for (i = 0; i < CurLast; i++) + drw_cur_free(drw, cursor[i]); + for (i = 0; i < LENGTH(colors); i++) +@@ -512,9 +553,57 @@ cleanupmon(Monitor *mon) + void + clientmessage(XEvent *e) + { ++ XWindowAttributes wa; ++ XSetWindowAttributes swa; + XClientMessageEvent *cme = &e->xclient; + Client *c = wintoclient(cme->window); + ++ if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) { ++ /* add systray icons */ ++ if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { ++ if (!(c = (Client *)calloc(1, sizeof(Client)))) ++ die("fatal: could not malloc() %u bytes\n", sizeof(Client)); ++ if (!(c->win = cme->data.l[2])) { ++ free(c); ++ return; ++ } ++ c->mon = selmon; ++ c->next = systray->icons; ++ systray->icons = c; ++ if (!XGetWindowAttributes(dpy, c->win, &wa)) { ++ /* use sane defaults */ ++ wa.width = bh; ++ wa.height = bh; ++ wa.border_width = 0; ++ } ++ c->x = c->oldx = c->y = c->oldy = 0; ++ c->w = c->oldw = wa.width; ++ c->h = c->oldh = wa.height; ++ c->oldbw = wa.border_width; ++ c->bw = 0; ++ c->isfloating = True; ++ /* reuse tags field as mapped status */ ++ c->tags = 1; ++ updatesizehints(c); ++ updatesystrayicongeom(c, wa.width, wa.height); ++ XAddToSaveSet(dpy, c->win); ++ XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask); ++ XReparentWindow(dpy, c->win, systray->win, 0, 0); ++ /* use parents background color */ ++ swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; ++ XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa); ++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION); ++ /* FIXME not sure if I have to send these events, too */ ++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION); ++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION); ++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION); ++ XSync(dpy, False); ++ resizebarwin(selmon); ++ updatesystray(); ++ setclientstate(c, NormalState); ++ } ++ return; ++ } + if (!c) + return; + if (cme->message_type == netatom[NetWMState]) { +@@ -567,7 +656,7 @@ configurenotify(XEvent *e) + for (c = m->clients; c; c = c->next) + if (c->isfullscreen) + resizeclient(c, m->mx, m->my, m->mw, m->mh); +- XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); ++ resizebarwin(m); + } + focus(NULL); + arrange(NULL); +@@ -652,6 +741,11 @@ destroynotify(XEvent *e) + + if ((c = wintoclient(ev->window))) + unmanage(c, 1); ++ else if ((c = wintosystrayicon(ev->window))) { ++ removesystrayicon(c); ++ resizebarwin(selmon); ++ updatesystray(); ++ } + } + + void +@@ -695,19 +789,23 @@ dirtomon(int dir) + void + drawbar(Monitor *m) + { +- int x, w, sw = 0; ++ int x, w, sw = 0, stw = 0; + int boxs = drw->fonts->h / 9; + int boxw = drw->fonts->h / 6 + 2; + unsigned int i, occ = 0, urg = 0; + Client *c; + ++ if(showsystray && m == systraytomon(m)) ++ stw = getsystraywidth(); ++ + /* draw status first so it can be overdrawn by tags later */ + if (m == selmon) { /* status is only drawn on selected monitor */ + drw_setscheme(drw, scheme[SchemeNorm]); +- sw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ +- drw_text(drw, m->ww - sw, 0, sw, bh, 0, stext, 0); ++ sw = TEXTW(stext) - lrpad / 2 + 2; /* 2px right padding */ ++ drw_text(drw, m->ww - sw - stw, 0, sw, bh, lrpad / 2 - 2, stext, 0); + } + ++ resizebarwin(m); + for (c = m->clients; c; c = c->next) { + occ |= c->tags; + if (c->isurgent) +@@ -728,7 +826,7 @@ drawbar(Monitor *m) + drw_setscheme(drw, scheme[SchemeNorm]); + x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); + +- if ((w = m->ww - sw - x) > bh) { ++ if ((w = m->ww - sw - stw - x) > bh) { + if (m->sel) { + drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); +@@ -739,7 +837,7 @@ drawbar(Monitor *m) + drw_rect(drw, x, 0, w, bh, 1, 1); + } + } +- drw_map(drw, m->barwin, 0, 0, m->ww, bh); ++ drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh); + } + + void +@@ -776,8 +874,11 @@ expose(XEvent *e) + Monitor *m; + XExposeEvent *ev = &e->xexpose; + +- if (ev->count == 0 && (m = wintomon(ev->window))) ++ if (ev->count == 0 && (m = wintomon(ev->window))) { + drawbar(m); ++ if (m == selmon) ++ updatesystray(); ++ } + } + + void +@@ -862,10 +963,17 @@ getatomprop(Client *c, Atom prop) + unsigned long dl; + unsigned char *p = NULL; + Atom da, atom = None; ++ /* FIXME getatomprop should return the number of items and a pointer to ++ * the stored data instead of this workaround */ ++ Atom req = XA_ATOM; ++ if (prop == xatom[XembedInfo]) ++ req = xatom[XembedInfo]; + +- if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, ++ if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req, + &da, &di, &dl, &dl, &p) == Success && p) { + atom = *(Atom *)p; ++ if (da == xatom[XembedInfo] && dl == 2) ++ atom = ((Atom *)p)[1]; + XFree(p); + } + return atom; +@@ -899,6 +1007,16 @@ getstate(Window w) + return result; + } + ++unsigned int ++getsystraywidth() ++{ ++ unsigned int w = 0; ++ Client *i; ++ if(showsystray) ++ for(i = systray->icons; i; w += i->w + systrayspacing, i = i->next) ; ++ return w ? w + systrayspacing : 1; ++} ++ + int + gettextprop(Window w, Atom atom, char *text, unsigned int size) + { +@@ -1003,7 +1121,7 @@ killclient(const Arg *arg) + { + if (!selmon->sel) + return; +- if (!sendevent(selmon->sel, wmatom[WMDelete])) { ++ if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) { + XGrabServer(dpy); + XSetErrorHandler(xerrordummy); + XSetCloseDownMode(dpy, DestroyAll); +@@ -1091,6 +1209,12 @@ maprequest(XEvent *e) + { + static XWindowAttributes wa; + XMapRequestEvent *ev = &e->xmaprequest; ++ Client *i; ++ if ((i = wintosystrayicon(ev->window))) { ++ sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION); ++ resizebarwin(selmon); ++ updatesystray(); ++ } + + if (!XGetWindowAttributes(dpy, ev->window, &wa)) + return; +@@ -1215,6 +1339,16 @@ propertynotify(XEvent *e) + Window trans; + XPropertyEvent *ev = &e->xproperty; + ++ if ((c = wintosystrayicon(ev->window))) { ++ if (ev->atom == XA_WM_NORMAL_HINTS) { ++ updatesizehints(c); ++ updatesystrayicongeom(c, c->w, c->h); ++ } ++ else ++ updatesystrayiconstate(c, ev); ++ resizebarwin(selmon); ++ updatesystray(); ++ } + if ((ev->window == root) && (ev->atom == XA_WM_NAME)) + updatestatus(); + else if (ev->state == PropertyDelete) +@@ -1265,6 +1399,20 @@ recttomon(int x, int y, int w, int h) + return r; + } + ++void ++removesystrayicon(Client *i) ++{ ++ Client **ii; ++ ++ if (!showsystray || !i) ++ return; ++ for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next); ++ if (ii) ++ *ii = i->next; ++ free(i); ++} ++ ++ + void + resize(Client *c, int x, int y, int w, int h, int interact) + { +@@ -1272,6 +1420,14 @@ resize(Client *c, int x, int y, int w, int h, int interact) + resizeclient(c, x, y, w, h); + } + ++void ++resizebarwin(Monitor *m) { ++ unsigned int w = m->ww; ++ if (showsystray && m == systraytomon(m)) ++ w -= getsystraywidth(); ++ XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh); ++} ++ + void + resizeclient(Client *c, int x, int y, int w, int h) + { +@@ -1344,6 +1500,19 @@ resizemouse(const Arg *arg) + } + } + ++void ++resizerequest(XEvent *e) ++{ ++ XResizeRequestEvent *ev = &e->xresizerequest; ++ Client *i; ++ ++ if ((i = wintosystrayicon(ev->window))) { ++ updatesystrayicongeom(i, ev->width, ev->height); ++ resizebarwin(selmon); ++ updatesystray(); ++ } ++} ++ + void + restack(Monitor *m) + { +@@ -1433,26 +1602,36 @@ setclientstate(Client *c, long state) + } + + int +-sendevent(Client *c, Atom proto) ++sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4) + { + int n; +- Atom *protocols; ++ Atom *protocols, mt; + int exists = 0; + XEvent ev; + +- if (XGetWMProtocols(dpy, c->win, &protocols, &n)) { +- while (!exists && n--) +- exists = protocols[n] == proto; +- XFree(protocols); ++ if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) { ++ mt = wmatom[WMProtocols]; ++ if (XGetWMProtocols(dpy, w, &protocols, &n)) { ++ while (!exists && n--) ++ exists = protocols[n] == proto; ++ XFree(protocols); ++ } ++ } ++ else { ++ exists = True; ++ mt = proto; + } + if (exists) { + ev.type = ClientMessage; +- ev.xclient.window = c->win; +- ev.xclient.message_type = wmatom[WMProtocols]; ++ ev.xclient.window = w; ++ ev.xclient.message_type = mt; + ev.xclient.format = 32; +- ev.xclient.data.l[0] = proto; +- ev.xclient.data.l[1] = CurrentTime; +- XSendEvent(dpy, c->win, False, NoEventMask, &ev); ++ ev.xclient.data.l[0] = d0; ++ ev.xclient.data.l[1] = d1; ++ ev.xclient.data.l[2] = d2; ++ ev.xclient.data.l[3] = d3; ++ ev.xclient.data.l[4] = d4; ++ XSendEvent(dpy, w, False, mask, &ev); + } + return exists; + } +@@ -1466,7 +1645,7 @@ setfocus(Client *c) + XA_WINDOW, 32, PropModeReplace, + (unsigned char *) &(c->win), 1); + } +- sendevent(c, wmatom[WMTakeFocus]); ++ sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); + } + + void +@@ -1555,6 +1734,10 @@ setup(void) + wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); + netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); + netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); ++ netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False); ++ netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False); ++ netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False); ++ netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False); + netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); + netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); + netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False); +@@ -1562,6 +1745,9 @@ setup(void) + netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); + netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); + netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False); ++ xatom[Manager] = XInternAtom(dpy, "MANAGER", False); ++ xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False); ++ xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False); + /* init cursors */ + cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); + cursor[CurResize] = drw_cur_create(drw, XC_sizing); +@@ -1570,6 +1756,8 @@ setup(void) + scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); + for (i = 0; i < LENGTH(colors); i++) + scheme[i] = drw_scm_create(drw, colors[i], 3); ++ /* init system tray */ ++ updatesystray(); + /* init bars */ + updatebars(); + updatestatus(); +@@ -1701,7 +1889,18 @@ togglebar(const Arg *arg) + { + selmon->showbar = !selmon->showbar; + updatebarpos(selmon); +- XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); ++ resizebarwin(selmon); ++ if (showsystray) { ++ XWindowChanges wc; ++ if (!selmon->showbar) ++ wc.y = -bh; ++ else if (selmon->showbar) { ++ wc.y = 0; ++ if (!selmon->topbar) ++ wc.y = selmon->mh - bh; ++ } ++ XConfigureWindow(dpy, systray->win, CWY, &wc); ++ } + arrange(selmon); + } + +@@ -1796,11 +1995,18 @@ unmapnotify(XEvent *e) + else + unmanage(c, 0); + } ++ else if ((c = wintosystrayicon(ev->window))) { ++ /* KLUDGE! sometimes icons occasionally unmap their windows, but do ++ * _not_ destroy them. We map those windows back */ ++ XMapRaised(dpy, c->win); ++ updatesystray(); ++ } + } + + void + updatebars(void) + { ++ unsigned int w; + Monitor *m; + XSetWindowAttributes wa = { + .override_redirect = True, +@@ -1811,10 +2017,15 @@ updatebars(void) + for (m = mons; m; m = m->next) { + if (m->barwin) + continue; +- m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen), ++ w = m->ww; ++ if (showsystray && m == systraytomon(m)) ++ w -= getsystraywidth(); ++ m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen), + CopyFromParent, DefaultVisual(dpy, screen), + CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); + XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); ++ if (showsystray && m == systraytomon(m)) ++ XMapRaised(dpy, systray->win); + XMapRaised(dpy, m->barwin); + XSetClassHint(dpy, m->barwin, &ch); + } +@@ -1990,6 +2201,121 @@ updatestatus(void) + if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) + strcpy(stext, "dwm-"VERSION); + drawbar(selmon); ++ updatesystray(); ++} ++ ++void ++updatesystrayicongeom(Client *i, int w, int h) ++{ ++ if (i) { ++ i->h = bh; ++ if (w == h) ++ i->w = bh; ++ else if (h == bh) ++ i->w = w; ++ else ++ i->w = (int) ((float)bh * ((float)w / (float)h)); ++ applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False); ++ /* force icons into the systray dimensions if they don't want to */ ++ if (i->h > bh) { ++ if (i->w == i->h) ++ i->w = bh; ++ else ++ i->w = (int) ((float)bh * ((float)i->w / (float)i->h)); ++ i->h = bh; ++ } ++ } ++} ++ ++void ++updatesystrayiconstate(Client *i, XPropertyEvent *ev) ++{ ++ long flags; ++ int code = 0; ++ ++ if (!showsystray || !i || ev->atom != xatom[XembedInfo] || ++ !(flags = getatomprop(i, xatom[XembedInfo]))) ++ return; ++ ++ if (flags & XEMBED_MAPPED && !i->tags) { ++ i->tags = 1; ++ code = XEMBED_WINDOW_ACTIVATE; ++ XMapRaised(dpy, i->win); ++ setclientstate(i, NormalState); ++ } ++ else if (!(flags & XEMBED_MAPPED) && i->tags) { ++ i->tags = 0; ++ code = XEMBED_WINDOW_DEACTIVATE; ++ XUnmapWindow(dpy, i->win); ++ setclientstate(i, WithdrawnState); ++ } ++ else ++ return; ++ sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0, ++ systray->win, XEMBED_EMBEDDED_VERSION); ++} ++ ++void ++updatesystray(void) ++{ ++ XSetWindowAttributes wa; ++ XWindowChanges wc; ++ Client *i; ++ Monitor *m = systraytomon(NULL); ++ unsigned int x = m->mx + m->mw; ++ unsigned int w = 1; ++ ++ if (!showsystray) ++ return; ++ if (!systray) { ++ /* init systray */ ++ if (!(systray = (Systray *)calloc(1, sizeof(Systray)))) ++ die("fatal: could not malloc() %u bytes\n", sizeof(Systray)); ++ systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel][ColBg].pixel); ++ wa.event_mask = ButtonPressMask | ExposureMask; ++ wa.override_redirect = True; ++ wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; ++ XSelectInput(dpy, systray->win, SubstructureNotifyMask); ++ XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32, ++ PropModeReplace, (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 1); ++ XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel, &wa); ++ XMapRaised(dpy, systray->win); ++ XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime); ++ if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) { ++ sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0); ++ XSync(dpy, False); ++ } ++ else { ++ fprintf(stderr, "dwm: unable to obtain system tray.\n"); ++ free(systray); ++ systray = NULL; ++ return; ++ } ++ } ++ for (w = 0, i = systray->icons; i; i = i->next) { ++ /* make sure the background color stays the same */ ++ wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; ++ XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa); ++ XMapRaised(dpy, i->win); ++ w += systrayspacing; ++ i->x = w; ++ XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h); ++ w += i->w; ++ if (i->mon != m) ++ i->mon = m; ++ } ++ w = w ? w + systrayspacing : 1; ++ x -= w; ++ XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh); ++ wc.x = x; wc.y = m->by; wc.width = w; wc.height = bh; ++ wc.stack_mode = Above; wc.sibling = m->barwin; ++ XConfigureWindow(dpy, systray->win, CWX|CWY|CWWidth|CWHeight|CWSibling|CWStackMode, &wc); ++ XMapWindow(dpy, systray->win); ++ XMapSubwindows(dpy, systray->win); ++ /* redraw background */ ++ XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel); ++ XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh); ++ XSync(dpy, False); + } + + void +@@ -2057,6 +2383,16 @@ wintoclient(Window w) + return NULL; + } + ++Client * ++wintosystrayicon(Window w) { ++ Client *i = NULL; ++ ++ if (!showsystray || !w) ++ return i; ++ for (i = systray->icons; i && i->win != w; i = i->next) ; ++ return i; ++} ++ + Monitor * + wintomon(Window w) + { +@@ -2110,6 +2446,22 @@ xerrorstart(Display *dpy, XErrorEvent *ee) + return -1; + } + ++Monitor * ++systraytomon(Monitor *m) { ++ Monitor *t; ++ int i, n; ++ if(!systraypinning) { ++ if(!m) ++ return selmon; ++ return m == selmon ? m : NULL; ++ } ++ for(n = 1, t = mons; t && t->next; n++, t = t->next) ; ++ for(i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next) ; ++ if(systraypinningfailfirst && n < systraypinning) ++ return mons; ++ return t; ++} ++ + void + zoom(const Arg *arg) + { +-- +2.17.1 + diff --git a/srcpkgs/dwm/template b/srcpkgs/dwm/template @@ -0,0 +1,26 @@ +# Template file for 'dwm' +pkgname=dwm +version=6.2 +revision=1 +patch_args="-Np1" +makedepends="libXinerama-devel libXft-devel freetype-devel" +short_desc="Dynamic window manager for X" +maintainer="Nathan Owens <ndowens04@gmail.com>" +license="MIT" +homepage="http://dwm.suckless.org" +distfiles="https://dl.suckless.org/dwm/dwm-${version}.tar.gz" +checksum=97902e2e007aaeaa3c6e3bed1f81785b817b7413947f1db1d3b62b8da4cd110e + +do_build() { + [ -e ${FILESDIR}/config.h ] && cp ${FILESDIR}/config.h config.h + sed -i "/CFLAGS/s|\${CPPFLAGS}|& $CFLAGS|g" config.mk + sed -i "/LDFLAGS/s|\-s|$LDFLAGS|g" config.mk + make CC=$CC INCS="-I. -I${XBPS_CROSS_BASE}/usr/include/freetype2" LIBS="-lX11 -lXinerama -lXft -lfontconfig" +} + +do_install() { + make PREFIX=/usr DESTDIR=$DESTDIR install + vinstall README 644 usr/share/doc/$pkgname + vinstall ${FILESDIR}/dwm.desktop 644 usr/share/xsessions + vlicense LICENSE +}