Compare commits
239 Commits
32827126cc
...
45c47f7d30
Author | SHA1 | Date |
---|---|---|
Emmanuel Lepage Vallée | 45c47f7d30 | |
Emmanuel Lepage Vallée | aa01c408ca | |
Emmanuel Lepage Vallee | 546ac6aec9 | |
Emmanuel Lepage Vallée | 01ae508899 | |
Emmanuel Lepage Vallée | 7b8426bd24 | |
Emmanuel Lepage Vallée | 7806763667 | |
Emmanuel Lepage Vallee | 70cd293839 | |
Emmanuel Lepage Vallee | 4a0645e942 | |
Emmanuel Lepage Vallee | 1ff860454e | |
Emmanuel Lepage Vallee | bbf1c9270f | |
Emmanuel Lepage Vallee | d8bc791818 | |
Emmanuel Lepage Vallee | 883cdb7f41 | |
Emmanuel Lepage Vallee | ddccddb6dc | |
Emmanuel Lepage Vallee | 3f2db184ad | |
Emmanuel Lepage Vallee | e55ea2b0d5 | |
Emmanuel Lepage Vallee | 6b7ecc51f8 | |
Emmanuel Lepage Vallee | 580f16b7ff | |
Emmanuel Lepage Vallee | dcdc6a1089 | |
Emmanuel Lepage Vallee | 8481af90c5 | |
Emmanuel Lepage Vallee | b9971a5acc | |
Emmanuel Lepage Vallee | b0a2d82d8f | |
Emmanuel Lepage Vallee | 82f54ab95c | |
Emmanuel Lepage Vallee | 98dd78b777 | |
Emmanuel Lepage Vallee | aa998db626 | |
Emmanuel Lepage Vallee | 5212f0634a | |
Emmanuel Lepage Vallee | cefd4f843e | |
Emmanuel Lepage Vallée | eddabebac4 | |
Emmanuel Lepage Vallee | 64d190546d | |
Emmanuel Lepage Vallee | b038463e22 | |
Emmanuel Lepage Vallee | 24fc1043ee | |
Emmanuel Lepage Vallee | ccbe116877 | |
Emmanuel Lepage Vallee | bd8f2f936b | |
Emmanuel Lepage Vallee | 552b2a22d1 | |
Emmanuel Lepage Vallee | 9336b62f80 | |
Emmanuel Lepage Vallee | e752943b98 | |
Emmanuel Lepage Vallee | 21a111d154 | |
Emmanuel Lepage Vallee | 89c84caee4 | |
poisson-aerohead | 87e09f81ab | |
Emmanuel Lepage Vallée | 5ca16ae8a0 | |
martin f. krafft | abac464384 | |
Emmanuel Lepage Vallée | d9bfc9c37e | |
Emmanuel Lepage Vallée | c3a508a886 | |
Lucas Schwiderski | 4b6d7fd241 | |
Lucas Schwiderski | c12715e11f | |
Emmanuel Lepage Vallée | edf21742b8 | |
Emmanuel Lepage Vallee | e27b908ca0 | |
Emmanuel Lepage Vallee | 17bd5fb036 | |
Emmanuel Lepage Vallée | 73e908ed95 | |
Emmanuel Lepage Vallée | 6ad693eff0 | |
Emmanuel Lepage Vallee | d5d74e44de | |
Emmanuel Lepage Vallee | b2368c54a8 | |
Emmanuel Lepage Vallee | dd6163ffe6 | |
Emmanuel Lepage Vallee | a94a4beb6f | |
Emmanuel Lepage Vallee | b883855272 | |
Emmanuel Lepage Vallee | 529a6c2a8d | |
Emmanuel Lepage Vallee | 0828c20a55 | |
Emmanuel Lepage Vallee | 67dc363437 | |
Emmanuel Lepage Vallee | dab767af3e | |
Emmanuel Lepage Vallee | b62f343409 | |
Emmanuel Lepage Vallee | ab977b2358 | |
Emmanuel Lepage Vallee | b4afd0206b | |
Emmanuel Lepage Vallee | d9f27bdf4b | |
Emmanuel Lepage Vallee | 4b606fb3d7 | |
Emmanuel Lepage Vallée | 2a8c17daea | |
Lucas Schwiderski | f39e8d261b | |
Lucas Schwiderski | 86ec4888b3 | |
Lucas Schwiderski | cc882585de | |
Emmanuel Lepage Vallée | ee3c42652e | |
mergify[bot] | 7ae6d26363 | |
mergify[bot] | c88dcf5405 | |
mattplm | 97726e8f38 | |
ViSaturn | 13cd20780e | |
Nguyễn Gia Phong | be45b40cdb | |
aflorea-2k | 8a81745d4d | |
aflorea-2k | 260f6dbe97 | |
Emmanuel Lepage Vallée | 4b494952da | |
mergify[bot] | fcd5918bd9 | |
aflorea-2k | ddb88ed945 | |
Andrei Florea | 5f5b1dcb2b | |
Andrei Florea | b73b885c1e | |
Lucas Schwiderski | 0a68341c12 | |
Lucas Schwiderski | c689af64d5 | |
Lucas Schwiderski | 05ca439ed5 | |
Andrei Florea | 66bb09718b | |
Lucas Schwiderski | 8fab5aa703 | |
Lucas Schwiderski | 4096c19223 | |
Lucas Schwiderski | f214ef16a7 | |
Lucas Schwiderski | 4b30158176 | |
Lucas Schwiderski | f2c66b006d | |
Lucas Schwiderski | 08c893fff9 | |
Lucas Schwiderski | a938a1b807 | |
Lucas Schwiderski | c1a3f02c88 | |
mergify[bot] | 832483dd60 | |
basaran | f473639c5d | |
mergify[bot] | d1c3394e40 | |
Uli Schlachter | d25ca02493 | |
Aire-One | 53a880454f | |
Lucas Schwiderski | 741efd4171 | |
Lucas Schwiderski | ab6df1280f | |
Emmanuel Lepage Vallée | 906dc543e4 | |
Lucas Schwiderski | 1a2037758b | |
Aire-One | 4188d1df1e | |
Aire-One | a3609146aa | |
Lucas Schwiderski | 4520f33309 | |
Lucas Schwiderski | fcae67cc03 | |
Lucas Schwiderski | dc0d5df4da | |
Lucas Schwiderski | e0e8f3fd72 | |
Lucas Schwiderski | bf4ad3310d | |
Lucas Schwiderski | fd59806392 | |
Lucas Schwiderski | 1cd89e7de5 | |
Lucas Schwiderski | a6864a3e59 | |
Lucas Schwiderski | 7838e89d7f | |
Lucas Schwiderski | 7591d5cde3 | |
Lucas Schwiderski | 3cefcfffe3 | |
Lucas Schwiderski | 33b2fdfbf6 | |
Lucas Schwiderski | 16df93370f | |
Lucas Schwiderski | b94cb51770 | |
Aire-One | 6b97ec3307 | |
mergify[bot] | f4fb055512 | |
Aire-One | 8085a508d1 | |
Aire-One | 948506cde1 | |
Lucas Schwiderski | 1182552783 | |
actionless | 87fb3d7553 | |
actionless | bbaccb05bc | |
mergify[bot] | b63399f656 | |
mergify[bot] | 149d18e0e7 | |
Emmanuel Lepage Vallee | 83c31f948b | |
Emmanuel Lepage Vallee | 82bd644ea1 | |
Emmanuel Lepage Vallee | 5e5f587bea | |
Emmanuel Lepage Vallée | fedc7dc69d | |
actionless | b91a033141 | |
actionless | fa7648e6d6 | |
actionless | 2249dc3c81 | |
Yauhen Kirylau | b65025ef62 | |
Yauhen Kirylau | 59789bc2cf | |
mergify[bot] | 4c8ac65d4c | |
Lucas Schwiderski | 8c422d4f68 | |
Lucas Schwiderski | 1b49a20e0d | |
Lucas Schwiderski | e0dea455c1 | |
Lucas Schwiderski | 4f1b308e2b | |
Lucas Schwiderski | 9a3ff8eb95 | |
Lucas Schwiderski | e0244e60da | |
mergify[bot] | 9c5149d4e3 | |
Alex Belykh | 0d0647848b | |
Lucas Schwiderski | 8d88f1fa52 | |
Lucas Schwiderski | cfe7da8526 | |
Lucas Schwiderski | 4d83228f00 | |
Lucas Schwiderski | 1867ab057c | |
Lucas Schwiderski | dc8108eff7 | |
Lucas Schwiderski | bccaac9b2f | |
Lucas Schwiderski | 6a3713a090 | |
Lucas Schwiderski | d9711c3f48 | |
Lucas Schwiderski | 857b7199d6 | |
Lucas Schwiderski | e7239840f4 | |
Lucas Schwiderski | 8334f9c1b1 | |
Lucas Schwiderski | 717d09aa94 | |
Lucas Schwiderski | 645156b3c0 | |
Lucas Schwiderski | 9bc8c28c90 | |
Lucas Schwiderski | 33ee8c09ba | |
Lucas Schwiderski | 87b717495f | |
Lucas Schwiderski | 4b37eb6b50 | |
Lucas Schwiderski | f74a838506 | |
Lucas Schwiderski | 674ee00437 | |
Lucas Schwiderski | 3fbcfc8553 | |
Lucas Schwiderski | 5c3b739c25 | |
Lucas Schwiderski | 8f39fb61bd | |
mergify[bot] | a4572b9b52 | |
mergify[bot] | 4c46f6dbf3 | |
Emmanuel Lepage Vallee | c355ce7d96 | |
Emmanuel Lepage Vallee | 5cfcbac959 | |
mergify[bot] | 42d241c707 | |
mergify[bot] | 35e0acbccb | |
Uli Schlachter | d2dc428e56 | |
actionless | 5bd0ff82a6 | |
Emmanuel Lepage Vallee | ee0d793efe | |
Emmanuel Lepage Vallee | dd26b8180d | |
Emmanuel Lepage Vallee | 738e2e0467 | |
Emmanuel Lepage Vallee | d373bf2d05 | |
Emmanuel Lepage Vallee | 78b8756068 | |
Emmanuel Lepage Vallee | 6a4e555ae1 | |
mergify[bot] | c8d3de3ff4 | |
actionless | 6b93661048 | |
Yauhen Kirylau | a35acea61a | |
Emmanuel Lepage Vallée | 47fd7797b4 | |
ShayAgros | ba923cb80d | |
Shay Agroskin | 1916677df1 | |
Shay Agroskin | 3f4b1bd0cc | |
mergify[bot] | fda950d186 | |
Emmanuel Lepage Vallee | e3ab76b872 | |
Aire-One | 6226742f72 | |
Aire-One | 9807ccd5e0 | |
Emmanuel Lepage Vallée | 022be39a3f | |
Emmanuel Lepage Vallée | 702db23ee0 | |
Emmanuel Lepage Vallée | 8e8525dae9 | |
Emmanuel Lepage Vallée | 747b14142f | |
Emmanuel Lepage Vallée | 3dddc2ba78 | |
Aire-One | b184f95195 | |
Emmanuel Lepage Vallee | 25f4cfcb05 | |
Emmanuel Lepage Vallee | 90c4c60d2a | |
Aire-One | bc8a5b0230 | |
Aire-One | 0ae0add45f | |
Aire-One | b706aa9bd0 | |
Aire-One | af3b194a31 | |
Aire-One | 20a8d902c5 | |
Aire-One | 3969ad8819 | |
Aire-One | 3b12a8d19a | |
Aire-One | 3ed2fc8500 | |
Aire-One | 5baa1c97cd | |
Aire-One | 93e9361280 | |
Aire-One | 12662d4cb1 | |
Aire-One | 3a6fa10754 | |
Aire-One | b82d2a690f | |
Aire-One | 4dd689f181 | |
mergify[bot] | 7a8fa9d27a | |
mergify[bot] | 972a194b01 | |
Lucas Schwiderski | 112dc8054e | |
Lucas Schwiderski | 8907f5bfbb | |
Lucas Schwiderski | f68939bfc1 | |
Lucas Schwiderski | ec3788bf73 | |
mergify[bot] | 95558ac919 | |
Emmanuel Lepage Vallée | 13e8408562 | |
Lucas Schwiderski | c0380e3080 | |
Emmanuel Lepage Vallée | 7050ba083f | |
Emmanuel Lepage Vallee | 743b327348 | |
Emmanuel Lepage Vallee | a5c4377901 | |
Emmanuel Lepage Vallee | c48e138b01 | |
Lucas Schwiderski | e7d55567a6 | |
Shay Agroskin | 62850476d2 | |
Shay Agroskin | a18e3508f6 | |
Shay Agroskin | 749422100e | |
actionless | e833da0303 | |
Lucas Schwiderski | afced71a9a | |
Lucas Schwiderski | 058190a3c0 | |
Lucas Schwiderski | 07df24f7d0 | |
Lucas Schwiderski | 504bf53b8c | |
Lucas Schwiderski | 7bc3ec4c35 | |
actionless | a2674c2d14 | |
actionless | 20a79ed448 | |
actionless | 901bb3d88e |
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Process (API) docs after a successful build on Travis (via ../.travis.yml).
|
||||
# Process (API) docs after a successful build on GitHub Actions.
|
||||
#
|
||||
# Updated/changed documentation for "master" is pushed to gh-pages.
|
||||
# In case of pull requests or other branches, it will get added to a separate branch.
|
||||
|
@ -9,48 +9,49 @@
|
|||
# NOTE: stdout/stderr might/should be discarded to not leak sensitive information.
|
||||
|
||||
echo "Post-processing (API) documentation."
|
||||
echo "TRAVIS_PULL_REQUEST: $TRAVIS_PULL_REQUEST"
|
||||
echo "TRAVIS_BRANCH: $TRAVIS_BRANCH"
|
||||
echo "PR Number: $PR_NUMBER"
|
||||
echo "GITHUB_HEAD_REF: $GITHUB_HEAD_REF"
|
||||
|
||||
if [ -z "$GH_APIDOC_TOKEN" ]; then
|
||||
echo "No GH_APIDOC_TOKEN available. Skipping."
|
||||
exit
|
||||
if [ -z "$APIDOC_TOKEN" ]; then
|
||||
echo "No APIDOC_TOKEN available. Skipping."
|
||||
exit
|
||||
fi
|
||||
|
||||
# NOTE: DO NOT USE "set -x", or anything else that would reveal GH_APIDOC_TOKEN!
|
||||
# NOTE: DO NOT USE "set -x", or anything else that would reveal APIDOC_TOKEN!
|
||||
# GitHub Actions does filter secrets, but extra caution won't hurt
|
||||
set -e
|
||||
set +x
|
||||
|
||||
# Display exit code in term of failure (probably due to 'set -x').
|
||||
# Display exit code in case of failure (probably due to 'set -x').
|
||||
trap '[ "$?" = 0 ] || echo "EXIT CODE: $?"' EXIT
|
||||
|
||||
REPO_APIDOC="https://${GH_APIDOC_TOKEN}@github.com/awesomeWM/apidoc"
|
||||
REPO_APIDOC="https://${APIDOC_TOKEN}@github.com/awesomeWM/apidoc"
|
||||
REPO_DIR="$PWD"
|
||||
|
||||
export GIT_AUTHOR_NAME="awesome-robot on Travis CI"
|
||||
export GIT_AUTHOR_NAME="awesome-robot on GitHub Actions"
|
||||
export GIT_AUTHOR_EMAIL="awesome-robot@users.noreply.github.com"
|
||||
export GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"
|
||||
export GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"
|
||||
|
||||
git clone --depth 1 --branch gh-pages "$REPO_APIDOC" build/apidoc \
|
||||
2>&1 | sed "s/$GH_APIDOC_TOKEN/GH_APIDOC_TOKEN/g"
|
||||
2>&1 | sed "s/$APIDOC_TOKEN/APIDOC_TOKEN/g"
|
||||
cd build/apidoc
|
||||
|
||||
# This will re-use already existing branches (updated PR).
|
||||
if [ "$TRAVIS_PULL_REQUEST" != false ]; then
|
||||
BRANCH="pr-$TRAVIS_PULL_REQUEST"
|
||||
elif [ "$TRAVIS_BRANCH" != master ]; then
|
||||
# Use merge-base of master in branch name, to keep different branches with
|
||||
# the same name apart.
|
||||
# shellcheck disable=SC2015
|
||||
BRANCH="$TRAVIS_BRANCH-$(cd "$REPO_DIR" \
|
||||
&& git fetch --unshallow origin master \
|
||||
&& git rev-parse --short "$(git merge-base HEAD FETCH_HEAD || true)" || true)"
|
||||
if [ "$PR_NUMBER" != false ]; then
|
||||
BRANCH="pr-$PR_NUMBER"
|
||||
elif [ "$GITHUB_HEAD_REF" != master ]; then
|
||||
# Use merge-base of master in branch name, to keep different branches with
|
||||
# the same name apart.
|
||||
# shellcheck disable=SC2015
|
||||
BRANCH="$GITHUB_HEAD_REF-$(cd "$REPO_DIR" \
|
||||
&& git fetch --unshallow origin master \
|
||||
&& git rev-parse --short "$(git merge-base HEAD FETCH_HEAD || true)" || true)"
|
||||
else
|
||||
BRANCH="gh-pages"
|
||||
fi
|
||||
if [ "$BRANCH" != "gh-pages" ]; then
|
||||
git checkout -b "$BRANCH" "origin/${BRANCH}" || git checkout -b "$BRANCH"
|
||||
git checkout -b "$BRANCH" "origin/${BRANCH}" 2> /dev/null || git checkout -b "$BRANCH"
|
||||
fi
|
||||
|
||||
# Use a temporary branch for the two commits, which allows for a better UI.
|
||||
|
@ -62,7 +63,7 @@ cat > ../doc/README.md <<END
|
|||
|
||||
This repository contains the built API documentation for the
|
||||
[awesome](https://github.com/awesomeWM/awesome) window manager. It is
|
||||
automatically updated via Travis when the master branch changes. Hence:
|
||||
automatically updated via GitHub Actions when the master branch changes. Hence:
|
||||
|
||||
## Do NOT send pull requests here
|
||||
|
||||
|
@ -72,47 +73,48 @@ END
|
|||
|
||||
# Create a patch without irrelevant changes (version / timestamp).
|
||||
diff -Nur . ../doc -I "Last updated" -I "<strong>Release</strong>:" \
|
||||
-I "<h2>API documentation for awesome, a highly configurable X window manager (version .*)\.</h2>" \
|
||||
-x .git | patch -p1
|
||||
-I "<h2>API documentation for awesome, a highly configurable X window manager (version .*)\.</h2>" \
|
||||
-x .git | patch -p1
|
||||
|
||||
git add --all .
|
||||
if git diff --cached --exit-code --quiet; then
|
||||
echo "Documentation has not changed."
|
||||
exit
|
||||
echo "Documentation has not changed."
|
||||
exit
|
||||
fi
|
||||
|
||||
LAST_COMMIT_MSG="$(cd "$REPO_DIR" && git log -1 --pretty=format:%s)"
|
||||
LAST_COMMIT="$(cd "$REPO_DIR" && git rev-parse --short HEAD)"
|
||||
|
||||
# Commit the relevant changes.
|
||||
COMMIT_MSG="Update docs for $AWESOME_VERSION via Travis
|
||||
COMMIT_MSG="Update docs for $AWESOME_VERSION via Github Actions
|
||||
|
||||
Last commit message:
|
||||
$LAST_COMMIT_MSG
|
||||
|
||||
Commits: https://github.com/awesomeWM/awesome/compare/${TRAVIS_COMMIT_RANGE/.../..}
|
||||
Build URL: https://travis-ci.com/awesomeWM/awesome/builds/${TRAVIS_BUILD_ID}"
|
||||
Commits: https://github.com/awesomeWM/awesome/compare/${GITHUB_BASE_REF}..${GITHUB_HEAD_REF}
|
||||
Build URL: $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"
|
||||
|
||||
git commit -m "[relevant] $COMMIT_MSG"
|
||||
|
||||
# Commit the irrelevant changes.
|
||||
mv .git ../doc
|
||||
cd ../doc
|
||||
git add --all .
|
||||
git commit -m "[boilerplate] $COMMIT_MSG"
|
||||
|
||||
# Reorder/swap commits, to have "relevant" after "boilerplate".
|
||||
# This makes it show up earlier in the Github interface etc.
|
||||
git tag _old
|
||||
git reset --hard HEAD~2
|
||||
git cherry-pick _old _old~1
|
||||
RELEVANT_REV="$(git rev-parse --short HEAD)"
|
||||
git tag -d _old
|
||||
if git commit -m "[boilerplate] $COMMIT_MSG"; then
|
||||
# Reorder/swap commits, to have "relevant" after "boilerplate".
|
||||
# This makes it show up earlier in the Github interface etc.
|
||||
git tag _old
|
||||
git reset --hard HEAD~2
|
||||
git cherry-pick _old _old~1
|
||||
RELEVANT_REV="$(git rev-parse --short HEAD)"
|
||||
git tag -d _old
|
||||
fi
|
||||
|
||||
git checkout "$BRANCH"
|
||||
OLD_REV="$(git rev-parse --short HEAD)"
|
||||
if [ "$TRAVIS_PULL_REQUEST" != false ]; then
|
||||
if [ "$PR_NUMBER" != false ]; then
|
||||
MERGE_COMMIT_MSG="$COMMIT_MSG
|
||||
Pull request: https://github.com/awesomeWM/awesome/pull/${TRAVIS_PULL_REQUEST}"
|
||||
Pull request: https://github.com/awesomeWM/awesome/pull/${PR_NUMBER}"
|
||||
else
|
||||
PR_OR_ISSUE="$(echo "$COMMIT_MSG" | head -n 1 | grep -o '#[0-9]\+' || true)"
|
||||
if [ -n "$PR_OR_ISSUE" ]; then
|
||||
|
@ -134,24 +136,24 @@ fi
|
|||
git merge --no-ff -m "$MERGE_COMMIT_MSG" merged-update
|
||||
NEW_REV="$(git rev-parse --short HEAD)"
|
||||
|
||||
git push origin "$BRANCH" 2>&1 | sed "s/$GH_APIDOC_TOKEN/GH_APIDOC_TOKEN/g"
|
||||
git push origin "$BRANCH" 2>&1 | sed "s/$APIDOC_TOKEN/APIDOC_TOKEN/g"
|
||||
|
||||
# Generate compare view links.
|
||||
# NOTE: use "\n" for line endings, not real ones for valid json!
|
||||
COMPARE_LINKS="Compare view: https://github.com/awesomeWM/apidoc/compare/${OLD_REV}...${NEW_REV}"
|
||||
COMPARE_LINKS="$COMPARE_LINKS\nRelevant changes: https://github.com/awesomeWM/apidoc/commit/${RELEVANT_REV}"
|
||||
if [ "$BRANCH" != "gh-pages" ]; then
|
||||
COMPARE_LINKS="$COMPARE_LINKS\nComparison against master (gh-pages): https://github.com/awesomeWM/apidoc/compare/gh-pages...${NEW_REV}"
|
||||
COMPARE_LINKS="$COMPARE_LINKS\nComparison against master (gh-pages): https://github.com/awesomeWM/apidoc/compare/gh-pages...${NEW_REV}"
|
||||
fi
|
||||
# shellcheck disable=SC2028
|
||||
echo "Compare links:\n$COMPARE_LINKS"
|
||||
printf %s "Compare links:\n$COMPARE_LINKS"
|
||||
|
||||
# Post a comment to the PR.
|
||||
if [ "$TRAVIS_PULL_REQUEST" != false ]; then
|
||||
curl -H "Authorization: token $GH_APIDOC_TOKEN" \
|
||||
-d "{\"body\": \"Documentation has been updated for this PR.\n\n$COMPARE_LINKS\"}" \
|
||||
"https://api.github.com/repos/awesomeWM/awesome/issues/${TRAVIS_PULL_REQUEST}/comments" \
|
||||
2>&1 | sed "s/$GH_APIDOC_TOKEN/GH_APIDOC_TOKEN/g"
|
||||
if [ "$PR_NUMBER" != false ]; then
|
||||
curl -H "Authorization: token $APIDOC_TOKEN" \
|
||||
-d "{\"body\": \"Documentation has been updated for this PR.\n\n$COMPARE_LINKS\"}" \
|
||||
"https://api.github.com/repos/awesomeWM/awesome/issues/${PR_NUMBER}/comments" \
|
||||
2>&1 | sed "s/$APIDOC_TOKEN/APIDOC_TOKEN/g"
|
||||
fi
|
||||
|
||||
# vim: filetype=sh:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
|
@ -0,0 +1,156 @@
|
|||
name: Update API docs
|
||||
|
||||
on:
|
||||
# Trigger on push to branches `master` and `3.5`.
|
||||
push:
|
||||
branches: [ master, 3.5 ]
|
||||
# Trigger on pull request events for PRs that have `master` as their target branch
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
# Allow running the workflow manually
|
||||
workflow_dispatch:
|
||||
|
||||
defaults:
|
||||
run:
|
||||
# GitHub Actions adds `errexit` and `pipefail` by default, but we add `xtrace`
|
||||
# to improve debugging some of the longer scripts.
|
||||
shell: /bin/bash -o errexit -o pipefail -o xtrace {0}
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
env:
|
||||
# Used for stable dates in documentation examples. See #2070.
|
||||
SOURCE_DATE_EPOCH: "1893456000"
|
||||
|
||||
steps:
|
||||
# Create a cache invalidation key based on the current year + week.
|
||||
# This way, packages will be checked for updates once every week.
|
||||
- name: Get Date
|
||||
id: get-date
|
||||
run: echo "::set-output name=date::$(/bin/date -u "+%Y%W")"
|
||||
|
||||
- name: Cache apt packages
|
||||
id: cache-apt
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: /var/cache/apt/archives
|
||||
# The trailing number serves as a version flag that can be incremented
|
||||
# to invalidate the cache after changing the list of packages.
|
||||
key: ${{ github.workflow }}-${{ runner.os }}-${{ steps.get-date.outputs.date }}-apt-3
|
||||
|
||||
- name: Download apt packages
|
||||
if: steps.cache-apt.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --download-only -y --no-install-recommends \
|
||||
asciidoctor \
|
||||
cmake \
|
||||
dbus-x11 \
|
||||
gettext \
|
||||
gir1.2-gtk-3.0 \
|
||||
gir1.2-pango-1.0 \
|
||||
git \
|
||||
libdbus-1-dev \
|
||||
libgirepository1.0-dev \
|
||||
libnotify-bin \
|
||||
libpango1.0-dev \
|
||||
libstartup-notification0-dev \
|
||||
libx11-xcb-dev \
|
||||
libxcb-cursor-dev \
|
||||
libxcb-icccm4-dev \
|
||||
libxcb-keysyms1-dev \
|
||||
libxcb-randr0-dev \
|
||||
libxcb-shape0-dev \
|
||||
libxcb-util0-dev \
|
||||
libxcb-xfixes0-dev \
|
||||
libxcb-xinerama0-dev \
|
||||
libxcb-xkb-dev \
|
||||
libxcb-xrm-dev \
|
||||
libxcb-xtest0-dev \
|
||||
libxdg-basedir-dev \
|
||||
libxkbcommon-dev \
|
||||
libxkbcommon-x11-dev \
|
||||
xutils-dev \
|
||||
lua-discount \
|
||||
liblua5.3-dev \
|
||||
lua5.3
|
||||
|
||||
- name: Install downloaded packages
|
||||
run: |
|
||||
sudo dpkg -i /var/cache/apt/archives/*.deb
|
||||
|
||||
- name: Cache luarocks
|
||||
id: cache-luarocks
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: /tmp/luarocks
|
||||
key: ${{ github.workflow }}-${{ runner.os }}-luarocks-3.5.0
|
||||
|
||||
- name: Install fresh Luarocks
|
||||
if: steps.cache-luarocks.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
wget -O /tmp/luarocks.tar.gz https://github.com/luarocks/luarocks/archive/v3.5.0.tar.gz
|
||||
mkdir /tmp/luarocks
|
||||
tar -xf /tmp/luarocks.tar.gz -C /tmp/luarocks --strip-components=1
|
||||
cd /tmp/luarocks
|
||||
./configure
|
||||
make build
|
||||
sudo make install
|
||||
|
||||
- name: Install cached Luarocks
|
||||
if: steps.cache-luarocks.outputs.cache-hit == 'true'
|
||||
run: |
|
||||
cd /tmp/luarocks
|
||||
sudo make install
|
||||
|
||||
- name: Install rocks
|
||||
run: |
|
||||
sudo -H luarocks install lgi
|
||||
sudo -H luarocks install ldoc
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Build Awesome version string
|
||||
run: |
|
||||
# If this workflow is triggered by a pull request, we get a base branch.
|
||||
# Otherwise, check if the current commit has a meaningful name.
|
||||
if [ -n "${{ github.base_ref }}" ]; then
|
||||
AWESOME_VERSION="${{ github.base_ref }}"
|
||||
else
|
||||
AWESOME_VERSION="$(git rev-parse --abbrev-ref HEAD)"
|
||||
fi
|
||||
|
||||
AWESOME_VERSION="${AWESOME_VERSION}-g$(git rev-parse --short HEAD)"
|
||||
|
||||
if [ "${{ github.event_name }}" == "pull_request" && -n "${{ matrix.test_prev_commits }}" ]; then
|
||||
AWESOME_VERSION="${AWESOME_VERSION}-PR${{ github.event.number }}"
|
||||
elif [ "${{ github.event_name }}" == "pull_request" ]; then
|
||||
AWESOME_VERSION="v9999-PR${{ github.event.number }}"
|
||||
fi
|
||||
|
||||
echo "AWESOME_VERSION=${AWESOME_VERSION}" >> ${GITHUB_ENV}
|
||||
|
||||
- name: Create Build Environment
|
||||
run: cmake -E make_directory -B "${{ github.workspace }}/build"
|
||||
|
||||
- name: Configure CMake
|
||||
run: |
|
||||
cmake -S ${{ github.workspace }} -B "${{ github.workspace}}/build" \
|
||||
-DAWESOME_VERSION=$AWESOME_VERSION \
|
||||
-DGENERATE_DOC=ON \
|
||||
-DGENERATE_MANPAGES=ON \
|
||||
-DDO_COVERAGE=OFF
|
||||
|
||||
- name: Build
|
||||
run: cd "${{ github.workspace }}/build" && make
|
||||
|
||||
- name: Run apidoc script
|
||||
env:
|
||||
PR_NUMBER: ${{ github.event.number }}
|
||||
APIDOC_TOKEN: ${{ secrets.APIDOC_TOKEN || github.token }}
|
||||
run: .github/scripts/apidoc.sh
|
||||
|
||||
# vim: filetype=yaml:expandtab:shiftwidth=2:tabstop=2
|
|
@ -0,0 +1,394 @@
|
|||
name: Build & Test
|
||||
|
||||
on:
|
||||
# Trigger on push to branches `master` and `3.5`.
|
||||
push:
|
||||
branches: [ master, 3.5 ]
|
||||
# Trigger on pull request events for PRs that have `master` as their target branch
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
# Allow running the workflow manually
|
||||
workflow_dispatch:
|
||||
|
||||
defaults:
|
||||
run:
|
||||
# GitHub Actions adds `errexit` and `pipefail` by default, but we add `xtrace`
|
||||
# to improve debugging some of the longer scripts.
|
||||
shell: /bin/bash -o errexit -o pipefail -o xtrace {0}
|
||||
|
||||
jobs:
|
||||
main:
|
||||
# The type of runner that the job will run on
|
||||
runs-on: ubuntu-20.04
|
||||
name: ${{ matrix.test_name }}
|
||||
|
||||
strategy:
|
||||
# Let other jobs continue even if one of them fails
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- test_name: "codecov-lua5.3"
|
||||
lua_version: "5.3"
|
||||
lua_name: "lua5.3"
|
||||
coverage: "codecov"
|
||||
manual_screens: true
|
||||
|
||||
- test_name: "coveralls-lua5.2"
|
||||
lua_version: "5.2"
|
||||
lua_name: "lua5.2"
|
||||
coverage: "coveralls"
|
||||
manual_screens: true
|
||||
|
||||
- test_name: "lua5.1"
|
||||
lua_version: "5.1"
|
||||
lua_name: "lua5.1"
|
||||
|
||||
- test_name: "luajit"
|
||||
lua_version: "5.1"
|
||||
lua_name: "luajit"
|
||||
lua_library: "/usr/lib/x86_64-linux-gnu/libluajit-5.1.so"
|
||||
lua_include: "/usr/include/luajit-2.1"
|
||||
luarocks_args: "--lua-suffix=jit-2.1.0-beta3"
|
||||
|
||||
# Lua 5.2 with fixed lgi version and screen size not divisible by 2.
|
||||
- test_name: "fixed-lgi-lua5.2"
|
||||
lua_version: "5.2"
|
||||
lua_name: "lua5.2"
|
||||
lgi_version: "0.9.2"
|
||||
tests_screen_size: "1921x1079"
|
||||
check_qa: true
|
||||
empty_theme_while_loading: true
|
||||
test_prev_commits: true
|
||||
|
||||
env:
|
||||
LUA: ${{ matrix.lua_version }}
|
||||
LUAINCLUDE: ${{ matrix.lua_include || format('/usr/include/lua{0}', matrix.lua_version) }}
|
||||
LUALIBRARY: ${{ matrix.lua_library || format('/usr/lib/x86_64-linux-gnu/liblua{0}.so', matrix.lua_version) }}
|
||||
TESTS_SCREEN_SIZE: ${{ matrix.tests_screen_size }}
|
||||
TEST_TIMEOUT: '100'
|
||||
CI: 'true'
|
||||
|
||||
steps:
|
||||
# Create a cache invalidation key based on the current year + week.
|
||||
# This way, packages will be checked for updates once every week.
|
||||
- name: Get Date
|
||||
id: get-date
|
||||
run: echo "::set-output name=date::$(/bin/date -u "+%Y%W")"
|
||||
|
||||
- name: Cache apt packages
|
||||
id: cache-apt
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: /var/cache/apt/archives
|
||||
# The trailing number serves as a version flag that can be incremented
|
||||
# to invalidate the cache after changing the list of packages.
|
||||
key: ${{ github.workflow }}-${{ runner.os }}-${{ steps.get-date.outputs.date }}-apt-4
|
||||
|
||||
- name: Download apt packages
|
||||
if: steps.cache-apt.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --download-only -y --no-install-recommends \
|
||||
asciidoctor \
|
||||
cmake \
|
||||
dbus-x11 \
|
||||
gettext \
|
||||
gir1.2-gtk-3.0 \
|
||||
gir1.2-pango-1.0 \
|
||||
git \
|
||||
libdbus-1-dev \
|
||||
libgirepository1.0-dev \
|
||||
libnotify-bin \
|
||||
libpango1.0-dev \
|
||||
libstartup-notification0-dev \
|
||||
libx11-xcb-dev \
|
||||
libxcb-cursor-dev \
|
||||
libxcb-icccm4-dev \
|
||||
libxcb-keysyms1-dev \
|
||||
libxcb-randr0-dev \
|
||||
libxcb-shape0-dev \
|
||||
libxcb-util0-dev \
|
||||
libxcb-xfixes0-dev \
|
||||
libxcb-xinerama0-dev \
|
||||
libxcb-xkb-dev \
|
||||
libxcb-xrm-dev \
|
||||
libxcb-xtest0-dev \
|
||||
libxdg-basedir-dev \
|
||||
libxkbcommon-dev \
|
||||
libxkbcommon-x11-dev \
|
||||
wmctrl \
|
||||
x11-apps \
|
||||
xcb-proto \
|
||||
xdotool \
|
||||
xorg \
|
||||
xserver-xephyr \
|
||||
xterm \
|
||||
xutils-dev \
|
||||
xvfb \
|
||||
zsh \
|
||||
lua-discount
|
||||
|
||||
- name: Install downloaded packages
|
||||
run: sudo dpkg -i /var/cache/apt/archives/*.deb
|
||||
|
||||
- name: Install Lua packages
|
||||
run: |
|
||||
if [ "${{ matrix.lua_name }}" = "luajit" ]; then
|
||||
sudo apt-get install libluajit-5.1-dev luajit
|
||||
fi
|
||||
sudo apt-get install liblua${{ matrix.lua_version }}-dev lua${{ matrix.lua_version }}
|
||||
|
||||
- name: Cache luarocks
|
||||
id: cache-luarocks
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: /tmp/luarocks
|
||||
# The build input for luarocks changes per test, so we need separate caches
|
||||
key: ${{ github.workflow }}-${{ runner.os }}-${{ matrix.test_name }}-luarocks-3.5.0
|
||||
|
||||
- name: Install fresh Luarocks
|
||||
if: steps.cache-luarocks.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
wget -O /tmp/luarocks.tar.gz https://github.com/luarocks/luarocks/archive/v3.5.0.tar.gz
|
||||
mkdir /tmp/luarocks
|
||||
tar -xf /tmp/luarocks.tar.gz -C /tmp/luarocks --strip-components=1
|
||||
cd /tmp/luarocks
|
||||
./configure --lua-version=${{ matrix.lua_version }} --with-lua-include=${LUAINCLUDE} ${{ matrix.luarocks_args }}
|
||||
make build
|
||||
sudo make install
|
||||
|
||||
- name: Install cached Luarocks
|
||||
if: steps.cache-luarocks.outputs.cache-hit == 'true'
|
||||
run: |
|
||||
cd /tmp/luarocks
|
||||
sudo make install
|
||||
|
||||
- name: Cache xcb-errors
|
||||
id: cache-xcb-errors
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: /tmp/xcb-errors
|
||||
key: ${{ github.workflow }}-${{ runner.os }}-xcb-errors-1.0
|
||||
|
||||
- name: Install fresh xcb-errors
|
||||
if: steps.cache-xcb-errors.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
git clone --recursive --depth 1 --branch 1.0 https://gitlab.freedesktop.org/xorg/lib/libxcb-errors.git /tmp/xcb-errors
|
||||
cd /tmp/xcb-errors
|
||||
./autogen.sh --prefix=/usr
|
||||
make
|
||||
sudo make install
|
||||
|
||||
- name: Install cached xcb-errors
|
||||
if: steps.cache-xcb-errors.outputs.cache-hit == 'true'
|
||||
run: |
|
||||
cd /tmp/xcb-errors
|
||||
sudo make install
|
||||
|
||||
- name: Install rocks
|
||||
run: |
|
||||
sudo -H luarocks install lgi ${{ matrix.lgi_version }}
|
||||
sudo -H luarocks install ldoc
|
||||
sudo -H luarocks install busted
|
||||
|
||||
- name: Install QA check rocks
|
||||
if: matrix.check_qa
|
||||
run: |
|
||||
sudo -H luarocks install luacheck
|
||||
sudo -H luarocks install depgraph
|
||||
|
||||
- name: Install cluacov rock
|
||||
if: matrix.coverage
|
||||
run: sudo -H luarocks install cluacov
|
||||
|
||||
- name: Install coveralls rock
|
||||
if: matrix.coverage == 'coveralls'
|
||||
run: sudo -H luarocks install luacov-coveralls
|
||||
|
||||
- name: Install codecov.io uploader
|
||||
if: matrix.coverage == 'codecov'
|
||||
run: wget -O /tmp/codecov-bash https://codecov.io/bash
|
||||
|
||||
# Check out repository to ${{ github.workspace }}
|
||||
# Automatically picks the current branch/PR
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Create Build Environment
|
||||
run: cmake -E make_directory -B "${{ github.workspace }}/build"
|
||||
|
||||
- name: Build Awesome version string
|
||||
run: |
|
||||
# If this workflow is triggered by a pull request, we get a base branch.
|
||||
# Otherwise, check if the current commit has a meaningful name.
|
||||
if [ -n "${{ github.base_ref }}" ]; then
|
||||
AWESOME_VERSION="${{ github.base_ref }}"
|
||||
else
|
||||
AWESOME_VERSION="$(git rev-parse --abbrev-ref HEAD)"
|
||||
fi
|
||||
|
||||
AWESOME_VERSION="${AWESOME_VERSION}-g$(git rev-parse --short HEAD)"
|
||||
|
||||
if [ "${{ github.event_name }}" == "pull_request" && -n "${{ matrix.test_prev_commits }}" ]; then
|
||||
AWESOME_VERSION="${AWESOME_VERSION}-PR${{ github.event.number }}"
|
||||
elif [ "${{ github.event_name }}" == "pull_request" ]; then
|
||||
AWESOME_VERSION="v9999-PR${{ github.event.number }}"
|
||||
fi
|
||||
|
||||
echo "AWESOME_VERSION=${AWESOME_VERSION}" >> ${GITHUB_ENV}
|
||||
|
||||
- name: Configure CMake
|
||||
run: |
|
||||
cmake -S ${{ github.workspace }} -B "${{ github.workspace}}/build" \
|
||||
-DAWESOME_VERSION=$AWESOME_VERSION \
|
||||
-DLUA_LIBRARY=$LUALIBRARY \
|
||||
-DLUA_INCLUDE_DIR=$LUAINCLUDE \
|
||||
-DGENERATE_DOC=OFF \
|
||||
-DGENERATE_MANPAGES=OFF \
|
||||
-DDO_COVERAGE=${{ matrix.coverage }} \
|
||||
-DTEST_MANUAL_SCREENS=${{ matrix.manual_screens }} \
|
||||
-DSTRICT_TESTS=true \
|
||||
-DCMAKE_C_FLAGS="-Werror"
|
||||
|
||||
# Break beautiful so that trying to access the theme before `beautiful.init()` causes an error
|
||||
- name: Patch beautiful for an empty default theme
|
||||
if: matrix.empty_theme_while_loading
|
||||
run: |
|
||||
sed -i -e 's/theme = {}/theme = setmetatable({}, { __index = function() error("May not access theme before beautiful.init()") end })/' lib/beautiful/init.lua
|
||||
grep -q 'May not access' lib/beautiful/init.lua
|
||||
|
||||
- name: Build
|
||||
run: cd "${{ github.workspace }}/build" && make
|
||||
|
||||
# Executable needs to be run once to provide coverage results
|
||||
- name: Install and run
|
||||
run: |
|
||||
cd "${{ github.workspace }}/build"
|
||||
sudo make install
|
||||
awesome --version
|
||||
|
||||
- name: Run integration tests
|
||||
run: cd "${{ github.workspace }}/build" && make check-integration
|
||||
|
||||
- name: Run unit tests
|
||||
run: cd "${{ github.workspace }}/build" && make check-unit
|
||||
|
||||
- name: Run examples tests
|
||||
if: matrix.coverage
|
||||
run: cd "${{ github.workspace }}/build" && make check-examples
|
||||
|
||||
- name: Run requires tests
|
||||
if: matrix.coverage
|
||||
run: cd "${{ github.workspace }}/build" && make check-requires
|
||||
|
||||
- name: Run themes tests
|
||||
run: cd "${{ github.workspace }}/build" && make check-themes
|
||||
|
||||
- name: Upload Lua code coverage report
|
||||
if: matrix.coverage == 'codecov'
|
||||
run: |
|
||||
luacov
|
||||
bash /tmp/codecov-bash -f build/luacov.report.out -X gcov -X coveragepy -F luacov
|
||||
|
||||
- name: Upload C code coverage report
|
||||
if: matrix.coverage == 'codecov'
|
||||
run: |
|
||||
# Report coverage for each .gcno file separately.
|
||||
# gcov will create .gcov files for the same source (e.g. for
|
||||
# globalconf.h from awesome.c.gcno and event.c.gcno).
|
||||
i=0
|
||||
cd "${{ github.workspace }}/build"
|
||||
find -path "*/lgi-check.dir" -prune -o \( -name '*.gcno' -print \) | while read -r gcno; do
|
||||
gcov -pb "$gcno"
|
||||
|
||||
mkdir gcov.$(( ++i ))
|
||||
mv *.gcov "gcov.$i"
|
||||
|
||||
# Delete any files for /usr.
|
||||
# They are not relevant and might cause "Invalid path part" errors
|
||||
# with Code Climate.
|
||||
find "gcov.$i" -maxdepth 1 -type f -name '#usr#*.gcov' -delete
|
||||
done
|
||||
|
||||
# Upload to Codecov.
|
||||
bash /tmp/codecov-bash -X gcov -X coveragepy -F gcov
|
||||
|
||||
- name: Merge coverage
|
||||
if: matrix.coverage == 'coveralls'
|
||||
# Coveralls doesn't support GitHub Actions with `service_name` + `service_job_id` (yet?),
|
||||
# but `luacov-coveralls` behaves as if they did by default.
|
||||
# We need to explicitly remove the `service_name`, so that Coveralls uses the
|
||||
# `repo_token` instead.
|
||||
# See "Referencing a repository": https://docs.coveralls.io/api-introduction
|
||||
run: |
|
||||
luacov-coveralls \
|
||||
--verbose \
|
||||
--merge \
|
||||
--repo-token ${{ secrets.COVERALLS_REPO_TOKEN || github.token }} \
|
||||
--service-name ""
|
||||
|
||||
# `check-qa` is the only test that doesn't get a coverage report, so it has to run after all of that.
|
||||
- name: Run qa tests
|
||||
if: matrix.check_qa
|
||||
run: cd "${{ github.workspace }}/build" && make check-qa
|
||||
|
||||
# Check each commit separately (to make git-bisect less annoying).
|
||||
- name: Test previous commits
|
||||
if: matrix.test_prev_commits && github.event_name == 'pull_request'
|
||||
run: |
|
||||
git remote add fork "${{ github.event.pull_request.head.repo.git_url }}"
|
||||
# `actions/checkout` creates a shallow repo (`--depth 1`) by default,
|
||||
# which is fine for everything up until now. But we need individual commits now.
|
||||
# And we only want to unshallow now, to not slow down the checkout for other jobs.
|
||||
git fetch --unshallow --all
|
||||
|
||||
rev_list="$(git rev-list --bisect-all origin/${{ github.base_ref }}..fork/${{ github.head_ref }})"
|
||||
# The most recent commit has already been tested. So if that's the
|
||||
# only commit in the PR, we can stop here.
|
||||
if [[ $(echo "$rev_list" | wc -l) -lt 2 ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
commits="$(echo "$rev_list" | grep -v 'dist=0' | cut -d' ' -f 1)"
|
||||
n="$(echo "$commits" | wc -l)"
|
||||
|
||||
echo "Testing $n commits:"
|
||||
echo "$commits" | xargs -I{} git log -1 --pretty='%h %s' {}
|
||||
|
||||
failed=""
|
||||
for commit in $commits; do
|
||||
echo "Testing commit $commit"
|
||||
|
||||
# Some files are updated when compiling...
|
||||
git checkout --force "$commit"
|
||||
git show --stat --oneline
|
||||
|
||||
cmake -S ${{ github.workspace }} -B "${{ github.workspace}}/build" \
|
||||
-DAWESOME_VERSION=$AWESOME_VERSION \
|
||||
-DLUA_LIBRARY=$LUALIBRARY \
|
||||
-DLUA_INCLUDE_DIR=$LUAINCLUDE \
|
||||
-DGENERATE_DOC=OFF \
|
||||
-DGENERATE_MANPAGES=OFF \
|
||||
-DDO_COVERAGE=OFF \
|
||||
-DTEST_MANUAL_SCREENS=${{ matrix.manual_screens }} \
|
||||
-DSTRICT_TESTS=true \
|
||||
-DCMAKE_C_FLAGS="-Werror"
|
||||
|
||||
cd "${{ github.workspace}}/build"
|
||||
if ! ( make && make check-unit ); then
|
||||
failed="$failed $commit"
|
||||
fi
|
||||
done
|
||||
|
||||
git checkout --quiet --force fork/${{ github.head_ref }}
|
||||
if [ -n "$failed" ]; then
|
||||
echo "Checks failed for these commits:"
|
||||
|
||||
for c in $failed; do
|
||||
git show --no-patch --pretty="%h %s (%an, %ad)" "$c"
|
||||
done
|
||||
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# vim: filetype=yaml:expandtab:shiftwidth=2:tabstop=2
|
|
@ -49,7 +49,7 @@ globals = {
|
|||
-- Enable cache (uses .luacheckcache relative to this rc file).
|
||||
cache = true
|
||||
|
||||
-- Do not enable colors to make the Travis CI output more readable.
|
||||
-- Do not enable colors to make the CI output more readable.
|
||||
color = false
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -3,7 +3,8 @@ pull_request_rules:
|
|||
conditions:
|
||||
- label!=no-mergify
|
||||
- '#approved-reviews-by>=2'
|
||||
- status-success=Travis CI - Pull Request
|
||||
- status-success=Build & Test
|
||||
- status-success=Update API docs
|
||||
- status-success=codecov/patch
|
||||
- status-success=coverage/coveralls
|
||||
actions:
|
||||
|
|
340
.travis.yml
340
.travis.yml
|
@ -1,340 +0,0 @@
|
|||
dist: xenial
|
||||
language: c
|
||||
|
||||
# Build only master and stable branches. Other branches go through PRs.
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- 3.5
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages: &BASE_PACKAGES
|
||||
# Build dependencies.
|
||||
# See also `apt-cache showsrc awesome | grep -E '^(Version|Build-Depends)'`.
|
||||
- libnotify-bin
|
||||
- libcairo2-dev
|
||||
- gir1.2-gtk-3.0
|
||||
- libpango1.0-dev
|
||||
- libxcb-xtest0-dev
|
||||
- libxcb-icccm4-dev
|
||||
- libxcb-randr0-dev
|
||||
- libxcb-keysyms1-dev
|
||||
- libxcb-xinerama0-dev
|
||||
- libdbus-1-dev
|
||||
- libxdg-basedir-dev
|
||||
- libstartup-notification0-dev
|
||||
- imagemagick
|
||||
- libxcb1-dev
|
||||
- libxcb-shape0-dev
|
||||
- libxcb-util0-dev
|
||||
- libx11-xcb-dev
|
||||
- libxcb-cursor-dev
|
||||
- libxcb-xkb-dev
|
||||
- libxcb-xfixes0-dev
|
||||
- libxkbcommon-dev
|
||||
- libxkbcommon-x11-dev
|
||||
# Deps for tests.
|
||||
- dbus-x11
|
||||
- xterm
|
||||
- xdotool
|
||||
- wmctrl
|
||||
- xterm
|
||||
- xvfb
|
||||
- zsh
|
||||
- x11-apps
|
||||
# Need xorg-macros
|
||||
- xutils-dev
|
||||
# lgi.
|
||||
- gir1.2-pango-1.0
|
||||
- libgirepository1.0-dev
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- env: LUA=5.2 LUANAME=lua5.2 DO_COVERAGE=coveralls MANUAL_SCREENS=1
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- *BASE_PACKAGES
|
||||
- liblua5.2-dev
|
||||
- lua5.2
|
||||
- env: LUA=5.3 LUANAME=lua5.3 DO_COVERAGE=codecov MANUAL_SCREENS=1
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- *BASE_PACKAGES
|
||||
- liblua5.3-dev
|
||||
- lua5.3
|
||||
- env: LUA=5.1 LUANAME=lua5.1 BUILD_IN_DIR=/tmp/awesome-build WITH_XCB_ERRORS=yes
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- *BASE_PACKAGES
|
||||
- liblua5.1-dev
|
||||
- lua5.1
|
||||
# For xcb-errors
|
||||
- xcb-proto
|
||||
- env: LUA=5.1 LUANAME=luajit-2.0 LUALIBRARY=/usr/lib/x86_64-linux-gnu/libluajit-5.1.so LUAROCKS_ARGS=--lua-suffix=jit-2.0.4
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- *BASE_PACKAGES
|
||||
- libluajit-5.1-dev
|
||||
- luajit
|
||||
# Lua 5.2 with older lgi and screen size not divisible by 2.
|
||||
# SOURCE_DATE_EPOCH: used for stable dates during build.
|
||||
- env: LUA=5.2 LUANAME=lua5.2 LGIVER=0.8.0 TESTS_SCREEN_SIZE=1921x1079 BUILD_APIDOC=true DO_CHECKQA=1 EMPTY_THEME_WHILE_LOADING=1 SOURCE_DATE_EPOCH=1893456000 TEST_PREV_COMMITS=1
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- *BASE_PACKAGES
|
||||
- liblua5.2-dev
|
||||
- lua5.2
|
||||
- lua-discount
|
||||
|
||||
env:
|
||||
global:
|
||||
# Secure GH_APIDOC_TOKEN to push to awesomeWM/apidoc.
|
||||
- secure: "R/HYDclnws1I1+v9Yjt+RKa4CsFhbBT9tiwE3EfPhEj2KCYX4sFRMxuZvLf5sq0XWdrQaPhQ54fgAZGr3f054JKRXcTB0g9J6nhSHz9kIjPh446gafUhEeDQcZRwM/MeCWiwFIkiZm6smYoDFE9JTWu6quNV+lQ4kcVDOp2ibEc="
|
||||
|
||||
before_install:
|
||||
- if [ "$BUILD_APIDOC" = true ] && [ -n "$DO_COVERAGE" ]; then echo "BUILD_APIDOC and DO_COVERAGE are not meant to be used together." >&2; exit 1; fi
|
||||
- if [ -z $LUAINCLUDE ]; then LUAINCLUDE=/usr/include/${LUANAME}; fi
|
||||
- if [ -z $LUALIBRARY ]; then LUALIBRARY=/usr/lib/x86_64-linux-gnu/lib${LUANAME}.so; fi
|
||||
- cmake --version
|
||||
|
||||
install:
|
||||
- sudo gem install asciidoctor
|
||||
- |
|
||||
# Install xcb-util-xrm.
|
||||
set -e
|
||||
(git clone --depth 1 --recursive https://github.com/Airblader/xcb-util-xrm.git /tmp/xcb-util-xrm
|
||||
cd /tmp/xcb-util-xrm
|
||||
./autogen.sh --prefix=/usr
|
||||
make && sudo make install)
|
||||
|
||||
# Install xcb-errors if needed
|
||||
- |
|
||||
set -e
|
||||
if [[ "$WITH_XCB_ERRORS" == "yes" ]]; then
|
||||
git clone --depth 1 --recursive https://gitlab.freedesktop.org/xorg/lib/libxcb-errors.git /tmp/xcb-errors
|
||||
(cd /tmp/xcb-errors
|
||||
./autogen.sh --prefix=/usr
|
||||
make && sudo make install)
|
||||
fi
|
||||
|
||||
- |
|
||||
# Install Lua (per env).
|
||||
if [[ "$LUANAME" == "luajit-2.0" ]]; then
|
||||
# "Create" /usr/bin/lua if needed (Yup, this is a bad hack)
|
||||
if [ ! -e "/usr/bin/lua" ]; then sudo ln -s /usr/bin/luajit /usr/bin/lua; fi
|
||||
else
|
||||
# lua5.3 does not install /usr/bin/lua, but lua5.1/lua5.2 do.
|
||||
if [ ! -e "/usr/bin/lua" ]; then sudo ln -s /usr/bin/${LUANAME} /usr/bin/lua; fi
|
||||
fi
|
||||
- lua -v
|
||||
|
||||
# Install luarocks (for the selected Lua version).
|
||||
- |
|
||||
travis_retry wget https://github.com/luarocks/luarocks/archive/v3.0.4.tar.gz
|
||||
tar xf v3.0.4.tar.gz -C /tmp
|
||||
(cd /tmp/luarocks-* \
|
||||
&& ./configure --lua-version=$LUA --with-lua-include=${LUAINCLUDE} ${LUAROCKS_ARGS} \
|
||||
&& make build \
|
||||
&& sudo make install)
|
||||
|
||||
- travis_retry sudo luarocks install lgi $LGIVER
|
||||
|
||||
# Install busted for "make check-unit".
|
||||
- travis_retry sudo luarocks install busted
|
||||
# Install luacheck for "make check-qa".
|
||||
- if [ "$DO_CHECKQA" = 1 ]; then travis_retry sudo luarocks install luacheck; fi
|
||||
# Install depgraph for "make check-qa".
|
||||
- if [ "$DO_CHECKQA" = 1 ]; then travis_retry sudo luarocks install depgraph; fi
|
||||
|
||||
# Install ldoc for building docs and check-ldoc-warnings.
|
||||
- |
|
||||
if [ "$BUILD_APIDOC" = "true" ] || [ "$DO_CHECKQA" = 1 ]; then
|
||||
travis_retry sudo luarocks install ldoc
|
||||
fi
|
||||
|
||||
# Install dependencies for code coverage testing.
|
||||
- if [ -n "$DO_COVERAGE" ]; then sudo luarocks install cluacov; fi
|
||||
- if [ "$DO_COVERAGE" = "coveralls" ]; then sudo luarocks install luacov-coveralls; fi
|
||||
|
||||
# Determine custom version.
|
||||
- export AWESOME_VERSION="${TRAVIS_BRANCH}-g$(git rev-parse --short HEAD)"
|
||||
- |
|
||||
if [ "$TRAVIS_PULL_REQUEST" != false ] && [ "$TEST_PREV_COMMITS" = 1 ]; then
|
||||
AWESOME_VERSION="${AWESOME_VERSION}-PR${TRAVIS_PULL_REQUEST}"
|
||||
elif [ "$TRAVIS_PULL_REQUEST" != false ]; then
|
||||
AWESOME_VERSION="v9999-PR${TRAVIS_PULL_REQUEST}";
|
||||
fi
|
||||
# function for codecov support
|
||||
- if [ "$DO_COVERAGE" = "codecov" ]; then travis_retry wget -O /tmp/codecov-bash https://codecov.io/bash; fi
|
||||
- |
|
||||
do_codecov() {
|
||||
echo "== do_codecov in $PWD: $*: build/luacov.stats.out: =="
|
||||
if [ "$DO_COVERAGE" = "codecov" ]; then
|
||||
test -f build/luacov.stats.out || { echo 'build/luacov.stats.out does not exist.'; return 1; }
|
||||
luacov || return 1
|
||||
travis_retry bash /tmp/codecov-bash -f build/luacov.report.out -X gcov -X coveragepy -F luacov -e LUANAME,LGIVER || return 1
|
||||
rm build/luacov.report.out build/luacov.stats.out
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
- |
|
||||
do_codecov_gcov() {
|
||||
echo "== do_codecov_gcov in $PWD: $*: =="
|
||||
if [ "$DO_COVERAGE" = "codecov" ]; then
|
||||
# Report coverage for each .gcno file separately.
|
||||
# gcov will create .gcov files for the same source (e.g. for
|
||||
# globalconf.h from awesome.c.gcno and event.c.gcno).
|
||||
i=0
|
||||
set -x
|
||||
(
|
||||
cd build
|
||||
find -path "*/lgi-check.dir" -prune -o \( -name '*.gcno' -print \) | while read -r gcno; do
|
||||
gcov -pb "$gcno"
|
||||
|
||||
mkdir gcov.$(( ++i ))
|
||||
mv *.gcov "gcov.$i"
|
||||
|
||||
# Delete any files for /usr.
|
||||
# They are not relevant and might cause "Invalid path part" errors
|
||||
# with Code Climate.
|
||||
find "gcov.$i" -maxdepth 1 -type f -name '#usr#*.gcov' -delete
|
||||
done
|
||||
|
||||
# Upload to Codecov.
|
||||
travis_retry bash /tmp/codecov-bash -X gcov -X coveragepy -F gcov -e LUANAME,LGIVER
|
||||
)
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Functions for custom Travis folds.
|
||||
- |
|
||||
travis_fold_start() {
|
||||
travis_fold start "$1"
|
||||
travis_fold_current="$1"
|
||||
}
|
||||
travis_fold_end() {
|
||||
travis_fold end "$travis_fold_current"
|
||||
}
|
||||
travis_run_in_fold() {
|
||||
travis_fold_start "$1"
|
||||
shift
|
||||
"$@" || return 1
|
||||
travis_fold_end
|
||||
return 0
|
||||
}
|
||||
script:
|
||||
- if [ "$MANUAL_SCREENS" != "1" ]; then export MANUAL_SCREENS=0; fi
|
||||
- export CMAKE_ARGS="-DLUA_LIBRARY=${LUALIBRARY} -D LUA_INCLUDE_DIR=${LUAINCLUDE} -D OVERRIDE_VERSION=$AWESOME_VERSION -D STRICT_TESTS=true -D DO_COVERAGE=$DO_COVERAGE -D TEST_MANUAL_SCREENS=$MANUAL_SCREENS -D CMAKE_C_FLAGS=-Werror"
|
||||
- |
|
||||
if [ "$EMPTY_THEME_WHILE_LOADING" = 1 ]; then
|
||||
# Break beautiful so that trying to access the theme before beautiful.init() causes an error
|
||||
sed -i -e 's/theme = {}/theme = setmetatable({}, { __index = function() error("May not access theme before beautiful.init()") end })/' lib/beautiful/init.lua \
|
||||
&& grep -q 'May not access' lib/beautiful/init.lua
|
||||
fi
|
||||
- |
|
||||
set -e
|
||||
if [ -n "$BUILD_IN_DIR" ]; then
|
||||
# Explicitly remove the Makefile to not build from the src dir accidentally.
|
||||
rm Makefile
|
||||
SOURCE_DIRECTORY="$PWD"
|
||||
mkdir "$BUILD_IN_DIR"
|
||||
cd "$BUILD_IN_DIR"
|
||||
travis_run_in_fold "build_in_dir" cmake $CMAKE_ARGS "$SOURCE_DIRECTORY"
|
||||
fi
|
||||
- travis_run_in_fold "make" make ; sleep 5
|
||||
- make ; sleep 5
|
||||
- make ; sleep 5
|
||||
- make ; sleep 5
|
||||
- |
|
||||
if [ "$TRAVIS_TEST_RESULT" = 0 ]; then
|
||||
travis_run_in_fold "make.install" sudo env PATH=$PATH make install
|
||||
awesome --version
|
||||
fi
|
||||
# Run checks.
|
||||
- |
|
||||
if [ "$TRAVIS_TEST_RESULT" = 0 ]; then
|
||||
set -ex
|
||||
if [ -n "$DO_COVERAGE" ]; then
|
||||
travis_fold_start "DO_COVERAGE"
|
||||
|
||||
# Run tests/examples explicitly.
|
||||
make check-examples || exit 1
|
||||
do_codecov samples
|
||||
|
||||
make check-unit || exit 1
|
||||
do_codecov unittests
|
||||
make check-integration || exit 1
|
||||
do_codecov functionaltests
|
||||
make check-themes || exit 1
|
||||
do_codecov themes
|
||||
do_codecov_gcov c_code
|
||||
|
||||
travis_fold_end
|
||||
else
|
||||
# TODO: does not run check-examples. Should it?
|
||||
travis_run_in_fold "make.check-unit" make check-unit
|
||||
travis_run_in_fold "make.check-integration" make check-integration
|
||||
travis_run_in_fold "make.check-themes" make check-themes
|
||||
fi
|
||||
set +x
|
||||
fi
|
||||
# Run check-qa.
|
||||
- |
|
||||
if [ "$DO_CHECKQA" = 1 ]; then
|
||||
travis_run_in_fold "make.check-qa" make check-qa
|
||||
fi
|
||||
- |
|
||||
if [ "$TEST_PREV_COMMITS" = 1 ] && ! [ "$TRAVIS_PULL_REQUEST" = false ]; then
|
||||
set -e
|
||||
# Check each commit separately (to make git-bisect less annoying).
|
||||
# Fix Travis' commit range (https://github.com/travis-ci/travis-ci/issues/4596).
|
||||
commit_range="${TRAVIS_COMMIT_RANGE/.../..}"
|
||||
echo "Testing previous commits ($commit_range)"
|
||||
rev_list="$(git rev-list --bisect-all $commit_range)"
|
||||
echo "rev-list: $rev_list"
|
||||
commits="$(echo "$rev_list" | grep -v 'dist=0' | cut -d\ -f 1)"
|
||||
n="$(echo "$commits" | wc -l)"
|
||||
echo "Testing $n commits: $commits"
|
||||
i=0
|
||||
failed=
|
||||
for commit in $commits; do
|
||||
i=$((i+1))
|
||||
travis_fold_start "test_commit_${commit}_.$i.$n"
|
||||
echo "Testing commit $commit"
|
||||
git reset --hard # Some files are updated when compiling...
|
||||
git checkout "$commit"
|
||||
git --no-pager show --stat
|
||||
|
||||
if ! make all check CMAKE_ARGS+="-D DO_COVERAGE=0"; then
|
||||
failed="$failed $commit"
|
||||
fi
|
||||
travis_fold_end
|
||||
done
|
||||
|
||||
git checkout -qf FETCH_HEAD
|
||||
if [ -n "$failed" ]; then
|
||||
echo "Checks failed for these commits:"
|
||||
for c in $failed; do
|
||||
git log -1 --pretty="%h %s (%an, %ad)" "$c"
|
||||
done
|
||||
false
|
||||
fi
|
||||
fi
|
||||
|
||||
after_success:
|
||||
# Push updated API docs for relevant branches, e.g. non-PRs builds on master.
|
||||
- if [ "$BUILD_APIDOC" = "true" ]; then build-utils/travis-apidoc.sh; fi
|
||||
# Push code coverage information
|
||||
- |
|
||||
set -e
|
||||
if [ "$DO_COVERAGE" = "coveralls" ]; then
|
||||
test -f build/luacov.stats.out || { echo 'build/luacov.stats.out does not exist.'; return 1; }
|
||||
luacov-coveralls --verbose --merge
|
||||
fi
|
|
@ -619,13 +619,14 @@ main(int argc, char **argv)
|
|||
bool success = true;
|
||||
/* Get the first config that will be tried */
|
||||
const char *config = luaA_find_config(&xdg, confpath, true_config_callback);
|
||||
fprintf(stdout, "Checking config '%s'... ", config);
|
||||
|
||||
/* Try to parse it */
|
||||
lua_State *L = luaL_newstate();
|
||||
if(luaL_loadfile(L, config))
|
||||
{
|
||||
const char *err = lua_tostring(L, -1);
|
||||
fprintf(stderr, "%s\n", err);
|
||||
fprintf(stdout, "\nERROR: %s\n", err);
|
||||
success = false;
|
||||
}
|
||||
p_delete(&config);
|
||||
|
@ -633,12 +634,11 @@ main(int argc, char **argv)
|
|||
|
||||
if(!success)
|
||||
{
|
||||
fprintf(stderr, "✘ Configuration file syntax error.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "✔ Configuration file syntax OK.\n");
|
||||
fprintf(stdout, "OK\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,6 +71,14 @@ if (NOT LUA_FOUND)
|
|||
"You might want to hint it using the LUA_DIR environment variable, "
|
||||
"or set the LUA_INCLUDE_DIR / LUA_LIBRARY CMake variables.")
|
||||
endif()
|
||||
|
||||
set(LUA_FULL_VERSION "${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}.${LUA_VERSION_PATCH}")
|
||||
# 5.1 <= LUA_VERSION < 5.4
|
||||
if(NOT ((LUA_FULL_VERSION VERSION_EQUAL 5.1.0 OR LUA_FULL_VERSION VERSION_GREATER 5.1.0) AND LUA_FULL_VERSION VERSION_LESS 5.4.0))
|
||||
message(FATAL_ERROR "Awesome only supports Lua versions 5.1-5.3, please refer to"
|
||||
"https://awesomewm.org/apidoc/documentation/10-building-and-testing.md.html#Building")
|
||||
endif()
|
||||
|
||||
# }}}
|
||||
|
||||
# {{{ Check if documentation can be build
|
||||
|
|
|
@ -77,7 +77,7 @@ mylauncher = awful.widget.launcher({ image = beautiful.awesome_icon,
|
|||
menubar.utils.terminal = terminal -- Set the terminal for applications that require it
|
||||
-- }}}
|
||||
|
||||
-- {{{ Tag
|
||||
-- {{{ Tag layout
|
||||
-- @DOC_LAYOUT@
|
||||
-- Table of layouts to cover with awful.layout.inc, order matters.
|
||||
tag.connect_signal("request::default_layouts", function()
|
||||
|
@ -99,6 +99,27 @@ tag.connect_signal("request::default_layouts", function()
|
|||
end)
|
||||
-- }}}
|
||||
|
||||
-- {{{ Wallpaper
|
||||
-- @DOC_WALLPAPER@
|
||||
screen.connect_signal("request::wallpaper", function(s)
|
||||
awful.wallpaper {
|
||||
screen = s,
|
||||
widget = {
|
||||
{
|
||||
image = beautiful.wallpaper,
|
||||
upscale = true,
|
||||
downscale = true,
|
||||
widget = wibox.widget.imagebox,
|
||||
},
|
||||
valign = "center",
|
||||
halign = "center",
|
||||
tiled = false,
|
||||
widget = wibox.container.tile,
|
||||
}
|
||||
}
|
||||
end)
|
||||
-- }}}
|
||||
|
||||
-- {{{ Wibar
|
||||
|
||||
-- Keyboard map indicator and switcher
|
||||
|
@ -107,19 +128,6 @@ mykeyboardlayout = awful.widget.keyboardlayout()
|
|||
-- Create a textclock widget
|
||||
mytextclock = wibox.widget.textclock()
|
||||
|
||||
-- @DOC_WALLPAPER@
|
||||
screen.connect_signal("request::wallpaper", function(s)
|
||||
-- Wallpaper
|
||||
if beautiful.wallpaper then
|
||||
local wallpaper = beautiful.wallpaper
|
||||
-- If wallpaper is a function, call it with the screen
|
||||
if type(wallpaper) == "function" then
|
||||
wallpaper = wallpaper(s)
|
||||
end
|
||||
gears.wallpaper.maximized(wallpaper, s, true)
|
||||
end
|
||||
end)
|
||||
|
||||
-- @DOC_FOR_EACH_SCREEN@
|
||||
screen.connect_signal("request::desktop_decoration", function(s)
|
||||
-- Each screen has its own tag table.
|
||||
|
@ -179,26 +187,27 @@ screen.connect_signal("request::desktop_decoration", function(s)
|
|||
|
||||
-- @DOC_WIBAR@
|
||||
-- Create the wibox
|
||||
s.mywibox = awful.wibar({ position = "top", screen = s })
|
||||
|
||||
-- @DOC_SETUP_WIDGETS@
|
||||
-- Add widgets to the wibox
|
||||
s.mywibox.widget = {
|
||||
layout = wibox.layout.align.horizontal,
|
||||
{ -- Left widgets
|
||||
layout = wibox.layout.fixed.horizontal,
|
||||
mylauncher,
|
||||
s.mytaglist,
|
||||
s.mypromptbox,
|
||||
},
|
||||
s.mytasklist, -- Middle widget
|
||||
{ -- Right widgets
|
||||
layout = wibox.layout.fixed.horizontal,
|
||||
mykeyboardlayout,
|
||||
wibox.widget.systray(),
|
||||
mytextclock,
|
||||
s.mylayoutbox,
|
||||
},
|
||||
s.mywibox = awful.wibar {
|
||||
position = "top",
|
||||
screen = s,
|
||||
-- @DOC_SETUP_WIDGETS@
|
||||
widget = {
|
||||
layout = wibox.layout.align.horizontal,
|
||||
{ -- Left widgets
|
||||
layout = wibox.layout.fixed.horizontal,
|
||||
mylauncher,
|
||||
s.mytaglist,
|
||||
s.mypromptbox,
|
||||
},
|
||||
s.mytasklist, -- Middle widget
|
||||
{ -- Right widgets
|
||||
layout = wibox.layout.fixed.horizontal,
|
||||
mykeyboardlayout,
|
||||
wibox.widget.systray(),
|
||||
mytextclock,
|
||||
s.mylayoutbox,
|
||||
},
|
||||
}
|
||||
}
|
||||
end)
|
||||
-- }}}
|
||||
|
|
|
@ -124,6 +124,10 @@ to an object such as the mouse.
|
|||
The `naughty.layout.box` allows to provide custom widgets to use within the
|
||||
notifications.
|
||||
|
||||
The `awful.wallpaper` provides a non-intereactive "backgroud" for one or more
|
||||
`screen`. While it uses normal widget, it will not automatically be repainted
|
||||
if they change. It will also not provide any mouse events.
|
||||
|
||||
Finally, the `awful.titlebar`, while not technically a real `wibox`, acts
|
||||
exactly the same way and allows to attach widgets on each side of clients.
|
||||
|
||||
|
|
|
@ -72,6 +72,17 @@ variables such as `bg_normal`. To get a list of all official variables, see
|
|||
the [appearance guide](../documentation/06-appearance.md.html).
|
||||
]]
|
||||
|
||||
sections.DOC_WALLPAPER = [[
|
||||
The AwesomeWM wallpaper module, `awful.wallpaper` support both per-screen wallpaper
|
||||
and wallpaper across multiple screens. In the default configuration, the `"request::wallpaper"` signal
|
||||
is emitted everytime a screen is added, moved, resized or when the bars
|
||||
(`awful.wibar`) are moved.
|
||||
|
||||
This is will suited for single-screen wallpapers. If you wish to use multi-screen wallpaper,
|
||||
it is better to create a global wallpaper object and edit it when the screen change. See
|
||||
the `add_screen`/`remove_screens` methods and the `screens` property of `awful.wallpaper` for
|
||||
examples.
|
||||
]]
|
||||
|
||||
sections.DOC_DEFAULT_APPLICATIONS = [[
|
||||
|
||||
|
|
|
@ -25,10 +25,10 @@ have not opened any programs. On the top right you see the time/date and a
|
|||
symbol showing the current layout. You can also click on the symbol to change
|
||||
the active layout.
|
||||
|
||||
One of the big advantages of Awesome over other tiling window managers is its good
|
||||
mouse support. Awesome can act as a full floating window manager (almost like
|
||||
openbox) if you want. For this basic tutorial we will mainly focus on keyboard
|
||||
control, so let's learn some key bindings now.
|
||||
One of the big advantages of Awesome over other tiling window managers is its
|
||||
good mouse support. Awesome can act as a full floating window manager (almost
|
||||
like openbox) if you want. For this basic tutorial we will mainly focus on
|
||||
keyboard control, so let's learn some key bindings now.
|
||||
|
||||
Let's open a terminal: press *Mod4+Enter*. Mod4 is your "Windows key", the key
|
||||
between Ctrl and Alt. You can change the modkey if you want, but we'll get to
|
||||
|
@ -65,20 +65,23 @@ overview now also provides a cheat sheet for controlling Vim.
|
|||
|
||||
## Change the theme
|
||||
|
||||
Awesome has four themes you can choose from: *default*, *sky*, *xresources*, and
|
||||
*zenburn*.
|
||||
Awesome has multiple builtin themes you can choose from:
|
||||
|
||||
To change the theme, open your rc.lua and edit this line near the beginning of
|
||||
the file:
|
||||
* *default*
|
||||
* *gtk*
|
||||
* *sky*
|
||||
* *xresources*
|
||||
* *zenburn*
|
||||
|
||||
To change the theme, open your `rc.lua`, find this line near the beginning of
|
||||
the file, and change `default` to one of the other values mentioned:
|
||||
|
||||
beautiful.init(gears.filesystem.get_themes_dir() .. "default/theme.lua")
|
||||
|
||||
For this tutorial we will stick with the default theme.
|
||||
|
||||
Now we will customize the theme. Copy
|
||||
`/usr/share/awesome/themes/default/theme.lua` to `~/.config/awesome/` and change
|
||||
the above line in your theme like this (remember to replace `USER` with your
|
||||
user name):
|
||||
However, for this tutorial we will copy and customize the default theme.
|
||||
Copy `/usr/share/awesome/themes/default/theme.lua` to `~/.config/awesome/`
|
||||
and change the line shown above in `rc.lua` like this. Make sure to replace
|
||||
`USER` with your user name.
|
||||
|
||||
beautiful.init("/home/USER/.config/awesome/theme.lua")
|
||||
|
||||
|
@ -89,7 +92,9 @@ this line in your theme file:
|
|||
|
||||
theme.wallpaper = themes_path.."default/background.png"
|
||||
|
||||
The default uses a path relative to `themes_path` by using the `..` operator to join two strings together. To just set it to an absolute path for example, you could do:
|
||||
The default uses a path relative to `themes_path` by using the `..` operator to
|
||||
join two strings together. To just set it to an absolute path for example,
|
||||
you could do:
|
||||
|
||||
theme.wallpaper = "/usr/share/backgrounds/my-awesome-wallpaper.png"
|
||||
|
||||
|
|
|
@ -36,8 +36,7 @@ Do **not** use such functions and prefer `awful.spawn.easy_async`,
|
|||
fast enough and won't impact the main event loop iteration time, you are wrong.
|
||||
*Every* calls to `io.open` are impacted by the system `iowait` queue and can
|
||||
spend hundreds of milliseconds blocked *before* being executed. Note that
|
||||
some common widget or probe libraries such as
|
||||
[Vicious](https://github.com/Mic92/vicious) do not follow this
|
||||
some common widget or probe libraries do not follow this
|
||||
advice currently and are known to cause input lag on some systems (but not all).
|
||||
|
||||
In both case, a warning like:
|
||||
|
@ -53,6 +52,19 @@ provide a theme daemon. For more information about how to manage the
|
|||
look and feel of applications, refer to the
|
||||
[Arch Linux Wiki](https://wiki.archlinux.org/index.php/Category:Eye_candy).
|
||||
|
||||
### Awesome doesn't show up on my login screen
|
||||
|
||||
There have been cases where Awesome wasn't correctly registered with the display manager,
|
||||
usually due to a missing `.desktop` file.
|
||||
|
||||
To fix such issues, copy `awesome.desktop` from the root of [the repository](https://github.com/awesomeWM/awesome/) to `/usr/share/xsessions/`.
|
||||
|
||||
```shell
|
||||
curl https://raw.githubusercontent.com/awesomeWM/awesome/master/awesome.desktop | sudo tee /usr/share/xsessions/awesome.desktop
|
||||
```
|
||||
|
||||
If you installed Awesome through a package manager, you might want to check if the package includes that file and, if not, notify the maintainer to add it as appropriate.
|
||||
|
||||
## Configuration
|
||||
|
||||
### How to change the default window management layout?
|
||||
|
|
|
@ -121,6 +121,8 @@ local function parse_files(paths, property_name, matcher, name_matcher)
|
|||
local exp2 = matcher or "[-*]*[ ]*".. property_name ..".(.+)"
|
||||
local exp3 = name_matcher or "[. ](.+)"
|
||||
|
||||
local count = 0
|
||||
local names = {} -- Used to check for duplicates
|
||||
local ret = {}
|
||||
|
||||
table.sort(paths)
|
||||
|
@ -162,13 +164,47 @@ local function parse_files(paths, property_name, matcher, name_matcher)
|
|||
"seems to be misformatted. Use `beautiful.namespace_name`"
|
||||
)
|
||||
else
|
||||
table.insert(ret, {
|
||||
file = file,
|
||||
name = name:gsub("_", "_"),
|
||||
link = get_link(file, var, var:match(exp3):gsub("_", "\\_")),
|
||||
desc = buffer:gmatch("[-*/ \n]+([^\n.]*)")() or "",
|
||||
mod = path_to_module(file),
|
||||
})
|
||||
local insert_name = name:gsub("_", "_")
|
||||
local link = get_link(file, var, var:match(exp3):gsub("_", "\\_"))
|
||||
local desc = buffer:gmatch("[-*/ \n]+([^\n.]*)")() or ""
|
||||
local mod = path_to_module(file)
|
||||
|
||||
if names[insert_name] == nil then
|
||||
count = count + 1
|
||||
table.insert(ret, count, {
|
||||
file = file,
|
||||
name = insert_name,
|
||||
link = link,
|
||||
desc = desc,
|
||||
mod = mod
|
||||
})
|
||||
names[insert_name] = count
|
||||
else
|
||||
link = link .. "(" .. mod .. ")"
|
||||
if type(ret[names[insert_name]].link) ~= "table" then
|
||||
ret[names[insert_name]].file = {
|
||||
ret[names[insert_name]].file,
|
||||
file
|
||||
}
|
||||
ret[names[insert_name]].link = {
|
||||
ret[names[insert_name]].link .. " (" .. ret[names[insert_name]].mod .. ")",
|
||||
link
|
||||
}
|
||||
ret[names[insert_name]].desc = {
|
||||
ret[names[insert_name]].desc,
|
||||
desc
|
||||
}
|
||||
ret[names[insert_name]].mod = {
|
||||
ret[names[insert_name]].mod,
|
||||
mod
|
||||
}
|
||||
else
|
||||
table.insert(ret[names[insert_name]].file, file)
|
||||
table.insert(ret[names[insert_name]].link, link)
|
||||
table.insert(ret[names[insert_name]].desc, desc)
|
||||
table.insert(ret[names[insert_name]].mod, mod)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
buffer = ""
|
||||
|
@ -190,7 +226,15 @@ local function create_table(entries, columns, prefix)
|
|||
local line = " <tr>"
|
||||
|
||||
for _, column in ipairs(columns) do
|
||||
line = line.."<td>"..entry[column].."</td>"
|
||||
if type(entry[column]) == "table" then
|
||||
line = line .. "<td><ul>"
|
||||
for _,v in pairs(entry[column]) do
|
||||
line = line .. "<li>" .. v .. "</li>"
|
||||
end
|
||||
line = line .. "</ul></td>"
|
||||
else
|
||||
line = line.."<td>"..entry[column].."</td>"
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(lines, prefix..line.."</tr>\n")
|
||||
|
|
|
@ -1,80 +1,80 @@
|
|||
* <table class='widget_list' border=1>
|
||||
* <tr><td>num_glyphs </td></tr>
|
||||
* <tr><td>cursor </td></tr>
|
||||
* <tr><td>arrow </td></tr>
|
||||
* <tr><td>based_arrow_down </td></tr>
|
||||
* <tr><td>based_arrow_up </td></tr>
|
||||
* <tr><td>boat </td></tr>
|
||||
* <tr><td>bogosity </td></tr>
|
||||
* <tr><td>bottom_left_corner </td></tr>
|
||||
* <tr><td>bottom_right_corner </td></tr>
|
||||
* <tr><td>bottom_side </td></tr>
|
||||
* <tr><td>bottom_tee </td></tr>
|
||||
* <tr><td>box_spiral </td></tr>
|
||||
* <tr><td>center_ptr </td></tr>
|
||||
* <tr><td>circle </td></tr>
|
||||
* <tr><td>clock </td></tr>
|
||||
* <tr><td>coffee_mug </td></tr>
|
||||
* <tr><td>cross </td></tr>
|
||||
* <tr><td>cross_reverse </td></tr>
|
||||
* <tr><td>crosshair </td></tr>
|
||||
* <tr><td>diamond_cross </td></tr>
|
||||
* <tr><td>dot </td></tr>
|
||||
* <tr><td>dotbox </td></tr>
|
||||
* <tr><td>double_arrow </td></tr>
|
||||
* <tr><td>draft_large </td></tr>
|
||||
* <tr><td>draft_small </td></tr>
|
||||
* <tr><td>draped_box </td></tr>
|
||||
* <tr><td>exchange </td></tr>
|
||||
* <tr><td>fleur </td></tr>
|
||||
* <tr><td>gobbler </td></tr>
|
||||
* <tr><td>gumby </td></tr>
|
||||
* <tr><td>hand </td></tr>
|
||||
* <tr><td>hand </td></tr>
|
||||
* <tr><td>heart </td></tr>
|
||||
* <tr><td>icon </td></tr>
|
||||
* <tr><td>iron_cross </td></tr>
|
||||
* <tr><td>left_ptr </td></tr>
|
||||
* <tr><td>left_side </td></tr>
|
||||
* <tr><td>left_tee </td></tr>
|
||||
* <tr><td>leftbutton </td></tr>
|
||||
* <tr><td>ll_angle </td></tr>
|
||||
* <tr><td>lr_angle </td></tr>
|
||||
* <tr><td>man </td></tr>
|
||||
* <tr><td>middlebutton </td></tr>
|
||||
* <tr><td>mouse </td></tr>
|
||||
* <tr><td>pencil </td></tr>
|
||||
* <tr><td>pirate </td></tr>
|
||||
* <tr><td>plus </td></tr>
|
||||
* <tr><td>question_arrow </td></tr>
|
||||
* <tr><td>right_ptr </td></tr>
|
||||
* <tr><td>right_side </td></tr>
|
||||
* <tr><td>right_tee </td></tr>
|
||||
* <tr><td>rightbutton </td></tr>
|
||||
* <tr><td>rtl_logo </td></tr>
|
||||
* <tr><td>sailboat </td></tr>
|
||||
* <tr><td>sb_down_arrow </td></tr>
|
||||
* <tr><td>sb_h_double_arrow </td></tr>
|
||||
* <tr><td>sb_left_arrow </td></tr>
|
||||
* <tr><td>sb_right_arrow </td></tr>
|
||||
* <tr><td>sb_up_arrow </td></tr>
|
||||
* <tr><td>sb_v_double_arrow </td></tr>
|
||||
* <tr><td>shuttle </td></tr>
|
||||
* <tr><td>sizing </td></tr>
|
||||
* <tr><td>spider </td></tr>
|
||||
* <tr><td>spraycan </td></tr>
|
||||
* <tr><td>star </td></tr>
|
||||
* <tr><td>target </td></tr>
|
||||
* <tr><td>tcross </td></tr>
|
||||
* <tr><td>top_left_arrow </td></tr>
|
||||
* <tr><td>top_left_corner </td></tr>
|
||||
* <tr><td>top_right_corner </td></tr>
|
||||
* <tr><td>top_side </td></tr>
|
||||
* <tr><td>top_tee </td></tr>
|
||||
* <tr><td>trek </td></tr>
|
||||
* <tr><td>ul_angle </td></tr>
|
||||
* <tr><td>umbrella </td></tr>
|
||||
* <tr><td>ur_angle </td></tr>
|
||||
* <tr><td>watch </td></tr>
|
||||
* <tr><td>xterm </td></tr>
|
||||
* </table>
|
||||
<div class='flex-list'>
|
||||
* <div>num_glyphs</div>
|
||||
* <div>arrow</div>
|
||||
* <div>based_arrow_down</div>
|
||||
* <div>based_arrow_up</div>
|
||||
* <div>boat</div>
|
||||
* <div>bogosity</div>
|
||||
* <div>bottom_left_corner</div>
|
||||
* <div>bottom_right_corner</div>
|
||||
* <div>bottom_side</div>
|
||||
* <div>bottom_tee</div>
|
||||
* <div>box_spiral</div>
|
||||
* <div>center_ptr</div>
|
||||
* <div>circle</div>
|
||||
* <div>clock</div>
|
||||
* <div>coffee_mug</div>
|
||||
* <div>cross</div>
|
||||
* <div>crosshair</div>
|
||||
* <div>cross_reverse</div>
|
||||
* <div>cursor</div>
|
||||
* <div>diamond_cross</div>
|
||||
* <div>dotbox</div>
|
||||
* <div>dot</div>
|
||||
* <div>double_arrow</div>
|
||||
* <div>draft_large</div>
|
||||
* <div>draft_small</div>
|
||||
* <div>draped_box</div>
|
||||
* <div>exchange</div>
|
||||
* <div>fleur</div>
|
||||
* <div>gobbler</div>
|
||||
* <div>gumby</div>
|
||||
* <div>hand</div>
|
||||
* <div>hand</div>
|
||||
* <div>heart</div>
|
||||
* <div>icon</div>
|
||||
* <div>iron_cross</div>
|
||||
* <div>leftbutton</div>
|
||||
* <div>left_ptr</div>
|
||||
* <div>left_side</div>
|
||||
* <div>left_tee</div>
|
||||
* <div>ll_angle</div>
|
||||
* <div>lr_angle</div>
|
||||
* <div>man</div>
|
||||
* <div>middlebutton</div>
|
||||
* <div>mouse</div>
|
||||
* <div>pencil</div>
|
||||
* <div>pirate</div>
|
||||
* <div>plus</div>
|
||||
* <div>question_arrow</div>
|
||||
* <div>rightbutton</div>
|
||||
* <div>right_ptr</div>
|
||||
* <div>right_side</div>
|
||||
* <div>right_tee</div>
|
||||
* <div>rtl_logo</div>
|
||||
* <div>sailboat</div>
|
||||
* <div>sb_down_arrow</div>
|
||||
* <div>sb_h_double_arrow</div>
|
||||
* <div>sb_left_arrow</div>
|
||||
* <div>sb_right_arrow</div>
|
||||
* <div>sb_up_arrow</div>
|
||||
* <div>sb_v_double_arrow</div>
|
||||
* <div>shuttle</div>
|
||||
* <div>sizing</div>
|
||||
* <div>spider</div>
|
||||
* <div>spraycan</div>
|
||||
* <div>star</div>
|
||||
* <div>target</div>
|
||||
* <div>tcross</div>
|
||||
* <div>top_left_arrow</div>
|
||||
* <div>top_left_corner</div>
|
||||
* <div>top_right_corner</div>
|
||||
* <div>top_side</div>
|
||||
* <div>top_tee</div>
|
||||
* <div>trek</div>
|
||||
* <div>ul_angle</div>
|
||||
* <div>umbrella</div>
|
||||
* <div>ur_angle</div>
|
||||
* <div>watch</div>
|
||||
* <div>xterm</div>
|
||||
* </div>
|
||||
|
|
|
@ -1,24 +1,25 @@
|
|||
--- Set a widget at a specific index, replace the current one.
|
||||
--- Set a widget at a specific index, replacing the current one.
|
||||
--
|
||||
-- @tparam number index A widget or a widget index
|
||||
-- @tparam widget widget2 The widget to take the place of the first one
|
||||
-- @treturn boolean If the operation is successful
|
||||
-- @tparam widget widget2 The widget to replace the previous one with
|
||||
-- @treturn boolean Returns `true` if the widget was replaced successfully,
|
||||
-- `false` otherwise.
|
||||
-- @method set
|
||||
-- @emits widget::replaced
|
||||
-- @emitstparam widget::replaced widget self The layout.
|
||||
-- @emitstparam widget::replaced widget widget index The inserted widget.
|
||||
-- @emitstparam widget::replaced widget widget The inserted widget.
|
||||
-- @emitstparam widget::replaced widget previous The previous widget.
|
||||
-- @emitstparam widget::replaced number index The replaced index.
|
||||
-- @interface layout
|
||||
|
||||
--- Replace the first instance of `widget` in the layout with `widget2`.
|
||||
--
|
||||
-- **Signal:** widget::replaced The argument is the new widget and the old one
|
||||
-- and the index.
|
||||
-- @tparam widget widget The widget to replace
|
||||
-- @tparam widget widget2 The widget to replace `widget` with
|
||||
-- @tparam[opt=false] boolean recursive Dig in all compatible layouts to find the widget.
|
||||
-- @treturn boolean If the operation is successful
|
||||
-- @tparam[opt=false] boolean recursive Recurse into all compatible layouts to
|
||||
-- find the widget.
|
||||
-- @treturn boolean Returns `true` if the widget was replaced successfully,
|
||||
-- `false` otherwise.
|
||||
-- @method replace_widget
|
||||
-- @emits widget::replaced
|
||||
-- @emitstparam widget::replaced widget self The layout.
|
||||
|
@ -31,35 +32,44 @@
|
|||
--
|
||||
-- @tparam number index1 The first widget index
|
||||
-- @tparam number index2 The second widget index
|
||||
-- @treturn boolean If the operation is successful
|
||||
-- @treturn boolean Returns `true` if the widget was replaced successfully,
|
||||
-- `false` otherwise.
|
||||
-- @method swap
|
||||
-- @emits widget::swapped
|
||||
-- @emitstparam widget::swapped widget self The layout.
|
||||
-- @emitstparam widget::swapped widget widget1 index The first widget.
|
||||
-- @emitstparam widget::swapped widget widget2 index The second widget.
|
||||
-- @emitstparam widget::swapped widget widget1 The first widget.
|
||||
-- @emitstparam widget::swapped widget widget2 The second widget.
|
||||
-- @emitstparam widget::swapped number index1 The first index.
|
||||
-- @emitstparam widget::swapped number index1 The second index.
|
||||
-- @interface layout
|
||||
|
||||
--- Swap 2 widgets in a layout.
|
||||
-- If widget1 is present multiple time, only the first instance is swapped
|
||||
-- **Signal:** widget::swapped The arguments are both widgets and both (new) indexes.
|
||||
-- if the layouts not the same, then only `widget::replaced` will be emitted.
|
||||
--
|
||||
-- If `widget1` is present multiple time, only the first instance is swapped.
|
||||
--
|
||||
-- Calls `set` internally, so the signal `widget::replaced` is emitted for both
|
||||
-- widgets as well.
|
||||
--
|
||||
-- @tparam widget widget1 The first widget
|
||||
-- @tparam widget widget2 The second widget
|
||||
-- @tparam[opt=false] boolean recursive Dig in all compatible layouts to find the widget.
|
||||
-- @treturn boolean If the operation is successful
|
||||
-- @tparam[opt=false] boolean recursive Recurse into all compatible layouts to
|
||||
-- find the widget.
|
||||
-- @treturn boolean Returns `true` if the widget was replaced successfully,
|
||||
-- `false` otherwise.
|
||||
-- @method swap_widgets
|
||||
-- @emits widget::swapped
|
||||
-- @emitstparam widget::swapped widget self The layout.
|
||||
-- @emitstparam widget::swapped widget widget1 index The first widget.
|
||||
-- @emitstparam widget::swapped widget widget2 index The second widget.
|
||||
-- @emitstparam widget::swapped widget widget1 The first widget.
|
||||
-- @emitstparam widget::swapped widget widget2 The second widget.
|
||||
-- @emitstparam widget::swapped number index1 The first index.
|
||||
-- @emitstparam widget::swapped number index1 The second index.
|
||||
-- @interface layout
|
||||
-- @see set
|
||||
|
||||
--- Reset a ratio layout. This removes all widgets from the layout.
|
||||
--- Reset the layout. This removes all widgets from the layout.
|
||||
-- @method reset
|
||||
-- @emits widget::reset
|
||||
-- @emitstparam widget::reset widget self The layout.
|
||||
-- @interface layout
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
--<table class='widget_list' border=1>
|
||||
-- <tr>
|
||||
-- <th align='center'>Format</th>
|
||||
-- <th align='center'>Description</th>
|
||||
-- </tr>
|
||||
-- <tr><td>%a</td><td>The abbreviated weekday name according to the current locale</td></tr>
|
||||
-- <tr><td>%A</td><td>the full weekday name according to the current locale</td></tr>
|
||||
-- <tr><td>%b</td><td>The abbreviated month name according to the current locale</td></tr>
|
||||
-- <tr><td>%B</td><td>The full month name according to the current locale</td></tr>
|
||||
-- <tr><td>%d</td><td>The day of the month as a decimal number (range 01 to 31)</td></tr>
|
||||
-- <tr><td>%e</td><td>The day of the month as a decimal number (range 1 to 31)</td></tr>
|
||||
-- <tr><td>%F</td><td>Equivalent to %Y-%m-%d (the ISO 8601 date format)</td></tr>
|
||||
-- <tr><td>%H</td><td>The hour as a decimal number using a 24-hour clock (range 00 to 23)</td></tr>
|
||||
-- <tr><td>%I</td><td>The hour as a decimal number using a 12-hour clock (range 01 to 12)</td></tr>
|
||||
-- <tr><td>%k</td><td>The hour (24-hour clock) as a decimal number (range 0 to 23); single digits are preceded by a blank</td></tr>
|
||||
-- <tr><td>%l</td><td>The hour (12-hour clock) as a decimal number (range 1 to 12); single digits are preceded by a blank</td></tr>
|
||||
-- <tr><td>%m</td><td>The month as a decimal number (range 01 to 12)</td></tr>
|
||||
-- <tr><td>%M</td><td>The minute as a decimal number (range 00 to 59)</td></tr>
|
||||
-- <tr><td>%p</td><td>Either "AM" or "PM" according to the given time value, or the corresponding strings for the current locale. Noon is treated as "PM" and midnight as "AM".</td></tr>
|
||||
-- <tr><td>%P</td><td>Like %p but lowercase: "am" or "pm" or a corresponding string for the current locale</td></tr>
|
||||
-- <tr><td>%r</td><td>The time in a.m. or p.m. notation</td></tr>
|
||||
-- <tr><td>%R</td><td>The time in 24-hour notation (%H:%M)</td></tr>
|
||||
-- <tr><td>%S</td><td>The second as a decimal number (range 00 to 60)</td></tr>
|
||||
-- <tr><td>%T</td><td>The time in 24-hour notation with seconds (%H:%M:%S)</td></tr>
|
||||
-- <tr><td>%y</td><td>The year as a decimal number without the century</td></tr>
|
||||
-- <tr><td>%Y</td><td>The year as a decimal number including the century</td></tr>
|
||||
-- <tr><td>%%</td><td>A literal % character</td></tr>
|
||||
-- </table>
|
|
@ -37,16 +37,16 @@ should be useful for you.
|
|||
|
||||
<div class="index_guides">
|
||||
<div>
|
||||
<a href="../doc/documentation/07-my-first-awesome.md.html">Getting started</a>
|
||||
<a href="../doc/documentation/90-FAQ.md.html">FAQ</a>
|
||||
<a href="../doc/documentation/01-readme.md.html">Read me</a>
|
||||
<a href="../doc/documentation/89-NEWS.md.html">NEWS</a>
|
||||
@{07-my-first-awesome.md|Getting started}
|
||||
@{90-FAQ.md|FAQ}
|
||||
@{01-readme.md|Read Me}
|
||||
@{89-NEWS.md|NEWS}
|
||||
</div>
|
||||
<div>
|
||||
<a href="../doc/documentation/03-declarative-layout.md.html">The widget system</a>
|
||||
<a href="../doc/documentation/09-options.md.html">Startup options</a>
|
||||
<a href="../doc/documentation/05-awesomerc.md.html">The default rc.lua</a>
|
||||
<a href="../doc/documentation/08-client-layout-system.md.html">Window management</a>
|
||||
@{03-declarative-layout.md|The widget system}
|
||||
@{09-options.md|Startup options}
|
||||
@{05-awesomerc.md|The default rc.lua}
|
||||
@{08-client-layout-system.md|Window management}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -456,6 +456,25 @@ add_custom_tag {
|
|||
},
|
||||
}
|
||||
|
||||
-- Define the supermodule class.
|
||||
-- This tag should be used at the module level. All properties from the
|
||||
-- supermodule will be recursively added to the module by our ldoc template.
|
||||
-- @supermodule supermodule
|
||||
add_custom_tag {
|
||||
name = "supermodule",
|
||||
hidden = true,
|
||||
auto_subtags = false
|
||||
}
|
||||
|
||||
-- Mark the item ad hidden.
|
||||
-- This tag should be used to hide items from the documentation.
|
||||
-- @hidden
|
||||
add_custom_tag {
|
||||
name = "hidden",
|
||||
hidden = true,
|
||||
auto_subtags = false
|
||||
}
|
||||
|
||||
-- More fitting section names
|
||||
kind_names={topic='Documentation', module='Libraries', script='Sample files'}
|
||||
|
||||
|
|
|
@ -257,6 +257,23 @@ table th, table td {
|
|||
border-bottom-width: 1px;
|
||||
}
|
||||
|
||||
.flex-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.flex-list > div {
|
||||
flex-grow: 1;
|
||||
/* Use base width based on font size
|
||||
to make sure text fits when zooming */
|
||||
width: 9em;
|
||||
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
margin: 5px;
|
||||
border: 1px solid rgb(193, 204, 228);
|
||||
}
|
||||
|
||||
#about {
|
||||
padding: 15px;
|
||||
padding-left: 16em;
|
||||
|
@ -503,3 +520,32 @@ pre .url { color: #272fc2; text-decoration: underline; }
|
|||
.index_guides div a:hover {
|
||||
background-color: #99b3ec;
|
||||
}
|
||||
|
||||
/* Inheritance diagram */
|
||||
.inheritance .inheritance__level {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.inheritance .inheritance__level--root {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.inheritance .inheritance__level__node::before {
|
||||
content: "↳";
|
||||
}
|
||||
|
||||
.inheritance .inheritance__level__node--root::before {
|
||||
/* simulate the spacing of the arrow character */
|
||||
content: " ";
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.extra-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.extra-header__section {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
|
185
docs/ldoc.ltp
185
docs/ldoc.ltp
|
@ -38,11 +38,86 @@
|
|||
# local use_li = ldoc.use_li
|
||||
# local display_name = ldoc.display_name
|
||||
# local iter = ldoc.modules.iter
|
||||
# local function M(txt,item) return ldoc.markup(txt,item,ldoc.plain) end
|
||||
# local function un_cmake(s) return s:gsub(";", ";"):gsub(""", '"') end
|
||||
# local function M(txt,item) return ldoc.markup(txt and un_cmake(txt) or nil,item,ldoc.plain) end
|
||||
# local nowrap = ldoc.wrap and '' or 'nowrap'
|
||||
# local html_space = function(s) return s:gsub(" ", "%%20") end
|
||||
# local no_underscores = function(s) return s:gsub("_", " ") end
|
||||
|
||||
# --------- modules hierarchy -------------
|
||||
# local hierarchy = {}
|
||||
# local curr = module
|
||||
# while curr do
|
||||
# hierarchy[#hierarchy + 1] = curr
|
||||
# -- no need to do anything more if there is no explicite @supermodule
|
||||
# if not curr.tags.supermodule then break end
|
||||
# local super = curr.tags.supermodule[1] -- only consider one way inheritance
|
||||
# local found = false
|
||||
# for kind, mods, type in ldoc.kinds() do
|
||||
# for mod in mods() do
|
||||
# local name = display_name(mod)
|
||||
# if name == super then
|
||||
# curr = mod
|
||||
# found = true
|
||||
# end
|
||||
# if found then break end
|
||||
# end
|
||||
# if found then break end
|
||||
# end
|
||||
# if not found then curr = nil end
|
||||
# end
|
||||
|
||||
# --------- merge modules content with supermodules -------------
|
||||
# local all_module_kinds = {}
|
||||
# if module then
|
||||
# for kind,items in module.kinds() do
|
||||
# local myitems = {}
|
||||
# for item in items() do
|
||||
# myitems[#myitems + 1] = item
|
||||
# end
|
||||
# all_module_kinds[#all_module_kinds + 1] = { kind = kind, items = myitems }
|
||||
# end
|
||||
# local filtered_kinds = { "Constructors", "Static module functions",
|
||||
# "Functions", "Methods", "lib.gears.object.properties Functions" }
|
||||
# for supermodule in iter(hierarchy) do
|
||||
# for kind,items in supermodule.kinds() do
|
||||
# local ignored = false
|
||||
# for _,filtered in ldoc.pairs(filtered_kinds) do
|
||||
# if kind == filtered then
|
||||
# ignored = true
|
||||
# break
|
||||
# end
|
||||
# end
|
||||
# if not ignored then
|
||||
# local curr_kind = nil
|
||||
# for k in iter(all_module_kinds) do
|
||||
# if k.kind == kind then
|
||||
# curr_kind = k
|
||||
# break
|
||||
# end
|
||||
# end
|
||||
# if not curr_kind then
|
||||
# curr_kind = { kind = kind, items = {} }
|
||||
# all_module_kinds[#all_module_kinds + 1] = curr_kind
|
||||
# end
|
||||
# for item in items() do
|
||||
# local tobeadded = true
|
||||
# for i in iter(curr_kind.items) do
|
||||
# if item.name == i.name then
|
||||
# tobeadded = false
|
||||
# break
|
||||
# end
|
||||
# end
|
||||
# if tobeadded then
|
||||
# item.inherited = true -- force inherited status
|
||||
# curr_kind.items[#curr_kind.items + 1] = item
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
|
||||
<!-- Menu -->
|
||||
|
||||
<div id="navigation">
|
||||
|
@ -59,7 +134,8 @@
|
|||
# if module and not ldoc.no_summary and #module.items > 0 then
|
||||
<h2>Contents</h2>
|
||||
<ul>
|
||||
# for kind,items in module.kinds() do
|
||||
# for k in iter(all_module_kinds) do
|
||||
# local kind = k.kind
|
||||
# if not kind:match("^ldoc_skip") then
|
||||
<li><a href="#$(no_spaces(kind))">$(kind)</a></li>
|
||||
# end
|
||||
|
@ -109,41 +185,90 @@
|
|||
<h1>Module: <code>$(module.name)</code></h1>
|
||||
<p>$(M(module.summary,module))</p>
|
||||
<p>$(M(module.description,module))</p>
|
||||
# if module.tags.include then
|
||||
$(M(ldoc.include_file(module.tags.include)))
|
||||
# end
|
||||
# if module.see then
|
||||
# local li,il = use_li(module.see)
|
||||
<h3>See also:</h3>
|
||||
<ul>
|
||||
# for see in iter(module.see) do
|
||||
$(li)<a href="$(ldoc.href(see))">$(see.label)</a>$(il)
|
||||
# end -- for
|
||||
</ul>
|
||||
# end -- if see
|
||||
# if module.usage then
|
||||
# local li,il = use_li(module.usage)
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
# for usage in iter(module.usage) do
|
||||
$(li)<pre class="example">$(ldoc.escape(usage))</pre>$(il)
|
||||
$(li)<pre class="example">$(ldoc.escape(un_cmake(usage)))</pre>$(il)
|
||||
# end -- for
|
||||
</ul>
|
||||
# end -- if usage
|
||||
<div class="extra-header">
|
||||
# if module.tags.supermodule then
|
||||
<div class="extra-header__section">
|
||||
<h3>Class Hierarchy</h3>
|
||||
<div class="inheritance">
|
||||
# local function draw_hierary_recursifly(i)
|
||||
# local is_root_level = (i == #hierarchy)
|
||||
<ul class="inheritance__level $(is_root_level and 'inheritance__level--root' or '')">
|
||||
<li class="inheritance__level__node $(is_root_level and 'inheritance__level__node--root' or '')">
|
||||
# local mod = hierarchy[i]
|
||||
# local name = display_name(hierarchy[i])
|
||||
# if mod == module then
|
||||
<strong>$(name)</strong>
|
||||
# else
|
||||
<a href="$(ldoc.ref_to_module(mod))">$(name)</a>
|
||||
# end
|
||||
</li>
|
||||
# if i > 1 then
|
||||
<li>
|
||||
# draw_hierary_recursifly(i - 1)
|
||||
</li>
|
||||
# end
|
||||
</ul>
|
||||
# end -- function draw_hierary_recursifly
|
||||
# draw_hierary_recursifly(#hierarchy)
|
||||
</div>
|
||||
</div>
|
||||
# end -- module.tags.supermodule
|
||||
|
||||
# if module.tags.include then
|
||||
$(M(ldoc.include_file(module.tags.include)))
|
||||
# end
|
||||
|
||||
# if module.info then
|
||||
<div class="extra-header__section">
|
||||
<h3>Info:</h3>
|
||||
<ul>
|
||||
# for tag, value in module.info:iter() do
|
||||
<li><strong>$(tag)</strong>: $(M(value,module))</li>
|
||||
# if tag == 'Author' then
|
||||
<li>
|
||||
<strong>Originally authored by</strong>: $(M(value,module))<br />
|
||||
<small>(Full contributors list available on
|
||||
<a href="https://github.com/awesomeWM/awesome/graphs/contributors">
|
||||
our github project)
|
||||
</a></small>
|
||||
|
||||
</li>
|
||||
# else
|
||||
<li><strong>$(tag)</strong>: $(M(value,module))</li>
|
||||
# end
|
||||
# end
|
||||
</ul>
|
||||
</div>
|
||||
# end -- if module.info
|
||||
|
||||
# if module.see then
|
||||
<div class="extra-header__section">
|
||||
# local li,il = use_li(module.see)
|
||||
# local list_or_p =(#module.see > 1) and 'ul' or 'p'
|
||||
<h3>See also:</h3>
|
||||
<$(list_or_p)>
|
||||
# for see in iter(module.see) do
|
||||
$(li)<a href="$(ldoc.href(see))">$(see.label)</a>$(il)
|
||||
# end -- for
|
||||
</$(list_or_p)>
|
||||
</div>
|
||||
# end -- if module.see
|
||||
</div>
|
||||
|
||||
|
||||
# if not ldoc.no_summary then
|
||||
# -- bang out the tables of item types for this module (e.g Functions, Tables, etc)
|
||||
# local last_kind = ""
|
||||
# for kind,items in module.kinds() do
|
||||
# for k in iter(all_module_kinds) do
|
||||
# local kind = k.kind
|
||||
# if not kind:match("^ldoc_skip") then
|
||||
# if last_kind ~= "" then
|
||||
</table>
|
||||
|
@ -151,8 +276,9 @@
|
|||
<h2><a href="#$(no_spaces(kind))">$(kind)</a></h2>
|
||||
<table class="function_list">
|
||||
# end
|
||||
# for item in items() do
|
||||
# for item in iter(k.items) do if not item.tags.hidden then
|
||||
# local dn = display_name(item)
|
||||
# local inherited = (item.baseclass ~= module.name)
|
||||
# if item.sanitize_type then item.sanitize_type(item, ldoc) end
|
||||
<tr>
|
||||
# if item.display_type and not item.compact_signature then
|
||||
|
@ -166,14 +292,14 @@
|
|||
# end
|
||||
</td>
|
||||
# end
|
||||
<td colspan="$(item.inherited and 1 or 2)" class="summary">$(M(item.summary,item))</td>
|
||||
# if item.inherited then
|
||||
<td class="baseclass" $(nowrap)>
|
||||
<td colspan="$(inherited and 1 or 2)" class="summary">$(M(item.summary,item))</td>
|
||||
# if inherited then
|
||||
<td class="baseclass" nowrap>
|
||||
Inherited from $(item.baseclass)
|
||||
</td>
|
||||
# end
|
||||
</tr>
|
||||
# end -- for items
|
||||
# end end -- for items
|
||||
# last_kind = kind
|
||||
#end -- for kinds
|
||||
</table>
|
||||
|
@ -187,7 +313,8 @@
|
|||
# --- function parameters or table fields.
|
||||
# local show_return = not ldoc.no_return_or_parms
|
||||
# local show_parms, last_kind = show_return, ""
|
||||
# for kind, items in module.kinds() do
|
||||
# for k in iter(all_module_kinds) do
|
||||
# local kind = k.kind
|
||||
# local kitem = module.kinds:get_item(kind)
|
||||
# local has_description = kitem and ldoc.descript(kitem) ~= ""
|
||||
# if not kind:match("^ldoc_skip") then
|
||||
|
@ -205,13 +332,13 @@
|
|||
# end
|
||||
# if kitem.usage then
|
||||
<h3>Usage:</h3>
|
||||
<pre class="example">$(ldoc.prettify(kitem.usage[1]))</pre>
|
||||
<pre class="example">$(ldoc.prettify(un_cmake(kitem.usage[1])))</pre>
|
||||
# end
|
||||
# end
|
||||
# if not kind:match("^ldoc_skip") then
|
||||
<dl class="function">
|
||||
# end
|
||||
# for item in items() do
|
||||
# for item in iter(k.items) do if not item.tags.hidden then
|
||||
<dt>
|
||||
<a name = "$(item.name)"></a>
|
||||
<strong>$(display_name(item))</strong>
|
||||
|
@ -225,8 +352,8 @@
|
|||
<span class="proptype">$(item.display_type)</span>
|
||||
# end
|
||||
<span class="baseclass" $(nowrap)>
|
||||
# if item.inherited then
|
||||
· Inherited from $(item.baseclass)
|
||||
# if item.baseclass ~= module.name then
|
||||
· Inherited from $(M(item.baseclass, item))
|
||||
# end
|
||||
# if item.extra_summary then
|
||||
# for _, col in ldoc.ipairs(item.extra_summary) do
|
||||
|
@ -324,7 +451,7 @@
|
|||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
# for usage in iter(item.usage) do
|
||||
$(li)<pre class="example">$(ldoc.prettify(usage))</pre>$(il)
|
||||
$(li)<pre class="example">$(ldoc.prettify(un_cmake(usage)))</pre>$(il)
|
||||
# end -- for
|
||||
</ul>
|
||||
# end -- if usage
|
||||
|
@ -371,7 +498,7 @@
|
|||
</span>
|
||||
|
||||
</dd>
|
||||
# end -- for items
|
||||
# end end -- for items
|
||||
# last_kind = kind
|
||||
# end -- for kinds
|
||||
</dl>
|
||||
|
|
2
ewmh.c
2
ewmh.c
|
@ -468,7 +468,7 @@ ewmh_process_client_message(xcb_client_message_event_t *ev)
|
|||
lua_State *L = globalconf_get_lua_State();
|
||||
luaA_object_push(L, globalconf.tags.tab[idx]);
|
||||
lua_pushstring(L, "ewmh");
|
||||
luaA_object_emit_signal(L, -1, "request::select", 1);
|
||||
luaA_object_emit_signal(L, -2, "request::select", 1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,28 @@ do
|
|||
assert(root.object == root_object)
|
||||
end
|
||||
|
||||
--- The old wallpaper only took native surfaces.
|
||||
--
|
||||
-- This was a problem for the test backend. The new function takes both
|
||||
-- native surfaces and LGI-ified Cairo surfaces.
|
||||
function root.wallpaper(pattern)
|
||||
if not pattern then return root._wallpaper() end
|
||||
|
||||
-- Checking for type will either potentially `error()` or always
|
||||
-- return `userdata`. This check will error() when the surface is
|
||||
-- already native.
|
||||
local err = pcall(function() return pattern._native end)
|
||||
|
||||
-- The presence of `root._write_string` means the test backend is
|
||||
-- used. Avoid passing the native surface.
|
||||
if err and not root._write_string then
|
||||
return root._wallpaper(pattern._native)
|
||||
else
|
||||
return root._wallpaper(pattern)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- root.bottons() used to be a capi function. However this proved confusing
|
||||
-- as rc.lua used `awful.button` and `root.buttons()` used capi.button. There
|
||||
-- was a little documented hack to "flatten" awful.button into a pair of
|
||||
|
|
|
@ -595,18 +595,42 @@ function client.object.move_to_screen(self, s)
|
|||
end
|
||||
end
|
||||
|
||||
--- Tag a client with the set of current tags.
|
||||
--- Find suitable tags for newly created clients.
|
||||
--
|
||||
-- In most cases, the functionality you're actually looking for as a user will
|
||||
-- either be
|
||||
--
|
||||
-- c:tags(c.screen.selected_tags)
|
||||
--
|
||||
-- or
|
||||
--
|
||||
-- local s = awful.screen.focused()
|
||||
-- c:move_to_screen(s)
|
||||
-- c:tags(s.selected_tags)
|
||||
--
|
||||
-- Despite its naming, this is primarily used to tag newly created clients.
|
||||
-- As such, this method has no effect when applied to a client that already has
|
||||
-- tags assigned (except for emitting `property::tag`).
|
||||
--
|
||||
-- Additionally, while it is a rare case, if the client's screen has no selected
|
||||
-- tags at the point of calling this method, it will fall back to the screen's
|
||||
-- full set of tags.
|
||||
--
|
||||
-- @method to_selected_tags
|
||||
-- @see screen.selected_tags
|
||||
function client.object.to_selected_tags(self)
|
||||
local tags = {}
|
||||
|
||||
-- From the client's current tags, find the ones that
|
||||
-- belong to the client's screen
|
||||
for _, t in ipairs(self:tags()) do
|
||||
if get_screen(t.screen) == get_screen(self.screen) then
|
||||
table.insert(tags, t)
|
||||
end
|
||||
end
|
||||
|
||||
-- If no tags were found,
|
||||
-- choose the screen's selected tags, if any, or all of the screens tags
|
||||
if self.screen then
|
||||
if #tags == 0 then
|
||||
tags = self.screen.selected_tags
|
||||
|
@ -617,6 +641,7 @@ function client.object.to_selected_tags(self)
|
|||
end
|
||||
end
|
||||
|
||||
-- Prevent clients from becoming untagged
|
||||
if #tags ~= 0 then
|
||||
self:tags(tags)
|
||||
end
|
||||
|
@ -1134,10 +1159,13 @@ end
|
|||
|
||||
--- Change window factor of a client.
|
||||
--
|
||||
-- This will emit `property::windowfact` on the specific tag object
|
||||
-- `c.screen.selected_tag`.
|
||||
--
|
||||
-- @legacylayout awful.client.incwfact
|
||||
-- @tparam number add Amount to increase/decrease the client's window factor.
|
||||
-- @tparam number add Amount to increase/decrease the client's window factor by.
|
||||
-- Should be between `-current_window_factor` and something close to
|
||||
-- infinite. The normalisation then ensures that the sum of all factors is 1.
|
||||
-- infinite. Normalisation then ensures that the sum of all factors is 1.
|
||||
-- @tparam client c the client.
|
||||
-- @emits property::windowfact
|
||||
function client.incwfact(add, c)
|
||||
|
|
|
@ -196,7 +196,7 @@ function focus.global_bydirection(dir, c, stacked)
|
|||
local scr = get_screen(sel and sel.screen or screen.focused())
|
||||
|
||||
-- change focus inside the screen
|
||||
focus.bydirection(dir, sel)
|
||||
focus.bydirection(dir, sel, stacked)
|
||||
|
||||
-- if focus not changed, we must change screen
|
||||
if sel == capi.client.focus then
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---------------------------------------------------------------------------
|
||||
--- D-Bus module for awful.
|
||||
--
|
||||
-- This module simply request the org.awesomewm.awful name on the D-Bus
|
||||
-- for futur usage by other awful modules.
|
||||
-- This module simply requests the org.awesomewm.awful name on the D-Bus
|
||||
-- for future usage by other awful modules.
|
||||
--
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
|
|
|
@ -438,7 +438,10 @@ function widget.new(args)
|
|||
end
|
||||
|
||||
function widget_instance:_create_group_columns(column_layouts, group, keys, s, wibox_height)
|
||||
local line_height = beautiful.get_font_height(self.font)
|
||||
local line_height = math.max(
|
||||
beautiful.get_font_height(self.font),
|
||||
beautiful.get_font_height(self.description_font)
|
||||
)
|
||||
local group_label_height = line_height + self.group_margin
|
||||
-- -1 for possible pagination:
|
||||
local max_height_px = wibox_height - group_label_height
|
||||
|
@ -472,7 +475,7 @@ function widget.new(args)
|
|||
table.insert(((i<available_height_items) and new_keys or overlap_leftovers), keys[i])
|
||||
end
|
||||
keys = new_keys
|
||||
table.insert(keys, {key=markup.fg(self.modifiers_fg, "▽"), description=""})
|
||||
table.insert(keys, {key="▽", description=""})
|
||||
end
|
||||
if not current_column then
|
||||
current_column = {layout=wibox.layout.fixed.vertical()}
|
||||
|
@ -481,32 +484,39 @@ function widget.new(args)
|
|||
|
||||
local function insert_keys(_keys, _add_new_column)
|
||||
local max_label_width = 0
|
||||
local max_label_content = ""
|
||||
local joined_labels = ""
|
||||
for i, key in ipairs(_keys) do
|
||||
local length = string.len(key.key or '') + string.len(key.description or '')
|
||||
local modifiers = key.mod
|
||||
if not modifiers or modifiers == "none" then
|
||||
modifiers = ""
|
||||
else
|
||||
length = length + string.len(modifiers) + 1 -- +1 for "+" character
|
||||
modifiers = markup.fg(self.modifiers_fg, modifiers.."+")
|
||||
end
|
||||
local key_label = ""
|
||||
if key.keylist and #key.keylist > 1 then
|
||||
for each_key_idx, each_key in ipairs(key.keylist) do
|
||||
key_label = key_label .. gstring.xml_escape(each_key)
|
||||
if each_key_idx ~= #key.keylist then
|
||||
key_label = key_label .. markup.fg(self.modifiers_fg, '/')
|
||||
end
|
||||
end
|
||||
elseif key.key then
|
||||
key_label = gstring.xml_escape(key.key)
|
||||
end
|
||||
local rendered_hotkey = markup.font(self.font,
|
||||
modifiers .. (key.key or "") .. " "
|
||||
modifiers .. key_label .. " "
|
||||
) .. markup.font(self.description_font,
|
||||
key.description or ""
|
||||
)
|
||||
if length > max_label_width then
|
||||
max_label_width = length
|
||||
max_label_content = rendered_hotkey
|
||||
local label_width = wibox.widget.textbox.get_markup_geometry(rendered_hotkey, s).width
|
||||
if label_width > max_label_width then
|
||||
max_label_width = label_width
|
||||
end
|
||||
joined_labels = joined_labels .. rendered_hotkey .. (i~=#_keys and "\n" or "")
|
||||
end
|
||||
current_column.layout:add(wibox.widget.textbox(joined_labels))
|
||||
local max_width, _ = wibox.widget.textbox(max_label_content):get_preferred_size(s)
|
||||
max_width = max_width + self.group_margin
|
||||
if not current_column.max_width or max_width > current_column.max_width then
|
||||
local max_width = max_label_width + self.group_margin
|
||||
if not current_column.max_width or (max_width > current_column.max_width) then
|
||||
current_column.max_width = max_width
|
||||
end
|
||||
-- +1 for group label:
|
||||
|
|
|
@ -35,6 +35,7 @@ local ret = {
|
|||
tooltip = require("awful.tooltip");
|
||||
permissions = require("awful.permissions");
|
||||
titlebar = require("awful.titlebar");
|
||||
wallpaper = require("awful.wallpaper");
|
||||
rules = require("awful.rules");
|
||||
popup = require("awful.popup");
|
||||
spawn = require("awful.spawn");
|
||||
|
|
|
@ -1,6 +1,27 @@
|
|||
---------------------------------------------------------------------------
|
||||
--- Create easily new key objects ignoring certain modifiers.
|
||||
--
|
||||
-- A key object can be used by @{awful.keyboard} and @{client} to define
|
||||
-- keybindings.
|
||||
--
|
||||
-- Use awful.key to define a keybinding
|
||||
-- ---
|
||||
--
|
||||
-- This example shows how to define a basic key object:
|
||||
--
|
||||
-- @DOC_text_awful_key_constructor_default_EXAMPLE@
|
||||
--
|
||||
-- This example shows how to define the same basic key object with the
|
||||
-- declarative pattern:
|
||||
--
|
||||
-- @DOC_text_awful_key_constructor_declarative_EXAMPLE@
|
||||
--
|
||||
-- This second example of a key definition uses the numrow keygroup. In this
|
||||
-- example, we define a key object, that select the tag to show according to
|
||||
-- the key index from the numrow.
|
||||
--
|
||||
-- @DOC_text_awful_key_constructor_keygroup_EXAMPLE@
|
||||
--
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @author Emmanuel Lepage Vallee <elv1313@gmail.com>
|
||||
-- @copyright 2018 Emmanuel Lepage Vallee
|
||||
|
@ -24,21 +45,6 @@ local gobject = require("gears.object")
|
|||
-- @property key
|
||||
-- @param string
|
||||
|
||||
--- A group of keys.
|
||||
--
|
||||
-- The valid keygroups are:
|
||||
--
|
||||
-- * **numrow**: The row above the letters in the US PC-105/PC-104 keyboards
|
||||
-- and its derivative. This is usually the number 1-9 followed by 0.
|
||||
-- * **arrows**: The Left/Right/Top/Bottom keys usually located right of the
|
||||
-- spacebar.
|
||||
-- * **fkeys**: The keys F1 through F12 located at the topmost row of any
|
||||
-- keyboard, plus F13 through F35 on specialist keyboards.
|
||||
-- * **numpad**: The number keys on the keypad to the right of the letters and
|
||||
-- the arrow keys. Not present in every keyboard.
|
||||
--
|
||||
-- @property keygroup
|
||||
|
||||
--- The table of modifier keys.
|
||||
--
|
||||
-- A modifier, such as `Control` are a predetermined set of keys that can be
|
||||
|
@ -99,6 +105,32 @@ local key = { mt = {}, hotkeys = {} }
|
|||
|
||||
local reverse_map = setmetatable({}, {__mode="k"})
|
||||
|
||||
--- The keygroups names.
|
||||
--
|
||||
-- It can be used instead of keygroup names.
|
||||
--
|
||||
-- Values associated to each property of this table are string:
|
||||
--
|
||||
-- - **NUMROW** = `"numrow"`: The row above the letters in the US PC-105/PC-104 keyboards and
|
||||
-- its derivative. This is usually the number 1-9 followed by 0.
|
||||
--
|
||||
-- - **ARROWS** = `"arrows"`: The Left/Right/Top/Bottom keys usually located right of the
|
||||
-- spacebar.
|
||||
--
|
||||
-- - **FKEYS** = `"fkeys"`: The keys F1 through F12 located at the topmost row of any
|
||||
-- keyboard, plus F13 through F35 on specialist keyboards.
|
||||
--
|
||||
-- - **NUMPAD** = `"numpad"`: The number keys on the keypad to the right of the letters and
|
||||
-- the arrow keys. Not present in every keyboard.
|
||||
--
|
||||
-- @table keygroup
|
||||
key.keygroup = {
|
||||
NUMROW = 'numrow', -- The number row.
|
||||
ARROWS = 'arrows', -- The directionnal arrows.
|
||||
FKEYS = 'fkeys', -- The function keys.
|
||||
NUMPAD = 'numpad', -- The numpad keys.
|
||||
}
|
||||
|
||||
function key:set_key(k)
|
||||
for _, v in ipairs(self) do
|
||||
v.key = k
|
||||
|
@ -216,11 +248,13 @@ end
|
|||
--
|
||||
-- @constructorfct2 awful.key
|
||||
-- @tparam table args
|
||||
-- @tparam function args.key The key to trigger an event. It can be the character
|
||||
-- itself of `#+keycode` (**mandatory**).
|
||||
-- @tparam function args.modifiers A list of modifier keys. Valid modifiers are:
|
||||
-- `Any`, `Mod1`, Mod2`, `Mod3`, `Mod4`, `Mod5`, `Shift`, `Lock` and `Control`.
|
||||
-- This argument is (**mandatory**).
|
||||
-- @tparam string args.key The key to trigger an event. It can be the character
|
||||
-- itself of `#+keycode`.
|
||||
-- @tparam[opt] string args.keygroup The keygroup to trigger an event. This
|
||||
-- parameter must be used as a replacement for the `key` parameter. See
|
||||
-- @{awful.key.keygroup}.
|
||||
-- @tparam table args.modifiers A list of modifier keys. Valid modifiers are:
|
||||
-- `Any`, `Mod1`, Mod2`, `Mod3`, `Mod4`, `Mod5`, `Shift`, `Lock` and `Control`.
|
||||
-- @tparam function args.on_press Callback for when the key is pressed.
|
||||
-- @tparam function args.on_release Callback for when the key is released.
|
||||
|
||||
|
|
|
@ -474,12 +474,20 @@ function keygrabber:start()
|
|||
end
|
||||
|
||||
--- Stop the keygrabber.
|
||||
--
|
||||
-- Also stops any `timeout`.
|
||||
--
|
||||
-- @method stop
|
||||
-- @emits stopped
|
||||
-- @emits property::current_instance
|
||||
function keygrabber:stop(_stop_key, _stop_mods) -- (at)function disables ldoc params
|
||||
keygrab.stop(self.grabber)
|
||||
|
||||
local timer = self._private.timer
|
||||
if timer and timer.started then
|
||||
timer:stop()
|
||||
end
|
||||
|
||||
if self.stop_callback then
|
||||
self.stop_callback(
|
||||
self.current_instance, _stop_key, _stop_mods, self.sequence
|
||||
|
@ -706,12 +714,13 @@ function keygrab.run_with_keybindings(args)
|
|||
else
|
||||
gdebug.print_warning(
|
||||
"The hook's 3rd parameter has to be a function. " ..
|
||||
gdebug.dump(v or {})
|
||||
gdebug.dump_return(v or {})
|
||||
)
|
||||
end
|
||||
else
|
||||
gdebug.print_warning(
|
||||
"The keybindings should be awful.key objects".. gdebug.dump(v or {})
|
||||
"The keybindings should be awful.key objects" ..
|
||||
gdebug.dump_return(v or {})
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -35,28 +35,29 @@ mouse.wibox = {}
|
|||
--
|
||||
-- @DOC_screen_client_snap_EXAMPLE@
|
||||
--
|
||||
-- @tfield integer awful.mouse.snap.default_distance
|
||||
-- @tfield integer snap.default_distance
|
||||
-- @tparam[opt=8] integer default_distance
|
||||
-- @see awful.mouse.snap
|
||||
|
||||
--- The default distance before activating screen edge snap.
|
||||
-- @tfield integer awful.mouse.snap.aerosnap_distance
|
||||
-- @tparam[opt=16] integer default_distance
|
||||
-- @tfield integer snap.aerosnap_distance
|
||||
-- @tparam[opt=16] integer aerosnap_distance
|
||||
-- @see awful.mouse.snap
|
||||
|
||||
--- Enable screen edges snapping.
|
||||
--
|
||||
--
|
||||
--
|
||||
--@DOC_awful_placement_aero_snap_EXAMPLE@
|
||||
--
|
||||
-- @tfield[opt=true] boolean awful.mouse.snap.edge_enabled
|
||||
-- @tfield[opt=true] boolean snap.edge_enabled
|
||||
-- @tparam boolean edge_enabled
|
||||
|
||||
--- Enable client to client snapping.
|
||||
-- @tfield[opt=true] boolean awful.mouse.snap.client_enabled
|
||||
-- @tfield[opt=true] boolean snap.client_enabled
|
||||
-- @tparam boolean client_enabled
|
||||
|
||||
--- Enable changing tag when a client is dragged to the edge of the screen.
|
||||
-- @tfield[opt=false] integer awful.mouse.drag_to_tag.enabled
|
||||
-- @tfield[opt=false] boolean drag_to_tag.enabled
|
||||
-- @tparam boolean enabled
|
||||
|
||||
--- The snap outline background color.
|
||||
-- @beautiful beautiful.snap_bg
|
||||
|
@ -341,9 +342,9 @@ function mouse.remove_client_mousebinding(button)
|
|||
return false
|
||||
end
|
||||
|
||||
for _, b in ipairs {"left", "right", "middle"} do
|
||||
for k, b in ipairs {"left", "middle", "right"} do
|
||||
mouse.object["is_".. b .."_mouse_button_pressed"] = function()
|
||||
return capi.mouse.coords().buttons[1]
|
||||
return capi.mouse.coords().buttons[k]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -367,6 +368,10 @@ end)
|
|||
capi.mouse.set_index_miss_handler(function(_,key)
|
||||
if mouse.object["get_"..key] then
|
||||
return mouse.object["get_"..key]()
|
||||
elseif mouse.object[key] and key:sub(1, 3) == "is_" then
|
||||
return mouse.object[key]()
|
||||
elseif mouse.object[key] then
|
||||
return mouse.object[key]
|
||||
else
|
||||
return props[key]
|
||||
end
|
||||
|
|
|
@ -184,6 +184,10 @@ local function compose(...)
|
|||
attach(d, ret, args)
|
||||
end
|
||||
|
||||
-- Cleanup the override because otherwise it might leak into
|
||||
-- future calls.
|
||||
rawset(args, "override_geometry", nil)
|
||||
|
||||
return last_geo, rets
|
||||
end, "compose")
|
||||
|
||||
|
@ -276,6 +280,30 @@ local outer_positions = {
|
|||
bottom_middle = function(r, w, _) return {x=r.x-w/2+r.width/2, y=r.y }, "middle" end,
|
||||
}
|
||||
|
||||
-- Map the opposite side for a string
|
||||
local opposites = {
|
||||
top = "bottom",
|
||||
bottom = "top",
|
||||
left = "right",
|
||||
right = "left",
|
||||
width = "height",
|
||||
height = "width",
|
||||
x = "y",
|
||||
y = "x",
|
||||
}
|
||||
|
||||
-- List reletvant sides for each orientation.
|
||||
local struts_orientation_to_sides = {
|
||||
horizontal = { "top" , "bottom" },
|
||||
vertical = { "left", "right" }
|
||||
}
|
||||
|
||||
-- Map orientation to the length components (width/height).
|
||||
local orientation_to_length = {
|
||||
horizontal = "width",
|
||||
vertical = "height"
|
||||
}
|
||||
|
||||
--- Add a context to the arguments.
|
||||
-- This function extend the argument table. The context is used by some
|
||||
-- internal helper methods. If there already is a context, it has priority and
|
||||
|
@ -477,8 +505,8 @@ wibox_update_strut = function(d, position, args)
|
|||
end
|
||||
|
||||
-- Detect horizontal or vertical drawables
|
||||
local geo = area_common(d)
|
||||
local vertical = geo.width < geo.height
|
||||
local geo = area_common(d)
|
||||
local orientation = geo.width < geo.height and "vertical" or "horizontal"
|
||||
|
||||
-- Look into the `position` string to find the relevants sides to crop from
|
||||
-- the workarea
|
||||
|
@ -486,17 +514,12 @@ wibox_update_strut = function(d, position, args)
|
|||
|
||||
local m = get_decoration(args)
|
||||
|
||||
if vertical then
|
||||
for _, v in ipairs {"right", "left"} do
|
||||
if (not position) or position:match(v) then
|
||||
struts[v] = geo.width + m[v]
|
||||
end
|
||||
end
|
||||
else
|
||||
for _, v in ipairs {"top", "bottom"} do
|
||||
if (not position) or position:match(v) then
|
||||
struts[v] = geo.height + m[v]
|
||||
end
|
||||
for _, v in ipairs(struts_orientation_to_sides[orientation]) do
|
||||
if (not position) or position:match(v) then
|
||||
-- Add the "short" rectangle lenght then the above and below margins.
|
||||
struts[v] = geo[opposites[orientation_to_length[orientation]]]
|
||||
+ m[v]
|
||||
+ m[opposites[v]]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
-- @author Emmanuel Lepage Vallee
|
||||
-- @copyright 2016 Emmanuel Lepage Vallee
|
||||
-- @popupmod awful.popup
|
||||
-- @supermodule wibox
|
||||
---------------------------------------------------------------------------
|
||||
local wibox = require( "wibox" )
|
||||
local gtable = require( "gears.table" )
|
||||
|
|
|
@ -114,7 +114,6 @@ local io = io
|
|||
local table = table
|
||||
local math = math
|
||||
local ipairs = ipairs
|
||||
local pcall = pcall
|
||||
local capi =
|
||||
{
|
||||
selection = selection
|
||||
|
@ -258,6 +257,11 @@ local function history_add(id, command)
|
|||
end
|
||||
|
||||
|
||||
local function have_multibyte_char_at(text, position)
|
||||
return text:sub(position, position):wlen() == -1
|
||||
end
|
||||
|
||||
|
||||
--- Draw the prompt text with a cursor.
|
||||
-- @tparam table args The table of arguments.
|
||||
-- @field text The text.
|
||||
|
@ -285,10 +289,14 @@ local function prompt_text_with_cursor(args)
|
|||
text_start = gstring.xml_escape(text)
|
||||
text_end = ""
|
||||
else
|
||||
char = gstring.xml_escape(text:sub(args.cursor_pos, args.cursor_pos))
|
||||
local offset = 0
|
||||
if have_multibyte_char_at(text, args.cursor_pos) then
|
||||
offset = 1
|
||||
end
|
||||
char = gstring.xml_escape(text:sub(args.cursor_pos, args.cursor_pos + offset))
|
||||
spacer = " "
|
||||
text_start = gstring.xml_escape(text:sub(1, args.cursor_pos - 1))
|
||||
text_end = gstring.xml_escape(text:sub(args.cursor_pos + 1))
|
||||
text_end = gstring.xml_escape(text:sub(args.cursor_pos + 1 + offset))
|
||||
end
|
||||
|
||||
local cursor_color = gcolor.ensure_pango_color(args.cursor_color)
|
||||
|
@ -544,9 +552,9 @@ function prompt.run(args, textbox, exe_callback, completion_callback,
|
|||
local function update()
|
||||
textbox:set_font(font)
|
||||
textbox:set_markup(prompt_text_with_cursor{
|
||||
text = command, text_color = inv_col, cursor_color = cur_col,
|
||||
cursor_pos = cur_pos, cursor_ul = cur_ul, selectall = selectall,
|
||||
prompt = prettyprompt, highlighter = highlighter })
|
||||
text = command, text_color = inv_col, cursor_color = cur_col,
|
||||
cursor_pos = cur_pos, cursor_ul = cur_ul, selectall = selectall,
|
||||
prompt = prettyprompt, highlighter = highlighter })
|
||||
end
|
||||
|
||||
grabber = keygrabber.run(
|
||||
|
@ -663,6 +671,9 @@ function prompt.run(args, textbox, exe_callback, completion_callback,
|
|||
elseif key == "b" then
|
||||
if cur_pos > 1 then
|
||||
cur_pos = cur_pos - 1
|
||||
if have_multibyte_char_at(command, cur_pos) then
|
||||
cur_pos = cur_pos - 1
|
||||
end
|
||||
end
|
||||
elseif key == "d" then
|
||||
if cur_pos <= #command then
|
||||
|
@ -711,12 +722,20 @@ function prompt.run(args, textbox, exe_callback, completion_callback,
|
|||
end
|
||||
elseif key == "f" then
|
||||
if cur_pos <= #command then
|
||||
cur_pos = cur_pos + 1
|
||||
if have_multibyte_char_at(command, cur_pos) then
|
||||
cur_pos = cur_pos + 2
|
||||
else
|
||||
cur_pos = cur_pos + 1
|
||||
end
|
||||
end
|
||||
elseif key == "h" then
|
||||
if cur_pos > 1 then
|
||||
command = command:sub(1, cur_pos - 2) .. command:sub(cur_pos)
|
||||
cur_pos = cur_pos - 1
|
||||
local offset = 0
|
||||
if have_multibyte_char_at(command, cur_pos - 1) then
|
||||
offset = 1
|
||||
end
|
||||
command = command:sub(1, cur_pos - 2 - offset) .. command:sub(cur_pos)
|
||||
cur_pos = cur_pos - 1 - offset
|
||||
end
|
||||
elseif key == "k" then
|
||||
command = command:sub(1, cur_pos - 1)
|
||||
|
@ -844,8 +863,12 @@ function prompt.run(args, textbox, exe_callback, completion_callback,
|
|||
cur_pos = #command + 1
|
||||
elseif key == "BackSpace" then
|
||||
if cur_pos > 1 then
|
||||
command = command:sub(1, cur_pos - 2) .. command:sub(cur_pos)
|
||||
cur_pos = cur_pos - 1
|
||||
local offset = 0
|
||||
if have_multibyte_char_at(command, cur_pos - 1) then
|
||||
offset = 1
|
||||
end
|
||||
command = command:sub(1, cur_pos - 2 - offset) .. command:sub(cur_pos)
|
||||
cur_pos = cur_pos - 1 - offset
|
||||
end
|
||||
elseif key == "Delete" then
|
||||
command = command:sub(1, cur_pos - 1) .. command:sub(cur_pos + 1)
|
||||
|
@ -889,22 +912,7 @@ function prompt.run(args, textbox, exe_callback, completion_callback,
|
|||
selectall = nil
|
||||
end
|
||||
|
||||
local success = pcall(update)
|
||||
while not success do
|
||||
-- TODO UGLY HACK TODO
|
||||
-- Setting the text failed. Most likely reason is that the user
|
||||
-- entered a multibyte character and pressed backspace which only
|
||||
-- removed the last byte. Let's remove another byte.
|
||||
if cur_pos <= 1 then
|
||||
-- No text left?!
|
||||
break
|
||||
end
|
||||
|
||||
command = command:sub(1, cur_pos - 2) .. command:sub(cur_pos)
|
||||
cur_pos = cur_pos - 1
|
||||
success = pcall(update)
|
||||
end
|
||||
|
||||
update()
|
||||
if changed_callback then
|
||||
changed_callback(command)
|
||||
end
|
||||
|
|
|
@ -349,7 +349,7 @@ function tag.find_fallback(screen, invalids)
|
|||
end
|
||||
end
|
||||
|
||||
--- When all clients are removed from the tag.
|
||||
--- Emitted when all clients are removed from the tag.
|
||||
-- @signal cleared
|
||||
-- @see clear
|
||||
|
||||
|
@ -1841,20 +1841,25 @@ capi.client.connect_signal("untagged", client_untagged)
|
|||
capi.client.connect_signal("tagged", client_tagged)
|
||||
capi.tag.connect_signal("request::select", tag.object.view_only)
|
||||
|
||||
--- True when a tagged client is urgent
|
||||
--- Emitted when the number of urgent clients on this tag changes.
|
||||
-- @signal property::urgent
|
||||
-- @param boolean `true` if there is at least one urgent client on the tag.
|
||||
-- @see client.urgent
|
||||
|
||||
--- The number of urgent tagged clients
|
||||
--- Emitted when the number of urgent clients on this tag changes.
|
||||
-- @signal property::urgent_count
|
||||
-- @param integer The number of urgent clients on the tag.
|
||||
-- @see client.urgent
|
||||
|
||||
--- Emitted when a screen is removed.
|
||||
--
|
||||
-- This can be used to salvage existing tags by moving them to a new
|
||||
-- screen (or creating a virtual screen). By default, there is no
|
||||
-- handler for this request. The tags will be deleted. To prevent
|
||||
-- this, an handler for this request must simply set a new screen
|
||||
-- screen (or creating a virtual screen).
|
||||
--
|
||||
-- By default, there is no handler for this request and the tags will be deleted.
|
||||
-- To prevent this, an handler for this request must simply set a new screen
|
||||
-- for the tag.
|
||||
--
|
||||
-- @signal request::screen
|
||||
-- @tparam string context Why it was called.
|
||||
|
||||
|
|
|
@ -505,20 +505,33 @@ local function get_children_by_id(self, name)
|
|||
end
|
||||
|
||||
|
||||
--- Get a client's titlebar.
|
||||
-- @tparam client c The client for which a titlebar is wanted.
|
||||
--- Create a new titlebar for the given client.
|
||||
--
|
||||
-- Every client can hold up to four titlebars, one for each side (i.e. each
|
||||
-- value of `args.position`).
|
||||
--
|
||||
-- If this constructor is called again with the same
|
||||
-- values for the client (`c`) and the titlebar position (`args.position`),
|
||||
-- the previous titlebar will be removed and replaced by the new one.
|
||||
--
|
||||
-- @DOC_awful_titlebar_constructor_EXAMPLE@
|
||||
--
|
||||
-- @tparam client c The client the titlebar will be attached to.
|
||||
-- @tparam[opt={}] table args A table with extra arguments for the titlebar.
|
||||
-- @tparam[opt=font.height*1.5] number args.size The height of the titlebar.
|
||||
-- @tparam[opt=top] string args.position" values are `top`,
|
||||
-- `left`, `right` and `bottom`.
|
||||
-- @tparam[opt=top] string args.bg_normal
|
||||
-- @tparam[opt=top] string args.bg_focus
|
||||
-- @tparam[opt=top] string args.bgimage_normal
|
||||
-- @tparam[opt=top] string args.bgimage_focus
|
||||
-- @tparam[opt=top] string args.fg_normal
|
||||
-- @tparam[opt=top] string args.fg_focus
|
||||
-- @tparam[opt=top] string args.font
|
||||
-- @tparam[opt=font.height*1.5] number args.size The size of the titlebar. Will
|
||||
-- be interpreted as `height` for horizontal titlebars or as `width` for
|
||||
-- vertical titlebars.
|
||||
-- @tparam[opt="top"] string args.position Possible values are `"top"`,
|
||||
-- `"left"`, `"right"` and `"bottom"`.
|
||||
-- @tparam[opt] string args.bg_normal
|
||||
-- @tparam[opt] string args.bg_focus
|
||||
-- @tparam[opt] string args.bgimage_normal
|
||||
-- @tparam[opt] string args.bgimage_focus
|
||||
-- @tparam[opt] string args.fg_normal
|
||||
-- @tparam[opt] string args.fg_focus
|
||||
-- @tparam[opt] string args.font
|
||||
-- @constructorfct awful.titlebar
|
||||
-- @treturn wibox.drawable The newly created titlebar object.
|
||||
local function new(c, args)
|
||||
args = args or {}
|
||||
local position = args.position or "top"
|
||||
|
@ -578,10 +591,10 @@ local function new(c, args)
|
|||
return ret
|
||||
end
|
||||
|
||||
--- Show a client's titlebar.
|
||||
--- Show the client's titlebar.
|
||||
-- @param c The client whose titlebar is modified
|
||||
-- @param[opt] position The position of the titlebar. Must be one of "left",
|
||||
-- "right", "top", "bottom". Default is "top".
|
||||
-- @tparam[opt="top"] string position The position of the titlebar. Must be one of `"left"`,
|
||||
-- `"right"`, `"top"`, `"bottom"`.
|
||||
-- @staticfct awful.titlebar.show
|
||||
-- @request client titlebars show granted Called when `awful.titlebar.show` is
|
||||
-- called.
|
||||
|
@ -594,20 +607,20 @@ function titlebar.show(c, position)
|
|||
new(c, args)
|
||||
end
|
||||
|
||||
--- Hide a client's titlebar.
|
||||
--- Hide the client's titlebar.
|
||||
-- @param c The client whose titlebar is modified
|
||||
-- @param[opt] position The position of the titlebar. Must be one of "left",
|
||||
-- "right", "top", "bottom". Default is "top".
|
||||
-- @tparam[opt="top"] string position The position of the titlebar. Must be one of `"left"`,
|
||||
-- `"right"`, `"top"`, `"bottom"`.
|
||||
-- @staticfct awful.titlebar.hide
|
||||
function titlebar.hide(c, position)
|
||||
position = position or "top"
|
||||
get_titlebar_function(c, position)(c, 0)
|
||||
end
|
||||
|
||||
--- Toggle a client's titlebar, hiding it if it is visible, otherwise showing it.
|
||||
--- Toggle the client's titlebar, hiding it if it is visible, otherwise showing it.
|
||||
-- @param c The client whose titlebar is modified
|
||||
-- @param[opt] position The position of the titlebar. Must be one of "left",
|
||||
-- "right", "top", "bottom". Default is "top".
|
||||
-- @tparam[opt="top"] string position The position of the titlebar. Must be one of `"left"`,
|
||||
-- `"right"`, `"top"`, `"bottom"`.
|
||||
-- @staticfct awful.titlebar.toggle
|
||||
-- @request client titlebars toggle granted Called when `awful.titlebar.toggle` is
|
||||
-- called.
|
||||
|
@ -649,9 +662,12 @@ local function update_on_signal(c, signal, widget)
|
|||
table.insert(widgets, widget)
|
||||
end
|
||||
|
||||
--- Create a new titlewidget. A title widget displays the name of a client.
|
||||
--- Create a new title widget.
|
||||
--
|
||||
-- A title widget displays the name of a client.
|
||||
-- Please note that this returns a textbox and all of textbox' API is available.
|
||||
-- This way, you can e.g. modify the font that is used.
|
||||
--
|
||||
-- @param c The client for which a titlewidget should be created.
|
||||
-- @return The title widget.
|
||||
-- @constructorfct awful.titlebar.widget.titlewidget
|
||||
|
@ -667,9 +683,12 @@ function titlebar.widget.titlewidget(c)
|
|||
return ret
|
||||
end
|
||||
|
||||
--- Create a new icon widget. An icon widget displays the icon of a client.
|
||||
--- Create a new icon widget.
|
||||
--
|
||||
-- An icon widget displays the icon of a client.
|
||||
-- Please note that this returns an imagebox and all of the imagebox' API is
|
||||
-- available. This way, you can e.g. disallow resizes.
|
||||
--
|
||||
-- @param c The client for which an icon widget should be created.
|
||||
-- @return The icon widget.
|
||||
-- @constructorfct awful.titlebar.widget.iconwidget
|
||||
|
@ -677,13 +696,16 @@ function titlebar.widget.iconwidget(c)
|
|||
return clienticon(c)
|
||||
end
|
||||
|
||||
--- Create a new button widget. A button widget displays an image and reacts to
|
||||
--- Create a new button widget.
|
||||
--
|
||||
-- A button widget displays an image and reacts to
|
||||
-- mouse clicks. Please note that the caller has to make sure that this widget
|
||||
-- gets redrawn when needed by calling the returned widget's update() function.
|
||||
-- gets redrawn when needed by calling the returned widget's `:update()` method.
|
||||
-- The selector function should return a value describing a state. If the value
|
||||
-- is a boolean, either "active" or "inactive" are used. The actual image is
|
||||
-- then found in the theme as "titlebar_[name]_button_[normal/focus]_[state]".
|
||||
-- is a boolean, either `"active"` or `"inactive"` are used. The actual image is
|
||||
-- then found in the theme as `titlebar_[name]_button_[normal/focus]_[state]`.
|
||||
-- If that value does not exist, the focused state is ignored for the next try.
|
||||
--
|
||||
-- @param c The client for which a button is created.
|
||||
-- @tparam string name Name of the button, used for accessing the theme and
|
||||
-- in the tooltip.
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
-- @author Sébastien Gross <seb•ɱɩɲʋʃ•awesome•ɑƬ•chezwam•ɖɵʈ•org>
|
||||
-- @copyright 2009 Sébastien Gross
|
||||
-- @popupmod awful.tooltip
|
||||
-- @supermodule wibox
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
local timer = require("gears.timer")
|
||||
|
|
|
@ -0,0 +1,859 @@
|
|||
---------------------------------------------------------------------------
|
||||
--- Allows to use the wibox widget system to draw the wallpaper.
|
||||
--
|
||||
-- Rather than simply having a function to set an image
|
||||
-- (stretched, centered or tiled) like most wallpaper tools, this module
|
||||
-- leverage the full widget system to draw the wallpaper. Note that the result
|
||||
-- is **not** interactive. If you want an interactive wallpaper, better use
|
||||
-- a `wibox` object with the `below` property set to `true` and maximized
|
||||
-- using `awful.placement.maximized`.
|
||||
--
|
||||
-- It is possible to create an `awful.wallpaper` object from any places, but
|
||||
-- it is recommanded to do it from the `request::wallpaper` signal handler.
|
||||
-- That signal is called everytime something which could affect the wallpaper
|
||||
-- rendering changes, such as new screens.
|
||||
--
|
||||
-- Single image
|
||||
-- ============
|
||||
--
|
||||
-- This is the default `rc.lua` wallpaper format. It fills the whole screen
|
||||
-- and stretches the image while keeping the aspect ratio.
|
||||
--
|
||||
--@DOC_awful_wallpaper_mazimized1_EXAMPLE@
|
||||
--
|
||||
-- If the image aspect ratio doesn't match, the `bg` property can be used to
|
||||
-- fill the empty area:
|
||||
--
|
||||
--@DOC_awful_wallpaper_mazimized2_EXAMPLE@
|
||||
--
|
||||
-- It is also possible to stretch the image:
|
||||
--
|
||||
--@DOC_awful_wallpaper_mazimized3_EXAMPLE@
|
||||
--
|
||||
-- Finally, it is also possible to use simpler "branding" in a corner using
|
||||
-- `awful.placement`:
|
||||
--
|
||||
--@DOC_awful_wallpaper_corner1_EXAMPLE@
|
||||
--
|
||||
-- Tiled
|
||||
-- =====
|
||||
--
|
||||
-- This example tiles an image:
|
||||
--
|
||||
--@DOC_awful_wallpaper_tiled1_EXAMPLE@
|
||||
--
|
||||
-- This one tiles a shape using the `wibox.widget.separator` widget:
|
||||
--
|
||||
--@DOC_awful_wallpaper_tiled2_EXAMPLE@
|
||||
--
|
||||
-- See the `wibox.container.tile` for more advanced tiling configuration
|
||||
-- options.
|
||||
--
|
||||
-- Solid colors and gradients
|
||||
-- ==========================
|
||||
--
|
||||
-- Solid colors can be set using the `bg` property mentionned above. It
|
||||
-- is also possible to set gradients:
|
||||
--
|
||||
--@DOC_awful_wallpaper_gradient1_EXAMPLE@
|
||||
--
|
||||
--@DOC_awful_wallpaper_gradient2_EXAMPLE@
|
||||
--
|
||||
-- Widgets
|
||||
-- =======
|
||||
--
|
||||
-- It is possible to create a wallpaper using any widgets. However, keep
|
||||
-- in mind that the wallpaper surface is not interactive, so some widgets
|
||||
-- like the sliders will render, but will not behave correctly. Also, it
|
||||
-- is not recommanded to update the wallpaper too often. This is very slow.
|
||||
--
|
||||
--@DOC_awful_wallpaper_widget2_EXAMPLE@
|
||||
--
|
||||
-- Cairo graphics API
|
||||
-- ==================
|
||||
--
|
||||
-- AwesomeWM widgets are backed by Cairo. So it is always possible to get
|
||||
-- access to the Cairo context directly to do some vector art:
|
||||
--
|
||||
--@DOC_awful_wallpaper_widget1_EXAMPLE@
|
||||
--
|
||||
--
|
||||
-- SVG vector images
|
||||
-- =================
|
||||
--
|
||||
-- SVG are supported if `librsvg` is installed. Please note that `librsvg`
|
||||
-- doesn't implement all filters you might find in the latest version of
|
||||
-- your web browser. It is possible some advanced SVG will not look exactly
|
||||
-- as they do in a web browser or even Inkscape. However, for most images,
|
||||
-- it should look identical.
|
||||
--
|
||||
-- Our SVG support goes beyond simple rendering. It is possible to set a
|
||||
-- custom CSS stylesheet (see `wibox.widget.imagebox.stylesheet`):
|
||||
--
|
||||
--@DOC_awful_wallpaper_svg_EXAMPLE@
|
||||
--
|
||||
-- Note that in the example above, it is raw SVG code, but it is also possible
|
||||
-- to use a file path. If you have a `.svgz`, you need to uncompress it first
|
||||
-- using `gunzip` or a software like Inkscape.
|
||||
--
|
||||
-- Multiple screen
|
||||
-- ===============
|
||||
--
|
||||
-- The default `rc.lua` creates a new wallpaper everytime `request::wallpaper`
|
||||
-- is emitted. This is well suited for having a single wallpaper per screen.
|
||||
-- It is also much simpler to implement slideshows and add/remove screens.
|
||||
--
|
||||
-- However, it isn't wall suited for wallpaper rendered across multiple screens.
|
||||
-- For this case, it is better to capture the return value of `awful.wallpaper {}`
|
||||
-- as a global variable. Then manually call `add_screen` and `remove_screen` when
|
||||
-- needed. A shortcut can be to do:
|
||||
--
|
||||
-- @DOC_text_awful_wallpaper_multi_screen_EXAMPLE@
|
||||
--
|
||||
-- Slideshow
|
||||
-- =========
|
||||
--
|
||||
-- Slideshows (changing the wallpaper after a few minutes) can be implemented
|
||||
-- directly using a timer and callback, but it is more elegant to simply request
|
||||
-- a new wallpaper, then get a random image from within the request handler. This
|
||||
-- way, corner cases such as adding and removing screens are handled:
|
||||
--
|
||||
--@DOC_awful_wallpaper_slideshow1_EXAMPLE@
|
||||
--
|
||||
-- @author Emmanuel Lepage Vallee <elv1313@gmail.com>
|
||||
-- @copyright 2019 Emmanuel Lepage Vallee
|
||||
-- @popupmod awful.wallpaper
|
||||
---------------------------------------------------------------------------
|
||||
require("awful._compat")
|
||||
local gtable = require( "gears.table" )
|
||||
local gobject = require( "gears.object" )
|
||||
local gcolor = require( "gears.color" )
|
||||
local gtimer = require( "gears.timer" )
|
||||
local surface = require( "gears.surface" )
|
||||
local base = require( "wibox.widget.base" )
|
||||
local background = require( "wibox.container.background")
|
||||
local beautiful = require( "beautiful" )
|
||||
local cairo = require( "lgi" ).cairo
|
||||
local draw = require( "wibox.widget" ).draw_to_cairo_context
|
||||
local grect = require( "gears.geometry" ).rectangle
|
||||
|
||||
local capi = { screen = screen, root = root }
|
||||
|
||||
local module = {}
|
||||
|
||||
local function get_screen(s)
|
||||
return s and capi.screen[s]
|
||||
end
|
||||
|
||||
-- Screen as key, wallpaper as values.
|
||||
local pending_repaint = setmetatable({}, {__mode = 'k'})
|
||||
|
||||
local backgrounds = setmetatable({}, {__mode = 'k'})
|
||||
|
||||
local panning_modes = {}
|
||||
|
||||
-- Get a list of all screen areas.
|
||||
local function get_rectangles(screens, honor_workarea, honor_padding)
|
||||
local ret = {}
|
||||
|
||||
for _, s in ipairs(screens) do
|
||||
table.insert(ret, s:get_bounding_geometry {
|
||||
honor_padding = honor_padding,
|
||||
honor_workarea = honor_workarea
|
||||
})
|
||||
end
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
-- Outer perimeter of all rectangles.
|
||||
function panning_modes.outer(self)
|
||||
local rectangles = get_rectangles(self.screens, self.honor_workarea, self.honor_padding)
|
||||
local p1, p2 = {x = math.huge, y = math.huge}, {x = 0, y = 0}
|
||||
|
||||
for _, rect in ipairs(rectangles) do
|
||||
p1.x, p1.y = math.min(p1.x, rect.x), math.min(p1.y, rect.y)
|
||||
p2.x, p2.y = math.max(p2.x, rect.x + rect.width), math.max(p2.y, rect.y + rect.height)
|
||||
end
|
||||
|
||||
-- Never try to paint this, it would freeze the system.
|
||||
assert(p1.x ~= math.huge and p1.y ~= math.huge, "Setting wallpaper failed"..#self.screens)
|
||||
|
||||
return {
|
||||
x = p1.x,
|
||||
y = p1.y,
|
||||
width = p2.x - p1.x,
|
||||
height = p2.y - p1.y,
|
||||
}
|
||||
end
|
||||
|
||||
-- Horizontal inner perimeter of all rectangles.
|
||||
function panning_modes.inner_horizontal(self)
|
||||
local rectangles = get_rectangles(self.screens, self.honor_workarea, self.honor_padding)
|
||||
local p1, p2 = {x = math.huge, y = 0}, {x = 0, y = math.huge}
|
||||
|
||||
for _, rect in ipairs(rectangles) do
|
||||
p1.x, p1.y = math.min(p1.x, rect.x), math.max(p1.y, rect.y)
|
||||
p2.x, p2.y = math.max(p2.x, rect.x + rect.width), math.min(p2.y, rect.y + rect.height)
|
||||
end
|
||||
|
||||
-- Never try to paint this, it would freeze the system.
|
||||
assert(p1.x ~= math.huge and p2.y ~= math.huge, "Setting wallpaper failed")
|
||||
|
||||
return {
|
||||
x = p1.x,
|
||||
y = p1.y,
|
||||
width = p2.x - p1.x,
|
||||
height = p2.y - p1.y,
|
||||
}
|
||||
end
|
||||
|
||||
-- Vertical inner perimeter of all rectangles.
|
||||
function panning_modes.inner_vertical(self)
|
||||
local rectangles = get_rectangles(self.screens, self.honor_workarea, self.honor_padding)
|
||||
local p1, p2 = {x = 0, y = math.huge}, {x = math.huge, y = 0}
|
||||
|
||||
for _, rect in ipairs(rectangles) do
|
||||
p1.x, p1.y = math.max(p1.x, rect.x), math.min(p1.y, rect.y)
|
||||
p2.x, p2.y = math.min(p2.x, rect.x + rect.width), math.max(p2.y, rect.y + rect.height)
|
||||
end
|
||||
|
||||
-- Never try to paint this, it would freeze the system.
|
||||
assert(p1.y ~= math.huge and p2.a ~= math.huge, "Setting wallpaper failed")
|
||||
|
||||
return {
|
||||
x = p1.x,
|
||||
y = p1.y,
|
||||
width = p2.x - p1.x,
|
||||
height = p2.y - p1.y,
|
||||
}
|
||||
end
|
||||
|
||||
-- Best or vertical and horizontal "inner" modes.
|
||||
function panning_modes.inner(self)
|
||||
local vert = panning_modes.inner_vertical(self)
|
||||
local hori = panning_modes.inner_horizontal(self)
|
||||
|
||||
if vert.width <= 0 or vert.height <= 0 then return hori end
|
||||
if hori.width <= 0 or hori.height <= 0 then return vert end
|
||||
|
||||
if vert.width * vert.height > hori.width * hori.height then
|
||||
return vert
|
||||
else
|
||||
return hori
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function paint()
|
||||
if not next(pending_repaint) then return end
|
||||
|
||||
local root_width, root_height = capi.root.size()
|
||||
|
||||
-- Get the current wallpaper content.
|
||||
local source = surface(root.wallpaper())
|
||||
|
||||
local target, cr
|
||||
|
||||
-- It's possible that a wallpaper for 1 screen is set using another tool, so make
|
||||
-- sure we copy the current content.
|
||||
if source then
|
||||
target = source:create_similar(cairo.Content.COLOR, root_width, root_height)
|
||||
cr = cairo.Context(target)
|
||||
|
||||
-- Copy the old wallpaper to the new one
|
||||
cr:save()
|
||||
cr.operator = cairo.Operator.SOURCE
|
||||
cr:set_source_surface(source, 0, 0)
|
||||
|
||||
for s in screen do
|
||||
cr:rectangle(
|
||||
s.geometry.x,
|
||||
s.geometry.y,
|
||||
s.geometry.width,
|
||||
s.geometry.height
|
||||
)
|
||||
end
|
||||
|
||||
cr:clip()
|
||||
|
||||
cr:paint()
|
||||
cr:restore()
|
||||
else
|
||||
target = cairo.ImageSurface(cairo.Format.RGB32, root_width, root_height)
|
||||
cr = cairo.Context(target)
|
||||
end
|
||||
|
||||
local walls = {}
|
||||
|
||||
for _, wall in pairs(backgrounds) do
|
||||
walls[wall] = true
|
||||
end
|
||||
|
||||
-- Not supposed to happen, but there is enough API surface for
|
||||
-- it to be a side effect of some signals. Calling the panning
|
||||
-- mode callback with zero screen is not supported.
|
||||
if not next(walls) then
|
||||
return
|
||||
end
|
||||
|
||||
for wall in pairs(walls) do
|
||||
|
||||
local geo = type(wall._private.panning_area) == "function" and
|
||||
wall._private.panning_area(wall) or
|
||||
panning_modes[wall._private.panning_area](wall)
|
||||
|
||||
-- If false, this panning area isn't well suited for the screen geometry.
|
||||
if geo.width > 0 or geo.height > 0 then
|
||||
local uncovered_areas = grect.area_remove(get_rectangles(wall.screens, false, false), geo)
|
||||
|
||||
cr:save()
|
||||
|
||||
-- Prevent overwrite then there is multiple non-continuous screens.
|
||||
for _, s in ipairs(wall.screens) do
|
||||
cr:rectangle(
|
||||
s.geometry.x,
|
||||
s.geometry.y,
|
||||
s.geometry.width,
|
||||
s.geometry.height
|
||||
)
|
||||
end
|
||||
|
||||
cr:clip()
|
||||
|
||||
-- The older surface might contain garbage, optionally clean it.
|
||||
if wall.uncovered_areas_color then
|
||||
cr:set_source(gcolor(wall.uncovered_areas_color))
|
||||
|
||||
for _, area in ipairs(uncovered_areas) do
|
||||
cr:rectangle(area.x, area.y, area.width, area.height)
|
||||
cr:fill()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if not wall._private.container then
|
||||
wall._private.container = background()
|
||||
wall._private.container.bg = wall._private.bg or beautiful.wallpaper_bg or "#000000"
|
||||
wall._private.container.fg = wall._private.fg or beautiful.wallpaper_fg or "#ffffff"
|
||||
wall._private.container.widget = wall.widget
|
||||
end
|
||||
|
||||
local a_context = {
|
||||
dpi = wall._private.context.dpi
|
||||
}
|
||||
|
||||
-- Pick the lowest DPI.
|
||||
if not a_context.dpi then
|
||||
a_context.dpi = math.huge
|
||||
for _, s in ipairs(wall.screens) do
|
||||
a_context.dpi = math.min(
|
||||
s.dpi and s.dpi or s.preferred_dpi, a_context.dpi
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
-- Fallback.
|
||||
if not a_context.dpi then
|
||||
a_context.dpi = 96
|
||||
end
|
||||
|
||||
cr:translate(geo.x, geo.y)
|
||||
draw(wall._private.container, cr, geo.width, geo.height, a_context)
|
||||
cr:restore()
|
||||
end
|
||||
end
|
||||
|
||||
-- Set the wallpaper.
|
||||
local pattern = cairo.Pattern.create_for_surface(target)
|
||||
capi.root.wallpaper(pattern)
|
||||
|
||||
-- Limit some potential GC induced increase in memory usage.
|
||||
-- But really, is someone is trying to apply wallpaper changes more
|
||||
-- often than the GC is executed, they are doing it wrong.
|
||||
target:finish()
|
||||
|
||||
end
|
||||
|
||||
local mutex = false
|
||||
|
||||
-- Uploading the surface to X11 is *very* resource intensive. Given the updates
|
||||
-- will often happen in batch (like startup), make sure to only do one "real"
|
||||
-- update.
|
||||
local function update()
|
||||
if mutex then return end
|
||||
|
||||
mutex = true
|
||||
|
||||
gtimer.delayed_call(function()
|
||||
-- Remove the mutex first in case `paint()` raises an exception.
|
||||
mutex = false
|
||||
paint()
|
||||
end)
|
||||
end
|
||||
|
||||
capi.screen.connect_signal("removed", function(s)
|
||||
if not backgrounds[s] then return end
|
||||
|
||||
backgrounds[s]:remove_screen(s)
|
||||
|
||||
update()
|
||||
end)
|
||||
|
||||
capi.screen.connect_signal("property::geometry", function(s)
|
||||
if not backgrounds[s] then return end
|
||||
|
||||
backgrounds[s]:repaint()
|
||||
end)
|
||||
|
||||
|
||||
--- The wallpaper widget.
|
||||
--
|
||||
-- When set, instead of using the `image_path` or `surface` properties, the
|
||||
-- wallpaper will be defined as a normal `wibox` widget tree.
|
||||
--
|
||||
-- @property widget
|
||||
-- @tparam wibox.widget widget
|
||||
-- @see wibox.widget.imagebox
|
||||
-- @see wibox.container.tile
|
||||
|
||||
--- The wallpaper DPI (dots per inch).
|
||||
--
|
||||
-- Each screen has a DPI. This value will be used by default, but sometime it
|
||||
-- is useful to override the screen DPI and use a custom one. This makes
|
||||
-- possible, for example, to draw the widgets bigger than they would otherwise
|
||||
-- be.
|
||||
--
|
||||
-- If not DPI is defined, it will use the smallest DPI from any of the screen.
|
||||
--
|
||||
-- In this example, there is 3 screens with DPI of 100, 200 and 300. As you can
|
||||
-- see, only the text size is affected. Many widgetds are DPI aware, but not all
|
||||
-- of them. This is either because DPI isn't relevant to them or simply because it
|
||||
-- isn't supported (like `wibox.widget.graph`).
|
||||
--
|
||||
-- @DOC_awful_wallpaper_dpi1_EXAMPLE@
|
||||
--
|
||||
-- @property dpi
|
||||
-- @tparam[opt=screen.dpi] number dpi
|
||||
-- @see screen
|
||||
-- @see screen.dpi
|
||||
|
||||
--- The wallpaper screen.
|
||||
--
|
||||
-- Note that there can only be one wallpaper per screen. If there is more, one
|
||||
-- will be chosen and all other ignored.
|
||||
--
|
||||
-- @property screen
|
||||
-- @tparam screen screen
|
||||
-- @see screens
|
||||
-- @see add_screen
|
||||
-- @see remove_screen
|
||||
|
||||
--- A list of screen for this wallpaper.
|
||||
--
|
||||
--@DOC_awful_wallpaper_screens1_EXAMPLE@
|
||||
--
|
||||
-- Some large wallpaper are made to span multiple screens.
|
||||
-- @property screens
|
||||
-- @tparam table screens
|
||||
-- @see screen
|
||||
-- @see add_screen
|
||||
-- @see remove_screen
|
||||
-- @see detach
|
||||
|
||||
--- The background color.
|
||||
--
|
||||
-- It will be used as the "fill" color if the `image` doesn't take all the
|
||||
-- screen space. It will also be the default background for the `widget.
|
||||
--
|
||||
-- As usual with colors in `AwesomeWM`, it can also be a gradient or a pattern.
|
||||
--
|
||||
-- @property bg
|
||||
-- @tparam gears.color bg
|
||||
-- @see gears.color
|
||||
|
||||
--- The foreground color.
|
||||
--
|
||||
-- This will be used by the `widget` (if any).
|
||||
--
|
||||
-- As usual with colors in `AwesomeWM`, it can also be a gradient or a pattern.
|
||||
--
|
||||
-- @property fg
|
||||
-- @tparam gears.color fg
|
||||
-- @see gears.color
|
||||
|
||||
--- The default wallpaper background color.
|
||||
-- @beautiful beautiful.wallpaper_bg
|
||||
-- @tparam gears.color wallpaper_bg
|
||||
-- @see bg
|
||||
|
||||
--- The default wallpaper foreground color.
|
||||
--
|
||||
-- This is useful when using widgets or text in the wallpaper. A wallpaper
|
||||
-- created from a single image wont use this.
|
||||
--
|
||||
-- @beautiful beautiful.wallpaper_fg
|
||||
-- @tparam gears.color wallpaper_fg
|
||||
-- @see bg
|
||||
|
||||
--- Honor the workarea.
|
||||
--
|
||||
-- When set to `true`, the wallpaper will only fill the workarea space instead
|
||||
-- of the entire screen. This means it wont be drawn below the `awful.wibar` or
|
||||
-- docked clients. This is useful when using opaque bars. Note that it can cause
|
||||
-- aspect ratio issues for the wallpaper `image` and add bars colored with the
|
||||
-- `bg` color on the sides.
|
||||
--
|
||||
--@DOC_awful_wallpaper_workarea1_EXAMPLE@
|
||||
--
|
||||
-- @property honor_workarea
|
||||
-- @tparam[opt=false] boolean honor_workarea
|
||||
-- @see honor_padding
|
||||
-- @see uncovered_areas
|
||||
|
||||
--- Honor the screen padding.
|
||||
--
|
||||
-- When set, this will look at the `screen.padding` property to restrict the
|
||||
-- area where the wallpaper is rendered.
|
||||
--
|
||||
-- @DOC_awful_wallpaper_padding1_EXAMPLE@
|
||||
--
|
||||
-- @property honor_padding
|
||||
-- @tparam boolean honor_padding
|
||||
-- @see honor_workarea
|
||||
-- @see uncovered_areas
|
||||
|
||||
--- Returns the list of screen(s) area which won't be covered by the wallpaper.
|
||||
--
|
||||
-- When `honor_workarea`, `honor_padding` or panning are used, some section of
|
||||
-- the screen won't have a wallpaper. This returns a list of areas tables. Each
|
||||
-- table has a `x`, `y`, `width` and `height` key.
|
||||
--
|
||||
-- @property uncovered_areas
|
||||
-- @tparam table uncovered_areas
|
||||
-- @see honor_workarea
|
||||
-- @see honor_padding
|
||||
-- @see uncovered_areas_color
|
||||
|
||||
--- The color for the uncovered areas.
|
||||
--
|
||||
-- Some application rely on the wallpaper for "fake" transparency. Even if an
|
||||
-- area is hidden under a wibar (or other clients), its background can still
|
||||
-- become visible. If you use such application and change your screen geometry
|
||||
-- often enough, it is possible some areas would become filled with the remains
|
||||
-- of previous wallpapers. This property allows to clean those areas with a solid
|
||||
-- color or a gradient.
|
||||
--
|
||||
-- @property uncovered_areas_color
|
||||
-- @tparam gears.color uncovered_areas_color
|
||||
-- @see uncovered_areas
|
||||
|
||||
--- Defines where the wallpaper is placed when there is multiple screens.
|
||||
--
|
||||
-- When there is more than 1 screen, it is possible they don't have the same
|
||||
-- resolution, position or orientation. Panning the wallpaper over them may look
|
||||
-- better if a continuous rectangle is used rather than creating a virtual rectangle
|
||||
-- around all screens.
|
||||
--
|
||||
-- The default algorithms are:
|
||||
--
|
||||
-- **outer:** *(default)*
|
||||
--
|
||||
-- Draw an imaginary rectangle around all screens.
|
||||
--
|
||||
-- @DOC_awful_wallpaper_panning_outer_EXAMPLE@
|
||||
--
|
||||
-- **inner:**
|
||||
--
|
||||
-- Take the largest area or either `inner_horizontal` or `inner_vertical`.
|
||||
--
|
||||
-- @DOC_awful_wallpaper_panning_inner_EXAMPLE@
|
||||
--
|
||||
-- **inner_horizontal:**
|
||||
--
|
||||
-- Take the smallest `x` value, the largest `x+width`, the smallest `y`
|
||||
-- and the smallest `y+height`.
|
||||
--
|
||||
-- @DOC_awful_wallpaper_panning_inner_horizontal_EXAMPLE@
|
||||
--
|
||||
-- **inner_vertical:**
|
||||
--
|
||||
-- Take the smallest `y` value, the largest `y+height`, the smallest `x`
|
||||
-- and the smallest `x+width`.
|
||||
--
|
||||
-- @DOC_awful_wallpaper_panning_inner_vertical_EXAMPLE@
|
||||
--
|
||||
-- **Custom function:**
|
||||
--
|
||||
-- It is also possible to define a custom function.
|
||||
--
|
||||
-- @DOC_awful_wallpaper_panning_custom_EXAMPLE@
|
||||
--
|
||||
-- @property panning_area
|
||||
-- @tparam function|string panning_area
|
||||
-- @see uncovered_areas
|
||||
|
||||
function module:set_panning_area(value)
|
||||
value = value or "outer"
|
||||
|
||||
assert(type(value) == "function" or panning_modes[value], "Invalid panning mode: "..tostring(value))
|
||||
|
||||
self._private.panning_area = value
|
||||
|
||||
self:repaint()
|
||||
|
||||
self:emit_signal("property::panning_area", value)
|
||||
end
|
||||
|
||||
function module:set_widget(w)
|
||||
self._private.widget = base.make_widget_from_value(w)
|
||||
|
||||
if self._private.container then
|
||||
self._private.container.widget = self._private.widget
|
||||
end
|
||||
|
||||
self:repaint()
|
||||
end
|
||||
|
||||
function module:get_widget()
|
||||
return self._private.widget
|
||||
end
|
||||
|
||||
function module:set_dpi(dpi)
|
||||
self._private.context.dpi = dpi
|
||||
self:repaint()
|
||||
end
|
||||
|
||||
function module:get_dpi()
|
||||
return self._private.context.dpi
|
||||
end
|
||||
|
||||
function module:set_screen(s)
|
||||
if not s then return end
|
||||
|
||||
self:_clear()
|
||||
self:add_screen(s)
|
||||
end
|
||||
|
||||
for _, prop in ipairs {"bg", "fg"} do
|
||||
module["set_"..prop] = function(self, color)
|
||||
if self._private.container then
|
||||
self._private.container[prop] = color
|
||||
end
|
||||
|
||||
self._private[prop] = color
|
||||
|
||||
self:repaint()
|
||||
end
|
||||
end
|
||||
|
||||
function module:get_uncovered_areas()
|
||||
local geo = type(self._private.panning_area) == "function" and
|
||||
self._private.panning_area(self) or
|
||||
panning_modes[self._private.panning_area](self)
|
||||
|
||||
return grect.area_remove(get_rectangles(self.screens, false, false), geo)
|
||||
end
|
||||
|
||||
function module:set_screens(screens)
|
||||
local to_rem = {}
|
||||
|
||||
-- All screens.
|
||||
-- The copy is needed because it's a metatable, `ipairs` doesn't work
|
||||
-- correctly in all Lua versions.
|
||||
if screens == capi.screen then
|
||||
screens = {}
|
||||
|
||||
for s in capi.screen do
|
||||
table.insert(screens, s)
|
||||
end
|
||||
end
|
||||
|
||||
for _, s in ipairs(screens) do
|
||||
to_rem[get_screen(s)] = true
|
||||
end
|
||||
|
||||
for _, s in ipairs(self.screens) do
|
||||
to_rem[get_screen(s)] = nil
|
||||
end
|
||||
|
||||
for _, s in ipairs(screens) do
|
||||
s = get_screen(s)
|
||||
self:add_screen(s)
|
||||
to_rem[s] = nil
|
||||
end
|
||||
|
||||
for s, remove in pairs(to_rem) do
|
||||
if remove then
|
||||
self:remove_screen(s)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function module:get_screens()
|
||||
return self._private.screens
|
||||
end
|
||||
|
||||
--- Add another screen (enable panning).
|
||||
--
|
||||
-- **Before:**
|
||||
--
|
||||
--@DOC_awful_wallpaper_add_screen1_EXAMPLE@
|
||||
--
|
||||
-- **After:**
|
||||
--
|
||||
--@DOC_awful_wallpaper_add_screen2_EXAMPLE@
|
||||
--
|
||||
-- Also note that adding a non-continuous screen might not work well,
|
||||
-- but will not automatically add the screens in between:
|
||||
--
|
||||
--@DOC_awful_wallpaper_add_screen3_EXAMPLE@
|
||||
--
|
||||
-- @method add_screen
|
||||
-- @tparam screen screen The screen object.
|
||||
-- @see remove_screen
|
||||
function module:add_screen(s)
|
||||
s = get_screen(s)
|
||||
|
||||
for _, s2 in ipairs(self._private.screens) do
|
||||
if s == s2 then return end
|
||||
end
|
||||
|
||||
table.insert(self._private.screens, s)
|
||||
|
||||
if backgrounds[s] and backgrounds[s] ~= self then
|
||||
backgrounds[s]:remove_screen(s)
|
||||
end
|
||||
|
||||
backgrounds[s] = self
|
||||
|
||||
self:repaint()
|
||||
end
|
||||
|
||||
--- Detach the wallpaper from all screens.
|
||||
--
|
||||
-- Adding a new wallpaper to a screen will automatically
|
||||
-- detach the older one. However there is some case when
|
||||
-- it is useful to call this manually. For example, when
|
||||
-- adding a new panned wallpaper, it is possible that 2
|
||||
-- wallpaper will have an overlap.
|
||||
--
|
||||
-- @method detach
|
||||
-- @see remove_screen
|
||||
-- @see add_screen
|
||||
function module:detach()
|
||||
local screens = gtable.clone(self.screens)
|
||||
|
||||
for _, s in ipairs(screens) do
|
||||
self:remove_screen(s)
|
||||
end
|
||||
end
|
||||
|
||||
function module:_clear()
|
||||
self._private.screens = setmetatable({}, {__mode = "v"})
|
||||
update()
|
||||
end
|
||||
|
||||
--- Repaint the wallpaper.
|
||||
--
|
||||
-- By default, even if the widget changes, the wallpaper will **NOT** be
|
||||
-- automatically repainted. Repainting the native X11 wallpaper is slow and
|
||||
-- it would be too easy to accidentally cause a performance problem. If you
|
||||
-- really need to repaint the wallpaper, call this method.
|
||||
--
|
||||
-- @method repaint
|
||||
function module:repaint()
|
||||
for _, s in ipairs(self._private.screens) do
|
||||
pending_repaint[s] = true
|
||||
end
|
||||
|
||||
update()
|
||||
end
|
||||
|
||||
--- Remove a screen.
|
||||
--
|
||||
-- Calling this will remove a screen, but will **not** repaint its area.
|
||||
-- In this example, the wallpaper was spanning all 3 screens and the
|
||||
-- first screen was removed:
|
||||
--
|
||||
-- @DOC_awful_wallpaper_remove_screen1_EXAMPLE@
|
||||
--
|
||||
-- As you can see, the content of screen 1 still looks like it is part of
|
||||
-- the 3 screen wallpaper. The only use case for calling this method is if
|
||||
-- you use a 3rd party tools to change the wallpaper.
|
||||
--
|
||||
-- If you wish to simply remove a screen and not have leftover content, it is
|
||||
-- simpler to just create a new wallpaper for that screen:
|
||||
--
|
||||
-- @DOC_awful_wallpaper_remove_screen2_EXAMPLE@
|
||||
--
|
||||
-- @method remove_screen
|
||||
-- @tparam screen screen The screen to remove.
|
||||
-- @see detach
|
||||
-- @see add_screen
|
||||
-- @see screens
|
||||
function module:remove_screen(s)
|
||||
s = get_screen(s)
|
||||
|
||||
for k, s2 in ipairs(self._private.screens) do
|
||||
if s == s2 then
|
||||
table.remove(self._private.screens, k)
|
||||
end
|
||||
end
|
||||
|
||||
backgrounds[s] = nil
|
||||
|
||||
self:repaint()
|
||||
end
|
||||
|
||||
--- Create a wallpaper.
|
||||
--
|
||||
-- Note that all parameters are not required. Please refer to the module description and examples to understand parameters usages.
|
||||
--
|
||||
-- @constructorfct awful.wallpaper
|
||||
-- @tparam table args
|
||||
-- @tparam[opt] wibox.widget args.widget The wallpaper widget.
|
||||
-- @tparam[opt] number args.dpi The wallpaper DPI (dots per inch).
|
||||
-- @tparam[opt] screen args.screen The wallpaper screen.
|
||||
-- @tparam[opt] table args.screens A list of screen for this wallpaper. Use this parameter as a remplacement for `args.screen` to manage multiscreen wallpaper. (Note: the expected table should be an array-like table `{screen1, screen2, ...}`)
|
||||
-- @tparam[opt] gears.color args.bg The background color.
|
||||
-- @tparam[opt] gears.color args.fg The foreground color.
|
||||
-- @tparam[opt] gears.color args.uncovered_areas_color The color for the uncovered areas.
|
||||
-- @tparam[opt] boolean args.honor_workarea Honor the workarea.
|
||||
-- @tparam[opt] boolean args.honor_padding Honor the screen padding.
|
||||
-- @tparam[opt] table args.uncovered_areas Returns the list of screen(s) area which won't be covered by the wallpaper.
|
||||
-- @tparam[opt] function|string args.panning_area Defines where the wallpaper is placed when there is multiple screens.
|
||||
|
||||
local function new(_, args)
|
||||
args = args or {}
|
||||
local ret = gobject {
|
||||
enable_auto_signals = true,
|
||||
enable_properties = true,
|
||||
}
|
||||
|
||||
rawset(ret, "_private", {})
|
||||
ret._private.context = {}
|
||||
ret._private.panning_area = "outer"
|
||||
|
||||
gtable.crush(ret, module, true)
|
||||
|
||||
ret:_clear()
|
||||
|
||||
-- Set the screen or screens first to avoid a race condition
|
||||
-- with the other setters.
|
||||
local args_screen, args_screens = args.screen, args.screens
|
||||
if args_screen then
|
||||
ret.screen = args_screen
|
||||
elseif args_screens then
|
||||
ret.screens = args_screens
|
||||
end
|
||||
|
||||
-- Avoid crushing `screen` and `screens` twice.
|
||||
args.screen, args.screens = nil, nil
|
||||
gtable.crush(ret, args, false)
|
||||
args.screen, args.screens = args_screen, args_screens
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
return setmetatable(module, {__call = new})
|
|
@ -1,16 +1,19 @@
|
|||
---------------------------------------------------------------------------
|
||||
--- Wibox module for awful.
|
||||
--- The main AwesomeWM "bar" module.
|
||||
--
|
||||
-- This module allows you to easily create wibox and attach them to the edge of
|
||||
-- a screen.
|
||||
--
|
||||
--@DOC_awful_wibar_default_EXAMPLE@
|
||||
--
|
||||
-- You can even have vertical bars too.
|
||||
--
|
||||
--@DOC_awful_wibar_left_EXAMPLE@
|
||||
--
|
||||
-- @author Emmanuel Lepage Vallee <elv1313@gmail.com>
|
||||
-- @copyright 2016 Emmanuel Lepage Vallee
|
||||
-- @popupmod awful.wibar
|
||||
-- @supermodule awful.popup
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
|
@ -27,6 +30,7 @@ local wibox = require("wibox")
|
|||
local beautiful = require("beautiful")
|
||||
local gdebug = require("gears.debug")
|
||||
local placement = require("awful.placement")
|
||||
local gtable = require("gears.table")
|
||||
|
||||
local function get_screen(s)
|
||||
return s and capi.screen[s]
|
||||
|
@ -38,16 +42,94 @@ local awfulwibar = { mt = {} }
|
|||
-- It's an array so it is ordered.
|
||||
local wiboxes = setmetatable({}, {__mode = "v"})
|
||||
|
||||
local opposite_margin = {
|
||||
top = "bottom",
|
||||
bottom = "top",
|
||||
left = "right",
|
||||
right = "left"
|
||||
}
|
||||
|
||||
local align_map = {
|
||||
top = "left",
|
||||
left = "top",
|
||||
bottom = "right",
|
||||
right = "bottom",
|
||||
centered = "centered"
|
||||
}
|
||||
|
||||
--- If the wibar needs to be stretched to fill the screen.
|
||||
--
|
||||
-- @DOC_awful_wibar_stretch_EXAMPLE@
|
||||
--
|
||||
-- @property stretch
|
||||
-- @tparam boolean stretch
|
||||
-- @propbeautiful
|
||||
-- @propemits true false
|
||||
-- @see align
|
||||
|
||||
--- How to align non-stretched wibars.
|
||||
--
|
||||
-- Values are:
|
||||
--
|
||||
-- * `"top"`
|
||||
-- * `"bottom"`
|
||||
-- * `"left"`
|
||||
-- * `"right"`
|
||||
-- * `"centered"`
|
||||
--
|
||||
-- @DOC_awful_wibar_align_EXAMPLE@
|
||||
--
|
||||
-- @property align
|
||||
-- @tparam string align
|
||||
-- @propbeautiful
|
||||
-- @propemits true false
|
||||
-- @see stretch
|
||||
|
||||
--- Margins on each side of the wibar.
|
||||
--
|
||||
-- It can either be a table with `top`, `bottom`, `left` and `right`
|
||||
-- properties, or a single number that applies to all four sides.
|
||||
--
|
||||
-- @DOC_awful_wibar_margins_EXAMPLE@
|
||||
--
|
||||
-- @property margins
|
||||
-- @tparam number|table margins
|
||||
-- @propbeautiful
|
||||
-- @propemits true false
|
||||
|
||||
--- If the wibar needs to be stretched to fill the screen.
|
||||
--
|
||||
-- @beautiful beautiful.wibar_stretch
|
||||
-- @tparam boolean stretch
|
||||
|
||||
--- Allow or deny the tiled clients to cover the wibar.
|
||||
--
|
||||
-- In the example below, we can see that the first screen workarea
|
||||
-- shrunk by the height of the wibar while the second screen is
|
||||
-- unchanged.
|
||||
--
|
||||
-- @DOC_screen_wibar_workarea_EXAMPLE@
|
||||
--
|
||||
-- @property restrict_workarea
|
||||
-- @tparam[opt=true] boolean restrict_workarea
|
||||
-- @propemits true false
|
||||
-- @see client.struts
|
||||
-- @see screen.workarea
|
||||
|
||||
--- If there is both vertical and horizontal wibar, give more space to vertical ones.
|
||||
--
|
||||
-- By default, if multiple wibars risk overlapping, it will be resolved
|
||||
-- by giving more space to the horizontal one:
|
||||
--
|
||||
-- ![wibar position](../images/AUTOGEN_awful_wibar_position.svg)
|
||||
--
|
||||
-- If this variable is to to `true`, it will behave like:
|
||||
--
|
||||
-- @DOC_awful_wibar_position2_EXAMPLE@
|
||||
--
|
||||
-- @beautiful beautiful.wibar_favor_vertical
|
||||
-- @tparam[opt=false] boolean favor_vertical
|
||||
|
||||
--- The wibar border width.
|
||||
-- @beautiful beautiful.wibar_border_width
|
||||
-- @tparam integer border_width
|
||||
|
@ -96,6 +178,15 @@ local wiboxes = setmetatable({}, {__mode = "v"})
|
|||
-- @beautiful beautiful.wibar_shape
|
||||
-- @tparam gears.shape shape
|
||||
|
||||
--- The wibar's margins.
|
||||
-- @beautiful beautiful.wibar_margins
|
||||
-- @tparam number|table margins
|
||||
|
||||
--- The wibar's alignments.
|
||||
-- @beautiful beautiful.wibar_align
|
||||
-- @tparam string align
|
||||
|
||||
|
||||
-- Compute the margin on one side
|
||||
local function get_margin(w, position, auto_stop)
|
||||
local h_or_w = (position == "top" or position == "bottom") and "height" or "width"
|
||||
|
@ -107,7 +198,15 @@ local function get_margin(w, position, auto_stop)
|
|||
|
||||
if v.position == position and v.screen == w.screen and v.visible then
|
||||
ret = ret + v[h_or_w]
|
||||
|
||||
local wb_margins = v.margins
|
||||
|
||||
if wb_margins then
|
||||
ret = ret + wb_margins[position] + wb_margins[opposite_margin[position]]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return ret
|
||||
|
@ -119,32 +218,49 @@ local function get_margins(w)
|
|||
local position = w.position
|
||||
assert(position)
|
||||
|
||||
local margins = {left=0, right=0, top=0, bottom=0}
|
||||
local margins = gtable.clone(w._private.margins)
|
||||
|
||||
margins[position] = get_margin(w, position, true)
|
||||
margins[position] = margins[position] + get_margin(w, position, true)
|
||||
|
||||
-- Avoid overlapping wibars
|
||||
if position == "left" or position == "right" then
|
||||
if (position == "left" or position == "right") and not beautiful.wibar_favor_vertical then
|
||||
margins.top = get_margin(w, "top" )
|
||||
margins.bottom = get_margin(w, "bottom")
|
||||
elseif (position == "top" or position == "bottom") and beautiful.wibar_favor_vertical then
|
||||
margins.left = get_margin(w, "left" )
|
||||
margins.right = get_margin(w, "right")
|
||||
end
|
||||
|
||||
return margins
|
||||
end
|
||||
|
||||
-- Create the placement function
|
||||
local function gen_placement(position, stretch)
|
||||
local function gen_placement(position, align, stretch)
|
||||
local maximize = (position == "right" or position == "left") and
|
||||
"maximize_vertically" or "maximize_horizontally"
|
||||
|
||||
return placement[position] + (stretch and placement[maximize] or nil)
|
||||
local corner = nil
|
||||
|
||||
if align ~= "centered" then
|
||||
if position == "right" or position == "left" then
|
||||
corner = placement[align .. "_" .. position]
|
||||
or placement[align_map[align] .. "_" .. position]
|
||||
else
|
||||
corner = placement[position .. "_" .. align]
|
||||
or placement[position .. "_" .. align_map[align]]
|
||||
end
|
||||
end
|
||||
|
||||
corner = corner or placement[position]
|
||||
|
||||
return corner + (stretch and placement[maximize] or nil)
|
||||
end
|
||||
|
||||
-- Attach the placement function.
|
||||
local function attach(wb, align)
|
||||
gen_placement(align, wb._stretch)(wb, {
|
||||
local function attach(wb, position)
|
||||
gen_placement(position, wb._private.align, wb._stretch)(wb, {
|
||||
attach = true,
|
||||
update_workarea = true,
|
||||
update_workarea = wb._private.restrict_workarea,
|
||||
margins = get_margins(wb)
|
||||
})
|
||||
end
|
||||
|
@ -172,15 +288,23 @@ end
|
|||
-- * top
|
||||
-- * bottom
|
||||
--
|
||||
-- @DOC_awful_wibar_position_EXAMPLE@
|
||||
--
|
||||
-- @property position
|
||||
-- @tparam string position Either "left", right", "top" or "bottom"
|
||||
-- @propemits true false
|
||||
|
||||
local function get_position(wb)
|
||||
function awfulwibar.get_position(wb)
|
||||
return wb._position or "top"
|
||||
end
|
||||
|
||||
local function set_position(wb, position, skip_reattach)
|
||||
function awfulwibar.set_position(wb, position, screen)
|
||||
if position == wb._position then return end
|
||||
|
||||
if screen then
|
||||
gdebug.deprecate("Use `wb.screen = screen` instead of awful.wibar.set_position", {deprecated_in=4})
|
||||
end
|
||||
|
||||
-- Detach first to avoid any uneeded callbacks
|
||||
if wb.detach_callback then
|
||||
wb.detach_callback()
|
||||
|
@ -191,14 +315,12 @@ local function set_position(wb, position, skip_reattach)
|
|||
|
||||
-- Move the wibar to the end of the list to avoid messing up the others in
|
||||
-- case there is stacked wibars on one side.
|
||||
if wb._position then
|
||||
for k, w in ipairs(wiboxes) do
|
||||
if w == wb then
|
||||
table.remove(wiboxes, k)
|
||||
end
|
||||
for k, w in ipairs(wiboxes) do
|
||||
if w == wb then
|
||||
table.remove(wiboxes, k)
|
||||
end
|
||||
table.insert(wiboxes, wb)
|
||||
end
|
||||
table.insert(wiboxes, wb)
|
||||
|
||||
-- In case the position changed, it may be necessary to reset the size
|
||||
if (wb._position == "left" or wb._position == "right")
|
||||
|
@ -217,7 +339,7 @@ local function set_position(wb, position, skip_reattach)
|
|||
|
||||
-- A way to skip reattach is required when first adding a wibar as it's not
|
||||
-- in the `wiboxes` table yet and can't be added until it's attached.
|
||||
if not skip_reattach then
|
||||
if not wb._private.skip_reattach then
|
||||
-- Changing the position will also cause the other margins to be invalidated.
|
||||
-- For example, adding a wibar to the top will change the margins of any left
|
||||
-- or right wibars. To solve, this, they need to be re-attached.
|
||||
|
@ -227,11 +349,11 @@ local function set_position(wb, position, skip_reattach)
|
|||
wb:emit_signal("property::position", position)
|
||||
end
|
||||
|
||||
local function get_stretch(w)
|
||||
function awfulwibar.get_stretch(w)
|
||||
return w._stretch
|
||||
end
|
||||
|
||||
local function set_stretch(w, value)
|
||||
function awfulwibar.set_stretch(w, value)
|
||||
w._stretch = value
|
||||
|
||||
attach(w, w.position)
|
||||
|
@ -239,10 +361,89 @@ local function set_stretch(w, value)
|
|||
w:emit_signal("property::stretch", value)
|
||||
end
|
||||
|
||||
|
||||
function awfulwibar.get_restrict_workarea(w)
|
||||
return w._private.restrict_workarea
|
||||
end
|
||||
|
||||
function awfulwibar.set_restrict_workarea(w, value)
|
||||
w._private.restrict_workarea = value
|
||||
|
||||
attach(w, w.position)
|
||||
|
||||
w:emit_signal("property::restrict_workarea", value)
|
||||
end
|
||||
|
||||
|
||||
function awfulwibar.set_margins(w, value)
|
||||
if type(value) == "number" then
|
||||
value = {
|
||||
top = value,
|
||||
bottom = value,
|
||||
right = value,
|
||||
left = value,
|
||||
}
|
||||
end
|
||||
|
||||
local old = gtable.crush({
|
||||
left = 0,
|
||||
right = 0,
|
||||
top = 0,
|
||||
bottom = 0
|
||||
}, w._private.margins or {}, true)
|
||||
|
||||
value = gtable.crush(old, value or {}, true)
|
||||
|
||||
w._private.margins = value
|
||||
|
||||
attach(w, w.position)
|
||||
|
||||
w:emit_signal("property::margins", value)
|
||||
end
|
||||
|
||||
-- Allow each margins to be set individually.
|
||||
local function meta_margins(self)
|
||||
return setmetatable({}, {
|
||||
__index = self._private.margins,
|
||||
__newindex = function(_, k, v)
|
||||
self._private.margins[k] = v
|
||||
awfulwibar.set_margins(self, self._private.margins)
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
function awfulwibar.get_margins(self)
|
||||
return self._private.meta_margins
|
||||
end
|
||||
|
||||
|
||||
function awfulwibar.get_align(self)
|
||||
return self._private.align
|
||||
end
|
||||
|
||||
function awfulwibar.set_align(self, value, screen)
|
||||
if value == "center" then
|
||||
gdebug.deprecate("awful.wibar.align(wb, 'center' is deprecated, use 'centered'", {deprecated_in=4})
|
||||
value = "centered"
|
||||
end
|
||||
|
||||
if screen then
|
||||
gdebug.deprecate("awful.wibar.align 'screen' argument is deprecated", {deprecated_in=4})
|
||||
end
|
||||
|
||||
assert(align_map[value])
|
||||
|
||||
self._private.align = value
|
||||
|
||||
attach(self, self.position)
|
||||
|
||||
self:emit_signal("property::align", value)
|
||||
end
|
||||
|
||||
--- Remove a wibar.
|
||||
-- @method remove
|
||||
|
||||
local function remove(self)
|
||||
function awfulwibar.remove(self)
|
||||
self.visible = false
|
||||
|
||||
if self.detach_callback then
|
||||
|
@ -259,26 +460,6 @@ local function remove(self)
|
|||
self._screen = nil
|
||||
end
|
||||
|
||||
--- Get a wibox position if it has been set, or return top.
|
||||
-- @param wb The wibox
|
||||
-- @deprecated awful.wibar.get_position
|
||||
-- @return The wibox position.
|
||||
function awfulwibar.get_position(wb)
|
||||
gdebug.deprecate("Use wb:get_position() instead of awful.wibar.get_position", {deprecated_in=4})
|
||||
return get_position(wb)
|
||||
end
|
||||
|
||||
--- Put a wibox on a screen at this position.
|
||||
-- @param wb The wibox to attach.
|
||||
-- @param position The position: top, bottom left or right.
|
||||
-- @param screen This argument is deprecated, use wb.screen directly.
|
||||
-- @deprecated awful.wibar.set_position
|
||||
function awfulwibar.set_position(wb, position, screen) --luacheck: no unused args
|
||||
gdebug.deprecate("Use wb:set_position(position) instead of awful.wibar.set_position", {deprecated_in=4})
|
||||
|
||||
set_position(wb, position)
|
||||
end
|
||||
|
||||
--- Attach a wibox to a screen.
|
||||
--
|
||||
-- This function has been moved to the `awful.placement` module. Calling this
|
||||
|
@ -289,7 +470,7 @@ end
|
|||
-- @param screen The screen to attach to
|
||||
-- @see awful.placement
|
||||
-- @deprecated awful.wibar.attach
|
||||
function awfulwibar.attach(wb, position, screen) --luacheck: no unused args
|
||||
local function legacy_attach(wb, position, screen) --luacheck: no unused args
|
||||
gdebug.deprecate("awful.wibar.attach is deprecated, use the 'attach' property"..
|
||||
" of awful.placement. This method doesn't do anything anymore",
|
||||
{deprecated_in=4}
|
||||
|
@ -318,7 +499,7 @@ end
|
|||
-- directly.
|
||||
-- @deprecated awful.wibar.align
|
||||
-- @see awful.placement.align
|
||||
function awfulwibar.align(wb, align, screen) --luacheck: no unused args
|
||||
local function legacy_align(wb, align, screen) --luacheck: no unused args
|
||||
if align == "center" then
|
||||
gdebug.deprecate("awful.wibar.align(wb, 'center' is deprecated, use 'centered'", {deprecated_in=4})
|
||||
align = "centered"
|
||||
|
@ -350,6 +531,9 @@ end
|
|||
-- @tparam[opt=nil] table args
|
||||
-- @tparam string args.position The position.
|
||||
-- @tparam string args.stretch If the wibar need to be stretched to fill the screen.
|
||||
-- @tparam boolean args.restrict_workarea Allow or deny the tiled clients to cover the wibar.
|
||||
-- @tparam string args.align How to align non-stretched wibars.
|
||||
-- @tparam table|number args.margins The wibar margins.
|
||||
--@DOC_wibox_constructor_COMMON@
|
||||
-- @return The new wibar
|
||||
-- @constructorfct awful.wibar
|
||||
|
@ -399,7 +583,7 @@ function awfulwibar.new(args)
|
|||
-- The C code scans the table directly, so metatable magic cannot be used.
|
||||
for _, prop in ipairs {
|
||||
"border_width", "border_color", "font", "opacity", "ontop", "cursor",
|
||||
"bgimage", "bg", "fg", "type", "stretch", "shape"
|
||||
"bgimage", "bg", "fg", "type", "stretch", "shape", "margins", "align"
|
||||
} do
|
||||
if (args[prop] == nil) and beautiful["wibar_"..prop] ~= nil then
|
||||
args[prop] = beautiful["wibar_"..prop]
|
||||
|
@ -408,25 +592,37 @@ function awfulwibar.new(args)
|
|||
|
||||
local w = wibox(args)
|
||||
|
||||
w.screen = screen
|
||||
w._screen = screen --HACK When a screen is removed, then getbycoords wont work
|
||||
w._stretch = args.stretch == nil and has_to_stretch or args.stretch
|
||||
w._private.align = (args.align and align_map[args.align]) and args.align or "centered"
|
||||
|
||||
w.get_position = get_position
|
||||
w.set_position = set_position
|
||||
w._private.margins = {
|
||||
left = 0,
|
||||
right = 0,
|
||||
top = 0,
|
||||
bottom = 0
|
||||
}
|
||||
w._private.meta_margins = meta_margins(w)
|
||||
|
||||
w.get_stretch = get_stretch
|
||||
w.set_stretch = set_stretch
|
||||
w.remove = remove
|
||||
|
||||
if args.visible == nil then w.visible = true end
|
||||
w._private.restrict_workarea = true
|
||||
|
||||
-- `w` needs to be inserted in `wiboxes` before reattach or its own offset
|
||||
-- will not be taken into account by the "older" wibars when `reattach` is
|
||||
-- called. `skip_reattach` is required.
|
||||
w:set_position(position, true)
|
||||
w._private.skip_reattach = true
|
||||
|
||||
table.insert(wiboxes, w)
|
||||
|
||||
w.screen = screen
|
||||
w._screen = screen --HACK When a screen is removed, then getbycoords wont work
|
||||
w._stretch = args.stretch == nil and has_to_stretch or args.stretch
|
||||
|
||||
if args.visible == nil then w.visible = true end
|
||||
|
||||
gtable.crush(w, awfulwibar, true)
|
||||
gtable.crush(w, args, false)
|
||||
|
||||
-- Now, let set_position behave normally.
|
||||
w._private.skip_reattach = false
|
||||
|
||||
awfulwibar.set_margins(w, args.margins)
|
||||
|
||||
-- Force all the wibars to be moved
|
||||
reattach(w)
|
||||
|
@ -454,6 +650,14 @@ function awfulwibar.mt:__call(...)
|
|||
return awfulwibar.new(...)
|
||||
end
|
||||
|
||||
function awfulwibar.mt:__index(_, k)
|
||||
if k == "align" then
|
||||
return legacy_align
|
||||
elseif k == "attach" then
|
||||
return legacy_attach
|
||||
end
|
||||
end
|
||||
|
||||
--@DOC_wibox_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008-2009 Julien Danjou
|
||||
-- @widgetmod awful.widget.button
|
||||
-- @supermodule wibox.widget.imagebox
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
@ -65,10 +66,6 @@ function button.mt:__call(...)
|
|||
return button.new(...)
|
||||
end
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return setmetatable(button, button.mt)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
---------------------------------------------------------------------------
|
||||
--- Container showing the icon of a client.
|
||||
-- @author Uli Schlachter
|
||||
-- @copyright 2017 Uli Schlachter
|
||||
-- @widgetmod awful.widget.clienticon
|
||||
-- @supermodule wibox.widget.base
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local base = require("wibox.widget.base")
|
||||
local surface = require("gears.surface")
|
||||
|
@ -123,10 +126,6 @@ client.connect_signal("property::icon", function(c)
|
|||
end
|
||||
end)
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return setmetatable(clienticon, {
|
||||
__call = function(_, ...)
|
||||
return new(...)
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008-2009 Julien Danjou
|
||||
-- @widgetmod awful.widget.launcher
|
||||
-- @supermodule awful.widget.button
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
@ -50,10 +51,6 @@ function launcher.mt:__call(...)
|
|||
return launcher.new(...)
|
||||
end
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return setmetatable(launcher, launcher.mt)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @widgetmod awful.widget.layoutbox
|
||||
-- @supermodule wibox.layout.fixed
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
-- @author Emmanuel Lepage Vallee <elv1313@gmail.com>
|
||||
-- @copyright 2010, 2018 Emmanuel Lepage Vallee
|
||||
-- @widgetmod awful.widget.layoutlist
|
||||
-- @supermodule wibox.widget.base
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
local capi = {screen = screen, tag = tag}
|
||||
|
@ -444,8 +445,4 @@ local function new(_, args)
|
|||
return ret
|
||||
end
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return setmetatable(module, {__call = new})
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
-- @author Uli Schlachter
|
||||
-- @copyright 2017 Uli Schlachter
|
||||
-- @containermod awful.widget.only_on_screen
|
||||
-- @supermodule wibox.widget.base
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local type = type
|
||||
|
@ -129,10 +130,6 @@ capi.screen.connect_signal("property::outputs", function()
|
|||
end
|
||||
end)
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return setmetatable(only_on_screen, only_on_screen.mt)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
-- @copyright 2009 Julien Danjou
|
||||
-- @copyright 2018 Aire-One
|
||||
-- @widgetmod awful.widget.prompt
|
||||
-- @supermodule wibox.container.background
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
--- The prompt foreground color.
|
||||
|
@ -158,10 +159,6 @@ function widgetprompt.mt:__call(...)
|
|||
return widgetprompt.new(...)
|
||||
end
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return setmetatable(widgetprompt, widgetprompt.mt)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -70,7 +70,8 @@ function gtk.get_theme_variables()
|
|||
|
||||
local result = {}
|
||||
local _gtk_status, Gtk = pcall(function()
|
||||
return require('lgi').Gtk
|
||||
local lgi = require('lgi')
|
||||
return lgi.require('Gtk', '3.0')
|
||||
end)
|
||||
if not _gtk_status or not Gtk then
|
||||
gears_debug.print_warning(
|
||||
|
|
|
@ -172,28 +172,39 @@ end
|
|||
-- @tparam string path The directory to search.
|
||||
-- @tparam[opt] table exts Specific extensions to limit the search to. eg:`{ "jpg", "png" }`
|
||||
-- If ommited, all files are considered.
|
||||
-- @tparam[opt=false] boolean absolute_path Return the absolute path instead of the filename.
|
||||
-- @treturn string|nil A randomly selected filename from the specified path (with
|
||||
-- a specified extension if required) or nil if no suitable file is found.
|
||||
-- a specified extension if required) or nil if no suitable file is found. If `absolute_path`
|
||||
-- is set, then a path is returned instead of a file name.
|
||||
-- @staticfct gears.filesystem.get_random_file_from_dir
|
||||
function filesystem.get_random_file_from_dir(path, exts)
|
||||
function filesystem.get_random_file_from_dir(path, exts, absolute_path)
|
||||
local files, valid_exts = {}, {}
|
||||
|
||||
-- Transforms { "jpg", ... } into { [jpg] = #, ... }
|
||||
if exts then for i, j in ipairs(exts) do valid_exts[j:lower()] = i end end
|
||||
if exts then for i, j in ipairs(exts) do valid_exts[j:lower():gsub("^[.]", "")] = i end end
|
||||
|
||||
-- Build a table of files from the path with the required extensions
|
||||
local file_list = Gio.File.new_for_path(path):enumerate_children("standard::*", 0)
|
||||
|
||||
-- This will happen when the directory doesn't exist.
|
||||
if not file_list then return nil end
|
||||
|
||||
for file in function() return file_list:next_file() end do
|
||||
if file:get_file_type() == "REGULAR" then
|
||||
local file_name = file:get_display_name()
|
||||
|
||||
if not exts or valid_exts[file_name:lower():match(".+%.(.*)$") or ""] then
|
||||
table.insert(files, file_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if #files == 0 then return nil end
|
||||
|
||||
-- Return a randomly selected filename from the file table
|
||||
return #files > 0 and files[math.random(#files)] or nil
|
||||
local file = files[math.random(#files)]
|
||||
|
||||
return absolute_path and (path:gsub("[/]*$", "") .. "/" .. file) or file
|
||||
end
|
||||
|
||||
return filesystem
|
||||
|
|
|
@ -46,9 +46,11 @@ function object.add_signal()
|
|||
end
|
||||
|
||||
--- Connect to a signal.
|
||||
--
|
||||
--@DOC_text_gears_object_signal_EXAMPLE@
|
||||
-- @tparam string name The name of the signal
|
||||
-- @tparam function func The callback to call when the signal is emitted
|
||||
--
|
||||
-- @tparam string name The name of the signal.
|
||||
-- @tparam function func The callback to call when the signal is emitted.
|
||||
-- @method connect_signal
|
||||
function object:connect_signal(name, func)
|
||||
assert(type(func) == "function", "callback must be a function, got: " .. type(func))
|
||||
|
@ -92,10 +94,16 @@ local function make_the_gc_obey(func)
|
|||
return func
|
||||
end
|
||||
|
||||
--- Connect to a signal weakly. This allows the callback function to be garbage
|
||||
-- collected and automatically disconnects the signal when that happens.
|
||||
-- @tparam string name The name of the signal
|
||||
-- @tparam function func The callback to call when the signal is emitted
|
||||
--- Connect to a signal weakly.
|
||||
--
|
||||
-- This allows the callback function to be garbage collected and
|
||||
-- automatically disconnects the signal when that happens.
|
||||
-- **Warning:**
|
||||
-- Only use this function if you really, really, really know what you
|
||||
-- are doing.
|
||||
--
|
||||
-- @tparam string name The name of the signal.
|
||||
-- @tparam function func The callback to call when the signal is emitted.
|
||||
-- @method weak_connect_signal
|
||||
function object:weak_connect_signal(name, func)
|
||||
assert(type(func) == "function", "callback must be a function, got: " .. type(func))
|
||||
|
@ -104,9 +112,9 @@ function object:weak_connect_signal(name, func)
|
|||
sig.weak[func] = make_the_gc_obey(func)
|
||||
end
|
||||
|
||||
--- Disonnect to a signal.
|
||||
-- @tparam string name The name of the signal
|
||||
-- @tparam function func The callback that should be disconnected
|
||||
--- Disonnect from a signal.
|
||||
-- @tparam string name The name of the signal.
|
||||
-- @tparam function func The callback that should be disconnected.
|
||||
-- @method disconnect_signal
|
||||
function object:disconnect_signal(name, func)
|
||||
local sig = find_signal(self, name)
|
||||
|
@ -118,8 +126,8 @@ end
|
|||
--
|
||||
-- @tparam string name The name of the signal
|
||||
-- @param ... Extra arguments for the callback functions. Each connected
|
||||
-- function receives the object as first argument and then any extra arguments
|
||||
-- that are given to emit_signal()
|
||||
-- function receives the object as first argument and then any extra
|
||||
-- arguments that are given to emit_signal()
|
||||
-- @method emit_signal
|
||||
function object:emit_signal(name, ...)
|
||||
local sig = find_signal(self, name)
|
||||
|
|
|
@ -39,27 +39,31 @@ function gtable.join(...)
|
|||
return ret
|
||||
end
|
||||
|
||||
--- Override elements in the first table by the one in the second.
|
||||
--- Override elements in the target table with values from the source table.
|
||||
--
|
||||
-- Note that this method doesn't copy entries found in `__index`.
|
||||
-- Nested tables are copied by reference and not recursed into.
|
||||
--
|
||||
-- @tparam table t the table to be overriden
|
||||
-- @tparam table set the table used to override members of `t`
|
||||
-- @tparam[opt=false] bool raw Use rawset (avoid the metatable)
|
||||
-- @treturn table t (for convenience)
|
||||
-- @tparam table target The target table. Values from `source` will be copied
|
||||
-- into this table.
|
||||
-- @tparam table source The source table. Its values will be copied into
|
||||
-- `target`.
|
||||
-- @tparam[opt=false] bool raw If `true`, values will be assigned with `rawset`.
|
||||
-- This will bypass metamethods on `target`.
|
||||
-- @treturn table The target table.
|
||||
-- @staticfct gears.table.crush
|
||||
function gtable.crush(t, set, raw)
|
||||
function gtable.crush(target, source, raw)
|
||||
if raw then
|
||||
for k, v in pairs(set) do
|
||||
rawset(t, k, v)
|
||||
for k, v in pairs(source) do
|
||||
rawset(target, k, v)
|
||||
end
|
||||
else
|
||||
for k, v in pairs(set) do
|
||||
t[k] = v
|
||||
for k, v in pairs(source) do
|
||||
target[k] = v
|
||||
end
|
||||
end
|
||||
|
||||
return t
|
||||
return target
|
||||
end
|
||||
|
||||
--- Pack all elements with an integer key into a new table.
|
||||
|
@ -165,6 +169,23 @@ function gtable.keys(t)
|
|||
return keys
|
||||
end
|
||||
|
||||
--- Get the number of keys in a table, both integer and string indicies.
|
||||
--
|
||||
-- This is functionally equivalent, but faster than `#gears.table.keys(t)`.
|
||||
--
|
||||
-- @DOC_text_gears_table_count_keys_EXAMPLE@
|
||||
--
|
||||
-- @tparam table t The table for which to count the keys.
|
||||
-- @treturn number The number of keys in the table.
|
||||
-- @staticfct gears.table.count_keys
|
||||
function gtable.count_keys(t)
|
||||
local count = 0
|
||||
for _ in pairs(t) do
|
||||
count = count + 1
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
||||
--- Filter a table's keys for certain content type.
|
||||
--
|
||||
-- @tparam table t The table to retrieve the keys for.
|
||||
|
@ -208,7 +229,8 @@ end
|
|||
--- Clone a table.
|
||||
--
|
||||
-- @tparam table t The table to clone.
|
||||
-- @tparam[opt=true] bool deep Create a deep clone?
|
||||
-- @tparam[opt=true] bool deep If `true`, recurse into nested tables to create
|
||||
-- a deep clone.
|
||||
-- @treturn table A clone of `t`.
|
||||
-- @staticfct gears.table.clone
|
||||
function gtable.clone(t, deep)
|
||||
|
@ -230,14 +252,16 @@ end
|
|||
-- `first_index` has to be specified.
|
||||
--
|
||||
-- @tparam table t The input table.
|
||||
-- @param value A value from the table.
|
||||
-- @tparam[opt=1] number step_size How many element forward (or backward) to pick.
|
||||
-- @tparam[opt=nil] function filter An optional function. When it returns
|
||||
-- `false`, the element are skipped until a match if found. It takes the value
|
||||
-- as its sole parameter.
|
||||
-- @param value The start value. Must be an element of the input table `t`.
|
||||
-- @tparam[opt=1] number step_size The amount to increment the index by.
|
||||
-- When this is negative, the function will cycle through the table backwards.
|
||||
-- @tparam[opt=nil] function filter An optional filter function. It receives a
|
||||
-- value from the table as parameter and should return a boolean. If it
|
||||
-- returns `false`, the value is skipped and `cycle_value` tries the next one.
|
||||
-- @tparam[opt=1] number start_at Where to start the lookup from.
|
||||
-- @return The value. If no element match, then `nil` is returned.
|
||||
-- @treturn number|nil The element (if any) key.
|
||||
-- @return The next eligible value. If no value matches, `nil` is returned.
|
||||
-- @treturn number|nil If a value is found, this is its index within the input
|
||||
-- table.
|
||||
-- @staticfct gears.table.cycle_value
|
||||
function gtable.cycle_value(t, value, step_size, filter, start_at)
|
||||
local k = gtable.hasitem(t, value, true, start_at)
|
||||
|
@ -287,17 +311,23 @@ function gtable.iterate(t, filter, start)
|
|||
end
|
||||
end
|
||||
|
||||
--- Merge items from one table to another one.
|
||||
--- Merge items from the source table into the target table.
|
||||
--
|
||||
-- @tparam table t The container table
|
||||
-- @tparam table set The mixin table.
|
||||
-- @treturn table (for convenience).
|
||||
-- Note that this only considers the array part of `source` (same semantics
|
||||
-- as `ipairs`).
|
||||
-- Nested tables are copied by reference and not recursed into.
|
||||
--
|
||||
-- @tparam table target The target table. Values from `source` will be copied
|
||||
-- into this table.
|
||||
-- @tparam table source The source table. Its values will be copied into
|
||||
-- `target`.
|
||||
-- @treturn table The target table.
|
||||
-- @staticfct gears.table.merge
|
||||
function gtable.merge(t, set)
|
||||
for _, v in ipairs(set) do
|
||||
table.insert(t, v)
|
||||
function gtable.merge(target, source)
|
||||
for _, v in ipairs(source) do
|
||||
table.insert(target, v)
|
||||
end
|
||||
return t
|
||||
return target
|
||||
end
|
||||
|
||||
--- Update the `target` table with entries from the `new` table.
|
||||
|
@ -384,7 +414,7 @@ end
|
|||
|
||||
--- Map a function to a table.
|
||||
--
|
||||
-- The function is applied to each value on the table, returning a modified
|
||||
-- The function is applied to each value in the table, returning a modified
|
||||
-- table.
|
||||
--
|
||||
-- @tparam function f The function to be applied to each value in the table.
|
||||
|
@ -400,3 +430,5 @@ function gtable.map(f, tbl)
|
|||
end
|
||||
|
||||
return gtable
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -99,11 +99,13 @@ function timer:start()
|
|||
end
|
||||
|
||||
--- Stop the timer.
|
||||
--
|
||||
-- Does nothing if the timer isn't running.
|
||||
--
|
||||
-- @method stop
|
||||
-- @emits stop
|
||||
function timer:stop()
|
||||
if self.data.source_id == nil then
|
||||
gdebug.print_error(traceback("timer not started"))
|
||||
return
|
||||
end
|
||||
glib.source_remove(self.data.source_id)
|
||||
|
@ -192,13 +194,17 @@ function timer.new(args)
|
|||
return ret
|
||||
end
|
||||
|
||||
--- Create a timeout for calling some callback function.
|
||||
-- When the callback function returns true, it will be called again after the
|
||||
-- same timeout. If false is returned, no more calls will be done. If the
|
||||
-- callback function causes an error, no more calls are done.
|
||||
--- Create a simple timer for calling the `callback` function continuously.
|
||||
--
|
||||
-- This is a small wrapper around `gears.timer`, that creates a timer based on
|
||||
-- `callback`.
|
||||
-- The timer will run continuously and call `callback` every `timeout` seconds.
|
||||
-- It is stopped when `callback` returns `false`, when `callback` throws an
|
||||
-- error or when the `:stop()` method is called on the return value.
|
||||
--
|
||||
-- @tparam number timeout Timeout in seconds (e.g. 1.5).
|
||||
-- @tparam function callback Function to run.
|
||||
-- @treturn timer The timer object that was set up.
|
||||
-- @treturn timer The new timer object.
|
||||
-- @staticfct gears.timer.start_new
|
||||
-- @see gears.timer.weak_start_new
|
||||
function timer.start_new(timeout, callback)
|
||||
|
@ -213,14 +219,18 @@ function timer.start_new(timeout, callback)
|
|||
return t
|
||||
end
|
||||
|
||||
--- Create a timeout for calling some callback function.
|
||||
-- This function is almost identical to `gears.timer.start_new`. The only difference
|
||||
-- is that this does not prevent the callback function from being garbage
|
||||
-- collected. After the callback function was collected, the timer returned
|
||||
-- will automatically be stopped.
|
||||
--- Create a simple timer for calling the `callback` function continuously.
|
||||
--
|
||||
-- This function is almost identical to `gears.timer.start_new`. The only
|
||||
-- difference is that this does not prevent the callback function from being
|
||||
-- garbage collected.
|
||||
-- In addition to the conditions in `gears.timer.start_new`,
|
||||
-- this timer will also stop if `callback` was garbage collected since the
|
||||
-- previous run.
|
||||
--
|
||||
-- @tparam number timeout Timeout in seconds (e.g. 1.5).
|
||||
-- @tparam function callback Function to start.
|
||||
-- @treturn timer The timer object that was set up.
|
||||
-- @treturn timer The new timer object.
|
||||
-- @staticfct gears.timer.weak_start_new
|
||||
-- @see gears.timer.start_new
|
||||
function timer.weak_start_new(timeout, callback)
|
||||
|
@ -247,7 +257,7 @@ function timer.run_delayed_calls_now()
|
|||
delayed_calls = {}
|
||||
end
|
||||
|
||||
--- Call the given function at the end of the current main loop iteration
|
||||
--- Call the given function at the end of the current GLib event loop iteration.
|
||||
-- @tparam function callback The function that should be called
|
||||
-- @param ... Arguments to the callback function
|
||||
-- @staticfct gears.timer.delayed_call
|
||||
|
|
|
@ -1,22 +1,7 @@
|
|||
---------------------------------------------------------------------------
|
||||
-- Functions for setting the wallpaper.
|
||||
--
|
||||
-- There are two levels of functionality provided by this module:
|
||||
--
|
||||
-- The low-level functionality consists of two functions.
|
||||
-- @{set} an already-prepared wallpaper on all screens and @{prepare_context}
|
||||
-- prepares things to draw a new wallpaper.
|
||||
--
|
||||
-- The low-level API can for example be used to set solid red as a wallpaper
|
||||
-- (see @{gears.color} for details on the supported syntax):
|
||||
--
|
||||
-- gears.wallpaper.set("#ff0000")
|
||||
--
|
||||
-- Ontop of these low-level functions, the remaining functions implement more
|
||||
-- useful functionality. For example, given a screen object `s`, an image can be
|
||||
-- set as the wallpaper as follows:
|
||||
--
|
||||
-- gears.wallpaper.maximized("path/to/image.png", s)
|
||||
-- This module is deprecated, please use `awful.wallpaper`.
|
||||
--
|
||||
-- @author Uli Schlachter
|
||||
-- @copyright 2012 Uli Schlachter
|
||||
|
@ -51,8 +36,10 @@ end
|
|||
-- @param s The screen to set the wallpaper on or nil for all screens
|
||||
-- @return[1] The available geometry (table with entries width and height)
|
||||
-- @return[1] A cairo context that the wallpaper should be drawn to.
|
||||
-- @staticfct gears.wallpaper.prepare_context
|
||||
-- @deprecated gears.wallpaper.prepare_context
|
||||
function wallpaper.prepare_context(s)
|
||||
debug.deprecate("Use `awful.wallpaper`", {deprecated_in=5})
|
||||
|
||||
s = get_screen(s)
|
||||
|
||||
local root_width, root_height = root.size()
|
||||
|
@ -110,8 +97,10 @@ end
|
|||
-- @param pattern The wallpaper that should be set. This can be a cairo surface,
|
||||
-- a description for gears.color or a cairo pattern.
|
||||
-- @see gears.color
|
||||
-- @staticfct gears.wallpaper.set
|
||||
-- @deprecated gears.wallpaper.set
|
||||
function wallpaper.set(pattern)
|
||||
debug.deprecate("Use `awful.wallpaper`", {deprecated_in=5})
|
||||
|
||||
if cairo.Surface:is_type_of(pattern) then
|
||||
pattern = cairo.Pattern.create_for_surface(pattern)
|
||||
end
|
||||
|
@ -121,7 +110,7 @@ function wallpaper.set(pattern)
|
|||
if not cairo.Pattern:is_type_of(pattern) then
|
||||
error("wallpaper.set() called with an invalid argument")
|
||||
end
|
||||
root.wallpaper(pattern._native)
|
||||
root.wallpaper(pattern)
|
||||
end
|
||||
|
||||
--- Set a centered wallpaper.
|
||||
|
@ -132,8 +121,10 @@ end
|
|||
-- gears.color. The default is black.
|
||||
-- @param scale The scale factor for the wallpaper. Default is 1 (original size).
|
||||
-- @see gears.color
|
||||
-- @staticfct gears.wallpaper.centered
|
||||
-- @deprecated gears.wallpaper.centered
|
||||
function wallpaper.centered(surf, s, background, scale)
|
||||
debug.deprecate("Use `awful.wallpaper`", {deprecated_in=5})
|
||||
|
||||
local geom, cr = wallpaper.prepare_context(s)
|
||||
local original_surf = surf
|
||||
surf = surface.load_uncached(surf)
|
||||
|
@ -172,8 +163,10 @@ end
|
|||
-- @param s The screen whose wallpaper should be set. Can be nil, in which case
|
||||
-- all screens are set.
|
||||
-- @param offset This can be set to a table with entries x and y.
|
||||
-- @staticfct gears.wallpaper.tiled
|
||||
-- @deprecated gears.wallpaper.tiled
|
||||
function wallpaper.tiled(surf, s, offset)
|
||||
debug.deprecate("Use `awful.wallpaper`", {deprecated_in=5})
|
||||
|
||||
local _, cr = wallpaper.prepare_context(s)
|
||||
|
||||
if offset then
|
||||
|
@ -202,8 +195,10 @@ end
|
|||
-- @param ignore_aspect If this is true, the image's aspect ratio is ignored.
|
||||
-- The default is to honor the aspect ratio.
|
||||
-- @param offset This can be set to a table with entries x and y.
|
||||
-- @staticfct gears.wallpaper.maximized
|
||||
-- @deprecated gears.wallpaper.maximized
|
||||
function wallpaper.maximized(surf, s, ignore_aspect, offset)
|
||||
debug.deprecate("Use `awful.wallpaper`", {deprecated_in=5})
|
||||
|
||||
local geom, cr = wallpaper.prepare_context(s)
|
||||
local original_surf = surf
|
||||
surf = surface.load_uncached(surf)
|
||||
|
@ -243,8 +238,10 @@ end
|
|||
-- @param background The background color that should be used. Gets handled via
|
||||
-- gears.color. The default is black.
|
||||
-- @see gears.color
|
||||
-- @staticfct gears.wallpaper.fit
|
||||
-- @deprecated gears.wallpaper.fit
|
||||
function wallpaper.fit(surf, s, background)
|
||||
debug.deprecate("Use `awful.wallpaper`", {deprecated_in=5})
|
||||
|
||||
local geom, cr = wallpaper.prepare_context(s)
|
||||
local original_surf = surf
|
||||
surf = surface.load_uncached(surf)
|
||||
|
|
|
@ -70,12 +70,15 @@ end
|
|||
-- @beautiful beautiful.menubar_bg_focus
|
||||
-- @param color
|
||||
|
||||
--- Menubar font.
|
||||
-- @beautiful beautiful.menubar_font
|
||||
-- @param[opt=beautiful.font] font
|
||||
|
||||
|
||||
-- menubar
|
||||
local menubar = { menu_entries = {} }
|
||||
menubar.menu_gen = require("menubar.menu_gen")
|
||||
menubar.utils = require("menubar.utils")
|
||||
local compute_text_width = menubar.utils.compute_text_width
|
||||
|
||||
-- Options section
|
||||
|
||||
|
@ -119,10 +122,9 @@ menubar.right_label = "▶▶"
|
|||
-- @tfield[opt="◀◀"] string left_label
|
||||
menubar.left_label = "◀◀"
|
||||
|
||||
-- awful.widget.common.list_update adds three times a margin of dpi(4)
|
||||
-- for each item:
|
||||
-- @tfield number list_interspace
|
||||
local list_interspace = theme.xresources.apply_dpi(4) * 3
|
||||
-- awful.widget.common.list_update adds spacing of dpi(4) between items.
|
||||
-- @tfield number list_spacing
|
||||
local list_spacing = theme.xresources.apply_dpi(4)
|
||||
|
||||
--- Allows user to specify custom parameters for prompt.run function
|
||||
-- (like colors). This will merge with the default parameters, overriding affected values.
|
||||
|
@ -149,7 +151,7 @@ end
|
|||
|
||||
--- Get how the menu item should be displayed.
|
||||
-- @param o The menu item.
|
||||
-- @return item name, item background color, background image, item icon.
|
||||
-- @return item name, item background color, background image, item icon, item args.
|
||||
local function label(o)
|
||||
local fg_color = theme.menubar_fg_normal or theme.menu_fg_normal or theme.fg_normal
|
||||
local bg_color = theme.menubar_bg_normal or theme.menu_bg_normal or theme.bg_normal
|
||||
|
@ -160,7 +162,8 @@ local function label(o)
|
|||
return colortext(gstring.xml_escape(o.name), fg_color),
|
||||
bg_color,
|
||||
nil,
|
||||
o.icon
|
||||
o.icon,
|
||||
o.icon and {icon_size=instance.geometry.height}
|
||||
end
|
||||
|
||||
local function load_count_table()
|
||||
|
@ -225,6 +228,11 @@ end
|
|||
-- @tparam number|screen scr Screen
|
||||
-- @return table List of items for current page.
|
||||
local function get_current_page(all_items, query, scr)
|
||||
|
||||
local compute_text_width = function(text, s)
|
||||
return wibox.widget.textbox.get_markup_geometry(text, s, instance.font)['width']
|
||||
end
|
||||
|
||||
scr = get_screen(scr)
|
||||
if not instance.prompt.width then
|
||||
instance.prompt.width = compute_text_width(instance.prompt.prompt, scr)
|
||||
|
@ -235,16 +243,19 @@ local function get_current_page(all_items, query, scr)
|
|||
if not menubar.right_label_width then
|
||||
menubar.right_label_width = compute_text_width(menubar.right_label, scr)
|
||||
end
|
||||
local border_width = theme.menubar_border_width or theme.menu_border_width or 0
|
||||
local available_space = instance.geometry.width - menubar.right_margin -
|
||||
menubar.right_label_width - menubar.left_label_width -
|
||||
compute_text_width(query, scr) - instance.prompt.width
|
||||
compute_text_width(query..' ', scr) - instance.prompt.width - border_width * 2
|
||||
-- space character is added as input cursor placeholder
|
||||
|
||||
local width_sum = 0
|
||||
local current_page = {}
|
||||
for i, item in ipairs(all_items) do
|
||||
item.width = item.width or
|
||||
compute_text_width(item.name, scr) +
|
||||
(item.icon and instance.geometry.height or 0) + list_interspace
|
||||
item.width = item.width or (
|
||||
compute_text_width(label(item), scr) +
|
||||
(item.icon and (instance.geometry.height + list_spacing) or 0) + list_spacing * 2
|
||||
)
|
||||
if width_sum + item.width > available_space then
|
||||
if current_item < i then
|
||||
table.insert(current_page, { name = menubar.right_label, icon = nil })
|
||||
|
@ -449,6 +460,7 @@ function menubar.show(scr)
|
|||
local bg_color = theme.menubar_bg_normal or theme.menu_bg_normal or theme.bg_normal
|
||||
local border_width = theme.menubar_border_width or theme.menu_border_width or 0
|
||||
local border_color = theme.menubar_border_color or theme.menu_border_color
|
||||
local font = theme.menubar_font or theme.font or "Monospace 10"
|
||||
|
||||
if not instance then
|
||||
-- Add to each category the name of its key in all_categories
|
||||
|
@ -467,11 +479,13 @@ function menubar.show(scr)
|
|||
fg = fg_color,
|
||||
border_width = border_width,
|
||||
border_color = border_color,
|
||||
font = font,
|
||||
},
|
||||
widget = common_args.w,
|
||||
prompt = awful.widget.prompt(),
|
||||
query = nil,
|
||||
count_table = nil,
|
||||
font = font,
|
||||
}
|
||||
local layout = wibox.layout.fixed.horizontal()
|
||||
layout:add(instance.prompt)
|
||||
|
@ -490,7 +504,7 @@ function menubar.show(scr)
|
|||
local geometry = menubar.geometry
|
||||
instance.geometry = {x = geometry.x or scrgeom.x,
|
||||
y = geometry.y or scrgeom.y,
|
||||
height = geometry.height or gmath.round(theme.get_font_height() * 1.5),
|
||||
height = geometry.height or gmath.round(theme.get_font_height(font) * 1.5),
|
||||
width = (geometry.width or scrgeom.width) - border_width * 2}
|
||||
instance.wibox:geometry(instance.geometry)
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ local glib = lgi.GLib
|
|||
local w_textbox = require("wibox.widget.textbox")
|
||||
local gdebug = require("gears.debug")
|
||||
local protected_call = require("gears.protected_call")
|
||||
local gstring = require("gears.string")
|
||||
local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1)
|
||||
|
||||
local utils = {}
|
||||
|
@ -410,6 +409,8 @@ function utils.parse_dir(dir_path, callback)
|
|||
end)
|
||||
end
|
||||
|
||||
-- luacov: disable
|
||||
|
||||
function utils.compute_textbox_width(textbox, s)
|
||||
gdebug.deprecate("Use 'width, _ = textbox:get_preferred_size(s)' directly.", {deprecated_in=4})
|
||||
s = screen[s or mouse.screen]
|
||||
|
@ -417,16 +418,13 @@ function utils.compute_textbox_width(textbox, s)
|
|||
return w
|
||||
end
|
||||
|
||||
--- Compute text width.
|
||||
-- @tparam str text Text.
|
||||
-- @tparam number|screen s Screen
|
||||
-- @treturn int Text width.
|
||||
-- @staticfct menubar.utils.compute_text_width
|
||||
function utils.compute_text_width(text, s)
|
||||
local w, _ = w_textbox(gstring.xml_escape(text)):get_preferred_size(s)
|
||||
return w
|
||||
function utils.compute_text_width(text, s, font)
|
||||
gdebug.deprecate("Use 'width = textbox.get_markup_geometry(text, s, font)['width']'.", {deprecated_in=4})
|
||||
return w_textbox.get_markup_geometry(text, s, font)['width']
|
||||
end
|
||||
|
||||
-- luacov: enable
|
||||
|
||||
return utils
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -57,7 +57,13 @@ local action = {}
|
|||
-- @propemits true false
|
||||
|
||||
--- When a notification is invoked.
|
||||
--
|
||||
-- Note that it is possible to call `:invoke()` without a notification object.
|
||||
-- It is possible the `notification` parameter will be nil.
|
||||
--
|
||||
-- @signal invoked
|
||||
-- @tparam naughty.action action The action.
|
||||
-- @tparam naughty.notification|nil notification The notification, if known.
|
||||
|
||||
function action:get_selected()
|
||||
return self._private.selected
|
||||
|
|
|
@ -191,7 +191,13 @@ naughty.notifications = { suspended = { }, _expired = {{}} }
|
|||
|
||||
naughty._active = {}
|
||||
|
||||
screen.connect_for_each_screen(function(s)
|
||||
local function get_screen(s)
|
||||
return s and capi.screen[s]
|
||||
end
|
||||
|
||||
local function init_screen(s)
|
||||
if naughty.notifications[s] then return end
|
||||
|
||||
naughty.notifications[s] = {
|
||||
top_left = {},
|
||||
top_middle = {},
|
||||
|
@ -201,7 +207,9 @@ screen.connect_for_each_screen(function(s)
|
|||
bottom_right = {},
|
||||
middle = {},
|
||||
}
|
||||
end)
|
||||
end
|
||||
|
||||
screen.connect_for_each_screen(init_screen)
|
||||
|
||||
capi.screen.connect_signal("removed", function(scr)
|
||||
-- Allow the notifications to be moved to another screen.
|
||||
|
@ -214,15 +222,18 @@ capi.screen.connect_signal("removed", function(scr)
|
|||
naughty.emit_signal("request::screen", n, "removed", {})
|
||||
end
|
||||
end
|
||||
|
||||
for _, n in ipairs(naughty._active) do
|
||||
if n._private.args and get_screen(n._private.args.screen) == scr then
|
||||
n._private.args.screen = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Destroy all notifications on this screen
|
||||
naughty.destroy_all_notifications({scr})
|
||||
naughty.notifications[scr] = nil
|
||||
end)
|
||||
|
||||
local function get_screen(s)
|
||||
return s and capi.screen[s]
|
||||
end
|
||||
|
||||
local function remove_from_index(n)
|
||||
for _, positions in pairs(naughty.notifications) do
|
||||
for _, ns in pairs(positions) do
|
||||
|
@ -646,6 +657,10 @@ local function register(notification, args)
|
|||
|
||||
assert(s)
|
||||
|
||||
if not naughty.notifications[s] then
|
||||
init_screen(get_screen(s))
|
||||
end
|
||||
|
||||
-- insert the notification to the table
|
||||
table.insert(naughty._active, notification)
|
||||
table.insert(naughty.notifications[s][notification.position], notification)
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
-- @author Emmanuel Lepage Vallee <elv1313@gmail.com>
|
||||
-- @copyright 2017 Emmanuel Lepage Vallee
|
||||
-- @popupmod naughty.layout.box
|
||||
-- @supermodule awful.popup
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
local capi = {screen=screen}
|
||||
|
|
|
@ -62,6 +62,12 @@ screen.connect_for_each_screen(function(s)
|
|||
}
|
||||
end)
|
||||
|
||||
capi.screen.connect_signal("removed", function(s)
|
||||
timer.delayed_call(function()
|
||||
current_notifications[s] = nil
|
||||
end)
|
||||
end)
|
||||
|
||||
--- Sum heights of notifications at position
|
||||
--
|
||||
-- @param s Screen to use
|
||||
|
@ -128,7 +134,7 @@ local function get_offset(s, position, idx, width, height)
|
|||
local find_old_to_replace = function()
|
||||
for i = 1, idx-1 do
|
||||
local n = current_notifications[s][position][i]
|
||||
if n.timeout > 0 then
|
||||
if n and n.timeout > 0 then
|
||||
return n
|
||||
end
|
||||
end
|
||||
|
|
|
@ -337,7 +337,10 @@ local function new(_, args)
|
|||
update_style(wdg)
|
||||
|
||||
wdg._private.default_buttons = gtable.join(
|
||||
abutton({ }, 1, function(a) a:invoke(args.notification) end)
|
||||
abutton({ }, 1, function(a)
|
||||
local notif = wdg._private.notification or args.notification
|
||||
a:invoke(notif)
|
||||
end)
|
||||
)
|
||||
|
||||
return wdg
|
||||
|
|
|
@ -570,6 +570,27 @@ function notification:set_timeout(timeout)
|
|||
self:emit_signal("property::timeout", timeout)
|
||||
end
|
||||
|
||||
function notification:get_message()
|
||||
-- This property was called "text" in older versions.
|
||||
-- Some modules like `lain` abused of the presets (they
|
||||
-- had little choice at the time) to set the message on
|
||||
-- an existing popup.
|
||||
local p = rawget(self, "preset") or {}
|
||||
local message = self._private.message or p.message or ""
|
||||
|
||||
if message == "" and p.text and p.text ~= "" then
|
||||
gdebug.deprecate(
|
||||
"Using the preset configuration to set the notification "..
|
||||
"message is not supported. Please use `n.message = 'text'`.",
|
||||
{deprecated_in=5}
|
||||
)
|
||||
|
||||
return p.text
|
||||
end
|
||||
|
||||
return message
|
||||
end
|
||||
|
||||
function notification:set_text(txt)
|
||||
gdebug.deprecate(
|
||||
"The `text` attribute is deprecated, use `message`",
|
||||
|
@ -861,7 +882,15 @@ local function select_legacy_preset(n, args)
|
|||
))
|
||||
|
||||
for k, v in pairs(n.preset) do
|
||||
n._private[k] = v
|
||||
-- Don't keep a strong reference to the screen, Lua 5.1 GC wont be
|
||||
-- smart enough to unwind the mess of circular weak references.
|
||||
if k ~= "screen" then
|
||||
n._private[k] = v
|
||||
end
|
||||
end
|
||||
|
||||
if n.preset.screen then
|
||||
n._private.weak_screen[1] = capi.screen[n.preset.screen]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -160,6 +160,15 @@ end
|
|||
-- @staticfct ruled.notification.apply
|
||||
function module.apply(n)
|
||||
local callbacks, props = {}, {}
|
||||
|
||||
if n.preset then
|
||||
for k, v in pairs(n.preset) do
|
||||
if not n._private[v] then
|
||||
props[k] = v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for _, v in ipairs(nrules._matching_source) do
|
||||
v.callback(nrules, n, props, callbacks)
|
||||
end
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
-- @author Emmanuel Lepage Vallee <elv1313@gmail.com>
|
||||
-- @copyright 2013 Emmanuel Lepage Vallee
|
||||
-- @containermod wibox.container.arcchart
|
||||
-- @supermodule wibox.widget.base
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
@ -357,10 +358,6 @@ function arcchart.mt:__call(...)
|
|||
return new(...)
|
||||
end
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return setmetatable(arcchart, arcchart.mt)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
-- @author Uli Schlachter
|
||||
-- @copyright 2010 Uli Schlachter
|
||||
-- @containermod wibox.container.background
|
||||
-- @supermodule wibox.widget.base
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local base = require("wibox.widget.base")
|
||||
|
@ -484,10 +485,6 @@ function background.mt:__call(...)
|
|||
return new(...)
|
||||
end
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return setmetatable(background, background.mt)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
-- @author Lukáš Hrázký
|
||||
-- @copyright 2012 Lukáš Hrázký
|
||||
-- @containermod wibox.container.constraint
|
||||
-- @supermodule wibox.widget.base
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
@ -176,10 +177,6 @@ function constraint.mt:__call(...)
|
|||
return new(...)
|
||||
end
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return setmetatable(constraint, constraint.mt)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -17,6 +17,7 @@ return setmetatable({
|
|||
radialprogressbar = require("wibox.container.radialprogressbar");
|
||||
arcchart = require("wibox.container.arcchart");
|
||||
place = require("wibox.container.place");
|
||||
tile = require("wibox.container.tile");
|
||||
}, {__call = function(_, args) return base.make_widget_declarative(args) end})
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
-- @author Uli Schlachter
|
||||
-- @copyright 2010 Uli Schlachter
|
||||
-- @containermod wibox.container.margin
|
||||
-- @supermodule wibox.widget.base
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local pairs = pairs
|
||||
|
@ -238,10 +239,6 @@ function margin.mt:__call(...)
|
|||
return new(...)
|
||||
end
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return setmetatable(margin, margin.mt)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
-- @author dodo
|
||||
-- @copyright 2012 dodo
|
||||
-- @containermod wibox.container.mirror
|
||||
-- @supermodule wibox.widget.base
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local type = type
|
||||
|
@ -129,10 +130,6 @@ function mirror.mt:__call(...)
|
|||
return new(...)
|
||||
end
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return setmetatable(mirror, mirror.mt)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
-- @author Emmanuel Lepage Vallee <elv1313@gmail.com>
|
||||
-- @copyright 2016 Emmanuel Lepage Vallee
|
||||
-- @containermod wibox.container.place
|
||||
-- @supermodule wibox.widget.base
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
@ -22,13 +23,8 @@ local align_fct = {
|
|||
}
|
||||
align_fct.top, align_fct.bottom = align_fct.left, align_fct.right
|
||||
|
||||
-- Layout this layout
|
||||
function place:layout(context, width, height)
|
||||
|
||||
if not self._private.widget then
|
||||
return
|
||||
end
|
||||
|
||||
-- Shared with some subclasses like the `tiled` and `scaled` modules.
|
||||
function place:_layout(context, width, height)
|
||||
local w, h = base.fit_widget(self, context, self._private.widget, width, height)
|
||||
|
||||
if self._private.content_fill_horizontal then
|
||||
|
@ -44,6 +40,21 @@ function place:layout(context, width, height)
|
|||
|
||||
local x, y = align_fct[halign](w, width), align_fct[valign](h, height)
|
||||
|
||||
-- Sub pixels makes everything blurry. This is now what people expect.
|
||||
x, y = math.floor(x), math.floor(y)
|
||||
|
||||
return x, y, w, h
|
||||
end
|
||||
|
||||
-- Layout this layout
|
||||
function place:layout(context, width, height)
|
||||
|
||||
if not self._private.widget then
|
||||
return
|
||||
end
|
||||
|
||||
local x, y, w, h = self:_layout(context, width, height)
|
||||
|
||||
return { base.place_widget_at(self._private.widget, x, y, w, h) }
|
||||
end
|
||||
|
||||
|
@ -96,6 +107,8 @@ end
|
|||
-- * *center* (default)
|
||||
-- * *bottom*
|
||||
--
|
||||
--@DOC_wibox_container_place_valign_EXAMPLE@
|
||||
--
|
||||
-- @property valign
|
||||
-- @tparam[opt="center"] string valign
|
||||
-- @propemits true false
|
||||
|
@ -108,6 +121,8 @@ end
|
|||
-- * *center* (default)
|
||||
-- * *right*
|
||||
--
|
||||
--@DOC_wibox_container_place_halign_EXAMPLE@
|
||||
--
|
||||
-- @property halign
|
||||
-- @tparam[opt="center"] string halign
|
||||
-- @propemits true false
|
||||
|
@ -158,6 +173,8 @@ end
|
|||
|
||||
--- Stretch the contained widget so it takes all the vertical space.
|
||||
--
|
||||
--@DOC_wibox_container_place_content_fill_vertical_EXAMPLE@
|
||||
--
|
||||
-- @property content_fill_vertical
|
||||
-- @tparam[opt=false] boolean content_fill_vertical
|
||||
-- @propemits true false
|
||||
|
@ -170,6 +187,8 @@ end
|
|||
|
||||
--- Stretch the contained widget so it takes all the horizontal space.
|
||||
--
|
||||
--@DOC_wibox_container_place_content_fill_horizontal_EXAMPLE@
|
||||
--
|
||||
-- @property content_fill_horizontal
|
||||
-- @tparam[opt=false] boolean content_fill_horizontal
|
||||
-- @propemits true false
|
||||
|
@ -203,10 +222,6 @@ function place.mt:__call(...)
|
|||
return new(...)
|
||||
end
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return setmetatable(place, place.mt)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
-- @author Emmanuel Lepage Vallee <elv1313@gmail.com>
|
||||
-- @copyright 2013 Emmanuel Lepage Vallee
|
||||
-- @containermod wibox.container.radialprogressbar
|
||||
-- @supermodule wibox.widget.base
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
@ -281,10 +282,6 @@ function radialprogressbar.mt:__call(...)
|
|||
return new(...)
|
||||
end
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return setmetatable(radialprogressbar, radialprogressbar.mt)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
-- @author Uli Schlachter
|
||||
-- @copyright 2010 Uli Schlachter
|
||||
-- @containermod wibox.container.rotate
|
||||
-- @supermodule wibox.widget.base
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local error = error
|
||||
|
@ -149,10 +150,6 @@ function rotate.mt:__call(...)
|
|||
return new(...)
|
||||
end
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return setmetatable(rotate, rotate.mt)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
-- @author Uli Schlachter (based on ideas from Saleur Geoffrey)
|
||||
-- @copyright 2015 Uli Schlachter
|
||||
-- @containermod wibox.container.scroll
|
||||
-- @supermodule wibox.widget.base
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local cache = require("gears.cache")
|
||||
|
@ -549,10 +550,6 @@ function scroll.step_functions.waiting_nonlinear_back_and_forth(elapsed, size, v
|
|||
return (size - visible_size) * state
|
||||
end
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return scroll
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -0,0 +1,212 @@
|
|||
---------------------------------------------------------------------------
|
||||
-- Replicate the content of the widget over and over.
|
||||
--
|
||||
-- This contained is intended to be used for wallpapers. It currently doesn't
|
||||
-- support mouse input in the replicated tiles.
|
||||
--
|
||||
--@DOC_wibox_container_defaults_tile_EXAMPLE@
|
||||
-- @author Emmanuel Lepage-Vallee
|
||||
-- @copyright 2021 Emmanuel Lepage-Vallee
|
||||
-- @containermod wibox.container.tile
|
||||
-- @supermodule wibox.container.place
|
||||
local place = require("wibox.container.place")
|
||||
local cairo = require("lgi").cairo
|
||||
local widget = require("wibox.widget")
|
||||
local gtable = require("gears.table")
|
||||
|
||||
local module = {mt = {}}
|
||||
|
||||
function module:draw(context, cr, width, height)
|
||||
if not self._private.tiled then return end
|
||||
if not self._private.widget then return end
|
||||
|
||||
local x, y, w, h = self:_layout(context, width, height)
|
||||
|
||||
local vspace, hspace = self.vertical_spacing, self.horizontal_spacing
|
||||
local vcrop, hcrop = self.vertical_crop, self.horizontal_crop
|
||||
|
||||
-- In theory we could avoid a few repaints by tracking the child widget
|
||||
-- redraw independently from the container redraw. However it is nearly a
|
||||
-- 1:1 march, so there's little reasons to do it.
|
||||
if not self._private.surface then
|
||||
self._private.surface = cairo.ImageSurface(cairo.Format.ARGB32, w+hspace, h+vspace)
|
||||
self._private.cr = cairo.Context(self._private.surface)
|
||||
self._private.cr:set_source(cr:get_source())
|
||||
self._private.pattern = cairo.Pattern.create_for_surface(self._private.surface)
|
||||
self._private.pattern.extend = cairo.Extend.REPEAT
|
||||
self._private.cr:translate(math.ceil(hspace), math.ceil(vspace))
|
||||
else
|
||||
self._private.cr:set_operator(cairo.Operator.CLEAR)
|
||||
self._private.cr:set_source_rgba(0,0,0,1)
|
||||
self._private.cr:paint()
|
||||
self._private.cr:set_operator(cairo.Operator.SOURCE)
|
||||
end
|
||||
|
||||
widget.draw_to_cairo_context(self._private.widget, self._private.cr, w, h, context)
|
||||
|
||||
cr:save()
|
||||
|
||||
-- We do our own clip.
|
||||
cr:reset_clip()
|
||||
|
||||
local x0, y0 = 0, 0
|
||||
|
||||
-- Avoid painting incomplete tiles
|
||||
if hcrop and x ~= 0 then
|
||||
x0 = x - math.floor(x/(w+hspace))*(w+hspace)
|
||||
end
|
||||
|
||||
if hcrop then
|
||||
width = x + w + hspace + math.floor((width - (x + w + hspace))/(w+hspace))*(w+hspace)
|
||||
end
|
||||
|
||||
if vcrop and y ~= 0 then
|
||||
y0 = y - math.floor(y/(h+vspace))*(h+vspace)
|
||||
end
|
||||
|
||||
if vcrop then
|
||||
height = (y+h+vspace) + math.floor((height - (y+h+vspace))/(h+vspace))*(h+vspace)
|
||||
end
|
||||
|
||||
-- Create a clip around the "real" widget in case there is some transparency.
|
||||
cr:rectangle(x0, y0, width-x0, y-y0)
|
||||
cr:rectangle(x0, y0, x-hspace-x0, height-y0)
|
||||
cr:rectangle(x+hspace+w, y0, width - (x+w+hspace), height-y0)
|
||||
cr:rectangle(x, y+vspace+h, w+hspace, height - (y+h+vspace))
|
||||
cr:clip()
|
||||
|
||||
-- Make sure the tiles are aligned with the child widget.
|
||||
cr:translate(x - hspace, y - vspace)
|
||||
|
||||
|
||||
-- Use OVER rather than SOURCE to preserve the alpha.
|
||||
cr.operator = cairo.Operator.OVER
|
||||
cr.source = self._private.pattern
|
||||
cr:paint()
|
||||
|
||||
cr:restore()
|
||||
end
|
||||
|
||||
--- The horizontal spacing between the tiled.
|
||||
--
|
||||
--@DOC_wibox_container_tile_horizontal_spacing_EXAMPLE@
|
||||
--
|
||||
-- @property horizontal_spacing
|
||||
-- @tparam number horizontal_spacing
|
||||
-- @propemits true false
|
||||
-- @see vertical_spacing
|
||||
|
||||
--- The vertical spacing between the tiled.
|
||||
--
|
||||
--@DOC_wibox_container_tile_vertical_spacing_EXAMPLE@
|
||||
--
|
||||
-- @property vertical_spacing
|
||||
-- @tparam number vertical_spacing
|
||||
-- @propemits true false
|
||||
-- @see horizontal_spacing
|
||||
|
||||
--- Avoid painting incomplete horizontal tiles.
|
||||
--
|
||||
--@DOC_wibox_container_tile_horizontal_crop_EXAMPLE@
|
||||
--
|
||||
-- @property horizontal_crop
|
||||
-- @tparam[opt=false] boolean tiled
|
||||
-- @see vertical_crop
|
||||
|
||||
--- Avoid painting incomplete vertical tiles.
|
||||
--
|
||||
--@DOC_wibox_container_tile_vertical_crop_EXAMPLE@
|
||||
--
|
||||
-- @property vertical_crop
|
||||
-- @tparam[opt=false] boolean tiled
|
||||
-- @see horizontal_crop
|
||||
|
||||
--- Enable or disable the tiling.
|
||||
--
|
||||
-- When set to `false`, this container behaves exactly like
|
||||
-- `wibox.container.place`.
|
||||
--
|
||||
--@DOC_wibox_container_tile_tiled_EXAMPLE@
|
||||
--
|
||||
-- @property tiled
|
||||
-- @tparam[opt=true] boolean tiled
|
||||
|
||||
local defaults = {
|
||||
horizontal_spacing = 0,
|
||||
vertical_spacing = 0,
|
||||
tiled = true,
|
||||
horizontal_crop = false,
|
||||
vertical_crop = false,
|
||||
}
|
||||
|
||||
for prop in pairs(defaults) do
|
||||
|
||||
module["set_"..prop] = function(self, value)
|
||||
self._private[prop] = value
|
||||
self:emit_signal("widget::redraw_needed", value)
|
||||
end
|
||||
|
||||
module["get_"..prop] = function(self)
|
||||
if self._private[prop] == nil then
|
||||
return defaults[prop]
|
||||
end
|
||||
|
||||
return self._private[prop]
|
||||
end
|
||||
end
|
||||
|
||||
local function new(_, args)
|
||||
args = args or {}
|
||||
local ret = place(args.widget, args.halign, args.valign)
|
||||
gtable.crush(ret, module, true)
|
||||
ret._private.tiled = true
|
||||
|
||||
local function redraw()
|
||||
ret:emit_signal("widget::redraw_needed")
|
||||
end
|
||||
|
||||
-- Resize the pattern as needed.
|
||||
local function reset()
|
||||
if ret._private.surface then
|
||||
ret._private.surface:finish()
|
||||
end
|
||||
|
||||
ret._private.cr = nil
|
||||
ret._private.surface = nil
|
||||
ret._private.pattern = nil
|
||||
end
|
||||
|
||||
local w = nil
|
||||
|
||||
ret:connect_signal("property::widget", function()
|
||||
reset()
|
||||
|
||||
if w then
|
||||
w:disconnect_signal("widget::redraw_needed", redraw)
|
||||
w:disconnect_signal("widget::layout_changed", reset)
|
||||
end
|
||||
|
||||
w = ret._private.widget
|
||||
|
||||
if w then
|
||||
w:connect_signal("widget::redraw_needed", redraw)
|
||||
w:connect_signal("widget::layout_changed", reset)
|
||||
end
|
||||
end)
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
--- Create a new tile container.
|
||||
-- @tparam table args
|
||||
-- @tparam wibox.widget widget args.widget The widget to tile.
|
||||
-- @tparam string args.halign Either `left`, `right` or `center`.
|
||||
-- @tparam string args.valign Either `top`, `bottom` or `center`.
|
||||
-- @constructorfct wibox.container.tile
|
||||
function module.mt:__call(...)
|
||||
return new(...)
|
||||
end
|
||||
|
||||
return setmetatable(module, module.mt)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
|
@ -1,9 +1,29 @@
|
|||
---------------------------------------------------------------------------
|
||||
-- The `align` layout has three slots for child widgets. On its main axis, it
|
||||
-- will use as much space as is available to it and distribute that to its child
|
||||
-- widgets by stretching or shrinking them based on the chosen @{expand}
|
||||
-- strategy.
|
||||
-- On its secondary axis, the biggest child widget determines the size of the
|
||||
-- layout, but smaller widgets will not be stretched to match it.
|
||||
--
|
||||
-- In its default configuration, the layout will give the first and third
|
||||
-- widgets only the minimum space they ask for and it aligns them to the outer
|
||||
-- edges. The remaining space between them is made available to the widget in
|
||||
-- slot two.
|
||||
--
|
||||
-- This layout is most commonly used to split content into left/top, center and
|
||||
-- right/bottom sections. As such, it is usually seen as the root layout in
|
||||
-- @{awful.wibar}.
|
||||
--
|
||||
-- You may also fill just one or two of the widget slots, the @{expand} algorithm
|
||||
-- will adjust accordingly.
|
||||
--
|
||||
--@DOC_wibox_layout_defaults_align_EXAMPLE@
|
||||
--
|
||||
-- @author Uli Schlachter
|
||||
-- @copyright 2010 Uli Schlachter
|
||||
-- @layoutmod wibox.layout.align
|
||||
-- @supermodule wibox.widget.base
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local table = table
|
||||
|
@ -139,8 +159,10 @@ function align:layout(context, width, height)
|
|||
return result
|
||||
end
|
||||
|
||||
--- Set the layout's first widget.
|
||||
-- This is the widget that is at the left/top
|
||||
--- The widget in slot one.
|
||||
--
|
||||
-- This is the widget that is at the left/top.
|
||||
--
|
||||
-- @property first
|
||||
-- @tparam widget first
|
||||
-- @propemits true false
|
||||
|
@ -154,7 +176,10 @@ function align:set_first(widget)
|
|||
self:emit_signal("property::first", widget)
|
||||
end
|
||||
|
||||
--- Set the layout's second widget. This is the centered one.
|
||||
--- The widget in slot two.
|
||||
--
|
||||
-- This is the centered one.
|
||||
--
|
||||
-- @property second
|
||||
-- @tparam widget second
|
||||
-- @propemits true false
|
||||
|
@ -168,8 +193,10 @@ function align:set_second(widget)
|
|||
self:emit_signal("property::second", widget)
|
||||
end
|
||||
|
||||
--- Set the layout's third widget.
|
||||
-- This is the widget that is at the right/bottom
|
||||
--- The widget in slot three.
|
||||
--
|
||||
-- This is the widget that is at the right/bottom.
|
||||
--
|
||||
-- @property third
|
||||
-- @tparam widget third
|
||||
-- @propemits true false
|
||||
|
@ -226,23 +253,27 @@ function align:fit(context, orig_width, orig_height)
|
|||
return used_in_dir, used_in_other
|
||||
end
|
||||
|
||||
--- Set the expand mode which determines how sub widgets expand to take up
|
||||
--- Set the expand mode, which determines how child widgets expand to take up
|
||||
-- unused space.
|
||||
--
|
||||
-- The following values are valid:
|
||||
--
|
||||
-- * "inside" - Default option. Size of outside widgets is determined using
|
||||
-- their fit function. Second, middle, or center widget expands to fill
|
||||
-- remaining space.
|
||||
-- * "outside" - Center widget is sized using its fit function and placed in
|
||||
-- the center of the allowed space. Outside widgets expand (or contract) to
|
||||
-- fill remaining space on their side.
|
||||
-- * "none" - All widgets are sized using their fit function, drawn to only the
|
||||
-- returned space, or remaining space, whichever is smaller. Center widget
|
||||
-- gets priority.
|
||||
-- * `"inside"`: The widgets in slot one and three are set to their minimal
|
||||
-- required size. The widget in slot two is then given the remaining space.
|
||||
-- This is the default behaviour.
|
||||
-- * `"outside"`: The widget in slot two is set to its minimal required size and
|
||||
-- placed in the center of the space available to the layout. The other
|
||||
-- widgets are then given the remaining space on either side.
|
||||
-- If the center widget requires all available space, the outer widgets are
|
||||
-- not drawn at all.
|
||||
-- * `"none"`: All widgets are given their minimal required size or the
|
||||
-- remaining space, whichever is smaller. The center widget gets priority.
|
||||
--
|
||||
-- Attempting to set any other value than one of those three will fall back to
|
||||
-- `"inside"`.
|
||||
--
|
||||
-- @property expand
|
||||
-- @tparam[opt=inside] string mode How to use unused space.
|
||||
-- @tparam[opt="inside"] string mode How to use unused space.
|
||||
|
||||
function align:set_expand(mode)
|
||||
if mode == "none" or mode == "outside" then
|
||||
|
@ -282,14 +313,16 @@ local function get_layout(dir, first, second, third)
|
|||
return ret
|
||||
end
|
||||
|
||||
--- Returns a new horizontal align layout. An align layout can display up to
|
||||
-- three widgets. The widget set via :set_left() is left-aligned. :set_right()
|
||||
-- sets a widget which will be right-aligned. The remaining space between those
|
||||
-- two will be given to the widget set via :set_middle().
|
||||
--- Returns a new horizontal align layout.
|
||||
--
|
||||
-- The three widget slots are aligned left, center and right.
|
||||
--
|
||||
-- Additionally, this creates the aliases `set_left`, `set_middle` and
|
||||
-- `set_right` to assign @{first}, @{second} and @{third} respectively.
|
||||
-- @constructorfct wibox.layout.align.horizontal
|
||||
-- @tparam[opt] widget left Widget to be put to the left.
|
||||
-- @tparam[opt] widget middle Widget to be put to the middle.
|
||||
-- @tparam[opt] widget right Widget to be put to the right.
|
||||
-- @tparam[opt] widget left Widget to be put in slot one.
|
||||
-- @tparam[opt] widget middle Widget to be put in slot two.
|
||||
-- @tparam[opt] widget right Widget to be put in slot three.
|
||||
function align.horizontal(left, middle, right)
|
||||
local ret = get_layout("x", left, middle, right)
|
||||
|
||||
|
@ -300,14 +333,16 @@ function align.horizontal(left, middle, right)
|
|||
return ret
|
||||
end
|
||||
|
||||
--- Returns a new vertical align layout. An align layout can display up to
|
||||
-- three widgets. The widget set via :set_top() is top-aligned. :set_bottom()
|
||||
-- sets a widget which will be bottom-aligned. The remaining space between those
|
||||
-- two will be given to the widget set via :set_middle().
|
||||
--- Returns a new vertical align layout.
|
||||
--
|
||||
-- The three widget slots are aligned top, center and bottom.
|
||||
--
|
||||
-- Additionally, this creates the aliases `set_top`, `set_middle` and
|
||||
-- `set_bottom` to assign @{first}, @{second} and @{third} respectively.
|
||||
-- @constructorfct wibox.layout.align.vertical
|
||||
-- @tparam[opt] widget top Widget to be put to the top.
|
||||
-- @tparam[opt] widget middle Widget to be put to the middle.
|
||||
-- @tparam[opt] widget bottom Widget to be put to the right.
|
||||
-- @tparam[opt] widget top Widget to be put in slot one.
|
||||
-- @tparam[opt] widget middle Widget to be put in slot two.
|
||||
-- @tparam[opt] widget bottom Widget to be put in slot three.
|
||||
function align.vertical(top, middle, bottom)
|
||||
local ret = get_layout("y", top, middle, bottom)
|
||||
|
||||
|
@ -320,10 +355,6 @@ end
|
|||
|
||||
--@DOC_fixed_COMMON@
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return align
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -1,9 +1,26 @@
|
|||
---------------------------------------------------------------------------
|
||||
-- A `fixed` layout may be initialized with any number of child widgets, and
|
||||
-- during runtime widgets may be added and removed dynamically.
|
||||
--
|
||||
-- On the main axis, child widgets are given a fixed size of exactly as much
|
||||
-- space as they ask for. The layout will then resize according to the sum of
|
||||
-- all child widgets. If the space available to the layout is not enough to
|
||||
-- include all child widgets, the excessive ones are not drawn at all.
|
||||
--
|
||||
-- Additionally, the layout allows adding empty spacing or even placing a custom
|
||||
-- spacing widget between the child widget.
|
||||
--
|
||||
-- On its secondary axis, the layout's size is determined by the largest child
|
||||
-- widget. Smaller child widgets are then placed with the same size.
|
||||
-- Therefore, child widgets may ignore their `forced_width` or `forced_height`
|
||||
-- properties for vertical and horizontal layouts respectively.
|
||||
--
|
||||
--@DOC_wibox_layout_defaults_fixed_EXAMPLE@
|
||||
--
|
||||
-- @author Uli Schlachter
|
||||
-- @copyright 2010 Uli Schlachter
|
||||
-- @layoutmod wibox.layout.fixed
|
||||
-- @supermodule wibox.widget.base
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1)
|
||||
|
@ -20,45 +37,96 @@ local fixed = {}
|
|||
-- @param height The available height.
|
||||
function fixed:layout(context, width, height)
|
||||
local result = {}
|
||||
local pos,spacing = 0, self._private.spacing
|
||||
local spacing_widget = self._private.spacing_widget
|
||||
local spacing = self._private.spacing or 0
|
||||
local is_y = self._private.dir == "y"
|
||||
local is_x = not is_y
|
||||
local abspace = math.abs(spacing)
|
||||
local spoffset = spacing < 0 and 0 or spacing
|
||||
local widgets_nr = #self._private.widgets
|
||||
local spacing_widget
|
||||
local x, y = 0, 0
|
||||
|
||||
spacing_widget = spacing ~= 0 and self._private.spacing_widget or nil
|
||||
|
||||
for index, widget in pairs(self._private.widgets) do
|
||||
local w, h, local_spacing = width - x, height - y, spacing
|
||||
|
||||
-- Some widget might be zero sized either because this is their
|
||||
-- minimum space or just because they are really empty. In this case,
|
||||
-- they must still be added to the layout. Otherwise, if their size
|
||||
-- change and this layout is resizable, they are lost "forever" until
|
||||
-- a full relayout is called on this fixed layout object.
|
||||
local zero = false
|
||||
|
||||
for k, v in pairs(self._private.widgets) do
|
||||
local x, y, w, h, _
|
||||
if is_y then
|
||||
x, y = 0, pos
|
||||
w, h = width, height - pos
|
||||
if k ~= #self._private.widgets or not self._private.fill_space then
|
||||
_, h = base.fit_widget(self, context, v, w, h);
|
||||
if index ~= widgets_nr or not self._private.fill_space then
|
||||
h = select(2, base.fit_widget(self, context, widget, w, h))
|
||||
zero = h == 0
|
||||
end
|
||||
|
||||
if y - spacing >= height then
|
||||
-- pop the spacing widget added in previous iteration if used
|
||||
if spacing_widget then
|
||||
table.remove(result)
|
||||
|
||||
-- Avoid adding zero-sized widgets at an out-of-bound
|
||||
-- position.
|
||||
y = y - spacing
|
||||
end
|
||||
|
||||
-- Never display "random" widgets as soon as a non-zero sized
|
||||
-- one doesn't fit.
|
||||
if not zero then
|
||||
break
|
||||
end
|
||||
end
|
||||
pos = pos + h + spacing
|
||||
else
|
||||
x, y = pos, 0
|
||||
w, h = width - pos, height
|
||||
if k ~= #self._private.widgets or not self._private.fill_space then
|
||||
w, _ = base.fit_widget(self, context, v, w, h);
|
||||
if index ~= widgets_nr or not self._private.fill_space then
|
||||
w = select(1, base.fit_widget(self, context, widget, w, h))
|
||||
zero = w == 0
|
||||
end
|
||||
|
||||
if x - spacing >= width then
|
||||
-- pop the spacing widget added in previous iteration if used
|
||||
if spacing_widget then
|
||||
table.remove(result)
|
||||
|
||||
-- Avoid adding zero-sized widgets at an out-of-bound
|
||||
-- position.
|
||||
x = x - spacing
|
||||
end
|
||||
|
||||
-- Never display "random" widgets as soon as a non-zero sized
|
||||
-- one doesn't fit.
|
||||
if not zero then
|
||||
break
|
||||
end
|
||||
end
|
||||
pos = pos + w + spacing
|
||||
end
|
||||
|
||||
if (is_y and pos-spacing > height) or
|
||||
(is_x and pos-spacing > width) then
|
||||
break
|
||||
if zero then
|
||||
local_spacing = 0
|
||||
end
|
||||
|
||||
-- Add the spacing widget
|
||||
if k > 1 and abspace > 0 and spacing_widget then
|
||||
-- Place widget, even if it has zero width/height. Otherwise
|
||||
-- any layout change for zero-sized widget would become invisible.
|
||||
table.insert(result, base.place_widget_at(widget, x, y, w, h))
|
||||
|
||||
x = is_x and x + w + local_spacing or x
|
||||
y = is_y and y + h + local_spacing or y
|
||||
|
||||
-- Add the spacing widget (if needed)
|
||||
if index < widgets_nr and spacing_widget then
|
||||
table.insert(result, base.place_widget_at(
|
||||
spacing_widget, is_x and (x - spoffset) or x, is_y and (y - spoffset) or y,
|
||||
is_x and abspace or w, is_y and abspace or h
|
||||
spacing_widget,
|
||||
is_x and (x - spoffset) or x,
|
||||
is_y and (y - spoffset) or y,
|
||||
is_x and abspace or w,
|
||||
is_y and abspace or h
|
||||
))
|
||||
end
|
||||
table.insert(result, base.place_widget_at(v, x, y, w, h))
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
|
@ -217,9 +285,13 @@ function fixed:set(index, widget2)
|
|||
return true
|
||||
end
|
||||
|
||||
--- The widget used to fill the spacing between the layout elements.
|
||||
--- A widget to insert as a separator between child widgets.
|
||||
--
|
||||
-- By default, no widget is used.
|
||||
-- If this property is a valid widget and `spacing` is greater than `0`, a
|
||||
-- copy of this widget is inserted between each child widget, with its size in
|
||||
-- the layout's main direction determined by `spacing`.
|
||||
--
|
||||
-- By default no widget is used and any `spacing` is applied as an empty offset.
|
||||
--
|
||||
--@DOC_wibox_layout_fixed_spacing_widget_EXAMPLE@
|
||||
--
|
||||
|
@ -261,40 +333,61 @@ end
|
|||
-- @param orig_width The available width.
|
||||
-- @param orig_height The available height.
|
||||
function fixed:fit(context, orig_width, orig_height)
|
||||
local width, height = orig_width, orig_height
|
||||
local used_in_dir, used_max = 0, 0
|
||||
local width_left, height_left = orig_width, orig_height
|
||||
local spacing = self._private.spacing or 0
|
||||
local widgets_nr = #self._private.widgets
|
||||
local is_y = self._private.dir == "y"
|
||||
local used_max = 0
|
||||
|
||||
for _, v in pairs(self._private.widgets) do
|
||||
local w, h = base.fit_widget(self, context, v, width, height)
|
||||
local in_dir, max
|
||||
if self._private.dir == "y" then
|
||||
max, in_dir = w, h
|
||||
height = height - in_dir
|
||||
-- when no widgets exist the function can be called with orig_width or
|
||||
-- orig_height equal to nil. Exit early in this case.
|
||||
if widgets_nr == 0 then
|
||||
return 0, 0
|
||||
end
|
||||
|
||||
for k, v in pairs(self._private.widgets) do
|
||||
local w, h = base.fit_widget(self, context, v, width_left, height_left)
|
||||
local max
|
||||
|
||||
if is_y then
|
||||
max = w
|
||||
height_left = height_left - h
|
||||
else
|
||||
in_dir, max = w, h
|
||||
width = width - in_dir
|
||||
max = h
|
||||
width_left = width_left - w
|
||||
end
|
||||
|
||||
if max > used_max then
|
||||
used_max = max
|
||||
end
|
||||
used_in_dir = used_in_dir + in_dir
|
||||
|
||||
if width <= 0 or height <= 0 then
|
||||
if self._private.dir == "y" then
|
||||
used_in_dir = orig_height
|
||||
if k < widgets_nr then
|
||||
if is_y then
|
||||
height_left = height_left - spacing
|
||||
else
|
||||
used_in_dir = orig_width
|
||||
width_left = width_left - spacing
|
||||
end
|
||||
end
|
||||
|
||||
if width_left <= 0 or height_left <= 0 then
|
||||
-- this complicated two lines determine whether we're out-of-space
|
||||
-- because of spacing, or if the last widget doesn't fit in
|
||||
if is_y then
|
||||
height_left = k < widgets_nr and height_left + spacing or height_left
|
||||
height_left = height_left < 0 and 0 or height_left
|
||||
else
|
||||
width_left = k < widgets_nr and width_left + spacing or width_left
|
||||
width_left = width_left < 0 and 0 or width_left
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local spacing = self._private.spacing * (#self._private.widgets-1)
|
||||
|
||||
if self._private.dir == "y" then
|
||||
return used_max, used_in_dir + spacing
|
||||
if is_y then
|
||||
return used_max, orig_height - height_left
|
||||
end
|
||||
return used_in_dir + spacing, used_max
|
||||
|
||||
return orig_width - width_left, used_max
|
||||
end
|
||||
|
||||
function fixed:reset()
|
||||
|
@ -336,29 +429,25 @@ local function get_layout(dir, widget1, ...)
|
|||
return ret
|
||||
end
|
||||
|
||||
--- Returns a new horizontal fixed layout. Each widget will get as much space as it
|
||||
-- asks for and each widget will be drawn next to its neighboring widget.
|
||||
-- Widgets can be added via :add() or as arguments to this function.
|
||||
-- Note that widgets ignore `forced_height`. They will use the preferred/minimum width
|
||||
-- on the horizontal axis, and a stretched height on the vertical axis.
|
||||
--- Creates and returns a new horizontal fixed layout.
|
||||
--
|
||||
-- @tparam widget ... Widgets that should be added to the layout.
|
||||
-- @constructorfct wibox.layout.fixed.horizontal
|
||||
function fixed.horizontal(...)
|
||||
return get_layout("x", ...)
|
||||
end
|
||||
|
||||
--- Returns a new vertical fixed layout. Each widget will get as much space as it
|
||||
-- asks for and each widget will be drawn next to its neighboring widget.
|
||||
-- Widgets can be added via :add() or as arguments to this function.
|
||||
-- Note that widgets ignore `forced_width`. They will use the preferred/minimum height
|
||||
-- on the vertical axis, and a stretched width on the horizontal axis.
|
||||
--- Creates and returns a new vertical fixed layout.
|
||||
--
|
||||
-- @tparam widget ... Widgets that should be added to the layout.
|
||||
-- @constructorfct wibox.layout.fixed.vertical
|
||||
function fixed.vertical(...)
|
||||
return get_layout("y", ...)
|
||||
end
|
||||
|
||||
--- Add spacing between each layout widgets.
|
||||
--- The amount of space inserted between the child widgets.
|
||||
--
|
||||
-- If a `spacing_widget` is defined, this value is used for its size.
|
||||
--
|
||||
--@DOC_wibox_layout_fixed_spacing_EXAMPLE@
|
||||
--
|
||||
|
@ -381,10 +470,6 @@ end
|
|||
|
||||
--@DOC_fixed_COMMON@
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return fixed
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -1,9 +1,25 @@
|
|||
---------------------------------------------------------------------------
|
||||
-- A `flex` layout may be initialized with any number of child widgets, and
|
||||
-- during runtime widgets may be added and removed dynamically.
|
||||
--
|
||||
-- On the main axis, the layout will divide the available space evenly between
|
||||
-- all child widgets, without any regard to how much space these widgets might
|
||||
-- be asking for.
|
||||
--
|
||||
-- Just like @{wibox.layout.fixed}, `flex` allows adding spacing between the
|
||||
-- widgets, either as an ofset via @{spacing} or with a
|
||||
-- @{spacing_widget}.
|
||||
--
|
||||
-- On its secondary axis, the layout's size is determined by the largest child
|
||||
-- widget. Smaller child widgets are then placed with the same size.
|
||||
-- Therefore, child widgets may ignore their `forced_width` or `forced_height`
|
||||
-- properties for vertical and horizontal layouts respectively.
|
||||
--
|
||||
--@DOC_wibox_layout_defaults_flex_EXAMPLE@
|
||||
-- @author Uli Schlachter
|
||||
-- @copyright 2010 Uli Schlachter
|
||||
-- @layoutmod wibox.layout.flex
|
||||
-- @supermodule wibox.layout.fixed
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local base = require("wibox.widget.base")
|
||||
|
@ -15,6 +31,16 @@ local gtable = require("gears.table")
|
|||
|
||||
local flex = {}
|
||||
|
||||
-- {{{ Override inherited properties we want to hide
|
||||
|
||||
--- From `wibox.layout.fixed`.
|
||||
-- @property fill_space
|
||||
-- @tparam boolean fill_space
|
||||
-- @propemits true false
|
||||
-- @hidden
|
||||
|
||||
-- }}}
|
||||
|
||||
--- Add some widgets to the given fixed layout.
|
||||
--
|
||||
-- @tparam widget ... Widgets that should be added (must at least be one).
|
||||
|
@ -45,14 +71,18 @@ local flex = {}
|
|||
-- @treturn boolean If the operation is successful
|
||||
-- @method insert
|
||||
-- @emits widget::inserted
|
||||
-- @emitstparam widget::inserted widget self The fixed layout.
|
||||
-- @emitstparam widget::inserted widget widget index The inserted widget.
|
||||
-- @emitstparam widget::inserted widget self The layout.
|
||||
-- @emitstparam widget::inserted widget widget The inserted widget.
|
||||
-- @emitstparam widget::inserted number count The widget count.
|
||||
-- @interface layout
|
||||
|
||||
--- The widget used to fill the spacing between the layout elements.
|
||||
--- A widget to insert as a separator between child widgets.
|
||||
--
|
||||
-- By default, no widget is used.
|
||||
-- If this property is a valid widget and @{spacing} is greater than `0`, a
|
||||
-- copy of this widget is inserted between each child widget, with its size in
|
||||
-- the layout's main direction determined by @{spacing}.
|
||||
--
|
||||
-- By default no widget is used and any @{spacing} is applied as an empty offset.
|
||||
--
|
||||
--@DOC_wibox_layout_flex_spacing_widget_EXAMPLE@
|
||||
--
|
||||
|
@ -61,13 +91,16 @@ local flex = {}
|
|||
-- @propemits true false
|
||||
-- @interface layout
|
||||
|
||||
--- Add spacing between each layout widgets.
|
||||
--- The amount of space inserted between the child widgets.
|
||||
--
|
||||
-- If a @{spacing_widget} is defined, this value is used for its size.
|
||||
--
|
||||
--@DOC_wibox_layout_flex_spacing_EXAMPLE@
|
||||
--
|
||||
-- @property spacing
|
||||
-- @tparam number spacing Spacing between widgets.
|
||||
-- @propemits true false
|
||||
-- @interface layout
|
||||
|
||||
function flex:layout(_, width, height)
|
||||
local result = {}
|
||||
|
@ -184,10 +217,7 @@ local function get_layout(dir, widget1, ...)
|
|||
return ret
|
||||
end
|
||||
|
||||
--- Returns a new horizontal flex layout.
|
||||
--
|
||||
-- A flex layout shares the available space.
|
||||
-- equally among all widgets. Widgets can be added via `:add(widget)`.
|
||||
--- Creates and returns a new horizontal flex layout.
|
||||
--
|
||||
-- @tparam widget ... Widgets that should be added to the layout.
|
||||
-- @constructorfct wibox.layout.flex.horizontal
|
||||
|
@ -195,10 +225,7 @@ function flex.horizontal(...)
|
|||
return get_layout("horizontal", ...)
|
||||
end
|
||||
|
||||
--- Returns a new vertical flex layout.
|
||||
--
|
||||
-- A flex layout shares the available space
|
||||
-- equally among all widgets. Widgets can be added via `:add(widget)`.
|
||||
--- Creates and returns a new vertical flex layout.
|
||||
--
|
||||
-- @tparam widget ... Widgets that should be added to the layout.
|
||||
-- @constructorfct wibox.layout.flex.vertical
|
||||
|
@ -208,10 +235,6 @@ end
|
|||
|
||||
--@DOC_fixed_COMMON@
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return flex
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
-- @author getzze
|
||||
-- @copyright 2017 getzze
|
||||
-- @layoutmod wibox.layout.grid
|
||||
-- @supermodule wibox.widget.base
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
@ -961,10 +962,6 @@ end
|
|||
|
||||
--@DOC_fixed_COMMON@
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return setmetatable(grid, grid.mt)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
-- @author Emmanuel Lepage Vallee
|
||||
-- @copyright 2016 Emmanuel Lepage Vallee
|
||||
-- @layoutmod wibox.layout.manual
|
||||
-- @supermodule wibox.widget.base
|
||||
---------------------------------------------------------------------------
|
||||
local gtable = require("gears.table")
|
||||
local base = require("wibox.widget.base")
|
||||
|
@ -245,8 +246,4 @@ end
|
|||
|
||||
--@DOC_fixed_COMMON@
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return setmetatable(manual_layout, {__call=function(_,...) return new_manual(...) end})
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
-- @author Emmanuel Lepage Vallee
|
||||
-- @copyright 2016 Emmanuel Lepage Vallee
|
||||
-- @layoutmod wibox.layout.ratio
|
||||
-- @supermodule wibox.layout.flex
|
||||
-- @see 03-declarative-layout.md
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local base = require("wibox.widget.base" )
|
||||
|
@ -524,10 +526,6 @@ end
|
|||
|
||||
--@DOC_fixed_COMMON@
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return ratio
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
-- @author Emmanuel Lepage Vallee
|
||||
-- @copyright 2016 Emmanuel Lepage Vallee
|
||||
-- @layoutmod wibox.layout.stack
|
||||
-- @supermodule wibox.layout.fixed
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local base = require("wibox.widget.base" )
|
||||
|
@ -210,9 +211,5 @@ end
|
|||
|
||||
--@DOC_fixed_COMMON@
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return setmetatable(stack, stack.mt)
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
-- @author Uli Schlachter
|
||||
-- @copyright 2010 Uli Schlachter
|
||||
-- @classmod wibox.widget.base
|
||||
-- @supermodule gears.object
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local object = require("gears.object")
|
||||
|
@ -17,6 +18,184 @@ local table = table
|
|||
|
||||
local base = {}
|
||||
|
||||
-- {{{ Properties available on all widgets
|
||||
|
||||
--- Get or set the children elements.
|
||||
-- @property children
|
||||
-- @tparam table children The children.
|
||||
-- @baseclass wibox.widget.base
|
||||
|
||||
--- Get all direct and indirect children widgets.
|
||||
-- This will scan all containers recursively to find widgets
|
||||
-- Warning: This method it prone to stack overflow if there is a loop in the
|
||||
-- widgets hierarchy. A hierarchy loop is when a widget, or any of its
|
||||
-- children, contain (directly or indirectly) itself.
|
||||
-- @property all_children
|
||||
-- @tparam table children The children.
|
||||
-- @baseclass wibox.widget.base
|
||||
|
||||
--- Force a widget height.
|
||||
-- @property forced_height
|
||||
-- @tparam number|nil height The height (`nil` for automatic)
|
||||
-- @baseclass wibox.widget.base
|
||||
|
||||
--- Force a widget width.
|
||||
-- @property forced_width
|
||||
-- @tparam number|nil width The width (`nil` for automatic)
|
||||
-- @baseclass wibox.widget.base
|
||||
|
||||
--- The widget opacity (transparency).
|
||||
-- @property opacity
|
||||
-- @tparam[opt=1] number opacity The opacity (between 0 and 1)
|
||||
-- @baseclass wibox.widget.base
|
||||
|
||||
--- The widget visibility.
|
||||
-- @property visible
|
||||
-- @param boolean
|
||||
-- @baseclass wibox.widget.base
|
||||
|
||||
--- The widget buttons.
|
||||
--
|
||||
-- The table contains a list of `awful.button` objects.
|
||||
-- @property buttons
|
||||
-- @param table
|
||||
-- @see awful.button
|
||||
-- @baseclass wibox.widget.base
|
||||
|
||||
-- }}}
|
||||
|
||||
-- {{{ Signals available on the widgets.
|
||||
|
||||
--- When the layout (size) change.
|
||||
-- This signal is emitted when the previous results of `:layout()` and `:fit()`
|
||||
-- are no longer valid. Unless this signal is emitted, `:layout()` and `:fit()`
|
||||
-- must return the same result when called with the same arguments.
|
||||
-- @signal widget::layout_changed
|
||||
-- @see widget::redraw_needed
|
||||
-- @baseclass wibox.widget.base
|
||||
|
||||
--- When the widget content changed.
|
||||
-- This signal is emitted when the content of the widget changes. The widget will
|
||||
-- be redrawn, it is not re-layouted. Put differently, it is assumed that
|
||||
-- `:layout()` and `:fit()` would still return the same results as before.
|
||||
-- @signal widget::redraw_needed
|
||||
-- @see widget::layout_changed
|
||||
-- @baseclass wibox.widget.base
|
||||
|
||||
--- When a mouse button is pressed over the widget.
|
||||
-- @signal button::press
|
||||
-- @tparam table self The current object instance itself.
|
||||
-- @tparam number lx The horizontal position relative to the (0,0) position in
|
||||
-- the widget.
|
||||
-- @tparam number ly The vertical position relative to the (0,0) position in the
|
||||
-- widget.
|
||||
-- @tparam number button The button number.
|
||||
-- @tparam table mods The modifiers (mod4, mod1 (alt), Control, Shift)
|
||||
-- @tparam table find_widgets_result The entry from the result of
|
||||
-- @{wibox.drawable:find_widgets} for the position that the mouse hit.
|
||||
-- @tparam wibox.drawable find_widgets_result.drawable The drawable containing
|
||||
-- the widget.
|
||||
-- @tparam widget find_widgets_result.widget The widget being displayed.
|
||||
-- @tparam wibox.hierarchy find_widgets_result.hierarchy The hierarchy
|
||||
-- managing the widget's geometry.
|
||||
-- @tparam number find_widgets_result.x An approximation of the X position that
|
||||
-- the widget is visible at on the surface.
|
||||
-- @tparam number find_widgets_result.y An approximation of the Y position that
|
||||
-- the widget is visible at on the surface.
|
||||
-- @tparam number find_widgets_result.width An approximation of the width that
|
||||
-- the widget is visible at on the surface.
|
||||
-- @tparam number find_widgets_result.height An approximation of the height that
|
||||
-- the widget is visible at on the surface.
|
||||
-- @tparam number find_widgets_result.widget_width The exact width of the widget
|
||||
-- in its local coordinate system.
|
||||
-- @tparam number find_widgets_result.widget_height The exact height of the widget
|
||||
-- in its local coordinate system.
|
||||
-- @see mouse
|
||||
-- @baseclass wibox.widget.base
|
||||
|
||||
--- When a mouse button is released over the widget.
|
||||
-- @signal button::release
|
||||
-- @tparam table self The current object instance itself.
|
||||
-- @tparam number lx The horizontal position relative to the (0,0) position in
|
||||
-- the widget.
|
||||
-- @tparam number ly The vertical position relative to the (0,0) position in the
|
||||
-- widget.
|
||||
-- @tparam number button The button number.
|
||||
-- @tparam table mods The modifiers (mod4, mod1 (alt), Control, Shift)
|
||||
-- @tparam table find_widgets_result The entry from the result of
|
||||
-- @{wibox.drawable:find_widgets} for the position that the mouse hit.
|
||||
-- @tparam wibox.drawable find_widgets_result.drawable The drawable containing
|
||||
-- the widget.
|
||||
-- @tparam widget find_widgets_result.widget The widget being displayed.
|
||||
-- @tparam wibox.hierarchy find_widgets_result.hierarchy The hierarchy
|
||||
-- managing the widget's geometry.
|
||||
-- @tparam number find_widgets_result.x An approximation of the X position that
|
||||
-- the widget is visible at on the surface.
|
||||
-- @tparam number find_widgets_result.y An approximation of the Y position that
|
||||
-- the widget is visible at on the surface.
|
||||
-- @tparam number find_widgets_result.width An approximation of the width that
|
||||
-- the widget is visible at on the surface.
|
||||
-- @tparam number find_widgets_result.height An approximation of the height that
|
||||
-- the widget is visible at on the surface.
|
||||
-- @tparam number find_widgets_result.widget_width The exact width of the widget
|
||||
-- in its local coordinate system.
|
||||
-- @tparam number find_widgets_result.widget_height The exact height of the widget
|
||||
-- in its local coordinate system.
|
||||
-- @see mouse
|
||||
-- @baseclass wibox.widget.base
|
||||
|
||||
--- When the mouse enter a widget.
|
||||
-- @signal mouse::enter
|
||||
-- @tparam table self The current object instance itself.
|
||||
-- @tparam table find_widgets_result The entry from the result of
|
||||
-- @{wibox.drawable:find_widgets} for the position that the mouse hit.
|
||||
-- @tparam wibox.drawable find_widgets_result.drawable The drawable containing
|
||||
-- the widget.
|
||||
-- @tparam widget find_widgets_result.widget The widget being displayed.
|
||||
-- @tparam wibox.hierarchy find_widgets_result.hierarchy The hierarchy
|
||||
-- managing the widget's geometry.
|
||||
-- @tparam number find_widgets_result.x An approximation of the X position that
|
||||
-- the widget is visible at on the surface.
|
||||
-- @tparam number find_widgets_result.y An approximation of the Y position that
|
||||
-- the widget is visible at on the surface.
|
||||
-- @tparam number find_widgets_result.width An approximation of the width that
|
||||
-- the widget is visible at on the surface.
|
||||
-- @tparam number find_widgets_result.height An approximation of the height that
|
||||
-- the widget is visible at on the surface.
|
||||
-- @tparam number find_widgets_result.widget_width The exact width of the widget
|
||||
-- in its local coordinate system.
|
||||
-- @tparam number find_widgets_result.widget_height The exact height of the widget
|
||||
-- in its local coordinate system.
|
||||
-- @see mouse
|
||||
-- @baseclass wibox.widget.base
|
||||
|
||||
--- When the mouse leave a widget.
|
||||
-- @signal mouse::leave
|
||||
-- @tparam table self The current object instance itself.
|
||||
-- @tparam table find_widgets_result The entry from the result of
|
||||
-- @{wibox.drawable:find_widgets} for the position that the mouse hit.
|
||||
-- @tparam wibox.drawable find_widgets_result.drawable The drawable containing
|
||||
-- the widget.
|
||||
-- @tparam widget find_widgets_result.widget The widget being displayed.
|
||||
-- @tparam wibox.hierarchy find_widgets_result.hierarchy The hierarchy
|
||||
-- managing the widget's geometry.
|
||||
-- @tparam number find_widgets_result.x An approximation of the X position that
|
||||
-- the widget is visible at on the surface.
|
||||
-- @tparam number find_widgets_result.y An approximation of the Y position that
|
||||
-- the widget is visible at on the surface.
|
||||
-- @tparam number find_widgets_result.width An approximation of the width that
|
||||
-- the widget is visible at on the surface.
|
||||
-- @tparam number find_widgets_result.height An approximation of the height that
|
||||
-- the widget is visible at on the surface.
|
||||
-- @tparam number find_widgets_result.widget_width The exact width of the widget
|
||||
-- in its local coordinate system.
|
||||
-- @tparam number find_widgets_result.widget_height The exact height of the widget
|
||||
-- in its local coordinate system.
|
||||
-- @see mouse
|
||||
-- @baseclass wibox.widget.base
|
||||
|
||||
-- }}}
|
||||
|
||||
-- {{{ Functions on widgets
|
||||
|
||||
-- Functions available on all widgets.
|
||||
|
@ -30,7 +209,8 @@ end, true)
|
|||
|
||||
--- Set a widget's visibility.
|
||||
-- @tparam boolean b Whether the widget is visible.
|
||||
-- @method set_visible
|
||||
-- @method wibox.widget.base:set_visible
|
||||
-- @hidden
|
||||
function base.widget:set_visible(b)
|
||||
if b ~= self._private.visible then
|
||||
self._private.visible = b
|
||||
|
@ -42,6 +222,7 @@ end
|
|||
|
||||
--- Add a new `awful.button` to this widget.
|
||||
-- @tparam awful.button button The button to add.
|
||||
-- @method wibox.widget.base:add_button
|
||||
function base.widget:add_button(button)
|
||||
if not button then return end
|
||||
|
||||
|
@ -65,7 +246,8 @@ end
|
|||
|
||||
--- Is the widget visible?
|
||||
-- @treturn boolean
|
||||
-- @method get_visible
|
||||
-- @method wibox.widget.base:get_visible
|
||||
-- @hidden
|
||||
function base.widget:get_visible()
|
||||
return self._private.visible or false
|
||||
end
|
||||
|
@ -73,17 +255,19 @@ end
|
|||
--- Set a widget's opacity.
|
||||
-- @tparam number o The opacity to use (a number from 0 (transparent) to 1
|
||||
-- (opaque)).
|
||||
-- @method set_opacity
|
||||
-- @method wibox.widget.base:set_opacity
|
||||
-- @hidden
|
||||
function base.widget:set_opacity(o)
|
||||
if o ~= self._private.opacity then
|
||||
self._private.opacity = o
|
||||
self:emit_signal("widget::redraw")
|
||||
self:emit_signal("widget::redraw_needed")
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the widget's opacity.
|
||||
-- @treturn number The opacity (between 0 (transparent) and 1 (opaque)).
|
||||
-- @method get_opacity
|
||||
-- @method wibox.widget.base:get_opacity
|
||||
-- @hidden
|
||||
function base.widget:get_opacity()
|
||||
return self._private.opacity
|
||||
end
|
||||
|
@ -91,8 +275,9 @@ end
|
|||
--- Set the widget's forced width.
|
||||
-- @tparam[opt] number width With `nil` the default mechanism of calling the
|
||||
-- `:fit` method is used.
|
||||
-- @see fit_widget
|
||||
-- @method set_forced_width
|
||||
-- @see wibox.widget.base:fit_widget
|
||||
-- @method wibox.widget.base:set_forced_width
|
||||
-- @hidden
|
||||
function base.widget:set_forced_width(width)
|
||||
if width ~= self._private.forced_width then
|
||||
self._private.forced_width = width
|
||||
|
@ -108,7 +293,8 @@ end
|
|||
-- actual size is during a `mouse::enter`, `mouse::leave` or button event.
|
||||
-- @treturn[opt] number The forced width (nil if automatic).
|
||||
-- @see fit_widget
|
||||
-- @method get_forced_width
|
||||
-- @method wibox.widget.base:get_forced_width
|
||||
-- @hidden
|
||||
function base.widget:get_forced_width()
|
||||
return self._private.forced_width
|
||||
end
|
||||
|
@ -116,8 +302,9 @@ end
|
|||
--- Set the widget's forced height.
|
||||
-- @tparam[opt] number height With `nil` the default mechanism of calling the
|
||||
-- `:fit` method is used.
|
||||
-- @see fit_widget
|
||||
-- @method set_height
|
||||
-- @see wibox.widget.base:fit_widget
|
||||
-- @method wibox.widget.base:set_height
|
||||
-- @hidden
|
||||
function base.widget:set_forced_height(height)
|
||||
if height ~= self._private.forced_height then
|
||||
self._private.forced_height = height
|
||||
|
@ -132,7 +319,8 @@ end
|
|||
-- If there is no forced width/height, then the only way to get the widget's
|
||||
-- actual size is during a `mouse::enter`, `mouse::leave` or button event.
|
||||
-- @treturn[opt] number The forced height (nil if automatic).
|
||||
-- @method get_forced_height
|
||||
-- @method wibox.widget.base:get_forced_height
|
||||
-- @hidden
|
||||
function base.widget:get_forced_height()
|
||||
return self._private.forced_height
|
||||
end
|
||||
|
@ -141,7 +329,8 @@ end
|
|||
--
|
||||
-- This method should be re-implemented by the relevant widgets.
|
||||
-- @treturn table children The children.
|
||||
-- @method get_children
|
||||
-- @method wibox.widget.base:get_children
|
||||
-- @hidden
|
||||
function base.widget:get_children()
|
||||
return {}
|
||||
end
|
||||
|
@ -151,7 +340,8 @@ end
|
|||
-- The default implementation does nothing, this must be re-implemented by
|
||||
-- all layout and container widgets.
|
||||
-- @tparam table children A table composed of valid widgets.
|
||||
-- @method set_children
|
||||
-- @method wibox.widget.base:set_children
|
||||
-- @hidden
|
||||
function base.widget:set_children(children) -- luacheck: no unused
|
||||
-- Nothing on purpose
|
||||
end
|
||||
|
@ -171,7 +361,8 @@ end
|
|||
-- *Warning*: This method it prone to stack overflow if the widget, or any of
|
||||
-- its children, contains (directly or indirectly) itself.
|
||||
-- @treturn table children The children.
|
||||
-- @method get_all_children
|
||||
-- @method wibox.widget.base:get_all_children
|
||||
-- @hidden
|
||||
function base.widget:get_all_children()
|
||||
local ret = {}
|
||||
digg_children(ret, self)
|
||||
|
@ -193,12 +384,17 @@ function base.set_widget_common(self, widget)
|
|||
end
|
||||
|
||||
self._private.widget = w
|
||||
|
||||
self:emit_signal("property::widget")
|
||||
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
|
||||
--- Emit a signal and ensure all parent widgets in the hierarchies also
|
||||
-- forward the signal. This is useful to track signals when there is a dynamic
|
||||
-- set of containers and layouts wrapping the widget.
|
||||
-- forward the signal.
|
||||
--
|
||||
-- This is useful to track signals when there is a dynamic set of containers
|
||||
-- and layouts wrapping the widget.
|
||||
--
|
||||
-- Note that this function has some flaws:
|
||||
--
|
||||
|
@ -213,7 +409,7 @@ end
|
|||
--
|
||||
-- @tparam string signal_name
|
||||
-- @param ... Other arguments
|
||||
-- @method emit_signal_recursive
|
||||
-- @method wibox.widget.base:emit_signal_recursive
|
||||
function base.widget:emit_signal_recursive(signal_name, ...)
|
||||
-- This is a convenience wrapper, the real implementation is in the
|
||||
-- hierarchy.
|
||||
|
@ -223,12 +419,14 @@ end
|
|||
|
||||
--- Get the index of a widget.
|
||||
-- @tparam widget widget The widget to look for.
|
||||
-- @tparam[opt] boolean recursive Also check sub-widgets?
|
||||
-- @tparam[opt] widget ... Additional widgets to add at the end of the "path"
|
||||
-- @treturn number The index.
|
||||
-- @tparam[opt] boolean recursive Recursively check accross the sub-widgets
|
||||
-- hierarchy.
|
||||
-- @tparam[opt] widget ... Additional widgets to add at the end of the
|
||||
-- sub-widgets hierarchy "path".
|
||||
-- @treturn number The widget index.
|
||||
-- @treturn widget The parent widget.
|
||||
-- @treturn table The path between "self" and "widget".
|
||||
-- @method index
|
||||
-- @treturn table The hierarchy path between "self" and "widget".
|
||||
-- @method wibox.widget.base:index
|
||||
function base.widget:index(widget, recursive, ...)
|
||||
local widgets = self:get_children()
|
||||
for idx, w in ipairs(widgets) do
|
||||
|
@ -533,32 +731,34 @@ local function drill(ids, content)
|
|||
end
|
||||
end
|
||||
|
||||
-- Add all widgets.
|
||||
for k = 1, max do
|
||||
-- ipairs cannot be used on sparse tables.
|
||||
local v, id2, e = widgets[k], id, nil
|
||||
if v then
|
||||
-- It is another declarative container, parse it.
|
||||
if (not v.is_widget) and (v.widget or v.layout) then
|
||||
e, id2 = drill(ids, v)
|
||||
widgets[k] = e
|
||||
elseif (not v.is_widget) and is_callable(v) then
|
||||
widgets[k] = v()
|
||||
end
|
||||
base.check_widget(widgets[k])
|
||||
if widgets and max > 0 then
|
||||
-- Add all widgets.
|
||||
for k = 1, max do
|
||||
-- ipairs cannot be used on sparse tables.
|
||||
local v, id2, e = widgets[k], id, nil
|
||||
if v then
|
||||
-- It is another declarative container, parse it.
|
||||
if (not v.is_widget) and (v.widget or v.layout) then
|
||||
e, id2 = drill(ids, v)
|
||||
widgets[k] = e
|
||||
elseif (not v.is_widget) and is_callable(v) then
|
||||
widgets[k] = v()
|
||||
end
|
||||
base.check_widget(widgets[k])
|
||||
|
||||
-- Place the widget in the access table.
|
||||
if id2 then
|
||||
l [id2] = e
|
||||
ids[id2] = ids[id2] or {}
|
||||
table.insert(ids[id2], e)
|
||||
-- Place the widget in the access table.
|
||||
if id2 then
|
||||
l [id2] = e
|
||||
ids[id2] = ids[id2] or {}
|
||||
table.insert(ids[id2], e)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Replace all children (if any) with the new ones.
|
||||
if widgets then
|
||||
|
||||
-- Replace all children (if any) with the new ones.
|
||||
l:set_children(widgets)
|
||||
end
|
||||
|
||||
return l, id
|
||||
end
|
||||
|
||||
|
@ -575,7 +775,8 @@ end
|
|||
--
|
||||
-- See [The declarative layout system](../documentation/03-declarative-layout.md.html).
|
||||
-- @tparam table args A table containing the widget's disposition.
|
||||
-- @method setup
|
||||
-- @method wibox.widget.base:setup
|
||||
-- @hidden
|
||||
function base.widget:setup(args)
|
||||
local f,ids = self.set_widget or self.add or self.set_first,{}
|
||||
local w, id = drill(ids, args)
|
||||
|
|
|
@ -37,8 +37,9 @@ local beautiful = require("beautiful")
|
|||
|
||||
local calendar = { mt = {} }
|
||||
|
||||
local properties = { "date", "font", "spacing", "week_numbers", "start_sunday", "long_weekdays", "fn_embed" }
|
||||
|
||||
local properties = { "date" , "font" , "spacing" , "week_numbers",
|
||||
"start_sunday", "long_weekdays", "fn_embed", "flex_height",
|
||||
}
|
||||
|
||||
--- The calendar font.
|
||||
-- @beautiful beautiful.calendar_font
|
||||
|
@ -60,6 +61,11 @@ local properties = { "date", "font", "spacing", "week_numbers", "start_sunday",
|
|||
-- @beautiful beautiful.calendar_long_weekdays
|
||||
-- @param boolean Use three characters for the weekdays instead of two
|
||||
|
||||
--- Allow cells to have flexible height.
|
||||
-- Flexible height allow cells to adapt their height to fill the empty space at the bottom of the widget.
|
||||
-- @beautiful beautiful.flex_height
|
||||
-- @param boolean Cells can skretch to fill the empty space.
|
||||
|
||||
--- The calendar date.
|
||||
--
|
||||
-- A table representing the date {day=[number|nil], month=[number|nil], year=[number]}.
|
||||
|
@ -116,6 +122,12 @@ local properties = { "date", "font", "spacing", "week_numbers", "start_sunday",
|
|||
-- @param function Function to embed the widget depending on its flag
|
||||
-- @property fn_embed
|
||||
|
||||
--- Allow cells to have flexible height
|
||||
--
|
||||
--@DOC_wibox_widget_calendar_flex_height_EXAMPLE@
|
||||
--
|
||||
-- @param[opt=false] boolean Allow flex height.
|
||||
-- @property flex_height
|
||||
|
||||
--- Make a textbox
|
||||
-- @tparam string text Text of the textbox
|
||||
|
@ -139,25 +151,47 @@ end
|
|||
-- @tparam number|nil date.day Date day
|
||||
-- @treturn widget Grid layout
|
||||
local function create_month(props, date)
|
||||
local num_rows = 8
|
||||
local num_columns = props.week_numbers and 8 or 7
|
||||
|
||||
-- Create grid layout
|
||||
local layout = grid()
|
||||
layout:set_expand(true)
|
||||
layout:set_expand(true)
|
||||
layout:set_homogeneous(true)
|
||||
layout:set_spacing(props.spacing)
|
||||
layout:set_forced_num_rows(num_rows)
|
||||
layout:set_forced_num_cols(num_columns)
|
||||
|
||||
local start_row = 3
|
||||
local start_column = num_columns - 6
|
||||
local week_start = props.start_sunday and 1 or 2
|
||||
local last_day = os.date("*t", os.time{year=date.year, month=date.month+1, day=0})
|
||||
local month_days = last_day.day
|
||||
local column_fday = (last_day.wday - month_days + 1 - week_start ) % 7
|
||||
|
||||
local num_columns = props.week_numbers and 8 or 7
|
||||
local start_column = num_columns - 6
|
||||
|
||||
-- Compute number of rows
|
||||
-- There are at least 4 weeks in a month
|
||||
local num_rows = 4
|
||||
-- On every month but february on non bisextile years
|
||||
if last_day.day > 28 then
|
||||
-- The number of days span over at least 5 weeks
|
||||
num_rows = num_rows + 1
|
||||
|
||||
-- On month with 30+ days add 1 week if:
|
||||
-- - if 30 days and the first day is the last day of the week
|
||||
-- - if 31 days and the first days is at least the second to last day
|
||||
if column_fday >= 5 then
|
||||
if last_day.day == 30 and column_fday == 6 or last_day.day == 31 then
|
||||
num_rows = num_rows + 1
|
||||
end
|
||||
end
|
||||
-- If the first day of february is anything but the first day of the week
|
||||
elseif column_fday > 1 then
|
||||
-- Span over 5 weeks
|
||||
num_rows = num_rows + 1
|
||||
end
|
||||
|
||||
-- Create grid layout
|
||||
local layout = grid()
|
||||
if props.flex_height then
|
||||
layout:set_expand(true)
|
||||
end
|
||||
layout:set_homogeneous(true)
|
||||
layout:set_spacing(props.spacing)
|
||||
layout:set_forced_num_rows(num_rows)
|
||||
layout:set_forced_num_cols(num_columns)
|
||||
|
||||
--local flags = {"header", "weekdays", "weeknumber", "normal", "focus"}
|
||||
local cell_date, t, i, j, w, flag, text
|
||||
|
||||
|
@ -331,6 +365,7 @@ local function get_calendar(type, date, font)
|
|||
ret._private.week_numbers = beautiful.calendar_week_numbers or false
|
||||
ret._private.start_sunday = beautiful.calendar_start_sunday or false
|
||||
ret._private.long_weekdays = beautiful.calendar_long_weekdays or false
|
||||
ret._private.flex_height = beautiful.calendar_flex_height or false
|
||||
ret._private.fn_embed = function (w, _) return w end
|
||||
|
||||
-- header specific
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
-- @author Emmanuel Lepage Valle
|
||||
-- @copyright 2010 Emmanuel Lepage Vallee
|
||||
-- @widgetmod wibox.widget.checkbox
|
||||
-- @supermodule wibox.widget.base
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local color = require( "gears.color" )
|
||||
|
@ -303,10 +304,6 @@ local function new(checked, args)
|
|||
return ret
|
||||
end
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return setmetatable({}, { __call = function(_, ...) return new(...) end})
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,26 +1,27 @@
|
|||
---------------------------------------------------------------------------
|
||||
-- A widget to display image.
|
||||
-- A widget to display an image.
|
||||
--
|
||||
-- The `wibox.widget.imagebox` is part of the Awesome WM's wiboxes system
|
||||
-- The `wibox.widget.imagebox` is part of the Awesome WM's widget system
|
||||
-- (see @{03-declarative-layout.md}).
|
||||
--
|
||||
-- This widget displays an image. The image can be a file,
|
||||
-- a cairo image surface, or an rsvg handle object (see the
|
||||
-- [image property](#image)).
|
||||
--
|
||||
-- Use a `wibox.widget.imagebox`
|
||||
-- Examples using a `wibox.widget.imagebox`:
|
||||
-- ---
|
||||
--
|
||||
-- @DOC_wibox_widget_defaults_imagebox_EXAMPLE@
|
||||
--
|
||||
-- Alternatively, you can declare the `imagebox` widget using the
|
||||
-- declarative pattern (Both codes are strictly equivalent):
|
||||
-- declarative pattern (both variants are strictly equivalent):
|
||||
--
|
||||
-- @DOC_wibox_widget_declarative-pattern_imagebox_EXAMPLE@
|
||||
--
|
||||
-- @author Uli Schlachter
|
||||
-- @copyright 2010 Uli Schlachter
|
||||
-- @widgetmod wibox.widget.imagebox
|
||||
-- @supermodule wibox.widget.base
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local lgi = require("lgi")
|
||||
|
@ -47,67 +48,40 @@ end
|
|||
|
||||
local imagebox = { mt = {} }
|
||||
|
||||
local rsvg_handle_cache = setmetatable({}, { __mode = 'v' })
|
||||
local rsvg_handle_cache = setmetatable({}, { __mode = 'k' })
|
||||
|
||||
---Load rsvg handle form image file
|
||||
---@tparam string file Path to svg file.
|
||||
---@return Rsvg handle
|
||||
-- @tparam string file Path to svg file.
|
||||
-- @return Rsvg handle
|
||||
-- @treturn table A table where cached data can be stored.
|
||||
local function load_rsvg_handle(file)
|
||||
if not Rsvg then return end
|
||||
|
||||
local cache = rsvg_handle_cache[file]
|
||||
local cache = (rsvg_handle_cache[file] or {})["handle"]
|
||||
|
||||
if cache then
|
||||
return cache
|
||||
return cache, rsvg_handle_cache[file]
|
||||
end
|
||||
|
||||
local handle, err = Rsvg.Handle.new_from_file(file)
|
||||
if not err then
|
||||
rsvg_handle_cache[file] = handle
|
||||
return handle
|
||||
end
|
||||
end
|
||||
local handle, err
|
||||
|
||||
-- Draw an imagebox with the given cairo context in the given geometry.
|
||||
function imagebox:draw(_, cr, width, height)
|
||||
if width == 0 or height == 0 or not self._private.default then return end
|
||||
|
||||
-- Set the clip
|
||||
if self._private.clip_shape then
|
||||
cr:clip(self._private.clip_shape(cr, width, height, unpack(self._private.clip_args)))
|
||||
end
|
||||
|
||||
if not self._private.resize_forbidden then
|
||||
-- Let's scale the image so that it fits into (width, height)
|
||||
local w, h = self._private.default.width, self._private.default.height
|
||||
local aspect = math.min(width / w, height / h)
|
||||
cr:scale(aspect, aspect)
|
||||
end
|
||||
|
||||
if self._private.handle then
|
||||
self._private.handle:render_cairo(cr)
|
||||
if file:match("<[?]?xml") or file:match("<svg") then
|
||||
handle, err = Rsvg.Handle.new_from_data(file)
|
||||
else
|
||||
cr:set_source_surface(self._private.image, 0, 0)
|
||||
cr:paint()
|
||||
end
|
||||
end
|
||||
|
||||
-- Fit the imagebox into the given geometry
|
||||
function imagebox:fit(_, width, height)
|
||||
if not self._private.default then return 0, 0 end
|
||||
local w, h = self._private.default.width, self._private.default.height
|
||||
|
||||
if not self._private.resize_forbidden or w > width or h > height then
|
||||
local aspect = math.min(width / w, height / h)
|
||||
return w * aspect, h * aspect
|
||||
handle, err = Rsvg.Handle.new_from_file(file)
|
||||
end
|
||||
|
||||
return w, h
|
||||
if not err then
|
||||
rsvg_handle_cache[file] = rsvg_handle_cache[file] or {}
|
||||
rsvg_handle_cache[file]["handle"] = handle
|
||||
return handle, rsvg_handle_cache[file]
|
||||
end
|
||||
end
|
||||
|
||||
---Apply cairo surface for given imagebox widget
|
||||
local function set_surface(ib, surf)
|
||||
local is_surd_valid = surf.width > 0 and surf.height > 0
|
||||
if not is_surd_valid then return end
|
||||
local is_surf_valid = surf.width > 0 and surf.height > 0
|
||||
if not is_surf_valid then return false end
|
||||
|
||||
ib._private.default = { width = surf.width, height = surf.height }
|
||||
ib._private.handle = nil
|
||||
|
@ -116,14 +90,16 @@ local function set_surface(ib, surf)
|
|||
end
|
||||
|
||||
---Apply RsvgHandle for given imagebox widget
|
||||
local function set_handle(ib, handle)
|
||||
local function set_handle(ib, handle, cache)
|
||||
local dim = handle:get_dimensions()
|
||||
local is_handle_valid = dim.width > 0 and dim.height > 0
|
||||
if not is_handle_valid then return end
|
||||
if not is_handle_valid then return false end
|
||||
|
||||
ib._private.default = { width = dim.width, height = dim.height }
|
||||
ib._private.handle = handle
|
||||
ib._private.cache = cache
|
||||
ib._private.image = nil
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
@ -135,32 +111,208 @@ end
|
|||
---@treturn boolean True if image was successfully applied
|
||||
local function load_and_apply(ib, file, image_loader, image_setter)
|
||||
local image_applied
|
||||
local object = image_loader(file)
|
||||
local object, cache = image_loader(file)
|
||||
|
||||
if object then
|
||||
image_applied = image_setter(ib, object)
|
||||
image_applied = image_setter(ib, object, cache)
|
||||
end
|
||||
return image_applied
|
||||
end
|
||||
|
||||
---Update the cached size depending on the stylesheet and dpi.
|
||||
--
|
||||
-- It's necessary because a single RSVG handle can be used by
|
||||
-- many imageboxes. So DPI and Stylesheet need to be set each time.
|
||||
local function update_dpi(self, ctx)
|
||||
if not self._private.handle then return end
|
||||
|
||||
local dpi = self._private.auto_dpi and
|
||||
ctx.dpi or
|
||||
self._private.dpi or
|
||||
nil
|
||||
|
||||
local need_dpi = dpi and
|
||||
self._private.last_dpi ~= dpi
|
||||
|
||||
local need_style = self._private.handle.set_stylesheet and
|
||||
self._private.stylesheet
|
||||
|
||||
local old_size = self._private.default and self._private.default.width
|
||||
|
||||
if dpi and dpi ~= self._private.cache.dpi then
|
||||
if type(dpi) == "table" then
|
||||
self._private.handle:set_dpi_x_y(dpi.x, dpi.y)
|
||||
else
|
||||
self._private.handle:set_dpi(dpi)
|
||||
end
|
||||
end
|
||||
|
||||
if need_style and self._private.cache.stylesheet ~= self._private.stylesheet then
|
||||
self._private.handle:set_stylesheet(self._private.stylesheet)
|
||||
end
|
||||
|
||||
-- Reload the size.
|
||||
if need_dpi or (need_style and self._private.stylesheet ~= self._private.last_stylesheet) then
|
||||
set_handle(self, self._private.handle, self._private.cache)
|
||||
end
|
||||
|
||||
self._private.last_dpi = dpi
|
||||
self._private.cache.dpi = dpi
|
||||
self._private.last_stylesheet = self._private.stylesheet
|
||||
self._private.cache.stylesheet = self._private.stylesheet
|
||||
|
||||
-- This can happen in the constructor when `dpi` is set after `image`.
|
||||
if old_size and old_size ~= self._private.default.width then
|
||||
self:emit_signal("widget::redraw_needed")
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
end
|
||||
|
||||
-- Draw an imagebox with the given cairo context in the given geometry.
|
||||
function imagebox:draw(ctx, cr, width, height)
|
||||
if width == 0 or height == 0 or not self._private.default then return end
|
||||
|
||||
-- For valign = "top" and halign = "left"
|
||||
local translate = {
|
||||
x = 0,
|
||||
y = 0,
|
||||
}
|
||||
|
||||
update_dpi(self, ctx)
|
||||
|
||||
local w, h = self._private.default.width, self._private.default.height
|
||||
|
||||
if self._private.resize then
|
||||
-- That's for the "fit" policy.
|
||||
local aspects = {
|
||||
w = width / w,
|
||||
h = height / h
|
||||
}
|
||||
|
||||
local policy = {
|
||||
w = self._private.horizontal_fit_policy or "auto",
|
||||
h = self._private.vertical_fit_policy or "auto"
|
||||
}
|
||||
|
||||
for _, aspect in ipairs {"w", "h"} do
|
||||
if self._private.upscale == false and (w < width and h < height) then
|
||||
aspects[aspect] = 1
|
||||
elseif self._private.downscale == false and (w >= width and h >= height) then
|
||||
aspects[aspect] = 1
|
||||
elseif policy[aspect] == "none" then
|
||||
aspects[aspect] = 1
|
||||
elseif policy[aspect] == "auto" then
|
||||
aspects[aspect] = math.min(width / w, height / h)
|
||||
end
|
||||
end
|
||||
|
||||
if self._private.halign == "center" then
|
||||
translate.x = math.floor((width - w*aspects.w)/2)
|
||||
elseif self._private.halign == "right" then
|
||||
translate.x = math.floor(width - (w*aspects.w))
|
||||
end
|
||||
|
||||
if self._private.valign == "center" then
|
||||
translate.y = math.floor((height - h*aspects.h)/2)
|
||||
elseif self._private.valign == "bottom" then
|
||||
translate.y = math.floor(height - (h*aspects.h))
|
||||
end
|
||||
|
||||
cr:translate(translate.x, translate.y)
|
||||
|
||||
-- Before using the scale, make sure it is below the threshold.
|
||||
local threshold, max_factor = self._private.max_scaling_factor, math.max(aspects.w, aspects.h)
|
||||
|
||||
if threshold and threshold > 0 and threshold < max_factor then
|
||||
aspects.w = (aspects.w*threshold)/max_factor
|
||||
aspects.h = (aspects.h*threshold)/max_factor
|
||||
end
|
||||
|
||||
-- Set the clip
|
||||
if self._private.clip_shape then
|
||||
cr:clip(self._private.clip_shape(cr, w*aspects.w, h*aspects.h, unpack(self._private.clip_args)))
|
||||
end
|
||||
|
||||
cr:scale(aspects.w, aspects.h)
|
||||
else
|
||||
if self._private.halign == "center" then
|
||||
translate.x = math.floor((width - w)/2)
|
||||
elseif self._private.halign == "right" then
|
||||
translate.x = math.floor(width - w)
|
||||
end
|
||||
|
||||
if self._private.valign == "center" then
|
||||
translate.y = math.floor((height - h)/2)
|
||||
elseif self._private.valign == "bottom" then
|
||||
translate.y = math.floor(height - h)
|
||||
end
|
||||
|
||||
cr:translate(translate.x, translate.y)
|
||||
|
||||
-- Set the clip
|
||||
if self._private.clip_shape then
|
||||
cr:clip(self._private.clip_shape(cr, w, h, unpack(self._private.clip_args)))
|
||||
end
|
||||
end
|
||||
|
||||
if self._private.handle then
|
||||
self._private.handle:render_cairo(cr)
|
||||
else
|
||||
cr:set_source_surface(self._private.image, 0, 0)
|
||||
|
||||
local filter = self._private.scaling_quality
|
||||
|
||||
if filter then
|
||||
cr:get_source():set_filter(cairo.Filter[filter:upper()])
|
||||
end
|
||||
|
||||
cr:paint()
|
||||
end
|
||||
end
|
||||
|
||||
-- Fit the imagebox into the given geometry
|
||||
function imagebox:fit(ctx, width, height)
|
||||
if not self._private.default then return 0, 0 end
|
||||
|
||||
update_dpi(self, ctx)
|
||||
|
||||
local w, h = self._private.default.width, self._private.default.height
|
||||
|
||||
if w <= width and h <= height and self._private.upscale == false then
|
||||
return w, h
|
||||
end
|
||||
|
||||
if (w < width or h < height) and self._private.downscale == false then
|
||||
return w, h
|
||||
end
|
||||
|
||||
if self._private.resize or w > width or h > height then
|
||||
local aspect = math.min(width / w, height / h)
|
||||
return w * aspect, h * aspect
|
||||
end
|
||||
|
||||
return w, h
|
||||
end
|
||||
|
||||
--- The image rendered by the `imagebox`.
|
||||
--
|
||||
-- It can can be any of the following:
|
||||
--
|
||||
-- * A `string` : Interpreted as the path to an image file,
|
||||
-- * A cairo image surface : Directly used as is,
|
||||
-- * An rsvg handle object : Directly used as is,
|
||||
-- * `nil` : Unset the image.
|
||||
-- * A `string`: Interpreted as a path to an image file
|
||||
-- * A cairo image surface: Directly used as-is
|
||||
-- * A librsvg handle object: Directly used as-is
|
||||
-- * `nil`: Unset the image.
|
||||
--
|
||||
-- @property image
|
||||
-- @tparam image image The image to render.
|
||||
-- @propemits false false
|
||||
-- @see set_image
|
||||
|
||||
--- Set the `imagebox` image.
|
||||
--
|
||||
-- The image can be a file, a cairo image surface, or an rsvg handle object
|
||||
-- (see the [image property](#image)).
|
||||
-- @method imagebox:set_image
|
||||
-- @method set_image
|
||||
-- @hidden
|
||||
-- @tparam image image The image to render.
|
||||
-- @treturn boolean `true` on success, `false` if the image cannot be used.
|
||||
-- @usage my_imagebox:set_image(beautiful.awesome_icon)
|
||||
|
@ -169,7 +321,10 @@ end
|
|||
function imagebox:set_image(image)
|
||||
local setup_succeed
|
||||
|
||||
if type(image) == "userdata" then
|
||||
-- Keep the original to prevent the cache from being GCed.
|
||||
self._private.original_image = image
|
||||
|
||||
if type(image) == "userdata" and not (Rsvg and Rsvg.Handle:is_type_of(image)) then
|
||||
-- This function is not documented to handle userdata objects, but
|
||||
-- historically it did, and it did by just assuming they refer to a
|
||||
-- cairo surface.
|
||||
|
@ -186,7 +341,8 @@ function imagebox:set_image(image)
|
|||
end
|
||||
elseif Rsvg and Rsvg.Handle:is_type_of(image) then
|
||||
-- try to apply given rsvg handle
|
||||
setup_succeed = set_handle(self, image)
|
||||
rsvg_handle_cache[image] = rsvg_handle_cache[image] or {}
|
||||
setup_succeed = set_handle(self, image, rsvg_handle_cache[image])
|
||||
elseif cairo.Surface:is_type_of(image) then
|
||||
-- try to apply given cairo surface
|
||||
setup_succeed = set_surface(self, image)
|
||||
|
@ -207,23 +363,27 @@ function imagebox:set_image(image)
|
|||
end
|
||||
|
||||
--- Set a clip shape for this imagebox.
|
||||
-- A clip shape define an area where the content is displayed and one where it
|
||||
-- is trimmed.
|
||||
--
|
||||
-- A clip shape defines an area and dimension to which the content should be
|
||||
-- trimmed.
|
||||
--
|
||||
-- @DOC_wibox_widget_imagebox_clip_shape_EXAMPLE@
|
||||
--
|
||||
-- @property clip_shape
|
||||
-- @tparam function|gears.shape clip_shape A `gears.shape` compatible shape function.
|
||||
-- @propemits true false
|
||||
-- @see gears.shape
|
||||
-- @see set_clip_shape
|
||||
|
||||
--- Set a clip shape for this imagebox.
|
||||
-- A clip shape define an area where the content is displayed and one where it
|
||||
-- is trimmed.
|
||||
--
|
||||
-- Any other parameters will be passed to the clip shape function.
|
||||
-- A clip shape defines an area and dimensions to which the content should be
|
||||
-- trimmed.
|
||||
--
|
||||
-- Additional parameters will be passed to the clip shape function.
|
||||
--
|
||||
-- @tparam function|gears.shape clip_shape A `gears_shape` compatible shape function.
|
||||
-- @method imagebox:set_clip_shape
|
||||
-- @method set_clip_shape
|
||||
-- @hidden
|
||||
-- @see gears.shape
|
||||
-- @see clip_shape
|
||||
function imagebox:set_clip_shape(clip_shape, ...)
|
||||
|
@ -234,22 +394,282 @@ function imagebox:set_clip_shape(clip_shape, ...)
|
|||
end
|
||||
|
||||
--- Should the image be resized to fit into the available space?
|
||||
--
|
||||
-- Note that `upscale` and `downscale` can affect the value of `resize`.
|
||||
-- If conflicting values are passed to the constructor, then the result
|
||||
-- is undefined.
|
||||
--
|
||||
-- @DOC_wibox_widget_imagebox_resize_EXAMPLE@
|
||||
-- @property resize
|
||||
-- @propemits true false
|
||||
-- @tparam boolean resize
|
||||
|
||||
--- Should the image be resized to fit into the available space?
|
||||
-- @tparam boolean allowed If `false`, the image will be clipped, else it will
|
||||
-- be resized to fit into the available space.
|
||||
-- @method imagebox:set_resize
|
||||
--- Allow the image to be upscaled (made bigger).
|
||||
--
|
||||
-- Note that `upscale` and `downscale` can affect the value of `resize`.
|
||||
-- If conflicting values are passed to the constructor, then the result
|
||||
-- is undefined.
|
||||
--
|
||||
-- @DOC_wibox_widget_imagebox_upscale_EXAMPLE@
|
||||
-- @property upscale
|
||||
-- @tparam boolean upscale
|
||||
-- @see downscale
|
||||
-- @see resize
|
||||
|
||||
--- Allow the image to be downscaled (made smaller).
|
||||
--
|
||||
-- Note that `upscale` and `downscale` can affect the value of `resize`.
|
||||
-- If conflicting values are passed to the constructor, then the result
|
||||
-- is undefined.
|
||||
--
|
||||
-- @DOC_wibox_widget_imagebox_downscale_EXAMPLE@
|
||||
-- @property downscale
|
||||
-- @tparam boolean downscale
|
||||
-- @see upscale
|
||||
-- @see resize
|
||||
|
||||
--- Set the SVG CSS stylesheet.
|
||||
--
|
||||
-- If the image is an SVG (vector graphics), this property allows to set
|
||||
-- a CSS stylesheet. It can be used to set colors and much more.
|
||||
--
|
||||
-- Note that this property is a string, not a path. If the stylesheet is
|
||||
-- stored on disk, read the content first.
|
||||
--
|
||||
--@DOC_wibox_widget_imagebox_stylesheet_EXAMPLE@
|
||||
--
|
||||
-- @property stylesheet
|
||||
-- @tparam string stylesheet
|
||||
-- @propemits true false
|
||||
|
||||
--- Set the SVG DPI (dot per inch).
|
||||
--
|
||||
-- Force a specific DPI when rendering the `.svg`. For other file formats,
|
||||
-- this does nothing.
|
||||
--
|
||||
-- It can either be a number of a table containing the `x` and `y` keys.
|
||||
--
|
||||
-- Please note that DPI and `resize` can "fight" each other and end up
|
||||
-- making the image smaller instead of bigger.
|
||||
--
|
||||
--@DOC_wibox_widget_imagebox_dpi_EXAMPLE@
|
||||
--
|
||||
-- @property dpi
|
||||
-- @tparam number|table dpi
|
||||
-- @propemits true false
|
||||
-- @see auto_dpi
|
||||
|
||||
--- Use the object DPI when rendering the SVG.
|
||||
--
|
||||
-- By default, the SVG are interpreted as-is. When this property is set,
|
||||
-- the screen DPI will be passed to the SVG renderer. Depending on which
|
||||
-- tool was used to create the `.svg`, this may do nothing at all. However,
|
||||
-- for example, if the `.svg` uses `<text>` elements and doesn't have an
|
||||
-- hardcoded stylesheet, the result will differ.
|
||||
--
|
||||
-- @property auto_dpi
|
||||
-- @tparam[opt=false] boolean auto_dpi
|
||||
-- @propemits true false
|
||||
-- @see dpi
|
||||
|
||||
for _, prop in ipairs {"stylesheet", "dpi", "auto_dpi"} do
|
||||
imagebox["set_" .. prop] = function(self, value)
|
||||
-- It will be set in :fit and :draw. The handle is shared
|
||||
-- by multiple imagebox, so it cannot be set just once.
|
||||
self._private[prop] = value
|
||||
|
||||
self:emit_signal("widget::redraw_needed")
|
||||
self:emit_signal("widget::layout_changed")
|
||||
self:emit_signal("property::" .. prop)
|
||||
end
|
||||
end
|
||||
|
||||
function imagebox:set_resize(allowed)
|
||||
self._private.resize_forbidden = not allowed
|
||||
self._private.resize = allowed
|
||||
|
||||
if allowed then
|
||||
self._private.downscale = true
|
||||
self._private.upscale = true
|
||||
self:emit_signal("property::downscale", allowed)
|
||||
self:emit_signal("property::upscale", allowed)
|
||||
end
|
||||
|
||||
self:emit_signal("widget::redraw_needed")
|
||||
self:emit_signal("widget::layout_changed")
|
||||
self:emit_signal("property::resize", allowed)
|
||||
end
|
||||
|
||||
for _, prop in ipairs {"downscale", "upscale" } do
|
||||
imagebox["set_" .. prop] = function(self, allowed)
|
||||
self._private[prop] = allowed
|
||||
|
||||
if self._private.resize ~= (self._private.upscale or self._private.downscale) then
|
||||
self._private.resize = self._private.upscale or self._private.downscale
|
||||
self:emit_signal("property::resize", self._private.resize)
|
||||
end
|
||||
|
||||
self:emit_signal("widget::redraw_needed")
|
||||
self:emit_signal("widget::layout_changed")
|
||||
self:emit_signal("property::"..prop, allowed)
|
||||
end
|
||||
end
|
||||
|
||||
--- Set the horizontal fit policy.
|
||||
--
|
||||
-- Valid values are:
|
||||
--
|
||||
-- * `"auto"`: Honor the `resize` variable and preserve the aspect ratio.
|
||||
-- This is the default behaviour.
|
||||
-- * `"none"`: Do not resize at all.
|
||||
-- * `"fit"`: Resize to the widget width.
|
||||
--
|
||||
-- Here is the result for a 22x32 image:
|
||||
--
|
||||
-- @DOC_wibox_widget_imagebox_horizontal_fit_policy_EXAMPLE@
|
||||
--
|
||||
-- @property horizontal_fit_policy
|
||||
-- @tparam[opt="auto"] string horizontal_fit_policy
|
||||
-- @propemits true false
|
||||
-- @see vertical_fit_policy
|
||||
-- @see resize
|
||||
|
||||
--- Set the vertical fit policy.
|
||||
--
|
||||
-- Valid values are:
|
||||
--
|
||||
-- * `"auto"`: Honor the `resize` varible and preserve the aspect ratio.
|
||||
-- This is the default behaviour.
|
||||
-- * `"none"`: Do not resize at all.
|
||||
-- * `"fit"`: Resize to the widget height.
|
||||
--
|
||||
-- Here is the result for a 32x22 image:
|
||||
--
|
||||
-- @DOC_wibox_widget_imagebox_vertical_fit_policy_EXAMPLE@
|
||||
--
|
||||
-- @property vertical_fit_policy
|
||||
-- @tparam[opt="auto"] string horizontal_fit_policy
|
||||
-- @propemits true false
|
||||
-- @see horizontal_fit_policy
|
||||
-- @see resize
|
||||
|
||||
|
||||
--- The vertical alignment.
|
||||
--
|
||||
-- Possible values are:
|
||||
--
|
||||
-- * `"top"`
|
||||
-- * `"center"` (default)
|
||||
-- * `"bottom"`
|
||||
--
|
||||
-- @DOC_wibox_widget_imagebox_valign_EXAMPLE@
|
||||
--
|
||||
-- @property valign
|
||||
-- @tparam[opt="center"] string valign
|
||||
-- @propemits true false
|
||||
-- @see wibox.container.place
|
||||
-- @see halign
|
||||
|
||||
--- The horizontal alignment.
|
||||
--
|
||||
-- Possible values are:
|
||||
--
|
||||
-- * `"left"`
|
||||
-- * `"center"` (default)
|
||||
-- * `"right"`
|
||||
--
|
||||
-- @DOC_wibox_widget_imagebox_halign_EXAMPLE@
|
||||
--
|
||||
-- @property halign
|
||||
-- @tparam[opt="center"] string halign
|
||||
-- @propemits true false
|
||||
-- @see wibox.container.place
|
||||
-- @see valign
|
||||
|
||||
--- The maximum scaling factor.
|
||||
--
|
||||
-- If an image is scaled too much, it gets very blurry. This
|
||||
-- property allows to limit the scaling.
|
||||
-- Use the properties `valign` and `halign` to control how the image will be
|
||||
-- aligned.
|
||||
--
|
||||
-- In the example below, the original size is 22x22
|
||||
--
|
||||
-- @DOC_wibox_widget_imagebox_max_scaling_factor_EXAMPLE@
|
||||
--
|
||||
-- @property max_scaling_factor
|
||||
-- @tparam number max_scaling_factor
|
||||
-- @propemits true false
|
||||
-- @see valign
|
||||
-- @see halign
|
||||
-- @see scaling_quality
|
||||
|
||||
--- Set the scaling aligorithm.
|
||||
--
|
||||
-- Depending on how the image is used, what is the "correct" way to
|
||||
-- scale can change. For example, upscaling a pixel art image should
|
||||
-- not make it blurry. However, scaling up a photo should not make it
|
||||
-- blocky.
|
||||
--
|
||||
--<table class='widget_list' border=1>
|
||||
-- <tr style='font-weight: bold;'>
|
||||
-- <th align='center'>Value</th>
|
||||
-- <th align='center'>Description</th>
|
||||
-- </tr>
|
||||
-- <tr><td>fast</td><td>A high-performance filter</td></tr>
|
||||
-- <tr><td>good</td><td>A reasonable-performance filter</td></tr>
|
||||
-- <tr><td>best</td><td>The highest-quality available</td></tr>
|
||||
-- <tr><td>nearest</td><td>Nearest-neighbor filtering (blocky)</td></tr>
|
||||
-- <tr><td>bilinear</td><td>Linear interpolation in two dimensions</td></tr>
|
||||
--</table>
|
||||
--
|
||||
-- The image used in the example below has a resolution of 32x22 and is
|
||||
-- intentionally blocky to highlight the difference.
|
||||
-- It is zoomed by a factor of 3.
|
||||
--
|
||||
-- @DOC_wibox_widget_imagebox_scaling_quality_EXAMPLE@
|
||||
--
|
||||
-- @property scaling_quality
|
||||
-- @tparam string scaling_quality Either `"fast"`, `"good"`, `"best"`,
|
||||
-- `"nearest"` or `"bilinear"`.
|
||||
-- @propemits true false
|
||||
-- @see resize
|
||||
-- @see horizontal_fit_policy
|
||||
-- @see vertical_fit_policy
|
||||
-- @see max_scaling_factor
|
||||
|
||||
local defaults = {
|
||||
halign = "left",
|
||||
valign = "top",
|
||||
horizontal_fit_policy = "auto",
|
||||
vertical_fit_policy = "auto",
|
||||
max_scaling_factor = 0,
|
||||
scaling_quality = "good"
|
||||
}
|
||||
|
||||
local function get_default(prop, value)
|
||||
if value == nil then return defaults[prop] end
|
||||
|
||||
return value
|
||||
end
|
||||
|
||||
for prop in pairs(defaults) do
|
||||
imagebox["set_"..prop] = function(self, value)
|
||||
if value == self._private[prop] then return end
|
||||
|
||||
self._private[prop] = get_default(prop, value)
|
||||
self:emit_signal("widget::redraw_needed")
|
||||
self:emit_signal("property::"..prop, self._private[prop])
|
||||
end
|
||||
|
||||
imagebox["get_"..prop] = function(self)
|
||||
if self._private[prop] == nil then
|
||||
return defaults[prop]
|
||||
end
|
||||
|
||||
return self._private[prop]
|
||||
end
|
||||
end
|
||||
|
||||
--- Returns a new `wibox.widget.imagebox` instance.
|
||||
--
|
||||
-- This is the constructor of `wibox.widget.imagebox`. It creates a new
|
||||
|
@ -272,12 +692,14 @@ local function new(image, resize_allowed, clip_shape, ...)
|
|||
local ret = base.make_widget(nil, nil, {enable_properties = true})
|
||||
|
||||
gtable.crush(ret, imagebox, true)
|
||||
ret._private.resize = true
|
||||
|
||||
if image then
|
||||
ret:set_image(image)
|
||||
end
|
||||
|
||||
if resize_allowed ~= nil then
|
||||
ret:set_resize(resize_allowed)
|
||||
ret.resize = resize_allowed
|
||||
end
|
||||
|
||||
ret._private.clip_shape = clip_shape
|
||||
|
@ -290,10 +712,6 @@ function imagebox.mt:__call(...)
|
|||
return new(...)
|
||||
end
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return setmetatable(imagebox, imagebox.mt)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
-- @author Emmanuel Lepage Valle
|
||||
-- @copyright 2012 Emmanuel Lepage Vallee
|
||||
-- @widgetmod wibox.widget.piechart
|
||||
-- @supermodule wibox.widget.base
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local color = require( "gears.color" )
|
||||
|
@ -260,9 +261,5 @@ local function new(data_list)
|
|||
return ret
|
||||
end
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return setmetatable(module, { __call = function(_, ...) return new(...) end })
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @widgetmod wibox.widget.progressbar
|
||||
-- @supermodule wibox.widget.base
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
@ -520,10 +521,6 @@ function progressbar.mt:__call(...)
|
|||
return progressbar.new(...)
|
||||
end
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return setmetatable(progressbar, progressbar.mt)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
-- @author Emmanuel Lepage Vallee <elv1313@gmail.com>
|
||||
-- @copyright 2014, 2017 Emmanuel Lepage Vallee
|
||||
-- @widgetmod wibox.widget.separator
|
||||
-- @supermodule wibox.widget.base
|
||||
---------------------------------------------------------------------------
|
||||
local beautiful = require( "beautiful" )
|
||||
local base = require( "wibox.widget.base" )
|
||||
|
@ -215,9 +216,5 @@ local function new(args)
|
|||
return ret
|
||||
end
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return setmetatable(separator, { __call = function(_, ...) return new(...) end })
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
-- @author Emmanuel Lepage Vallee <elv1313@gmail.com>
|
||||
-- @copyright 2015 Grigory Mishchenko, 2016 Emmanuel Lepage Vallee
|
||||
-- @widgetmod wibox.widget.slider
|
||||
-- @supermodule wibox.widget.base
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
@ -324,7 +325,7 @@ function slider:draw(_, cr, width, height)
|
|||
|
||||
local handle_height, handle_width = height, self._private.handle_width
|
||||
or beautiful.slider_handle_width
|
||||
or height/2
|
||||
or math.floor(height/2)
|
||||
|
||||
local handle_border_width = self._private.handle_border_width
|
||||
or beautiful.slider_handle_border_width
|
||||
|
@ -362,7 +363,7 @@ function slider:draw(_, cr, width, height)
|
|||
end
|
||||
else
|
||||
bar_height = bar_height or beautiful.slider_bar_height or height
|
||||
y_offset = (height - bar_height)/2
|
||||
y_offset = math.floor((height - bar_height)/2)
|
||||
end
|
||||
|
||||
|
||||
|
@ -379,8 +380,10 @@ function slider:draw(_, cr, width, height)
|
|||
bar_shape(cr, width - x_offset - right_margin, bar_height or height)
|
||||
|
||||
if bar_active_color and type(bar_color) == "string" and type(bar_active_color) == "string" then
|
||||
local bar_active_width = active_rate * (width - x_offset - right_margin)
|
||||
local bar_active_width = math.floor(
|
||||
active_rate * (width - x_offset - right_margin)
|
||||
- (handle_width - handle_border_width/2) * (active_rate - 0.5)
|
||||
)
|
||||
cr:set_source(color.create_pattern{
|
||||
type = "linear",
|
||||
from = {0,0},
|
||||
|
@ -452,7 +455,7 @@ function slider:draw(_, cr, width, height)
|
|||
|
||||
-- Get the widget size back to it's non-transfored value
|
||||
local min, _, interval = get_extremums(self)
|
||||
local rel_value = ((value-min)/interval) * (width-handle_width)
|
||||
local rel_value = math.floor(((value-min)/interval) * (width-handle_width))
|
||||
|
||||
cr:translate(x_offset + rel_value, y_offset)
|
||||
|
||||
|
@ -538,10 +541,6 @@ function slider.mt:__call(...)
|
|||
return new(...)
|
||||
end
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return setmetatable(slider, slider.mt)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
-- @author Uli Schlachter
|
||||
-- @copyright 2010 Uli Schlachter
|
||||
-- @widgetmod wibox.widget.systray
|
||||
-- @supermodule wibox.widget.base
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local wbase = require("wibox.widget.base")
|
||||
|
@ -224,10 +225,6 @@ function systray.mt:__call(...)
|
|||
return instance
|
||||
end
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return setmetatable(systray, systray.mt)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
---------------------------------------------------------------------------
|
||||
--
|
||||
--@DOC_wibox_widget_defaults_textbox_EXAMPLE@
|
||||
--
|
||||
-- @author Uli Schlachter
|
||||
-- @author dodo
|
||||
-- @copyright 2010, 2011 Uli Schlachter, dodo
|
||||
-- @widgetmod wibox.widget.textbox
|
||||
-- @supermodule wibox.widget.base
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local base = require("wibox.widget.base")
|
||||
|
@ -146,7 +148,7 @@ function textbox:get_height_for_width_at_dpi(width, dpi)
|
|||
end
|
||||
|
||||
--- Set the text of the textbox.(with
|
||||
-- [Pango markup](https://developer.gnome.org/pango/stable/pango-Markup.html)).
|
||||
-- [Pango markup](https://docs.gtk.org/Pango/pango_markup.html)).
|
||||
--
|
||||
-- @tparam string text The text to set. This can contain pango markup (e.g.
|
||||
-- `<b>bold</b>`). You can use `gears.string.escape` to escape
|
||||
|
@ -176,7 +178,7 @@ function textbox:set_markup_silently(text)
|
|||
end
|
||||
|
||||
--- Set the text of the textbox (with
|
||||
-- [Pango markup](https://developer.gnome.org/pango/stable/pango-Markup.html)).
|
||||
-- [Pango markup](https://docs.gtk.org/Pango/pango_markup.html)).
|
||||
--
|
||||
-- @property markup
|
||||
-- @tparam string text The text to set. This can contain pango markup (e.g.
|
||||
|
@ -220,17 +222,22 @@ function textbox:get_text()
|
|||
return self._private.layout.text
|
||||
end
|
||||
|
||||
--- Set a textbox ellipsize mode.
|
||||
--- Set the text ellipsize mode.
|
||||
--
|
||||
-- Valid values are:
|
||||
--
|
||||
-- * **start**
|
||||
-- * **middle**
|
||||
-- * **end**
|
||||
-- * `"start"`
|
||||
-- * `"middle"`
|
||||
-- * `"end"`
|
||||
-- * `"none"`
|
||||
--
|
||||
-- See Pango for additional details:
|
||||
-- [Layout.set_ellipsize](https://docs.gtk.org/Pango/method.Layout.set_ellipsize.html)
|
||||
--
|
||||
--@DOC_wibox_widget_textbox_ellipsize_EXAMPLE@
|
||||
--
|
||||
-- @property ellipsize
|
||||
-- @tparam string mode Where should long lines be shortened? "start", "middle"
|
||||
-- or "end".
|
||||
-- @tparam string mode The ellipsize mode.
|
||||
-- @propemits true false
|
||||
|
||||
function textbox:set_ellipsize(mode)
|
||||
|
@ -373,9 +380,26 @@ function textbox.mt.__call(_, ...)
|
|||
return new(...)
|
||||
end
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
--- Get geometry of text label, as if textbox would be created for it on the screen.
|
||||
--
|
||||
-- @tparam string text The text content, pango markup supported.
|
||||
-- @tparam[opt=nil] integer|screen s The screen on which the textbox would be displayed.
|
||||
-- @tparam[opt=beautiful.font] string font The font description as string.
|
||||
-- @treturn table Geometry (width, height) hashtable.
|
||||
-- @staticfct wibox.widget.textbox.get_markup_geometry
|
||||
function textbox.get_markup_geometry(text, s, font)
|
||||
font = font or beautiful.font
|
||||
local pctx = PangoCairo.font_map_get_default():create_context()
|
||||
local playout = Pango.Layout.new(pctx)
|
||||
playout:set_font_description(beautiful.get_font(font))
|
||||
local dpi_scale = beautiful.xresources.get_dpi(s)
|
||||
pctx:set_resolution(dpi_scale)
|
||||
playout:context_changed()
|
||||
local attr, parsed = Pango.parse_markup(text, -1, 0)
|
||||
playout.attributes, playout.text = attr, parsed
|
||||
local _, logical = playout:get_pixel_extents()
|
||||
return logical
|
||||
end
|
||||
|
||||
return setmetatable(textbox, textbox.mt)
|
||||
|
||||
|
|
|
@ -1,9 +1,46 @@
|
|||
---------------------------------------------------------------------------
|
||||
--- Text clock widget.
|
||||
--
|
||||
-- The `wibox.widget.textclock` widget is part of the Awesome WM's widget
|
||||
-- system (see @{03-declarative-layout.md}).
|
||||
--
|
||||
-- This widget displays a text clock formatted by the
|
||||
-- [GLib Date Time format](https://developer.gnome.org/glib/stable/glib-GDateTime.html#g-date-time-format)
|
||||
-- and [GTimeZone](https://developer.gnome.org/glib/stable/glib-GTimeZone.html#g-time-zone-new).
|
||||
--
|
||||
-- The `wibox.widget.textclock` inherits from `wibox.widget.textbox`. It means
|
||||
-- that, once created, the user will receive a derivated instance of
|
||||
-- `wibox.widget.textbox` associated with a private `gears.timer` to manage
|
||||
-- timed updates of the displayed clock.
|
||||
--
|
||||
-- Use a `wibox.widget.textclock`
|
||||
-- ---
|
||||
--
|
||||
-- @DOC_wibox_widget_defaults_textclock_EXAMPLE@
|
||||
--
|
||||
-- Alternatively, you can declare the `textclock` widget using the
|
||||
-- declarative pattern (Both codes are strictly equivalent):
|
||||
--
|
||||
-- @DOC_wibox_widget_declarative-pattern_textclock_EXAMPLE@
|
||||
--
|
||||
-- The GLib DateTime format
|
||||
-- ---
|
||||
--
|
||||
-- The time displayed by the textclock widget can be formated by the GLib
|
||||
-- DateTime format.
|
||||
--
|
||||
-- Here is a short list with commonly used format specifiers (extracted from
|
||||
-- the Glib API references):
|
||||
--
|
||||
--@DOC_glib_timedate_format_COMMON@
|
||||
--
|
||||
-- You can read more on the GLib DateTime format in the
|
||||
-- [GLib documentation](https://developer.gnome.org/glib/stable/glib-GDateTime.html#g-date-time-format).
|
||||
--
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @widgetmod wibox.widget.textclock
|
||||
-- @supermodule wibox.widget.textbox
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
@ -126,10 +163,6 @@ function textclock.mt:__call(...)
|
|||
return new(...)
|
||||
end
|
||||
|
||||
--@DOC_widget_COMMON@
|
||||
|
||||
--@DOC_object_COMMON@
|
||||
|
||||
return setmetatable(textclock, textclock.mt)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
4
luaa.h
4
luaa.h
|
@ -31,6 +31,10 @@
|
|||
#include "common/lualib.h"
|
||||
#include "common/luaclass.h"
|
||||
|
||||
#if !(501 <= LUA_VERSION_NUM && LUA_VERSION_NUM < 504)
|
||||
#error "Awesome only supports Lua versions 5.1-5.3 and LuaJIT2, please refer to https://awesomewm.org/apidoc/documentation/10-building-and-testing.md.html#Building"
|
||||
#endif
|
||||
|
||||
#define luaA_deprecate(L, repl) \
|
||||
do { \
|
||||
luaA_warn(L, "%s: This function is deprecated and will be removed, see %s", \
|
||||
|
|
|
@ -82,7 +82,7 @@ mousegrabber_handleevent(lua_State *L, int x, int y, uint16_t mask)
|
|||
* The function is called with one argument:
|
||||
* a table containing modifiers pointer coordinates.
|
||||
*
|
||||
* The list of valid cusrors are:
|
||||
* The list of valid cursors is:
|
||||
*
|
||||
*@DOC_cursor_c_COMMON@
|
||||
*
|
||||
|
|
118
objects/client.c
118
objects/client.c
|
@ -136,7 +136,7 @@ lua_class_t client_class;
|
|||
* @table awful.client.object
|
||||
*/
|
||||
|
||||
/** AwesomeWM is about to scan for existing clients.
|
||||
/** Emitted when AwesomeWM is about to scan for existing clients.
|
||||
*
|
||||
* Connect to this signal when code needs to be executed after screens are
|
||||
* initialized, but before clients are added.
|
||||
|
@ -145,7 +145,7 @@ lua_class_t client_class;
|
|||
* @classsignal
|
||||
*/
|
||||
|
||||
/** AwesomeWM is done scanning for clients.
|
||||
/** Emitted when AwesomeWM is done scanning for clients.
|
||||
*
|
||||
* This is emitted before the `startup` signal and after the `scanning` signal.
|
||||
*
|
||||
|
@ -153,23 +153,24 @@ lua_class_t client_class;
|
|||
* @classsignal
|
||||
*/
|
||||
|
||||
/** When a client gains focus.
|
||||
/** Emitted when a client gains focus.
|
||||
* @signal focus
|
||||
* @classsignal
|
||||
*/
|
||||
|
||||
/** Before manage, after unmanage, and when clients swap.
|
||||
/** Emitted before `request::manage`, after `request::unmanage`,
|
||||
* and when clients swap.
|
||||
* @signal list
|
||||
* @classsignal
|
||||
*/
|
||||
|
||||
/** When 2 clients are swapped
|
||||
/** Emitted when 2 clients are swapped
|
||||
* @tparam client client The other client
|
||||
* @tparam boolean is_source If self is the source or the destination of the swap
|
||||
* @signal swapped
|
||||
*/
|
||||
|
||||
/** When a new client appears and gets managed by Awesome.
|
||||
/** Emitted when a new client appears and gets managed by Awesome.
|
||||
*
|
||||
* This request should be implemented by code which track the client. It isn't
|
||||
* recommended to use this to initialize the client content. This use case is
|
||||
|
@ -188,7 +189,7 @@ lua_class_t client_class;
|
|||
* @classsignal
|
||||
*/
|
||||
|
||||
/** When a client is going away.
|
||||
/** Emitted when a client is going away.
|
||||
*
|
||||
* Each places which store `client` objects in non-weak table or whose state
|
||||
* depend on the current client should answer this request.
|
||||
|
@ -216,32 +217,32 @@ lua_class_t client_class;
|
|||
* @deprecatedsignal unmanage
|
||||
*/
|
||||
|
||||
/** When a mouse button is pressed in a client.
|
||||
/** Emitted when a mouse button is pressed in a client.
|
||||
* @signal button::press
|
||||
*/
|
||||
|
||||
/** When a mouse button is released in a client.
|
||||
/** Emitted when a mouse button is released in a client.
|
||||
*
|
||||
* @signal button::release
|
||||
*/
|
||||
|
||||
/** When the mouse enters a client.
|
||||
/** Emitted when the mouse enters a client.
|
||||
*
|
||||
* @signal mouse::enter
|
||||
*/
|
||||
|
||||
/** When the mouse leaves a client.
|
||||
/** Emitted when the mouse leaves a client.
|
||||
*
|
||||
* @signal mouse::leave
|
||||
*/
|
||||
|
||||
/**
|
||||
* When the mouse moves within a client.
|
||||
* Emitted when the mouse moves within a client.
|
||||
*
|
||||
* @signal mouse::move
|
||||
*/
|
||||
|
||||
/** When a client should get activated (focused and/or raised).
|
||||
/** Emitted when a client should get activated (focused and/or raised).
|
||||
*
|
||||
* **Contexts are:**
|
||||
*
|
||||
|
@ -279,7 +280,7 @@ lua_class_t client_class;
|
|||
* @classsignal
|
||||
*/
|
||||
|
||||
/** When an event could lead to the client being activated.
|
||||
/** Emitted when an event could lead to the client being activated.
|
||||
*
|
||||
* This is an layer "on top" of `request::activate` for event which are not
|
||||
* actual request for activation/focus, but where "it would be nice" if the
|
||||
|
@ -300,7 +301,7 @@ lua_class_t client_class;
|
|||
*
|
||||
*/
|
||||
|
||||
/** When something request a client geometry to be modified.
|
||||
/** Emitted when something request a client's geometry to be modified.
|
||||
*
|
||||
* @signal request::geometry
|
||||
* @tparam client c The client
|
||||
|
@ -315,23 +316,39 @@ lua_class_t client_class;
|
|||
* @classsignal
|
||||
*/
|
||||
|
||||
/** When the tag requests to be moved to a tag or needs a new tag.
|
||||
/** Emitted when a client requests to be moved to a tag or needs a new tag.
|
||||
*
|
||||
* @signal request::tag
|
||||
* @tparam client c The client requesting a new tag.
|
||||
* @classsignal
|
||||
*/
|
||||
|
||||
/** When the client requests to become urgent.
|
||||
/** Emitted when any client's `urgent` property changes.
|
||||
*
|
||||
* Emitted both when `urgent = true` and `urgent = false`, so you will likely
|
||||
* want to check `c.urgent` within the signal callback.
|
||||
*
|
||||
* client.connect_signal("property::urgent", function(c)
|
||||
* if c.urgent then
|
||||
* naughty.notify {
|
||||
* title = "Urgent client",
|
||||
* message = c.name,
|
||||
* }
|
||||
* end
|
||||
* end)
|
||||
*
|
||||
* @signal request::urgent
|
||||
* @tparam client c The client whose property changed.
|
||||
* @classsignal
|
||||
*/
|
||||
|
||||
/** Emitted during startup to gather the default client mousebindings.
|
||||
/** Emitted once to request default client mousebindings during the initial
|
||||
* startup sequence.
|
||||
*
|
||||
* This signals gives a chance to all module to register new client keybindings.
|
||||
* Assuming the client rules does not overwrite them with the `keys` property,
|
||||
* they will be added to all clients.
|
||||
* This signal gives all modules a chance to register their default client
|
||||
* mousebindings.
|
||||
* They will then be added to all new clients, unless rules overwrite them via
|
||||
* the `buttons` property.
|
||||
*
|
||||
* @signal request::default_mousebindings
|
||||
* @tparam string context The reason why the signal was sent (currently always
|
||||
|
@ -339,41 +356,30 @@ lua_class_t client_class;
|
|||
* @classsignal
|
||||
*/
|
||||
|
||||
/** Emitted during startup to gather the default client keybindings.
|
||||
/** Emitted once to request default client keybindings during the initial
|
||||
* startup sequence.
|
||||
*
|
||||
* This signals gives a chance to all module to register new client keybindings.
|
||||
* Assuming the client rules does not overwrite them with the `keys` property,
|
||||
* they will be added to all clients.
|
||||
* This signal gives all modules a chance to register their default client
|
||||
* keybindings.
|
||||
* They will then be added to all new clients, unless rules overwrite them via
|
||||
* the `keys` property.
|
||||
*
|
||||
* @signal request::default_keybindings
|
||||
* @tparam string context The reason why the signal was sent (currently always
|
||||
* `startup`).
|
||||
* @classsignal
|
||||
*/
|
||||
|
||||
/** Sent once when AwesomeWM starts to add default keybindings.
|
||||
*
|
||||
* Keybindings can be set directly on clients. Actually, older version of
|
||||
* AwesomeWM did that through the rules. However this makes it impossible for
|
||||
* auto-configured modules to add their own keybindings. Using the signals,
|
||||
* `rc.lua` or any module can cleanly manage keybindings.
|
||||
*
|
||||
* @signal request::default_keybindings
|
||||
* @tparam string context The context (currently always "startup").
|
||||
* @classsignal
|
||||
* @request client default_keybindings startup granted Sent when AwesomeWM starts.
|
||||
*/
|
||||
|
||||
/** When a client gets tagged.
|
||||
/** Emitted when a client gets tagged.
|
||||
* @signal tagged
|
||||
* @tparam tag t The tag object.
|
||||
*/
|
||||
|
||||
/** When a client gets unfocused.
|
||||
/** Emitted when a client gets unfocused.
|
||||
* @signal unfocus
|
||||
*/
|
||||
|
||||
/** When a client gets untagged.
|
||||
/** Emitted when a client gets untagged.
|
||||
* @signal untagged
|
||||
* @tparam tag t The tag object.
|
||||
*/
|
||||
|
@ -404,13 +410,13 @@ lua_class_t client_class;
|
|||
/**
|
||||
* The focused `client` or nil (in case there is none).
|
||||
*
|
||||
* It is not recommanded to set the focused client using
|
||||
* this property. Please use `c:activate{}` instead of
|
||||
* It is not recommended to set the focused client using
|
||||
* this property. Please use @{client.activate} instead of
|
||||
* `client.focus = c`. Setting the focus directly bypasses
|
||||
* all the filters and emits fewer signals, which tend to
|
||||
* cause unwanted side effects and make it harder to alter
|
||||
* the code behavior in the future. It usually takes *more*
|
||||
* code to use this rather than `:activate{}` because all
|
||||
* code to use this rather than @{client.activate} because all
|
||||
* the boilerplate code (such as `c:raise()`) needs to be
|
||||
* added everywhere.
|
||||
*
|
||||
|
@ -591,12 +597,12 @@ lua_class_t client_class;
|
|||
*/
|
||||
|
||||
/**
|
||||
* The machine client is running on.
|
||||
* The machine the client is running on.
|
||||
*
|
||||
* X11 windows can "live" in another computer but shown
|
||||
* X11 windows can "live" in one computer but be shown
|
||||
* in another one. This is called "network transparency"
|
||||
* and is either used directly by allowing remote windows
|
||||
* using the `xhosts` command for using proxies such as
|
||||
* using the `xhosts` command or using proxies such as
|
||||
* `ssh -X` or `ssh -Y`.
|
||||
*
|
||||
* According to EWMH, this property contains the value
|
||||
|
@ -622,7 +628,7 @@ lua_class_t client_class;
|
|||
* This property holds the client icon closest to the size configured via
|
||||
* @{awesome.set_preferred_icon_size}.
|
||||
*
|
||||
* It is not a path or an "real" file. Rather, it is already a bitmap surface.
|
||||
* It is not a path or a "real" file. Rather, it is already a bitmap surface.
|
||||
*
|
||||
* Typically you would want to use @{awful.widget.clienticon} to get this as a
|
||||
* widget.
|
||||
|
@ -649,6 +655,14 @@ lua_class_t client_class;
|
|||
* The available sizes of client icons. This is a table where each entry
|
||||
* contains the width and height of an icon.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* {
|
||||
* { 24, 24 },
|
||||
* { 32, 32 },
|
||||
* { 64, 64 },
|
||||
* }
|
||||
*
|
||||
* @property icon_sizes
|
||||
* @tparam table sizes
|
||||
* @propemits false false
|
||||
|
@ -750,9 +764,13 @@ lua_class_t client_class;
|
|||
* Note that setting this directly will override and disable all related theme
|
||||
* variables.
|
||||
*
|
||||
* Setting a transparent color (e.g. to implement dynamic borders without size
|
||||
* changes) is supported, but requires the color to be set to `#00000000`
|
||||
* specifically. Other RGB colors with an alpha of `0` won't work.
|
||||
*
|
||||
* @property border_color
|
||||
* @tparam color border_color Any string, gradients and patterns will be converted to a
|
||||
* cairo pattern.
|
||||
* @tparam color border_color Any string, gradient or pattern definition that
|
||||
* can be converted to a cairo pattern.
|
||||
* @propemits false false
|
||||
* @usebeautiful beautiful.border_color_marked The fallback color when the
|
||||
* client is marked.
|
||||
|
|
|
@ -205,7 +205,7 @@
|
|||
|
||||
lua_class_t tag_class;
|
||||
|
||||
/** When a tag requests to be selected.
|
||||
/** Emitted when a tag requests to be selected.
|
||||
* @signal request::select
|
||||
* @tparam string context The reason why it was called.
|
||||
* @request tag select ewmh granted When the client request to be moved to a
|
||||
|
@ -214,11 +214,17 @@ lua_class_t tag_class;
|
|||
*/
|
||||
|
||||
/**
|
||||
* This signal is emitted to fill the list of default layouts.
|
||||
* This signal is emitted to request the list of default layouts.
|
||||
*
|
||||
* It is emitted on the global `tag` class rather than individual tag objects.
|
||||
* The default handler is part of `rc.lua`. New modules can also use this signal
|
||||
* to dynamically add new layouts to the list of default layouts.
|
||||
* This default handler is part of `rc.lua`:
|
||||
*
|
||||
* @DOC_awful_tag_request_default_layouts_EXAMPLE@
|
||||
*
|
||||
* External modules can also use this signal to dynamically add additional
|
||||
* default layouts.
|
||||
*
|
||||
* @DOC_awful_tag_module_default_layouts_EXAMPLE@
|
||||
*
|
||||
* @signal request::default_layouts
|
||||
* @tparam string context The context (currently always "startup").
|
||||
|
@ -240,12 +246,12 @@ lua_class_t tag_class;
|
|||
* @tparam table hints A, currently empty, table with hints.
|
||||
*/
|
||||
|
||||
/** When a client gets tagged with this tag.
|
||||
/** Emitted when a client gets tagged with this tag.
|
||||
* @signal tagged
|
||||
* @tparam client c The tagged client.
|
||||
*/
|
||||
|
||||
/** When a client gets untagged with this tag.
|
||||
/** Emitted when a client gets untagged with this tag.
|
||||
* @signal untagged
|
||||
* @tparam client c The untagged client.
|
||||
*/
|
||||
|
|
|
@ -444,6 +444,9 @@ options_check_args(int argc, char **argv, int *init_flags, string_array_t *paths
|
|||
if (confpath != NULL)
|
||||
fatal("--config may only be specified once");
|
||||
confpath = a_strdup(optarg);
|
||||
|
||||
/* Make sure multi-file config works */
|
||||
string_array_append(paths, g_path_get_dirname(optarg));
|
||||
break;
|
||||
case 'm':
|
||||
/* Validation */
|
||||
|
|
7
root.c
7
root.c
|
@ -481,6 +481,11 @@ luaA_root_wallpaper(lua_State *L)
|
|||
{
|
||||
if(lua_gettop(L) == 1)
|
||||
{
|
||||
/* Avoid `error()s` down the line. If this happens during
|
||||
* initialization, AwesomeWM can be stuck in an infinite loop */
|
||||
if(lua_isnil(L, -1))
|
||||
return 0;
|
||||
|
||||
cairo_pattern_t *pattern = (cairo_pattern_t *)lua_touserdata(L, -1);
|
||||
lua_pushboolean(L, root_set_wallpaper(pattern));
|
||||
/* Don't return the wallpaper, it's too easy to get memleaks */
|
||||
|
@ -602,7 +607,7 @@ const struct luaL_Reg awesome_root_methods[] =
|
|||
{ "cursor", luaA_root_cursor },
|
||||
{ "fake_input", luaA_root_fake_input },
|
||||
{ "drawins", luaA_root_drawins },
|
||||
{ "wallpaper", luaA_root_wallpaper },
|
||||
{ "_wallpaper", luaA_root_wallpaper },
|
||||
{ "size", luaA_root_size },
|
||||
{ "size_mm", luaA_root_size_mm },
|
||||
{ "tags", luaA_root_tags },
|
||||
|
|
|
@ -41,9 +41,20 @@ describe('helper functions', function()
|
|||
assert.are_equal('<span property1="foo">', get_tag(sample_markup))
|
||||
end)
|
||||
end)
|
||||
describe('helper functions multibyte', function()
|
||||
local sample_markup = 'Сперва<span property1="foo">Высокоосвещенный</span>Конечный'
|
||||
it('main', function()
|
||||
assert.are_equal('Сперва', get_first_part(sample_markup))
|
||||
assert.are_equal('Высокоосвещенный', get_highlighted_part(sample_markup))
|
||||
assert.are_equal('Конечный', get_last_part(sample_markup))
|
||||
assert.are_equal('СперваВысокоосвещенныйКонечный', get_prompt_text(sample_markup))
|
||||
assert.are_equal('<span property1="foo">', get_tag(sample_markup))
|
||||
end)
|
||||
end)
|
||||
|
||||
|
||||
local function enter_text(callback, text)
|
||||
for char in string.gmatch(text, '.') do
|
||||
for char in string.gmatch(text, '([%z\1-\127\194-\244][\128-\191]*)') do
|
||||
callback({}, char, 'press')
|
||||
callback({}, char, 'release')
|
||||
end
|
||||
|
@ -62,7 +73,20 @@ insulate('main', function ()
|
|||
}
|
||||
-- luacheck: globals string
|
||||
function string.wlen(self)
|
||||
return #self
|
||||
local _, string_length = string.gsub(self, "[^\128-\193]", "")
|
||||
local byte = string.byte(self)
|
||||
if (
|
||||
#self > 0 and string_length == 0
|
||||
) or (
|
||||
byte and
|
||||
(
|
||||
(byte >= 194 and byte <= 244)
|
||||
) and
|
||||
string_length == 1 and #self == 1
|
||||
) then
|
||||
return -1
|
||||
end
|
||||
return string_length
|
||||
end
|
||||
local keygrabber = require("awful.keygrabber")
|
||||
package.loaded['awful.keygrabber'] = mock(keygrabber, true)
|
||||
|
@ -171,6 +195,40 @@ insulate('main', function ()
|
|||
prompt_callback({}, 'Left', 'press')
|
||||
assert_prompt_text('comman', 'd', ' ')
|
||||
end)
|
||||
it('moving cursor readline', function()
|
||||
prompt.run{
|
||||
textbox = atextbox,
|
||||
}
|
||||
enter_text(prompt_callback, 'command')
|
||||
prompt_callback({'Control'}, 'a', 'press')
|
||||
assert_prompt_text('', 'c', 'ommand ')
|
||||
|
||||
prompt_callback({'Control'}, 'f', 'press')
|
||||
assert_prompt_text('c', 'o', 'mmand ')
|
||||
|
||||
prompt_callback({'Control'}, 'e', 'press')
|
||||
assert_prompt_text('command', ' ', '')
|
||||
|
||||
prompt_callback({'Control'}, 'b', 'press')
|
||||
assert_prompt_text('comman', 'd', ' ')
|
||||
end)
|
||||
it('moving cursor readline multibyte', function()
|
||||
prompt.run{
|
||||
textbox = atextbox,
|
||||
}
|
||||
enter_text(prompt_callback, 'кокаинум')
|
||||
prompt_callback({'Control'}, 'a', 'press')
|
||||
assert_prompt_text('', 'к', 'окаинум ')
|
||||
|
||||
prompt_callback({'Control'}, 'f', 'press')
|
||||
assert_prompt_text('к', 'о', 'каинум ')
|
||||
|
||||
prompt_callback({'Control'}, 'e', 'press')
|
||||
assert_prompt_text('кокаинум', ' ', '')
|
||||
|
||||
prompt_callback({'Control'}, 'b', 'press')
|
||||
assert_prompt_text('кокаину', 'м', ' ')
|
||||
end)
|
||||
it('backspace', function()
|
||||
prompt.run{
|
||||
textbox = atextbox,
|
||||
|
@ -192,6 +250,70 @@ insulate('main', function ()
|
|||
prompt_callback({}, 'BackSpace', 'press')
|
||||
assert_prompt_text('o', 'm', 'an ')
|
||||
end)
|
||||
it('backspace multibyte', function()
|
||||
prompt.run{
|
||||
textbox = atextbox,
|
||||
}
|
||||
enter_text(prompt_callback, 'кокаинум')
|
||||
prompt_callback({}, 'BackSpace', 'press')
|
||||
assert_prompt_text('кокаину', ' ', '')
|
||||
|
||||
prompt_callback({}, 'Home', 'press')
|
||||
prompt_callback({}, 'BackSpace', 'press')
|
||||
assert_prompt_text('', 'к', 'окаину ')
|
||||
|
||||
--@TODO: Left/Right not yet implemented for multibyte chars
|
||||
--prompt_callback({}, 'Right', 'press')
|
||||
--prompt_callback({}, 'BackSpace', 'press')
|
||||
--assert_prompt_text('', 'о', 'каину ')
|
||||
|
||||
--prompt_callback({}, 'Right', 'press')
|
||||
--prompt_callback({}, 'Right', 'press')
|
||||
--prompt_callback({}, 'BackSpace', 'press')
|
||||
--assert_prompt_text('о', 'а', 'ину ')
|
||||
end)
|
||||
it('backspace readline', function()
|
||||
prompt.run{
|
||||
textbox = atextbox,
|
||||
}
|
||||
enter_text(prompt_callback, 'command')
|
||||
prompt_callback({'Control'}, 'h', 'press')
|
||||
assert_prompt_text('comman', ' ', '')
|
||||
|
||||
prompt_callback({'Control'}, 'a', 'press')
|
||||
prompt_callback({'Control'}, 'h', 'press')
|
||||
assert_prompt_text('', 'c', 'omman ')
|
||||
|
||||
prompt_callback({'Control'}, 'f', 'press')
|
||||
prompt_callback({'Control'}, 'h', 'press')
|
||||
assert_prompt_text('', 'o', 'mman ')
|
||||
|
||||
prompt_callback({'Control'}, 'f', 'press')
|
||||
prompt_callback({'Control'}, 'f', 'press')
|
||||
prompt_callback({'Control'}, 'h', 'press')
|
||||
assert_prompt_text('o', 'm', 'an ')
|
||||
end)
|
||||
it('backspace readline multibyte', function()
|
||||
prompt.run{
|
||||
textbox = atextbox,
|
||||
}
|
||||
enter_text(prompt_callback, 'кокаинум')
|
||||
prompt_callback({'Control'}, 'h', 'press')
|
||||
assert_prompt_text('кокаину', ' ', '')
|
||||
|
||||
prompt_callback({'Control'}, 'a', 'press')
|
||||
prompt_callback({'Control'}, 'h', 'press')
|
||||
assert_prompt_text('', 'к', 'окаину ')
|
||||
|
||||
prompt_callback({'Control'}, 'f', 'press')
|
||||
prompt_callback({'Control'}, 'h', 'press')
|
||||
assert_prompt_text('', 'о', 'каину ')
|
||||
|
||||
prompt_callback({'Control'}, 'f', 'press')
|
||||
prompt_callback({'Control'}, 'f', 'press')
|
||||
prompt_callback({'Control'}, 'h', 'press')
|
||||
assert_prompt_text('о', 'а', 'ину ')
|
||||
end)
|
||||
it('delete', function()
|
||||
prompt.run{
|
||||
textbox = atextbox,
|
||||
|
|
|
@ -12,8 +12,8 @@ describe("beautiful init", function()
|
|||
|
||||
-- Check beautiful.get_font and get_merged_font
|
||||
it('Check beautiful.get_font', function()
|
||||
assert.is_same(beautiful.get_font("Monospace Bold 12"),
|
||||
beautiful.get_merged_font("Monospace 12", "Bold"))
|
||||
assert.is_same(beautiful.get_font("Monospace Bold 12"):to_string(),
|
||||
beautiful.get_merged_font("Monospace 12", "Bold"):to_string())
|
||||
end)
|
||||
|
||||
-- Check beautiful.get_font_height
|
||||
|
|
|
@ -115,22 +115,40 @@ describe("gears.filesystem", function()
|
|||
assert.is_true(test_b == "a.png"
|
||||
or test_b == "b.jpg")
|
||||
|
||||
-- Any file found (selected extensions)
|
||||
local test_c = gfs.get_random_file_from_dir(root .. "filesystem_tests", {".png", ".jpg"})
|
||||
assert.is_true(test_c == "a.png"
|
||||
or test_c == "b.jpg")
|
||||
|
||||
-- Test absolute paths.
|
||||
local test_d = gfs.get_random_file_from_dir(root .. "filesystem_tests", {".png", ".jpg"}, true)
|
||||
assert.is_true(test_d == root .. "filesystem_tests/a.png"
|
||||
or test_d == root .. "filesystem_tests/b.jpg")
|
||||
|
||||
-- Make sure the paths are generated correctly.
|
||||
assert.is_nil(test_d:match("//"))
|
||||
|
||||
-- "." in filename test cases with extensions
|
||||
local test_c = gfs.get_random_file_from_dir(root .. "filesystem_tests/y", {"ext"})
|
||||
assert.is_true(test_c == "filename.ext"
|
||||
or test_c == ".filename.ext"
|
||||
or test_c == "file.name.ext"
|
||||
or test_c == ".file.name.ext")
|
||||
local test_e = gfs.get_random_file_from_dir(root .. "filesystem_tests/y", {"ext"})
|
||||
assert.is_true(test_e == "filename.ext"
|
||||
or test_e == ".filename.ext"
|
||||
or test_e == "file.name.ext"
|
||||
or test_e == ".file.name.ext")
|
||||
|
||||
-- "." in filename test cases with no extensions
|
||||
local test_d = gfs.get_random_file_from_dir(root .. "filesystem_tests/y", {""})
|
||||
assert.is_true(test_d == "filename"
|
||||
or test_d == "filename."
|
||||
or test_d == "filename.ext."
|
||||
or test_d == ".filename"
|
||||
or test_d == ".filename."
|
||||
or test_d == "file.name.ext."
|
||||
or test_d == ".file.name.ext.")
|
||||
local test_f = gfs.get_random_file_from_dir(root .. "filesystem_tests/y", {""})
|
||||
assert.is_true(test_f == "filename"
|
||||
or test_f == "filename."
|
||||
or test_f == "filename.ext."
|
||||
or test_f == ".filename"
|
||||
or test_f == ".filename."
|
||||
or test_f == "file.name.ext."
|
||||
or test_f == ".file.name.ext.")
|
||||
|
||||
-- Test invalid directories.
|
||||
local test_g = gfs.get_random_file_from_dir(root .. "filesystem_tests/fake_dir")
|
||||
assert.is_nil(test_g)
|
||||
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
|
|
@ -7,6 +7,34 @@ describe("gears.table", function()
|
|||
assert.is.same(gtable.keys(t), { 1, 2, "a" })
|
||||
end)
|
||||
|
||||
describe("gears.table.count_keys", function()
|
||||
it("counts keys in an empty table", function()
|
||||
local t = {}
|
||||
assert.is.same(gtable.count_keys(t), 0)
|
||||
end)
|
||||
|
||||
it("counts keys in a sparse array", function()
|
||||
local t = { 1, nil, 3 }
|
||||
assert.is.same(gtable.count_keys(t), 2)
|
||||
end)
|
||||
|
||||
it("counts keys in a regular array", function()
|
||||
local t = { 1, 2, 3 }
|
||||
assert.is.same(gtable.count_keys(t), 3)
|
||||
end)
|
||||
|
||||
it("counts keys in a hash table", function()
|
||||
local t = { a = 1, b = "2", c = true }
|
||||
assert.is.same(gtable.count_keys(t), 3)
|
||||
end)
|
||||
|
||||
it("counts keys in a mixed table", function()
|
||||
local t = { 1, a = 2, nil, 4 }
|
||||
assert.is.same(gtable.count_keys(t), 3)
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
it("table.keys_filter", function()
|
||||
local t = { "a", 1, function() end, false}
|
||||
assert.is.same(gtable.keys_filter(t, "number", "function"), { 2, 3 })
|
||||
|
@ -104,3 +132,5 @@ describe("gears.table", function()
|
|||
end)
|
||||
end)
|
||||
end)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue