mirror of
https://github.com/xmonad/xmonad.git
synced 2025-05-19 08:30:21 -07:00
Compare commits
176 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
fa8f34596d | ||
|
799b0dc199 | ||
|
8ff0fb7b52 | ||
|
7a93f11bfd | ||
|
c605d09681 | ||
|
ebf265a84c | ||
|
da4ef9ea37 | ||
|
0d90d183a7 | ||
|
756643c30e | ||
|
ca1ba91360 | ||
|
f2d1efbb6f | ||
|
4173227e04 | ||
|
3a37d4c1f8 | ||
|
bd99fd5f34 | ||
|
e9e1ad3190 | ||
|
07d95ad8fc | ||
|
39ae48970c | ||
|
eae89e25f9 | ||
|
ab6648ca8f | ||
|
5d73d294d4 | ||
|
1c57ed4c9a | ||
|
30d3f7159b | ||
|
81cf71d7c6 | ||
|
eba9e97794 | ||
|
aadb8df59b | ||
|
053c798085 | ||
|
a4140b9349 | ||
|
dad56b04f5 | ||
|
a58ccac7ba | ||
|
b1d9884d2d | ||
|
2ba1258cc1 | ||
|
bcf3bf6c77 | ||
|
8b54c11558 | ||
|
7de2d3e969 | ||
|
cfbf1ad51d | ||
|
21028ad648 | ||
|
4be171810c | ||
|
edadb427e7 | ||
|
38a303ea3e | ||
|
4620a705b4 | ||
|
7d588210e2 | ||
|
f09d7aa641 | ||
|
cde1a25bca | ||
|
383e3d6f47 | ||
|
81a80b8a5d | ||
|
ce22dbf7db | ||
|
88102c0afb | ||
|
804bef7bcf | ||
|
746880e9b9 | ||
|
82a7762f81 | ||
|
459f6afeca | ||
|
88b4ad3c13 | ||
|
7cb14762cb | ||
|
0ed6a2377e | ||
|
e5548547e3 | ||
|
4b9ef59706 | ||
|
5cf87c75cd | ||
|
c3acee78d0 | ||
|
1396343a58 | ||
|
c9334fbae7 | ||
|
c496c31158 | ||
|
31f63bb162 | ||
|
ddb4292d5a | ||
|
765e059470 | ||
|
c4cf4715f7 | ||
|
fa124f5658 | ||
|
855ff2f73c | ||
|
5a04fa185d | ||
|
706f54862c | ||
|
1d43cd203f | ||
|
8421b100dd | ||
|
0156e2963b | ||
|
32afd5e7e8 | ||
|
404e50d560 | ||
|
05d6037f53 | ||
|
2f58567912 | ||
|
f2aa84e102 | ||
|
2b7e278f7f | ||
|
bd69d20d01 | ||
|
35fa7bf4a2 | ||
|
a239a00977 | ||
|
afb66dd55c | ||
|
1b7dea7acc | ||
|
8e820945f4 | ||
|
21cc6ebd93 | ||
|
050ba6420d | ||
|
67b5510dde | ||
|
327c2cf0c1 | ||
|
96b3628b54 | ||
|
dc4d304802 | ||
|
c264e4cdb3 | ||
|
bb895d8415 | ||
|
897597463a | ||
|
937493256d | ||
|
8ec512b437 | ||
|
e563e01a5f | ||
|
0e4c1e6837 | ||
|
5c2ba06902 | ||
|
efffa8946a | ||
|
431bb4b57c | ||
|
3c80296733 | ||
|
f289b3b134 | ||
|
0932779f15 | ||
|
9138046ec5 | ||
|
a24e9b4c7f | ||
|
1aac6611d8 | ||
|
51e507e953 | ||
|
10abd059b7 | ||
|
d4c607c4f9 | ||
|
28bc7dacde | ||
|
b7a76a5e8c | ||
|
58f3e8c6f1 | ||
|
00045cfc2a | ||
|
69134f9e8a | ||
|
025a78508c | ||
|
b03fa7a67b | ||
|
64fbf6a09d | ||
|
eeac754ac7 | ||
|
5ee76ca48f | ||
|
aa9dd2696a | ||
|
19cba6b25f | ||
|
970893f556 | ||
|
1364ee4b1f | ||
|
a17fa0d28b | ||
|
b394435443 | ||
|
386d4e6295 | ||
|
ea295dabcc | ||
|
4b3e5e0d07 | ||
|
4b2107a07a | ||
|
3ae5f46052 | ||
|
f734f19c1a | ||
|
391c0fc0c9 | ||
|
5ecdf7591d | ||
|
301428e5df | ||
|
63f73e18f9 | ||
|
57c3a13125 | ||
|
e6329968ff | ||
|
c1670303c0 | ||
|
1d1c012cb9 | ||
|
a19ffb0404 | ||
|
5aa70bd88a | ||
|
2502fd8d55 | ||
|
d0942e37ad | ||
|
40f8246080 | ||
|
be8fd7fdc9 | ||
|
6e35910b62 | ||
|
2f2d105098 | ||
|
cd86480ff7 | ||
|
5c7c28060c | ||
|
78719507a9 | ||
|
f4d25fcef4 | ||
|
314390937c | ||
|
cf4d6f31b1 | ||
|
044d9244e5 | ||
|
ab99c17a68 | ||
|
d170e99bc5 | ||
|
96452213f4 | ||
|
c19eb06807 | ||
|
6d7da8dc25 | ||
|
f96b3f0398 | ||
|
34f257ad6f | ||
|
f94ad61a27 | ||
|
3977a7a4e2 | ||
|
3cd839f0ac | ||
|
a9abc4e09c | ||
|
25a4ed69da | ||
|
262dc4779f | ||
|
a2259bb309 | ||
|
3d8238b35d | ||
|
fd9de8903f | ||
|
fb1f33258e | ||
|
d0f12af1ae | ||
|
df6b40c980 | ||
|
b771abeadc | ||
|
2db596fbe8 | ||
|
0f31b24bd2 |
6
.github/workflows/generatemanpage.yml
vendored
6
.github/workflows/generatemanpage.yml
vendored
@ -10,7 +10,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Clone project
|
- name: Clone project
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
@ -26,8 +26,8 @@ jobs:
|
|||||||
- name: Commit/push if changed
|
- name: Commit/push if changed
|
||||||
run: |
|
run: |
|
||||||
set -ex
|
set -ex
|
||||||
git config user.name github-actions
|
git config user.name 'github-actions[bot]'
|
||||||
git config user.email github-actions@github.com
|
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
|
||||||
git diff --quiet --exit-code && exit
|
git diff --quiet --exit-code && exit
|
||||||
git commit -a -m 'man: Update'
|
git commit -a -m 'man: Update'
|
||||||
git push
|
git push
|
||||||
|
31
.github/workflows/haskell-ci-hackage.patch
vendored
31
.github/workflows/haskell-ci-hackage.patch
vendored
@ -37,36 +37,43 @@ set in GitHub repository secrets.
|
|||||||
jobs:
|
jobs:
|
||||||
linux:
|
linux:
|
||||||
name: Haskell-CI - Linux - ${{ matrix.compiler }}
|
name: Haskell-CI - Linux - ${{ matrix.compiler }}
|
||||||
@@ -31,6 +38,7 @@
|
@@ -33,6 +40,7 @@
|
||||||
compilerVersion: 9.0.2
|
compilerVersion: 9.8.4
|
||||||
setup-method: ghcup
|
setup-method: ghcup
|
||||||
allow-failure: false
|
allow-failure: false
|
||||||
+ upload: true
|
+ upload: true
|
||||||
- compiler: ghc-8.10.7
|
- compiler: ghc-9.6.7
|
||||||
compilerKind: ghc
|
compilerKind: ghc
|
||||||
compilerVersion: 8.10.7
|
compilerVersion: 9.6.7
|
||||||
@@ -237,7 +237,7 @@
|
@@ -257,6 +265,10 @@
|
||||||
${CABAL} -vnormal check
|
|
||||||
- name: haddock
|
- name: haddock
|
||||||
run: |
|
run: |
|
||||||
- $CABAL v2-haddock --disable-documentation $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
|
$CABAL v2-haddock --disable-documentation $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
|
||||||
|
+ - name: haddock for hackage
|
||||||
|
+ if: matrix.upload
|
||||||
|
+ run: |
|
||||||
+ $CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH --haddock-for-hackage --builddir $GITHUB_WORKSPACE/haddock all
|
+ $CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH --haddock-for-hackage --builddir $GITHUB_WORKSPACE/haddock all
|
||||||
- name: unconstrained build
|
- name: unconstrained build
|
||||||
run: |
|
run: |
|
||||||
rm -f cabal.project.local
|
rm -f cabal.project.local
|
||||||
@@ -248,3 +248,75 @@
|
@@ -267,3 +279,80 @@
|
||||||
with:
|
with:
|
||||||
key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
|
key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
|
||||||
path: ~/.cabal/store
|
path: ~/.cabal/store
|
||||||
+ - name: upload artifacts (sdist)
|
+ # must be separate artifacts because GitHub Actions are still broken:
|
||||||
|
+ # https://github.com/actions/upload-artifact/issues/441
|
||||||
|
+ # https://github.com/actions/upload-artifact/issues/457
|
||||||
|
+ - name: upload artifact (sdist)
|
||||||
+ if: matrix.upload
|
+ if: matrix.upload
|
||||||
+ uses: actions/upload-artifact@v3
|
+ uses: actions/upload-artifact@v4
|
||||||
+ with:
|
+ with:
|
||||||
|
+ name: sdist
|
||||||
+ path: ${{ github.workspace }}/sdist/*.tar.gz
|
+ path: ${{ github.workspace }}/sdist/*.tar.gz
|
||||||
+ - name: upload artifacts (haddock)
|
+ - name: upload artifact (haddock)
|
||||||
+ if: matrix.upload
|
+ if: matrix.upload
|
||||||
+ uses: actions/upload-artifact@v3
|
+ uses: actions/upload-artifact@v4
|
||||||
+ with:
|
+ with:
|
||||||
|
+ name: haddock
|
||||||
+ path: ${{ github.workspace }}/haddock/*-docs.tar.gz
|
+ path: ${{ github.workspace }}/haddock/*-docs.tar.gz
|
||||||
+ - name: hackage upload (candidate)
|
+ - name: hackage upload (candidate)
|
||||||
+ if: matrix.upload && github.event_name == 'workflow_dispatch' && github.event.inputs.version != ''
|
+ if: matrix.upload && github.event_name == 'workflow_dispatch' && github.event.inputs.version != ''
|
||||||
|
125
.github/workflows/haskell-ci.yml
vendored
125
.github/workflows/haskell-ci.yml
vendored
@ -8,9 +8,9 @@
|
|||||||
#
|
#
|
||||||
# For more information, see https://github.com/haskell-CI/haskell-ci
|
# For more information, see https://github.com/haskell-CI/haskell-ci
|
||||||
#
|
#
|
||||||
# version: 0.15.20230312
|
# version: 0.19.20250506
|
||||||
#
|
#
|
||||||
# REGENDATA ("0.15.20230312",["github","cabal.project"])
|
# REGENDATA ("0.19.20250506",["github","cabal.project"])
|
||||||
#
|
#
|
||||||
name: Haskell-CI
|
name: Haskell-CI
|
||||||
on:
|
on:
|
||||||
@ -26,28 +26,44 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
linux:
|
linux:
|
||||||
name: Haskell-CI - Linux - ${{ matrix.compiler }}
|
name: Haskell-CI - Linux - ${{ matrix.compiler }}
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-24.04
|
||||||
timeout-minutes:
|
timeout-minutes:
|
||||||
60
|
60
|
||||||
container:
|
container:
|
||||||
image: buildpack-deps:bionic
|
image: buildpack-deps:jammy
|
||||||
continue-on-error: ${{ matrix.allow-failure }}
|
continue-on-error: ${{ matrix.allow-failure }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- compiler: ghc-9.6.1
|
- compiler: ghc-9.12.2
|
||||||
compilerKind: ghc
|
compilerKind: ghc
|
||||||
compilerVersion: 9.6.1
|
compilerVersion: 9.12.2
|
||||||
setup-method: ghcup
|
setup-method: ghcup
|
||||||
allow-failure: false
|
allow-failure: false
|
||||||
- compiler: ghc-9.4.4
|
- compiler: ghc-9.10.2
|
||||||
compilerKind: ghc
|
compilerKind: ghc
|
||||||
compilerVersion: 9.4.4
|
compilerVersion: 9.10.2
|
||||||
setup-method: ghcup
|
setup-method: ghcup
|
||||||
allow-failure: false
|
allow-failure: false
|
||||||
- compiler: ghc-9.2.7
|
- compiler: ghc-9.8.4
|
||||||
compilerKind: ghc
|
compilerKind: ghc
|
||||||
compilerVersion: 9.2.7
|
compilerVersion: 9.8.4
|
||||||
|
setup-method: ghcup
|
||||||
|
allow-failure: false
|
||||||
|
upload: true
|
||||||
|
- compiler: ghc-9.6.7
|
||||||
|
compilerKind: ghc
|
||||||
|
compilerVersion: 9.6.7
|
||||||
|
setup-method: ghcup
|
||||||
|
allow-failure: false
|
||||||
|
- compiler: ghc-9.4.8
|
||||||
|
compilerKind: ghc
|
||||||
|
compilerVersion: 9.4.8
|
||||||
|
setup-method: ghcup
|
||||||
|
allow-failure: false
|
||||||
|
- compiler: ghc-9.2.8
|
||||||
|
compilerKind: ghc
|
||||||
|
compilerVersion: 9.2.8
|
||||||
setup-method: ghcup
|
setup-method: ghcup
|
||||||
allow-failure: false
|
allow-failure: false
|
||||||
- compiler: ghc-9.0.2
|
- compiler: ghc-9.0.2
|
||||||
@ -55,7 +71,6 @@ jobs:
|
|||||||
compilerVersion: 9.0.2
|
compilerVersion: 9.0.2
|
||||||
setup-method: ghcup
|
setup-method: ghcup
|
||||||
allow-failure: false
|
allow-failure: false
|
||||||
upload: true
|
|
||||||
- compiler: ghc-8.10.7
|
- compiler: ghc-8.10.7
|
||||||
compilerKind: ghc
|
compilerKind: ghc
|
||||||
compilerVersion: 8.10.7
|
compilerVersion: 8.10.7
|
||||||
@ -64,36 +79,39 @@ jobs:
|
|||||||
- compiler: ghc-8.8.4
|
- compiler: ghc-8.8.4
|
||||||
compilerKind: ghc
|
compilerKind: ghc
|
||||||
compilerVersion: 8.8.4
|
compilerVersion: 8.8.4
|
||||||
setup-method: hvr-ppa
|
setup-method: ghcup
|
||||||
allow-failure: false
|
allow-failure: false
|
||||||
- compiler: ghc-8.6.5
|
- compiler: ghc-8.6.5
|
||||||
compilerKind: ghc
|
compilerKind: ghc
|
||||||
compilerVersion: 8.6.5
|
compilerVersion: 8.6.5
|
||||||
setup-method: hvr-ppa
|
setup-method: ghcup
|
||||||
allow-failure: false
|
allow-failure: false
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
steps:
|
steps:
|
||||||
- name: apt
|
- name: apt-get install
|
||||||
run: |
|
run: |
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common libtinfo5
|
apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common libtinfo5
|
||||||
if [ "${{ matrix.setup-method }}" = ghcup ]; then
|
apt-get install -y libx11-dev libxext-dev libxinerama-dev libxrandr-dev libxss-dev
|
||||||
mkdir -p "$HOME/.ghcup/bin"
|
- name: Install GHCup
|
||||||
curl -sL https://downloads.haskell.org/ghcup/0.1.18.0/x86_64-linux-ghcup-0.1.18.0 > "$HOME/.ghcup/bin/ghcup"
|
run: |
|
||||||
chmod a+x "$HOME/.ghcup/bin/ghcup"
|
mkdir -p "$HOME/.ghcup/bin"
|
||||||
"$HOME/.ghcup/bin/ghcup" install ghc "$HCVER" || (cat "$HOME"/.ghcup/logs/*.* && false)
|
curl -sL https://downloads.haskell.org/ghcup/0.1.50.1/x86_64-linux-ghcup-0.1.50.1 > "$HOME/.ghcup/bin/ghcup"
|
||||||
"$HOME/.ghcup/bin/ghcup" install cabal 3.10.1.0 || (cat "$HOME"/.ghcup/logs/*.* && false)
|
chmod a+x "$HOME/.ghcup/bin/ghcup"
|
||||||
apt-get update
|
- name: Install cabal-install
|
||||||
apt-get install -y libx11-dev libxext-dev libxinerama-dev libxrandr-dev libxss-dev
|
run: |
|
||||||
else
|
"$HOME/.ghcup/bin/ghcup" install cabal 3.14.2.0 || (cat "$HOME"/.ghcup/logs/*.* && false)
|
||||||
apt-add-repository -y 'ppa:hvr/ghc'
|
echo "CABAL=$HOME/.ghcup/bin/cabal-3.14.2.0 -vnormal+nowrap" >> "$GITHUB_ENV"
|
||||||
apt-get update
|
- name: Install GHC (GHCup)
|
||||||
apt-get install -y "$HCNAME" libx11-dev libxext-dev libxinerama-dev libxrandr-dev libxss-dev
|
if: matrix.setup-method == 'ghcup'
|
||||||
mkdir -p "$HOME/.ghcup/bin"
|
run: |
|
||||||
curl -sL https://downloads.haskell.org/ghcup/0.1.18.0/x86_64-linux-ghcup-0.1.18.0 > "$HOME/.ghcup/bin/ghcup"
|
"$HOME/.ghcup/bin/ghcup" install ghc "$HCVER" || (cat "$HOME"/.ghcup/logs/*.* && false)
|
||||||
chmod a+x "$HOME/.ghcup/bin/ghcup"
|
HC=$("$HOME/.ghcup/bin/ghcup" whereis ghc "$HCVER")
|
||||||
"$HOME/.ghcup/bin/ghcup" install cabal 3.10.1.0 || (cat "$HOME"/.ghcup/logs/*.* && false)
|
HCPKG=$(echo "$HC" | sed 's#ghc$#ghc-pkg#')
|
||||||
fi
|
HADDOCK=$(echo "$HC" | sed 's#ghc$#haddock#')
|
||||||
|
echo "HC=$HC" >> "$GITHUB_ENV"
|
||||||
|
echo "HCPKG=$HCPKG" >> "$GITHUB_ENV"
|
||||||
|
echo "HADDOCK=$HADDOCK" >> "$GITHUB_ENV"
|
||||||
env:
|
env:
|
||||||
HCKIND: ${{ matrix.compilerKind }}
|
HCKIND: ${{ matrix.compilerKind }}
|
||||||
HCNAME: ${{ matrix.compiler }}
|
HCNAME: ${{ matrix.compiler }}
|
||||||
@ -104,28 +122,12 @@ jobs:
|
|||||||
echo "LANG=C.UTF-8" >> "$GITHUB_ENV"
|
echo "LANG=C.UTF-8" >> "$GITHUB_ENV"
|
||||||
echo "CABAL_DIR=$HOME/.cabal" >> "$GITHUB_ENV"
|
echo "CABAL_DIR=$HOME/.cabal" >> "$GITHUB_ENV"
|
||||||
echo "CABAL_CONFIG=$HOME/.cabal/config" >> "$GITHUB_ENV"
|
echo "CABAL_CONFIG=$HOME/.cabal/config" >> "$GITHUB_ENV"
|
||||||
HCDIR=/opt/$HCKIND/$HCVER
|
|
||||||
if [ "${{ matrix.setup-method }}" = ghcup ]; then
|
|
||||||
HC=$HOME/.ghcup/bin/$HCKIND-$HCVER
|
|
||||||
echo "HC=$HC" >> "$GITHUB_ENV"
|
|
||||||
echo "HCPKG=$HOME/.ghcup/bin/$HCKIND-pkg-$HCVER" >> "$GITHUB_ENV"
|
|
||||||
echo "HADDOCK=$HOME/.ghcup/bin/haddock-$HCVER" >> "$GITHUB_ENV"
|
|
||||||
echo "CABAL=$HOME/.ghcup/bin/cabal-3.10.1.0 -vnormal+nowrap" >> "$GITHUB_ENV"
|
|
||||||
else
|
|
||||||
HC=$HCDIR/bin/$HCKIND
|
|
||||||
echo "HC=$HC" >> "$GITHUB_ENV"
|
|
||||||
echo "HCPKG=$HCDIR/bin/$HCKIND-pkg" >> "$GITHUB_ENV"
|
|
||||||
echo "HADDOCK=$HCDIR/bin/haddock" >> "$GITHUB_ENV"
|
|
||||||
echo "CABAL=$HOME/.ghcup/bin/cabal-3.10.1.0 -vnormal+nowrap" >> "$GITHUB_ENV"
|
|
||||||
fi
|
|
||||||
|
|
||||||
HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
|
HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
|
||||||
echo "HCNUMVER=$HCNUMVER" >> "$GITHUB_ENV"
|
echo "HCNUMVER=$HCNUMVER" >> "$GITHUB_ENV"
|
||||||
echo "ARG_TESTS=--enable-tests" >> "$GITHUB_ENV"
|
echo "ARG_TESTS=--enable-tests" >> "$GITHUB_ENV"
|
||||||
echo "ARG_BENCH=--enable-benchmarks" >> "$GITHUB_ENV"
|
echo "ARG_BENCH=--enable-benchmarks" >> "$GITHUB_ENV"
|
||||||
echo "HEADHACKAGE=false" >> "$GITHUB_ENV"
|
echo "HEADHACKAGE=false" >> "$GITHUB_ENV"
|
||||||
echo "ARG_COMPILER=--$HCKIND --with-compiler=$HC" >> "$GITHUB_ENV"
|
echo "ARG_COMPILER=--$HCKIND --with-compiler=$HC" >> "$GITHUB_ENV"
|
||||||
echo "GHCJSARITH=0" >> "$GITHUB_ENV"
|
|
||||||
env:
|
env:
|
||||||
HCKIND: ${{ matrix.compilerKind }}
|
HCKIND: ${{ matrix.compilerKind }}
|
||||||
HCNAME: ${{ matrix.compiler }}
|
HCNAME: ${{ matrix.compiler }}
|
||||||
@ -168,14 +170,14 @@ jobs:
|
|||||||
- name: install cabal-plan
|
- name: install cabal-plan
|
||||||
run: |
|
run: |
|
||||||
mkdir -p $HOME/.cabal/bin
|
mkdir -p $HOME/.cabal/bin
|
||||||
curl -sL https://github.com/haskell-hvr/cabal-plan/releases/download/v0.6.2.0/cabal-plan-0.6.2.0-x86_64-linux.xz > cabal-plan.xz
|
curl -sL https://github.com/haskell-hvr/cabal-plan/releases/download/v0.7.3.0/cabal-plan-0.7.3.0-x86_64-linux.xz > cabal-plan.xz
|
||||||
echo 'de73600b1836d3f55e32d80385acc055fd97f60eaa0ab68a755302685f5d81bc cabal-plan.xz' | sha256sum -c -
|
echo 'f62ccb2971567a5f638f2005ad3173dba14693a45154c1508645c52289714cb2 cabal-plan.xz' | sha256sum -c -
|
||||||
xz -d < cabal-plan.xz > $HOME/.cabal/bin/cabal-plan
|
xz -d < cabal-plan.xz > $HOME/.cabal/bin/cabal-plan
|
||||||
rm -f cabal-plan.xz
|
rm -f cabal-plan.xz
|
||||||
chmod a+x $HOME/.cabal/bin/cabal-plan
|
chmod a+x $HOME/.cabal/bin/cabal-plan
|
||||||
cabal-plan --version
|
cabal-plan --version
|
||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
path: source
|
path: source
|
||||||
- name: initial cabal.project for sdist
|
- name: initial cabal.project for sdist
|
||||||
@ -207,7 +209,7 @@ jobs:
|
|||||||
package xmonad
|
package xmonad
|
||||||
flags: +pedantic
|
flags: +pedantic
|
||||||
EOF
|
EOF
|
||||||
$HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(xmonad)$/; }' >> cabal.project.local
|
$HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: any.$_ installed\n" unless /^(xmonad)$/; }' >> cabal.project.local
|
||||||
cat cabal.project
|
cat cabal.project
|
||||||
cat cabal.project.local
|
cat cabal.project.local
|
||||||
- name: dump install plan
|
- name: dump install plan
|
||||||
@ -215,7 +217,7 @@ jobs:
|
|||||||
$CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
|
$CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
|
||||||
cabal-plan
|
cabal-plan
|
||||||
- name: restore cache
|
- name: restore cache
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v4
|
||||||
with:
|
with:
|
||||||
key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
|
key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
|
||||||
path: ~/.cabal/store
|
path: ~/.cabal/store
|
||||||
@ -238,6 +240,10 @@ jobs:
|
|||||||
cd ${PKGDIR_xmonad} || false
|
cd ${PKGDIR_xmonad} || false
|
||||||
${CABAL} -vnormal check
|
${CABAL} -vnormal check
|
||||||
- name: haddock
|
- name: haddock
|
||||||
|
run: |
|
||||||
|
$CABAL v2-haddock --disable-documentation $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
|
||||||
|
- name: haddock for hackage
|
||||||
|
if: matrix.upload
|
||||||
run: |
|
run: |
|
||||||
$CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH --haddock-for-hackage --builddir $GITHUB_WORKSPACE/haddock all
|
$CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH --haddock-for-hackage --builddir $GITHUB_WORKSPACE/haddock all
|
||||||
- name: unconstrained build
|
- name: unconstrained build
|
||||||
@ -245,20 +251,25 @@ jobs:
|
|||||||
rm -f cabal.project.local
|
rm -f cabal.project.local
|
||||||
$CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
|
$CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
|
||||||
- name: save cache
|
- name: save cache
|
||||||
uses: actions/cache/save@v3
|
|
||||||
if: always()
|
if: always()
|
||||||
|
uses: actions/cache/save@v4
|
||||||
with:
|
with:
|
||||||
key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
|
key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
|
||||||
path: ~/.cabal/store
|
path: ~/.cabal/store
|
||||||
- name: upload artifacts (sdist)
|
# must be separate artifacts because GitHub Actions are still broken:
|
||||||
|
# https://github.com/actions/upload-artifact/issues/441
|
||||||
|
# https://github.com/actions/upload-artifact/issues/457
|
||||||
|
- name: upload artifact (sdist)
|
||||||
if: matrix.upload
|
if: matrix.upload
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
|
name: sdist
|
||||||
path: ${{ github.workspace }}/sdist/*.tar.gz
|
path: ${{ github.workspace }}/sdist/*.tar.gz
|
||||||
- name: upload artifacts (haddock)
|
- name: upload artifact (haddock)
|
||||||
if: matrix.upload
|
if: matrix.upload
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
|
name: haddock
|
||||||
path: ${{ github.workspace }}/haddock/*-docs.tar.gz
|
path: ${{ github.workspace }}/haddock/*-docs.tar.gz
|
||||||
- name: hackage upload (candidate)
|
- name: hackage upload (candidate)
|
||||||
if: matrix.upload && github.event_name == 'workflow_dispatch' && github.event.inputs.version != ''
|
if: matrix.upload && github.event_name == 'workflow_dispatch' && github.event.inputs.version != ''
|
||||||
|
6
.github/workflows/hlint.yaml
vendored
6
.github/workflows/hlint.yaml
vendored
@ -8,15 +8,15 @@ jobs:
|
|||||||
hlint:
|
hlint:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: 'Set up HLint'
|
- name: 'Set up HLint'
|
||||||
uses: haskell/actions/hlint-setup@v2
|
uses: haskell-actions/hlint-setup@v2
|
||||||
with:
|
with:
|
||||||
version: '3.5'
|
version: '3.5'
|
||||||
|
|
||||||
- name: 'Run HLint'
|
- name: 'Run HLint'
|
||||||
uses: haskell/actions/hlint-run@v2
|
uses: haskell-actions/hlint-run@v2
|
||||||
with:
|
with:
|
||||||
path: '.'
|
path: '.'
|
||||||
fail-on: status
|
fail-on: status
|
||||||
|
12
.github/workflows/nix.yml
vendored
12
.github/workflows/nix.yml
vendored
@ -6,20 +6,16 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-20.04 # FIXME
|
runs-on: ubuntu-latest
|
||||||
name: Nix Flake - Linux
|
name: Nix Flake - Linux
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v18
|
uses: cachix/install-nix-action@v31
|
||||||
with:
|
with:
|
||||||
install_url: https://nixos-nix-install-tests.cachix.org/serve/i6laym9jw3wg9mw6ncyrk6gjx4l34vvx/install
|
github_access_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
install_options: '--tarball-url-prefix https://nixos-nix-install-tests.cachix.org/serve'
|
|
||||||
extra_nix_config: |
|
|
||||||
experimental-features = nix-command flakes
|
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Clone project
|
- name: Clone project
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Build
|
- name: Build
|
||||||
run: nix build --print-build-logs
|
run: nix build --print-build-logs
|
||||||
|
14
.github/workflows/packdeps.yml
vendored
14
.github/workflows/packdeps.yml
vendored
@ -13,16 +13,15 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clone project
|
- name: Clone project
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Setup Haskell
|
- name: Setup Haskell
|
||||||
uses: haskell/actions/setup@v2
|
uses: haskell-actions/setup@v2
|
||||||
with:
|
with:
|
||||||
# packdeps doesn't build with newer as of 2021-10
|
# packdeps doesn't build with newer as of 2021-10
|
||||||
ghc-version: '8.8'
|
ghc-version: '8.8'
|
||||||
- name: Install packdeps
|
- name: Install packdeps
|
||||||
run: |
|
run: |
|
||||||
set -ex
|
set -ex
|
||||||
echo "$HOME/.cabal/bin" >> $GITHUB_PATH
|
|
||||||
cd # go somewhere without a cabal.project
|
cd # go somewhere without a cabal.project
|
||||||
cabal install packdeps
|
cabal install packdeps
|
||||||
- name: Check package bounds (all)
|
- name: Check package bounds (all)
|
||||||
@ -41,10 +40,9 @@ jobs:
|
|||||||
*.cabal
|
*.cabal
|
||||||
|
|
||||||
workflow-keepalive:
|
workflow-keepalive:
|
||||||
|
if: github.event_name == 'schedule'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
actions: write
|
||||||
steps:
|
steps:
|
||||||
- name: Re-enable workflow
|
- uses: liskin/gh-workflow-keepalive@v1
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
run: |
|
|
||||||
gh api -X PUT repos/${{ github.repository }}/actions/workflows/packdeps.yml/enable
|
|
||||||
|
9
.github/workflows/stack.yml
vendored
9
.github/workflows/stack.yml
vendored
@ -17,10 +17,13 @@ jobs:
|
|||||||
- resolver: lts-18 # GHC 8.10
|
- resolver: lts-18 # GHC 8.10
|
||||||
- resolver: lts-19 # GHC 9.0
|
- resolver: lts-19 # GHC 9.0
|
||||||
- resolver: lts-20 # GHC 9.2
|
- resolver: lts-20 # GHC 9.2
|
||||||
|
- resolver: lts-21 # GHC 9.4
|
||||||
|
- resolver: lts-22 # GHC 9.6
|
||||||
|
- resolver: lts-23 # GHC 9.8
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clone project
|
- name: Clone project
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install C dependencies
|
- name: Install C dependencies
|
||||||
run: |
|
run: |
|
||||||
@ -44,13 +47,13 @@ jobs:
|
|||||||
date +date=1-%Y-%m >> $GITHUB_OUTPUT
|
date +date=1-%Y-%m >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Cache Haskell package metadata
|
- name: Cache Haskell package metadata
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ~/.stack/pantry
|
path: ~/.stack/pantry
|
||||||
key: stack-pantry-${{ runner.os }}-${{ steps.cache-date.outputs.date }}
|
key: stack-pantry-${{ runner.os }}-${{ steps.cache-date.outputs.date }}
|
||||||
|
|
||||||
- name: Cache Haskell dependencies
|
- name: Cache Haskell dependencies
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.stack/*
|
~/.stack/*
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -27,3 +27,6 @@ tags
|
|||||||
/cabal.sandbox.config
|
/cabal.sandbox.config
|
||||||
/dist-newstyle/
|
/dist-newstyle/
|
||||||
/dist/
|
/dist/
|
||||||
|
|
||||||
|
# nix artifacts
|
||||||
|
result
|
||||||
|
3
.mailmap
3
.mailmap
@ -35,4 +35,5 @@ Valery V. Vorotyntsev <valery.vv@gmail.com>
|
|||||||
Vanessa McHale <vamchale@gmail.com> <vanessa.mchale@reconfigure.io>
|
Vanessa McHale <vamchale@gmail.com> <vanessa.mchale@reconfigure.io>
|
||||||
Wirt Wolff <wirtwolff@gmail.com>
|
Wirt Wolff <wirtwolff@gmail.com>
|
||||||
|
|
||||||
slotThe <soliditsallgood@mailbox.org> <50166980+slotThe@users.noreply.github.com>
|
Tony Zorman <soliditsallgood@mailbox.org> <50166980+slotThe@users.noreply.github.com>
|
||||||
|
Tony Zorman <soliditsallgood@mailbox.org>
|
||||||
|
58
CHANGES.md
58
CHANGES.md
@ -1,5 +1,57 @@
|
|||||||
# Change Log / Release Notes
|
# Change Log / Release Notes
|
||||||
|
|
||||||
|
## _unreleased_
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
* Use `cabal` for `--recompile` if there is a `.cabal` file in the config
|
||||||
|
directory and none of `build`, `stack.yaml`, `flake.nix`, nor `default.nix`
|
||||||
|
exist.
|
||||||
|
|
||||||
|
### Enhancements
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
### Other
|
||||||
|
|
||||||
|
PR #404 (see last change in 0.17.1) has been reverted, because the affected
|
||||||
|
compilers are (hopefully) no longer being used.
|
||||||
|
|
||||||
|
All 9.0 releases of GHC, plus 9.2.1 and 9.2.2 have the join point bug.
|
||||||
|
Note that 9.0.x is known to also have GC issues and is officially deprecated,
|
||||||
|
and the only 9.2 release that should be used is 9.2.8. Additionally, GHC HQ
|
||||||
|
doesn't support releases before 9.6.6.
|
||||||
|
|
||||||
|
## 0.18.0 (February 3, 2024)
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
* Dropped support for GHC 8.4.
|
||||||
|
|
||||||
|
### Enhancements
|
||||||
|
|
||||||
|
* Exported `sendRestart` and `sendReplace` from `XMonad.Operations`.
|
||||||
|
|
||||||
|
* Exported `buildLaunch` from `XMonad.Main`.
|
||||||
|
|
||||||
|
* `Tall` does not draw windows with zero area.
|
||||||
|
|
||||||
|
* `XMonad.Operations.floatLocation` now applies size hints. This means windows
|
||||||
|
will snap to these hints as soon as they're floated (mouse move, keybinding).
|
||||||
|
Previously that only happened on mouse resize.
|
||||||
|
|
||||||
|
* Recompilation now detects `flake.nix` and `default.nix` (can be a
|
||||||
|
symlink) and switches to using `nix build` as appropriate.
|
||||||
|
|
||||||
|
* Added `unGrab` to `XMonad.Operations`; this releases XMonad's passive
|
||||||
|
keyboard grab, so other applications (like `scrot`) can do their
|
||||||
|
thing.
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* Duplicated floats (e.g. from X.A.CopyToAll) no longer escape to inactive
|
||||||
|
screens.
|
||||||
|
|
||||||
## 0.17.2 (April 2, 2023)
|
## 0.17.2 (April 2, 2023)
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
@ -14,6 +66,9 @@
|
|||||||
|
|
||||||
* Exported `cacheNumlockMask` and `mkGrabs` from `XMonad.Operations`.
|
* Exported `cacheNumlockMask` and `mkGrabs` from `XMonad.Operations`.
|
||||||
|
|
||||||
|
* Added `willFloat` function to `XMonad.ManageHooks` to detect whether the
|
||||||
|
(about to be) managed window will be a floating window or not.
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
* Fixed border color of windows with alpha channel. Now all windows have the
|
* Fixed border color of windows with alpha channel. Now all windows have the
|
||||||
@ -71,9 +126,6 @@
|
|||||||
* Added `withUnfocused` function to `XMonad.Operations`, allowing for `X`
|
* Added `withUnfocused` function to `XMonad.Operations`, allowing for `X`
|
||||||
operations to be applied to unfocused windows.
|
operations to be applied to unfocused windows.
|
||||||
|
|
||||||
* Added `willFloat` function to `XMonad.ManageHooks` to detect whether the
|
|
||||||
(about to be) managed window will be a floating window or not
|
|
||||||
|
|
||||||
[these build scripts]: https://github.com/xmonad/xmonad-testing/tree/master/build-scripts
|
[these build scripts]: https://github.com/xmonad/xmonad-testing/tree/master/build-scripts
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
33
INSTALL.md
33
INSTALL.md
@ -123,7 +123,9 @@ Unless you already know which one you prefer, use Stack, which is easier.
|
|||||||
|
|
||||||
#### Install Stack
|
#### Install Stack
|
||||||
|
|
||||||
The easiest way to get [stack] is probably via your system's package
|
Probably one of the best ways to get [stack] is to use [GHCup], which is the main Haskell installer according to language's official [website][GHCup] and community [survey]. GHCup is [widely available] and is considered less error prone than other installation options.
|
||||||
|
|
||||||
|
You can also use your system's package
|
||||||
manager:
|
manager:
|
||||||
|
|
||||||
``` console
|
``` console
|
||||||
@ -145,9 +147,6 @@ stack via its [documentation][stack]):
|
|||||||
$ curl -sSL https://get.haskellstack.org/ | sh
|
$ curl -sSL https://get.haskellstack.org/ | sh
|
||||||
```
|
```
|
||||||
|
|
||||||
Yet another way would be via [ghcup]; this is similar to installers like
|
|
||||||
`rustup`, in case you prefer that.
|
|
||||||
|
|
||||||
#### Create a New Project
|
#### Create a New Project
|
||||||
|
|
||||||
Let's create a stack project. Since we're already in the correct
|
Let's create a stack project. Since we're already in the correct
|
||||||
@ -222,7 +221,9 @@ be that you don't have the required C libraries installed. See
|
|||||||
|
|
||||||
#### Install cabal-install
|
#### Install cabal-install
|
||||||
|
|
||||||
The easiest way to get [cabal-install] is probably via your system's package
|
Probably one of the best ways to get [cabal-install] is to use [GHCup], which is the main Haskell installer according to language's official [website][GHCup] and community [survey]. GHCup is [widely available] and is considered less error prone than other installation options.
|
||||||
|
|
||||||
|
You can also use your system's package
|
||||||
manager:
|
manager:
|
||||||
|
|
||||||
``` console
|
``` console
|
||||||
@ -231,22 +232,22 @@ $ sudo dnf install cabal-install # Fedora
|
|||||||
$ sudo pacman -S cabal-install # Arch
|
$ sudo pacman -S cabal-install # Arch
|
||||||
```
|
```
|
||||||
|
|
||||||
If your distribution does not package cabal-install, [ghcup][] is another
|
See also <https://www.haskell.org/cabal/#install-upgrade>.
|
||||||
option. See also <https://www.haskell.org/cabal/#install-upgrade>.
|
|
||||||
|
|
||||||
#### Create a New Project
|
#### Create a New Project
|
||||||
|
|
||||||
Let's create a cabal project. Since we're already in the correct
|
If you want to use `xmonad` or `xmonad-contrib` from git, you will need a
|
||||||
directory (`~/.config/xmonad`) with `xmonad` and `xmonad-contrib`
|
`cabal.project` file. If you want to use both from [Hackage][], you should
|
||||||
subdirectories, we'll instruct cabal to use them. Create a file named
|
skip this step.
|
||||||
`cabal.project` containing:
|
|
||||||
|
Create a file named `cabal.project` containing:
|
||||||
|
|
||||||
```
|
```
|
||||||
packages: */*.cabal
|
packages: */*.cabal
|
||||||
```
|
```
|
||||||
|
|
||||||
(If you skip this step, cabal will use the latest releases from [Hackage][]
|
(If you do this step without using [git] checkouts, you will get an error from
|
||||||
instead.)
|
cabal in the next step. Simply remove `cabal.project` and try again.)
|
||||||
|
|
||||||
#### Install Everything
|
#### Install Everything
|
||||||
|
|
||||||
@ -255,7 +256,7 @@ libraries and then build the xmonad binary:
|
|||||||
|
|
||||||
``` console
|
``` console
|
||||||
$ cabal update
|
$ cabal update
|
||||||
$ cabal install --package-env=$HOME/.config/xmonad --lib xmonad xmonad-contrib
|
$ cabal install --package-env=$HOME/.config/xmonad --lib base xmonad xmonad-contrib
|
||||||
$ cabal install --package-env=$HOME/.config/xmonad xmonad
|
$ cabal install --package-env=$HOME/.config/xmonad xmonad
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -393,7 +394,9 @@ executable will also be within that directory and not in
|
|||||||
[git]: https://git-scm.com/
|
[git]: https://git-scm.com/
|
||||||
[stack]: https://docs.haskellstack.org/en/stable/README/
|
[stack]: https://docs.haskellstack.org/en/stable/README/
|
||||||
[cabal-install]: https://www.haskell.org/cabal/
|
[cabal-install]: https://www.haskell.org/cabal/
|
||||||
[ghcup]: https://www.haskell.org/ghcup/
|
[GHCup]: https://www.haskell.org/ghcup/
|
||||||
|
[survey]: https://taylor.fausak.me/2022/11/18/haskell-survey-results/
|
||||||
|
[widely available]: https://www.haskell.org/ghcup/install/#supported-platforms
|
||||||
[what xmonad would do]: https://github.com/xmonad/xmonad/blob/master/src/XMonad/Core.hs#L659-L667
|
[what xmonad would do]: https://github.com/xmonad/xmonad/blob/master/src/XMonad/Core.hs#L659-L667
|
||||||
[Hackage]: https://hackage.haskell.org/
|
[Hackage]: https://hackage.haskell.org/
|
||||||
[scripts/build]: https://github.com/xmonad/xmonad-contrib/blob/master/scripts/build
|
[scripts/build]: https://github.com/xmonad/xmonad-contrib/blob/master/scripts/build
|
||||||
|
@ -117,7 +117,12 @@ When the time comes to release another version of xmonad and xmonad-contrib:
|
|||||||
|
|
||||||
See [old announcements][old-announce] ([even older][older-announce]) for inspiration.
|
See [old announcements][old-announce] ([even older][older-announce]) for inspiration.
|
||||||
|
|
||||||
7. Bump version for development (add `.9`) and prepare fresh sections in
|
7. Trigger xmonad-docs build to generate and persist docs for the just
|
||||||
|
released version:
|
||||||
|
|
||||||
|
- https://github.com/xmonad/xmonad-docs/actions/workflows/stack.yml
|
||||||
|
|
||||||
|
8. Bump version for development (add `.9`) and prepare fresh sections in
|
||||||
[`CHANGES.md`](CHANGES.md).
|
[`CHANGES.md`](CHANGES.md).
|
||||||
|
|
||||||
[packdeps]: https://hackage.haskell.org/package/packdeps
|
[packdeps]: https://hackage.haskell.org/package/packdeps
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
<a href="https://github.com/xmonad/xmonad/blob/readme/LICENSE"><img alt="License" src="https://img.shields.io/github/license/xmonad/xmonad"></a>
|
<a href="https://github.com/xmonad/xmonad/blob/readme/LICENSE"><img alt="License" src="https://img.shields.io/github/license/xmonad/xmonad"></a>
|
||||||
<a href="https://haskell.org/"><img alt="Made in Haskell" src="https://img.shields.io/badge/Made%20in-Haskell-%235e5086?logo=haskell"></a>
|
<a href="https://haskell.org/"><img alt="Made in Haskell" src="https://img.shields.io/badge/Made%20in-Haskell-%235e5086?logo=haskell"></a>
|
||||||
<br>
|
<br>
|
||||||
<a href="https://github.com/xmonad/xmonad/actions/workflows/stack.yml"><img alt="Stack" src="https://img.shields.io/github/workflow/status/xmonad/xmonad/Stack?label=Stack&logo=githubactions&logoColor=white"></a>
|
<a href="https://github.com/xmonad/xmonad/actions/workflows/stack.yml"><img alt="Stack" src="https://img.shields.io/github/actions/workflow/status/xmonad/xmonad/stack.yml?label=Stack&logo=githubactions&logoColor=white"></a>
|
||||||
<a href="https://github.com/xmonad/xmonad/actions/workflows/haskell-ci.yml"><img alt="Cabal" src="https://img.shields.io/github/workflow/status/xmonad/xmonad/Haskell-CI?label=Cabal&logo=githubactions&logoColor=white"></a>
|
<a href="https://github.com/xmonad/xmonad/actions/workflows/haskell-ci.yml"><img alt="Cabal" src="https://img.shields.io/github/actions/workflow/status/xmonad/xmonad/haskell-ci.yml?label=Cabal&logo=githubactions&logoColor=white"></a>
|
||||||
<a href="https://github.com/xmonad/xmonad/actions/workflows/nix.yml"><img alt="Nix" src="https://img.shields.io/github/workflow/status/xmonad/xmonad/Nix?label=Nix&logo=githubactions&logoColor=white"></a>
|
<a href="https://github.com/xmonad/xmonad/actions/workflows/nix.yml"><img alt="Nix" src="https://img.shields.io/github/actions/workflow/status/xmonad/xmonad/nix.yml?label=Nix&logo=githubactions&logoColor=white"></a>
|
||||||
<br>
|
<br>
|
||||||
<a href="https://github.com/sponsors/xmonad"><img alt="GitHub Sponsors" src="https://img.shields.io/github/sponsors/xmonad?label=GitHub%20Sponsors&logo=githubsponsors"></a>
|
<a href="https://github.com/sponsors/xmonad"><img alt="GitHub Sponsors" src="https://img.shields.io/github/sponsors/xmonad?label=GitHub%20Sponsors&logo=githubsponsors"></a>
|
||||||
<a href="https://opencollective.com/xmonad"><img alt="Open Collective" src="https://img.shields.io/opencollective/all/xmonad?label=Open%20Collective&logo=opencollective"></a>
|
<a href="https://opencollective.com/xmonad"><img alt="Open Collective" src="https://img.shields.io/opencollective/all/xmonad?label=Open%20Collective&logo=opencollective"></a>
|
||||||
|
128
TUTORIAL.md
128
TUTORIAL.md
@ -38,13 +38,13 @@ package manager, you will need to `xmonad --recompile` _every time_ a
|
|||||||
Haskell dependency is updated—else xmonad may fail to start when you
|
Haskell dependency is updated—else xmonad may fail to start when you
|
||||||
want to log in!
|
want to log in!
|
||||||
|
|
||||||
We're going to assume xmonad version `0.17.0` and xmonad-contrib version
|
We're going to assume xmonad version `>= 0.17.0` and xmonad-contrib
|
||||||
`0.17.0` here, though most of these steps should work with older
|
version `>= 0.17.0` here, though most of these steps should work with
|
||||||
versions as well. When we get to the relevant parts, will point you to
|
older versions as well. When we get to the relevant parts, will point
|
||||||
alternatives that work with at least xmonad version `0.15` and
|
you to alternatives that work with at least xmonad version `0.15` and
|
||||||
xmonad-contrib version `0.16`. This will usually be accompanied by a
|
xmonad-contrib version `0.16`. This will usually be accompanied by big
|
||||||
big "_IF YOU ARE ON A VERSION `< 0.17.0`_", so don't worry about missing
|
warning labels for the respective version bounds, so don't worry about
|
||||||
it!
|
missing it!
|
||||||
|
|
||||||
Throughout the tutorial we will use, for keybindings, a syntax very akin
|
Throughout the tutorial we will use, for keybindings, a syntax very akin
|
||||||
to the [GNU Emacs conventions] for the same thing—so `C-x` means "hold
|
to the [GNU Emacs conventions] for the same thing—so `C-x` means "hold
|
||||||
@ -77,6 +77,11 @@ a live xmonad session in some capacity. If you have set up your
|
|||||||
`~/.xinitrc` as directed in the xmonad guided tour, you should be good
|
`~/.xinitrc` as directed in the xmonad guided tour, you should be good
|
||||||
to go! If not, just smack an `exec xmonad` at the bottom of that file.
|
to go! If not, just smack an `exec xmonad` at the bottom of that file.
|
||||||
|
|
||||||
|
In particular, it might be a good idea to set a wallpaper beforehand.
|
||||||
|
Otherwise, when switching workspaces or closing windows, you might start
|
||||||
|
seeing "shadows" of windows that were there before, unable to interact
|
||||||
|
with them.
|
||||||
|
|
||||||
## Installing Xmobar
|
## Installing Xmobar
|
||||||
|
|
||||||
What we need to do now—provided we want to use a bar at all—is to
|
What we need to do now—provided we want to use a bar at all—is to
|
||||||
@ -108,6 +113,8 @@ utility modules we will use. At the very top of the file, write
|
|||||||
import XMonad
|
import XMonad
|
||||||
|
|
||||||
import XMonad.Util.EZConfig
|
import XMonad.Util.EZConfig
|
||||||
|
-- NOTE: Only needed for versions < 0.18.0! For 0.18.0 and up, this is
|
||||||
|
-- already included in the XMonad import and will give you a warning!
|
||||||
import XMonad.Util.Ungrab
|
import XMonad.Util.Ungrab
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -263,7 +270,7 @@ myLayout = tiled ||| Mirror tiled ||| Full
|
|||||||
```
|
```
|
||||||
|
|
||||||
The so-called `where`-clause above simply consists of local declarations
|
The so-called `where`-clause above simply consists of local declarations
|
||||||
that might clutter things up where they all declared at the top-level
|
that might clutter things up were they all declared at the top-level
|
||||||
like this
|
like this
|
||||||
|
|
||||||
``` haskell
|
``` haskell
|
||||||
@ -379,12 +386,16 @@ effect (and some applications, like chromium, will misbehave and need
|
|||||||
some [Hacks] to make this work), we will also add the relevant function
|
some [Hacks] to make this work), we will also add the relevant function
|
||||||
to get "proper" fullscreen behaviour here.
|
to get "proper" fullscreen behaviour here.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
_IF YOU ARE ON A VERSION `< 0.17.0`_: The `ewmhFullscreen` function does
|
_IF YOU ARE ON A VERSION `< 0.17.0`_: The `ewmhFullscreen` function does
|
||||||
not exist in these versions. Instead of it, you can try to add
|
not exist in these versions. Instead of it, you can try to add
|
||||||
`fullscreenEventHook` to your `handleEventHook` to achieve similar
|
`fullscreenEventHook` to your `handleEventHook` to achieve similar
|
||||||
functionality (how to do this is explained in the documentation of
|
functionality (how to do this is explained in the documentation of
|
||||||
[XMonad.Hooks.EwmhDesktops]).
|
[XMonad.Hooks.EwmhDesktops]).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
To use the two combinators, we compose them with the `xmonad` function
|
To use the two combinators, we compose them with the `xmonad` function
|
||||||
in the following way:
|
in the following way:
|
||||||
|
|
||||||
@ -430,7 +441,7 @@ Much better!
|
|||||||
## Make XMonad and Xmobar Talk to Each Other
|
## Make XMonad and Xmobar Talk to Each Other
|
||||||
|
|
||||||
Onto the main dish. First, we have to import the necessary modules.
|
Onto the main dish. First, we have to import the necessary modules.
|
||||||
Add the following to your list of imports:
|
Add the following to your list of imports
|
||||||
|
|
||||||
``` haskell
|
``` haskell
|
||||||
import XMonad.Hooks.DynamicLog
|
import XMonad.Hooks.DynamicLog
|
||||||
@ -438,23 +449,27 @@ import XMonad.Hooks.StatusBar
|
|||||||
import XMonad.Hooks.StatusBar.PP
|
import XMonad.Hooks.StatusBar.PP
|
||||||
```
|
```
|
||||||
|
|
||||||
_IF YOU ARE ON A VERSION `< 0.17.0`_: The `XMonad.Hooks.StatusBar` and
|
and replace your `main` function above with:
|
||||||
`XMonad.Hooks.StatusBar.PP` modules don't exist yet. You can find
|
|
||||||
everything you need in the `XMonad.Hooks.DynamicLog` module, so remove
|
|
||||||
these two imports.
|
|
||||||
|
|
||||||
Replace your `main` function above with:
|
|
||||||
|
|
||||||
``` haskell
|
``` haskell
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = xmonad $ ewmhFullscreen $ ewmh $ xmobarProp $ myConfig
|
main = xmonad $ ewmhFullscreen $ ewmh $ xmobarProp $ myConfig
|
||||||
```
|
```
|
||||||
|
|
||||||
_IF YOU ARE ON A VERSION `< 0.17.0`_: The `xmobarProp` function does not
|
---
|
||||||
exist in these versions. Instead of it, use `xmobar` via
|
|
||||||
`main = xmonad . ewmh =<< xmobar myConfig` and carefully read the part
|
_IF YOU ARE ON A VERSION `< 0.17.0`_: The `XMonad.Hooks.StatusBar` and
|
||||||
about pipes later on (`xmobar` uses pipes to make xmobar talk to
|
`XMonad.Hooks.StatusBar.PP` modules don't exist yet. You can find
|
||||||
xmonad).
|
everything you need in the `XMonad.Hooks.DynamicLog` module, so remove
|
||||||
|
these two imports.
|
||||||
|
|
||||||
|
Further, the `xmobarProp` function does not exist in older versions.
|
||||||
|
Instead of it, use `xmobar` via `main = xmonad . ewmh =<< xmobar
|
||||||
|
myConfig` and carefully read the part about pipes later on (`xmobar`
|
||||||
|
uses pipes to make xmobar talk to xmonad). Do note the lack of
|
||||||
|
`ewmhFullscreen`, as explained above!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
As a quick side-note, we could have also written
|
As a quick side-note, we could have also written
|
||||||
|
|
||||||
@ -540,11 +555,15 @@ when things are not being read! For this reason we have to use
|
|||||||
(this is useful, for example, for [XMonad.Util.ClickableWorkspaces],
|
(this is useful, for example, for [XMonad.Util.ClickableWorkspaces],
|
||||||
which is a new feature in `0.17.0`).
|
which is a new feature in `0.17.0`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
_IF YOU ARE ON A VERSION `< 0.17.0`_: As discussed above, the `xmobar`
|
_IF YOU ARE ON A VERSION `< 0.17.0`_: As discussed above, the `xmobar`
|
||||||
function uses pipes, so you actually do want to use the `StdinReader`.
|
function uses pipes, so you actually do want to use the `StdinReader`.
|
||||||
Simply replace _all_ occurences of `XMonadLog` with `StdinReader`
|
Simply replace _all_ occurences of `XMonadLog` with `StdinReader`
|
||||||
below (don't forget the template!)
|
below (don't forget the template!)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Configuring Xmobar
|
## Configuring Xmobar
|
||||||
|
|
||||||
Now, before this will work, we have to configure xmobar. Here's a nice
|
Now, before this will work, we have to configure xmobar. Here's a nice
|
||||||
@ -660,6 +679,8 @@ main = xmonad
|
|||||||
$ myConfig
|
$ myConfig
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
_IF YOU ARE ON A VERSION `< 0.17.0`_: `xmobar` has a similar definition,
|
_IF YOU ARE ON A VERSION `< 0.17.0`_: `xmobar` has a similar definition,
|
||||||
relying on `statusBar` alone: `xmobar = statusBar "xmobar" xmobarPP
|
relying on `statusBar` alone: `xmobar = statusBar "xmobar" xmobarPP
|
||||||
toggleStrutsKey`. Sadly, the `defToggleStrutsKey` function is not yet
|
toggleStrutsKey`. Sadly, the `defToggleStrutsKey` function is not yet
|
||||||
@ -668,7 +689,6 @@ _IF YOU ARE ON A VERSION `< 0.17.0`_: `xmobar` has a similar definition,
|
|||||||
``` haskell
|
``` haskell
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = xmonad
|
main = xmonad
|
||||||
. ewmhFullscreen
|
|
||||||
. ewmh
|
. ewmh
|
||||||
=<< statusBar "xmobar" def toggleStrutsKey myConfig
|
=<< statusBar "xmobar" def toggleStrutsKey myConfig
|
||||||
where
|
where
|
||||||
@ -676,6 +696,8 @@ main = xmonad
|
|||||||
toggleStrutsKey XConfig{ modMask = m } = (m, xK_b)
|
toggleStrutsKey XConfig{ modMask = m } = (m, xK_b)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
The `defToggleStrutsKey` here is just the key with which you can toggle
|
The `defToggleStrutsKey` here is just the key with which you can toggle
|
||||||
the bar; it is bound to `M-b`. If you want to change this, you can also
|
the bar; it is bound to `M-b`. If you want to change this, you can also
|
||||||
define your own:
|
define your own:
|
||||||
@ -772,6 +794,8 @@ myXmobarPP = def
|
|||||||
lowWhite = xmobarColor "#bbbbbb" ""
|
lowWhite = xmobarColor "#bbbbbb" ""
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
_IF YOU ARE ON A VERSION `< 0.17`_: Both `logTitles` and `xmobarBorder`
|
_IF YOU ARE ON A VERSION `< 0.17`_: Both `logTitles` and `xmobarBorder`
|
||||||
are not available yet, so you will have to remove them. As an
|
are not available yet, so you will have to remove them. As an
|
||||||
alternative to `xmobarBorder`, a common way to "mark" the currently
|
alternative to `xmobarBorder`, a common way to "mark" the currently
|
||||||
@ -779,6 +803,8 @@ _IF YOU ARE ON A VERSION `< 0.17`_: Both `logTitles` and `xmobarBorder`
|
|||||||
`ppCurrent = wrap (blue "[") (blue "]")` and see if you like it. Also
|
`ppCurrent = wrap (blue "[") (blue "]")` and see if you like it. Also
|
||||||
read the bit about `ppOrder` further down!
|
read the bit about `ppOrder` further down!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
That's a lot! But don't worry, take a deep breath and remind yourself
|
That's a lot! But don't worry, take a deep breath and remind yourself
|
||||||
of what you read above in the documentation of the [PP record]. Even if
|
of what you read above in the documentation of the [PP record]. Even if
|
||||||
you haven't read the documentation yet, most of the fields should be
|
you haven't read the documentation yet, most of the fields should be
|
||||||
@ -882,10 +908,10 @@ apt-get install nm-applet feh xfce4-power-manager
|
|||||||
|
|
||||||
First, configure xscreensaver how you like it with the
|
First, configure xscreensaver how you like it with the
|
||||||
`xscreensaver-demo` command. Now, we will set these things up in
|
`xscreensaver-demo` command. Now, we will set these things up in
|
||||||
`~/.xinitrc` (we could also do most of this in xmonad's `startupHook`,
|
`~/.xinitrc`. If you want to use XMonad with a desktop environment, see
|
||||||
but `~/.xinitrc` is perhaps more standard). If you want to use xmonad
|
[Basic Desktop Environment Integration] for how to do this. For a
|
||||||
with a desktop environment, see [Basic Desktop Environment Integration]
|
version using XMonad's built in functionality instead, see the [next
|
||||||
for how to do this.
|
section][using-the-startupHook].
|
||||||
|
|
||||||
Your `~/.xinitrc` may wind up looking like this:
|
Your `~/.xinitrc` may wind up looking like this:
|
||||||
|
|
||||||
@ -933,6 +959,38 @@ Mission accomplished!
|
|||||||
Of course substitute the wallpaper for one of your own. If you like the
|
Of course substitute the wallpaper for one of your own. If you like the
|
||||||
one used above, you can find it [here](https://i.imgur.com/9MQHuZx.png).
|
one used above, you can find it [here](https://i.imgur.com/9MQHuZx.png).
|
||||||
|
|
||||||
|
### Using the `startupHook`
|
||||||
|
|
||||||
|
Instead of the `.xinitrc` file, one can also use XMonad's built in
|
||||||
|
`startupHook` in order to auto start programs. The
|
||||||
|
[XMonad.Util.SpawnOnce] library is perfect for this use case, allowing
|
||||||
|
programs to start only once, and not with every invocation of `M-q`!
|
||||||
|
|
||||||
|
This requires but a small change in `myConfig`:
|
||||||
|
|
||||||
|
``` haskell
|
||||||
|
-- import XMonad.Util.SpawnOnce (spawnOnce)
|
||||||
|
|
||||||
|
myConfig = def
|
||||||
|
{ modMask = mod4Mask -- Rebind Mod to the Super key
|
||||||
|
, layoutHook = myLayout -- Use custom layouts
|
||||||
|
, startupHook = myStartupHook
|
||||||
|
}
|
||||||
|
`additionalKeysP`
|
||||||
|
[ ("M-S-z", spawn "xscreensaver-command -lock")
|
||||||
|
, ("M-C-s", unGrab *> spawn "scrot -s" )
|
||||||
|
, ("M-f" , spawn "firefox" )
|
||||||
|
]
|
||||||
|
|
||||||
|
myStartupHook :: X ()
|
||||||
|
myStartupHook = do
|
||||||
|
spawnOnce "trayer --edge top --align right --SetDockType true \
|
||||||
|
\--SetPartialStrut true --expand true --width 10 \
|
||||||
|
\--transparent true --tint 0x5f5f5f --height 18"
|
||||||
|
spawnOnce "feh --bg-fill --no-fehbg ~/.wallpapers/haskell-red-noise.png"
|
||||||
|
-- … and so on …
|
||||||
|
```
|
||||||
|
|
||||||
## Final Touches
|
## Final Touches
|
||||||
|
|
||||||
There may be some programs that you don't want xmonad to tile. The
|
There may be some programs that you don't want xmonad to tile. The
|
||||||
@ -1010,6 +1068,9 @@ import XMonad.Hooks.StatusBar.PP
|
|||||||
|
|
||||||
import XMonad.Util.EZConfig
|
import XMonad.Util.EZConfig
|
||||||
import XMonad.Util.Loggers
|
import XMonad.Util.Loggers
|
||||||
|
-- NOTE: Importing XMonad.Util.Ungrab is only necessary for versions
|
||||||
|
-- < 0.18.0! For 0.18.0 and up, this is already included in the
|
||||||
|
-- XMonad import and will generate a warning instead!
|
||||||
import XMonad.Util.Ungrab
|
import XMonad.Util.Ungrab
|
||||||
|
|
||||||
import XMonad.Layout.Magnifier
|
import XMonad.Layout.Magnifier
|
||||||
@ -1238,21 +1299,22 @@ either :)
|
|||||||
[Basic Desktop Environment Integration]: https://wiki.haskell.org/Xmonad/Basic_Desktop_Environment_Integration
|
[Basic Desktop Environment Integration]: https://wiki.haskell.org/Xmonad/Basic_Desktop_Environment_Integration
|
||||||
|
|
||||||
[Hacks]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Util-Hacks.html
|
[Hacks]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Util-Hacks.html
|
||||||
[PP record]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Hooks-DynamicLog.html#t:PP
|
|
||||||
[INSTALL.md]: INSTALL.md
|
[INSTALL.md]: INSTALL.md
|
||||||
|
[PP record]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Hooks-DynamicLog.html#t:PP
|
||||||
[XMonad.Config]: https://github.com/xmonad/xmonad/blob/master/src/XMonad/Config.hs
|
[XMonad.Config]: https://github.com/xmonad/xmonad/blob/master/src/XMonad/Config.hs
|
||||||
[XMonad.ManageHook]: https://xmonad.github.io/xmonad-docs/xmonad/XMonad-ManageHook.html
|
|
||||||
[XMonad.Util.Loggers]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Util-Loggers.html
|
|
||||||
[XMonad.Util.EZConfig]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Util-EZConfig.html
|
|
||||||
[XMonad.Layout.Renamed]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Layout-Renamed.html
|
|
||||||
[XMonad.Layout.Magnifier]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Layout-Magnifier.html
|
|
||||||
[XMonad.Doc.Contributing]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Doc-Configuring.html
|
[XMonad.Doc.Contributing]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Doc-Configuring.html
|
||||||
[XMonad.Hooks.EwmhDesktops]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Hooks-EwmhDesktops.html
|
[XMonad.Hooks.EwmhDesktops]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Hooks-EwmhDesktops.html
|
||||||
[XMonad.Layout.ThreeColumns]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Layout-ThreeColumns.html
|
|
||||||
[XMonad.Hooks.ManageHelpers]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Hooks-ManageHelpers.html
|
[XMonad.Hooks.ManageHelpers]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Hooks-ManageHelpers.html
|
||||||
|
[XMonad.Layout.Magnifier]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Layout-Magnifier.html
|
||||||
|
[XMonad.Layout.Renamed]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Layout-Renamed.html
|
||||||
|
[XMonad.Layout.ThreeColumns]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Layout-ThreeColumns.html
|
||||||
|
[XMonad.ManageHook]: https://xmonad.github.io/xmonad-docs/xmonad/XMonad-ManageHook.html
|
||||||
[XMonad.Util.ClickableWorkspaces]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Util-ClickableWorkspaces.html
|
[XMonad.Util.ClickableWorkspaces]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Util-ClickableWorkspaces.html
|
||||||
|
[XMonad.Util.EZConfig]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Util-EZConfig.html
|
||||||
|
[XMonad.Util.Loggers]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Util-Loggers.html
|
||||||
|
[XMonad.Util.SpawnOnce]: https://hackage.haskell.org/package/xmonad-contrib/docs/XMonad-Util-SpawnOnce.html
|
||||||
|
|
||||||
[xmobar]: https://xmobar.org/
|
[xmobar]: https://codeberg.org/xmobar/xmobar
|
||||||
[battery]: https://codeberg.org/xmobar/xmobar/src/branch/master/doc/plugins.org#batteryp-dirs-args-refreshrate
|
[battery]: https://codeberg.org/xmobar/xmobar/src/branch/master/doc/plugins.org#batteryp-dirs-args-refreshrate
|
||||||
[xmobar.hs]: https://codeberg.org/xmobar/xmobar/src/branch/master/etc/xmobar.hs
|
[xmobar.hs]: https://codeberg.org/xmobar/xmobar/src/branch/master/etc/xmobar.hs
|
||||||
[Wikipedia page]: https://en.wikipedia.org/wiki/ICAO_airport_code#Prefixes
|
[Wikipedia page]: https://en.wikipedia.org/wiki/ICAO_airport_code#Prefixes
|
||||||
|
53
flake.nix
53
flake.nix
@ -2,9 +2,9 @@
|
|||||||
# See xmonad-contrib/NIX.md for an overview of module usage.
|
# See xmonad-contrib/NIX.md for an overview of module usage.
|
||||||
{
|
{
|
||||||
inputs = {
|
inputs = {
|
||||||
flake-utils.url = github:numtide/flake-utils;
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
git-ignore-nix.url = github:hercules-ci/gitignore.nix/master;
|
git-ignore-nix.url = "github:hercules-ci/gitignore.nix/master";
|
||||||
unstable.url = github:NixOS/nixpkgs/nixos-unstable;
|
unstable.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
};
|
};
|
||||||
outputs = { self, flake-utils, nixpkgs, unstable, git-ignore-nix }:
|
outputs = { self, flake-utils, nixpkgs, unstable, git-ignore-nix }:
|
||||||
let
|
let
|
||||||
@ -15,17 +15,26 @@
|
|||||||
else [ "haskell" "packages" compiler ]
|
else [ "haskell" "packages" compiler ]
|
||||||
);
|
);
|
||||||
fromHOL = hol: comp: final: prev: with prev.lib; with attrsets;
|
fromHOL = hol: comp: final: prev: with prev.lib; with attrsets;
|
||||||
setAttrByPath (hpath comp)
|
let
|
||||||
((getAttrFromPath (hpath comp) prev).override (old: {
|
path = hpath comp;
|
||||||
|
root = head path;
|
||||||
|
branch = tail path;
|
||||||
|
hpkgs' = (getAttrFromPath path prev).override (old: {
|
||||||
overrides = composeExtensions (old.overrides or (_: _: {}))
|
overrides = composeExtensions (old.overrides or (_: _: {}))
|
||||||
(hol final prev);
|
(hol final prev);
|
||||||
}));
|
});
|
||||||
|
in {
|
||||||
|
${root} = recursiveUpdate prev.${root} (setAttrByPath branch hpkgs');
|
||||||
|
};
|
||||||
hoverlay = final: prev: hself: hsuper:
|
hoverlay = final: prev: hself: hsuper:
|
||||||
with prev.haskell.lib.compose; {
|
with prev.haskell.lib.compose; {
|
||||||
xmonad = hself.callCabal2nix "xmonad"
|
xmonad = hself.callCabal2nix "xmonad"
|
||||||
(git-ignore-nix.lib.gitignoreSource ./.) { };
|
(git-ignore-nix.lib.gitignoreSource ./.) { };
|
||||||
};
|
};
|
||||||
overlay = fromHOL hoverlay { };
|
defComp = if builtins.pathExists ./comp.nix
|
||||||
|
then import ./comp.nix
|
||||||
|
else { };
|
||||||
|
overlay = fromHOL hoverlay defComp;
|
||||||
overlays = [ overlay ];
|
overlays = [ overlay ];
|
||||||
nixosModule = { config, pkgs, lib, ... }: with lib; with attrsets;
|
nixosModule = { config, pkgs, lib, ... }: with lib; with attrsets;
|
||||||
let
|
let
|
||||||
@ -37,7 +46,7 @@
|
|||||||
enable = mkEnableOption "flake";
|
enable = mkEnableOption "flake";
|
||||||
prefix = mkOption {
|
prefix = mkOption {
|
||||||
default = null;
|
default = null;
|
||||||
type = nullOr string;
|
type = nullOr str;
|
||||||
example = literalExpression "\"unstable\"";
|
example = literalExpression "\"unstable\"";
|
||||||
description = ''
|
description = ''
|
||||||
Specify a nested alternative <literal>pkgs</literal> by attrName.
|
Specify a nested alternative <literal>pkgs</literal> by attrName.
|
||||||
@ -45,7 +54,7 @@
|
|||||||
};
|
};
|
||||||
compiler = mkOption {
|
compiler = mkOption {
|
||||||
default = null;
|
default = null;
|
||||||
type = nullOr string;
|
type = nullOr str;
|
||||||
example = literalExpression "\"ghc922\"";
|
example = literalExpression "\"ghc922\"";
|
||||||
description = ''
|
description = ''
|
||||||
Which compiler to build xmonad with.
|
Which compiler to build xmonad with.
|
||||||
@ -64,12 +73,32 @@
|
|||||||
nixosModules = [ nixosModule ];
|
nixosModules = [ nixosModule ];
|
||||||
in flake-utils.lib.eachDefaultSystem (system:
|
in flake-utils.lib.eachDefaultSystem (system:
|
||||||
let pkgs = import nixpkgs { inherit system overlays; };
|
let pkgs = import nixpkgs { inherit system overlays; };
|
||||||
|
hpkg = pkgs.lib.attrsets.getAttrFromPath (hpath defComp) pkgs;
|
||||||
|
modifyDevShell =
|
||||||
|
if builtins.pathExists ./develop.nix
|
||||||
|
then import ./develop.nix
|
||||||
|
else _: x: x;
|
||||||
in
|
in
|
||||||
rec {
|
rec {
|
||||||
devShell = pkgs.haskellPackages.shellFor {
|
devShell = hpkg.shellFor (modifyDevShell pkgs {
|
||||||
packages = p: [ p.xmonad ];
|
packages = p: [ p.xmonad ];
|
||||||
};
|
});
|
||||||
defaultPackage = pkgs.haskellPackages.xmonad;
|
defaultPackage = hpkg.xmonad;
|
||||||
|
# An auxiliary NixOS module that modernises the standard xmonad NixOS module
|
||||||
|
# and wrapper script used, replacing them with versions from unstable.
|
||||||
|
# Currently, due to the NIX_GHC --> XMONAD_GHC env var change, this is
|
||||||
|
# necessary in order for Mod-q recompilation to work out-of-the-box.
|
||||||
|
modernise =
|
||||||
|
let
|
||||||
|
xmonadModFile = "services/x11/window-managers/xmonad.nix";
|
||||||
|
unpkgs = import unstable { inherit system; };
|
||||||
|
replaceWrapper = _: _:
|
||||||
|
{ xmonad-with-packages = unpkgs.xmonad-with-packages; };
|
||||||
|
in {
|
||||||
|
disabledModules = [ xmonadModFile ];
|
||||||
|
imports = [ (unstable + "/nixos/modules/" + xmonadModFile) ];
|
||||||
|
nixpkgs.overlays = [ replaceWrapper ];
|
||||||
|
};
|
||||||
}) // {
|
}) // {
|
||||||
inherit hoverlay overlay overlays nixosModule nixosModules;
|
inherit hoverlay overlay overlays nixosModule nixosModules;
|
||||||
lib = { inherit hpath fromHOL; };
|
lib = { inherit hpath fromHOL; };
|
||||||
|
28
man/xmonad.1
28
man/xmonad.1
@ -1,5 +1,19 @@
|
|||||||
.\" Automatically generated by Pandoc 2.9.2.1
|
.\" Automatically generated by Pandoc 3.1.3
|
||||||
.\"
|
.\"
|
||||||
|
.\" Define V font for inline verbatim, using C font in formats
|
||||||
|
.\" that render this, and otherwise B font.
|
||||||
|
.ie "\f[CB]x\f[]"x" \{\
|
||||||
|
. ftr V B
|
||||||
|
. ftr VI BI
|
||||||
|
. ftr VB B
|
||||||
|
. ftr VBI BI
|
||||||
|
.\}
|
||||||
|
.el \{\
|
||||||
|
. ftr V CR
|
||||||
|
. ftr VI CI
|
||||||
|
. ftr VB CB
|
||||||
|
. ftr VBI CBI
|
||||||
|
.\}
|
||||||
.TH "XMONAD" "1" "27 October 2021" "Tiling Window Manager" ""
|
.TH "XMONAD" "1" "27 October 2021" "Tiling Window Manager" ""
|
||||||
.hy
|
.hy
|
||||||
.SH Name
|
.SH Name
|
||||||
@ -191,15 +205,15 @@ xmonad is customized in your \f[I]xmonad.hs\f[R], and then restarted
|
|||||||
with mod-q.
|
with mod-q.
|
||||||
You can choose where your configuration file lives by
|
You can choose where your configuration file lives by
|
||||||
.IP "1." 3
|
.IP "1." 3
|
||||||
Setting \f[C]XMONAD_DATA_DIR,\f[R] \f[C]XMONAD_CONFIG_DIR\f[R], and
|
Setting \f[V]XMONAD_DATA_DIR,\f[R] \f[V]XMONAD_CONFIG_DIR\f[R], and
|
||||||
\f[C]XMONAD_CACHE_DIR\f[R]; \f[I]xmonad.hs\f[R] is then expected to be
|
\f[V]XMONAD_CACHE_DIR\f[R]; \f[I]xmonad.hs\f[R] is then expected to be
|
||||||
in \f[C]XMONAD_CONFIG_DIR\f[R].
|
in \f[V]XMONAD_CONFIG_DIR\f[R].
|
||||||
.IP "2." 3
|
.IP "2." 3
|
||||||
Creating \f[I]xmonad.hs\f[R] in \f[I]\[ti]/.xmonad\f[R].
|
Creating \f[I]xmonad.hs\f[R] in \f[I]\[ti]/.xmonad\f[R].
|
||||||
.IP "3." 3
|
.IP "3." 3
|
||||||
Creating \f[I]xmonad.hs\f[R] in \f[C]XDG_CONFIG_HOME\f[R].
|
Creating \f[I]xmonad.hs\f[R] in \f[V]XDG_CONFIG_HOME\f[R].
|
||||||
Note that, in this case, xmonad will use \f[C]XDG_DATA_HOME\f[R] and
|
Note that, in this case, xmonad will use \f[V]XDG_DATA_HOME\f[R] and
|
||||||
\f[C]XDG_CACHE_HOME\f[R] for its data and cache directory respectively.
|
\f[V]XDG_CACHE_HOME\f[R] for its data and cache directory respectively.
|
||||||
.PP
|
.PP
|
||||||
You can find many extensions to the core feature set in the xmonad-
|
You can find many extensions to the core feature set in the xmonad-
|
||||||
contrib package, available through your package manager or from
|
contrib package, available through your package manager or from
|
||||||
|
@ -8,15 +8,167 @@
|
|||||||
<meta name="dcterms.date" content="2021-10-27" />
|
<meta name="dcterms.date" content="2021-10-27" />
|
||||||
<title>XMONAD(1) Tiling Window Manager</title>
|
<title>XMONAD(1) Tiling Window Manager</title>
|
||||||
<style>
|
<style>
|
||||||
|
html {
|
||||||
|
color: #1a1a1a;
|
||||||
|
background-color: #fdfdfd;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
margin: 0 auto;
|
||||||
|
max-width: 36em;
|
||||||
|
padding-left: 50px;
|
||||||
|
padding-right: 50px;
|
||||||
|
padding-top: 50px;
|
||||||
|
padding-bottom: 50px;
|
||||||
|
hyphens: auto;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
font-kerning: normal;
|
||||||
|
}
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
body {
|
||||||
|
font-size: 0.9em;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
font-size: 1.8em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media print {
|
||||||
|
html {
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
background-color: transparent;
|
||||||
|
color: black;
|
||||||
|
font-size: 12pt;
|
||||||
|
}
|
||||||
|
p, h2, h3 {
|
||||||
|
orphans: 3;
|
||||||
|
widows: 3;
|
||||||
|
}
|
||||||
|
h2, h3, h4 {
|
||||||
|
page-break-after: avoid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
margin: 1em 0;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: #1a1a1a;
|
||||||
|
}
|
||||||
|
a:visited {
|
||||||
|
color: #1a1a1a;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
margin-top: 1.4em;
|
||||||
|
}
|
||||||
|
h5, h6 {
|
||||||
|
font-size: 1em;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
h6 {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
ol, ul {
|
||||||
|
padding-left: 1.7em;
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
li > ol, li > ul {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
blockquote {
|
||||||
|
margin: 1em 0 1em 1.7em;
|
||||||
|
padding-left: 1em;
|
||||||
|
border-left: 2px solid #e6e6e6;
|
||||||
|
color: #606060;
|
||||||
|
}
|
||||||
|
code {
|
||||||
|
font-family: Menlo, Monaco, Consolas, 'Lucida Console', monospace;
|
||||||
|
font-size: 85%;
|
||||||
|
margin: 0;
|
||||||
|
hyphens: manual;
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
margin: 1em 0;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
pre code {
|
||||||
|
padding: 0;
|
||||||
|
overflow: visible;
|
||||||
|
overflow-wrap: normal;
|
||||||
|
}
|
||||||
|
.sourceCode {
|
||||||
|
background-color: transparent;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
hr {
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
border: none;
|
||||||
|
height: 1px;
|
||||||
|
margin: 1em 0;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
margin: 1em 0;
|
||||||
|
border-collapse: collapse;
|
||||||
|
width: 100%;
|
||||||
|
overflow-x: auto;
|
||||||
|
display: block;
|
||||||
|
font-variant-numeric: lining-nums tabular-nums;
|
||||||
|
}
|
||||||
|
table caption {
|
||||||
|
margin-bottom: 0.75em;
|
||||||
|
}
|
||||||
|
tbody {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
border-top: 1px solid #1a1a1a;
|
||||||
|
border-bottom: 1px solid #1a1a1a;
|
||||||
|
}
|
||||||
|
th {
|
||||||
|
border-top: 1px solid #1a1a1a;
|
||||||
|
padding: 0.25em 0.5em 0.25em 0.5em;
|
||||||
|
}
|
||||||
|
td {
|
||||||
|
padding: 0.125em 0.5em 0.25em 0.5em;
|
||||||
|
}
|
||||||
|
header {
|
||||||
|
margin-bottom: 4em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
#TOC li {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
#TOC ul {
|
||||||
|
padding-left: 1.3em;
|
||||||
|
}
|
||||||
|
#TOC > ul {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
#TOC a:not(:hover) {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
code{white-space: pre-wrap;}
|
code{white-space: pre-wrap;}
|
||||||
span.smallcaps{font-variant: small-caps;}
|
span.smallcaps{font-variant: small-caps;}
|
||||||
span.underline{text-decoration: underline;}
|
div.columns{display: flex; gap: min(4vw, 1.5em);}
|
||||||
div.column{display: inline-block; vertical-align: top; width: 50%;}
|
div.column{flex: auto; overflow-x: auto;}
|
||||||
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
|
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
|
||||||
ul.task-list{list-style: none;}
|
/* The extra [class] is a hack that increases specificity enough to
|
||||||
|
override a similar rule in reveal.js */
|
||||||
|
ul.task-list[class]{list-style: none;}
|
||||||
|
ul.task-list li input[type="checkbox"] {
|
||||||
|
font-size: inherit;
|
||||||
|
width: 0.8em;
|
||||||
|
margin: 0 0.8em 0.2em -1.6em;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
|
||||||
|
/* CSS for syntax highlighting */
|
||||||
pre > code.sourceCode { white-space: pre; position: relative; }
|
pre > code.sourceCode { white-space: pre; position: relative; }
|
||||||
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
|
pre > code.sourceCode > span { line-height: 1.25; }
|
||||||
pre > code.sourceCode > span:empty { height: 1.2em; }
|
pre > code.sourceCode > span:empty { height: 1.2em; }
|
||||||
|
.sourceCode { overflow: visible; }
|
||||||
code.sourceCode > span { color: inherit; text-decoration: inherit; }
|
code.sourceCode > span { color: inherit; text-decoration: inherit; }
|
||||||
div.sourceCode { margin: 1em 0; }
|
div.sourceCode { margin: 1em 0; }
|
||||||
pre.sourceCode { margin: 0; }
|
pre.sourceCode { margin: 0; }
|
||||||
@ -51,7 +203,7 @@
|
|||||||
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
|
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
|
||||||
code span.at { color: #7d9029; } /* Attribute */
|
code span.at { color: #7d9029; } /* Attribute */
|
||||||
code span.bn { color: #40a070; } /* BaseN */
|
code span.bn { color: #40a070; } /* BaseN */
|
||||||
code span.bu { } /* BuiltIn */
|
code span.bu { color: #008000; } /* BuiltIn */
|
||||||
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
|
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
|
||||||
code span.ch { color: #4070a0; } /* Char */
|
code span.ch { color: #4070a0; } /* Char */
|
||||||
code span.cn { color: #880000; } /* Constant */
|
code span.cn { color: #880000; } /* Constant */
|
||||||
@ -64,7 +216,7 @@
|
|||||||
code span.ex { } /* Extension */
|
code span.ex { } /* Extension */
|
||||||
code span.fl { color: #40a070; } /* Float */
|
code span.fl { color: #40a070; } /* Float */
|
||||||
code span.fu { color: #06287e; } /* Function */
|
code span.fu { color: #06287e; } /* Function */
|
||||||
code span.im { } /* Import */
|
code span.im { color: #008000; font-weight: bold; } /* Import */
|
||||||
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
|
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
|
||||||
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
|
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
|
||||||
code span.op { color: #666666; } /* Operator */
|
code span.op { color: #666666; } /* Operator */
|
||||||
@ -86,165 +238,253 @@
|
|||||||
</header>
|
</header>
|
||||||
<nav id="TOC" role="doc-toc">
|
<nav id="TOC" role="doc-toc">
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="#name">Name</a></li>
|
<li><a href="#name" id="toc-name">Name</a></li>
|
||||||
<li><a href="#description">Description</a></li>
|
<li><a href="#description" id="toc-description">Description</a></li>
|
||||||
<li><a href="#usage">Usage</a>
|
<li><a href="#usage" id="toc-usage">Usage</a>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="#flags">Flags</a></li>
|
<li><a href="#flags" id="toc-flags">Flags</a></li>
|
||||||
<li><a href="#default-keyboard-bindings">Default keyboard bindings</a></li>
|
<li><a href="#default-keyboard-bindings"
|
||||||
|
id="toc-default-keyboard-bindings">Default keyboard bindings</a></li>
|
||||||
</ul></li>
|
</ul></li>
|
||||||
<li><a href="#examples">Examples</a></li>
|
<li><a href="#examples" id="toc-examples">Examples</a></li>
|
||||||
<li><a href="#customization">Customization</a>
|
<li><a href="#customization" id="toc-customization">Customization</a>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="#modular-configuration">Modular Configuration</a></li>
|
<li><a href="#modular-configuration"
|
||||||
|
id="toc-modular-configuration">Modular Configuration</a></li>
|
||||||
</ul></li>
|
</ul></li>
|
||||||
<li><a href="#bugs">Bugs</a></li>
|
<li><a href="#bugs" id="toc-bugs">Bugs</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
<h1 id="name">Name</h1>
|
<h1 id="name">Name</h1>
|
||||||
<p>xmonad - Tiling Window Manager</p>
|
<p>xmonad - Tiling Window Manager</p>
|
||||||
<h1 id="description">Description</h1>
|
<h1 id="description">Description</h1>
|
||||||
<p><em>xmonad</em> is a minimalist tiling window manager for X, written in Haskell. Windows are managed using automatic layout algorithms, which can be dynamically reconfigured. At any time windows are arranged so as to maximize the use of screen real estate. All features of the window manager are accessible purely from the keyboard: a mouse is entirely optional. <em>xmonad</em> is configured in Haskell, and custom layout algorithms may be implemented by the user in config files. A principle of <em>xmonad</em> is predictability: the user should know in advance precisely the window arrangement that will result from any action.</p>
|
<p><em>xmonad</em> is a minimalist tiling window manager for X, written
|
||||||
<p>By default, <em>xmonad</em> provides three layout algorithms: tall, wide and fullscreen. In tall or wide mode, windows are tiled and arranged to prevent overlap and maximize screen use. Sets of windows are grouped together on virtual screens, and each screen retains its own layout, which may be reconfigured dynamically. Multiple physical monitors are supported via Xinerama, allowing simultaneous display of a number of screens.</p>
|
in Haskell. Windows are managed using automatic layout algorithms, which
|
||||||
<p>By utilizing the expressivity of a modern functional language with a rich static type system, <em>xmonad</em> provides a complete, featureful window manager in less than 1200 lines of code, with an emphasis on correctness and robustness. Internal properties of the window manager are checked using a combination of static guarantees provided by the type system, and type-based automated testing. A benefit of this is that the code is simple to understand, and easy to modify.</p>
|
can be dynamically reconfigured. At any time windows are arranged so as
|
||||||
|
to maximize the use of screen real estate. All features of the window
|
||||||
|
manager are accessible purely from the keyboard: a mouse is entirely
|
||||||
|
optional. <em>xmonad</em> is configured in Haskell, and custom layout
|
||||||
|
algorithms may be implemented by the user in config files. A principle
|
||||||
|
of <em>xmonad</em> is predictability: the user should know in advance
|
||||||
|
precisely the window arrangement that will result from any action.</p>
|
||||||
|
<p>By default, <em>xmonad</em> provides three layout algorithms: tall,
|
||||||
|
wide and fullscreen. In tall or wide mode, windows are tiled and
|
||||||
|
arranged to prevent overlap and maximize screen use. Sets of windows are
|
||||||
|
grouped together on virtual screens, and each screen retains its own
|
||||||
|
layout, which may be reconfigured dynamically. Multiple physical
|
||||||
|
monitors are supported via Xinerama, allowing simultaneous display of a
|
||||||
|
number of screens.</p>
|
||||||
|
<p>By utilizing the expressivity of a modern functional language with a
|
||||||
|
rich static type system, <em>xmonad</em> provides a complete, featureful
|
||||||
|
window manager in less than 1200 lines of code, with an emphasis on
|
||||||
|
correctness and robustness. Internal properties of the window manager
|
||||||
|
are checked using a combination of static guarantees provided by the
|
||||||
|
type system, and type-based automated testing. A benefit of this is that
|
||||||
|
the code is simple to understand, and easy to modify.</p>
|
||||||
<h1 id="usage">Usage</h1>
|
<h1 id="usage">Usage</h1>
|
||||||
<p><em>xmonad</em> places each window into a “workspace”. Each workspace can have any number of windows, which you can cycle though with mod-j and mod-k. Windows are either displayed full screen, tiled horizontally, or tiled vertically. You can toggle the layout mode with mod-space, which will cycle through the available modes.</p>
|
<p><em>xmonad</em> places each window into a “workspace”. Each workspace
|
||||||
<p>You can switch to workspace N with mod-N. For example, to switch to workspace 5, you would press mod-5. Similarly, you can move the current window to another workspace with mod-shift-N.</p>
|
can have any number of windows, which you can cycle though with mod-j
|
||||||
<p>When running with multiple monitors (Xinerama), each screen has exactly 1 workspace visible. mod-{w,e,r} switch the focus between screens, while shift-mod-{w,e,r} move the current window to that screen. When <em>xmonad</em> starts, workspace 1 is on screen 1, workspace 2 is on screen 2, etc. When switching workspaces to one that is already visible, the current and visible workspaces are swapped.</p>
|
and mod-k. Windows are either displayed full screen, tiled horizontally,
|
||||||
|
or tiled vertically. You can toggle the layout mode with mod-space,
|
||||||
|
which will cycle through the available modes.</p>
|
||||||
|
<p>You can switch to workspace N with mod-N. For example, to switch to
|
||||||
|
workspace 5, you would press mod-5. Similarly, you can move the current
|
||||||
|
window to another workspace with mod-shift-N.</p>
|
||||||
|
<p>When running with multiple monitors (Xinerama), each screen has
|
||||||
|
exactly 1 workspace visible. mod-{w,e,r} switch the focus between
|
||||||
|
screens, while shift-mod-{w,e,r} move the current window to that screen.
|
||||||
|
When <em>xmonad</em> starts, workspace 1 is on screen 1, workspace 2 is
|
||||||
|
on screen 2, etc. When switching workspaces to one that is already
|
||||||
|
visible, the current and visible workspaces are swapped.</p>
|
||||||
<h2 id="flags">Flags</h2>
|
<h2 id="flags">Flags</h2>
|
||||||
<p>xmonad has several flags which you may pass to the executable. These flags are:</p>
|
<p>xmonad has several flags which you may pass to the executable. These
|
||||||
|
flags are:</p>
|
||||||
<dl>
|
<dl>
|
||||||
<dt>–recompile</dt>
|
<dt>–recompile</dt>
|
||||||
<dd>Recompiles your <em>xmonad.hs</em> configuration
|
<dd>
|
||||||
|
Recompiles your <em>xmonad.hs</em> configuration
|
||||||
</dd>
|
</dd>
|
||||||
<dt>–restart</dt>
|
<dt>–restart</dt>
|
||||||
<dd>Causes the currently running <em>xmonad</em> process to restart
|
<dd>
|
||||||
|
Causes the currently running <em>xmonad</em> process to restart
|
||||||
</dd>
|
</dd>
|
||||||
<dt>–replace</dt>
|
<dt>–replace</dt>
|
||||||
<dd>Replace the current window manager with xmonad
|
<dd>
|
||||||
|
Replace the current window manager with xmonad
|
||||||
</dd>
|
</dd>
|
||||||
<dt>–version</dt>
|
<dt>–version</dt>
|
||||||
<dd>Display version of <em>xmonad</em>
|
<dd>
|
||||||
|
Display version of <em>xmonad</em>
|
||||||
</dd>
|
</dd>
|
||||||
<dt>–verbose-version</dt>
|
<dt>–verbose-version</dt>
|
||||||
<dd>Display detailed version of <em>xmonad</em>
|
<dd>
|
||||||
|
Display detailed version of <em>xmonad</em>
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<h2 id="default-keyboard-bindings">Default keyboard bindings</h2>
|
<h2 id="default-keyboard-bindings">Default keyboard bindings</h2>
|
||||||
<dl>
|
<dl>
|
||||||
<dt>mod-shift-return</dt>
|
<dt>mod-shift-return</dt>
|
||||||
<dd>Launch terminal
|
<dd>
|
||||||
|
Launch terminal
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-p</dt>
|
<dt>mod-p</dt>
|
||||||
<dd>Launch dmenu
|
<dd>
|
||||||
|
Launch dmenu
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-shift-p</dt>
|
<dt>mod-shift-p</dt>
|
||||||
<dd>Launch gmrun
|
<dd>
|
||||||
|
Launch gmrun
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-shift-c</dt>
|
<dt>mod-shift-c</dt>
|
||||||
<dd>Close the focused window
|
<dd>
|
||||||
|
Close the focused window
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-space</dt>
|
<dt>mod-space</dt>
|
||||||
<dd>Rotate through the available layout algorithms
|
<dd>
|
||||||
|
Rotate through the available layout algorithms
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-shift-space</dt>
|
<dt>mod-shift-space</dt>
|
||||||
<dd>Reset the layouts on the current workspace to default
|
<dd>
|
||||||
|
Reset the layouts on the current workspace to default
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-n</dt>
|
<dt>mod-n</dt>
|
||||||
<dd>Resize viewed windows to the correct size
|
<dd>
|
||||||
|
Resize viewed windows to the correct size
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-tab</dt>
|
<dt>mod-tab</dt>
|
||||||
<dd>Move focus to the next window
|
<dd>
|
||||||
|
Move focus to the next window
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-shift-tab</dt>
|
<dt>mod-shift-tab</dt>
|
||||||
<dd>Move focus to the previous window
|
<dd>
|
||||||
|
Move focus to the previous window
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-j</dt>
|
<dt>mod-j</dt>
|
||||||
<dd>Move focus to the next window
|
<dd>
|
||||||
|
Move focus to the next window
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-k</dt>
|
<dt>mod-k</dt>
|
||||||
<dd>Move focus to the previous window
|
<dd>
|
||||||
|
Move focus to the previous window
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-m</dt>
|
<dt>mod-m</dt>
|
||||||
<dd>Move focus to the master window
|
<dd>
|
||||||
|
Move focus to the master window
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-return</dt>
|
<dt>mod-return</dt>
|
||||||
<dd>Swap the focused window and the master window
|
<dd>
|
||||||
|
Swap the focused window and the master window
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-shift-j</dt>
|
<dt>mod-shift-j</dt>
|
||||||
<dd>Swap the focused window with the next window
|
<dd>
|
||||||
|
Swap the focused window with the next window
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-shift-k</dt>
|
<dt>mod-shift-k</dt>
|
||||||
<dd>Swap the focused window with the previous window
|
<dd>
|
||||||
|
Swap the focused window with the previous window
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-h</dt>
|
<dt>mod-h</dt>
|
||||||
<dd>Shrink the master area
|
<dd>
|
||||||
|
Shrink the master area
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-l</dt>
|
<dt>mod-l</dt>
|
||||||
<dd>Expand the master area
|
<dd>
|
||||||
|
Expand the master area
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-t</dt>
|
<dt>mod-t</dt>
|
||||||
<dd>Push window back into tiling
|
<dd>
|
||||||
|
Push window back into tiling
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-comma</dt>
|
<dt>mod-comma</dt>
|
||||||
<dd>Increment the number of windows in the master area
|
<dd>
|
||||||
|
Increment the number of windows in the master area
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-period</dt>
|
<dt>mod-period</dt>
|
||||||
<dd>Deincrement the number of windows in the master area
|
<dd>
|
||||||
|
Deincrement the number of windows in the master area
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-shift-q</dt>
|
<dt>mod-shift-q</dt>
|
||||||
<dd>Quit xmonad
|
<dd>
|
||||||
|
Quit xmonad
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-q</dt>
|
<dt>mod-q</dt>
|
||||||
<dd>Restart xmonad
|
<dd>
|
||||||
|
Restart xmonad
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-shift-slash</dt>
|
<dt>mod-shift-slash</dt>
|
||||||
<dd>Run xmessage with a summary of the default keybindings (useful for beginners)
|
<dd>
|
||||||
|
Run xmessage with a summary of the default keybindings (useful for
|
||||||
|
beginners)
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-question</dt>
|
<dt>mod-question</dt>
|
||||||
<dd>Run xmessage with a summary of the default keybindings (useful for beginners)
|
<dd>
|
||||||
|
Run xmessage with a summary of the default keybindings (useful for
|
||||||
|
beginners)
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-[1..9]</dt>
|
<dt>mod-[1..9]</dt>
|
||||||
<dd>Switch to workspace N
|
<dd>
|
||||||
|
Switch to workspace N
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-shift-[1..9]</dt>
|
<dt>mod-shift-[1..9]</dt>
|
||||||
<dd>Move client to workspace N
|
<dd>
|
||||||
|
Move client to workspace N
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-{w,e,r}</dt>
|
<dt>mod-{w,e,r}</dt>
|
||||||
<dd>Switch to physical/Xinerama screens 1, 2, or 3
|
<dd>
|
||||||
|
Switch to physical/Xinerama screens 1, 2, or 3
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-shift-{w,e,r}</dt>
|
<dt>mod-shift-{w,e,r}</dt>
|
||||||
<dd>Move client to screen 1, 2, or 3
|
<dd>
|
||||||
|
Move client to screen 1, 2, or 3
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-button1</dt>
|
<dt>mod-button1</dt>
|
||||||
<dd>Set the window to floating mode and move by dragging
|
<dd>
|
||||||
|
Set the window to floating mode and move by dragging
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-button2</dt>
|
<dt>mod-button2</dt>
|
||||||
<dd>Raise the window to the top of the stack
|
<dd>
|
||||||
|
Raise the window to the top of the stack
|
||||||
</dd>
|
</dd>
|
||||||
<dt>mod-button3</dt>
|
<dt>mod-button3</dt>
|
||||||
<dd>Set the window to floating mode and resize by dragging
|
<dd>
|
||||||
|
Set the window to floating mode and resize by dragging
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<h1 id="examples">Examples</h1>
|
<h1 id="examples">Examples</h1>
|
||||||
<p>To use xmonad as your window manager add to your <em>~/.xinitrc</em> file:</p>
|
<p>To use xmonad as your window manager add to your <em>~/.xinitrc</em>
|
||||||
|
file:</p>
|
||||||
<blockquote>
|
<blockquote>
|
||||||
<p>exec xmonad</p>
|
<p>exec xmonad</p>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
<h1 id="customization">Customization</h1>
|
<h1 id="customization">Customization</h1>
|
||||||
<p>xmonad is customized in your <em>xmonad.hs</em>, and then restarted with mod-q. You can choose where your configuration file lives by</p>
|
<p>xmonad is customized in your <em>xmonad.hs</em>, and then restarted
|
||||||
|
with mod-q. You can choose where your configuration file lives by</p>
|
||||||
<ol type="1">
|
<ol type="1">
|
||||||
<li>Setting <code>XMONAD_DATA_DIR,</code> <code>XMONAD_CONFIG_DIR</code>, and <code>XMONAD_CACHE_DIR</code>; <em>xmonad.hs</em> is then expected to be in <code>XMONAD_CONFIG_DIR</code>.</li>
|
<li>Setting <code>XMONAD_DATA_DIR,</code>
|
||||||
|
<code>XMONAD_CONFIG_DIR</code>, and <code>XMONAD_CACHE_DIR</code>;
|
||||||
|
<em>xmonad.hs</em> is then expected to be in
|
||||||
|
<code>XMONAD_CONFIG_DIR</code>.</li>
|
||||||
<li>Creating <em>xmonad.hs</em> in <em>~/.xmonad</em>.</li>
|
<li>Creating <em>xmonad.hs</em> in <em>~/.xmonad</em>.</li>
|
||||||
<li>Creating <em>xmonad.hs</em> in <code>XDG_CONFIG_HOME</code>. Note that, in this case, xmonad will use <code>XDG_DATA_HOME</code> and <code>XDG_CACHE_HOME</code> for its data and cache directory respectively.</li>
|
<li>Creating <em>xmonad.hs</em> in <code>XDG_CONFIG_HOME</code>. Note
|
||||||
|
that, in this case, xmonad will use <code>XDG_DATA_HOME</code> and
|
||||||
|
<code>XDG_CACHE_HOME</code> for its data and cache directory
|
||||||
|
respectively.</li>
|
||||||
</ol>
|
</ol>
|
||||||
<p>You can find many extensions to the core feature set in the xmonad- contrib package, available through your package manager or from <a href="https://xmonad.org">xmonad.org</a>.</p>
|
<p>You can find many extensions to the core feature set in the xmonad-
|
||||||
|
contrib package, available through your package manager or from <a
|
||||||
|
href="https://xmonad.org">xmonad.org</a>.</p>
|
||||||
<h2 id="modular-configuration">Modular Configuration</h2>
|
<h2 id="modular-configuration">Modular Configuration</h2>
|
||||||
<p>As of <em>xmonad-0.9</em>, any additional Haskell modules may be placed in <em>~/.xmonad/lib/</em> are available in GHC’s searchpath. Hierarchical modules are supported: for example, the file <em>~/.xmonad/lib/XMonad/Stack/MyAdditions.hs</em> could contain:</p>
|
<p>As of <em>xmonad-0.9</em>, any additional Haskell modules may be
|
||||||
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true"></a><span class="kw">module</span> <span class="dt">XMonad.Stack.MyAdditions</span> (function1) <span class="kw">where</span></span>
|
placed in <em>~/.xmonad/lib/</em> are available in GHC’s searchpath.
|
||||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true"></a> function1 <span class="ot">=</span> <span class="fu">error</span> <span class="st">"function1: Not implemented yet!"</span></span></code></pre></div>
|
Hierarchical modules are supported: for example, the file
|
||||||
<p>Your xmonad.hs may then import XMonad.Stack.MyAdditions as if that module was contained within xmonad or xmonad-contrib.</p>
|
<em>~/.xmonad/lib/XMonad/Stack/MyAdditions.hs</em> could contain:</p>
|
||||||
|
<div class="sourceCode" id="cb1"><pre
|
||||||
|
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> <span class="dt">XMonad.Stack.MyAdditions</span> (function1) <span class="kw">where</span></span>
|
||||||
|
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a> function1 <span class="ot">=</span> <span class="fu">error</span> <span class="st">"function1: Not implemented yet!"</span></span></code></pre></div>
|
||||||
|
<p>Your xmonad.hs may then import XMonad.Stack.MyAdditions as if that
|
||||||
|
module was contained within xmonad or xmonad-contrib.</p>
|
||||||
<h1 id="bugs">Bugs</h1>
|
<h1 id="bugs">Bugs</h1>
|
||||||
<p>Probably. If you find any, please report them to the <a href="https://github.com/xmonad/xmonad/issues">bugtracker</a></p>
|
<p>Probably. If you find any, please report them to the <a
|
||||||
|
href="https://github.com/xmonad/xmonad/issues">bugtracker</a></p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
{-# LANGUAGE MultiParamTypeClasses #-}
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||||
{-# LANGUAGE NamedFieldPuns #-}
|
{-# LANGUAGE NamedFieldPuns #-}
|
||||||
{-# LANGUAGE ScopedTypeVariables #-}
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
|
{-# LANGUAGE DerivingVia #-}
|
||||||
|
{-# LANGUAGE ViewPatterns #-}
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
-- |
|
-- |
|
||||||
@ -32,7 +34,7 @@ module XMonad.Core (
|
|||||||
StateExtension(..), ExtensionClass(..), ConfExtension(..),
|
StateExtension(..), ExtensionClass(..), ConfExtension(..),
|
||||||
runX, catchX, userCode, userCodeDef, io, catchIO, installSignalHandlers, uninstallSignalHandlers,
|
runX, catchX, userCode, userCodeDef, io, catchIO, installSignalHandlers, uninstallSignalHandlers,
|
||||||
withDisplay, withWindowSet, isRoot, runOnWorkspaces,
|
withDisplay, withWindowSet, isRoot, runOnWorkspaces,
|
||||||
getAtom, spawn, spawnPID, xfork, xmessage, recompile, trace, whenJust, whenX,
|
getAtom, spawn, spawnPID, xfork, xmessage, recompile, trace, whenJust, whenX, ifM,
|
||||||
getXMonadDir, getXMonadCacheDir, getXMonadDataDir, stateFileName, binFileName,
|
getXMonadDir, getXMonadCacheDir, getXMonadDataDir, stateFileName, binFileName,
|
||||||
atom_WM_STATE, atom_WM_PROTOCOLS, atom_WM_DELETE_WINDOW, atom_WM_TAKE_FOCUS, withWindowAttributes,
|
atom_WM_STATE, atom_WM_PROTOCOLS, atom_WM_DELETE_WINDOW, atom_WM_TAKE_FOCUS, withWindowAttributes,
|
||||||
ManageHook, Query(..), runQuery, Directories'(..), Directories, getDirectories,
|
ManageHook, Query(..), runQuery, Directories'(..), Directories, getDirectories,
|
||||||
@ -48,12 +50,14 @@ import Control.Monad.Fail
|
|||||||
import Control.Monad.Fix (fix)
|
import Control.Monad.Fix (fix)
|
||||||
import Control.Monad.State
|
import Control.Monad.State
|
||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
import Control.Monad (filterM, guard, liftM2, void, when)
|
import Control.Monad (filterM, guard, void, when)
|
||||||
|
import Data.Char (isSpace)
|
||||||
import Data.Semigroup
|
import Data.Semigroup
|
||||||
import Data.Traversable (for)
|
import Data.Traversable (for)
|
||||||
import Data.Time.Clock (UTCTime)
|
import Data.Time.Clock (UTCTime)
|
||||||
import Data.Default.Class
|
import Data.Default.Class
|
||||||
import System.Environment (lookupEnv)
|
import System.Environment (lookupEnv)
|
||||||
|
import Data.List (isInfixOf, intercalate, (\\))
|
||||||
import System.FilePath
|
import System.FilePath
|
||||||
import System.IO
|
import System.IO
|
||||||
import System.Info
|
import System.Info
|
||||||
@ -68,8 +72,8 @@ import System.Exit
|
|||||||
import Graphics.X11.Xlib
|
import Graphics.X11.Xlib
|
||||||
import Graphics.X11.Xlib.Extras (getWindowAttributes, WindowAttributes, Event)
|
import Graphics.X11.Xlib.Extras (getWindowAttributes, WindowAttributes, Event)
|
||||||
import Data.Typeable
|
import Data.Typeable
|
||||||
import Data.List (isInfixOf, (\\))
|
|
||||||
import Data.Maybe (isJust,fromMaybe)
|
import Data.Maybe (isJust,fromMaybe)
|
||||||
|
import Data.Monoid (Ap(..))
|
||||||
|
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
import qualified Data.Set as S
|
import qualified Data.Set as S
|
||||||
@ -165,12 +169,7 @@ newtype ScreenDetail = SD { screenRect :: Rectangle }
|
|||||||
--
|
--
|
||||||
newtype X a = X (ReaderT XConf (StateT XState IO) a)
|
newtype X a = X (ReaderT XConf (StateT XState IO) a)
|
||||||
deriving (Functor, Applicative, Monad, MonadFail, MonadIO, MonadState XState, MonadReader XConf)
|
deriving (Functor, Applicative, Monad, MonadFail, MonadIO, MonadState XState, MonadReader XConf)
|
||||||
|
deriving (Semigroup, Monoid) via Ap X a
|
||||||
instance Semigroup a => Semigroup (X a) where
|
|
||||||
(<>) = liftM2 (<>)
|
|
||||||
|
|
||||||
instance (Monoid a) => Monoid (X a) where
|
|
||||||
mempty = pure mempty
|
|
||||||
|
|
||||||
instance Default a => Default (X a) where
|
instance Default a => Default (X a) where
|
||||||
def = return def
|
def = return def
|
||||||
@ -178,16 +177,11 @@ instance Default a => Default (X a) where
|
|||||||
type ManageHook = Query (Endo WindowSet)
|
type ManageHook = Query (Endo WindowSet)
|
||||||
newtype Query a = Query (ReaderT Window X a)
|
newtype Query a = Query (ReaderT Window X a)
|
||||||
deriving (Functor, Applicative, Monad, MonadReader Window, MonadIO)
|
deriving (Functor, Applicative, Monad, MonadReader Window, MonadIO)
|
||||||
|
deriving (Semigroup, Monoid) via Ap Query a
|
||||||
|
|
||||||
runQuery :: Query a -> Window -> X a
|
runQuery :: Query a -> Window -> X a
|
||||||
runQuery (Query m) = runReaderT m
|
runQuery (Query m) = runReaderT m
|
||||||
|
|
||||||
instance Semigroup a => Semigroup (Query a) where
|
|
||||||
(<>) = liftM2 (<>)
|
|
||||||
|
|
||||||
instance Monoid a => Monoid (Query a) where
|
|
||||||
mempty = pure mempty
|
|
||||||
|
|
||||||
instance Default a => Default (Query a) where
|
instance Default a => Default (Query a) where
|
||||||
def = return def
|
def = return def
|
||||||
|
|
||||||
@ -423,9 +417,13 @@ data StateExtension =
|
|||||||
data ConfExtension = forall a. Typeable a => ConfExtension a
|
data ConfExtension = forall a. Typeable a => ConfExtension a
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------
|
-- ---------------------------------------------------------------------
|
||||||
-- | General utilities
|
-- General utilities
|
||||||
--
|
|
||||||
-- Lift an 'IO' action into the 'X' monad
|
-- | If-then-else lifted to a 'Monad'.
|
||||||
|
ifM :: Monad m => m Bool -> m a -> m a -> m a
|
||||||
|
ifM mb t f = mb >>= \b -> if b then t else f
|
||||||
|
|
||||||
|
-- | Lift an 'IO' action into the 'X' monad
|
||||||
io :: MonadIO m => IO a -> m a
|
io :: MonadIO m => IO a -> m a
|
||||||
io = liftIO
|
io = liftIO
|
||||||
|
|
||||||
@ -584,21 +582,32 @@ srcFileName, libFileName :: Directories -> FilePath
|
|||||||
srcFileName Directories{ cfgDir } = cfgDir </> "xmonad.hs"
|
srcFileName Directories{ cfgDir } = cfgDir </> "xmonad.hs"
|
||||||
libFileName Directories{ cfgDir } = cfgDir </> "lib"
|
libFileName Directories{ cfgDir } = cfgDir </> "lib"
|
||||||
|
|
||||||
buildScriptFileName, stackYamlFileName :: Directories -> FilePath
|
buildScriptFileName, stackYamlFileName, nixFlakeFileName, nixDefaultFileName :: Directories -> FilePath
|
||||||
buildScriptFileName Directories{ cfgDir } = cfgDir </> "build"
|
buildScriptFileName Directories{ cfgDir } = cfgDir </> "build"
|
||||||
stackYamlFileName Directories{ cfgDir } = cfgDir </> "stack.yaml"
|
stackYamlFileName Directories{ cfgDir } = cfgDir </> "stack.yaml"
|
||||||
|
nixFlakeFileName Directories{ cfgDir } = cfgDir </> "flake.nix"
|
||||||
|
nixDefaultFileName Directories{ cfgDir } = cfgDir </> "default.nix"
|
||||||
|
|
||||||
-- | Compilation method for xmonad configuration.
|
-- | Compilation method for xmonad configuration.
|
||||||
data Compile = CompileGhc | CompileStackGhc FilePath | CompileScript FilePath
|
data Compile
|
||||||
|
= CompileGhc
|
||||||
|
| CompileCabal
|
||||||
|
| CompileStackGhc FilePath
|
||||||
|
| CompileNixFlake
|
||||||
|
| CompileNixDefault
|
||||||
|
| CompileScript FilePath
|
||||||
deriving (Show)
|
deriving (Show)
|
||||||
|
|
||||||
-- | Detect compilation method by looking for known file names in xmonad
|
-- | Detect compilation method by looking for known file names in xmonad
|
||||||
-- configuration directory.
|
-- configuration directory.
|
||||||
detectCompile :: Directories -> IO Compile
|
detectCompile :: Directories -> IO Compile
|
||||||
detectCompile dirs = tryScript <|> tryStack <|> useGhc
|
detectCompile dirs =
|
||||||
|
tryScript <|> tryStack <|> tryNixFlake <|> tryNixDefault <|> tryCabal <|> useGhc
|
||||||
where
|
where
|
||||||
buildScript = buildScriptFileName dirs
|
buildScript = buildScriptFileName dirs
|
||||||
stackYaml = stackYamlFileName dirs
|
stackYaml = stackYamlFileName dirs
|
||||||
|
flakeNix = nixFlakeFileName dirs
|
||||||
|
defaultNix = nixDefaultFileName dirs
|
||||||
|
|
||||||
tryScript = do
|
tryScript = do
|
||||||
guard =<< doesFileExist buildScript
|
guard =<< doesFileExist buildScript
|
||||||
@ -612,18 +621,58 @@ detectCompile dirs = tryScript <|> tryStack <|> useGhc
|
|||||||
trace $ "Suggested resolution to use it: chmod u+x " <> show buildScript
|
trace $ "Suggested resolution to use it: chmod u+x " <> show buildScript
|
||||||
empty
|
empty
|
||||||
|
|
||||||
|
tryNixFlake = do
|
||||||
|
guard =<< doesFileExist flakeNix
|
||||||
|
canonNixFlake <- canonicalizePath flakeNix
|
||||||
|
trace $ "XMonad will use nix flake at " <> show canonNixFlake <> " to recompile"
|
||||||
|
pure CompileNixFlake
|
||||||
|
|
||||||
|
tryNixDefault = do
|
||||||
|
guard =<< doesFileExist defaultNix
|
||||||
|
canonNixDefault <- canonicalizePath defaultNix
|
||||||
|
trace $ "XMonad will use nix file at " <> show canonNixDefault <> " to recompile"
|
||||||
|
pure CompileNixDefault
|
||||||
|
|
||||||
tryStack = do
|
tryStack = do
|
||||||
guard =<< doesFileExist stackYaml
|
guard =<< doesFileExist stackYaml
|
||||||
canonStackYaml <- canonicalizePath stackYaml
|
canonStackYaml <- canonicalizePath stackYaml
|
||||||
trace $ "XMonad will use stack ghc --stack-yaml " <> show canonStackYaml <> " to recompile."
|
trace $ "XMonad will use stack ghc --stack-yaml " <> show canonStackYaml <> " to recompile."
|
||||||
pure $ CompileStackGhc canonStackYaml
|
pure $ CompileStackGhc canonStackYaml
|
||||||
|
|
||||||
|
tryCabal = let cwd = cfgDir dirs in listCabalFiles cwd >>= \ case
|
||||||
|
[] -> do
|
||||||
|
empty
|
||||||
|
[name] -> do
|
||||||
|
trace $ "XMonad will use " <> show name <> " to recompile."
|
||||||
|
pure CompileCabal
|
||||||
|
_ : _ : _ -> do
|
||||||
|
trace $ "XMonad will not use cabal, because there are multiple cabal files in " <> show cwd <> "."
|
||||||
|
empty
|
||||||
|
|
||||||
useGhc = do
|
useGhc = do
|
||||||
trace $ "XMonad will use ghc to recompile, because neither "
|
trace $ "XMonad will use ghc to recompile, because none of "
|
||||||
<> show buildScript <> " nor " <> show stackYaml <> " exists."
|
<> intercalate ", "
|
||||||
|
[ show buildScript
|
||||||
|
, show stackYaml
|
||||||
|
, show flakeNix
|
||||||
|
, show defaultNix
|
||||||
|
] <> " nor a suitable .cabal file exist."
|
||||||
pure CompileGhc
|
pure CompileGhc
|
||||||
|
|
||||||
isExecutable f = E.catch (executable <$> getPermissions f) (\(SomeException _) -> return False)
|
listCabalFiles :: FilePath -> IO [FilePath]
|
||||||
|
listCabalFiles dir = map (dir </>) . Prelude.filter isCabalFile <$> listFiles dir
|
||||||
|
|
||||||
|
isCabalFile :: FilePath -> Bool
|
||||||
|
isCabalFile file = case splitExtension file of
|
||||||
|
(name, ".cabal") -> not (null name)
|
||||||
|
_ -> False
|
||||||
|
|
||||||
|
listFiles :: FilePath -> IO [FilePath]
|
||||||
|
listFiles dir = getDirectoryContents dir >>= filterM (doesFileExist . (dir </>))
|
||||||
|
|
||||||
|
-- | Determine whether or not the file found at the provided filepath is executable.
|
||||||
|
isExecutable :: FilePath -> IO Bool
|
||||||
|
isExecutable f = E.catch (executable <$> getPermissions f) (\(SomeException _) -> return False)
|
||||||
|
|
||||||
-- | Should we recompile xmonad configuration? Is it newer than the compiled
|
-- | Should we recompile xmonad configuration? Is it newer than the compiled
|
||||||
-- binary?
|
-- binary?
|
||||||
@ -642,12 +691,15 @@ shouldCompile dirs CompileGhc = do
|
|||||||
cs <- prep <$> E.catch (getDirectoryContents t) (\(SomeException _) -> return [])
|
cs <- prep <$> E.catch (getDirectoryContents t) (\(SomeException _) -> return [])
|
||||||
ds <- filterM doesDirectoryExist cs
|
ds <- filterM doesDirectoryExist cs
|
||||||
concat . ((cs \\ ds):) <$> mapM allFiles ds
|
concat . ((cs \\ ds):) <$> mapM allFiles ds
|
||||||
|
shouldCompile _ CompileCabal = return True
|
||||||
shouldCompile dirs CompileStackGhc{} = do
|
shouldCompile dirs CompileStackGhc{} = do
|
||||||
stackYamlT <- getModTime (stackYamlFileName dirs)
|
stackYamlT <- getModTime (stackYamlFileName dirs)
|
||||||
binT <- getModTime (binFileName dirs)
|
binT <- getModTime (binFileName dirs)
|
||||||
if binT < stackYamlT
|
if binT < stackYamlT
|
||||||
then True <$ trace "XMonad recompiling because some files have changed."
|
then True <$ trace "XMonad recompiling because some files have changed."
|
||||||
else shouldCompile dirs CompileGhc
|
else shouldCompile dirs CompileGhc
|
||||||
|
shouldCompile _dirs CompileNixFlake{} = True <$ trace "XMonad recompiling because flake recompilation is being used."
|
||||||
|
shouldCompile _dirs CompileNixDefault{} = True <$ trace "XMonad recompiling because nix recompilation is being used."
|
||||||
shouldCompile _dirs CompileScript{} =
|
shouldCompile _dirs CompileScript{} =
|
||||||
True <$ trace "XMonad recompiling because a custom build script is being used."
|
True <$ trace "XMonad recompiling because a custom build script is being used."
|
||||||
|
|
||||||
@ -659,17 +711,31 @@ compile :: Directories -> Compile -> IO ExitCode
|
|||||||
compile dirs method =
|
compile dirs method =
|
||||||
bracket_ uninstallSignalHandlers installSignalHandlers $
|
bracket_ uninstallSignalHandlers installSignalHandlers $
|
||||||
withFile (errFileName dirs) WriteMode $ \err -> do
|
withFile (errFileName dirs) WriteMode $ \err -> do
|
||||||
let run = runProc (cfgDir dirs) err
|
let run = runProc err
|
||||||
case method of
|
case method of
|
||||||
CompileGhc -> do
|
CompileGhc -> do
|
||||||
ghc <- fromMaybe "ghc" <$> lookupEnv "XMONAD_GHC"
|
ghc <- fromMaybe "ghc" <$> lookupEnv "XMONAD_GHC"
|
||||||
run ghc ghcArgs
|
run ghc ghcArgs
|
||||||
|
CompileCabal -> run "cabal" ["build"] .&&. copyBinary
|
||||||
|
where
|
||||||
|
copyBinary :: IO ExitCode
|
||||||
|
copyBinary = readProc err "cabal" ["-v0", "list-bin", "."] >>= \ case
|
||||||
|
Left status -> return status
|
||||||
|
Right (trim -> path) -> copyBinaryFrom path
|
||||||
CompileStackGhc stackYaml ->
|
CompileStackGhc stackYaml ->
|
||||||
run "stack" ["build", "--silent", "--stack-yaml", stackYaml] .&&.
|
run "stack" ["build", "--silent", "--stack-yaml", stackYaml] .&&.
|
||||||
run "stack" ("ghc" : "--stack-yaml" : stackYaml : "--" : ghcArgs)
|
run "stack" ("ghc" : "--stack-yaml" : stackYaml : "--" : ghcArgs)
|
||||||
|
CompileNixFlake ->
|
||||||
|
run "nix" ["build"] >>= andCopyFromResultDir
|
||||||
|
CompileNixDefault ->
|
||||||
|
run "nix-build" [] >>= andCopyFromResultDir
|
||||||
CompileScript script ->
|
CompileScript script ->
|
||||||
run script [binFileName dirs]
|
run script [binFileName dirs]
|
||||||
where
|
where
|
||||||
|
cwd :: FilePath
|
||||||
|
cwd = cfgDir dirs
|
||||||
|
|
||||||
|
ghcArgs :: [String]
|
||||||
ghcArgs = [ "--make"
|
ghcArgs = [ "--make"
|
||||||
, "xmonad.hs"
|
, "xmonad.hs"
|
||||||
, "-i" -- only look in @lib@
|
, "-i" -- only look in @lib@
|
||||||
@ -681,13 +747,51 @@ compile dirs method =
|
|||||||
, "-o", binFileName dirs
|
, "-o", binFileName dirs
|
||||||
]
|
]
|
||||||
|
|
||||||
|
andCopyFromResultDir :: ExitCode -> IO ExitCode
|
||||||
|
andCopyFromResultDir exitCode = do
|
||||||
|
if exitCode == ExitSuccess then copyFromResultDir else return exitCode
|
||||||
|
|
||||||
|
findM :: (Monad m, Foldable t) => (a -> m Bool) -> t a -> m (Maybe a)
|
||||||
|
findM p = foldr (\x -> ifM (p x) (pure $ Just x)) (pure Nothing)
|
||||||
|
|
||||||
|
catchAny :: IO a -> (SomeException -> IO a) -> IO a
|
||||||
|
catchAny = E.catch
|
||||||
|
|
||||||
|
copyFromResultDir :: IO ExitCode
|
||||||
|
copyFromResultDir = do
|
||||||
|
let binaryDirectory = cfgDir dirs </> "result" </> "bin"
|
||||||
|
binFiles <- map (binaryDirectory </>) <$> catchAny (listDirectory binaryDirectory) (\_ -> return [])
|
||||||
|
mfilepath <- findM isExecutable binFiles
|
||||||
|
case mfilepath of
|
||||||
|
Just filepath -> copyBinaryFrom filepath
|
||||||
|
Nothing -> return $ ExitFailure 1
|
||||||
|
|
||||||
|
copyBinaryFrom :: FilePath -> IO ExitCode
|
||||||
|
copyBinaryFrom filepath = copyFile filepath (binFileName dirs) >> return ExitSuccess
|
||||||
|
|
||||||
-- waitForProcess =<< System.Process.runProcess, but without closing the err handle
|
-- waitForProcess =<< System.Process.runProcess, but without closing the err handle
|
||||||
runProc cwd err exe args = do
|
runProc :: Handle -> String -> [String] -> IO ExitCode
|
||||||
hPutStrLn err $ unwords $ "$" : exe : args
|
runProc err exe args = do
|
||||||
hFlush err
|
(Nothing, Nothing, Nothing, h) <- createProcess_ "runProc" =<< mkProc err exe args
|
||||||
(_, _, _, h) <- createProcess_ "runProc" (proc exe args){ cwd = Just cwd, std_err = UseHandle err }
|
|
||||||
waitForProcess h
|
waitForProcess h
|
||||||
|
|
||||||
|
readProc :: Handle -> String -> [String] -> IO (Either ExitCode String)
|
||||||
|
readProc err exe args = do
|
||||||
|
spec <- mkProc err exe args
|
||||||
|
(Nothing, Just out, Nothing, h) <- createProcess_ "readProc" spec{ std_out = CreatePipe }
|
||||||
|
result <- hGetContents out
|
||||||
|
hPutStr err result >> hFlush err
|
||||||
|
waitForProcess h >>= \ case
|
||||||
|
ExitSuccess -> return $ Right result
|
||||||
|
status -> return $ Left status
|
||||||
|
|
||||||
|
mkProc :: Handle -> FilePath -> [FilePath] -> IO CreateProcess
|
||||||
|
mkProc err exe args = do
|
||||||
|
hPutStrLn err $ unwords $ "$" : exe : args
|
||||||
|
hFlush err
|
||||||
|
return (proc exe args){ cwd = Just cwd, std_err = UseHandle err }
|
||||||
|
|
||||||
|
(.&&.) :: Monad m => m ExitCode -> m ExitCode -> m ExitCode
|
||||||
cmd1 .&&. cmd2 = cmd1 >>= \case
|
cmd1 .&&. cmd2 = cmd1 >>= \case
|
||||||
ExitSuccess -> cmd2
|
ExitSuccess -> cmd2
|
||||||
e -> pure e
|
e -> pure e
|
||||||
@ -787,3 +891,6 @@ uninstallSignalHandlers = io $ do
|
|||||||
installHandler openEndedPipe Default Nothing
|
installHandler openEndedPipe Default Nothing
|
||||||
installHandler sigCHLD Default Nothing
|
installHandler sigCHLD Default Nothing
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
|
trim :: String -> String
|
||||||
|
trim = reverse . dropWhile isSpace . reverse . dropWhile isSpace
|
||||||
|
@ -62,9 +62,13 @@ data Tall a = Tall { tallNMaster :: !Int -- ^ The default number o
|
|||||||
|
|
||||||
-- a nice pure layout, lots of properties for the layout, and its messages, in Properties.hs
|
-- a nice pure layout, lots of properties for the layout, and its messages, in Properties.hs
|
||||||
instance LayoutClass Tall a where
|
instance LayoutClass Tall a where
|
||||||
pureLayout (Tall nmaster _ frac) r s = zip ws rs
|
pureLayout (Tall nmaster _ frac) r s
|
||||||
|
| frac == 0 = drop nmaster layout
|
||||||
|
| frac == 1 = take nmaster layout
|
||||||
|
| otherwise = layout
|
||||||
where ws = W.integrate s
|
where ws = W.integrate s
|
||||||
rs = tile frac r nmaster (length ws)
|
rs = tile frac r nmaster (length ws)
|
||||||
|
layout = zip ws rs
|
||||||
|
|
||||||
pureMessage (Tall nmaster delta frac) m =
|
pureMessage (Tall nmaster delta frac) m =
|
||||||
msum [fmap resize (fromMessage m)
|
msum [fmap resize (fromMessage m)
|
||||||
|
@ -15,19 +15,18 @@
|
|||||||
--
|
--
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
module XMonad.Main (xmonad, launch) where
|
module XMonad.Main (xmonad, buildLaunch, launch) where
|
||||||
|
|
||||||
import System.Locale.SetLocale
|
import System.Locale.SetLocale
|
||||||
import qualified Control.Exception as E
|
import qualified Control.Exception as E
|
||||||
import Data.Bits
|
import Data.Bits
|
||||||
import Data.List ((\\))
|
import Data.List ((\\))
|
||||||
import Data.Foldable (traverse_)
|
import Data.Foldable (traverse_)
|
||||||
import Data.Function
|
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
import qualified Data.Set as S
|
import qualified Data.Set as S
|
||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
import Control.Monad.State
|
import Control.Monad.State
|
||||||
import Control.Monad (filterM, guard, unless, void, when)
|
import Control.Monad (filterM, guard, unless, void, when, forever)
|
||||||
import Data.Maybe (fromMaybe, isJust)
|
import Data.Maybe (fromMaybe, isJust)
|
||||||
import Data.Monoid (getAll)
|
import Data.Monoid (getAll)
|
||||||
|
|
||||||
@ -132,25 +131,6 @@ buildLaunch dirs = do
|
|||||||
args <- getArgs
|
args <- getArgs
|
||||||
executeFile bin False args Nothing
|
executeFile bin False args Nothing
|
||||||
|
|
||||||
sendRestart :: IO ()
|
|
||||||
sendRestart = do
|
|
||||||
dpy <- openDisplay ""
|
|
||||||
rw <- rootWindow dpy $ defaultScreen dpy
|
|
||||||
xmonad_restart <- internAtom dpy "XMONAD_RESTART" False
|
|
||||||
allocaXEvent $ \e -> do
|
|
||||||
setEventType e clientMessage
|
|
||||||
setClientMessageEvent' e rw xmonad_restart 32 []
|
|
||||||
sendEvent dpy rw False structureNotifyMask e
|
|
||||||
sync dpy False
|
|
||||||
|
|
||||||
-- | a wrapper for 'replace'
|
|
||||||
sendReplace :: IO ()
|
|
||||||
sendReplace = do
|
|
||||||
dpy <- openDisplay ""
|
|
||||||
let dflt = defaultScreen dpy
|
|
||||||
rootw <- rootWindow dpy dflt
|
|
||||||
replace dpy dflt rootw
|
|
||||||
|
|
||||||
-- | Entry point into xmonad for custom builds.
|
-- | Entry point into xmonad for custom builds.
|
||||||
--
|
--
|
||||||
-- This function isn't meant to be called by the typical xmonad user
|
-- This function isn't meant to be called by the typical xmonad user
|
||||||
@ -268,11 +248,10 @@ launch initxmc drs = do
|
|||||||
userCode $ startupHook initxmc
|
userCode $ startupHook initxmc
|
||||||
|
|
||||||
rrData <- io $ xrrQueryExtension dpy
|
rrData <- io $ xrrQueryExtension dpy
|
||||||
|
let rrUpdate = when (isJust rrData) . void . xrrUpdateConfiguration
|
||||||
|
|
||||||
-- main loop, for all you HOF/recursion fans out there.
|
-- main loop, for all you HOF/recursion fans out there.
|
||||||
-- forever $ prehandle =<< io (nextEvent dpy e >> rrUpdate e >> getEvent e)
|
forever $ prehandle =<< io (nextEvent dpy e >> rrUpdate e >> getEvent e)
|
||||||
-- sadly, 9.2.{1,2,3} join points mishandle the above and trash the heap (see #389)
|
|
||||||
mainLoop dpy e rrData
|
|
||||||
|
|
||||||
return ()
|
return ()
|
||||||
where
|
where
|
||||||
@ -283,8 +262,6 @@ launch initxmc drs = do
|
|||||||
in local (\c -> c { mousePosition = mouse, currentEvent = Just e }) (handleWithHook e)
|
in local (\c -> c { mousePosition = mouse, currentEvent = Just e }) (handleWithHook e)
|
||||||
evs = [ keyPress, keyRelease, enterNotify, leaveNotify
|
evs = [ keyPress, keyRelease, enterNotify, leaveNotify
|
||||||
, buttonPress, buttonRelease]
|
, buttonPress, buttonRelease]
|
||||||
rrUpdate e r = when (isJust r) (void (xrrUpdateConfiguration e))
|
|
||||||
mainLoop d e r = io (nextEvent d e >> rrUpdate e r >> getEvent e) >>= prehandle >> mainLoop d e r
|
|
||||||
|
|
||||||
|
|
||||||
-- | Runs handleEventHook from the configuration and runs the default handler
|
-- | Runs handleEventHook from the configuration and runs the default handler
|
||||||
@ -485,36 +462,3 @@ grabButtons = do
|
|||||||
ems <- extraModifiers
|
ems <- extraModifiers
|
||||||
ba <- asks buttonActions
|
ba <- asks buttonActions
|
||||||
mapM_ (\(m,b) -> mapM_ (grab b . (m .|.)) ems) (M.keys ba)
|
mapM_ (\(m,b) -> mapM_ (grab b . (m .|.)) ems) (M.keys ba)
|
||||||
|
|
||||||
-- | @replace@ to signals compliant window managers to exit.
|
|
||||||
replace :: Display -> ScreenNumber -> Window -> IO ()
|
|
||||||
replace dpy dflt rootw = do
|
|
||||||
-- check for other WM
|
|
||||||
wmSnAtom <- internAtom dpy ("WM_S" ++ show dflt) False
|
|
||||||
currentWmSnOwner <- xGetSelectionOwner dpy wmSnAtom
|
|
||||||
when (currentWmSnOwner /= 0) $ do
|
|
||||||
-- prepare to receive destroyNotify for old WM
|
|
||||||
selectInput dpy currentWmSnOwner structureNotifyMask
|
|
||||||
|
|
||||||
-- create off-screen window
|
|
||||||
netWmSnOwner <- allocaSetWindowAttributes $ \attributes -> do
|
|
||||||
set_override_redirect attributes True
|
|
||||||
set_event_mask attributes propertyChangeMask
|
|
||||||
let screen = defaultScreenOfDisplay dpy
|
|
||||||
visual = defaultVisualOfScreen screen
|
|
||||||
attrmask = cWOverrideRedirect .|. cWEventMask
|
|
||||||
createWindow dpy rootw (-100) (-100) 1 1 0 copyFromParent copyFromParent visual attrmask attributes
|
|
||||||
|
|
||||||
-- try to acquire wmSnAtom, this should signal the old WM to terminate
|
|
||||||
xSetSelectionOwner dpy wmSnAtom netWmSnOwner currentTime
|
|
||||||
|
|
||||||
-- SKIPPED: check if we acquired the selection
|
|
||||||
-- SKIPPED: send client message indicating that we are now the WM
|
|
||||||
|
|
||||||
-- wait for old WM to go away
|
|
||||||
fix $ \again -> do
|
|
||||||
evt <- allocaXEvent $ \event -> do
|
|
||||||
windowEvent dpy currentWmSnOwner structureNotifyMask event
|
|
||||||
get_EventType event
|
|
||||||
|
|
||||||
when (evt /= destroyNotify) again
|
|
||||||
|
@ -64,11 +64,8 @@ x <&&> y = ifM x y (pure False)
|
|||||||
(<||>) :: Monad m => m Bool -> m Bool -> m Bool
|
(<||>) :: Monad m => m Bool -> m Bool -> m Bool
|
||||||
x <||> y = ifM x (pure True) y
|
x <||> y = ifM x (pure True) y
|
||||||
|
|
||||||
-- | If-then-else lifted to a 'Monad'.
|
-- | Return the window title; i.e., the string returned by @_NET_WM_NAME@,
|
||||||
ifM :: Monad m => m Bool -> m a -> m a -> m a
|
-- or failing that, the string returned by @WM_NAME@.
|
||||||
ifM mb t f = mb >>= \b -> if b then t else f
|
|
||||||
|
|
||||||
-- | Return the window title.
|
|
||||||
title :: Query String
|
title :: Query String
|
||||||
title = ask >>= \w -> liftX $ do
|
title = ask >>= \w -> liftX $ do
|
||||||
d <- asks display
|
d <- asks display
|
||||||
@ -77,7 +74,7 @@ title = ask >>= \w -> liftX $ do
|
|||||||
(internAtom d "_NET_WM_NAME" False >>= getTextProperty d w)
|
(internAtom d "_NET_WM_NAME" False >>= getTextProperty d w)
|
||||||
`E.catch` \(SomeException _) -> getTextProperty d w wM_NAME
|
`E.catch` \(SomeException _) -> getTextProperty d w wM_NAME
|
||||||
extract prop = do l <- wcTextPropertyToTextList d prop
|
extract prop = do l <- wcTextPropertyToTextList d prop
|
||||||
return $ if null l then "" else head l
|
return $ fromMaybe "" $ listToMaybe l
|
||||||
io $ bracket getProp (xFree . tp_value) extract `E.catch` \(SomeException _) -> return ""
|
io $ bracket getProp (xFree . tp_value) extract `E.catch` \(SomeException _) -> return ""
|
||||||
|
|
||||||
-- | Return the application name; i.e., the /first/ string returned by
|
-- | Return the application name; i.e., the /first/ string returned by
|
||||||
@ -95,7 +92,9 @@ className :: Query String
|
|||||||
className = ask >>= (\w -> liftX $ withDisplay $ \d -> fmap resClass $ io $ getClassHint d w)
|
className = ask >>= (\w -> liftX $ withDisplay $ \d -> fmap resClass $ io $ getClassHint d w)
|
||||||
|
|
||||||
-- | A query that can return an arbitrary X property of type 'String',
|
-- | A query that can return an arbitrary X property of type 'String',
|
||||||
-- identified by name.
|
-- identified by name. Works for ASCII strings only. For the properties
|
||||||
|
-- @_NET_WM_NAME@/@WM_NAME@ and @WM_CLASS@ the specialised variants 'title'
|
||||||
|
-- and 'appName'/'className' are preferred.
|
||||||
stringProperty :: String -> Query String
|
stringProperty :: String -> Query String
|
||||||
stringProperty p = ask >>= (\w -> liftX $ withDisplay $ \d -> fromMaybe "" <$> getStringProperty d w p)
|
stringProperty p = ask >>= (\w -> liftX $ withDisplay $ \d -> fromMaybe "" <$> getStringProperty d w p)
|
||||||
|
|
||||||
|
@ -33,10 +33,11 @@ module XMonad.Operations (
|
|||||||
-- * Keyboard and Mouse
|
-- * Keyboard and Mouse
|
||||||
cleanMask, extraModifiers,
|
cleanMask, extraModifiers,
|
||||||
mouseDrag, mouseMoveWindow, mouseResizeWindow,
|
mouseDrag, mouseMoveWindow, mouseResizeWindow,
|
||||||
setButtonGrab, setFocusX, cacheNumlockMask, mkGrabs,
|
setButtonGrab, setFocusX, cacheNumlockMask, mkGrabs, unGrab,
|
||||||
|
|
||||||
-- * Messages
|
-- * Messages
|
||||||
sendMessage, broadcastMessage, sendMessageWithNoRefresh,
|
sendMessage, broadcastMessage, sendMessageWithNoRefresh,
|
||||||
|
sendRestart, sendReplace,
|
||||||
|
|
||||||
-- * Save and Restore State
|
-- * Save and Restore State
|
||||||
StateFile (..), writeStateToFile, readStateFile, restart,
|
StateFile (..), writeStateToFile, readStateFile, restart,
|
||||||
@ -196,6 +197,7 @@ windows f = do
|
|||||||
let m = W.floating ws
|
let m = W.floating ws
|
||||||
flt = [(fw, scaleRationalRect viewrect r)
|
flt = [(fw, scaleRationalRect viewrect r)
|
||||||
| fw <- filter (`M.member` m) (W.index this)
|
| fw <- filter (`M.member` m) (W.index this)
|
||||||
|
, fw `notElem` vis
|
||||||
, Just r <- [M.lookup fw m]]
|
, Just r <- [M.lookup fw m]]
|
||||||
vs = flt ++ rs
|
vs = flt ++ rs
|
||||||
|
|
||||||
@ -473,6 +475,28 @@ mkGrabs ks = withDisplay $ \dpy -> do
|
|||||||
, extraMod <- extraMods
|
, extraMod <- extraMods
|
||||||
]
|
]
|
||||||
|
|
||||||
|
-- | Release XMonad's keyboard grab, so other grabbers can do their thing.
|
||||||
|
--
|
||||||
|
-- Start a keyboard action with this if it is going to run something
|
||||||
|
-- that needs to do a keyboard, pointer, or server grab. For example,
|
||||||
|
--
|
||||||
|
-- > , ((modm .|. controlMask, xK_p), unGrab >> spawn "scrot")
|
||||||
|
--
|
||||||
|
-- (Other examples are certain screen lockers and "gksu".)
|
||||||
|
-- This avoids needing to insert a pause/sleep before running the
|
||||||
|
-- command.
|
||||||
|
--
|
||||||
|
-- XMonad retains the keyboard grab during key actions because if they
|
||||||
|
-- use a submap, they need the keyboard to be grabbed, and if they had
|
||||||
|
-- to assert their own grab then the asynchronous nature of X11 allows
|
||||||
|
-- race conditions between XMonad, other clients, and the X server that
|
||||||
|
-- would cause keys to sometimes be "leaked" to the focused window.
|
||||||
|
unGrab :: X ()
|
||||||
|
unGrab = withDisplay $ \d -> io $ do
|
||||||
|
ungrabKeyboard d currentTime
|
||||||
|
ungrabPointer d currentTime
|
||||||
|
sync d False
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
-- Message handling
|
-- Message handling
|
||||||
|
|
||||||
@ -519,6 +543,59 @@ setLayout l = do
|
|||||||
handleMessage (W.layout ws) (SomeMessage ReleaseResources)
|
handleMessage (W.layout ws) (SomeMessage ReleaseResources)
|
||||||
windows $ const $ ss{ W.current = c{ W.workspace = ws{ W.layout = l } } }
|
windows $ const $ ss{ W.current = c{ W.workspace = ws{ W.layout = l } } }
|
||||||
|
|
||||||
|
-- | Signal xmonad to restart itself.
|
||||||
|
sendRestart :: IO ()
|
||||||
|
sendRestart = do
|
||||||
|
dpy <- openDisplay ""
|
||||||
|
rw <- rootWindow dpy $ defaultScreen dpy
|
||||||
|
xmonad_restart <- internAtom dpy "XMONAD_RESTART" False
|
||||||
|
allocaXEvent $ \e -> do
|
||||||
|
setEventType e clientMessage
|
||||||
|
setClientMessageEvent' e rw xmonad_restart 32 []
|
||||||
|
sendEvent dpy rw False structureNotifyMask e
|
||||||
|
sync dpy False
|
||||||
|
|
||||||
|
-- | Signal compliant window managers to exit.
|
||||||
|
sendReplace :: IO ()
|
||||||
|
sendReplace = do
|
||||||
|
dpy <- openDisplay ""
|
||||||
|
let dflt = defaultScreen dpy
|
||||||
|
rootw <- rootWindow dpy dflt
|
||||||
|
replace dpy dflt rootw
|
||||||
|
|
||||||
|
-- | Signal compliant window managers to exit.
|
||||||
|
replace :: Display -> ScreenNumber -> Window -> IO ()
|
||||||
|
replace dpy dflt rootw = do
|
||||||
|
-- check for other WM
|
||||||
|
wmSnAtom <- internAtom dpy ("WM_S" ++ show dflt) False
|
||||||
|
currentWmSnOwner <- xGetSelectionOwner dpy wmSnAtom
|
||||||
|
when (currentWmSnOwner /= 0) $ do
|
||||||
|
-- prepare to receive destroyNotify for old WM
|
||||||
|
selectInput dpy currentWmSnOwner structureNotifyMask
|
||||||
|
|
||||||
|
-- create off-screen window
|
||||||
|
netWmSnOwner <- allocaSetWindowAttributes $ \attributes -> do
|
||||||
|
set_override_redirect attributes True
|
||||||
|
set_event_mask attributes propertyChangeMask
|
||||||
|
let screen = defaultScreenOfDisplay dpy
|
||||||
|
visual = defaultVisualOfScreen screen
|
||||||
|
attrmask = cWOverrideRedirect .|. cWEventMask
|
||||||
|
createWindow dpy rootw (-100) (-100) 1 1 0 copyFromParent copyFromParent visual attrmask attributes
|
||||||
|
|
||||||
|
-- try to acquire wmSnAtom, this should signal the old WM to terminate
|
||||||
|
xSetSelectionOwner dpy wmSnAtom netWmSnOwner currentTime
|
||||||
|
|
||||||
|
-- SKIPPED: check if we acquired the selection
|
||||||
|
-- SKIPPED: send client message indicating that we are now the WM
|
||||||
|
|
||||||
|
-- wait for old WM to go away
|
||||||
|
fix $ \again -> do
|
||||||
|
evt <- allocaXEvent $ \event -> do
|
||||||
|
windowEvent dpy currentWmSnOwner structureNotifyMask event
|
||||||
|
get_EventType event
|
||||||
|
|
||||||
|
when (evt /= destroyNotify) again
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
-- Utilities
|
-- Utilities
|
||||||
|
|
||||||
@ -649,6 +726,7 @@ floatLocation w =
|
|||||||
|
|
||||||
where go = withDisplay $ \d -> do
|
where go = withDisplay $ \d -> do
|
||||||
ws <- gets windowset
|
ws <- gets windowset
|
||||||
|
sh <- io $ getWMNormalHints d w
|
||||||
wa <- io $ getWindowAttributes d w
|
wa <- io $ getWindowAttributes d w
|
||||||
let bw = (fromIntegral . wa_border_width) wa
|
let bw = (fromIntegral . wa_border_width) wa
|
||||||
point_sc <- pointScreen (fi $ wa_x wa) (fi $ wa_y wa)
|
point_sc <- pointScreen (fi $ wa_x wa) (fi $ wa_y wa)
|
||||||
@ -663,13 +741,14 @@ floatLocation w =
|
|||||||
sr = screenRect . W.screenDetail $ sc
|
sr = screenRect . W.screenDetail $ sc
|
||||||
x = (fi (wa_x wa) - fi (rect_x sr)) % fi (rect_width sr)
|
x = (fi (wa_x wa) - fi (rect_x sr)) % fi (rect_width sr)
|
||||||
y = (fi (wa_y wa) - fi (rect_y sr)) % fi (rect_height sr)
|
y = (fi (wa_y wa) - fi (rect_y sr)) % fi (rect_height sr)
|
||||||
width = fi (wa_width wa + bw*2) % fi (rect_width sr)
|
(width, height) = applySizeHintsContents sh (wa_width wa, wa_height wa)
|
||||||
height = fi (wa_height wa + bw*2) % fi (rect_height sr)
|
rwidth = fi (width + bw*2) % fi (rect_width sr)
|
||||||
|
rheight = fi (height + bw*2) % fi (rect_height sr)
|
||||||
-- adjust x/y of unmanaged windows if we ignored or didn't get pointScreen,
|
-- adjust x/y of unmanaged windows if we ignored or didn't get pointScreen,
|
||||||
-- it might be out of bounds otherwise
|
-- it might be out of bounds otherwise
|
||||||
rr = if managed || point_sc `sr_eq` Just sc
|
rr = if managed || point_sc `sr_eq` Just sc
|
||||||
then W.RationalRect x y width height
|
then W.RationalRect x y rwidth rheight
|
||||||
else W.RationalRect (0.5 - width/2) (0.5 - height/2) width height
|
else W.RationalRect (0.5 - rwidth/2) (0.5 - rheight/2) rwidth rheight
|
||||||
|
|
||||||
return (W.screen sc, rr)
|
return (W.screen sc, rr)
|
||||||
|
|
||||||
|
@ -106,7 +106,10 @@ import qualified Data.Map as M (Map,insert,delete,empty)
|
|||||||
--
|
--
|
||||||
-- <https://dspace.library.uu.nl/handle/1874/2532 R. Hinze and J. Jeuring, Functional Pearl: Weaving a Web>
|
-- <https://dspace.library.uu.nl/handle/1874/2532 R. Hinze and J. Jeuring, Functional Pearl: Weaving a Web>
|
||||||
--
|
--
|
||||||
-- and Conor McBride's zipper differentiation paper.
|
-- and
|
||||||
|
--
|
||||||
|
-- <http://strictlypositive.org/diff.pdf Conor McBride, The Derivative of a Regular Type is its Type of One-Hole Contexts>.
|
||||||
|
--
|
||||||
-- Another good reference is: <https://wiki.haskell.org/Zipper The Zipper, Haskell wikibook>
|
-- Another good reference is: <https://wiki.haskell.org/Zipper The Zipper, Haskell wikibook>
|
||||||
|
|
||||||
-- $xinerama
|
-- $xinerama
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
resolver: lts-19.6
|
resolver: lts-21.12
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
- ./
|
- ./
|
||||||
|
@ -166,11 +166,16 @@ tests =
|
|||||||
-- tall layout
|
-- tall layout
|
||||||
|
|
||||||
,("tile 1 window fullsize", property prop_tile_fullscreen)
|
,("tile 1 window fullsize", property prop_tile_fullscreen)
|
||||||
|
,("tile max ratio", property prop_tile_max_ratio)
|
||||||
|
,("tile min ratio", property prop_tile_min_ratio)
|
||||||
,("tiles never overlap", property prop_tile_non_overlap)
|
,("tiles never overlap", property prop_tile_non_overlap)
|
||||||
,("split horizontal", property prop_split_horizontal)
|
,("split horizontal", property prop_split_horizontal)
|
||||||
,("split vertical", property prop_split_vertical)
|
,("split vertical", property prop_split_vertical)
|
||||||
|
|
||||||
,("pure layout tall", property prop_purelayout_tall)
|
,("pure layout tall", property prop_purelayout_tall)
|
||||||
|
{- Following two test cases should be automatically generated by QuickCheck ideally, but it fails. -}
|
||||||
|
,("pure layout tall: ratio = 0", property (\n d rect -> prop_purelayout_tall n d 0 rect))
|
||||||
|
,("pure layout tall: ratio = 1", property (\n d rect -> prop_purelayout_tall n d 1 rect))
|
||||||
,("send shrink tall", property prop_shrink_tall)
|
,("send shrink tall", property prop_shrink_tall)
|
||||||
,("send expand tall", property prop_expand_tall)
|
,("send expand tall", property prop_expand_tall)
|
||||||
,("send incmaster tall", property prop_incmaster_tall)
|
,("send incmaster tall", property prop_incmaster_tall)
|
||||||
|
@ -11,8 +11,9 @@ import XMonad.Layout
|
|||||||
|
|
||||||
import Graphics.X11.Xlib.Types (Rectangle(..))
|
import Graphics.X11.Xlib.Types (Rectangle(..))
|
||||||
|
|
||||||
import Data.Maybe
|
import Control.Applicative
|
||||||
import Data.List (sort)
|
import Data.List (sort)
|
||||||
|
import Data.Maybe
|
||||||
import Data.Ratio
|
import Data.Ratio
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
@ -27,6 +28,22 @@ prop_tile_non_overlap rect windows nmaster = noOverlaps (tile pct rect nmaster w
|
|||||||
where _ = rect :: Rectangle
|
where _ = rect :: Rectangle
|
||||||
pct = 3 % 100
|
pct = 3 % 100
|
||||||
|
|
||||||
|
-- with a ratio of 1, no stack windows are drawn of there is at least
|
||||||
|
-- one master window around.
|
||||||
|
prop_tile_max_ratio = extremeRatio 1 drop
|
||||||
|
|
||||||
|
-- with a ratio of 0, no master windows are drawn at all if there are
|
||||||
|
-- any stack windows around.
|
||||||
|
prop_tile_min_ratio = extremeRatio 0 take
|
||||||
|
|
||||||
|
extremeRatio amount getRects rect = do
|
||||||
|
w@(NonNegative windows) <- arbitrary `suchThat` (> NonNegative 0)
|
||||||
|
NonNegative nmaster <- arbitrary `suchThat` (< w)
|
||||||
|
let tiled = tile amount rect nmaster windows
|
||||||
|
pure $ if nmaster == 0
|
||||||
|
then prop_tile_non_overlap rect windows nmaster
|
||||||
|
else all ((== 0) . rect_width) $ getRects nmaster tiled
|
||||||
|
|
||||||
-- splitting horizontally yields sensible results
|
-- splitting horizontally yields sensible results
|
||||||
prop_split_horizontal (NonNegative n) x =
|
prop_split_horizontal (NonNegative n) x =
|
||||||
noOverflows (+) (rect_x x) (rect_width x) ==>
|
noOverflows (+) (rect_x x) (rect_width x) ==>
|
||||||
@ -49,13 +66,20 @@ prop_split_vertical (r :: Rational) x =
|
|||||||
|
|
||||||
|
|
||||||
-- pureLayout works.
|
-- pureLayout works.
|
||||||
prop_purelayout_tall n r1 r2 rect = do
|
prop_purelayout_tall n d r rect = do
|
||||||
x <- (arbitrary :: Gen T) `suchThat` (isJust . peek)
|
x <- (arbitrary :: Gen T) `suchThat` (isJust . peek)
|
||||||
let layout = Tall n r1 r2
|
let layout = Tall n d r
|
||||||
st = fromJust . stack . workspace . current $ x
|
st = fromJust . stack . workspace . current $ x
|
||||||
ts = pureLayout layout rect st
|
ts = pureLayout layout rect st
|
||||||
|
ntotal = length (index x)
|
||||||
return $
|
return $
|
||||||
length ts == length (index x)
|
(if r == 0 then
|
||||||
|
-- (<=) for Bool is the logical implication
|
||||||
|
(0 <= n && n <= ntotal) <= (length ts == ntotal - n)
|
||||||
|
else if r == 1 then
|
||||||
|
(0 <= n && n <= ntotal) <= (length ts == n)
|
||||||
|
else
|
||||||
|
length ts == ntotal)
|
||||||
&&
|
&&
|
||||||
noOverlaps (map snd ts)
|
noOverlaps (map snd ts)
|
||||||
&&
|
&&
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
name: xmonad
|
name: xmonad
|
||||||
version: 0.17.2
|
version: 0.18.0.9
|
||||||
synopsis: A tiling window manager
|
synopsis: A tiling window manager
|
||||||
description: xmonad is a tiling window manager for X. Windows are arranged
|
description: xmonad is a tiling window manager for X. Windows are arranged
|
||||||
automatically to tile the screen without gaps or overlap, maximising
|
automatically to tile the screen without gaps or overlap, maximising
|
||||||
@ -27,7 +27,7 @@ author: Spencer Janssen, Don Stewart, Adam Vogt, David Roundy, Jason
|
|||||||
Ondřej Súkup, Paul Hebble, Shachaf Ben-Kiki, Siim Põder, Tim McIver,
|
Ondřej Súkup, Paul Hebble, Shachaf Ben-Kiki, Siim Põder, Tim McIver,
|
||||||
Trevor Elliott, Wouter Swierstra, Conrad Irwin, Tim Thelion, Tony Zorman
|
Trevor Elliott, Wouter Swierstra, Conrad Irwin, Tim Thelion, Tony Zorman
|
||||||
maintainer: xmonad@haskell.org
|
maintainer: xmonad@haskell.org
|
||||||
tested-with: GHC == 8.6.5 || == 8.8.4 || == 8.10.7 || == 9.0.2 || == 9.2.7 || == 9.4.4 || == 9.6.1
|
tested-with: GHC == 8.6.5 || == 8.8.4 || == 8.10.7 || == 9.0.2 || == 9.2.8 || == 9.4.8 || == 9.6.7 || == 9.8.4 || == 9.10.2 || == 9.12.2
|
||||||
category: System
|
category: System
|
||||||
homepage: http://xmonad.org
|
homepage: http://xmonad.org
|
||||||
bug-reports: https://github.com/xmonad/xmonad/issues
|
bug-reports: https://github.com/xmonad/xmonad/issues
|
||||||
@ -65,7 +65,7 @@ library
|
|||||||
XMonad.StackSet
|
XMonad.StackSet
|
||||||
other-modules: Paths_xmonad
|
other-modules: Paths_xmonad
|
||||||
hs-source-dirs: src
|
hs-source-dirs: src
|
||||||
build-depends: base >= 4.11 && < 5
|
build-depends: base >= 4.12 && < 5
|
||||||
, X11 >= 1.10 && < 1.11
|
, X11 >= 1.10 && < 1.11
|
||||||
, containers
|
, containers
|
||||||
, data-default-class
|
, data-default-class
|
||||||
@ -129,5 +129,8 @@ test-suite properties
|
|||||||
, xmonad
|
, xmonad
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
|
||||||
|
if impl(ghc > 9.8)
|
||||||
|
ghc-options: -Wno-x-partial
|
||||||
|
|
||||||
if flag(pedantic)
|
if flag(pedantic)
|
||||||
ghc-options: -Werror
|
ghc-options: -Werror
|
||||||
|
Loading…
x
Reference in New Issue
Block a user