Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
15a7cb9cf9 | ||
|
|
0234e81811 | ||
|
|
6f62c7f21c | ||
|
|
3c000b8a6e | ||
|
|
0f9b041b20 | ||
|
|
98f6ac9c48 | ||
|
|
9861d24c2a | ||
|
|
f74fc3e8ca | ||
|
|
09b2c49eb3 | ||
|
|
ab62d2a3cf | ||
|
|
fa55571118 | ||
|
|
a516cf8f59 | ||
|
|
074a654597 | ||
|
|
472cf5382c | ||
|
|
82afefe5f8 | ||
|
|
677660c1c6 | ||
|
|
e9311431f8 | ||
|
|
e5d2481d6d | ||
|
|
fc9dae95f9 | ||
|
|
dd0671440d | ||
|
|
0b1b33ea84 | ||
|
|
e3278ecf27 | ||
|
|
2401855b70 | ||
|
|
da291cefa5 | ||
|
|
e2e05748f7 | ||
|
|
c20ea98de4 | ||
|
|
d0d977ff56 | ||
|
|
cf48fc47df | ||
|
|
335d4cc9ec | ||
|
|
c7222d22bd | ||
|
|
4fffba005d | ||
|
|
b93d0f5f1e | ||
|
|
d39e669743 | ||
|
|
f9826edc24 | ||
|
|
5e645acbd0 | ||
|
|
1042639a08 | ||
|
|
ab8c6477cb | ||
|
|
0fbe8bdb39 | ||
|
|
a992efb0cb | ||
|
|
b97ccf0379 | ||
|
|
7a446364dc | ||
|
|
449a20ce9b | ||
|
|
ae4e8b9294 | ||
|
|
b4fa0edf28 | ||
|
|
e09b145f3a | ||
|
|
004094ef78 | ||
|
|
0c4e7645d0 | ||
|
|
c777e8280d | ||
|
|
2ea64d0603 | ||
|
|
dcdf2c1df3 | ||
|
|
c1841ec169 | ||
|
|
e1c77f049f | ||
|
|
fa624380b1 | ||
|
|
d8900ef80f | ||
|
|
46e63e9faa | ||
|
|
af82ffec78 | ||
|
|
b7e0ff6fd1 | ||
|
|
ced6f57dfd | ||
|
|
21e29d99c3 | ||
|
|
c31c7b92e5 | ||
|
|
0bbf0cbd9f | ||
|
|
70f6748f3c | ||
|
|
aaa41f0384 | ||
|
|
a053b4e555 | ||
|
|
36498f2acf | ||
|
|
bd84c6645a | ||
|
|
f42d80598f | ||
|
|
4004023297 | ||
|
|
9896260636 |
No files matched your search
@@ -0,0 +1 @@
|
|||||||
|
ko_fi: felitendo
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
name: 💡 Feature request
|
||||||
|
description: An idea to make middleclick-autoscroll better.
|
||||||
|
labels:
|
||||||
|
- enhancement
|
||||||
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
id: checks
|
||||||
|
attributes:
|
||||||
|
label: Before you start
|
||||||
|
options:
|
||||||
|
- label: I searched the issues and this is not requested yet.
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: problem
|
||||||
|
attributes:
|
||||||
|
label: What problem would this solve?
|
||||||
|
description: What are you trying to do, and what gets in the way?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: idea
|
||||||
|
attributes:
|
||||||
|
label: What would you like?
|
||||||
|
description: How it could work. A rough idea is fine.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: alternatives
|
||||||
|
attributes:
|
||||||
|
label: Other ways you thought of
|
||||||
|
- type: textarea
|
||||||
|
id: more
|
||||||
|
attributes:
|
||||||
|
label: Anything else?
|
||||||
|
description: Mockups, screenshots, or other tools that do it well.
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
name: 🐛 Bug report
|
||||||
|
description: Something does not work as it should.
|
||||||
|
labels:
|
||||||
|
- bug
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: Thanks for taking the time! The more you fill in, the faster it can be fixed.
|
||||||
|
- type: checkboxes
|
||||||
|
id: checks
|
||||||
|
attributes:
|
||||||
|
label: Before you start
|
||||||
|
options:
|
||||||
|
- label: I searched the issues and this is not reported yet.
|
||||||
|
required: true
|
||||||
|
- label: I use the latest version.
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: what
|
||||||
|
attributes:
|
||||||
|
label: What happened?
|
||||||
|
description: What did you do, and what went wrong?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: steps
|
||||||
|
attributes:
|
||||||
|
label: Steps to reproduce
|
||||||
|
placeholder: |
|
||||||
|
1.
|
||||||
|
2.
|
||||||
|
3.
|
||||||
|
- type: textarea
|
||||||
|
id: expected
|
||||||
|
attributes:
|
||||||
|
label: What did you expect?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: app
|
||||||
|
attributes:
|
||||||
|
label: App
|
||||||
|
description: 'Which app, and how it is installed: native package, Flatpak, Snap or AppImage.'
|
||||||
|
placeholder: Discord, Flatpak
|
||||||
|
- type: input
|
||||||
|
id: version
|
||||||
|
attributes:
|
||||||
|
label: Version
|
||||||
|
description: The output of `middleclick-autoscroll --version`.
|
||||||
|
placeholder: middleclick-autoscroll 1.6.0
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: dropdown
|
||||||
|
id: install
|
||||||
|
attributes:
|
||||||
|
label: How did you install it?
|
||||||
|
options:
|
||||||
|
- AUR (Arch, CachyOS, EndeavourOS, Manjaro)
|
||||||
|
- Fedora package
|
||||||
|
- Bazzite
|
||||||
|
- Debian or Ubuntu package
|
||||||
|
- openSUSE package
|
||||||
|
- Built from source
|
||||||
|
- Other
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: system
|
||||||
|
attributes:
|
||||||
|
label: System
|
||||||
|
description: Distribution, desktop and session (Wayland or X11).
|
||||||
|
placeholder: CachyOS, KDE Plasma 6.4, Wayland
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: logs
|
||||||
|
attributes:
|
||||||
|
label: Status and logs
|
||||||
|
description: The output of `middleclick-autoscroll status` and `middleclick-autoscroll list`.
|
||||||
|
render: shell
|
||||||
|
- type: textarea
|
||||||
|
id: more
|
||||||
|
attributes:
|
||||||
|
label: Anything else?
|
||||||
|
description: Screenshots, videos or anything else that could help.
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
Executable
+136
@@ -0,0 +1,136 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Builds the GitHub release notes for a tag, the way big projects such as
|
||||||
|
# Immich lay them out: the hand-written entry from CHANGELOG.md (a welcome,
|
||||||
|
# the highlights), a support section, then every commit since the last
|
||||||
|
# release, sorted by kind, and a link to the full changelog.
|
||||||
|
#
|
||||||
|
# .github/release-notes.sh v1.2.0 the notes
|
||||||
|
# .github/release-notes.sh --title v1.2.0 the title (checks the entry exists)
|
||||||
|
#
|
||||||
|
# Commit authors come from the GitHub API through gh. Without it the list
|
||||||
|
# goes without them.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.."
|
||||||
|
|
||||||
|
title=0
|
||||||
|
if [[ ${1:-} == --title ]]; then
|
||||||
|
title=1
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
tag="${1:?usage: release-notes.sh [--title] vX.Y.Z}"
|
||||||
|
|
||||||
|
if ! grep -qx "## $tag" CHANGELOG.md; then
|
||||||
|
echo "CHANGELOG.md has no entry for $tag. Add \"## $tag\" first." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if (( title )); then
|
||||||
|
printf '%s\n' "$tag"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
repo="${GITHUB_REPOSITORY:-$(git remote get-url origin | sed -E 's#^.*github\.com[:/]##; s#\.git$##')}"
|
||||||
|
name="${repo#*/}"
|
||||||
|
|
||||||
|
# The entry: up to the next one, without the date line (GitHub shows the
|
||||||
|
# date), one heading level up, outside code blocks.
|
||||||
|
entry="$(awk -v h="## $tag" '
|
||||||
|
$0 == h { on = 1; next }
|
||||||
|
on && /^## / { exit }
|
||||||
|
!on { next }
|
||||||
|
/^```/ { code = !code }
|
||||||
|
!code && /^_[0-9]{4}-[0-9]{2}-[0-9]{2}_$/ { next }
|
||||||
|
!code && /^###/ { sub(/^#/, "") }
|
||||||
|
{ print }
|
||||||
|
' CHANGELOG.md | sed -e '/./,$!d')"
|
||||||
|
|
||||||
|
# The commits: from the last release, or from the start. A tag that does not
|
||||||
|
# exist yet is a preview of what HEAD would become.
|
||||||
|
if git rev-parse -q --verify "refs/tags/$tag" > /dev/null; then
|
||||||
|
target="$tag"
|
||||||
|
prev="$(git describe --tags --abbrev=0 --match 'v[0-9]*' "$tag^" 2>/dev/null || true)"
|
||||||
|
else
|
||||||
|
target="$(git rev-parse HEAD)"
|
||||||
|
prev="$(git describe --tags --abbrev=0 --match 'v[0-9]*' HEAD 2>/dev/null || true)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
declare -A login=()
|
||||||
|
if command -v gh > /dev/null; then
|
||||||
|
if [[ -n $prev ]]; then
|
||||||
|
api=(api "repos/$repo/compare/$prev...$target" --jq '.commits[] | [.sha, (.author.login // "")] | @tsv')
|
||||||
|
else
|
||||||
|
api=(api --paginate "repos/$repo/commits?sha=$target&per_page=100" --jq '.[] | [.sha, (.author.login // "")] | @tsv')
|
||||||
|
fi
|
||||||
|
while IFS=$'\t' read -r sha who; do
|
||||||
|
[[ -n $who ]] && login[$sha]="$who"
|
||||||
|
done < <(gh "${api[@]}" 2>/dev/null || true)
|
||||||
|
fi
|
||||||
|
|
||||||
|
declare -A list=()
|
||||||
|
count_maint=0
|
||||||
|
while IFS=$'\t' read -r sha subject body; do
|
||||||
|
# Version bumps say nothing a reader needs.
|
||||||
|
[[ $subject =~ ^(chore:\ )?($name\ )?v?[0-9]+\.[0-9]+\.[0-9]+$ ]] && continue
|
||||||
|
|
||||||
|
case "$subject" in
|
||||||
|
*!:*) kind=breaking ;;
|
||||||
|
feat:* | feat\(*) kind=feat ;;
|
||||||
|
fix:* | fix\(*) kind=fix ;;
|
||||||
|
perf:* | perf\(*) kind=enh ;;
|
||||||
|
docs:* | docs\(*) kind=docs ;;
|
||||||
|
chore* | ci:* | ci\(* | build* | refactor* | test* | style*) kind=maint ;;
|
||||||
|
# Older commits without a prefix, sorted by what they say.
|
||||||
|
*README* | *readme* | *Readme*) kind=docs ;;
|
||||||
|
Add\ * | Put\ * | Introduce\ *) kind=feat ;;
|
||||||
|
Fix\ * | Repair\ * | Recover\ * | Stop\ *) kind=fix ;;
|
||||||
|
*\ *) kind=enh ;;
|
||||||
|
*) kind=maint ;;
|
||||||
|
esac
|
||||||
|
[[ $body == *"BREAKING CHANGE"* ]] && kind=breaking
|
||||||
|
[[ $subject == "Initial commit" ]] && kind=maint
|
||||||
|
|
||||||
|
line="* $subject"
|
||||||
|
[[ -n ${login[$sha]:-} ]] && line+=" by @${login[$sha]}"
|
||||||
|
line+=" in https://github.com/$repo/commit/$sha"
|
||||||
|
list[$kind]+="$line"$'\n'
|
||||||
|
[[ $kind == maint ]] && count_maint=$((count_maint + 1))
|
||||||
|
done < <(git log --reverse --no-merges --format='%H%x09%s%x09%b%x1e' "${prev:+$prev..}$target" | tr '\n\036' ' \n' | sed 's/^ //')
|
||||||
|
|
||||||
|
changes=''
|
||||||
|
for pair in "breaking:🚨 Breaking Changes" "feat:🚀 Features" "enh:🌟 Enhancements" "fix:🐛 Bug fixes" "docs:📚 Documentation"; do
|
||||||
|
kind="${pair%%:*}"
|
||||||
|
[[ -n ${list[$kind]:-} ]] || continue
|
||||||
|
changes+="### ${pair#*:}"$'\n'"${list[$kind]}"
|
||||||
|
done
|
||||||
|
if [[ -n ${list[maint]:-} ]]; then
|
||||||
|
changes+=$'\n'"<details><summary>🧰 Maintenance ($count_maint)</summary>"$'\n\n'"${list[maint]}"$'\n'"</details>"$'\n'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n $prev ]]; then
|
||||||
|
full="**Full Changelog**: https://github.com/$repo/compare/$prev...$tag"
|
||||||
|
else
|
||||||
|
full="**Full Changelog**: https://github.com/$repo/commits/$tag"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# A release with highlights is a big one: it gets a heading and the support
|
||||||
|
# section, as in Immich. A patch is a sentence or two and the list.
|
||||||
|
if grep -q '^## Highlights$' <<< "$entry"; then
|
||||||
|
cat <<EOF
|
||||||
|
# 🚀 $name $tag
|
||||||
|
|
||||||
|
$entry
|
||||||
|
|
||||||
|
## ☕ Support $name
|
||||||
|
|
||||||
|
If $name is useful to you, you can buy me a coffee. It keeps these tools going. Found a bug or have an idea? Tell me in the [issues](https://github.com/$repo/issues).
|
||||||
|
|
||||||
|
<a href="https://ko-fi.com/felitendo"><img src="https://storage.ko-fi.com/cdn/kofi5.png?v=6" alt="Buy me a coffee on Ko-fi" height="48"></a>
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
printf '%s\n\n' "$entry"
|
||||||
|
fi
|
||||||
|
printf "## What's Changed\n%s\n\n%s\n" "$changes" "$full"
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
name: check
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
pull_request:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check:
|
||||||
|
name: syntax and shellcheck
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
|
# The Makefile skips whatever is missing rather than failing, so the
|
||||||
|
# tools it looks for have to be here or the check checks less than it
|
||||||
|
# appears to.
|
||||||
|
- name: Install the tools the Makefile looks for
|
||||||
|
run: |
|
||||||
|
sudo apt-get update -qq
|
||||||
|
sudo apt-get install -y --no-install-recommends \
|
||||||
|
shellcheck gettext scdoc
|
||||||
|
|
||||||
|
- run: make check
|
||||||
|
|
||||||
|
- name: Build the catalogs and the man page
|
||||||
|
run: make build
|
||||||
@@ -0,0 +1,264 @@
|
|||||||
|
name: release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags: ['v*']
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
dry_run:
|
||||||
|
description: >-
|
||||||
|
Build the repositories with a throwaway key and install from them,
|
||||||
|
without publishing anything. This is how the release path gets
|
||||||
|
exercised without cutting a tag.
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deb:
|
||||||
|
name: Debian package
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container: debian:stable
|
||||||
|
steps:
|
||||||
|
- name: Install the build tools
|
||||||
|
run: |
|
||||||
|
apt-get update -qq
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
ca-certificates git make gettext scdoc dpkg-dev
|
||||||
|
|
||||||
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
|
- name: Check the tag against the Makefile
|
||||||
|
run: packaging/check-version.sh "${{ github.ref_name }}"
|
||||||
|
|
||||||
|
- name: Check CHANGELOG.md has this release
|
||||||
|
if: startsWith(github.ref, 'refs/tags/v')
|
||||||
|
run: .github/release-notes.sh --title "${{ github.ref_name }}"
|
||||||
|
|
||||||
|
- run: packaging/build-deb.sh
|
||||||
|
|
||||||
|
- name: Look inside what was built
|
||||||
|
run: |
|
||||||
|
dpkg-deb --info dist/*.deb
|
||||||
|
dpkg-deb --contents dist/*.deb
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: deb
|
||||||
|
path: dist/*.deb
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
rpm:
|
||||||
|
name: RPM package
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container: fedora:latest
|
||||||
|
steps:
|
||||||
|
- name: Install the build tools
|
||||||
|
run: |
|
||||||
|
dnf install -y --setopt=install_weak_deps=False \
|
||||||
|
git make gettext scdoc tar rpm-build rpm-sign systemd-rpm-macros
|
||||||
|
|
||||||
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
|
- name: Check the tag against the Makefile
|
||||||
|
run: packaging/check-version.sh "${{ github.ref_name }}"
|
||||||
|
|
||||||
|
- run: packaging/build-rpm.sh
|
||||||
|
|
||||||
|
# Signed here rather than alongside the APT repository, because this is
|
||||||
|
# the one place with a native rpm-sign. A dry run signs with a key it
|
||||||
|
# makes on the spot, so the command itself is still exercised.
|
||||||
|
- name: Sign the package
|
||||||
|
env:
|
||||||
|
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||||
|
DRY_RUN: ${{ inputs.dry_run }}
|
||||||
|
run: |
|
||||||
|
if [ "$DRY_RUN" = "true" ]; then
|
||||||
|
gpg --batch --passphrase '' --quick-generate-key \
|
||||||
|
'dry run <dry-run@example.invalid>' rsa2048 sign never
|
||||||
|
elif [ -n "${GPG_PRIVATE_KEY:-}" ]; then
|
||||||
|
printf '%s' "$GPG_PRIVATE_KEY" | gpg --batch --import
|
||||||
|
else
|
||||||
|
echo "No GPG_PRIVATE_KEY secret; leaving the package unsigned."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
keyid="$(gpg --list-secret-keys --with-colons | awk -F: '/^sec:/ { print $5; exit }')"
|
||||||
|
rpmsign --define "_gpg_name $keyid" --addsign dist/*.rpm
|
||||||
|
gpg --armor --export "$keyid" > dist/rpm-signer.asc
|
||||||
|
rpm --import dist/rpm-signer.asc
|
||||||
|
rpm --checksig dist/*.rpm
|
||||||
|
|
||||||
|
- name: Look inside what was built
|
||||||
|
run: |
|
||||||
|
rpm -qip dist/*.rpm
|
||||||
|
rpm -qlp dist/*.rpm
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: rpm
|
||||||
|
path: |
|
||||||
|
dist/*.rpm
|
||||||
|
dist/rpm-signer.asc
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
publish:
|
||||||
|
name: Release and repositories
|
||||||
|
needs: [deb, rpm]
|
||||||
|
if: startsWith(github.ref, 'refs/tags/v') || inputs.dry_run
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
# All tags, for the link to the changes since the last release.
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- uses: actions/download-artifact@v8
|
||||||
|
with:
|
||||||
|
path: incoming
|
||||||
|
merge-multiple: true
|
||||||
|
|
||||||
|
- name: Attach the packages to the release
|
||||||
|
if: ${{ !inputs.dry_run }}
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
run: |
|
||||||
|
.github/release-notes.sh "${{ github.ref_name }}" > notes.md
|
||||||
|
gh release create "${{ github.ref_name }}" \
|
||||||
|
--title "$(.github/release-notes.sh --title "${{ github.ref_name }}")" \
|
||||||
|
--notes-file notes.md \
|
||||||
|
incoming/*.deb incoming/*.rpm \
|
||||||
|
|| gh release upload "${{ github.ref_name }}" \
|
||||||
|
incoming/*.deb incoming/*.rpm --clobber
|
||||||
|
|
||||||
|
- name: Install the repository tools
|
||||||
|
run: |
|
||||||
|
sudo apt-get update -qq
|
||||||
|
sudo apt-get install -y --no-install-recommends \
|
||||||
|
dpkg-dev apt-utils createrepo-c
|
||||||
|
|
||||||
|
- name: Get a signing key
|
||||||
|
id: key
|
||||||
|
env:
|
||||||
|
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||||
|
DRY_RUN: ${{ inputs.dry_run }}
|
||||||
|
run: |
|
||||||
|
if [ "$DRY_RUN" = "true" ]; then
|
||||||
|
gpg --batch --passphrase '' --quick-generate-key \
|
||||||
|
'dry run <dry-run@example.invalid>' rsa2048 sign never
|
||||||
|
elif [ -n "${GPG_PRIVATE_KEY:-}" ]; then
|
||||||
|
printf '%s' "$GPG_PRIVATE_KEY" | gpg --batch --import
|
||||||
|
else
|
||||||
|
echo "present=no" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "::warning::No GPG_PRIVATE_KEY secret, so the apt and dnf repositories were not updated. The packages are on the release."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "present=yes" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Check out the published repositories
|
||||||
|
if: steps.key.outputs.present == 'yes' && !inputs.dry_run
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
ref: gh-pages
|
||||||
|
path: pages
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Update the repositories
|
||||||
|
if: steps.key.outputs.present == 'yes'
|
||||||
|
run: |
|
||||||
|
# First release, or a dry run: there is no branch to start from.
|
||||||
|
if [ ! -d pages/.git ]; then
|
||||||
|
rm -rf pages && mkdir pages
|
||||||
|
git -C pages init -q -b gh-pages
|
||||||
|
git -C pages remote add origin "https://github.com/${{ github.repository }}.git"
|
||||||
|
fi
|
||||||
|
rm -f incoming/rpm-signer.asc
|
||||||
|
packaging/publish-repos.sh pages incoming
|
||||||
|
|
||||||
|
- name: Check that what was written can be verified
|
||||||
|
if: steps.key.outputs.present == 'yes'
|
||||||
|
run: |
|
||||||
|
find pages -type f -not -path '*/.git/*' | sort
|
||||||
|
echo '--- Release ---'; cat pages/deb/Release
|
||||||
|
echo '--- Packages ---'; cat pages/deb/Packages
|
||||||
|
gpg --verify pages/deb/InRelease
|
||||||
|
gpg --verify pages/deb/Release.gpg pages/deb/Release
|
||||||
|
gpg --verify pages/rpm/repodata/repomd.xml.asc pages/rpm/repodata/repomd.xml
|
||||||
|
|
||||||
|
# The proof that the repository works is apt reading it: the signature,
|
||||||
|
# the index, the dependencies and the program that comes out the far end.
|
||||||
|
- name: Install from the repository that was just built
|
||||||
|
if: inputs.dry_run
|
||||||
|
run: |
|
||||||
|
sudo install -d -m 0755 /etc/apt/keyrings
|
||||||
|
sudo gpg --dearmor -o /etc/apt/keyrings/middleclick-autoscroll.gpg < pages/KEY.gpg
|
||||||
|
echo "deb [signed-by=/etc/apt/keyrings/middleclick-autoscroll.gpg] file://$PWD/pages/deb ./" \
|
||||||
|
| sudo tee /etc/apt/sources.list.d/middleclick-autoscroll.list
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y middleclick-autoscroll
|
||||||
|
middleclick-autoscroll --version
|
||||||
|
middleclick-autoscroll list
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v7
|
||||||
|
if: inputs.dry_run
|
||||||
|
with:
|
||||||
|
name: pages
|
||||||
|
path: pages
|
||||||
|
include-hidden-files: true
|
||||||
|
|
||||||
|
- name: Push them
|
||||||
|
if: steps.key.outputs.present == 'yes' && !inputs.dry_run
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
run: |
|
||||||
|
cd pages
|
||||||
|
git config user.name "github-actions[bot]"
|
||||||
|
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||||
|
git add -A
|
||||||
|
git diff --quiet --cached && { echo "nothing changed"; exit 0; }
|
||||||
|
git commit -q -m "Publish ${{ github.ref_name }}"
|
||||||
|
git push "https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git" HEAD:gh-pages
|
||||||
|
|
||||||
|
verify-dnf:
|
||||||
|
name: Install from the RPM repository
|
||||||
|
needs: publish
|
||||||
|
if: inputs.dry_run
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container: fedora:latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/download-artifact@v8
|
||||||
|
with:
|
||||||
|
name: pages
|
||||||
|
path: pages
|
||||||
|
|
||||||
|
# A real run signs the package and the repository metadata with the one
|
||||||
|
# key from the secret. A dry run has no secret, so each job made a key of
|
||||||
|
# its own and both public halves are needed to check both signatures.
|
||||||
|
- uses: actions/download-artifact@v8
|
||||||
|
with:
|
||||||
|
name: rpm
|
||||||
|
path: signer
|
||||||
|
|
||||||
|
- name: Install from the repository that was just built
|
||||||
|
run: |
|
||||||
|
rpm --import pages/KEY.gpg
|
||||||
|
rpm --import signer/rpm-signer.asc
|
||||||
|
cat > /etc/yum.repos.d/middleclick-autoscroll.repo <<EOF
|
||||||
|
[middleclick-autoscroll]
|
||||||
|
name=middleclick-autoscroll
|
||||||
|
baseurl=file://$PWD/pages/rpm
|
||||||
|
enabled=1
|
||||||
|
gpgcheck=1
|
||||||
|
repo_gpgcheck=1
|
||||||
|
gpgkey=file://$PWD/pages/KEY.gpg
|
||||||
|
EOF
|
||||||
|
# util-linux is for runuser below; the base image does not carry it,
|
||||||
|
# and util-linux-core is not the half that has it.
|
||||||
|
dnf install -y middleclick-autoscroll util-linux
|
||||||
|
|
||||||
|
# As somebody, not as root: running it as root is refused, which is
|
||||||
|
# the point of it, and a container is root by default.
|
||||||
|
useradd -m tester
|
||||||
|
runuser -u tester -- middleclick-autoscroll --version
|
||||||
|
runuser -u tester -- middleclick-autoscroll list
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
# build artifacts
|
# build artifacts
|
||||||
po/*.mo
|
po/*.mo
|
||||||
doc/*.1
|
doc/*.1
|
||||||
|
|
||||||
|
# packages
|
||||||
|
dist/
|
||||||
+112
@@ -0,0 +1,112 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
What each release brings, newest first. The [GitHub releases](https://github.com/LoonixTools/middleclick-autoscroll/releases) add every commit that went into it. Versions before `v1.1.0` came without notes.
|
||||||
|
|
||||||
|
## v1.6.1
|
||||||
|
|
||||||
|
_2026-09-29_
|
||||||
|
|
||||||
|
A small patch. Autoscroll now works in Steam with **Use experimental SteamRT3 Steam Client** turned on. And apps that start at login through a link, like Mullvad VPN, get autoscroll now instead of an error.
|
||||||
|
|
||||||
|
## v1.6.0
|
||||||
|
|
||||||
|
_2026-09-24_
|
||||||
|
|
||||||
|
Welcome to middleclick-autoscroll `v1.6.0`! The menu got quicker and simpler: search your apps, fewer settings, and no more waiting for a key. It now speaks eleven languages. The ten new ones are machine translated, so corrections are very welcome.
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img width="620" alt="The applications list in Konsole, with a search field on top" src="https://raw.githubusercontent.com/LoonixTools/middleclick-autoscroll/v1.6.0/res/screenshots/applications.png">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
### Highlights
|
||||||
|
|
||||||
|
- Search field in the applications list
|
||||||
|
- Long lists scroll
|
||||||
|
- Faster start
|
||||||
|
- Simpler settings
|
||||||
|
- Spotify in the applications list
|
||||||
|
- Results show up in the menu
|
||||||
|
- Ten more languages
|
||||||
|
|
||||||
|
## v1.5.4
|
||||||
|
|
||||||
|
_2026-09-24_
|
||||||
|
|
||||||
|
A small patch. For some of you Discord was still missing after `v1.5.3`, because an old result from before the update kept it out. Every update now starts with a fresh scan, so Discord shows up again after your next login, or right away with **Re-apply everything**.
|
||||||
|
|
||||||
|
## v1.5.3
|
||||||
|
|
||||||
|
_2026-09-24_
|
||||||
|
|
||||||
|
A small patch. Discord changed the way it installs itself and slipped out of the list, so autoscroll never reached it. It is back.
|
||||||
|
|
||||||
|
## v1.5.2
|
||||||
|
|
||||||
|
_2026-09-24_
|
||||||
|
|
||||||
|
A small patch. The menu now says "1 minute ago" instead of "1 minutes ago".
|
||||||
|
|
||||||
|
## v1.5.1
|
||||||
|
|
||||||
|
_2026-09-15_
|
||||||
|
|
||||||
|
A small patch. Autoscroll now works in Brave, which has its own name for it. AppImages are recognised too: an Electron AppImage gets autoscroll like any other app, and one that cannot autoscroll at all, like Modrinth, is left out of the list.
|
||||||
|
|
||||||
|
## v1.5.0
|
||||||
|
|
||||||
|
_2026-09-08_
|
||||||
|
|
||||||
|
Welcome to middleclick-autoscroll `v1.5.0`! A middle click now scrolls everywhere instead of pasting text.
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img width="620" alt="The middleclick-autoscroll menu in Konsole, with middle-click paste off" src="https://raw.githubusercontent.com/LoonixTools/middleclick-autoscroll/22bd4f2a3dd89c4cb90fb497c69762b5df7dc6e7/res/screenshots/menu.png">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
### Highlights
|
||||||
|
|
||||||
|
- Middle-click paste is off
|
||||||
|
|
||||||
|
## v1.4.0
|
||||||
|
|
||||||
|
_2026-09-06_
|
||||||
|
|
||||||
|
Welcome to middleclick-autoscroll `v1.4.0`! This one is all about Steam.
|
||||||
|
|
||||||
|
### Highlights
|
||||||
|
|
||||||
|
- Steam stops reinstalling itself
|
||||||
|
- Scripts that start Steam
|
||||||
|
|
||||||
|
## v1.3.0
|
||||||
|
|
||||||
|
_2026-09-04_
|
||||||
|
|
||||||
|
Welcome to middleclick-autoscroll `v1.3.0`! Browsers look clean again, and Helium joins the list.
|
||||||
|
|
||||||
|
### Highlights
|
||||||
|
|
||||||
|
- No more warning bar in browsers
|
||||||
|
- Autoscroll in Helium
|
||||||
|
|
||||||
|
## v1.2.0
|
||||||
|
|
||||||
|
_2026-09-01_
|
||||||
|
|
||||||
|
Welcome to middleclick-autoscroll `v1.2.0`! Steam keeps its autoscroll now, however you start it.
|
||||||
|
|
||||||
|
### Highlights
|
||||||
|
|
||||||
|
- Steam keeps autoscroll
|
||||||
|
- More ways to start Steam
|
||||||
|
|
||||||
|
## v1.1.0
|
||||||
|
|
||||||
|
_2026-08-24_
|
||||||
|
|
||||||
|
Welcome to middleclick-autoscroll `v1.1.0`! It now works far beyond Arch, with packages that keep themselves up to date.
|
||||||
|
|
||||||
|
### Highlights
|
||||||
|
|
||||||
|
- Debian, Ubuntu, Fedora and openSUSE
|
||||||
|
- Packages that update with your system
|
||||||
|
- Steam fixes
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
## Style
|
||||||
|
|
||||||
|
- Keep everything short: replies, explanations, comments, docs.
|
||||||
|
- Use simple English: short sentences, common words.
|
||||||
|
- Avoid em dashes (—). Do not just swap them for "-" either. Rewrite the sentence instead, for
|
||||||
|
example with a comma, a colon, brackets or two sentences.
|
||||||
|
|
||||||
|
## Commits
|
||||||
|
|
||||||
|
- English only.
|
||||||
|
- Conventional Commits prefix: `feat:`, `fix:`, `chore:`, `docs:`, `refactor:`, `ci:`, `build:`.
|
||||||
|
- Subject as short as possible. Imperative, lowercase, no trailing period.
|
||||||
|
- Body only when something genuinely cannot be inferred from the diff.
|
||||||
|
- Never add `Co-Authored-By`, "Generated with" or any other AI attribution to commits or PR descriptions.
|
||||||
|
- Do not commit or push before I have checked the changes locally and said they are fine. Then
|
||||||
|
commit and push. Several attempts at the same thing make one commit, and attempts that did not
|
||||||
|
work make none. Different things done in one session get a commit each. This also goes for
|
||||||
|
releases and tags.
|
||||||
|
|
||||||
|
## Releases
|
||||||
|
|
||||||
|
Releases look like the ones of big projects such as Immich. `.github/release-notes.sh <tag>` builds
|
||||||
|
the notes: the entry from `CHANGELOG.md` (welcome and highlights), a support section, every commit
|
||||||
|
since the last release sorted by its prefix (`feat`, `fix`, `docs`, ...) with author and link, and
|
||||||
|
the full changelog link. So commit subjects end up in public: keep them clear.
|
||||||
|
|
||||||
|
1. Read `git log <last tag>..HEAD` and pick the version: only fixes → patch, something new → minor,
|
||||||
|
something that breaks or needs the user to act → major.
|
||||||
|
2. Bump the version and add the entry at the top of `CHANGELOG.md`, in one commit (`chore: 1.4.0`).
|
||||||
|
3. Push, then push the tag: `git tag v1.4.0 && git push origin main v1.4.0`. The `release` workflow
|
||||||
|
builds the packages and creates the release. It stops before building when the entry is missing.
|
||||||
|
4. PKGBUILDS picks up the new release for the AUR on its own.
|
||||||
|
|
||||||
|
A minor or major release (has `### Highlights`, gets a heading and the support section):
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## v1.4.0
|
||||||
|
|
||||||
|
_2026-09-24_
|
||||||
|
|
||||||
|
Welcome to middleclick-autoscroll `v1.4.0`! One or two sentences on what this release is about.
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img width="480" alt="What the picture shows" src="https://raw.githubusercontent.com/LoonixTools/middleclick-autoscroll/v1.4.0/<path>">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
### 🚨 Breaking changes
|
||||||
|
|
||||||
|
- Only if there are any: what changed, and what the user has to do.
|
||||||
|
|
||||||
|
### Highlights
|
||||||
|
|
||||||
|
- First highlight, a few words
|
||||||
|
- Second highlight
|
||||||
|
```
|
||||||
|
|
||||||
|
A picture under the welcome is optional. To show the menu or another screen of the program, use a
|
||||||
|
real screenshot of it running in Konsole, in English. Never a text copy of the screen. The same goes
|
||||||
|
for the README. The highlights stay a plain list: no heading or text per highlight, the list of
|
||||||
|
commits explains the rest.
|
||||||
|
|
||||||
|
A patch release is just a sentence or two, for example: "A small patch. The menu no longer closes
|
||||||
|
when you press Enter." The list of commits follows on its own.
|
||||||
|
|
||||||
|
- Write for users: what they notice, not how the code does it. Friendly and simple.
|
||||||
|
- Commands and settings they type go in backticks, buttons and labels in bold.
|
||||||
|
- To change an old release: edit its entry, commit, then
|
||||||
|
`gh release edit <tag> --title <tag> --notes "$(.github/release-notes.sh <tag>)"`.
|
||||||
|
|
||||||
|
## README
|
||||||
|
|
||||||
|
- New UI (a window, a screen, a menu, a setting, a notification) gets a screenshot in the README,
|
||||||
|
next to the text about it. Like for releases: a real screenshot of it running, in English.
|
||||||
|
- When a screen changes, take its screenshot again. The README never shows an old one.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# middleclick-autoscroll - build and install
|
# middleclick-autoscroll: build and install
|
||||||
#
|
#
|
||||||
# Everything here is plain shell; "building" only means compiling the gettext
|
# Everything here is plain shell; "building" only means compiling the gettext
|
||||||
# catalogs and rendering the man page. Both targets degrade to a no-op when
|
# catalogs and rendering the man page. Both targets degrade to a no-op when
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
# Overridable so a packager can pass the version it is actually building
|
# Overridable so a packager can pass the version it is actually building
|
||||||
# (`make VERSION=$pkgver`). The literal below is the fallback for builds
|
# (`make VERSION=$pkgver`). The literal below is the fallback for builds
|
||||||
# straight from a checkout, and is what a release tag has to carry.
|
# straight from a checkout, and is what a release tag has to carry.
|
||||||
VERSION ?= 1.0.1
|
VERSION ?= 1.6.1
|
||||||
|
|
||||||
PREFIX ?= /usr
|
PREFIX ?= /usr
|
||||||
DESTDIR ?=
|
DESTDIR ?=
|
||||||
@@ -17,9 +17,26 @@ DATADIR ?= $(PREFIX)/share
|
|||||||
LIBDIR ?= $(DATADIR)/middleclick-autoscroll/lib
|
LIBDIR ?= $(DATADIR)/middleclick-autoscroll/lib
|
||||||
LOCALEDIR ?= $(DATADIR)/locale
|
LOCALEDIR ?= $(DATADIR)/locale
|
||||||
MANDIR ?= $(DATADIR)/man
|
MANDIR ?= $(DATADIR)/man
|
||||||
USERUNITDIR ?= $(PREFIX)/lib/systemd/user
|
|
||||||
|
|
||||||
LINGUAS := de
|
# Where systemd looks for user units. For a normal install into /usr this is
|
||||||
|
# asked of systemd itself, because the answer is not the same everywhere. A
|
||||||
|
# distribution that still keeps /lib separate from /usr/lib says so here. It is
|
||||||
|
# only guessed at when there is no systemd installed to ask.
|
||||||
|
#
|
||||||
|
# A build with a prefix of its own keeps the units under that prefix instead,
|
||||||
|
# and under share rather than lib. systemd searches both for a system prefix,
|
||||||
|
# but only share for a home one: $XDG_DATA_HOME/systemd/user is a search path
|
||||||
|
# and ~/.local/lib/systemd/user is not, so an install into ~/.local that put
|
||||||
|
# the units in lib would leave the watcher impossible to enable. That prefix is
|
||||||
|
# the one an atomic distribution leaves a user: there is no writing to /usr on
|
||||||
|
# Bazzite or Silverblue without layering a package and rebooting.
|
||||||
|
ifeq ($(PREFIX),/usr)
|
||||||
|
USERUNITDIR ?= $(shell pkg-config --variable=systemduserunitdir systemd 2>/dev/null || echo /usr/lib/systemd/user)
|
||||||
|
else
|
||||||
|
USERUNITDIR ?= $(DATADIR)/systemd/user
|
||||||
|
endif
|
||||||
|
|
||||||
|
LINGUAS := cs de es fr it nl pl pt_BR ru tr uk
|
||||||
MOFILES := $(patsubst %,po/%.mo,$(LINGUAS))
|
MOFILES := $(patsubst %,po/%.mo,$(LINGUAS))
|
||||||
MANPAGE := doc/middleclick-autoscroll.1
|
MANPAGE := doc/middleclick-autoscroll.1
|
||||||
|
|
||||||
@@ -28,24 +45,30 @@ LIBS := $(wildcard src/lib/*.sh)
|
|||||||
MSGFMT := $(shell command -v msgfmt 2>/dev/null)
|
MSGFMT := $(shell command -v msgfmt 2>/dev/null)
|
||||||
SCDOC := $(shell command -v scdoc 2>/dev/null)
|
SCDOC := $(shell command -v scdoc 2>/dev/null)
|
||||||
|
|
||||||
.PHONY: all build install uninstall check clean
|
.PHONY: all build install uninstall check clean version
|
||||||
|
|
||||||
all: build
|
all: build
|
||||||
|
|
||||||
build: $(MOFILES) $(MANPAGE)
|
build: $(MOFILES) $(MANPAGE)
|
||||||
|
|
||||||
|
# The one place the version is written down, for everything that has to agree
|
||||||
|
# with it: the packaging scripts, and the release workflow checking that the
|
||||||
|
# tag it was handed says the same thing.
|
||||||
|
version:
|
||||||
|
@echo $(VERSION)
|
||||||
|
|
||||||
po/%.mo: po/%.po
|
po/%.mo: po/%.po
|
||||||
ifdef MSGFMT
|
ifdef MSGFMT
|
||||||
$(MSGFMT) --check --output-file=$@ $<
|
$(MSGFMT) --check --output-file=$@ $<
|
||||||
else
|
else
|
||||||
@echo "msgfmt not found - skipping $@"
|
@echo "msgfmt not found, skipping $@"
|
||||||
endif
|
endif
|
||||||
|
|
||||||
$(MANPAGE): doc/middleclick-autoscroll.1.scd
|
$(MANPAGE): doc/middleclick-autoscroll.1.scd
|
||||||
ifdef SCDOC
|
ifdef SCDOC
|
||||||
$(SCDOC) < $< > $@
|
$(SCDOC) < $< > $@
|
||||||
else
|
else
|
||||||
@echo "scdoc not found - skipping $@"
|
@echo "scdoc not found, skipping $@"
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Syntax-check every shell file, and run shellcheck when it is available.
|
# Syntax-check every shell file, and run shellcheck when it is available.
|
||||||
@@ -57,7 +80,7 @@ check:
|
|||||||
shellcheck -x -e SC1090,SC1091 src/middleclick-autoscroll $(LIBS); \
|
shellcheck -x -e SC1090,SC1091 src/middleclick-autoscroll $(LIBS); \
|
||||||
echo "ok shellcheck"; \
|
echo "ok shellcheck"; \
|
||||||
else \
|
else \
|
||||||
echo "shellcheck not found - skipped"; \
|
echo "shellcheck not found, skipped"; \
|
||||||
fi
|
fi
|
||||||
@if command -v desktop-file-validate >/dev/null 2>&1; then \
|
@if command -v desktop-file-validate >/dev/null 2>&1; then \
|
||||||
echo "ok desktop-file-validate (nothing to check)"; \
|
echo "ok desktop-file-validate (nothing to check)"; \
|
||||||
|
|||||||
@@ -1,191 +1,162 @@
|
|||||||
# middleclick-autoscroll
|
<p align="center">
|
||||||
|
<img width="200" src="res/middleclick-autoscroll.svg" alt="middleclick-autoscroll">
|
||||||
|
</p>
|
||||||
|
|
||||||
Middle-click autoscroll — hold the middle mouse button, move the pointer, the
|
<h1 align="center">middleclick-autoscroll</h1>
|
||||||
page scrolls — for every Chromium-based application on the system. Discord,
|
|
||||||
Vesktop, Equibop, VS Code, Obsidian, Signal, Spotify, Steam, Chromium-based
|
<h3 align="center">Middle-click autoscroll in every app that supports it.</h3>
|
||||||
browsers, and whatever gets installed next week.
|
|
||||||
|
<p align="center">
|
||||||
|
Browsers, Electron apps like Discord and Spotify, Steam and anything else built on Chromium.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h5 align="center">
|
||||||
|
<a href="#install">Install</a> |
|
||||||
|
<a href="#how-to-use">How to use</a> |
|
||||||
|
<a href="https://github.com/LoonixTools/middleclick-autoscroll/issues">Report a bug</a>
|
||||||
|
</h5>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://ko-fi.com/felitendo"><img src="https://storage.ko-fi.com/cdn/kofi5.png?v=6" alt="Buy me a coffee on Ko-fi" height="48"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><b>Arch</b></summary>
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
paru -S middleclick-autoscroll
|
yay -S middleclick-autoscroll
|
||||||
middleclick-autoscroll enable
|
|
||||||
```
|
```
|
||||||
|
|
||||||
That is the whole setup. Nothing else has to be configured, and no file has to
|
</details>
|
||||||
be edited.
|
|
||||||
|
|
||||||
## Why this needs a program at all
|
<details>
|
||||||
|
<summary><b>Fedora</b></summary>
|
||||||
|
|
||||||
Blink — the engine inside Chromium, Electron and CEF — has had Windows-style
|
```bash
|
||||||
autoscroll for years. On Linux it is switched off, because middle click is
|
sudo curl -fsSL -o /etc/yum.repos.d/middleclick-autoscroll.repo \
|
||||||
already taken by primary-selection paste. One command line argument turns it
|
https://loonixtools.github.io/middleclick-autoscroll/middleclick-autoscroll.repo
|
||||||
back on:
|
sudo dnf install middleclick-autoscroll
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><b>Bazzite</b></summary>
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo curl -fsSL -o /etc/yum.repos.d/middleclick-autoscroll.repo \
|
||||||
|
https://loonixtools.github.io/middleclick-autoscroll/middleclick-autoscroll.repo
|
||||||
|
sudo rpm-ostree install middleclick-autoscroll
|
||||||
|
systemctl reboot
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><b>Debian</b>, Ubuntu</summary>
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo install -d -m 0755 /etc/apt/keyrings
|
||||||
|
curl -fsSL https://loonixtools.github.io/middleclick-autoscroll/KEY.gpg \
|
||||||
|
| sudo gpg --dearmor -o /etc/apt/keyrings/middleclick-autoscroll.gpg
|
||||||
|
echo "deb [signed-by=/etc/apt/keyrings/middleclick-autoscroll.gpg] https://loonixtools.github.io/middleclick-autoscroll/deb ./" \
|
||||||
|
| sudo tee /etc/apt/sources.list.d/middleclick-autoscroll.list
|
||||||
|
sudo apt update && sudo apt install middleclick-autoscroll
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><b>openSUSE</b></summary>
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo rpm --import https://loonixtools.github.io/middleclick-autoscroll/KEY.gpg
|
||||||
|
sudo zypper addrepo --gpgcheck --refresh \
|
||||||
|
https://loonixtools.github.io/middleclick-autoscroll/rpm middleclick-autoscroll
|
||||||
|
sudo zypper install middleclick-autoscroll
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## How to use
|
||||||
|
|
||||||
|
```bash
|
||||||
|
middleclick-autoscroll
|
||||||
|
```
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="res/screenshots/menu.png" alt="The middleclick-autoscroll menu in Konsole: autoscroll on, 19 of 19 applications covered" width="620">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
Press **1**. Autoscroll _✨just works✨_, like on Windows.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Applications</summary>
|
||||||
|
|
||||||
|
**3** lists every app it found. Type to search, then Space turns one on or off.
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="res/screenshots/applications.png" alt="The applications list in Konsole, with a search field on top and how each app gets autoscroll" width="620">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## More
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>How it works</summary>
|
||||||
|
|
||||||
|
Chromium, Electron and CEF all have autoscroll built in. On Linux it is off, because middle click
|
||||||
|
pastes there. One flag turns it back on:
|
||||||
|
|
||||||
```
|
```
|
||||||
--enable-blink-features=MiddleClickAutoscroll
|
--enable-blink-features=MiddleClickAutoscroll
|
||||||
```
|
```
|
||||||
|
|
||||||
Getting that argument into one application is a five-minute job. Getting it into
|
Adding it to every app by hand is a pain, and updates can undo it. This tool does it for you:
|
||||||
all of them, in a way that survives the next package upgrade, is not:
|
|
||||||
|
|
||||||
- Some applications read a flag file, some don't.
|
- It finds every app built on Chromium. AppImages too, without unpacking or starting them.
|
||||||
- Some ship their own copy of Electron, some use the system one.
|
- It puts the flag where the app reads it: the app's flags file, or a copy of its menu entry in
|
||||||
- Flatpaks see none of the host's configuration.
|
your home folder.
|
||||||
- An application that starts itself at login uses a different entry than the one
|
- It watches for new apps and covers them on their own.
|
||||||
in the menu, and Discord launched at login used to behave differently from
|
- It only writes to your home folder, and `disable` puts everything back.
|
||||||
Discord launched by hand.
|
|
||||||
- Steam takes no arguments for its interface at all, and puts back any file you
|
|
||||||
change.
|
|
||||||
- Every upgrade can undo the lot.
|
|
||||||
|
|
||||||
## The interface
|
**Browsers** get a spelling of the flag that shows no warning bar. Brave and Helium also get their
|
||||||
|
own name for the feature. A browser ignores names it does not know.
|
||||||
|
|
||||||
`middleclick-autoscroll` on its own:
|
**Steam** builds its own command line and repairs any file that looks changed. So the flag goes into
|
||||||
|
the script that starts its web helper, and the file keeps the size and date Steam expects. Steam
|
||||||
|
finds nothing to repair, and autoscroll works in the store and the library. After a Steam update,
|
||||||
|
the patch comes back on its own.
|
||||||
|
|
||||||
```
|
</details>
|
||||||
Middle-Click Autoscroll
|
|
||||||
|
|
||||||
Autoscroll ON
|
<details>
|
||||||
|
<summary>Commands</summary>
|
||||||
Applications covered 14 of 15
|
|
||||||
Not identified 1 - see the applications list
|
|
||||||
Steam ON
|
|
||||||
New applications ON
|
|
||||||
Last applied 3 minutes ago
|
|
||||||
|
|
||||||
Applications pick this up the next time they are started.
|
|
||||||
|
|
||||||
[1] Turn autoscroll on or off
|
|
||||||
[2] Apply now
|
|
||||||
[3] Applications
|
|
||||||
[4] Settings
|
|
||||||
[q] Quit
|
|
||||||
```
|
|
||||||
|
|
||||||
**[3] Applications** lists everything that was found, how each one is handled,
|
|
||||||
and lets a single application be switched off — or an unrecognised one switched
|
|
||||||
on — with the space bar:
|
|
||||||
|
|
||||||
```
|
|
||||||
Applications
|
|
||||||
|
|
||||||
▸ Vesktop on (flag file)
|
|
||||||
Discord on (flag file)
|
|
||||||
Code - OSS on (flag file)
|
|
||||||
Obsidian on (flag file)
|
|
||||||
Signal on (flag file)
|
|
||||||
Spotify on (launcher)
|
|
||||||
Steam on (Steam)
|
|
||||||
Cursor cannot tell
|
|
||||||
```
|
|
||||||
|
|
||||||
**[4] Settings** has the categories — Electron and CEF applications, browsers,
|
|
||||||
Flatpaks, autostart entries, Steam, Spotify, whether to watch for new
|
|
||||||
applications, and a field for extra Chromium arguments if you want any.
|
|
||||||
|
|
||||||
There is a configuration file behind all of this. You are never asked to open
|
|
||||||
it.
|
|
||||||
|
|
||||||
## Where the argument actually goes
|
|
||||||
|
|
||||||
Two routes, picked per application.
|
|
||||||
|
|
||||||
| | |
|
| | |
|
||||||
|---|---|
|
|---|---|
|
||||||
| **Flag file** | Arch's Electron and Chromium wrappers read extra arguments from `~/.config/<name>-flags.conf`. This is the good one: it is the supported way to pass arguments, it survives package upgrades untouched, and it applies to a launch from a terminal as much as one from the menu. |
|
| `middleclick-autoscroll` | The menu |
|
||||||
| **Desktop entry** | For applications that ship their own binary with no wrapper, and for Flatpaks, a copy of the entry with the argument appended goes into `~/.local/share/applications`, where it shadows the system one. |
|
| `… enable` | Turn on |
|
||||||
|
| `… disable` | Undo everything |
|
||||||
|
| `… apply` | Pick up new apps |
|
||||||
|
| `… status` | What is covered |
|
||||||
|
| `… list` | All apps and how they are handled |
|
||||||
|
|
||||||
Entries that already live in `~/.local/share/applications` — AppImages, web app
|
</details>
|
||||||
shortcuts — are edited in place and the original is kept. So are the entries in
|
|
||||||
`~/.config/autostart`, so an application that starts itself at login gets the
|
|
||||||
same treatment as one started from the menu.
|
|
||||||
|
|
||||||
An `--enable-blink-features` that is already there is **extended**, never
|
<details>
|
||||||
repeated. Chromium keeps only the last occurrence of that option, so a second
|
<summary>Build from source</summary>
|
||||||
one would silently switch off whatever the first one enabled.
|
|
||||||
|
|
||||||
## Steam
|
|
||||||
|
|
||||||
Steam's interface is CEF and supports the feature perfectly well, but Steam
|
|
||||||
builds the command line for its web helper itself and offers no way to add to
|
|
||||||
it. The only place an argument fits is the script that starts the helper, inside
|
|
||||||
Steam's own installation:
|
|
||||||
|
|
||||||
```
|
|
||||||
~/.local/share/Steam/ubuntu12_64/steamwebhelper_sniper_wrap.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
Steam checksums that script at every start and restores it when it differs, so
|
|
||||||
its launcher entry also gets `-noverifyfiles`. **The trade-off is real**: with
|
|
||||||
verification off, Steam no longer repairs a damaged installation by itself. That
|
|
||||||
is why Steam is a switch of its own rather than part of the general handling —
|
|
||||||
turn it off in the settings and Steam is left completely alone.
|
|
||||||
|
|
||||||
The script comes back on every client update. The watcher notices and puts the
|
|
||||||
patch back.
|
|
||||||
|
|
||||||
Starting Steam from a terminal without `-noverifyfiles` undoes it for that one
|
|
||||||
session; the next start from the menu has it again.
|
|
||||||
|
|
||||||
## Applications installed later
|
|
||||||
|
|
||||||
A systemd user path unit watches every directory a launcher can appear in —
|
|
||||||
`/usr/share/applications`, the Flatpak exports, `~/.local/share/applications`,
|
|
||||||
`~/.config/autostart` — plus Steam's helper script. Anything new is handled
|
|
||||||
within a second of being installed, whether it came from pacman, the AUR,
|
|
||||||
Flatpak or an AppImage manager. There is no hook to install per package manager.
|
|
||||||
|
|
||||||
## What it will not guess
|
|
||||||
|
|
||||||
An AppImage keeps its payload in a compressed filesystem, so there is no way to
|
|
||||||
tell from the outside whether Chromium is in there. Those show up as **cannot
|
|
||||||
tell** and are left alone until you switch them on from the applications screen.
|
|
||||||
|
|
||||||
Detection is deliberately conservative everywhere else too. A wrong "yes" would
|
|
||||||
append an unknown argument to something that is not Chromium, and plenty of
|
|
||||||
programs treat an unrecognised argument as a file name to open.
|
|
||||||
|
|
||||||
## Undoing it
|
|
||||||
|
|
||||||
```bash
|
|
||||||
middleclick-autoscroll disable
|
|
||||||
```
|
|
||||||
|
|
||||||
Every change is recorded in a ledger as it is made, and `disable` replays it
|
|
||||||
backwards: generated entries are deleted, edited files are restored from their
|
|
||||||
backups, flag files that only ever contained our line are removed, and a flag
|
|
||||||
file that was merged into loses exactly the one feature that was added to it.
|
|
||||||
Files that were not touched by this program are not touched by it now either.
|
|
||||||
|
|
||||||
Run this before uninstalling the package.
|
|
||||||
|
|
||||||
## Commands
|
|
||||||
|
|
||||||
| | |
|
|
||||||
|---|---|
|
|
||||||
| `middleclick-autoscroll` | the menu above |
|
|
||||||
| `… enable` | turn it on, apply, start watching |
|
|
||||||
| `… disable` | turn it off and put everything back |
|
|
||||||
| `… apply` | apply to anything new (this is what the watcher calls) |
|
|
||||||
| `… status` | what is covered |
|
|
||||||
| `… list` | every application that was found and how it is handled |
|
|
||||||
|
|
||||||
See `man middleclick-autoscroll` for the details.
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
Arch or an Arch derivative (CachyOS, EndeavourOS, Manjaro), bash, systemd for
|
|
||||||
the watcher. Nothing outside your home directory is ever written to, and running
|
|
||||||
it as root is refused.
|
|
||||||
|
|
||||||
## Building from source
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
make
|
make
|
||||||
sudo make install
|
sudo make install
|
||||||
```
|
```
|
||||||
|
|
||||||
`make check` runs `bash -n` and, if installed, `shellcheck` over every script.
|
Optional: `msgfmt` for translations, `scdoc` for the man page.
|
||||||
|
|
||||||
## License
|
</details>
|
||||||
|
|
||||||
GPL-3.0-or-later.
|
GPL-3.0-or-later.
|
||||||
@@ -2,7 +2,7 @@ middleclick-autoscroll(1)
|
|||||||
|
|
||||||
# NAME
|
# NAME
|
||||||
|
|
||||||
middleclick-autoscroll - middle-click autoscroll for Chromium-based applications
|
middleclick-autoscroll - middle-click autoscroll in every application that supports it
|
||||||
|
|
||||||
# SYNOPSIS
|
# SYNOPSIS
|
||||||
|
|
||||||
@@ -20,9 +20,26 @@ on the command line.
|
|||||||
and puts that argument somewhere the application will actually read it, then
|
and puts that argument somewhere the application will actually read it, then
|
||||||
keeps doing so for anything installed later.
|
keeps doing so for anything installed later.
|
||||||
|
|
||||||
|
A browser is given *--enable-features=MiddleClickAutoscroll* instead. It asks
|
||||||
|
for the same feature, because Blink generates a feature of that name for each
|
||||||
|
of its runtime flags. But it is not on the list of flags Chromium warns about,
|
||||||
|
so the browser does not put a bar reading "You are using an unsupported command-line
|
||||||
|
flag" above every page. That spelling only works from Chromium 124 onwards,
|
||||||
|
which is why everything else keeps the first one: an application that embeds an
|
||||||
|
older Chromium, such as Steam's CEF, has no such bar to show anyway. Two
|
||||||
|
browsers know the feature under a name of their own and ignore Chromium's:
|
||||||
|
Helium, which is asked for *HeliumMiddleClickAutoscroll* as well, and Brave,
|
||||||
|
which is asked for *MiddelButtonClickAutoscroll* (spelled the way Brave spells
|
||||||
|
it). A name a browser does not know is ignored. It works on any distribution:
|
||||||
|
which of the routes below an application takes is read off its launcher, not
|
||||||
|
assumed from where the launcher came from.
|
||||||
|
|
||||||
Run without a command it shows an interactive menu. Everything it can be told
|
Run without a command it shows an interactive menu. Everything it can be told
|
||||||
is reachable from there; the configuration file behind it does not need to be
|
is reachable from there; the configuration file behind it does not need to be
|
||||||
edited by hand.
|
edited by hand. Its applications list turns single applications on or off,
|
||||||
|
Steam and Spotify included. Its settings hold the rest: the desktop's
|
||||||
|
middle-click paste, the watcher, and more Chromium arguments for every
|
||||||
|
application.
|
||||||
|
|
||||||
Nothing outside the user's home directory is written to, and running it as root
|
Nothing outside the user's home directory is written to, and running it as root
|
||||||
is refused.
|
is refused.
|
||||||
@@ -36,10 +53,17 @@ is refused.
|
|||||||
*disable*
|
*disable*
|
||||||
Turn it off and put every file that was changed back the way it was.
|
Turn it off and put every file that was changed back the way it was.
|
||||||
|
|
||||||
*apply*
|
*apply* [*--rebuild*]
|
||||||
Apply to anything that has appeared since the last run. This is what the
|
Apply to anything that has appeared since the last run. This is what the
|
||||||
watcher calls; running it by hand is only needed when the watcher is off.
|
watcher calls; running it by hand is only needed when the watcher is off.
|
||||||
|
|
||||||
|
Entries left behind by an application that has since been uninstalled are
|
||||||
|
removed here too. The entry shadowing it lives in the user's home, where
|
||||||
|
the package manager that removed the application cannot see it.
|
||||||
|
|
||||||
|
With *--rebuild* everything is taken back first and written again from
|
||||||
|
scratch. That is the repair: it does not care what looks correct already.
|
||||||
|
|
||||||
*status*
|
*status*
|
||||||
How many applications are covered, whether Steam is patched, and when the
|
How many applications are covered, whether Steam is patched, and when the
|
||||||
last run was.
|
last run was.
|
||||||
@@ -59,20 +83,30 @@ is refused.
|
|||||||
Two ways, chosen per application.
|
Two ways, chosen per application.
|
||||||
|
|
||||||
*Flag file*
|
*Flag file*
|
||||||
Arch's Electron and Chromium wrappers read extra arguments from
|
Where the launcher reads extra arguments from
|
||||||
_$XDG_CONFIG_HOME/<name>-flags.conf_. This is the preferred route: it is
|
_$XDG_CONFIG_HOME/<name>-flags.conf_. This is the preferred route: it is
|
||||||
the supported way to pass arguments, it survives package upgrades, and it
|
the supported way to pass arguments, it survives package upgrades, and it
|
||||||
applies to a launch from a terminal as much as one from the menu. An
|
applies to a launch from a terminal as much as one from the menu. A
|
||||||
*--enable-blink-features* line that is already in the file is extended
|
feature list that is already in the file is extended rather than
|
||||||
rather than duplicated - Chromium keeps only the last occurrence of that
|
duplicated. Chromium keeps only the last occurrence of such an option, so
|
||||||
option, so a second one would switch the first one off.
|
a second one would switch the first one off.
|
||||||
|
|
||||||
|
Arch's Electron and Chromium packages all wrap their binaries this way, and
|
||||||
|
so do a number of individual vendors' launchers elsewhere. Whether a given
|
||||||
|
launcher does is read off the launcher itself, never assumed from the
|
||||||
|
distribution: only one that really names such a file takes this route.
|
||||||
|
|
||||||
*Desktop entry*
|
*Desktop entry*
|
||||||
For applications that ship their own binary with no wrapper, and for
|
For applications that ship their own binary with no wrapper, and for
|
||||||
Flatpaks, a copy of the desktop entry with the argument appended is written
|
everything inside a Flatpak or a snap, a copy of the desktop entry with the
|
||||||
to _~/.local/share/applications_, where it shadows the system one. Entries
|
argument appended is written to _~/.local/share/applications_, where it
|
||||||
that already live there - AppImages, web app shortcuts - are edited in
|
shadows the system one. Entries that already live there (AppImages, web
|
||||||
place, with the original kept.
|
app shortcuts) are edited in place, with the original kept.
|
||||||
|
|
||||||
|
This is the route everything takes on the distributions whose Chromium
|
||||||
|
wrappers keep their equivalent file under _/etc_, where it is the system's
|
||||||
|
to write and not the user's: Debian, Ubuntu, Fedora and openSUSE among
|
||||||
|
them.
|
||||||
|
|
||||||
A generated entry is marked *X-MCA-Generated* and an entry edited in place
|
A generated entry is marked *X-MCA-Generated* and an entry edited in place
|
||||||
*X-MCA-Patched*. The two are never confused: the first is deleted when
|
*X-MCA-Patched*. The two are never confused: the first is deleted when
|
||||||
@@ -81,7 +115,17 @@ Two ways, chosen per application.
|
|||||||
|
|
||||||
Programs that start themselves at login write their own entry into
|
Programs that start themselves at login write their own entry into
|
||||||
_~/.config/autostart_ pointing straight at their binary, bypassing the menu
|
_~/.config/autostart_ pointing straight at their binary, bypassing the menu
|
||||||
entry entirely. Those are patched in place as well.
|
entry entirely. Those are patched in place as well, unless the application is
|
||||||
|
turned off in the applications list. An entry that is a symlink, often to an
|
||||||
|
application's entry in _/usr/share/applications_, is replaced by a patched
|
||||||
|
file rather than written through, and undoing puts the link back.
|
||||||
|
|
||||||
|
Shortcuts on the desktop itself are patched in place too. Nothing in the XDG
|
||||||
|
search path looks at that folder, so a shortcut that lives only there would
|
||||||
|
otherwise be invisible. And Steam puts one there for every game somebody asks
|
||||||
|
for a shortcut to. The folder's name is translated, and the name in use is read
|
||||||
|
from _~/.config/user-dirs.dirs_ rather than guessed; the watcher is told about
|
||||||
|
it in a drop-in written when autoscroll is turned on.
|
||||||
|
|
||||||
# STEAM
|
# STEAM
|
||||||
|
|
||||||
@@ -91,28 +135,122 @@ helper, inside Steam's own installation:
|
|||||||
|
|
||||||
~/.local/share/Steam/ubuntu12_64/steamwebhelper_sniper_wrap.sh
|
~/.local/share/Steam/ubuntu12_64/steamwebhelper_sniper_wrap.sh
|
||||||
|
|
||||||
Steam checksums that script at every start and restores it when it differs, so
|
The steamrt3 client, a beta for now, has a script of its own:
|
||||||
its launcher entry also gets *-noverifyfiles*. The trade-off is that Steam no
|
|
||||||
longer repairs a damaged installation on its own; that is why Steam is a switch
|
|
||||||
of its own in the settings.
|
|
||||||
|
|
||||||
Starting Steam from a terminal without *-noverifyfiles* undoes the patch for
|
~/.local/share/Steam/steamrt64/steamwebhelper.sh
|
||||||
that session. The watcher notices and puts it back, so the next start has it
|
|
||||||
again.
|
Both are patched where both are there, so switching clients keeps autoscroll.
|
||||||
|
|
||||||
|
Where that installation is depends on how Steam was installed:
|
||||||
|
_~/.local/share/Steam_ for Valve's own package and Arch's,
|
||||||
|
_~/.steam/debian-installation_ for Debian's, and the private tree of the
|
||||||
|
sandbox for the Flatpak and the snap. All of them are looked at.
|
||||||
|
|
||||||
|
Steam compares the installed files against its manifest at every start (by
|
||||||
|
size and timestamp, not by content) and restores whatever differs. So
|
||||||
|
the patch is written to look untouched: the bytes the argument costs are taken
|
||||||
|
back out of the script's own comments and the timestamp is put back afterwards,
|
||||||
|
leaving a file exactly as long and exactly as old as Steam left it. A client
|
||||||
|
that checks its files finds nothing to repair, and the argument survives
|
||||||
|
however Steam was started: from the menu, from a game shortcut, from a
|
||||||
|
launcher like Heroic or Lutris, or from a terminal.
|
||||||
|
|
||||||
|
That is what has to work, because it is the only thing that does. A patch that
|
||||||
|
changes the length is never written, whatever else could be done to cover for
|
||||||
|
it: Steam checks its files at the shutdown it runs itself as well as at a start
|
||||||
|
it was given arguments for, and that one carries no arguments of anybody's. One
|
||||||
|
wrong length costs the whole client package downloaded, extracted and installed
|
||||||
|
again, and a client that quits at the end of it instead of coming up.
|
||||||
|
|
||||||
|
The steamrt3 script has no comments to pay with. So it is copied aside as
|
||||||
|
_steamwebhelper.sh.orig_, and a stub of the same size takes its place. The stub
|
||||||
|
runs the copy with the argument added. Steam only checks the files it knows,
|
||||||
|
and the copy is not one of them.
|
||||||
|
|
||||||
|
So where neither fits, or a client update has changed how the helper is
|
||||||
|
started, nothing is written and the status screen says Steam is not patched.
|
||||||
|
Nothing goes on Steam's launcher entry, its autostart entry or the shortcuts it
|
||||||
|
writes for single games either, and Steam goes on repairing its own
|
||||||
|
installation.
|
||||||
|
|
||||||
|
An installation patched by an earlier version, which appended where the
|
||||||
|
comments were short, is written again to fit at the next apply, or taken back
|
||||||
|
if it cannot be made to.
|
||||||
|
|
||||||
|
A client update brings a new version of the script. The watcher notices and
|
||||||
|
patches it again, and the copy kept for undoing is replaced with the new
|
||||||
|
version at the same time, so undoing puts back the script Steam last shipped
|
||||||
|
rather than the one from before the update.
|
||||||
|
|
||||||
# SPOTIFY
|
# SPOTIFY
|
||||||
|
|
||||||
The official client is CEF rather than Electron. Installed through
|
The official client is CEF rather than Electron. Installed through
|
||||||
*spotify-launcher*, it is started by a program that builds its own command line
|
*spotify-launcher*, it is started by a program that builds its own command line
|
||||||
and has a configuration file with a slot for extra arguments; that slot is
|
and has a configuration file with a slot for extra arguments; that slot is
|
||||||
where the flag goes. Installed as a plain package, it is an ordinary desktop
|
where the flag goes, and the launcher shows up in the applications list like
|
||||||
entry and needs nothing special.
|
any other application. Installed as a plain package, a Flatpak or a snap, it is
|
||||||
|
an ordinary desktop entry and needs nothing special.
|
||||||
|
|
||||||
# WHAT CANNOT BE DETECTED
|
# MIDDLE-CLICK PASTE
|
||||||
|
|
||||||
An AppImage keeps its payload in a compressed filesystem, so there is no way to
|
Inside a Chromium application the argument settles this on its own: with
|
||||||
tell from the outside whether it contains Chromium. Those are listed as *cannot
|
autoscroll on, Blink stops pasting the primary selection on middle click,
|
||||||
tell* and left alone until they are switched on from the applications screen.
|
because the button is doing something else now. Everywhere else on the desktop
|
||||||
|
middle click goes on pasting, so the desktop's own switch for it is turned off
|
||||||
|
too.
|
||||||
|
|
||||||
|
KDE has such a switch, and only for a Wayland session, where the paste is a
|
||||||
|
protocol the compositor either offers or does not:
|
||||||
|
|
||||||
|
~/.config/kwinrc, [Wayland], EnablePrimarySelection=false
|
||||||
|
|
||||||
|
It is written with *kwriteconfig6*, the same tool System Settings uses, because
|
||||||
|
kwinrc has a cascade behind it and entries a distribution can mark immutable;
|
||||||
|
an edit that reaches past all that writes something KDE goes on to ignore. KWin
|
||||||
|
reads the key once, while it starts, so the change is true from the next login
|
||||||
|
on rather than straight away.
|
||||||
|
|
||||||
|
What the key said before is recorded, and *disable* puts that back. A key that
|
||||||
|
already said *false* before any of this is left alone and not recorded either,
|
||||||
|
so a paste the user switched off themselves is never switched back on.
|
||||||
|
|
||||||
|
On X11 there is nothing to switch. The primary selection is part of X itself
|
||||||
|
and every toolkit reaches for it on its own; no one place can say no. The
|
||||||
|
status screen leaves the row out where there is nothing to report.
|
||||||
|
|
||||||
|
Turn it off under *Settings* to keep the desktop's middle-click paste.
|
||||||
|
|
||||||
|
# APPIMAGES
|
||||||
|
|
||||||
|
An AppImage is the AppImage runtime, an ordinary executable, with a squashfs
|
||||||
|
image appended to it. The payload is compressed, so none of the files that
|
||||||
|
identify Chromium is on disk where it could be found.
|
||||||
|
|
||||||
|
The names are, though. squashfs keeps the name of everything it holds in one
|
||||||
|
table of its own, a few kilobytes of it, and a name is all this question needs -
|
||||||
|
so that table is read and decompressed in place. Nothing is unpacked, and the
|
||||||
|
image is never run: this can happen from the watcher, and starting a program
|
||||||
|
because it was installed is not something a scan gets to do.
|
||||||
|
|
||||||
|
Two kinds of image are still out of reach. One is packed with *lzo* or *lz4*,
|
||||||
|
which squashfs stores as bare blocks that neither tool will read without the
|
||||||
|
framing their own file formats add. The other is the original AppImage layout,
|
||||||
|
which is an ISO9660 filesystem rather than a squashfs one. Both are listed as
|
||||||
|
*cannot tell* and left alone until they are switched on from the applications
|
||||||
|
screen.
|
||||||
|
|
||||||
|
# WHAT HAS NO FLAG AT ALL
|
||||||
|
|
||||||
|
Autoscroll is a Blink feature, so only an application drawn by Blink can be
|
||||||
|
given it. An application built on WebKitGTK is not one of those. That
|
||||||
|
includes Tauri on Linux, GNOME Web, and anything else linked against
|
||||||
|
libwebkit2gtk. WebKit has no equivalent feature to ask for, on any command line
|
||||||
|
or in any configuration file.
|
||||||
|
|
||||||
|
Such an application is identified as what it is and then left out of the list
|
||||||
|
entirely, rather than being offered as something that could be switched on. An
|
||||||
|
application that is absent from *list* is absent because there is nothing this
|
||||||
|
tool could do for it.
|
||||||
|
|
||||||
# FILES
|
# FILES
|
||||||
|
|
||||||
@@ -126,20 +264,39 @@ _~/.local/state/middleclick-autoscroll/ledger_
|
|||||||
_~/.local/state/middleclick-autoscroll/backup/_
|
_~/.local/state/middleclick-autoscroll/backup/_
|
||||||
Copies of the files that are edited in place rather than shadowed.
|
Copies of the files that are edited in place rather than shadowed.
|
||||||
|
|
||||||
|
_~/.config/kwinrc_
|
||||||
|
KDE's own configuration. One key in it, *EnablePrimarySelection*, is
|
||||||
|
written when the desktop's middle-click paste is turned off, and put
|
||||||
|
back by *disable*.
|
||||||
|
|
||||||
_~/.cache/middleclick-autoscroll/detect_
|
_~/.cache/middleclick-autoscroll/detect_
|
||||||
Which programs were found to be Chromium, keyed by size and modification
|
Which programs were found to be Chromium, keyed by size and modification
|
||||||
time. Safe to delete.
|
time. Its first line says which version of the program wrote it, and a
|
||||||
|
file from an older one is ignored rather than trusted. Otherwise an entry
|
||||||
|
for a file that has not changed would never be looked at again.
|
||||||
|
Safe to delete.
|
||||||
|
|
||||||
# ENVIRONMENT
|
# ENVIRONMENT
|
||||||
|
|
||||||
*NO_COLOR*
|
*NO_COLOR*
|
||||||
Disables colour.
|
Disables colour.
|
||||||
|
|
||||||
|
# REQUIREMENTS
|
||||||
|
|
||||||
|
Bash 4.2 or newer and GNU coreutils. The watcher needs a systemd user session;
|
||||||
|
without one everything else works and applications installed later are picked
|
||||||
|
up at the next *apply* rather than on their own.
|
||||||
|
|
||||||
|
*gzip* is what reads the name table of an AppImage, and *xz* or *zstd* the ones
|
||||||
|
packed with those instead. None of the three is required: an image whose
|
||||||
|
compressor has no tool installed is listed as *cannot tell*, exactly like the
|
||||||
|
two formats there is no reader for at all.
|
||||||
|
|
||||||
# SEE ALSO
|
# SEE ALSO
|
||||||
|
|
||||||
*systemctl*(1), *flatpak*(1)
|
*systemctl*(1), *flatpak*(1), *snap*(8), *kwriteconfig6*(1)
|
||||||
|
|
||||||
# AUTHORS
|
# AUTHORS
|
||||||
|
|
||||||
Felitendo. Source and issue tracker at
|
Felitendo. Source and issue tracker at
|
||||||
https://github.com/Felitendo/middleclick-autoscroll
|
https://github.com/LoonixTools/middleclick-autoscroll
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
# Packaging and releases
|
||||||
|
|
||||||
|
The Makefile installs everything; these only wrap what it produced. That is
|
||||||
|
on purpose: a packaging script that lists the files again is a second
|
||||||
|
description of the layout, and two descriptions drift.
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| `deb/control`, `deb/copyright` | metadata for the Debian binary package |
|
||||||
|
| `rpm/middleclick-autoscroll.spec` | the RPM spec |
|
||||||
|
| `build-deb.sh`, `build-rpm.sh` | build one package into `dist/` |
|
||||||
|
| `check-version.sh` | refuses a tag that disagrees with the Makefile |
|
||||||
|
| `publish-repos.sh` | regenerates the APT and RPM repositories |
|
||||||
|
| `pages/` | the landing page and the `.repo` file served from GitHub Pages |
|
||||||
|
|
||||||
|
Neither package carries a maintainer script. The units are enabled per user by
|
||||||
|
the program itself, and there is nothing to do as root at install time.
|
||||||
|
|
||||||
|
## Building one by hand
|
||||||
|
|
||||||
|
```bash
|
||||||
|
packaging/build-deb.sh # needs dpkg-dev, gettext, scdoc
|
||||||
|
packaging/build-rpm.sh # needs rpm-build, gettext, scdoc, systemd-rpm-macros
|
||||||
|
```
|
||||||
|
|
||||||
|
Both take the version from `make version` unless one is passed as the first
|
||||||
|
argument.
|
||||||
|
|
||||||
|
## Making a release
|
||||||
|
|
||||||
|
1. Bump `VERSION` in the Makefile.
|
||||||
|
2. Add the release to `CHANGELOG.md`, in the format CLAUDE.md describes.
|
||||||
|
3. Commit, then `git tag vX.Y.Z && git push --tags`.
|
||||||
|
|
||||||
|
The `release` workflow builds both packages in a Debian and a Fedora container,
|
||||||
|
refuses the tag if it disagrees with the Makefile or has no changelog entry,
|
||||||
|
attaches the packages to a GitHub release with the entry as its notes, and adds
|
||||||
|
them to the APT and RPM repositories on the `gh-pages` branch. Nothing else has
|
||||||
|
to be done by hand.
|
||||||
|
|
||||||
|
## Trying the release path first
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gh workflow run release.yml -f dry_run=true
|
||||||
|
```
|
||||||
|
|
||||||
|
Builds both packages, builds both repositories with a key generated on the
|
||||||
|
spot, checks the three signatures it wrote, and then installs the packages back
|
||||||
|
out of the repositories (apt on the runner, dnf in a Fedora container). Nothing
|
||||||
|
is pushed and no release is made. This is worth running after any change to the
|
||||||
|
packaging, because the alternative is finding out from a tag.
|
||||||
|
|
||||||
|
## Setting up the signing, once
|
||||||
|
|
||||||
|
The repositories are signed, so this needs a key. Make one that exists for
|
||||||
|
nothing else (not a personal key) and give it no passphrase. It lives as an
|
||||||
|
encrypted repository secret, and `rpmsign` cannot be handed a passphrase
|
||||||
|
unattended.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gpg --batch --passphrase '' --quick-generate-key \
|
||||||
|
'middleclick-autoscroll repository <felitendoyt@gmail.com>' rsa4096 sign never
|
||||||
|
|
||||||
|
gpg --armor --export-secret-keys 'middleclick-autoscroll repository' \
|
||||||
|
| gh secret set GPG_PRIVATE_KEY
|
||||||
|
```
|
||||||
|
|
||||||
|
Without the secret the workflow still builds both packages and attaches them to
|
||||||
|
the release; it says so in the log and leaves the repositories alone.
|
||||||
|
|
||||||
|
## Pointing Pages at it, once, in this order
|
||||||
|
|
||||||
|
The `gh-pages` branch does not exist until a release has put something on it,
|
||||||
|
and a branch that does not exist cannot be picked in the Pages settings. So:
|
||||||
|
|
||||||
|
1. Set the secret, above.
|
||||||
|
2. Tag a release. The workflow creates the branch and fills it.
|
||||||
|
3. *Then* set **Pages** to deploy from a branch and pick `gh-pages` at the
|
||||||
|
root.
|
||||||
|
|
||||||
|
Doing it the other way round is a wall, and leaving Pages pointed at `main`
|
||||||
|
serves the source tree at the address the install instructions name. Then the
|
||||||
|
key and the indexes are 404 and nothing installs.
|
||||||
|
|
||||||
|
## What users end up with
|
||||||
|
|
||||||
|
The public key is published as `KEY.gpg` beside the repositories, and the
|
||||||
|
landing page carries the setup lines for each distribution. After that, a new
|
||||||
|
version arrives with `apt upgrade`, `dnf upgrade` or `zypper up` like anything
|
||||||
|
else.
|
||||||
Executable
+50
@@ -0,0 +1,50 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Builds the binary package for Debian, Ubuntu and their derivatives into
|
||||||
|
# dist/.
|
||||||
|
#
|
||||||
|
# Everything the package contains comes out of `make install`. This only wraps
|
||||||
|
# what that produced, so there is exactly one description of where a file goes
|
||||||
|
# and it is the Makefile. A packaging script that lists the files again is a
|
||||||
|
# second description, and the two drift.
|
||||||
|
#
|
||||||
|
# Needs: make, dpkg-deb, msgfmt (gettext), scdoc.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
here="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
version="${1:-$(make -s -C "$here" version)}"
|
||||||
|
name=middleclick-autoscroll
|
||||||
|
|
||||||
|
# A package without its man page or its translations is not a package this
|
||||||
|
# should be quietly willing to produce: the Makefile skips both when the tools
|
||||||
|
# are missing, and the result would look like a successful build.
|
||||||
|
for tool in msgfmt scdoc dpkg-deb; do
|
||||||
|
command -v "$tool" > /dev/null || { echo "$0: $tool is not installed" >&2; exit 1; }
|
||||||
|
done
|
||||||
|
|
||||||
|
root="$(mktemp -d)"
|
||||||
|
trap 'rm -rf -- "$root"' EXIT
|
||||||
|
|
||||||
|
make -C "$here" install \
|
||||||
|
DESTDIR="$root" \
|
||||||
|
PREFIX=/usr \
|
||||||
|
VERSION="$version" \
|
||||||
|
USERUNITDIR=/usr/lib/systemd/user
|
||||||
|
|
||||||
|
install -d "$root/DEBIAN"
|
||||||
|
sed "s|@VERSION@|$version|g" "$here/packaging/deb/control" > "$root/DEBIAN/control"
|
||||||
|
install -Dm644 "$here/packaging/deb/copyright" \
|
||||||
|
"$root/usr/share/doc/$name/copyright"
|
||||||
|
|
||||||
|
# Relative to the package root, and DEBIAN/ itself is not part of the contents.
|
||||||
|
# Sorted in the C locale so the file comes out the same whatever the locale of
|
||||||
|
# the machine that built it.
|
||||||
|
( cd "$root" && find . -type f ! -path './DEBIAN/*' -printf '%P\0' \
|
||||||
|
| LC_ALL=C sort -z | xargs -0 md5sum > DEBIAN/md5sums )
|
||||||
|
|
||||||
|
mkdir -p "$here/dist"
|
||||||
|
out="$here/dist/${name}_${version}_all.deb"
|
||||||
|
dpkg-deb --root-owner-group --build "$root" "$out" > /dev/null
|
||||||
|
|
||||||
|
echo "$out"
|
||||||
Executable
+39
@@ -0,0 +1,39 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Builds the binary package for Fedora, RHEL, openSUSE and their derivatives
|
||||||
|
# into dist/.
|
||||||
|
#
|
||||||
|
# The spec takes the version as a macro rather than carrying one of its own,
|
||||||
|
# for the same reason the Debian control file has a placeholder: the Makefile
|
||||||
|
# is where the version is written down.
|
||||||
|
#
|
||||||
|
# Needs: rpmbuild, make, msgfmt (gettext), scdoc, systemd-rpm-macros.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
here="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
version="${1:-$(make -s -C "$here" version)}"
|
||||||
|
name=middleclick-autoscroll
|
||||||
|
|
||||||
|
command -v rpmbuild > /dev/null || { echo "$0: rpmbuild is not installed" >&2; exit 1; }
|
||||||
|
|
||||||
|
top="$(mktemp -d)"
|
||||||
|
trap 'rm -rf -- "$top"' EXIT
|
||||||
|
mkdir -p "$top"/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS}
|
||||||
|
|
||||||
|
# The working tree as it is, not as it was committed: a package built from a
|
||||||
|
# checkout has to contain what is in that checkout.
|
||||||
|
tar czf "$top/SOURCES/$name-$version.tar.gz" \
|
||||||
|
--transform "s,^\\.,$name-$version," \
|
||||||
|
--exclude=./.git --exclude=./dist --exclude=./po/'*.mo' \
|
||||||
|
-C "$here" .
|
||||||
|
|
||||||
|
rpmbuild \
|
||||||
|
--define "_topdir $top" \
|
||||||
|
--define "_version $version" \
|
||||||
|
-bb "$here/packaging/rpm/$name.spec" > /dev/null
|
||||||
|
|
||||||
|
mkdir -p "$here/dist"
|
||||||
|
cp "$top"/RPMS/noarch/*.rpm "$here/dist/"
|
||||||
|
|
||||||
|
ls "$here/dist/$name-$version"*.rpm
|
||||||
Executable
+36
@@ -0,0 +1,36 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Refuses a release whose tag and Makefile disagree.
|
||||||
|
#
|
||||||
|
# The version is baked into the program at install time from the Makefile, and
|
||||||
|
# the packages take theirs from the same place. But the tag is what people see
|
||||||
|
# and what the release is named after. A tag that says something else produces
|
||||||
|
# a package called 1.0.4 containing a program that reports 1.0.3, and nothing
|
||||||
|
# would have complained.
|
||||||
|
#
|
||||||
|
# Anything that is not a v-tag (a run started by hand from a branch) is not a
|
||||||
|
# release and has nothing to check.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
here="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
ref="${1:-}"
|
||||||
|
|
||||||
|
case "$ref" in
|
||||||
|
v[0-9]*) ;;
|
||||||
|
*)
|
||||||
|
echo "not a release tag (${ref:-none}), nothing to check against"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
tag_version="${ref#v}"
|
||||||
|
make_version="$(make -s -C "$here" version)"
|
||||||
|
|
||||||
|
if [[ $tag_version != "$make_version" ]]; then
|
||||||
|
echo "tag $ref says $tag_version, the Makefile says $make_version" >&2
|
||||||
|
echo "Bump VERSION in the Makefile to match the tag, or retag." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$ref matches the Makefile"
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
Package: middleclick-autoscroll
|
||||||
|
Version: @VERSION@
|
||||||
|
Section: utils
|
||||||
|
Priority: optional
|
||||||
|
Architecture: all
|
||||||
|
Maintainer: Felitendo <felitendoyt@gmail.com>
|
||||||
|
Depends: bash (>= 4.2), coreutils, findutils, grep, sed, mawk | gawk | original-awk
|
||||||
|
Recommends: gettext-base, systemd, desktop-file-utils
|
||||||
|
Homepage: https://github.com/LoonixTools/middleclick-autoscroll
|
||||||
|
Description: middle-click autoscroll for Chromium-based applications
|
||||||
|
Blink (the engine inside Chromium, Electron and CEF) has had Windows-style
|
||||||
|
autoscroll for years: hold the middle mouse button, move the pointer, the page
|
||||||
|
scrolls. On Linux it is switched off, because middle click is already taken by
|
||||||
|
primary-selection paste.
|
||||||
|
.
|
||||||
|
This turns it back on for every application on the system that can do it, and
|
||||||
|
for anything installed later. There is no list of supported applications to
|
||||||
|
keep up to date: every launcher is examined, the ones running on Chromium
|
||||||
|
underneath are identified by what they ship rather than by their name, and the
|
||||||
|
argument goes wherever that particular application will actually read it.
|
||||||
|
.
|
||||||
|
Nothing outside the user's home directory is ever written to. Run
|
||||||
|
"middleclick-autoscroll disable" before removing this package, so that
|
||||||
|
everything it changed is put back.
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||||
|
Upstream-Name: middleclick-autoscroll
|
||||||
|
Source: https://github.com/LoonixTools/middleclick-autoscroll
|
||||||
|
|
||||||
|
Files: *
|
||||||
|
Copyright: 2026 Felitendo
|
||||||
|
License: GPL-3+
|
||||||
|
|
||||||
|
License: GPL-3+
|
||||||
|
This program is free software: you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
|
Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
version.
|
||||||
|
.
|
||||||
|
This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
.
|
||||||
|
On Debian systems the full text of the GNU General Public License version 3 can
|
||||||
|
be found in /usr/share/common-licenses/GPL-3.
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>middleclick-autoscroll</title>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--bg: #ffffff;
|
||||||
|
--fg: #1b1f23;
|
||||||
|
--muted: #57606a;
|
||||||
|
--rule: #d8dee4;
|
||||||
|
--code-bg: #f6f8fa;
|
||||||
|
--accent: #1793d1;
|
||||||
|
}
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root:not([data-theme="light"]) {
|
||||||
|
--bg: #0d1117;
|
||||||
|
--fg: #e6edf3;
|
||||||
|
--muted: #9198a1;
|
||||||
|
--rule: #30363d;
|
||||||
|
--code-bg: #161b22;
|
||||||
|
--accent: #58a6ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
* { box-sizing: border-box; }
|
||||||
|
body {
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 3rem 1.25rem 5rem;
|
||||||
|
max-width: 46rem;
|
||||||
|
background: var(--bg);
|
||||||
|
color: var(--fg);
|
||||||
|
font: 16px/1.6 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
||||||
|
"Helvetica Neue", Arial, sans-serif;
|
||||||
|
}
|
||||||
|
h1 { font-size: 1.6rem; margin: 0 0 .4rem; }
|
||||||
|
h2 {
|
||||||
|
font-size: 1.05rem; margin: 2.5rem 0 .6rem;
|
||||||
|
padding-bottom: .3rem; border-bottom: 1px solid var(--rule);
|
||||||
|
}
|
||||||
|
p.lead { color: var(--muted); margin: 0 0 2rem; }
|
||||||
|
p { margin: 0 0 1rem; }
|
||||||
|
a { color: var(--accent); }
|
||||||
|
code {
|
||||||
|
background: var(--code-bg); padding: .12em .35em;
|
||||||
|
border-radius: 4px; font-size: .9em;
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
background: var(--code-bg);
|
||||||
|
border: 1px solid var(--rule);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: .9rem 1rem;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
pre code { background: none; padding: 0; font-size: .85rem; }
|
||||||
|
footer {
|
||||||
|
margin-top: 3.5rem; padding-top: 1rem;
|
||||||
|
border-top: 1px solid var(--rule);
|
||||||
|
color: var(--muted); font-size: .9rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1>middleclick-autoscroll</h1>
|
||||||
|
<p class="lead">
|
||||||
|
Middle-click autoscroll in every Chromium-based application on the system,
|
||||||
|
and in anything installed later: hold the middle mouse button, move the
|
||||||
|
pointer, and the page scrolls.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
This page is the package repository. Set it up once and every new version
|
||||||
|
arrives with the rest of your system updates. The
|
||||||
|
<a href="https://github.com/LoonixTools/middleclick-autoscroll">source and the
|
||||||
|
documentation</a> are on GitHub.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Debian, Ubuntu, Linux Mint, Pop!_OS</h2>
|
||||||
|
<pre><code>sudo install -d -m 0755 /etc/apt/keyrings
|
||||||
|
curl -fsSL @BASEURL@/KEY.gpg \
|
||||||
|
| sudo gpg --dearmor -o /etc/apt/keyrings/middleclick-autoscroll.gpg
|
||||||
|
echo "deb [signed-by=/etc/apt/keyrings/middleclick-autoscroll.gpg] @BASEURL@/deb ./" \
|
||||||
|
| sudo tee /etc/apt/sources.list.d/middleclick-autoscroll.list
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install middleclick-autoscroll</code></pre>
|
||||||
|
|
||||||
|
<h2>Fedora, RHEL, CentOS Stream</h2>
|
||||||
|
<pre><code>sudo curl -fsSL -o /etc/yum.repos.d/middleclick-autoscroll.repo \
|
||||||
|
@BASEURL@/middleclick-autoscroll.repo
|
||||||
|
sudo dnf install middleclick-autoscroll</code></pre>
|
||||||
|
|
||||||
|
<h2>openSUSE</h2>
|
||||||
|
<pre><code>sudo rpm --import @BASEURL@/KEY.gpg
|
||||||
|
sudo zypper addrepo --gpgcheck --refresh @BASEURL@/rpm middleclick-autoscroll
|
||||||
|
sudo zypper install middleclick-autoscroll</code></pre>
|
||||||
|
|
||||||
|
<h2>Arch, CachyOS, EndeavourOS, Manjaro</h2>
|
||||||
|
<pre><code>paru -S middleclick-autoscroll</code></pre>
|
||||||
|
|
||||||
|
<h2>Then, once</h2>
|
||||||
|
<pre><code>middleclick-autoscroll enable</code></pre>
|
||||||
|
<p>
|
||||||
|
That is the whole setup. Nothing else has to be configured and no file has to
|
||||||
|
be edited. Run <code>middleclick-autoscroll disable</code> before removing the
|
||||||
|
package. It puts back everything that was changed.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
GPL-3.0-or-later. Packages are signed; the public key is
|
||||||
|
<a href="@BASEURL@/KEY.gpg">KEY.gpg</a>.
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[middleclick-autoscroll]
|
||||||
|
name=middleclick-autoscroll
|
||||||
|
baseurl=@BASEURL@/rpm
|
||||||
|
enabled=1
|
||||||
|
gpgcheck=1
|
||||||
|
repo_gpgcheck=1
|
||||||
|
gpgkey=@BASEURL@/KEY.gpg
|
||||||
Executable
+88
@@ -0,0 +1,88 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Puts the packages that were just built into the APT and RPM repositories on
|
||||||
|
# the gh-pages branch, and regenerates the indexes over everything that is
|
||||||
|
# there.
|
||||||
|
#
|
||||||
|
# Old versions are kept rather than replaced. An index built over all of them
|
||||||
|
# is what lets somebody pin a version or go back to one, and it costs a few
|
||||||
|
# hundred kilobytes.
|
||||||
|
#
|
||||||
|
# Usage: publish-repos.sh <gh-pages checkout> <directory of new packages>
|
||||||
|
#
|
||||||
|
# Needs: dpkg-dev, apt-utils, createrepo-c, gpg, and a secret key already
|
||||||
|
# imported. Its id is taken from the keyring.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
pages="$(cd -- "$1" && pwd)"
|
||||||
|
incoming="$(cd -- "$2" && pwd)"
|
||||||
|
here="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
|
||||||
|
base_url="${MCA_REPO_URL:-https://loonixtools.github.io/middleclick-autoscroll}"
|
||||||
|
|
||||||
|
keyid="$(gpg --list-secret-keys --with-colons | awk -F: '/^sec:/ { print $5; exit }')"
|
||||||
|
[[ -n $keyid ]] || { echo "$0: no secret key in the keyring" >&2; exit 1; }
|
||||||
|
|
||||||
|
mkdir -p "$pages/deb" "$pages/rpm"
|
||||||
|
cp -- "$incoming"/*.deb "$pages/deb/"
|
||||||
|
cp -- "$incoming"/*.rpm "$pages/rpm/"
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# APT
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# A flat repository: the packages and their index sit in one directory and the
|
||||||
|
# sources line ends in "./". There is one distribution here and it is the same
|
||||||
|
# package for all of them, so the suite and component machinery of a pool
|
||||||
|
# layout would describe nothing.
|
||||||
|
(
|
||||||
|
cd "$pages/deb"
|
||||||
|
|
||||||
|
# The old index must be gone before the new one is written: apt-ftparchive
|
||||||
|
# hashes every file in the directory, and a Release that hashes the
|
||||||
|
# previous Release is a Release that cannot be verified.
|
||||||
|
rm -f Packages Packages.gz Release Release.gpg InRelease
|
||||||
|
|
||||||
|
dpkg-scanpackages --multiversion . > Packages
|
||||||
|
gzip -9kf Packages
|
||||||
|
|
||||||
|
apt-ftparchive \
|
||||||
|
-o APT::FTPArchive::Release::Origin=middleclick-autoscroll \
|
||||||
|
-o APT::FTPArchive::Release::Label=middleclick-autoscroll \
|
||||||
|
-o APT::FTPArchive::Release::Suite=stable \
|
||||||
|
-o APT::FTPArchive::Release::Codename=stable \
|
||||||
|
-o APT::FTPArchive::Release::Architectures=all \
|
||||||
|
-o APT::FTPArchive::Release::Components=main \
|
||||||
|
release . > Release
|
||||||
|
|
||||||
|
# Both signatures: InRelease is what current apt fetches, Release.gpg is
|
||||||
|
# what an older one falls back to.
|
||||||
|
gpg --batch --yes --local-user "$keyid" --clearsign --output InRelease Release
|
||||||
|
gpg --batch --yes --local-user "$keyid" --detach-sign --armor --output Release.gpg Release
|
||||||
|
)
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# RPM
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
(
|
||||||
|
cd "$pages/rpm"
|
||||||
|
createrepo_c --quiet --update .
|
||||||
|
rm -f repodata/repomd.xml.asc
|
||||||
|
gpg --batch --yes --local-user "$keyid" --detach-sign --armor repodata/repomd.xml
|
||||||
|
)
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# The key and the landing page
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
gpg --armor --export "$keyid" > "$pages/KEY.gpg"
|
||||||
|
|
||||||
|
sed "s|@BASEURL@|$base_url|g" "$here/packaging/pages/index.html" > "$pages/index.html"
|
||||||
|
sed "s|@BASEURL@|$base_url|g" "$here/packaging/pages/middleclick-autoscroll.repo" \
|
||||||
|
> "$pages/middleclick-autoscroll.repo"
|
||||||
|
|
||||||
|
# Pages would otherwise hand the whole directory to Jekyll, which drops every
|
||||||
|
# file whose name starts with an underscore and can rewrite the rest.
|
||||||
|
touch "$pages/.nojekyll"
|
||||||
|
|
||||||
|
echo "signed with $keyid"
|
||||||
|
ls -1 "$pages/deb" "$pages/rpm"
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
# Built with `packaging/build-rpm.sh`, which passes the version in rather than
|
||||||
|
# editing this file: the Makefile is where the version is written down, and two
|
||||||
|
# places that have to agree are one place too many.
|
||||||
|
%global upstream_version %{?_version}%{!?_version:1.0.3}
|
||||||
|
|
||||||
|
Name: middleclick-autoscroll
|
||||||
|
Version: %{upstream_version}
|
||||||
|
Release: 1%{?dist}
|
||||||
|
Summary: Middle-click autoscroll for Chromium-based applications
|
||||||
|
|
||||||
|
License: GPL-3.0-or-later
|
||||||
|
URL: https://github.com/LoonixTools/middleclick-autoscroll
|
||||||
|
Source0: %{name}-%{version}.tar.gz
|
||||||
|
|
||||||
|
BuildArch: noarch
|
||||||
|
BuildRequires: make
|
||||||
|
BuildRequires: gettext
|
||||||
|
BuildRequires: scdoc
|
||||||
|
# For %{_userunitdir}, which is where the watcher's user units belong.
|
||||||
|
BuildRequires: systemd-rpm-macros
|
||||||
|
|
||||||
|
Requires: bash >= 4.2
|
||||||
|
Requires: coreutils
|
||||||
|
Requires: findutils
|
||||||
|
Requires: grep
|
||||||
|
Requires: sed
|
||||||
|
Requires: gawk
|
||||||
|
|
||||||
|
# The interface falls back to English without gettext and picks up new
|
||||||
|
# applications at the next `apply` without systemd, so neither is required.
|
||||||
|
Recommends: /usr/bin/gettext
|
||||||
|
Recommends: systemd
|
||||||
|
Recommends: desktop-file-utils
|
||||||
|
|
||||||
|
%description
|
||||||
|
Blink (the engine inside Chromium, Electron and CEF) has had Windows-style
|
||||||
|
autoscroll for years: hold the middle mouse button, move the pointer, the page
|
||||||
|
scrolls. On Linux it is switched off, because middle click is already taken by
|
||||||
|
primary-selection paste.
|
||||||
|
|
||||||
|
This turns it back on for every application on the system that can do it, and
|
||||||
|
for anything installed later. There is no list of supported applications to keep
|
||||||
|
up to date: every launcher is examined, the ones running on Chromium underneath
|
||||||
|
are identified by what they ship rather than by their name, and the argument goes
|
||||||
|
wherever that particular application will actually read it.
|
||||||
|
|
||||||
|
Nothing outside the user's home directory is ever written to. Run
|
||||||
|
"middleclick-autoscroll disable" before removing this package, so that everything
|
||||||
|
it changed is put back.
|
||||||
|
|
||||||
|
%prep
|
||||||
|
%autosetup -n %{name}-%{version}
|
||||||
|
|
||||||
|
%build
|
||||||
|
%make_build VERSION=%{upstream_version}
|
||||||
|
|
||||||
|
%install
|
||||||
|
%make_install PREFIX=%{_prefix} VERSION=%{upstream_version} \
|
||||||
|
USERUNITDIR=%{_userunitdir}
|
||||||
|
|
||||||
|
%find_lang %{name}
|
||||||
|
|
||||||
|
%files -f %{name}.lang
|
||||||
|
%license LICENSE
|
||||||
|
%doc %{_datadir}/doc/%{name}/README.md
|
||||||
|
%{_bindir}/%{name}
|
||||||
|
%{_datadir}/%{name}/
|
||||||
|
%{_userunitdir}/%{name}.path
|
||||||
|
%{_userunitdir}/%{name}.service
|
||||||
|
%{_mandir}/man1/%{name}.1*
|
||||||
|
|
||||||
|
%changelog
|
||||||
@@ -0,0 +1,265 @@
|
|||||||
|
# Czech translation for middleclick-autoscroll.
|
||||||
|
# Machine translated. Corrections are welcome.
|
||||||
|
# Copyright (C) 2026 Felitendo
|
||||||
|
# This file is distributed under the same license as middleclick-autoscroll.
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: middleclick-autoscroll 1.6.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: https://github.com/LoonixTools/middleclick-autoscroll/"
|
||||||
|
"issues\n"
|
||||||
|
"POT-Creation-Date: 2026-09-24 00:00+0200\n"
|
||||||
|
"PO-Revision-Date: 2026-09-24 00:00+0200\n"
|
||||||
|
"Last-Translator: machine translation\n"
|
||||||
|
"Language-Team: Czech\n"
|
||||||
|
"Language: cs\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
|
#. Status labels
|
||||||
|
msgid "ON"
|
||||||
|
msgstr "ZAPNUTO"
|
||||||
|
|
||||||
|
msgid "OFF"
|
||||||
|
msgstr "VYPNUTO"
|
||||||
|
|
||||||
|
msgid "on"
|
||||||
|
msgstr "zapnuto"
|
||||||
|
|
||||||
|
msgid "off"
|
||||||
|
msgstr "vypnuto"
|
||||||
|
|
||||||
|
msgid "(none)"
|
||||||
|
msgstr "(žádné)"
|
||||||
|
|
||||||
|
msgid "flag file"
|
||||||
|
msgstr "soubor s příznaky"
|
||||||
|
|
||||||
|
msgid "launcher"
|
||||||
|
msgstr "spouštěč"
|
||||||
|
|
||||||
|
msgid "cannot tell"
|
||||||
|
msgstr "nelze určit"
|
||||||
|
|
||||||
|
msgid "not patched yet"
|
||||||
|
msgstr "zatím nepoužito"
|
||||||
|
|
||||||
|
#. Status block
|
||||||
|
msgid "Autoscroll"
|
||||||
|
msgstr "Autoscroll"
|
||||||
|
|
||||||
|
msgid "Applications covered"
|
||||||
|
msgstr "Pokryté aplikace"
|
||||||
|
|
||||||
|
msgid "%d of %d"
|
||||||
|
msgstr "%d z %d"
|
||||||
|
|
||||||
|
msgid "Not identified"
|
||||||
|
msgstr "Nerozpoznáno"
|
||||||
|
|
||||||
|
msgid "%d (see the applications list)"
|
||||||
|
msgstr "%d (viz seznam aplikací)"
|
||||||
|
|
||||||
|
msgid "Steam"
|
||||||
|
msgstr "Steam"
|
||||||
|
|
||||||
|
msgid "Middle-click paste"
|
||||||
|
msgstr "Vkládání kolečkem"
|
||||||
|
|
||||||
|
msgid "New applications"
|
||||||
|
msgstr "Nové aplikace"
|
||||||
|
|
||||||
|
msgid "Last applied"
|
||||||
|
msgstr "Naposledy použito"
|
||||||
|
|
||||||
|
msgid "Applications pick this up the next time they are started."
|
||||||
|
msgstr "Aplikace to převezmou při příštím spuštění."
|
||||||
|
|
||||||
|
#. Menu
|
||||||
|
msgid "Turn autoscroll on or off"
|
||||||
|
msgstr "Zapnout nebo vypnout autoscroll"
|
||||||
|
|
||||||
|
msgid "Re-apply everything"
|
||||||
|
msgstr "Znovu použít vše"
|
||||||
|
|
||||||
|
msgid "Applications"
|
||||||
|
msgstr "Aplikace"
|
||||||
|
|
||||||
|
msgid "Settings"
|
||||||
|
msgstr "Nastavení"
|
||||||
|
|
||||||
|
msgid "Quit"
|
||||||
|
msgstr "Konec"
|
||||||
|
|
||||||
|
msgid "Press any key to continue..."
|
||||||
|
msgstr "Stiskněte libovolnou klávesu..."
|
||||||
|
|
||||||
|
msgid "One moment..."
|
||||||
|
msgstr "Okamžik..."
|
||||||
|
|
||||||
|
#. Settings
|
||||||
|
msgid "Turn off middle-click paste"
|
||||||
|
msgstr "Vypnout vkládání kolečkem"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Stops middle click from pasting anywhere else. Starts with the next login."
|
||||||
|
msgstr "Kolečko už jinde nevkládá. Platí od příštího přihlášení."
|
||||||
|
|
||||||
|
msgid "Cover new applications"
|
||||||
|
msgstr "Pokrýt nové aplikace"
|
||||||
|
|
||||||
|
msgid "Applications installed later get autoscroll on their own."
|
||||||
|
msgstr "Později nainstalované aplikace dostanou autoscroll samy."
|
||||||
|
|
||||||
|
msgid "More Chromium arguments"
|
||||||
|
msgstr "Další argumenty Chromia"
|
||||||
|
|
||||||
|
msgid "Passed to every application along with the autoscroll one."
|
||||||
|
msgstr "Předávají se každé aplikaci spolu s tím pro autoscroll."
|
||||||
|
|
||||||
|
msgid "Up/Down: select, Space: change, q: back"
|
||||||
|
msgstr "Nahoru/Dolů: vybrat, Mezerník: změnit, q: zpět"
|
||||||
|
|
||||||
|
msgid "Arguments separated by spaces, empty for none:"
|
||||||
|
msgstr "Argumenty oddělené mezerami, prázdné pro žádné:"
|
||||||
|
|
||||||
|
msgid "Could not save the setting."
|
||||||
|
msgstr "Nastavení se nepodařilo uložit."
|
||||||
|
|
||||||
|
#. Applications screen
|
||||||
|
msgid "Looking at the installed applications..."
|
||||||
|
msgstr "Procházím nainstalované aplikace..."
|
||||||
|
|
||||||
|
msgid "No Chromium-based applications found."
|
||||||
|
msgstr "Nenalezeny žádné aplikace založené na Chromiu."
|
||||||
|
|
||||||
|
msgid "Anything marked \"cannot tell\" stays off until it is turned on here."
|
||||||
|
msgstr "Co je označeno „nelze určit“, zůstane vypnuté, dokud to tu nezapnete."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off. This is what would be covered."
|
||||||
|
msgstr "Autoscroll je vypnutý. Toto by bylo pokryto."
|
||||||
|
|
||||||
|
msgid "Up/Down: select, Space: turn on or off, q: back"
|
||||||
|
msgstr "Nahoru/Dolů: vybrat, Mezerník: zapnout či vypnout, q: zpět"
|
||||||
|
|
||||||
|
msgid "Search:"
|
||||||
|
msgstr "Hledat:"
|
||||||
|
|
||||||
|
msgid "Type to search, Down: go to the list, Esc: back"
|
||||||
|
msgstr "Pište pro hledání, Dolů: do seznamu, Esc: zpět"
|
||||||
|
|
||||||
|
msgid "No matches."
|
||||||
|
msgstr "Žádné výsledky."
|
||||||
|
|
||||||
|
#. Results
|
||||||
|
msgid "Autoscroll is on for %d applications."
|
||||||
|
msgstr "Autoscroll je zapnutý. Aplikací: %d."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Applications that are already running pick this up when they are restarted."
|
||||||
|
msgstr "Již spuštěné aplikace to převezmou po restartu."
|
||||||
|
|
||||||
|
msgid "Could not start the watcher for newly installed applications."
|
||||||
|
msgstr "Sledování nových aplikací se nepodařilo spustit."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"No systemd user session, so newly installed applications will not be picked "
|
||||||
|
"up on their own."
|
||||||
|
msgstr ""
|
||||||
|
"Chybí uživatelská relace systemd, takže nově nainstalované aplikace nebudou "
|
||||||
|
"zachyceny samy."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off and everything that was changed has been put back."
|
||||||
|
msgstr "Autoscroll je vypnutý a všechny změny byly vráceny."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off. Turn it on first."
|
||||||
|
msgstr "Autoscroll je vypnutý. Nejdřív ho zapněte."
|
||||||
|
|
||||||
|
msgid "Applied again to %d applications."
|
||||||
|
msgstr "Znovu použito. Aplikací: %d."
|
||||||
|
|
||||||
|
msgid "Applied to %d applications."
|
||||||
|
msgstr "Použito. Aplikací: %d."
|
||||||
|
|
||||||
|
msgid "Already applied to %d applications."
|
||||||
|
msgstr "Už použito. Aplikací: %d."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Steam starts its interface in a way this version cannot change without Steam "
|
||||||
|
"noticing; leaving it alone."
|
||||||
|
msgstr ""
|
||||||
|
"Steam spouští své rozhraní způsobem, který tato verze nedokáže změnit, aniž "
|
||||||
|
"by si toho Steam všiml; Steam zůstává beze změny."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Steam's interface cannot be given the flag without leaving a file Steam "
|
||||||
|
"would reinstall; the change has been taken back."
|
||||||
|
msgstr ""
|
||||||
|
"Rozhraní Steamu nelze dát příznak bez souboru, který by Steam znovu "
|
||||||
|
"nainstaloval; změna byla vrácena."
|
||||||
|
|
||||||
|
msgid "Middle click stops pasting at the next login."
|
||||||
|
msgstr "Kolečko přestane vkládat od příštího přihlášení."
|
||||||
|
|
||||||
|
#. Help
|
||||||
|
msgid "Usage: middleclick-autoscroll [command]"
|
||||||
|
msgstr "Použití: middleclick-autoscroll [příkaz]"
|
||||||
|
|
||||||
|
msgid "Commands:"
|
||||||
|
msgstr "Příkazy:"
|
||||||
|
|
||||||
|
msgid "Turn autoscroll on"
|
||||||
|
msgstr "Zapnout autoscroll"
|
||||||
|
|
||||||
|
msgid "Turn it off and put everything back"
|
||||||
|
msgstr "Vypnout a vše vrátit"
|
||||||
|
|
||||||
|
msgid "Apply to anything installed since the last run"
|
||||||
|
msgstr "Použít na vše nainstalované od posledního spuštění"
|
||||||
|
|
||||||
|
msgid "Take everything back and apply it again"
|
||||||
|
msgstr "Vše vrátit a použít znovu"
|
||||||
|
|
||||||
|
msgid "Show what is covered"
|
||||||
|
msgstr "Ukázat, co je pokryto"
|
||||||
|
|
||||||
|
msgid "List every application that was found"
|
||||||
|
msgstr "Vypsat všechny nalezené aplikace"
|
||||||
|
|
||||||
|
msgid "Show this help"
|
||||||
|
msgstr "Zobrazit tuto nápovědu"
|
||||||
|
|
||||||
|
msgid "Show the version"
|
||||||
|
msgstr "Zobrazit verzi"
|
||||||
|
|
||||||
|
msgid "Without a command an interactive menu is shown."
|
||||||
|
msgstr "Bez příkazu se zobrazí interaktivní nabídka."
|
||||||
|
|
||||||
|
msgid "Unknown command: %s"
|
||||||
|
msgstr "Neznámý příkaz: %s"
|
||||||
|
|
||||||
|
#. Time
|
||||||
|
msgid "never"
|
||||||
|
msgstr "nikdy"
|
||||||
|
|
||||||
|
msgid "just now"
|
||||||
|
msgstr "právě teď"
|
||||||
|
|
||||||
|
msgid "1 minute ago"
|
||||||
|
msgstr "před 1 minutou"
|
||||||
|
|
||||||
|
msgid "%d minutes ago"
|
||||||
|
msgstr "před %d min"
|
||||||
|
|
||||||
|
msgid "1 hour ago"
|
||||||
|
msgstr "před 1 hodinou"
|
||||||
|
|
||||||
|
msgid "%d hours ago"
|
||||||
|
msgstr "před %d h"
|
||||||
|
|
||||||
|
msgid "1 day ago"
|
||||||
|
msgstr "před 1 dnem"
|
||||||
|
|
||||||
|
msgid "%d days ago"
|
||||||
|
msgstr "před %d dny"
|
||||||
@@ -4,10 +4,11 @@
|
|||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: middleclick-autoscroll 1.0.1\n"
|
"Project-Id-Version: middleclick-autoscroll 1.6.0\n"
|
||||||
"Report-Msgid-Bugs-To: https://github.com/Felitendo/middleclick-autoscroll/issues\n"
|
"Report-Msgid-Bugs-To: https://github.com/LoonixTools/middleclick-autoscroll/"
|
||||||
"POT-Creation-Date: 2026-08-16 00:00+0200\n"
|
"issues\n"
|
||||||
"PO-Revision-Date: 2026-08-16 00:00+0200\n"
|
"POT-Creation-Date: 2026-09-24 00:00+0200\n"
|
||||||
|
"PO-Revision-Date: 2026-09-24 00:00+0200\n"
|
||||||
"Last-Translator: Felitendo\n"
|
"Last-Translator: Felitendo\n"
|
||||||
"Language-Team: German\n"
|
"Language-Team: German\n"
|
||||||
"Language: de\n"
|
"Language: de\n"
|
||||||
@@ -43,7 +44,6 @@ msgstr "nicht erkennbar"
|
|||||||
msgid "not patched yet"
|
msgid "not patched yet"
|
||||||
msgstr "noch nicht gepatcht"
|
msgstr "noch nicht gepatcht"
|
||||||
|
|
||||||
|
|
||||||
#. Status block
|
#. Status block
|
||||||
msgid "Autoscroll"
|
msgid "Autoscroll"
|
||||||
msgstr "Autoscroll"
|
msgstr "Autoscroll"
|
||||||
@@ -57,12 +57,15 @@ msgstr "%d von %d"
|
|||||||
msgid "Not identified"
|
msgid "Not identified"
|
||||||
msgstr "Nicht erkannt"
|
msgstr "Nicht erkannt"
|
||||||
|
|
||||||
msgid "%d - see the applications list"
|
msgid "%d (see the applications list)"
|
||||||
msgstr "%d – siehe Anwendungsliste"
|
msgstr "%d (siehe Anwendungsliste)"
|
||||||
|
|
||||||
msgid "Steam"
|
msgid "Steam"
|
||||||
msgstr "Steam"
|
msgstr "Steam"
|
||||||
|
|
||||||
|
msgid "Middle-click paste"
|
||||||
|
msgstr "Mittelklick-Einfügen"
|
||||||
|
|
||||||
msgid "New applications"
|
msgid "New applications"
|
||||||
msgstr "Neue Anwendungen"
|
msgstr "Neue Anwendungen"
|
||||||
|
|
||||||
@@ -72,13 +75,12 @@ msgstr "Zuletzt angewendet"
|
|||||||
msgid "Applications pick this up the next time they are started."
|
msgid "Applications pick this up the next time they are started."
|
||||||
msgstr "Anwendungen übernehmen das beim nächsten Start."
|
msgstr "Anwendungen übernehmen das beim nächsten Start."
|
||||||
|
|
||||||
|
|
||||||
#. Menu
|
#. Menu
|
||||||
msgid "Turn autoscroll on or off"
|
msgid "Turn autoscroll on or off"
|
||||||
msgstr "Autoscroll ein- oder ausschalten"
|
msgstr "Autoscroll ein- oder ausschalten"
|
||||||
|
|
||||||
msgid "Apply now"
|
msgid "Re-apply everything"
|
||||||
msgstr "Jetzt anwenden"
|
msgstr "Alles neu anwenden"
|
||||||
|
|
||||||
msgid "Applications"
|
msgid "Applications"
|
||||||
msgstr "Anwendungen"
|
msgstr "Anwendungen"
|
||||||
@@ -92,31 +94,32 @@ msgstr "Beenden"
|
|||||||
msgid "Press any key to continue..."
|
msgid "Press any key to continue..."
|
||||||
msgstr "Beliebige Taste drücken …"
|
msgstr "Beliebige Taste drücken …"
|
||||||
|
|
||||||
|
msgid "One moment..."
|
||||||
|
msgstr "Einen Moment …"
|
||||||
|
|
||||||
#. Settings
|
#. Settings
|
||||||
msgid "Electron and CEF applications"
|
msgid "Turn off middle-click paste"
|
||||||
msgstr "Electron- und CEF-Anwendungen"
|
msgstr "Mittelklick-Einfügen abschalten"
|
||||||
|
|
||||||
msgid "Chromium-based browsers"
|
msgid ""
|
||||||
msgstr "Chromium-basierte Browser"
|
"Stops middle click from pasting anywhere else. Starts with the next login."
|
||||||
|
msgstr ""
|
||||||
|
"Mittelklick fügt auch sonst nirgends mehr ein. Ab der nächsten Anmeldung."
|
||||||
|
|
||||||
msgid "Flatpak applications"
|
msgid "Cover new applications"
|
||||||
msgstr "Flatpak-Anwendungen"
|
msgstr "Neue Anwendungen abdecken"
|
||||||
|
|
||||||
msgid "Programs that start themselves at login"
|
msgid "Applications installed later get autoscroll on their own."
|
||||||
msgstr "Programme, die sich beim Anmelden selbst starten"
|
msgstr "Später installierte Anwendungen bekommen Autoscroll von selbst."
|
||||||
|
|
||||||
msgid "Spotify"
|
msgid "More Chromium arguments"
|
||||||
msgstr "Spotify"
|
msgstr "Weitere Chromium-Argumente"
|
||||||
|
|
||||||
msgid "Apply to newly installed applications"
|
msgid "Passed to every application along with the autoscroll one."
|
||||||
msgstr "Auf neu installierte Anwendungen anwenden"
|
msgstr "Gehen zusammen mit dem Autoscroll-Argument an jede Anwendung."
|
||||||
|
|
||||||
msgid "Additional Chromium arguments"
|
msgid "Up/Down: select, Space: change, q: back"
|
||||||
msgstr "Zusätzliche Chromium-Argumente"
|
msgstr "Hoch/Runter: wählen, Leertaste: ändern, q: zurück"
|
||||||
|
|
||||||
msgid "Up/Down select - Space or Right changes - q goes back"
|
|
||||||
msgstr "Hoch/Runter wählt – Leertaste oder Rechts ändert – q geht zurück"
|
|
||||||
|
|
||||||
msgid "Arguments separated by spaces, empty for none:"
|
msgid "Arguments separated by spaces, empty for none:"
|
||||||
msgstr "Argumente mit Leerzeichen getrennt, leer für keine:"
|
msgstr "Argumente mit Leerzeichen getrennt, leer für keine:"
|
||||||
@@ -124,7 +127,6 @@ msgstr "Argumente mit Leerzeichen getrennt, leer für keine:"
|
|||||||
msgid "Could not save the setting."
|
msgid "Could not save the setting."
|
||||||
msgstr "Einstellung konnte nicht gespeichert werden."
|
msgstr "Einstellung konnte nicht gespeichert werden."
|
||||||
|
|
||||||
|
|
||||||
#. Applications screen
|
#. Applications screen
|
||||||
msgid "Looking at the installed applications..."
|
msgid "Looking at the installed applications..."
|
||||||
msgstr "Installierte Anwendungen werden durchgesehen …"
|
msgstr "Installierte Anwendungen werden durchgesehen …"
|
||||||
@@ -132,31 +134,42 @@ msgstr "Installierte Anwendungen werden durchgesehen …"
|
|||||||
msgid "No Chromium-based applications found."
|
msgid "No Chromium-based applications found."
|
||||||
msgstr "Keine Chromium-basierten Anwendungen gefunden."
|
msgstr "Keine Chromium-basierten Anwendungen gefunden."
|
||||||
|
|
||||||
msgid "Anything not identified is left alone until it is turned on here."
|
msgid "Anything marked \"cannot tell\" stays off until it is turned on here."
|
||||||
msgstr "Nicht erkannte Anwendungen bleiben unangetastet, bis sie hier eingeschaltet werden."
|
msgstr "Was „nicht erkennbar“ ist, bleibt aus, bis es hier eingeschaltet wird."
|
||||||
|
|
||||||
msgid "Autoscroll is off - this is what would be covered."
|
msgid "Autoscroll is off. This is what would be covered."
|
||||||
msgstr "Autoscroll ist aus – das hier wäre abgedeckt."
|
msgstr "Autoscroll ist aus. Das hier wäre abgedeckt."
|
||||||
|
|
||||||
msgid "Up/Down select - Space turns one on or off - q goes back"
|
msgid "Up/Down: select, Space: turn on or off, q: back"
|
||||||
msgstr "Hoch/Runter wählt – Leertaste schaltet einzeln ein oder aus – q geht zurück"
|
msgstr "Hoch/Runter: wählen, Leertaste: ein- oder ausschalten, q: zurück"
|
||||||
|
|
||||||
|
msgid "Search:"
|
||||||
|
msgstr "Suchen:"
|
||||||
|
|
||||||
|
msgid "Type to search, Down: go to the list, Esc: back"
|
||||||
|
msgstr "Tippen zum Suchen, Runter: zur Liste, Esc: zurück"
|
||||||
|
|
||||||
|
msgid "No matches."
|
||||||
|
msgstr "Keine Treffer."
|
||||||
|
|
||||||
#. Results
|
#. Results
|
||||||
msgid "Autoscroll is on for %d applications."
|
msgid "Autoscroll is on for %d applications."
|
||||||
msgstr "Autoscroll ist für %d Anwendungen an."
|
msgstr "Autoscroll ist für %d Anwendungen an."
|
||||||
|
|
||||||
msgid "Applications that are already running pick this up when they are restarted."
|
msgid ""
|
||||||
|
"Applications that are already running pick this up when they are restarted."
|
||||||
msgstr "Bereits laufende Anwendungen übernehmen das nach einem Neustart."
|
msgstr "Bereits laufende Anwendungen übernehmen das nach einem Neustart."
|
||||||
|
|
||||||
msgid "Steam's launcher now skips its file check, which is what keeps the change from being undone at every start."
|
|
||||||
msgstr "Steams Startereintrag überspringt jetzt die Dateiprüfung – nur so bleibt die Änderung bei jedem Start erhalten."
|
|
||||||
|
|
||||||
msgid "Could not start the watcher for newly installed applications."
|
msgid "Could not start the watcher for newly installed applications."
|
||||||
msgstr "Die Überwachung neu installierter Anwendungen konnte nicht gestartet werden."
|
msgstr ""
|
||||||
|
"Die Überwachung neu installierter Anwendungen konnte nicht gestartet werden."
|
||||||
|
|
||||||
msgid "No systemd user session - newly installed applications will not be picked up on their own."
|
msgid ""
|
||||||
msgstr "Keine systemd-Benutzersitzung – neu installierte Anwendungen werden nicht von selbst erfasst."
|
"No systemd user session, so newly installed applications will not be picked "
|
||||||
|
"up on their own."
|
||||||
|
msgstr ""
|
||||||
|
"Keine systemd-Benutzersitzung, daher werden neu installierte Anwendungen "
|
||||||
|
"nicht von selbst erfasst."
|
||||||
|
|
||||||
msgid "Autoscroll is off and everything that was changed has been put back."
|
msgid "Autoscroll is off and everything that was changed has been put back."
|
||||||
msgstr "Autoscroll ist aus, alle Änderungen wurden zurückgenommen."
|
msgstr "Autoscroll ist aus, alle Änderungen wurden zurückgenommen."
|
||||||
@@ -164,15 +177,32 @@ msgstr "Autoscroll ist aus, alle Änderungen wurden zurückgenommen."
|
|||||||
msgid "Autoscroll is off. Turn it on first."
|
msgid "Autoscroll is off. Turn it on first."
|
||||||
msgstr "Autoscroll ist aus. Erst einschalten."
|
msgstr "Autoscroll ist aus. Erst einschalten."
|
||||||
|
|
||||||
|
msgid "Applied again to %d applications."
|
||||||
|
msgstr "Erneut auf %d Anwendungen angewendet."
|
||||||
|
|
||||||
msgid "Applied to %d applications."
|
msgid "Applied to %d applications."
|
||||||
msgstr "Auf %d Anwendungen angewendet."
|
msgstr "Auf %d Anwendungen angewendet."
|
||||||
|
|
||||||
msgid "Already applied to %d applications."
|
msgid "Already applied to %d applications."
|
||||||
msgstr "Bereits auf %d Anwendungen angewendet."
|
msgstr "Bereits auf %d Anwendungen angewendet."
|
||||||
|
|
||||||
msgid "Steam starts its interface in a way this version does not recognise; leaving it alone."
|
msgid ""
|
||||||
msgstr "Steam startet seine Oberfläche auf eine Art, die diese Version nicht kennt; Steam bleibt unangetastet."
|
"Steam starts its interface in a way this version cannot change without Steam "
|
||||||
|
"noticing; leaving it alone."
|
||||||
|
msgstr ""
|
||||||
|
"Steam startet seine Oberfläche auf eine Art, die diese Version nicht ändern "
|
||||||
|
"kann, ohne dass Steam es merkt; Steam bleibt unangetastet."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Steam's interface cannot be given the flag without leaving a file Steam "
|
||||||
|
"would reinstall; the change has been taken back."
|
||||||
|
msgstr ""
|
||||||
|
"Steams Oberfläche lässt sich das Flag nicht geben, ohne eine Datei zu "
|
||||||
|
"hinterlassen, die Steam neu installieren würde; die Änderung wurde "
|
||||||
|
"zurückgenommen."
|
||||||
|
|
||||||
|
msgid "Middle click stops pasting at the next login."
|
||||||
|
msgstr "Mittelklick fügt ab der nächsten Anmeldung nichts mehr ein."
|
||||||
|
|
||||||
#. Help
|
#. Help
|
||||||
msgid "Usage: middleclick-autoscroll [command]"
|
msgid "Usage: middleclick-autoscroll [command]"
|
||||||
@@ -190,6 +220,9 @@ msgstr "Ausschalten und alles zurücknehmen"
|
|||||||
msgid "Apply to anything installed since the last run"
|
msgid "Apply to anything installed since the last run"
|
||||||
msgstr "Auf alles anwenden, was seit dem letzten Lauf dazugekommen ist"
|
msgstr "Auf alles anwenden, was seit dem letzten Lauf dazugekommen ist"
|
||||||
|
|
||||||
|
msgid "Take everything back and apply it again"
|
||||||
|
msgstr "Alles zurücknehmen und neu anwenden"
|
||||||
|
|
||||||
msgid "Show what is covered"
|
msgid "Show what is covered"
|
||||||
msgstr "Anzeigen, was abgedeckt ist"
|
msgstr "Anzeigen, was abgedeckt ist"
|
||||||
|
|
||||||
@@ -208,7 +241,6 @@ msgstr "Ohne Befehl wird ein interaktives Menü angezeigt."
|
|||||||
msgid "Unknown command: %s"
|
msgid "Unknown command: %s"
|
||||||
msgstr "Unbekannter Befehl: %s"
|
msgstr "Unbekannter Befehl: %s"
|
||||||
|
|
||||||
|
|
||||||
#. Time
|
#. Time
|
||||||
msgid "never"
|
msgid "never"
|
||||||
msgstr "nie"
|
msgstr "nie"
|
||||||
@@ -216,11 +248,20 @@ msgstr "nie"
|
|||||||
msgid "just now"
|
msgid "just now"
|
||||||
msgstr "gerade eben"
|
msgstr "gerade eben"
|
||||||
|
|
||||||
|
msgid "1 minute ago"
|
||||||
|
msgstr "vor 1 Minute"
|
||||||
|
|
||||||
msgid "%d minutes ago"
|
msgid "%d minutes ago"
|
||||||
msgstr "vor %d Minuten"
|
msgstr "vor %d Minuten"
|
||||||
|
|
||||||
|
msgid "1 hour ago"
|
||||||
|
msgstr "vor 1 Stunde"
|
||||||
|
|
||||||
msgid "%d hours ago"
|
msgid "%d hours ago"
|
||||||
msgstr "vor %d Stunden"
|
msgstr "vor %d Stunden"
|
||||||
|
|
||||||
|
msgid "1 day ago"
|
||||||
|
msgstr "vor 1 Tag"
|
||||||
|
|
||||||
msgid "%d days ago"
|
msgid "%d days ago"
|
||||||
msgstr "vor %d Tagen"
|
msgstr "vor %d Tagen"
|
||||||
@@ -0,0 +1,266 @@
|
|||||||
|
# Spanish translation for middleclick-autoscroll.
|
||||||
|
# Machine translated. Corrections are welcome.
|
||||||
|
# Copyright (C) 2026 Felitendo
|
||||||
|
# This file is distributed under the same license as middleclick-autoscroll.
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: middleclick-autoscroll 1.6.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: https://github.com/LoonixTools/middleclick-autoscroll/"
|
||||||
|
"issues\n"
|
||||||
|
"POT-Creation-Date: 2026-09-24 00:00+0200\n"
|
||||||
|
"PO-Revision-Date: 2026-09-24 00:00+0200\n"
|
||||||
|
"Last-Translator: machine translation\n"
|
||||||
|
"Language-Team: Spanish\n"
|
||||||
|
"Language: es\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
|
#. Status labels
|
||||||
|
msgid "ON"
|
||||||
|
msgstr "ACTIVADO"
|
||||||
|
|
||||||
|
msgid "OFF"
|
||||||
|
msgstr "DESACTIVADO"
|
||||||
|
|
||||||
|
msgid "on"
|
||||||
|
msgstr "activado"
|
||||||
|
|
||||||
|
msgid "off"
|
||||||
|
msgstr "desactivado"
|
||||||
|
|
||||||
|
msgid "(none)"
|
||||||
|
msgstr "(ninguno)"
|
||||||
|
|
||||||
|
msgid "flag file"
|
||||||
|
msgstr "archivo de flags"
|
||||||
|
|
||||||
|
msgid "launcher"
|
||||||
|
msgstr "lanzador"
|
||||||
|
|
||||||
|
msgid "cannot tell"
|
||||||
|
msgstr "no se sabe"
|
||||||
|
|
||||||
|
msgid "not patched yet"
|
||||||
|
msgstr "aún sin aplicar"
|
||||||
|
|
||||||
|
#. Status block
|
||||||
|
msgid "Autoscroll"
|
||||||
|
msgstr "Autoscroll"
|
||||||
|
|
||||||
|
msgid "Applications covered"
|
||||||
|
msgstr "Aplicaciones cubiertas"
|
||||||
|
|
||||||
|
msgid "%d of %d"
|
||||||
|
msgstr "%d de %d"
|
||||||
|
|
||||||
|
msgid "Not identified"
|
||||||
|
msgstr "Sin identificar"
|
||||||
|
|
||||||
|
msgid "%d (see the applications list)"
|
||||||
|
msgstr "%d (ver la lista de aplicaciones)"
|
||||||
|
|
||||||
|
msgid "Steam"
|
||||||
|
msgstr "Steam"
|
||||||
|
|
||||||
|
msgid "Middle-click paste"
|
||||||
|
msgstr "Pegar con clic central"
|
||||||
|
|
||||||
|
msgid "New applications"
|
||||||
|
msgstr "Aplicaciones nuevas"
|
||||||
|
|
||||||
|
msgid "Last applied"
|
||||||
|
msgstr "Aplicado por última vez"
|
||||||
|
|
||||||
|
msgid "Applications pick this up the next time they are started."
|
||||||
|
msgstr "Las aplicaciones lo toman la próxima vez que se inicien."
|
||||||
|
|
||||||
|
#. Menu
|
||||||
|
msgid "Turn autoscroll on or off"
|
||||||
|
msgstr "Activar o desactivar autoscroll"
|
||||||
|
|
||||||
|
msgid "Re-apply everything"
|
||||||
|
msgstr "Volver a aplicar todo"
|
||||||
|
|
||||||
|
msgid "Applications"
|
||||||
|
msgstr "Aplicaciones"
|
||||||
|
|
||||||
|
msgid "Settings"
|
||||||
|
msgstr "Ajustes"
|
||||||
|
|
||||||
|
msgid "Quit"
|
||||||
|
msgstr "Salir"
|
||||||
|
|
||||||
|
msgid "Press any key to continue..."
|
||||||
|
msgstr "Pulsa cualquier tecla para continuar..."
|
||||||
|
|
||||||
|
msgid "One moment..."
|
||||||
|
msgstr "Un momento..."
|
||||||
|
|
||||||
|
#. Settings
|
||||||
|
msgid "Turn off middle-click paste"
|
||||||
|
msgstr "Desactivar pegar con clic central"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Stops middle click from pasting anywhere else. Starts with the next login."
|
||||||
|
msgstr ""
|
||||||
|
"El clic central ya no pega en ningún otro sitio. Desde el próximo inicio."
|
||||||
|
|
||||||
|
msgid "Cover new applications"
|
||||||
|
msgstr "Cubrir aplicaciones nuevas"
|
||||||
|
|
||||||
|
msgid "Applications installed later get autoscroll on their own."
|
||||||
|
msgstr "Las aplicaciones instaladas más tarde reciben autoscroll solas."
|
||||||
|
|
||||||
|
msgid "More Chromium arguments"
|
||||||
|
msgstr "Más argumentos de Chromium"
|
||||||
|
|
||||||
|
msgid "Passed to every application along with the autoscroll one."
|
||||||
|
msgstr "Se pasan a cada aplicación junto con el de autoscroll."
|
||||||
|
|
||||||
|
msgid "Up/Down: select, Space: change, q: back"
|
||||||
|
msgstr "Arriba/Abajo: elegir, Espacio: cambiar, q: volver"
|
||||||
|
|
||||||
|
msgid "Arguments separated by spaces, empty for none:"
|
||||||
|
msgstr "Argumentos separados por espacios, vacío para ninguno:"
|
||||||
|
|
||||||
|
msgid "Could not save the setting."
|
||||||
|
msgstr "No se pudo guardar el ajuste."
|
||||||
|
|
||||||
|
#. Applications screen
|
||||||
|
msgid "Looking at the installed applications..."
|
||||||
|
msgstr "Revisando las aplicaciones instaladas..."
|
||||||
|
|
||||||
|
msgid "No Chromium-based applications found."
|
||||||
|
msgstr "No se encontraron aplicaciones basadas en Chromium."
|
||||||
|
|
||||||
|
msgid "Anything marked \"cannot tell\" stays off until it is turned on here."
|
||||||
|
msgstr "Lo marcado como «no se sabe» sigue desactivado hasta activarlo aquí."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off. This is what would be covered."
|
||||||
|
msgstr "Autoscroll está desactivado. Esto es lo que se cubriría."
|
||||||
|
|
||||||
|
msgid "Up/Down: select, Space: turn on or off, q: back"
|
||||||
|
msgstr "Arriba/Abajo: elegir, Espacio: activar o desactivar, q: volver"
|
||||||
|
|
||||||
|
msgid "Search:"
|
||||||
|
msgstr "Buscar:"
|
||||||
|
|
||||||
|
msgid "Type to search, Down: go to the list, Esc: back"
|
||||||
|
msgstr "Escribe para buscar, Abajo: ir a la lista, Esc: volver"
|
||||||
|
|
||||||
|
msgid "No matches."
|
||||||
|
msgstr "Sin resultados."
|
||||||
|
|
||||||
|
#. Results
|
||||||
|
msgid "Autoscroll is on for %d applications."
|
||||||
|
msgstr "Autoscroll está activado para %d aplicaciones."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Applications that are already running pick this up when they are restarted."
|
||||||
|
msgstr "Las aplicaciones que ya están abiertas lo toman al reiniciarse."
|
||||||
|
|
||||||
|
msgid "Could not start the watcher for newly installed applications."
|
||||||
|
msgstr "No se pudo iniciar la vigilancia de aplicaciones nuevas."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"No systemd user session, so newly installed applications will not be picked "
|
||||||
|
"up on their own."
|
||||||
|
msgstr ""
|
||||||
|
"No hay sesión de usuario de systemd, así que las aplicaciones nuevas no se "
|
||||||
|
"detectarán solas."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off and everything that was changed has been put back."
|
||||||
|
msgstr "Autoscroll está desactivado y todo lo cambiado se ha restaurado."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off. Turn it on first."
|
||||||
|
msgstr "Autoscroll está desactivado. Actívalo primero."
|
||||||
|
|
||||||
|
msgid "Applied again to %d applications."
|
||||||
|
msgstr "Aplicado de nuevo a %d aplicaciones."
|
||||||
|
|
||||||
|
msgid "Applied to %d applications."
|
||||||
|
msgstr "Aplicado a %d aplicaciones."
|
||||||
|
|
||||||
|
msgid "Already applied to %d applications."
|
||||||
|
msgstr "Ya aplicado a %d aplicaciones."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Steam starts its interface in a way this version cannot change without Steam "
|
||||||
|
"noticing; leaving it alone."
|
||||||
|
msgstr ""
|
||||||
|
"Steam inicia su interfaz de una forma que esta versión no puede cambiar sin "
|
||||||
|
"que Steam lo note; se deja como está."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Steam's interface cannot be given the flag without leaving a file Steam "
|
||||||
|
"would reinstall; the change has been taken back."
|
||||||
|
msgstr ""
|
||||||
|
"No se puede dar el flag a la interfaz de Steam sin dejar un archivo que "
|
||||||
|
"Steam reinstalaría; el cambio se ha deshecho."
|
||||||
|
|
||||||
|
msgid "Middle click stops pasting at the next login."
|
||||||
|
msgstr "El clic central dejará de pegar en el próximo inicio de sesión."
|
||||||
|
|
||||||
|
#. Help
|
||||||
|
msgid "Usage: middleclick-autoscroll [command]"
|
||||||
|
msgstr "Uso: middleclick-autoscroll [comando]"
|
||||||
|
|
||||||
|
msgid "Commands:"
|
||||||
|
msgstr "Comandos:"
|
||||||
|
|
||||||
|
msgid "Turn autoscroll on"
|
||||||
|
msgstr "Activar autoscroll"
|
||||||
|
|
||||||
|
msgid "Turn it off and put everything back"
|
||||||
|
msgstr "Desactivarlo y restaurar todo"
|
||||||
|
|
||||||
|
msgid "Apply to anything installed since the last run"
|
||||||
|
msgstr "Aplicar a todo lo instalado desde la última vez"
|
||||||
|
|
||||||
|
msgid "Take everything back and apply it again"
|
||||||
|
msgstr "Deshacer todo y volver a aplicarlo"
|
||||||
|
|
||||||
|
msgid "Show what is covered"
|
||||||
|
msgstr "Mostrar qué está cubierto"
|
||||||
|
|
||||||
|
msgid "List every application that was found"
|
||||||
|
msgstr "Listar todas las aplicaciones encontradas"
|
||||||
|
|
||||||
|
msgid "Show this help"
|
||||||
|
msgstr "Mostrar esta ayuda"
|
||||||
|
|
||||||
|
msgid "Show the version"
|
||||||
|
msgstr "Mostrar la versión"
|
||||||
|
|
||||||
|
msgid "Without a command an interactive menu is shown."
|
||||||
|
msgstr "Sin comando se muestra un menú interactivo."
|
||||||
|
|
||||||
|
msgid "Unknown command: %s"
|
||||||
|
msgstr "Comando desconocido: %s"
|
||||||
|
|
||||||
|
#. Time
|
||||||
|
msgid "never"
|
||||||
|
msgstr "nunca"
|
||||||
|
|
||||||
|
msgid "just now"
|
||||||
|
msgstr "ahora mismo"
|
||||||
|
|
||||||
|
msgid "1 minute ago"
|
||||||
|
msgstr "hace 1 minuto"
|
||||||
|
|
||||||
|
msgid "%d minutes ago"
|
||||||
|
msgstr "hace %d minutos"
|
||||||
|
|
||||||
|
msgid "1 hour ago"
|
||||||
|
msgstr "hace 1 hora"
|
||||||
|
|
||||||
|
msgid "%d hours ago"
|
||||||
|
msgstr "hace %d horas"
|
||||||
|
|
||||||
|
msgid "1 day ago"
|
||||||
|
msgstr "hace 1 día"
|
||||||
|
|
||||||
|
msgid "%d days ago"
|
||||||
|
msgstr "hace %d días"
|
||||||
@@ -0,0 +1,269 @@
|
|||||||
|
# French translation for middleclick-autoscroll.
|
||||||
|
# Machine translated. Corrections are welcome.
|
||||||
|
# Copyright (C) 2026 Felitendo
|
||||||
|
# This file is distributed under the same license as middleclick-autoscroll.
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: middleclick-autoscroll 1.6.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: https://github.com/LoonixTools/middleclick-autoscroll/"
|
||||||
|
"issues\n"
|
||||||
|
"POT-Creation-Date: 2026-09-24 00:00+0200\n"
|
||||||
|
"PO-Revision-Date: 2026-09-24 00:00+0200\n"
|
||||||
|
"Last-Translator: machine translation\n"
|
||||||
|
"Language-Team: French\n"
|
||||||
|
"Language: fr\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
|
#. Status labels
|
||||||
|
msgid "ON"
|
||||||
|
msgstr "ACTIVÉ"
|
||||||
|
|
||||||
|
msgid "OFF"
|
||||||
|
msgstr "DÉSACTIVÉ"
|
||||||
|
|
||||||
|
msgid "on"
|
||||||
|
msgstr "activé"
|
||||||
|
|
||||||
|
msgid "off"
|
||||||
|
msgstr "désactivé"
|
||||||
|
|
||||||
|
msgid "(none)"
|
||||||
|
msgstr "(aucun)"
|
||||||
|
|
||||||
|
msgid "flag file"
|
||||||
|
msgstr "fichier de flags"
|
||||||
|
|
||||||
|
msgid "launcher"
|
||||||
|
msgstr "lanceur"
|
||||||
|
|
||||||
|
msgid "cannot tell"
|
||||||
|
msgstr "indéterminé"
|
||||||
|
|
||||||
|
msgid "not patched yet"
|
||||||
|
msgstr "pas encore appliqué"
|
||||||
|
|
||||||
|
#. Status block
|
||||||
|
msgid "Autoscroll"
|
||||||
|
msgstr "Autoscroll"
|
||||||
|
|
||||||
|
msgid "Applications covered"
|
||||||
|
msgstr "Applications couvertes"
|
||||||
|
|
||||||
|
msgid "%d of %d"
|
||||||
|
msgstr "%d sur %d"
|
||||||
|
|
||||||
|
msgid "Not identified"
|
||||||
|
msgstr "Non identifiées"
|
||||||
|
|
||||||
|
msgid "%d (see the applications list)"
|
||||||
|
msgstr "%d (voir la liste des applications)"
|
||||||
|
|
||||||
|
msgid "Steam"
|
||||||
|
msgstr "Steam"
|
||||||
|
|
||||||
|
msgid "Middle-click paste"
|
||||||
|
msgstr "Collage au clic du milieu"
|
||||||
|
|
||||||
|
msgid "New applications"
|
||||||
|
msgstr "Nouvelles applications"
|
||||||
|
|
||||||
|
msgid "Last applied"
|
||||||
|
msgstr "Dernier passage"
|
||||||
|
|
||||||
|
msgid "Applications pick this up the next time they are started."
|
||||||
|
msgstr "Les applications le prennent en compte à leur prochain démarrage."
|
||||||
|
|
||||||
|
#. Menu
|
||||||
|
msgid "Turn autoscroll on or off"
|
||||||
|
msgstr "Activer ou désactiver l'autoscroll"
|
||||||
|
|
||||||
|
msgid "Re-apply everything"
|
||||||
|
msgstr "Tout réappliquer"
|
||||||
|
|
||||||
|
msgid "Applications"
|
||||||
|
msgstr "Applications"
|
||||||
|
|
||||||
|
msgid "Settings"
|
||||||
|
msgstr "Paramètres"
|
||||||
|
|
||||||
|
msgid "Quit"
|
||||||
|
msgstr "Quitter"
|
||||||
|
|
||||||
|
msgid "Press any key to continue..."
|
||||||
|
msgstr "Appuyez sur une touche pour continuer..."
|
||||||
|
|
||||||
|
msgid "One moment..."
|
||||||
|
msgstr "Un instant..."
|
||||||
|
|
||||||
|
#. Settings
|
||||||
|
msgid "Turn off middle-click paste"
|
||||||
|
msgstr "Désactiver le collage au clic du milieu"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Stops middle click from pasting anywhere else. Starts with the next login."
|
||||||
|
msgstr "Le clic du milieu ne colle plus ailleurs. Dès la prochaine connexion."
|
||||||
|
|
||||||
|
msgid "Cover new applications"
|
||||||
|
msgstr "Couvrir les nouvelles applications"
|
||||||
|
|
||||||
|
msgid "Applications installed later get autoscroll on their own."
|
||||||
|
msgstr ""
|
||||||
|
"Les applications installées plus tard reçoivent l'autoscroll d'elles-mêmes."
|
||||||
|
|
||||||
|
msgid "More Chromium arguments"
|
||||||
|
msgstr "Autres arguments Chromium"
|
||||||
|
|
||||||
|
msgid "Passed to every application along with the autoscroll one."
|
||||||
|
msgstr "Transmis à chaque application avec celui de l'autoscroll."
|
||||||
|
|
||||||
|
msgid "Up/Down: select, Space: change, q: back"
|
||||||
|
msgstr "Haut/Bas : choisir, Espace : changer, q : retour"
|
||||||
|
|
||||||
|
msgid "Arguments separated by spaces, empty for none:"
|
||||||
|
msgstr "Arguments séparés par des espaces, vide pour aucun :"
|
||||||
|
|
||||||
|
msgid "Could not save the setting."
|
||||||
|
msgstr "Impossible d'enregistrer le paramètre."
|
||||||
|
|
||||||
|
#. Applications screen
|
||||||
|
msgid "Looking at the installed applications..."
|
||||||
|
msgstr "Examen des applications installées..."
|
||||||
|
|
||||||
|
msgid "No Chromium-based applications found."
|
||||||
|
msgstr "Aucune application basée sur Chromium trouvée."
|
||||||
|
|
||||||
|
msgid "Anything marked \"cannot tell\" stays off until it is turned on here."
|
||||||
|
msgstr ""
|
||||||
|
"Ce qui est marqué « indéterminé » reste désactivé jusqu'à être activé ici."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off. This is what would be covered."
|
||||||
|
msgstr "L'autoscroll est désactivé. Voici ce qui serait couvert."
|
||||||
|
|
||||||
|
msgid "Up/Down: select, Space: turn on or off, q: back"
|
||||||
|
msgstr "Haut/Bas : choisir, Espace : activer ou désactiver, q : retour"
|
||||||
|
|
||||||
|
msgid "Search:"
|
||||||
|
msgstr "Rechercher :"
|
||||||
|
|
||||||
|
msgid "Type to search, Down: go to the list, Esc: back"
|
||||||
|
msgstr "Tapez pour rechercher, Bas : aller à la liste, Échap : retour"
|
||||||
|
|
||||||
|
msgid "No matches."
|
||||||
|
msgstr "Aucun résultat."
|
||||||
|
|
||||||
|
#. Results
|
||||||
|
msgid "Autoscroll is on for %d applications."
|
||||||
|
msgstr "L'autoscroll est activé pour %d applications."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Applications that are already running pick this up when they are restarted."
|
||||||
|
msgstr ""
|
||||||
|
"Les applications déjà ouvertes le prennent en compte après un redémarrage."
|
||||||
|
|
||||||
|
msgid "Could not start the watcher for newly installed applications."
|
||||||
|
msgstr "Impossible de démarrer la surveillance des nouvelles applications."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"No systemd user session, so newly installed applications will not be picked "
|
||||||
|
"up on their own."
|
||||||
|
msgstr ""
|
||||||
|
"Pas de session utilisateur systemd, les nouvelles applications ne seront "
|
||||||
|
"donc pas prises en charge d'elles-mêmes."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off and everything that was changed has been put back."
|
||||||
|
msgstr ""
|
||||||
|
"L'autoscroll est désactivé et tout ce qui avait été modifié a été rétabli."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off. Turn it on first."
|
||||||
|
msgstr "L'autoscroll est désactivé. Activez-le d'abord."
|
||||||
|
|
||||||
|
msgid "Applied again to %d applications."
|
||||||
|
msgstr "Réappliqué à %d applications."
|
||||||
|
|
||||||
|
msgid "Applied to %d applications."
|
||||||
|
msgstr "Appliqué à %d applications."
|
||||||
|
|
||||||
|
msgid "Already applied to %d applications."
|
||||||
|
msgstr "Déjà appliqué à %d applications."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Steam starts its interface in a way this version cannot change without Steam "
|
||||||
|
"noticing; leaving it alone."
|
||||||
|
msgstr ""
|
||||||
|
"Steam lance son interface d'une façon que cette version ne peut pas modifier "
|
||||||
|
"sans que Steam le remarque ; Steam reste tel quel."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Steam's interface cannot be given the flag without leaving a file Steam "
|
||||||
|
"would reinstall; the change has been taken back."
|
||||||
|
msgstr ""
|
||||||
|
"L'interface de Steam ne peut pas recevoir le flag sans laisser un fichier "
|
||||||
|
"que Steam réinstallerait ; la modification a été annulée."
|
||||||
|
|
||||||
|
msgid "Middle click stops pasting at the next login."
|
||||||
|
msgstr "Le clic du milieu ne collera plus à la prochaine connexion."
|
||||||
|
|
||||||
|
#. Help
|
||||||
|
msgid "Usage: middleclick-autoscroll [command]"
|
||||||
|
msgstr "Utilisation : middleclick-autoscroll [commande]"
|
||||||
|
|
||||||
|
msgid "Commands:"
|
||||||
|
msgstr "Commandes :"
|
||||||
|
|
||||||
|
msgid "Turn autoscroll on"
|
||||||
|
msgstr "Activer l'autoscroll"
|
||||||
|
|
||||||
|
msgid "Turn it off and put everything back"
|
||||||
|
msgstr "Le désactiver et tout rétablir"
|
||||||
|
|
||||||
|
msgid "Apply to anything installed since the last run"
|
||||||
|
msgstr "Appliquer à tout ce qui a été installé depuis le dernier passage"
|
||||||
|
|
||||||
|
msgid "Take everything back and apply it again"
|
||||||
|
msgstr "Tout annuler et réappliquer"
|
||||||
|
|
||||||
|
msgid "Show what is covered"
|
||||||
|
msgstr "Afficher ce qui est couvert"
|
||||||
|
|
||||||
|
msgid "List every application that was found"
|
||||||
|
msgstr "Lister toutes les applications trouvées"
|
||||||
|
|
||||||
|
msgid "Show this help"
|
||||||
|
msgstr "Afficher cette aide"
|
||||||
|
|
||||||
|
msgid "Show the version"
|
||||||
|
msgstr "Afficher la version"
|
||||||
|
|
||||||
|
msgid "Without a command an interactive menu is shown."
|
||||||
|
msgstr "Sans commande, un menu interactif s'affiche."
|
||||||
|
|
||||||
|
msgid "Unknown command: %s"
|
||||||
|
msgstr "Commande inconnue : %s"
|
||||||
|
|
||||||
|
#. Time
|
||||||
|
msgid "never"
|
||||||
|
msgstr "jamais"
|
||||||
|
|
||||||
|
msgid "just now"
|
||||||
|
msgstr "à l'instant"
|
||||||
|
|
||||||
|
msgid "1 minute ago"
|
||||||
|
msgstr "il y a 1 minute"
|
||||||
|
|
||||||
|
msgid "%d minutes ago"
|
||||||
|
msgstr "il y a %d minutes"
|
||||||
|
|
||||||
|
msgid "1 hour ago"
|
||||||
|
msgstr "il y a 1 heure"
|
||||||
|
|
||||||
|
msgid "%d hours ago"
|
||||||
|
msgstr "il y a %d heures"
|
||||||
|
|
||||||
|
msgid "1 day ago"
|
||||||
|
msgstr "il y a 1 jour"
|
||||||
|
|
||||||
|
msgid "%d days ago"
|
||||||
|
msgstr "il y a %d jours"
|
||||||
@@ -0,0 +1,269 @@
|
|||||||
|
# Italian translation for middleclick-autoscroll.
|
||||||
|
# Machine translated. Corrections are welcome.
|
||||||
|
# Copyright (C) 2026 Felitendo
|
||||||
|
# This file is distributed under the same license as middleclick-autoscroll.
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: middleclick-autoscroll 1.6.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: https://github.com/LoonixTools/middleclick-autoscroll/"
|
||||||
|
"issues\n"
|
||||||
|
"POT-Creation-Date: 2026-09-24 00:00+0200\n"
|
||||||
|
"PO-Revision-Date: 2026-09-24 00:00+0200\n"
|
||||||
|
"Last-Translator: machine translation\n"
|
||||||
|
"Language-Team: Italian\n"
|
||||||
|
"Language: it\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
|
#. Status labels
|
||||||
|
msgid "ON"
|
||||||
|
msgstr "ACCESO"
|
||||||
|
|
||||||
|
msgid "OFF"
|
||||||
|
msgstr "SPENTO"
|
||||||
|
|
||||||
|
msgid "on"
|
||||||
|
msgstr "acceso"
|
||||||
|
|
||||||
|
msgid "off"
|
||||||
|
msgstr "spento"
|
||||||
|
|
||||||
|
msgid "(none)"
|
||||||
|
msgstr "(nessuno)"
|
||||||
|
|
||||||
|
msgid "flag file"
|
||||||
|
msgstr "file di flag"
|
||||||
|
|
||||||
|
msgid "launcher"
|
||||||
|
msgstr "lanciatore"
|
||||||
|
|
||||||
|
msgid "cannot tell"
|
||||||
|
msgstr "incerto"
|
||||||
|
|
||||||
|
msgid "not patched yet"
|
||||||
|
msgstr "non ancora applicato"
|
||||||
|
|
||||||
|
#. Status block
|
||||||
|
msgid "Autoscroll"
|
||||||
|
msgstr "Autoscroll"
|
||||||
|
|
||||||
|
msgid "Applications covered"
|
||||||
|
msgstr "Applicazioni coperte"
|
||||||
|
|
||||||
|
msgid "%d of %d"
|
||||||
|
msgstr "%d di %d"
|
||||||
|
|
||||||
|
msgid "Not identified"
|
||||||
|
msgstr "Non identificate"
|
||||||
|
|
||||||
|
msgid "%d (see the applications list)"
|
||||||
|
msgstr "%d (vedi l'elenco delle applicazioni)"
|
||||||
|
|
||||||
|
msgid "Steam"
|
||||||
|
msgstr "Steam"
|
||||||
|
|
||||||
|
msgid "Middle-click paste"
|
||||||
|
msgstr "Incolla con clic centrale"
|
||||||
|
|
||||||
|
msgid "New applications"
|
||||||
|
msgstr "Nuove applicazioni"
|
||||||
|
|
||||||
|
msgid "Last applied"
|
||||||
|
msgstr "Applicato l'ultima volta"
|
||||||
|
|
||||||
|
msgid "Applications pick this up the next time they are started."
|
||||||
|
msgstr "Le applicazioni lo recepiscono al prossimo avvio."
|
||||||
|
|
||||||
|
#. Menu
|
||||||
|
msgid "Turn autoscroll on or off"
|
||||||
|
msgstr "Accendi o spegni l'autoscroll"
|
||||||
|
|
||||||
|
msgid "Re-apply everything"
|
||||||
|
msgstr "Riapplica tutto"
|
||||||
|
|
||||||
|
msgid "Applications"
|
||||||
|
msgstr "Applicazioni"
|
||||||
|
|
||||||
|
msgid "Settings"
|
||||||
|
msgstr "Impostazioni"
|
||||||
|
|
||||||
|
msgid "Quit"
|
||||||
|
msgstr "Esci"
|
||||||
|
|
||||||
|
msgid "Press any key to continue..."
|
||||||
|
msgstr "Premi un tasto per continuare..."
|
||||||
|
|
||||||
|
msgid "One moment..."
|
||||||
|
msgstr "Un momento..."
|
||||||
|
|
||||||
|
#. Settings
|
||||||
|
msgid "Turn off middle-click paste"
|
||||||
|
msgstr "Disattiva incolla con clic centrale"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Stops middle click from pasting anywhere else. Starts with the next login."
|
||||||
|
msgstr ""
|
||||||
|
"Il clic centrale non incolla più da nessun'altra parte. Dal prossimo accesso."
|
||||||
|
|
||||||
|
msgid "Cover new applications"
|
||||||
|
msgstr "Copri le nuove applicazioni"
|
||||||
|
|
||||||
|
msgid "Applications installed later get autoscroll on their own."
|
||||||
|
msgstr "Le applicazioni installate in seguito ricevono l'autoscroll da sole."
|
||||||
|
|
||||||
|
msgid "More Chromium arguments"
|
||||||
|
msgstr "Altri argomenti di Chromium"
|
||||||
|
|
||||||
|
msgid "Passed to every application along with the autoscroll one."
|
||||||
|
msgstr "Passati a ogni applicazione insieme a quello per l'autoscroll."
|
||||||
|
|
||||||
|
msgid "Up/Down: select, Space: change, q: back"
|
||||||
|
msgstr "Su/Giù: scegli, Spazio: cambia, q: indietro"
|
||||||
|
|
||||||
|
msgid "Arguments separated by spaces, empty for none:"
|
||||||
|
msgstr "Argomenti separati da spazi, vuoto per nessuno:"
|
||||||
|
|
||||||
|
msgid "Could not save the setting."
|
||||||
|
msgstr "Impossibile salvare l'impostazione."
|
||||||
|
|
||||||
|
#. Applications screen
|
||||||
|
msgid "Looking at the installed applications..."
|
||||||
|
msgstr "Esame delle applicazioni installate..."
|
||||||
|
|
||||||
|
msgid "No Chromium-based applications found."
|
||||||
|
msgstr "Nessuna applicazione basata su Chromium trovata."
|
||||||
|
|
||||||
|
msgid "Anything marked \"cannot tell\" stays off until it is turned on here."
|
||||||
|
msgstr ""
|
||||||
|
"Ciò che è segnato come «incerto» resta spento finché non viene acceso qui."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off. This is what would be covered."
|
||||||
|
msgstr "L'autoscroll è spento. Ecco cosa verrebbe coperto."
|
||||||
|
|
||||||
|
msgid "Up/Down: select, Space: turn on or off, q: back"
|
||||||
|
msgstr "Su/Giù: scegli, Spazio: accendi o spegni, q: indietro"
|
||||||
|
|
||||||
|
msgid "Search:"
|
||||||
|
msgstr "Cerca:"
|
||||||
|
|
||||||
|
msgid "Type to search, Down: go to the list, Esc: back"
|
||||||
|
msgstr "Scrivi per cercare, Giù: vai all'elenco, Esc: indietro"
|
||||||
|
|
||||||
|
msgid "No matches."
|
||||||
|
msgstr "Nessun risultato."
|
||||||
|
|
||||||
|
#. Results
|
||||||
|
msgid "Autoscroll is on for %d applications."
|
||||||
|
msgstr "L'autoscroll è acceso per %d applicazioni."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Applications that are already running pick this up when they are restarted."
|
||||||
|
msgstr "Le applicazioni già aperte lo recepiscono dopo un riavvio."
|
||||||
|
|
||||||
|
msgid "Could not start the watcher for newly installed applications."
|
||||||
|
msgstr "Impossibile avviare il controllo delle nuove applicazioni."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"No systemd user session, so newly installed applications will not be picked "
|
||||||
|
"up on their own."
|
||||||
|
msgstr ""
|
||||||
|
"Nessuna sessione utente di systemd, quindi le nuove applicazioni non "
|
||||||
|
"verranno rilevate da sole."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off and everything that was changed has been put back."
|
||||||
|
msgstr ""
|
||||||
|
"L'autoscroll è spento e tutto ciò che era stato modificato è stato "
|
||||||
|
"ripristinato."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off. Turn it on first."
|
||||||
|
msgstr "L'autoscroll è spento. Prima accendilo."
|
||||||
|
|
||||||
|
msgid "Applied again to %d applications."
|
||||||
|
msgstr "Riapplicato a %d applicazioni."
|
||||||
|
|
||||||
|
msgid "Applied to %d applications."
|
||||||
|
msgstr "Applicato a %d applicazioni."
|
||||||
|
|
||||||
|
msgid "Already applied to %d applications."
|
||||||
|
msgstr "Già applicato a %d applicazioni."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Steam starts its interface in a way this version cannot change without Steam "
|
||||||
|
"noticing; leaving it alone."
|
||||||
|
msgstr ""
|
||||||
|
"Steam avvia la sua interfaccia in un modo che questa versione non può "
|
||||||
|
"cambiare senza che Steam se ne accorga; Steam resta com'è."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Steam's interface cannot be given the flag without leaving a file Steam "
|
||||||
|
"would reinstall; the change has been taken back."
|
||||||
|
msgstr ""
|
||||||
|
"All'interfaccia di Steam non si può dare il flag senza lasciare un file che "
|
||||||
|
"Steam reinstallerebbe; la modifica è stata annullata."
|
||||||
|
|
||||||
|
msgid "Middle click stops pasting at the next login."
|
||||||
|
msgstr "Il clic centrale smetterà di incollare al prossimo accesso."
|
||||||
|
|
||||||
|
#. Help
|
||||||
|
msgid "Usage: middleclick-autoscroll [command]"
|
||||||
|
msgstr "Uso: middleclick-autoscroll [comando]"
|
||||||
|
|
||||||
|
msgid "Commands:"
|
||||||
|
msgstr "Comandi:"
|
||||||
|
|
||||||
|
msgid "Turn autoscroll on"
|
||||||
|
msgstr "Accendi l'autoscroll"
|
||||||
|
|
||||||
|
msgid "Turn it off and put everything back"
|
||||||
|
msgstr "Spegnilo e ripristina tutto"
|
||||||
|
|
||||||
|
msgid "Apply to anything installed since the last run"
|
||||||
|
msgstr "Applica a tutto ciò che è stato installato dall'ultima volta"
|
||||||
|
|
||||||
|
msgid "Take everything back and apply it again"
|
||||||
|
msgstr "Annulla tutto e riapplica"
|
||||||
|
|
||||||
|
msgid "Show what is covered"
|
||||||
|
msgstr "Mostra cosa è coperto"
|
||||||
|
|
||||||
|
msgid "List every application that was found"
|
||||||
|
msgstr "Elenca tutte le applicazioni trovate"
|
||||||
|
|
||||||
|
msgid "Show this help"
|
||||||
|
msgstr "Mostra questo aiuto"
|
||||||
|
|
||||||
|
msgid "Show the version"
|
||||||
|
msgstr "Mostra la versione"
|
||||||
|
|
||||||
|
msgid "Without a command an interactive menu is shown."
|
||||||
|
msgstr "Senza comando viene mostrato un menu interattivo."
|
||||||
|
|
||||||
|
msgid "Unknown command: %s"
|
||||||
|
msgstr "Comando sconosciuto: %s"
|
||||||
|
|
||||||
|
#. Time
|
||||||
|
msgid "never"
|
||||||
|
msgstr "mai"
|
||||||
|
|
||||||
|
msgid "just now"
|
||||||
|
msgstr "proprio ora"
|
||||||
|
|
||||||
|
msgid "1 minute ago"
|
||||||
|
msgstr "1 minuto fa"
|
||||||
|
|
||||||
|
msgid "%d minutes ago"
|
||||||
|
msgstr "%d minuti fa"
|
||||||
|
|
||||||
|
msgid "1 hour ago"
|
||||||
|
msgstr "1 ora fa"
|
||||||
|
|
||||||
|
msgid "%d hours ago"
|
||||||
|
msgstr "%d ore fa"
|
||||||
|
|
||||||
|
msgid "1 day ago"
|
||||||
|
msgstr "1 giorno fa"
|
||||||
|
|
||||||
|
msgid "%d days ago"
|
||||||
|
msgstr "%d giorni fa"
|
||||||
@@ -4,9 +4,10 @@
|
|||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: middleclick-autoscroll 1.0.1\n"
|
"Project-Id-Version: middleclick-autoscroll 1.6.0\n"
|
||||||
"Report-Msgid-Bugs-To: https://github.com/Felitendo/middleclick-autoscroll/issues\n"
|
"Report-Msgid-Bugs-To: https://github.com/LoonixTools/middleclick-autoscroll/"
|
||||||
"POT-Creation-Date: 2026-08-16 00:00+0200\n"
|
"issues\n"
|
||||||
|
"POT-Creation-Date: 2026-09-24 00:00+0200\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@@ -43,7 +44,6 @@ msgstr ""
|
|||||||
msgid "not patched yet"
|
msgid "not patched yet"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
||||||
#. Status block
|
#. Status block
|
||||||
msgid "Autoscroll"
|
msgid "Autoscroll"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -57,12 +57,15 @@ msgstr ""
|
|||||||
msgid "Not identified"
|
msgid "Not identified"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "%d - see the applications list"
|
msgid "%d (see the applications list)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Steam"
|
msgid "Steam"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Middle-click paste"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "New applications"
|
msgid "New applications"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -72,12 +75,11 @@ msgstr ""
|
|||||||
msgid "Applications pick this up the next time they are started."
|
msgid "Applications pick this up the next time they are started."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
||||||
#. Menu
|
#. Menu
|
||||||
msgid "Turn autoscroll on or off"
|
msgid "Turn autoscroll on or off"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Apply now"
|
msgid "Re-apply everything"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Applications"
|
msgid "Applications"
|
||||||
@@ -92,30 +94,30 @@ msgstr ""
|
|||||||
msgid "Press any key to continue..."
|
msgid "Press any key to continue..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "One moment..."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. Settings
|
#. Settings
|
||||||
msgid "Electron and CEF applications"
|
msgid "Turn off middle-click paste"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Chromium-based browsers"
|
msgid ""
|
||||||
|
"Stops middle click from pasting anywhere else. Starts with the next login."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Flatpak applications"
|
msgid "Cover new applications"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Programs that start themselves at login"
|
msgid "Applications installed later get autoscroll on their own."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Spotify"
|
msgid "More Chromium arguments"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Apply to newly installed applications"
|
msgid "Passed to every application along with the autoscroll one."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Additional Chromium arguments"
|
msgid "Up/Down: select, Space: change, q: back"
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Up/Down select - Space or Right changes - q goes back"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Arguments separated by spaces, empty for none:"
|
msgid "Arguments separated by spaces, empty for none:"
|
||||||
@@ -124,7 +126,6 @@ msgstr ""
|
|||||||
msgid "Could not save the setting."
|
msgid "Could not save the setting."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
||||||
#. Applications screen
|
#. Applications screen
|
||||||
msgid "Looking at the installed applications..."
|
msgid "Looking at the installed applications..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -132,30 +133,38 @@ msgstr ""
|
|||||||
msgid "No Chromium-based applications found."
|
msgid "No Chromium-based applications found."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Anything not identified is left alone until it is turned on here."
|
msgid "Anything marked \"cannot tell\" stays off until it is turned on here."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Autoscroll is off - this is what would be covered."
|
msgid "Autoscroll is off. This is what would be covered."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Up/Down select - Space turns one on or off - q goes back"
|
msgid "Up/Down: select, Space: turn on or off, q: back"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Search:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Type to search, Down: go to the list, Esc: back"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "No matches."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. Results
|
#. Results
|
||||||
msgid "Autoscroll is on for %d applications."
|
msgid "Autoscroll is on for %d applications."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Applications that are already running pick this up when they are restarted."
|
msgid ""
|
||||||
msgstr ""
|
"Applications that are already running pick this up when they are restarted."
|
||||||
|
|
||||||
msgid "Steam's launcher now skips its file check, which is what keeps the change from being undone at every start."
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Could not start the watcher for newly installed applications."
|
msgid "Could not start the watcher for newly installed applications."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "No systemd user session - newly installed applications will not be picked up on their own."
|
msgid ""
|
||||||
|
"No systemd user session, so newly installed applications will not be picked "
|
||||||
|
"up on their own."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Autoscroll is off and everything that was changed has been put back."
|
msgid "Autoscroll is off and everything that was changed has been put back."
|
||||||
@@ -164,15 +173,27 @@ msgstr ""
|
|||||||
msgid "Autoscroll is off. Turn it on first."
|
msgid "Autoscroll is off. Turn it on first."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Applied again to %d applications."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Applied to %d applications."
|
msgid "Applied to %d applications."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Already applied to %d applications."
|
msgid "Already applied to %d applications."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Steam starts its interface in a way this version does not recognise; leaving it alone."
|
msgid ""
|
||||||
|
"Steam starts its interface in a way this version cannot change without Steam "
|
||||||
|
"noticing; leaving it alone."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Steam's interface cannot be given the flag without leaving a file Steam "
|
||||||
|
"would reinstall; the change has been taken back."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Middle click stops pasting at the next login."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. Help
|
#. Help
|
||||||
msgid "Usage: middleclick-autoscroll [command]"
|
msgid "Usage: middleclick-autoscroll [command]"
|
||||||
@@ -190,6 +211,9 @@ msgstr ""
|
|||||||
msgid "Apply to anything installed since the last run"
|
msgid "Apply to anything installed since the last run"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Take everything back and apply it again"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Show what is covered"
|
msgid "Show what is covered"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -208,7 +232,6 @@ msgstr ""
|
|||||||
msgid "Unknown command: %s"
|
msgid "Unknown command: %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
||||||
#. Time
|
#. Time
|
||||||
msgid "never"
|
msgid "never"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -216,11 +239,20 @@ msgstr ""
|
|||||||
msgid "just now"
|
msgid "just now"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "1 minute ago"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "%d minutes ago"
|
msgid "%d minutes ago"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "1 hour ago"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "%d hours ago"
|
msgid "%d hours ago"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "1 day ago"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "%d days ago"
|
msgid "%d days ago"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -0,0 +1,267 @@
|
|||||||
|
# Dutch translation for middleclick-autoscroll.
|
||||||
|
# Machine translated. Corrections are welcome.
|
||||||
|
# Copyright (C) 2026 Felitendo
|
||||||
|
# This file is distributed under the same license as middleclick-autoscroll.
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: middleclick-autoscroll 1.6.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: https://github.com/LoonixTools/middleclick-autoscroll/"
|
||||||
|
"issues\n"
|
||||||
|
"POT-Creation-Date: 2026-09-24 00:00+0200\n"
|
||||||
|
"PO-Revision-Date: 2026-09-24 00:00+0200\n"
|
||||||
|
"Last-Translator: machine translation\n"
|
||||||
|
"Language-Team: Dutch\n"
|
||||||
|
"Language: nl\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
|
#. Status labels
|
||||||
|
msgid "ON"
|
||||||
|
msgstr "AAN"
|
||||||
|
|
||||||
|
msgid "OFF"
|
||||||
|
msgstr "UIT"
|
||||||
|
|
||||||
|
msgid "on"
|
||||||
|
msgstr "aan"
|
||||||
|
|
||||||
|
msgid "off"
|
||||||
|
msgstr "uit"
|
||||||
|
|
||||||
|
msgid "(none)"
|
||||||
|
msgstr "(geen)"
|
||||||
|
|
||||||
|
msgid "flag file"
|
||||||
|
msgstr "flagbestand"
|
||||||
|
|
||||||
|
msgid "launcher"
|
||||||
|
msgstr "starter"
|
||||||
|
|
||||||
|
msgid "cannot tell"
|
||||||
|
msgstr "onbekend"
|
||||||
|
|
||||||
|
msgid "not patched yet"
|
||||||
|
msgstr "nog niet toegepast"
|
||||||
|
|
||||||
|
#. Status block
|
||||||
|
msgid "Autoscroll"
|
||||||
|
msgstr "Autoscroll"
|
||||||
|
|
||||||
|
msgid "Applications covered"
|
||||||
|
msgstr "Gedekte toepassingen"
|
||||||
|
|
||||||
|
msgid "%d of %d"
|
||||||
|
msgstr "%d van %d"
|
||||||
|
|
||||||
|
msgid "Not identified"
|
||||||
|
msgstr "Niet herkend"
|
||||||
|
|
||||||
|
msgid "%d (see the applications list)"
|
||||||
|
msgstr "%d (zie de lijst met toepassingen)"
|
||||||
|
|
||||||
|
msgid "Steam"
|
||||||
|
msgstr "Steam"
|
||||||
|
|
||||||
|
msgid "Middle-click paste"
|
||||||
|
msgstr "Plakken met middelklik"
|
||||||
|
|
||||||
|
msgid "New applications"
|
||||||
|
msgstr "Nieuwe toepassingen"
|
||||||
|
|
||||||
|
msgid "Last applied"
|
||||||
|
msgstr "Laatst toegepast"
|
||||||
|
|
||||||
|
msgid "Applications pick this up the next time they are started."
|
||||||
|
msgstr "Toepassingen nemen dit over bij de volgende start."
|
||||||
|
|
||||||
|
#. Menu
|
||||||
|
msgid "Turn autoscroll on or off"
|
||||||
|
msgstr "Autoscroll aan- of uitzetten"
|
||||||
|
|
||||||
|
msgid "Re-apply everything"
|
||||||
|
msgstr "Alles opnieuw toepassen"
|
||||||
|
|
||||||
|
msgid "Applications"
|
||||||
|
msgstr "Toepassingen"
|
||||||
|
|
||||||
|
msgid "Settings"
|
||||||
|
msgstr "Instellingen"
|
||||||
|
|
||||||
|
msgid "Quit"
|
||||||
|
msgstr "Afsluiten"
|
||||||
|
|
||||||
|
msgid "Press any key to continue..."
|
||||||
|
msgstr "Druk op een toets om door te gaan..."
|
||||||
|
|
||||||
|
msgid "One moment..."
|
||||||
|
msgstr "Een moment..."
|
||||||
|
|
||||||
|
#. Settings
|
||||||
|
msgid "Turn off middle-click paste"
|
||||||
|
msgstr "Plakken met middelklik uitzetten"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Stops middle click from pasting anywhere else. Starts with the next login."
|
||||||
|
msgstr ""
|
||||||
|
"Middelklik plakt dan nergens anders meer. Vanaf de volgende aanmelding."
|
||||||
|
|
||||||
|
msgid "Cover new applications"
|
||||||
|
msgstr "Nieuwe toepassingen meenemen"
|
||||||
|
|
||||||
|
msgid "Applications installed later get autoscroll on their own."
|
||||||
|
msgstr "Later geïnstalleerde toepassingen krijgen vanzelf autoscroll."
|
||||||
|
|
||||||
|
msgid "More Chromium arguments"
|
||||||
|
msgstr "Meer Chromium-argumenten"
|
||||||
|
|
||||||
|
msgid "Passed to every application along with the autoscroll one."
|
||||||
|
msgstr "Gaan samen met dat voor autoscroll naar elke toepassing."
|
||||||
|
|
||||||
|
msgid "Up/Down: select, Space: change, q: back"
|
||||||
|
msgstr "Omhoog/Omlaag: kiezen, Spatie: wijzigen, q: terug"
|
||||||
|
|
||||||
|
msgid "Arguments separated by spaces, empty for none:"
|
||||||
|
msgstr "Argumenten gescheiden door spaties, leeg voor geen:"
|
||||||
|
|
||||||
|
msgid "Could not save the setting."
|
||||||
|
msgstr "De instelling kon niet worden opgeslagen."
|
||||||
|
|
||||||
|
#. Applications screen
|
||||||
|
msgid "Looking at the installed applications..."
|
||||||
|
msgstr "Geïnstalleerde toepassingen worden bekeken..."
|
||||||
|
|
||||||
|
msgid "No Chromium-based applications found."
|
||||||
|
msgstr "Geen op Chromium gebaseerde toepassingen gevonden."
|
||||||
|
|
||||||
|
msgid "Anything marked \"cannot tell\" stays off until it is turned on here."
|
||||||
|
msgstr ""
|
||||||
|
"Wat als \"onbekend\" gemarkeerd is, blijft uit tot het hier aangezet wordt."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off. This is what would be covered."
|
||||||
|
msgstr "Autoscroll staat uit. Dit zou gedekt worden."
|
||||||
|
|
||||||
|
msgid "Up/Down: select, Space: turn on or off, q: back"
|
||||||
|
msgstr "Omhoog/Omlaag: kiezen, Spatie: aan- of uitzetten, q: terug"
|
||||||
|
|
||||||
|
msgid "Search:"
|
||||||
|
msgstr "Zoeken:"
|
||||||
|
|
||||||
|
msgid "Type to search, Down: go to the list, Esc: back"
|
||||||
|
msgstr "Typ om te zoeken, Omlaag: naar de lijst, Esc: terug"
|
||||||
|
|
||||||
|
msgid "No matches."
|
||||||
|
msgstr "Geen resultaten."
|
||||||
|
|
||||||
|
#. Results
|
||||||
|
msgid "Autoscroll is on for %d applications."
|
||||||
|
msgstr "Autoscroll staat aan voor %d toepassingen."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Applications that are already running pick this up when they are restarted."
|
||||||
|
msgstr "Toepassingen die al draaien, nemen dit over na een herstart."
|
||||||
|
|
||||||
|
msgid "Could not start the watcher for newly installed applications."
|
||||||
|
msgstr "Kon het bewaken van nieuwe toepassingen niet starten."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"No systemd user session, so newly installed applications will not be picked "
|
||||||
|
"up on their own."
|
||||||
|
msgstr ""
|
||||||
|
"Geen systemd-gebruikerssessie, dus nieuw geïnstalleerde toepassingen worden "
|
||||||
|
"niet vanzelf opgepikt."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off and everything that was changed has been put back."
|
||||||
|
msgstr "Autoscroll staat uit en alles wat veranderd was, is teruggezet."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off. Turn it on first."
|
||||||
|
msgstr "Autoscroll staat uit. Zet het eerst aan."
|
||||||
|
|
||||||
|
msgid "Applied again to %d applications."
|
||||||
|
msgstr "Opnieuw toegepast op %d toepassingen."
|
||||||
|
|
||||||
|
msgid "Applied to %d applications."
|
||||||
|
msgstr "Toegepast op %d toepassingen."
|
||||||
|
|
||||||
|
msgid "Already applied to %d applications."
|
||||||
|
msgstr "Al toegepast op %d toepassingen."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Steam starts its interface in a way this version cannot change without Steam "
|
||||||
|
"noticing; leaving it alone."
|
||||||
|
msgstr ""
|
||||||
|
"Steam start zijn interface op een manier die deze versie niet kan veranderen "
|
||||||
|
"zonder dat Steam het merkt; Steam blijft zoals het is."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Steam's interface cannot be given the flag without leaving a file Steam "
|
||||||
|
"would reinstall; the change has been taken back."
|
||||||
|
msgstr ""
|
||||||
|
"De interface van Steam kan de flag niet krijgen zonder een bestand achter te "
|
||||||
|
"laten dat Steam opnieuw zou installeren; de wijziging is teruggedraaid."
|
||||||
|
|
||||||
|
msgid "Middle click stops pasting at the next login."
|
||||||
|
msgstr "Middelklik plakt vanaf de volgende aanmelding niet meer."
|
||||||
|
|
||||||
|
#. Help
|
||||||
|
msgid "Usage: middleclick-autoscroll [command]"
|
||||||
|
msgstr "Gebruik: middleclick-autoscroll [opdracht]"
|
||||||
|
|
||||||
|
msgid "Commands:"
|
||||||
|
msgstr "Opdrachten:"
|
||||||
|
|
||||||
|
msgid "Turn autoscroll on"
|
||||||
|
msgstr "Autoscroll aanzetten"
|
||||||
|
|
||||||
|
msgid "Turn it off and put everything back"
|
||||||
|
msgstr "Uitzetten en alles terugzetten"
|
||||||
|
|
||||||
|
msgid "Apply to anything installed since the last run"
|
||||||
|
msgstr "Toepassen op alles wat sinds de vorige keer geïnstalleerd is"
|
||||||
|
|
||||||
|
msgid "Take everything back and apply it again"
|
||||||
|
msgstr "Alles terugdraaien en opnieuw toepassen"
|
||||||
|
|
||||||
|
msgid "Show what is covered"
|
||||||
|
msgstr "Tonen wat gedekt is"
|
||||||
|
|
||||||
|
msgid "List every application that was found"
|
||||||
|
msgstr "Alle gevonden toepassingen tonen"
|
||||||
|
|
||||||
|
msgid "Show this help"
|
||||||
|
msgstr "Deze hulp tonen"
|
||||||
|
|
||||||
|
msgid "Show the version"
|
||||||
|
msgstr "De versie tonen"
|
||||||
|
|
||||||
|
msgid "Without a command an interactive menu is shown."
|
||||||
|
msgstr "Zonder opdracht wordt een interactief menu getoond."
|
||||||
|
|
||||||
|
msgid "Unknown command: %s"
|
||||||
|
msgstr "Onbekende opdracht: %s"
|
||||||
|
|
||||||
|
#. Time
|
||||||
|
msgid "never"
|
||||||
|
msgstr "nooit"
|
||||||
|
|
||||||
|
msgid "just now"
|
||||||
|
msgstr "zojuist"
|
||||||
|
|
||||||
|
msgid "1 minute ago"
|
||||||
|
msgstr "1 minuut geleden"
|
||||||
|
|
||||||
|
msgid "%d minutes ago"
|
||||||
|
msgstr "%d minuten geleden"
|
||||||
|
|
||||||
|
msgid "1 hour ago"
|
||||||
|
msgstr "1 uur geleden"
|
||||||
|
|
||||||
|
msgid "%d hours ago"
|
||||||
|
msgstr "%d uur geleden"
|
||||||
|
|
||||||
|
msgid "1 day ago"
|
||||||
|
msgstr "1 dag geleden"
|
||||||
|
|
||||||
|
msgid "%d days ago"
|
||||||
|
msgstr "%d dagen geleden"
|
||||||
@@ -0,0 +1,266 @@
|
|||||||
|
# Polish translation for middleclick-autoscroll.
|
||||||
|
# Machine translated. Corrections are welcome.
|
||||||
|
# Copyright (C) 2026 Felitendo
|
||||||
|
# This file is distributed under the same license as middleclick-autoscroll.
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: middleclick-autoscroll 1.6.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: https://github.com/LoonixTools/middleclick-autoscroll/"
|
||||||
|
"issues\n"
|
||||||
|
"POT-Creation-Date: 2026-09-24 00:00+0200\n"
|
||||||
|
"PO-Revision-Date: 2026-09-24 00:00+0200\n"
|
||||||
|
"Last-Translator: machine translation\n"
|
||||||
|
"Language-Team: Polish\n"
|
||||||
|
"Language: pl\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
|
#. Status labels
|
||||||
|
msgid "ON"
|
||||||
|
msgstr "WŁ."
|
||||||
|
|
||||||
|
msgid "OFF"
|
||||||
|
msgstr "WYŁ."
|
||||||
|
|
||||||
|
msgid "on"
|
||||||
|
msgstr "wł."
|
||||||
|
|
||||||
|
msgid "off"
|
||||||
|
msgstr "wył."
|
||||||
|
|
||||||
|
msgid "(none)"
|
||||||
|
msgstr "(brak)"
|
||||||
|
|
||||||
|
msgid "flag file"
|
||||||
|
msgstr "plik flag"
|
||||||
|
|
||||||
|
msgid "launcher"
|
||||||
|
msgstr "skrót"
|
||||||
|
|
||||||
|
msgid "cannot tell"
|
||||||
|
msgstr "nie wiadomo"
|
||||||
|
|
||||||
|
msgid "not patched yet"
|
||||||
|
msgstr "jeszcze nie zastosowano"
|
||||||
|
|
||||||
|
#. Status block
|
||||||
|
msgid "Autoscroll"
|
||||||
|
msgstr "Autoscroll"
|
||||||
|
|
||||||
|
msgid "Applications covered"
|
||||||
|
msgstr "Objęte aplikacje"
|
||||||
|
|
||||||
|
msgid "%d of %d"
|
||||||
|
msgstr "%d z %d"
|
||||||
|
|
||||||
|
msgid "Not identified"
|
||||||
|
msgstr "Nierozpoznane"
|
||||||
|
|
||||||
|
msgid "%d (see the applications list)"
|
||||||
|
msgstr "%d (zob. listę aplikacji)"
|
||||||
|
|
||||||
|
msgid "Steam"
|
||||||
|
msgstr "Steam"
|
||||||
|
|
||||||
|
msgid "Middle-click paste"
|
||||||
|
msgstr "Wklejanie kółkiem myszy"
|
||||||
|
|
||||||
|
msgid "New applications"
|
||||||
|
msgstr "Nowe aplikacje"
|
||||||
|
|
||||||
|
msgid "Last applied"
|
||||||
|
msgstr "Ostatnio zastosowano"
|
||||||
|
|
||||||
|
msgid "Applications pick this up the next time they are started."
|
||||||
|
msgstr "Aplikacje przejmą to przy następnym uruchomieniu."
|
||||||
|
|
||||||
|
#. Menu
|
||||||
|
msgid "Turn autoscroll on or off"
|
||||||
|
msgstr "Włącz lub wyłącz autoscroll"
|
||||||
|
|
||||||
|
msgid "Re-apply everything"
|
||||||
|
msgstr "Zastosuj wszystko ponownie"
|
||||||
|
|
||||||
|
msgid "Applications"
|
||||||
|
msgstr "Aplikacje"
|
||||||
|
|
||||||
|
msgid "Settings"
|
||||||
|
msgstr "Ustawienia"
|
||||||
|
|
||||||
|
msgid "Quit"
|
||||||
|
msgstr "Zakończ"
|
||||||
|
|
||||||
|
msgid "Press any key to continue..."
|
||||||
|
msgstr "Naciśnij dowolny klawisz, aby kontynuować..."
|
||||||
|
|
||||||
|
msgid "One moment..."
|
||||||
|
msgstr "Chwileczkę..."
|
||||||
|
|
||||||
|
#. Settings
|
||||||
|
msgid "Turn off middle-click paste"
|
||||||
|
msgstr "Wyłącz wklejanie kółkiem myszy"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Stops middle click from pasting anywhere else. Starts with the next login."
|
||||||
|
msgstr "Kółko myszy nie wkleja już nigdzie indziej. Od następnego logowania."
|
||||||
|
|
||||||
|
msgid "Cover new applications"
|
||||||
|
msgstr "Obejmuj nowe aplikacje"
|
||||||
|
|
||||||
|
msgid "Applications installed later get autoscroll on their own."
|
||||||
|
msgstr "Aplikacje zainstalowane później same dostaną autoscroll."
|
||||||
|
|
||||||
|
msgid "More Chromium arguments"
|
||||||
|
msgstr "Więcej argumentów Chromium"
|
||||||
|
|
||||||
|
msgid "Passed to every application along with the autoscroll one."
|
||||||
|
msgstr "Przekazywane każdej aplikacji razem z tym od autoscrolla."
|
||||||
|
|
||||||
|
msgid "Up/Down: select, Space: change, q: back"
|
||||||
|
msgstr "Góra/Dół: wybierz, Spacja: zmień, q: wstecz"
|
||||||
|
|
||||||
|
msgid "Arguments separated by spaces, empty for none:"
|
||||||
|
msgstr "Argumenty oddzielone spacjami, puste oznacza brak:"
|
||||||
|
|
||||||
|
msgid "Could not save the setting."
|
||||||
|
msgstr "Nie udało się zapisać ustawienia."
|
||||||
|
|
||||||
|
#. Applications screen
|
||||||
|
msgid "Looking at the installed applications..."
|
||||||
|
msgstr "Przeglądanie zainstalowanych aplikacji..."
|
||||||
|
|
||||||
|
msgid "No Chromium-based applications found."
|
||||||
|
msgstr "Nie znaleziono aplikacji opartych na Chromium."
|
||||||
|
|
||||||
|
msgid "Anything marked \"cannot tell\" stays off until it is turned on here."
|
||||||
|
msgstr ""
|
||||||
|
"Pozycje „nie wiadomo” zostają wyłączone, dopóki nie włączysz ich tutaj."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off. This is what would be covered."
|
||||||
|
msgstr "Autoscroll jest wyłączony. Tyle zostałoby objęte."
|
||||||
|
|
||||||
|
msgid "Up/Down: select, Space: turn on or off, q: back"
|
||||||
|
msgstr "Góra/Dół: wybierz, Spacja: włącz lub wyłącz, q: wstecz"
|
||||||
|
|
||||||
|
msgid "Search:"
|
||||||
|
msgstr "Szukaj:"
|
||||||
|
|
||||||
|
msgid "Type to search, Down: go to the list, Esc: back"
|
||||||
|
msgstr "Pisz, aby szukać, Dół: do listy, Esc: wstecz"
|
||||||
|
|
||||||
|
msgid "No matches."
|
||||||
|
msgstr "Brak wyników."
|
||||||
|
|
||||||
|
#. Results
|
||||||
|
msgid "Autoscroll is on for %d applications."
|
||||||
|
msgstr "Autoscroll włączony dla %d aplikacji."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Applications that are already running pick this up when they are restarted."
|
||||||
|
msgstr "Uruchomione już aplikacje przejmą to po ponownym uruchomieniu."
|
||||||
|
|
||||||
|
msgid "Could not start the watcher for newly installed applications."
|
||||||
|
msgstr "Nie udało się uruchomić obserwowania nowych aplikacji."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"No systemd user session, so newly installed applications will not be picked "
|
||||||
|
"up on their own."
|
||||||
|
msgstr ""
|
||||||
|
"Brak sesji użytkownika systemd, więc nowo zainstalowane aplikacje nie "
|
||||||
|
"zostaną wykryte same."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off and everything that was changed has been put back."
|
||||||
|
msgstr "Autoscroll jest wyłączony, a wszystkie zmiany zostały cofnięte."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off. Turn it on first."
|
||||||
|
msgstr "Autoscroll jest wyłączony. Najpierw go włącz."
|
||||||
|
|
||||||
|
msgid "Applied again to %d applications."
|
||||||
|
msgstr "Ponownie zastosowano dla %d aplikacji."
|
||||||
|
|
||||||
|
msgid "Applied to %d applications."
|
||||||
|
msgstr "Zastosowano dla %d aplikacji."
|
||||||
|
|
||||||
|
msgid "Already applied to %d applications."
|
||||||
|
msgstr "Już zastosowano dla %d aplikacji."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Steam starts its interface in a way this version cannot change without Steam "
|
||||||
|
"noticing; leaving it alone."
|
||||||
|
msgstr ""
|
||||||
|
"Steam uruchamia swój interfejs w sposób, którego ta wersja nie może zmienić "
|
||||||
|
"bez wiedzy Steama; Steam pozostaje bez zmian."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Steam's interface cannot be given the flag without leaving a file Steam "
|
||||||
|
"would reinstall; the change has been taken back."
|
||||||
|
msgstr ""
|
||||||
|
"Interfejsowi Steama nie można dodać flagi bez zostawienia pliku, który Steam "
|
||||||
|
"zainstalowałby ponownie; zmiana została cofnięta."
|
||||||
|
|
||||||
|
msgid "Middle click stops pasting at the next login."
|
||||||
|
msgstr "Kółko myszy przestanie wklejać od następnego logowania."
|
||||||
|
|
||||||
|
#. Help
|
||||||
|
msgid "Usage: middleclick-autoscroll [command]"
|
||||||
|
msgstr "Użycie: middleclick-autoscroll [polecenie]"
|
||||||
|
|
||||||
|
msgid "Commands:"
|
||||||
|
msgstr "Polecenia:"
|
||||||
|
|
||||||
|
msgid "Turn autoscroll on"
|
||||||
|
msgstr "Włącz autoscroll"
|
||||||
|
|
||||||
|
msgid "Turn it off and put everything back"
|
||||||
|
msgstr "Wyłącz i cofnij wszystko"
|
||||||
|
|
||||||
|
msgid "Apply to anything installed since the last run"
|
||||||
|
msgstr "Zastosuj do wszystkiego zainstalowanego od ostatniego razu"
|
||||||
|
|
||||||
|
msgid "Take everything back and apply it again"
|
||||||
|
msgstr "Cofnij wszystko i zastosuj ponownie"
|
||||||
|
|
||||||
|
msgid "Show what is covered"
|
||||||
|
msgstr "Pokaż, co jest objęte"
|
||||||
|
|
||||||
|
msgid "List every application that was found"
|
||||||
|
msgstr "Wypisz wszystkie znalezione aplikacje"
|
||||||
|
|
||||||
|
msgid "Show this help"
|
||||||
|
msgstr "Pokaż tę pomoc"
|
||||||
|
|
||||||
|
msgid "Show the version"
|
||||||
|
msgstr "Pokaż wersję"
|
||||||
|
|
||||||
|
msgid "Without a command an interactive menu is shown."
|
||||||
|
msgstr "Bez polecenia wyświetlane jest menu interaktywne."
|
||||||
|
|
||||||
|
msgid "Unknown command: %s"
|
||||||
|
msgstr "Nieznane polecenie: %s"
|
||||||
|
|
||||||
|
#. Time
|
||||||
|
msgid "never"
|
||||||
|
msgstr "nigdy"
|
||||||
|
|
||||||
|
msgid "just now"
|
||||||
|
msgstr "przed chwilą"
|
||||||
|
|
||||||
|
msgid "1 minute ago"
|
||||||
|
msgstr "1 minutę temu"
|
||||||
|
|
||||||
|
msgid "%d minutes ago"
|
||||||
|
msgstr "%d min temu"
|
||||||
|
|
||||||
|
msgid "1 hour ago"
|
||||||
|
msgstr "1 godzinę temu"
|
||||||
|
|
||||||
|
msgid "%d hours ago"
|
||||||
|
msgstr "%d godz. temu"
|
||||||
|
|
||||||
|
msgid "1 day ago"
|
||||||
|
msgstr "1 dzień temu"
|
||||||
|
|
||||||
|
msgid "%d days ago"
|
||||||
|
msgstr "%d dni temu"
|
||||||
+268
@@ -0,0 +1,268 @@
|
|||||||
|
# Brazilian Portuguese translation for middleclick-autoscroll.
|
||||||
|
# Machine translated. Corrections are welcome.
|
||||||
|
# Copyright (C) 2026 Felitendo
|
||||||
|
# This file is distributed under the same license as middleclick-autoscroll.
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: middleclick-autoscroll 1.6.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: https://github.com/LoonixTools/middleclick-autoscroll/"
|
||||||
|
"issues\n"
|
||||||
|
"POT-Creation-Date: 2026-09-24 00:00+0200\n"
|
||||||
|
"PO-Revision-Date: 2026-09-24 00:00+0200\n"
|
||||||
|
"Last-Translator: machine translation\n"
|
||||||
|
"Language-Team: Brazilian Portuguese\n"
|
||||||
|
"Language: pt_BR\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
|
#. Status labels
|
||||||
|
msgid "ON"
|
||||||
|
msgstr "LIGADO"
|
||||||
|
|
||||||
|
msgid "OFF"
|
||||||
|
msgstr "DESLIGADO"
|
||||||
|
|
||||||
|
msgid "on"
|
||||||
|
msgstr "ligado"
|
||||||
|
|
||||||
|
msgid "off"
|
||||||
|
msgstr "desligado"
|
||||||
|
|
||||||
|
msgid "(none)"
|
||||||
|
msgstr "(nenhum)"
|
||||||
|
|
||||||
|
msgid "flag file"
|
||||||
|
msgstr "arquivo de flags"
|
||||||
|
|
||||||
|
msgid "launcher"
|
||||||
|
msgstr "lançador"
|
||||||
|
|
||||||
|
msgid "cannot tell"
|
||||||
|
msgstr "indeterminado"
|
||||||
|
|
||||||
|
msgid "not patched yet"
|
||||||
|
msgstr "ainda não aplicado"
|
||||||
|
|
||||||
|
#. Status block
|
||||||
|
msgid "Autoscroll"
|
||||||
|
msgstr "Autoscroll"
|
||||||
|
|
||||||
|
msgid "Applications covered"
|
||||||
|
msgstr "Aplicativos cobertos"
|
||||||
|
|
||||||
|
msgid "%d of %d"
|
||||||
|
msgstr "%d de %d"
|
||||||
|
|
||||||
|
msgid "Not identified"
|
||||||
|
msgstr "Não identificados"
|
||||||
|
|
||||||
|
msgid "%d (see the applications list)"
|
||||||
|
msgstr "%d (veja a lista de aplicativos)"
|
||||||
|
|
||||||
|
msgid "Steam"
|
||||||
|
msgstr "Steam"
|
||||||
|
|
||||||
|
msgid "Middle-click paste"
|
||||||
|
msgstr "Colar com clique do meio"
|
||||||
|
|
||||||
|
msgid "New applications"
|
||||||
|
msgstr "Novos aplicativos"
|
||||||
|
|
||||||
|
msgid "Last applied"
|
||||||
|
msgstr "Aplicado pela última vez"
|
||||||
|
|
||||||
|
msgid "Applications pick this up the next time they are started."
|
||||||
|
msgstr "Os aplicativos passam a usar isso na próxima vez que forem abertos."
|
||||||
|
|
||||||
|
#. Menu
|
||||||
|
msgid "Turn autoscroll on or off"
|
||||||
|
msgstr "Ligar ou desligar o autoscroll"
|
||||||
|
|
||||||
|
msgid "Re-apply everything"
|
||||||
|
msgstr "Aplicar tudo de novo"
|
||||||
|
|
||||||
|
msgid "Applications"
|
||||||
|
msgstr "Aplicativos"
|
||||||
|
|
||||||
|
msgid "Settings"
|
||||||
|
msgstr "Configurações"
|
||||||
|
|
||||||
|
msgid "Quit"
|
||||||
|
msgstr "Sair"
|
||||||
|
|
||||||
|
msgid "Press any key to continue..."
|
||||||
|
msgstr "Pressione qualquer tecla para continuar..."
|
||||||
|
|
||||||
|
msgid "One moment..."
|
||||||
|
msgstr "Um momento..."
|
||||||
|
|
||||||
|
#. Settings
|
||||||
|
msgid "Turn off middle-click paste"
|
||||||
|
msgstr "Desligar colar com clique do meio"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Stops middle click from pasting anywhere else. Starts with the next login."
|
||||||
|
msgstr ""
|
||||||
|
"O clique do meio para de colar em outros lugares. A partir do próximo login."
|
||||||
|
|
||||||
|
msgid "Cover new applications"
|
||||||
|
msgstr "Cobrir novos aplicativos"
|
||||||
|
|
||||||
|
msgid "Applications installed later get autoscroll on their own."
|
||||||
|
msgstr "Aplicativos instalados depois recebem o autoscroll sozinhos."
|
||||||
|
|
||||||
|
msgid "More Chromium arguments"
|
||||||
|
msgstr "Mais argumentos do Chromium"
|
||||||
|
|
||||||
|
msgid "Passed to every application along with the autoscroll one."
|
||||||
|
msgstr "Passados a todo aplicativo junto com o do autoscroll."
|
||||||
|
|
||||||
|
msgid "Up/Down: select, Space: change, q: back"
|
||||||
|
msgstr "Cima/Baixo: escolher, Espaço: mudar, q: voltar"
|
||||||
|
|
||||||
|
msgid "Arguments separated by spaces, empty for none:"
|
||||||
|
msgstr "Argumentos separados por espaços, vazio para nenhum:"
|
||||||
|
|
||||||
|
msgid "Could not save the setting."
|
||||||
|
msgstr "Não foi possível salvar a configuração."
|
||||||
|
|
||||||
|
#. Applications screen
|
||||||
|
msgid "Looking at the installed applications..."
|
||||||
|
msgstr "Verificando os aplicativos instalados..."
|
||||||
|
|
||||||
|
msgid "No Chromium-based applications found."
|
||||||
|
msgstr "Nenhum aplicativo baseado em Chromium encontrado."
|
||||||
|
|
||||||
|
msgid "Anything marked \"cannot tell\" stays off until it is turned on here."
|
||||||
|
msgstr ""
|
||||||
|
"O que está marcado como \"indeterminado\" fica desligado até ser ligado aqui."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off. This is what would be covered."
|
||||||
|
msgstr "O autoscroll está desligado. Isto é o que seria coberto."
|
||||||
|
|
||||||
|
msgid "Up/Down: select, Space: turn on or off, q: back"
|
||||||
|
msgstr "Cima/Baixo: escolher, Espaço: ligar ou desligar, q: voltar"
|
||||||
|
|
||||||
|
msgid "Search:"
|
||||||
|
msgstr "Buscar:"
|
||||||
|
|
||||||
|
msgid "Type to search, Down: go to the list, Esc: back"
|
||||||
|
msgstr "Digite para buscar, Baixo: ir para a lista, Esc: voltar"
|
||||||
|
|
||||||
|
msgid "No matches."
|
||||||
|
msgstr "Nenhum resultado."
|
||||||
|
|
||||||
|
#. Results
|
||||||
|
msgid "Autoscroll is on for %d applications."
|
||||||
|
msgstr "O autoscroll está ligado para %d aplicativos."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Applications that are already running pick this up when they are restarted."
|
||||||
|
msgstr ""
|
||||||
|
"Aplicativos que já estão abertos passam a usar isso ao serem reiniciados."
|
||||||
|
|
||||||
|
msgid "Could not start the watcher for newly installed applications."
|
||||||
|
msgstr "Não foi possível iniciar o monitoramento de novos aplicativos."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"No systemd user session, so newly installed applications will not be picked "
|
||||||
|
"up on their own."
|
||||||
|
msgstr ""
|
||||||
|
"Sem sessão de usuário do systemd, então novos aplicativos não serão "
|
||||||
|
"detectados sozinhos."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off and everything that was changed has been put back."
|
||||||
|
msgstr "O autoscroll está desligado e tudo o que foi alterado foi restaurado."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off. Turn it on first."
|
||||||
|
msgstr "O autoscroll está desligado. Ligue-o primeiro."
|
||||||
|
|
||||||
|
msgid "Applied again to %d applications."
|
||||||
|
msgstr "Aplicado de novo a %d aplicativos."
|
||||||
|
|
||||||
|
msgid "Applied to %d applications."
|
||||||
|
msgstr "Aplicado a %d aplicativos."
|
||||||
|
|
||||||
|
msgid "Already applied to %d applications."
|
||||||
|
msgstr "Já aplicado a %d aplicativos."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Steam starts its interface in a way this version cannot change without Steam "
|
||||||
|
"noticing; leaving it alone."
|
||||||
|
msgstr ""
|
||||||
|
"O Steam inicia sua interface de um jeito que esta versão não consegue mudar "
|
||||||
|
"sem que o Steam perceba; ele fica como está."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Steam's interface cannot be given the flag without leaving a file Steam "
|
||||||
|
"would reinstall; the change has been taken back."
|
||||||
|
msgstr ""
|
||||||
|
"A interface do Steam não pode receber o flag sem deixar um arquivo que o "
|
||||||
|
"Steam reinstalaria; a alteração foi desfeita."
|
||||||
|
|
||||||
|
msgid "Middle click stops pasting at the next login."
|
||||||
|
msgstr "O clique do meio para de colar no próximo login."
|
||||||
|
|
||||||
|
#. Help
|
||||||
|
msgid "Usage: middleclick-autoscroll [command]"
|
||||||
|
msgstr "Uso: middleclick-autoscroll [comando]"
|
||||||
|
|
||||||
|
msgid "Commands:"
|
||||||
|
msgstr "Comandos:"
|
||||||
|
|
||||||
|
msgid "Turn autoscroll on"
|
||||||
|
msgstr "Ligar o autoscroll"
|
||||||
|
|
||||||
|
msgid "Turn it off and put everything back"
|
||||||
|
msgstr "Desligar e restaurar tudo"
|
||||||
|
|
||||||
|
msgid "Apply to anything installed since the last run"
|
||||||
|
msgstr "Aplicar a tudo o que foi instalado desde a última vez"
|
||||||
|
|
||||||
|
msgid "Take everything back and apply it again"
|
||||||
|
msgstr "Desfazer tudo e aplicar de novo"
|
||||||
|
|
||||||
|
msgid "Show what is covered"
|
||||||
|
msgstr "Mostrar o que está coberto"
|
||||||
|
|
||||||
|
msgid "List every application that was found"
|
||||||
|
msgstr "Listar todos os aplicativos encontrados"
|
||||||
|
|
||||||
|
msgid "Show this help"
|
||||||
|
msgstr "Mostrar esta ajuda"
|
||||||
|
|
||||||
|
msgid "Show the version"
|
||||||
|
msgstr "Mostrar a versão"
|
||||||
|
|
||||||
|
msgid "Without a command an interactive menu is shown."
|
||||||
|
msgstr "Sem comando, um menu interativo é exibido."
|
||||||
|
|
||||||
|
msgid "Unknown command: %s"
|
||||||
|
msgstr "Comando desconhecido: %s"
|
||||||
|
|
||||||
|
#. Time
|
||||||
|
msgid "never"
|
||||||
|
msgstr "nunca"
|
||||||
|
|
||||||
|
msgid "just now"
|
||||||
|
msgstr "agora mesmo"
|
||||||
|
|
||||||
|
msgid "1 minute ago"
|
||||||
|
msgstr "há 1 minuto"
|
||||||
|
|
||||||
|
msgid "%d minutes ago"
|
||||||
|
msgstr "há %d minutos"
|
||||||
|
|
||||||
|
msgid "1 hour ago"
|
||||||
|
msgstr "há 1 hora"
|
||||||
|
|
||||||
|
msgid "%d hours ago"
|
||||||
|
msgstr "há %d horas"
|
||||||
|
|
||||||
|
msgid "1 day ago"
|
||||||
|
msgstr "há 1 dia"
|
||||||
|
|
||||||
|
msgid "%d days ago"
|
||||||
|
msgstr "há %d dias"
|
||||||
@@ -0,0 +1,267 @@
|
|||||||
|
# Russian translation for middleclick-autoscroll.
|
||||||
|
# Machine translated. Corrections are welcome.
|
||||||
|
# Copyright (C) 2026 Felitendo
|
||||||
|
# This file is distributed under the same license as middleclick-autoscroll.
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: middleclick-autoscroll 1.6.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: https://github.com/LoonixTools/middleclick-autoscroll/"
|
||||||
|
"issues\n"
|
||||||
|
"POT-Creation-Date: 2026-09-24 00:00+0200\n"
|
||||||
|
"PO-Revision-Date: 2026-09-24 00:00+0200\n"
|
||||||
|
"Last-Translator: machine translation\n"
|
||||||
|
"Language-Team: Russian\n"
|
||||||
|
"Language: ru\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
|
#. Status labels
|
||||||
|
msgid "ON"
|
||||||
|
msgstr "ВКЛ"
|
||||||
|
|
||||||
|
msgid "OFF"
|
||||||
|
msgstr "ВЫКЛ"
|
||||||
|
|
||||||
|
msgid "on"
|
||||||
|
msgstr "вкл"
|
||||||
|
|
||||||
|
msgid "off"
|
||||||
|
msgstr "выкл"
|
||||||
|
|
||||||
|
msgid "(none)"
|
||||||
|
msgstr "(нет)"
|
||||||
|
|
||||||
|
msgid "flag file"
|
||||||
|
msgstr "файл флагов"
|
||||||
|
|
||||||
|
msgid "launcher"
|
||||||
|
msgstr "ярлык"
|
||||||
|
|
||||||
|
msgid "cannot tell"
|
||||||
|
msgstr "неизвестно"
|
||||||
|
|
||||||
|
msgid "not patched yet"
|
||||||
|
msgstr "ещё не применено"
|
||||||
|
|
||||||
|
#. Status block
|
||||||
|
msgid "Autoscroll"
|
||||||
|
msgstr "Автопрокрутка"
|
||||||
|
|
||||||
|
msgid "Applications covered"
|
||||||
|
msgstr "Приложения с автопрокруткой"
|
||||||
|
|
||||||
|
msgid "%d of %d"
|
||||||
|
msgstr "%d из %d"
|
||||||
|
|
||||||
|
msgid "Not identified"
|
||||||
|
msgstr "Не распознано"
|
||||||
|
|
||||||
|
msgid "%d (see the applications list)"
|
||||||
|
msgstr "%d (см. список приложений)"
|
||||||
|
|
||||||
|
msgid "Steam"
|
||||||
|
msgstr "Steam"
|
||||||
|
|
||||||
|
msgid "Middle-click paste"
|
||||||
|
msgstr "Вставка средней кнопкой"
|
||||||
|
|
||||||
|
msgid "New applications"
|
||||||
|
msgstr "Новые приложения"
|
||||||
|
|
||||||
|
msgid "Last applied"
|
||||||
|
msgstr "Последнее применение"
|
||||||
|
|
||||||
|
msgid "Applications pick this up the next time they are started."
|
||||||
|
msgstr "Приложения подхватят это при следующем запуске."
|
||||||
|
|
||||||
|
#. Menu
|
||||||
|
msgid "Turn autoscroll on or off"
|
||||||
|
msgstr "Включить или выключить автопрокрутку"
|
||||||
|
|
||||||
|
msgid "Re-apply everything"
|
||||||
|
msgstr "Применить всё заново"
|
||||||
|
|
||||||
|
msgid "Applications"
|
||||||
|
msgstr "Приложения"
|
||||||
|
|
||||||
|
msgid "Settings"
|
||||||
|
msgstr "Настройки"
|
||||||
|
|
||||||
|
msgid "Quit"
|
||||||
|
msgstr "Выход"
|
||||||
|
|
||||||
|
msgid "Press any key to continue..."
|
||||||
|
msgstr "Нажмите любую клавишу..."
|
||||||
|
|
||||||
|
msgid "One moment..."
|
||||||
|
msgstr "Минутку..."
|
||||||
|
|
||||||
|
#. Settings
|
||||||
|
msgid "Turn off middle-click paste"
|
||||||
|
msgstr "Отключить вставку средней кнопкой"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Stops middle click from pasting anywhere else. Starts with the next login."
|
||||||
|
msgstr ""
|
||||||
|
"Средняя кнопка больше нигде не вставляет. Со следующего входа в систему."
|
||||||
|
|
||||||
|
msgid "Cover new applications"
|
||||||
|
msgstr "Охватывать новые приложения"
|
||||||
|
|
||||||
|
msgid "Applications installed later get autoscroll on their own."
|
||||||
|
msgstr "Приложения, установленные позже, получат автопрокрутку сами."
|
||||||
|
|
||||||
|
msgid "More Chromium arguments"
|
||||||
|
msgstr "Другие аргументы Chromium"
|
||||||
|
|
||||||
|
msgid "Passed to every application along with the autoscroll one."
|
||||||
|
msgstr "Передаются каждому приложению вместе с аргументом автопрокрутки."
|
||||||
|
|
||||||
|
msgid "Up/Down: select, Space: change, q: back"
|
||||||
|
msgstr "Вверх/Вниз: выбор, Пробел: изменить, q: назад"
|
||||||
|
|
||||||
|
msgid "Arguments separated by spaces, empty for none:"
|
||||||
|
msgstr "Аргументы через пробел (пусто, если не нужны):"
|
||||||
|
|
||||||
|
msgid "Could not save the setting."
|
||||||
|
msgstr "Не удалось сохранить настройку."
|
||||||
|
|
||||||
|
#. Applications screen
|
||||||
|
msgid "Looking at the installed applications..."
|
||||||
|
msgstr "Просмотр установленных приложений..."
|
||||||
|
|
||||||
|
msgid "No Chromium-based applications found."
|
||||||
|
msgstr "Приложения на основе Chromium не найдены."
|
||||||
|
|
||||||
|
msgid "Anything marked \"cannot tell\" stays off until it is turned on here."
|
||||||
|
msgstr ""
|
||||||
|
"Помеченное как «неизвестно» остаётся выключенным, пока его здесь не включат."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off. This is what would be covered."
|
||||||
|
msgstr "Автопрокрутка выключена. Вот что было бы охвачено."
|
||||||
|
|
||||||
|
msgid "Up/Down: select, Space: turn on or off, q: back"
|
||||||
|
msgstr "Вверх/Вниз: выбор, Пробел: включить или выключить, q: назад"
|
||||||
|
|
||||||
|
msgid "Search:"
|
||||||
|
msgstr "Поиск:"
|
||||||
|
|
||||||
|
msgid "Type to search, Down: go to the list, Esc: back"
|
||||||
|
msgstr "Печатайте для поиска, Вниз: к списку, Esc: назад"
|
||||||
|
|
||||||
|
msgid "No matches."
|
||||||
|
msgstr "Ничего не найдено."
|
||||||
|
|
||||||
|
#. Results
|
||||||
|
msgid "Autoscroll is on for %d applications."
|
||||||
|
msgstr "Автопрокрутка включена. Приложений: %d."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Applications that are already running pick this up when they are restarted."
|
||||||
|
msgstr "Уже запущенные приложения подхватят это после перезапуска."
|
||||||
|
|
||||||
|
msgid "Could not start the watcher for newly installed applications."
|
||||||
|
msgstr "Не удалось запустить отслеживание новых приложений."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"No systemd user session, so newly installed applications will not be picked "
|
||||||
|
"up on their own."
|
||||||
|
msgstr ""
|
||||||
|
"Нет пользовательского сеанса systemd, поэтому новые приложения не будут "
|
||||||
|
"подхвачены сами."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off and everything that was changed has been put back."
|
||||||
|
msgstr "Автопрокрутка выключена, все изменения отменены."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off. Turn it on first."
|
||||||
|
msgstr "Автопрокрутка выключена. Сначала включите её."
|
||||||
|
|
||||||
|
msgid "Applied again to %d applications."
|
||||||
|
msgstr "Применено заново. Приложений: %d."
|
||||||
|
|
||||||
|
msgid "Applied to %d applications."
|
||||||
|
msgstr "Применено. Приложений: %d."
|
||||||
|
|
||||||
|
msgid "Already applied to %d applications."
|
||||||
|
msgstr "Уже применено. Приложений: %d."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Steam starts its interface in a way this version cannot change without Steam "
|
||||||
|
"noticing; leaving it alone."
|
||||||
|
msgstr ""
|
||||||
|
"Steam запускает свой интерфейс так, что эта версия не может это изменить "
|
||||||
|
"незаметно для Steam; Steam остаётся без изменений."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Steam's interface cannot be given the flag without leaving a file Steam "
|
||||||
|
"would reinstall; the change has been taken back."
|
||||||
|
msgstr ""
|
||||||
|
"Интерфейсу Steam нельзя передать флаг, не оставив файл, который Steam "
|
||||||
|
"переустановил бы; изменение отменено."
|
||||||
|
|
||||||
|
msgid "Middle click stops pasting at the next login."
|
||||||
|
msgstr "Средняя кнопка перестанет вставлять со следующего входа в систему."
|
||||||
|
|
||||||
|
#. Help
|
||||||
|
msgid "Usage: middleclick-autoscroll [command]"
|
||||||
|
msgstr "Использование: middleclick-autoscroll [команда]"
|
||||||
|
|
||||||
|
msgid "Commands:"
|
||||||
|
msgstr "Команды:"
|
||||||
|
|
||||||
|
msgid "Turn autoscroll on"
|
||||||
|
msgstr "Включить автопрокрутку"
|
||||||
|
|
||||||
|
msgid "Turn it off and put everything back"
|
||||||
|
msgstr "Выключить и всё вернуть"
|
||||||
|
|
||||||
|
msgid "Apply to anything installed since the last run"
|
||||||
|
msgstr "Применить ко всему, что установлено с прошлого запуска"
|
||||||
|
|
||||||
|
msgid "Take everything back and apply it again"
|
||||||
|
msgstr "Всё отменить и применить заново"
|
||||||
|
|
||||||
|
msgid "Show what is covered"
|
||||||
|
msgstr "Показать, что охвачено"
|
||||||
|
|
||||||
|
msgid "List every application that was found"
|
||||||
|
msgstr "Показать все найденные приложения"
|
||||||
|
|
||||||
|
msgid "Show this help"
|
||||||
|
msgstr "Показать эту справку"
|
||||||
|
|
||||||
|
msgid "Show the version"
|
||||||
|
msgstr "Показать версию"
|
||||||
|
|
||||||
|
msgid "Without a command an interactive menu is shown."
|
||||||
|
msgstr "Без команды показывается интерактивное меню."
|
||||||
|
|
||||||
|
msgid "Unknown command: %s"
|
||||||
|
msgstr "Неизвестная команда: %s"
|
||||||
|
|
||||||
|
#. Time
|
||||||
|
msgid "never"
|
||||||
|
msgstr "никогда"
|
||||||
|
|
||||||
|
msgid "just now"
|
||||||
|
msgstr "только что"
|
||||||
|
|
||||||
|
msgid "1 minute ago"
|
||||||
|
msgstr "1 минуту назад"
|
||||||
|
|
||||||
|
msgid "%d minutes ago"
|
||||||
|
msgstr "%d мин. назад"
|
||||||
|
|
||||||
|
msgid "1 hour ago"
|
||||||
|
msgstr "1 час назад"
|
||||||
|
|
||||||
|
msgid "%d hours ago"
|
||||||
|
msgstr "%d ч назад"
|
||||||
|
|
||||||
|
msgid "1 day ago"
|
||||||
|
msgstr "1 день назад"
|
||||||
|
|
||||||
|
msgid "%d days ago"
|
||||||
|
msgstr "%d дн. назад"
|
||||||
@@ -0,0 +1,266 @@
|
|||||||
|
# Turkish translation for middleclick-autoscroll.
|
||||||
|
# Machine translated. Corrections are welcome.
|
||||||
|
# Copyright (C) 2026 Felitendo
|
||||||
|
# This file is distributed under the same license as middleclick-autoscroll.
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: middleclick-autoscroll 1.6.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: https://github.com/LoonixTools/middleclick-autoscroll/"
|
||||||
|
"issues\n"
|
||||||
|
"POT-Creation-Date: 2026-09-24 00:00+0200\n"
|
||||||
|
"PO-Revision-Date: 2026-09-24 00:00+0200\n"
|
||||||
|
"Last-Translator: machine translation\n"
|
||||||
|
"Language-Team: Turkish\n"
|
||||||
|
"Language: tr\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
|
#. Status labels
|
||||||
|
msgid "ON"
|
||||||
|
msgstr "AÇIK"
|
||||||
|
|
||||||
|
msgid "OFF"
|
||||||
|
msgstr "KAPALI"
|
||||||
|
|
||||||
|
msgid "on"
|
||||||
|
msgstr "açık"
|
||||||
|
|
||||||
|
msgid "off"
|
||||||
|
msgstr "kapalı"
|
||||||
|
|
||||||
|
msgid "(none)"
|
||||||
|
msgstr "(yok)"
|
||||||
|
|
||||||
|
msgid "flag file"
|
||||||
|
msgstr "bayrak dosyası"
|
||||||
|
|
||||||
|
msgid "launcher"
|
||||||
|
msgstr "başlatıcı"
|
||||||
|
|
||||||
|
msgid "cannot tell"
|
||||||
|
msgstr "belirsiz"
|
||||||
|
|
||||||
|
msgid "not patched yet"
|
||||||
|
msgstr "henüz uygulanmadı"
|
||||||
|
|
||||||
|
#. Status block
|
||||||
|
msgid "Autoscroll"
|
||||||
|
msgstr "Autoscroll"
|
||||||
|
|
||||||
|
msgid "Applications covered"
|
||||||
|
msgstr "Kapsanan uygulamalar"
|
||||||
|
|
||||||
|
msgid "%d of %d"
|
||||||
|
msgstr "%d / %d"
|
||||||
|
|
||||||
|
msgid "Not identified"
|
||||||
|
msgstr "Tanınmadı"
|
||||||
|
|
||||||
|
msgid "%d (see the applications list)"
|
||||||
|
msgstr "%d (uygulama listesine bakın)"
|
||||||
|
|
||||||
|
msgid "Steam"
|
||||||
|
msgstr "Steam"
|
||||||
|
|
||||||
|
msgid "Middle-click paste"
|
||||||
|
msgstr "Orta tıkla yapıştırma"
|
||||||
|
|
||||||
|
msgid "New applications"
|
||||||
|
msgstr "Yeni uygulamalar"
|
||||||
|
|
||||||
|
msgid "Last applied"
|
||||||
|
msgstr "Son uygulanma"
|
||||||
|
|
||||||
|
msgid "Applications pick this up the next time they are started."
|
||||||
|
msgstr "Uygulamalar bunu bir sonraki açılışta alır."
|
||||||
|
|
||||||
|
#. Menu
|
||||||
|
msgid "Turn autoscroll on or off"
|
||||||
|
msgstr "Autoscroll'u aç veya kapat"
|
||||||
|
|
||||||
|
msgid "Re-apply everything"
|
||||||
|
msgstr "Her şeyi yeniden uygula"
|
||||||
|
|
||||||
|
msgid "Applications"
|
||||||
|
msgstr "Uygulamalar"
|
||||||
|
|
||||||
|
msgid "Settings"
|
||||||
|
msgstr "Ayarlar"
|
||||||
|
|
||||||
|
msgid "Quit"
|
||||||
|
msgstr "Çık"
|
||||||
|
|
||||||
|
msgid "Press any key to continue..."
|
||||||
|
msgstr "Devam etmek için bir tuşa basın..."
|
||||||
|
|
||||||
|
msgid "One moment..."
|
||||||
|
msgstr "Bir dakika..."
|
||||||
|
|
||||||
|
#. Settings
|
||||||
|
msgid "Turn off middle-click paste"
|
||||||
|
msgstr "Orta tıkla yapıştırmayı kapat"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Stops middle click from pasting anywhere else. Starts with the next login."
|
||||||
|
msgstr ""
|
||||||
|
"Orta tık artık başka hiçbir yerde yapıştırmaz. Bir sonraki girişten itibaren."
|
||||||
|
|
||||||
|
msgid "Cover new applications"
|
||||||
|
msgstr "Yeni uygulamaları kapsa"
|
||||||
|
|
||||||
|
msgid "Applications installed later get autoscroll on their own."
|
||||||
|
msgstr "Sonradan kurulan uygulamalar Autoscroll'u kendiliğinden alır."
|
||||||
|
|
||||||
|
msgid "More Chromium arguments"
|
||||||
|
msgstr "Ek Chromium argümanları"
|
||||||
|
|
||||||
|
msgid "Passed to every application along with the autoscroll one."
|
||||||
|
msgstr "Autoscroll argümanıyla birlikte her uygulamaya verilir."
|
||||||
|
|
||||||
|
msgid "Up/Down: select, Space: change, q: back"
|
||||||
|
msgstr "Yukarı/Aşağı: seç, Boşluk: değiştir, q: geri"
|
||||||
|
|
||||||
|
msgid "Arguments separated by spaces, empty for none:"
|
||||||
|
msgstr "Boşlukla ayrılmış argümanlar, hiçbiri için boş bırakın:"
|
||||||
|
|
||||||
|
msgid "Could not save the setting."
|
||||||
|
msgstr "Ayar kaydedilemedi."
|
||||||
|
|
||||||
|
#. Applications screen
|
||||||
|
msgid "Looking at the installed applications..."
|
||||||
|
msgstr "Kurulu uygulamalara bakılıyor..."
|
||||||
|
|
||||||
|
msgid "No Chromium-based applications found."
|
||||||
|
msgstr "Chromium tabanlı uygulama bulunamadı."
|
||||||
|
|
||||||
|
msgid "Anything marked \"cannot tell\" stays off until it is turned on here."
|
||||||
|
msgstr "\"belirsiz\" olarak işaretlenenler burada açılana kadar kapalı kalır."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off. This is what would be covered."
|
||||||
|
msgstr "Autoscroll kapalı. Kapsanacak olanlar bunlar."
|
||||||
|
|
||||||
|
msgid "Up/Down: select, Space: turn on or off, q: back"
|
||||||
|
msgstr "Yukarı/Aşağı: seç, Boşluk: aç veya kapat, q: geri"
|
||||||
|
|
||||||
|
msgid "Search:"
|
||||||
|
msgstr "Ara:"
|
||||||
|
|
||||||
|
msgid "Type to search, Down: go to the list, Esc: back"
|
||||||
|
msgstr "Aramak için yazın, Aşağı: listeye git, Esc: geri"
|
||||||
|
|
||||||
|
msgid "No matches."
|
||||||
|
msgstr "Eşleşme yok."
|
||||||
|
|
||||||
|
#. Results
|
||||||
|
msgid "Autoscroll is on for %d applications."
|
||||||
|
msgstr "Autoscroll %d uygulama için açık."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Applications that are already running pick this up when they are restarted."
|
||||||
|
msgstr "Zaten çalışan uygulamalar bunu yeniden başlatıldıklarında alır."
|
||||||
|
|
||||||
|
msgid "Could not start the watcher for newly installed applications."
|
||||||
|
msgstr "Yeni uygulamaları izleme başlatılamadı."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"No systemd user session, so newly installed applications will not be picked "
|
||||||
|
"up on their own."
|
||||||
|
msgstr ""
|
||||||
|
"systemd kullanıcı oturumu yok, bu yüzden yeni kurulan uygulamalar "
|
||||||
|
"kendiliğinden algılanmayacak."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off and everything that was changed has been put back."
|
||||||
|
msgstr "Autoscroll kapalı ve değiştirilen her şey geri alındı."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off. Turn it on first."
|
||||||
|
msgstr "Autoscroll kapalı. Önce açın."
|
||||||
|
|
||||||
|
msgid "Applied again to %d applications."
|
||||||
|
msgstr "%d uygulamaya yeniden uygulandı."
|
||||||
|
|
||||||
|
msgid "Applied to %d applications."
|
||||||
|
msgstr "%d uygulamaya uygulandı."
|
||||||
|
|
||||||
|
msgid "Already applied to %d applications."
|
||||||
|
msgstr "Zaten %d uygulamaya uygulanmış."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Steam starts its interface in a way this version cannot change without Steam "
|
||||||
|
"noticing; leaving it alone."
|
||||||
|
msgstr ""
|
||||||
|
"Steam arayüzünü, bu sürümün Steam fark etmeden değiştiremeyeceği bir şekilde "
|
||||||
|
"başlatıyor; olduğu gibi bırakılıyor."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Steam's interface cannot be given the flag without leaving a file Steam "
|
||||||
|
"would reinstall; the change has been taken back."
|
||||||
|
msgstr ""
|
||||||
|
"Steam arayüzüne, Steam'in yeniden kuracağı bir dosya bırakmadan bayrak "
|
||||||
|
"verilemiyor; değişiklik geri alındı."
|
||||||
|
|
||||||
|
msgid "Middle click stops pasting at the next login."
|
||||||
|
msgstr "Orta tık bir sonraki girişte yapıştırmayı bırakır."
|
||||||
|
|
||||||
|
#. Help
|
||||||
|
msgid "Usage: middleclick-autoscroll [command]"
|
||||||
|
msgstr "Kullanım: middleclick-autoscroll [komut]"
|
||||||
|
|
||||||
|
msgid "Commands:"
|
||||||
|
msgstr "Komutlar:"
|
||||||
|
|
||||||
|
msgid "Turn autoscroll on"
|
||||||
|
msgstr "Autoscroll'u aç"
|
||||||
|
|
||||||
|
msgid "Turn it off and put everything back"
|
||||||
|
msgstr "Kapat ve her şeyi geri al"
|
||||||
|
|
||||||
|
msgid "Apply to anything installed since the last run"
|
||||||
|
msgstr "Son çalıştırmadan beri kurulan her şeye uygula"
|
||||||
|
|
||||||
|
msgid "Take everything back and apply it again"
|
||||||
|
msgstr "Her şeyi geri al ve yeniden uygula"
|
||||||
|
|
||||||
|
msgid "Show what is covered"
|
||||||
|
msgstr "Neyin kapsandığını göster"
|
||||||
|
|
||||||
|
msgid "List every application that was found"
|
||||||
|
msgstr "Bulunan tüm uygulamaları listele"
|
||||||
|
|
||||||
|
msgid "Show this help"
|
||||||
|
msgstr "Bu yardımı göster"
|
||||||
|
|
||||||
|
msgid "Show the version"
|
||||||
|
msgstr "Sürümü göster"
|
||||||
|
|
||||||
|
msgid "Without a command an interactive menu is shown."
|
||||||
|
msgstr "Komut verilmezse etkileşimli bir menü gösterilir."
|
||||||
|
|
||||||
|
msgid "Unknown command: %s"
|
||||||
|
msgstr "Bilinmeyen komut: %s"
|
||||||
|
|
||||||
|
#. Time
|
||||||
|
msgid "never"
|
||||||
|
msgstr "hiç"
|
||||||
|
|
||||||
|
msgid "just now"
|
||||||
|
msgstr "az önce"
|
||||||
|
|
||||||
|
msgid "1 minute ago"
|
||||||
|
msgstr "1 dakika önce"
|
||||||
|
|
||||||
|
msgid "%d minutes ago"
|
||||||
|
msgstr "%d dakika önce"
|
||||||
|
|
||||||
|
msgid "1 hour ago"
|
||||||
|
msgstr "1 saat önce"
|
||||||
|
|
||||||
|
msgid "%d hours ago"
|
||||||
|
msgstr "%d saat önce"
|
||||||
|
|
||||||
|
msgid "1 day ago"
|
||||||
|
msgstr "1 gün önce"
|
||||||
|
|
||||||
|
msgid "%d days ago"
|
||||||
|
msgstr "%d gün önce"
|
||||||
@@ -0,0 +1,266 @@
|
|||||||
|
# Ukrainian translation for middleclick-autoscroll.
|
||||||
|
# Machine translated. Corrections are welcome.
|
||||||
|
# Copyright (C) 2026 Felitendo
|
||||||
|
# This file is distributed under the same license as middleclick-autoscroll.
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: middleclick-autoscroll 1.6.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: https://github.com/LoonixTools/middleclick-autoscroll/"
|
||||||
|
"issues\n"
|
||||||
|
"POT-Creation-Date: 2026-09-24 00:00+0200\n"
|
||||||
|
"PO-Revision-Date: 2026-09-24 00:00+0200\n"
|
||||||
|
"Last-Translator: machine translation\n"
|
||||||
|
"Language-Team: Ukrainian\n"
|
||||||
|
"Language: uk\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
|
#. Status labels
|
||||||
|
msgid "ON"
|
||||||
|
msgstr "УВІМК"
|
||||||
|
|
||||||
|
msgid "OFF"
|
||||||
|
msgstr "ВИМК"
|
||||||
|
|
||||||
|
msgid "on"
|
||||||
|
msgstr "увімк"
|
||||||
|
|
||||||
|
msgid "off"
|
||||||
|
msgstr "вимк"
|
||||||
|
|
||||||
|
msgid "(none)"
|
||||||
|
msgstr "(немає)"
|
||||||
|
|
||||||
|
msgid "flag file"
|
||||||
|
msgstr "файл прапорців"
|
||||||
|
|
||||||
|
msgid "launcher"
|
||||||
|
msgstr "ярлик"
|
||||||
|
|
||||||
|
msgid "cannot tell"
|
||||||
|
msgstr "невідомо"
|
||||||
|
|
||||||
|
msgid "not patched yet"
|
||||||
|
msgstr "ще не застосовано"
|
||||||
|
|
||||||
|
#. Status block
|
||||||
|
msgid "Autoscroll"
|
||||||
|
msgstr "Автопрокручування"
|
||||||
|
|
||||||
|
msgid "Applications covered"
|
||||||
|
msgstr "Охоплені застосунки"
|
||||||
|
|
||||||
|
msgid "%d of %d"
|
||||||
|
msgstr "%d з %d"
|
||||||
|
|
||||||
|
msgid "Not identified"
|
||||||
|
msgstr "Не розпізнано"
|
||||||
|
|
||||||
|
msgid "%d (see the applications list)"
|
||||||
|
msgstr "%d (див. список застосунків)"
|
||||||
|
|
||||||
|
msgid "Steam"
|
||||||
|
msgstr "Steam"
|
||||||
|
|
||||||
|
msgid "Middle-click paste"
|
||||||
|
msgstr "Вставлення середньою кнопкою"
|
||||||
|
|
||||||
|
msgid "New applications"
|
||||||
|
msgstr "Нові застосунки"
|
||||||
|
|
||||||
|
msgid "Last applied"
|
||||||
|
msgstr "Востаннє застосовано"
|
||||||
|
|
||||||
|
msgid "Applications pick this up the next time they are started."
|
||||||
|
msgstr "Застосунки підхоплять це під час наступного запуску."
|
||||||
|
|
||||||
|
#. Menu
|
||||||
|
msgid "Turn autoscroll on or off"
|
||||||
|
msgstr "Увімкнути або вимкнути автопрокручування"
|
||||||
|
|
||||||
|
msgid "Re-apply everything"
|
||||||
|
msgstr "Застосувати все знову"
|
||||||
|
|
||||||
|
msgid "Applications"
|
||||||
|
msgstr "Застосунки"
|
||||||
|
|
||||||
|
msgid "Settings"
|
||||||
|
msgstr "Налаштування"
|
||||||
|
|
||||||
|
msgid "Quit"
|
||||||
|
msgstr "Вийти"
|
||||||
|
|
||||||
|
msgid "Press any key to continue..."
|
||||||
|
msgstr "Натисніть будь-яку клавішу..."
|
||||||
|
|
||||||
|
msgid "One moment..."
|
||||||
|
msgstr "Хвилинку..."
|
||||||
|
|
||||||
|
#. Settings
|
||||||
|
msgid "Turn off middle-click paste"
|
||||||
|
msgstr "Вимкнути вставлення середньою кнопкою"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Stops middle click from pasting anywhere else. Starts with the next login."
|
||||||
|
msgstr "Середня кнопка більше ніде не вставляє. З наступного входу в систему."
|
||||||
|
|
||||||
|
msgid "Cover new applications"
|
||||||
|
msgstr "Охоплювати нові застосунки"
|
||||||
|
|
||||||
|
msgid "Applications installed later get autoscroll on their own."
|
||||||
|
msgstr "Застосунки, встановлені пізніше, отримають автопрокручування самі."
|
||||||
|
|
||||||
|
msgid "More Chromium arguments"
|
||||||
|
msgstr "Інші аргументи Chromium"
|
||||||
|
|
||||||
|
msgid "Passed to every application along with the autoscroll one."
|
||||||
|
msgstr "Передаються кожному застосунку разом з аргументом автопрокручування."
|
||||||
|
|
||||||
|
msgid "Up/Down: select, Space: change, q: back"
|
||||||
|
msgstr "Вгору/Вниз: вибір, Пробіл: змінити, q: назад"
|
||||||
|
|
||||||
|
msgid "Arguments separated by spaces, empty for none:"
|
||||||
|
msgstr "Аргументи через пробіл (порожньо, якщо не потрібні):"
|
||||||
|
|
||||||
|
msgid "Could not save the setting."
|
||||||
|
msgstr "Не вдалося зберегти налаштування."
|
||||||
|
|
||||||
|
#. Applications screen
|
||||||
|
msgid "Looking at the installed applications..."
|
||||||
|
msgstr "Перегляд встановлених застосунків..."
|
||||||
|
|
||||||
|
msgid "No Chromium-based applications found."
|
||||||
|
msgstr "Застосунків на основі Chromium не знайдено."
|
||||||
|
|
||||||
|
msgid "Anything marked \"cannot tell\" stays off until it is turned on here."
|
||||||
|
msgstr ""
|
||||||
|
"Позначене як «невідомо» лишається вимкненим, доки його тут не увімкнуть."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off. This is what would be covered."
|
||||||
|
msgstr "Автопрокручування вимкнено. Ось що було б охоплено."
|
||||||
|
|
||||||
|
msgid "Up/Down: select, Space: turn on or off, q: back"
|
||||||
|
msgstr "Вгору/Вниз: вибір, Пробіл: увімкнути чи вимкнути, q: назад"
|
||||||
|
|
||||||
|
msgid "Search:"
|
||||||
|
msgstr "Пошук:"
|
||||||
|
|
||||||
|
msgid "Type to search, Down: go to the list, Esc: back"
|
||||||
|
msgstr "Друкуйте для пошуку, Вниз: до списку, Esc: назад"
|
||||||
|
|
||||||
|
msgid "No matches."
|
||||||
|
msgstr "Нічого не знайдено."
|
||||||
|
|
||||||
|
#. Results
|
||||||
|
msgid "Autoscroll is on for %d applications."
|
||||||
|
msgstr "Автопрокручування увімкнено. Застосунків: %d."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Applications that are already running pick this up when they are restarted."
|
||||||
|
msgstr "Уже запущені застосунки підхоплять це після перезапуску."
|
||||||
|
|
||||||
|
msgid "Could not start the watcher for newly installed applications."
|
||||||
|
msgstr "Не вдалося запустити стеження за новими застосунками."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"No systemd user session, so newly installed applications will not be picked "
|
||||||
|
"up on their own."
|
||||||
|
msgstr ""
|
||||||
|
"Немає користувацького сеансу systemd, тож нові застосунки не буде підхоплено "
|
||||||
|
"самостійно."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off and everything that was changed has been put back."
|
||||||
|
msgstr "Автопрокручування вимкнено, усі зміни скасовано."
|
||||||
|
|
||||||
|
msgid "Autoscroll is off. Turn it on first."
|
||||||
|
msgstr "Автопрокручування вимкнено. Спершу увімкніть його."
|
||||||
|
|
||||||
|
msgid "Applied again to %d applications."
|
||||||
|
msgstr "Застосовано знову. Застосунків: %d."
|
||||||
|
|
||||||
|
msgid "Applied to %d applications."
|
||||||
|
msgstr "Застосовано. Застосунків: %d."
|
||||||
|
|
||||||
|
msgid "Already applied to %d applications."
|
||||||
|
msgstr "Уже застосовано. Застосунків: %d."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Steam starts its interface in a way this version cannot change without Steam "
|
||||||
|
"noticing; leaving it alone."
|
||||||
|
msgstr ""
|
||||||
|
"Steam запускає свій інтерфейс так, що ця версія не може це змінити непомітно "
|
||||||
|
"для Steam; Steam лишається без змін."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Steam's interface cannot be given the flag without leaving a file Steam "
|
||||||
|
"would reinstall; the change has been taken back."
|
||||||
|
msgstr ""
|
||||||
|
"Інтерфейсу Steam не можна передати прапорець, не залишивши файл, який Steam "
|
||||||
|
"перевстановив би; зміну скасовано."
|
||||||
|
|
||||||
|
msgid "Middle click stops pasting at the next login."
|
||||||
|
msgstr "Середня кнопка перестане вставляти з наступного входу в систему."
|
||||||
|
|
||||||
|
#. Help
|
||||||
|
msgid "Usage: middleclick-autoscroll [command]"
|
||||||
|
msgstr "Використання: middleclick-autoscroll [команда]"
|
||||||
|
|
||||||
|
msgid "Commands:"
|
||||||
|
msgstr "Команди:"
|
||||||
|
|
||||||
|
msgid "Turn autoscroll on"
|
||||||
|
msgstr "Увімкнути автопрокручування"
|
||||||
|
|
||||||
|
msgid "Turn it off and put everything back"
|
||||||
|
msgstr "Вимкнути й усе повернути"
|
||||||
|
|
||||||
|
msgid "Apply to anything installed since the last run"
|
||||||
|
msgstr "Застосувати до всього, що встановлено з минулого запуску"
|
||||||
|
|
||||||
|
msgid "Take everything back and apply it again"
|
||||||
|
msgstr "Усе скасувати й застосувати знову"
|
||||||
|
|
||||||
|
msgid "Show what is covered"
|
||||||
|
msgstr "Показати, що охоплено"
|
||||||
|
|
||||||
|
msgid "List every application that was found"
|
||||||
|
msgstr "Показати всі знайдені застосунки"
|
||||||
|
|
||||||
|
msgid "Show this help"
|
||||||
|
msgstr "Показати цю довідку"
|
||||||
|
|
||||||
|
msgid "Show the version"
|
||||||
|
msgstr "Показати версію"
|
||||||
|
|
||||||
|
msgid "Without a command an interactive menu is shown."
|
||||||
|
msgstr "Без команди показується інтерактивне меню."
|
||||||
|
|
||||||
|
msgid "Unknown command: %s"
|
||||||
|
msgstr "Невідома команда: %s"
|
||||||
|
|
||||||
|
#. Time
|
||||||
|
msgid "never"
|
||||||
|
msgstr "ніколи"
|
||||||
|
|
||||||
|
msgid "just now"
|
||||||
|
msgstr "щойно"
|
||||||
|
|
||||||
|
msgid "1 minute ago"
|
||||||
|
msgstr "1 хвилину тому"
|
||||||
|
|
||||||
|
msgid "%d minutes ago"
|
||||||
|
msgstr "%d хв тому"
|
||||||
|
|
||||||
|
msgid "1 hour ago"
|
||||||
|
msgstr "1 годину тому"
|
||||||
|
|
||||||
|
msgid "%d hours ago"
|
||||||
|
msgstr "%d год тому"
|
||||||
|
|
||||||
|
msgid "1 day ago"
|
||||||
|
msgstr "1 день тому"
|
||||||
|
|
||||||
|
msgid "%d days ago"
|
||||||
|
msgstr "%d дн. тому"
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-8.7 17.8 437.4 437.4" width="512" height="512">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="shell" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#ffffff"/><stop offset="1" stop-color="#dfe7f0"/></linearGradient>
|
||||||
|
<linearGradient id="wheel" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#5fd0ff"/><stop offset="1" stop-color="#0c62a0"/></linearGradient>
|
||||||
|
<radialGradient id="glow" cx=".5" cy=".5" r=".5"><stop offset="0" stop-color="#2aa7e8" stop-opacity=".55"/><stop offset="1" stop-color="#2aa7e8" stop-opacity="0"/></radialGradient>
|
||||||
|
<filter id="soft" x="-20%" y="-20%" width="140%" height="150%"><feDropShadow dx="0" dy="10" stdDeviation="12" flood-color="#04213a" flood-opacity=".35"/></filter>
|
||||||
|
<linearGradient id="disc" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#5fd0ff"/><stop offset="1" stop-color="#0c62a0"/></linearGradient>
|
||||||
|
</defs>
|
||||||
|
<g filter="url(#soft)">
|
||||||
|
<circle cx="200" cy="200" r="150" fill="url(#disc)"/>
|
||||||
|
<g fill="#ffffff">
|
||||||
|
<path d="M200 70 L236 118 L164 118 Z"/>
|
||||||
|
<path d="M200 330 L236 282 L164 282 Z"/>
|
||||||
|
<path d="M70 200 L118 164 L118 236 Z" opacity=".6"/>
|
||||||
|
<path d="M330 200 L282 164 L282 236 Z" opacity=".6"/>
|
||||||
|
<circle cx="200" cy="200" r="22"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g transform="translate(150 150) scale(.62) rotate(-12 256 266)" filter="url(#soft)">
|
||||||
|
<rect x="166" y="96" width="180" height="340" rx="90" fill="url(#shell)" stroke="#c9d5e3" stroke-width="4"/>
|
||||||
|
<path d="M170 228 C 210 240, 302 240, 342 228" fill="none" stroke="#c9d5e3" stroke-width="5" stroke-linecap="round"/>
|
||||||
|
<path d="M256 100 L256 236" stroke="#c9d5e3" stroke-width="5"/>
|
||||||
|
<circle cx="256" cy="168" r="70" fill="url(#glow)"/>
|
||||||
|
<rect x="236" y="128" width="40" height="80" rx="20" fill="url(#wheel)"/>
|
||||||
|
<g stroke="#ffffff" stroke-opacity=".55" stroke-width="5" stroke-linecap="round"><line x1="246" y1="148" x2="266" y2="148"/><line x1="246" y1="168" x2="266" y2="168"/><line x1="246" y1="188" x2="266" y2="188"/></g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 49 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 76 KiB |
@@ -3,21 +3,44 @@ Description=Watch for newly installed Chromium-based applications
|
|||||||
Documentation=man:middleclick-autoscroll(1)
|
Documentation=man:middleclick-autoscroll(1)
|
||||||
|
|
||||||
[Path]
|
[Path]
|
||||||
# Every way an application can turn up: a package, a Flatpak, something
|
# Every way an application can turn up: a package, a Flatpak, a snap, something
|
||||||
# installed by hand. Watching where the launchers land means there is no hook
|
# installed by hand. Watching where the launchers land means there is no hook
|
||||||
# to write per package manager - pacman, flatpak and an AppImage manager all
|
# to write per package manager: pacman, apt, dnf, zypper, flatpak, snapd and
|
||||||
# end up here.
|
# an AppImage manager all end up here.
|
||||||
|
#
|
||||||
|
# A directory that does not exist on this system costs nothing: systemd watches
|
||||||
|
# the nearest parent that does and picks the path up when it appears.
|
||||||
PathModified=/usr/share/applications
|
PathModified=/usr/share/applications
|
||||||
PathModified=/usr/local/share/applications
|
PathModified=/usr/local/share/applications
|
||||||
PathModified=%h/.local/share/applications
|
PathModified=%h/.local/share/applications
|
||||||
PathModified=%h/.config/autostart
|
PathModified=%h/.config/autostart
|
||||||
PathModified=/var/lib/flatpak/exports/share/applications
|
PathModified=/var/lib/flatpak/exports/share/applications
|
||||||
PathModified=%h/.local/share/flatpak/exports/share/applications
|
PathModified=%h/.local/share/flatpak/exports/share/applications
|
||||||
|
PathModified=/var/lib/snapd/desktop/applications
|
||||||
|
|
||||||
|
# NixOS and Guix build the search path out of profiles rather than /usr.
|
||||||
|
PathModified=/run/current-system/sw/share/applications
|
||||||
|
PathModified=%h/.nix-profile/share/applications
|
||||||
|
PathModified=%h/.guix-profile/share/applications
|
||||||
|
|
||||||
|
# The desktop folder is watched too. Steam writes a shortcut there for every
|
||||||
|
# game somebody asks for one, and starting a game is a Steam start. But the
|
||||||
|
# folder's name is translated and cannot be written down here. `enable` adds it
|
||||||
|
# in a drop-in, from the name this system uses.
|
||||||
|
|
||||||
# Steam replaces the script that starts its interface on every client update,
|
# Steam replaces the script that starts its interface on every client update,
|
||||||
# which takes the patch with it.
|
# which takes the patch with it. Where that installation lives depends on how
|
||||||
|
# Steam was installed. The steamrt3 client has a script of its own.
|
||||||
PathChanged=%h/.local/share/Steam/ubuntu12_64/steamwebhelper_sniper_wrap.sh
|
PathChanged=%h/.local/share/Steam/ubuntu12_64/steamwebhelper_sniper_wrap.sh
|
||||||
|
PathChanged=%h/.steam/debian-installation/ubuntu12_64/steamwebhelper_sniper_wrap.sh
|
||||||
PathChanged=%h/.var/app/com.valvesoftware.Steam/.local/share/Steam/ubuntu12_64/steamwebhelper_sniper_wrap.sh
|
PathChanged=%h/.var/app/com.valvesoftware.Steam/.local/share/Steam/ubuntu12_64/steamwebhelper_sniper_wrap.sh
|
||||||
|
PathChanged=%h/.var/app/com.valvesoftware.Steam/data/Steam/ubuntu12_64/steamwebhelper_sniper_wrap.sh
|
||||||
|
PathChanged=%h/snap/steam/common/.local/share/Steam/ubuntu12_64/steamwebhelper_sniper_wrap.sh
|
||||||
|
PathChanged=%h/.local/share/Steam/steamrt64/steamwebhelper.sh
|
||||||
|
PathChanged=%h/.steam/debian-installation/steamrt64/steamwebhelper.sh
|
||||||
|
PathChanged=%h/.var/app/com.valvesoftware.Steam/.local/share/Steam/steamrt64/steamwebhelper.sh
|
||||||
|
PathChanged=%h/.var/app/com.valvesoftware.Steam/data/Steam/steamrt64/steamwebhelper.sh
|
||||||
|
PathChanged=%h/snap/steam/common/.local/share/Steam/steamrt64/steamwebhelper.sh
|
||||||
|
|
||||||
Unit=middleclick-autoscroll.service
|
Unit=middleclick-autoscroll.service
|
||||||
|
|
||||||
|
|||||||
+118
-23
@@ -4,17 +4,18 @@
|
|||||||
#
|
#
|
||||||
# The routing lives in mca_route and is used twice: once by mca_apply to patch
|
# The routing lives in mca_route and is used twice: once by mca_apply to patch
|
||||||
# and once by the applications screen to show what would happen. Keeping it in
|
# and once by the applications screen to show what would happen. Keeping it in
|
||||||
# one function is what makes that screen trustworthy - it is not a description
|
# one function is what makes that screen trustworthy: it is not a description
|
||||||
# of the behaviour, it is the behaviour.
|
# of the behaviour, it is the behaviour.
|
||||||
|
|
||||||
MCA_CHANGES=0
|
MCA_CHANGES=0
|
||||||
MCA_ROUTES=()
|
MCA_ROUTES=()
|
||||||
|
|
||||||
# mca_route <kind> <id> <program>
|
# mca_route <kind> <id> <program> [packaging]
|
||||||
# What happens to one application, left in MCA_ROUTE:
|
# What happens to one application, left in MCA_ROUTE:
|
||||||
# flags - the launcher reads a flag file; write it there
|
# flags - the launcher reads a flag file; write it there
|
||||||
# desktop - no flag file; shadow or edit the desktop entry
|
# desktop - no flag file; shadow or edit the desktop entry
|
||||||
# steam - Steam's own two-part treatment
|
# steam - Steam's own two-part treatment
|
||||||
|
# spotify - the flag goes into spotify-launcher's configuration file
|
||||||
# unknown - cannot tell what engine this is (an AppImage), so nothing is done
|
# unknown - cannot tell what engine this is (an AppImage), so nothing is done
|
||||||
# off - detected, but switched off
|
# off - detected, but switched off
|
||||||
#
|
#
|
||||||
@@ -24,13 +25,13 @@ MCA_ROUTES=()
|
|||||||
MCA_ROUTE=''
|
MCA_ROUTE=''
|
||||||
|
|
||||||
mca_route() {
|
mca_route() {
|
||||||
local kind="$1" id="$2" prog="$3"
|
local kind="$1" id="$2" prog="$3" packaging="${4:-native}"
|
||||||
|
|
||||||
if [[ $kind == steam ]]; then
|
if [[ $kind == steam || $kind == spotify ]]; then
|
||||||
if mca_config_list_has Skip "$id" || [[ $CFG_STEAM != yes ]]; then
|
if mca_config_list_has Skip "$id"; then
|
||||||
MCA_ROUTE=off
|
MCA_ROUTE=off
|
||||||
else
|
else
|
||||||
MCA_ROUTE=steam
|
MCA_ROUTE="$kind"
|
||||||
fi
|
fi
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
@@ -40,9 +41,9 @@ mca_route() {
|
|||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# A Flatpak has its own copy of everything and none of the host's wrappers,
|
# A Flatpak or a snap carries its own copy of everything and sees none of
|
||||||
# so the desktop entry is the only way in.
|
# the host's wrappers, so the desktop entry is the only way in.
|
||||||
if [[ $kind == flatpak ]]; then
|
if [[ $packaging != native ]]; then
|
||||||
MCA_ROUTE=desktop
|
MCA_ROUTE=desktop
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
@@ -56,16 +57,25 @@ mca_route() {
|
|||||||
|
|
||||||
# mca_apply
|
# mca_apply
|
||||||
# Brings everything into line with the current settings. Safe to run as often
|
# Brings everything into line with the current settings. Safe to run as often
|
||||||
# as it likes to be - it writes only what differs, which is what keeps the
|
# as it likes to be. It writes only what differs, which is what keeps the
|
||||||
# watcher from chasing its own changes.
|
# watcher from chasing its own changes.
|
||||||
mca_apply() {
|
mca_apply() {
|
||||||
local i id file prog kind route steam_done=0
|
local i id file prog kind packaging route steam_done=0 spotify_done=0
|
||||||
|
|
||||||
MCA_CHANGES=0
|
MCA_CHANGES=0
|
||||||
MCA_ROUTES=()
|
MCA_ROUTES=()
|
||||||
MCA_N_ON=0; MCA_N_OFF=0; MCA_N_UNKNOWN=0
|
MCA_N_ON=0; MCA_N_OFF=0; MCA_N_UNKNOWN=0
|
||||||
|
|
||||||
mca_config_load
|
mca_config_load
|
||||||
|
|
||||||
|
# An installation that was set up by a version whose answer was a different
|
||||||
|
# flag still has that flag where it put it, and nothing below would touch it
|
||||||
|
# again: a file that is already marked as patched is left alone. Taking
|
||||||
|
# everything back once, here, is what carries such an installation over.
|
||||||
|
if [[ "$(mca_state_read flag_scheme 1)" != "$MCA_FLAG_SCHEME" ]]; then
|
||||||
|
mca_revert_all
|
||||||
|
fi
|
||||||
|
|
||||||
mca_scan
|
mca_scan
|
||||||
|
|
||||||
for i in "${!MCA_IDS[@]}"; do
|
for i in "${!MCA_IDS[@]}"; do
|
||||||
@@ -73,8 +83,9 @@ mca_apply() {
|
|||||||
file="${MCA_FILES[i]}"
|
file="${MCA_FILES[i]}"
|
||||||
prog="${MCA_PROGS[i]}"
|
prog="${MCA_PROGS[i]}"
|
||||||
kind="${MCA_KINDS[i]}"
|
kind="${MCA_KINDS[i]}"
|
||||||
|
packaging="${MCA_PACKAGING[i]}"
|
||||||
|
|
||||||
mca_route "$kind" "$id" "$prog"
|
mca_route "$kind" "$id" "$prog" "$packaging"
|
||||||
route="$MCA_ROUTE"
|
route="$MCA_ROUTE"
|
||||||
MCA_ROUTES[i]="$route"
|
MCA_ROUTES[i]="$route"
|
||||||
|
|
||||||
@@ -86,35 +97,57 @@ mca_apply() {
|
|||||||
|
|
||||||
case "$route" in
|
case "$route" in
|
||||||
flags)
|
flags)
|
||||||
mca_flags_apply "$prog" || mca_desktop_apply "$id" "$file"
|
mca_flags_apply "$prog" "$kind" \
|
||||||
|
|| mca_desktop_apply "$id" "$file" "$(mca_flags "$kind")"
|
||||||
;;
|
;;
|
||||||
desktop)
|
desktop)
|
||||||
mca_desktop_apply "$id" "$file"
|
mca_desktop_apply "$id" "$file" "$(mca_flags "$kind")"
|
||||||
;;
|
;;
|
||||||
steam)
|
steam)
|
||||||
mca_steam_desktop_apply "$id" "$file"
|
# Nothing is done to the entry itself: what Steam needs is
|
||||||
|
# in its own installation, and the same patch serves every
|
||||||
|
# way of starting the client.
|
||||||
if (( ! steam_done )); then
|
if (( ! steam_done )); then
|
||||||
mca_steam_apply
|
mca_steam_apply
|
||||||
steam_done=1
|
steam_done=1
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
|
spotify)
|
||||||
|
(( spotify_done )) || mca_spotify_apply
|
||||||
|
spotify_done=1
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
# Steam is worth patching even when its desktop entry is missing - a user
|
# Steam is worth patching even when its desktop entry is missing. A user
|
||||||
# who starts it from a script or a game launcher still gets the interface.
|
# who starts it from a script or a game launcher still gets the interface.
|
||||||
if [[ $CFG_STEAM == yes ]] && (( ! steam_done )) && mca_steam_installed; then
|
if (( ! steam_done )) && mca_steam_wanted && mca_steam_installed; then
|
||||||
mca_steam_apply
|
mca_steam_apply
|
||||||
fi
|
fi
|
||||||
|
|
||||||
[[ $CFG_AUTOSTART == yes ]] && mca_autostart_apply
|
# Autostart entries. A Chromium application that starts itself at login
|
||||||
[[ $CFG_SPOTIFY == yes ]] && mca_spotify_apply
|
# points straight at its binary and never reads the entry in the menu, so
|
||||||
|
# Discord at login used to behave differently from Discord from the menu.
|
||||||
|
mca_autostart_apply
|
||||||
|
|
||||||
|
# Shortcuts on the desktop itself, which nothing above has seen: the XDG
|
||||||
|
# search path does not go there. Each entry is gated on its own, so there is
|
||||||
|
# nothing to check out here.
|
||||||
|
mca_shortcuts_apply
|
||||||
|
|
||||||
|
# Not about any one application: middle click goes on pasting everywhere
|
||||||
|
# else on the desktop, and KDE is the one desktop that can be told not to.
|
||||||
|
# See kde.sh.
|
||||||
|
[[ $CFG_PASTE == yes ]] && mca_kde_paste_apply
|
||||||
|
|
||||||
|
mca_prune_orphans
|
||||||
|
|
||||||
if (( MCA_CHANGES )) && mca_have update-desktop-database; then
|
if (( MCA_CHANGES )) && mca_have update-desktop-database; then
|
||||||
update-desktop-database "$MCA_APPDIR" 2>/dev/null || true
|
update-desktop-database "$MCA_APPDIR" 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mca_state_write last_apply "$(date +%s)"
|
mca_state_write last_apply "$(date +%s)"
|
||||||
|
mca_state_write flag_scheme "$MCA_FLAG_SCHEME"
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,13 +168,19 @@ mca_revert() {
|
|||||||
# The watcher
|
# The watcher
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# A systemd user path unit watching every directory a desktop entry can appear
|
# A systemd user path unit watching every directory a desktop entry can appear
|
||||||
# in. That covers a package installed with pacman, a Flatpak, an AppImage
|
# in. That covers a package from whatever the distribution's package manager
|
||||||
# registered by hand and a Steam client update, without a hook per package
|
# is, a Flatpak, a snap, an AppImage registered by hand and a Steam client
|
||||||
# manager.
|
# update, without a hook per package manager.
|
||||||
|
|
||||||
MCA_UNIT_PATH="middleclick-autoscroll.path"
|
MCA_UNIT_PATH="middleclick-autoscroll.path"
|
||||||
MCA_UNIT_SERVICE="middleclick-autoscroll.service"
|
MCA_UNIT_SERVICE="middleclick-autoscroll.service"
|
||||||
|
|
||||||
|
# The desktop folder is watched like every other directory an entry can turn up
|
||||||
|
# in, but its name is translated and the unit that ships with the package
|
||||||
|
# cannot know it. So that one path is written here, into a drop-in, from the
|
||||||
|
# name this system actually uses.
|
||||||
|
MCA_UNIT_DROPIN="${MCA_XDG_CONFIG}/systemd/user/${MCA_UNIT_PATH}.d"
|
||||||
|
|
||||||
mca_watch_available() {
|
mca_watch_available() {
|
||||||
mca_have systemctl && [[ -n ${XDG_RUNTIME_DIR:-} || -S "/run/user/$(id -u)/bus" ]]
|
mca_have systemctl && [[ -n ${XDG_RUNTIME_DIR:-} || -S "/run/user/$(id -u)/bus" ]]
|
||||||
}
|
}
|
||||||
@@ -151,17 +190,56 @@ mca_watch_enabled() {
|
|||||||
systemctl --user is-enabled --quiet "$MCA_UNIT_PATH" 2>/dev/null
|
systemctl --user is-enabled --quiet "$MCA_UNIT_PATH" 2>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# _mca_watch_dropin_write
|
||||||
|
# Returns 0 when the drop-in changed and systemd has to be told, 1 when it was
|
||||||
|
# already right. That is the same contract as mca_write_if_changed, for the
|
||||||
|
# same reason: the watcher runs after every desktop entry that appears anywhere on
|
||||||
|
# the system, and a daemon-reload each time would be absurd.
|
||||||
|
_mca_watch_dropin_write() {
|
||||||
|
local dir file="$MCA_UNIT_DROPIN/desktop.conf" content
|
||||||
|
|
||||||
|
dir="$(mca_desktop_folder)"
|
||||||
|
[[ -d $dir ]] || { _mca_watch_dropin_remove; return $?; }
|
||||||
|
|
||||||
|
# A per cent sign starts a specifier in a unit file and has to be doubled
|
||||||
|
# to mean itself. Rare in a folder name, fatal when it happens.
|
||||||
|
content="[Path]"$'\n'"PathModified=${dir//%/%%}"$'\n'
|
||||||
|
|
||||||
|
mca_write_if_changed "$file" "$content"
|
||||||
|
}
|
||||||
|
|
||||||
|
_mca_watch_dropin_remove() {
|
||||||
|
[[ -e "$MCA_UNIT_DROPIN/desktop.conf" ]] || return 1
|
||||||
|
rm -f -- "$MCA_UNIT_DROPIN/desktop.conf"
|
||||||
|
rmdir "$MCA_UNIT_DROPIN" 2>/dev/null || true
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
mca_watch_enable() {
|
mca_watch_enable() {
|
||||||
mca_watch_available || return 1
|
mca_watch_available || return 1
|
||||||
|
_mca_watch_dropin_write
|
||||||
|
systemctl --user daemon-reload > /dev/null 2>&1 || true
|
||||||
systemctl --user enable --now "$MCA_UNIT_PATH" > /dev/null 2>&1 || return 1
|
systemctl --user enable --now "$MCA_UNIT_PATH" > /dev/null 2>&1 || return 1
|
||||||
systemctl --user enable "$MCA_UNIT_SERVICE" > /dev/null 2>&1 || true
|
systemctl --user enable "$MCA_UNIT_SERVICE" > /dev/null 2>&1 || true
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# mca_watch_refresh
|
||||||
|
# Keeps a running watcher in step with a desktop folder that has been renamed,
|
||||||
|
# which is what a change of session language does to it.
|
||||||
|
mca_watch_refresh() {
|
||||||
|
mca_watch_available || return 0
|
||||||
|
_mca_watch_dropin_write || return 0
|
||||||
|
systemctl --user daemon-reload > /dev/null 2>&1 || true
|
||||||
|
systemctl --user restart "$MCA_UNIT_PATH" > /dev/null 2>&1 || true
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
mca_watch_disable() {
|
mca_watch_disable() {
|
||||||
mca_watch_available || return 0
|
mca_watch_available || return 0
|
||||||
systemctl --user disable --now "$MCA_UNIT_PATH" > /dev/null 2>&1 || true
|
systemctl --user disable --now "$MCA_UNIT_PATH" > /dev/null 2>&1 || true
|
||||||
systemctl --user disable "$MCA_UNIT_SERVICE" > /dev/null 2>&1 || true
|
systemctl --user disable "$MCA_UNIT_SERVICE" > /dev/null 2>&1 || true
|
||||||
|
_mca_watch_dropin_remove && systemctl --user daemon-reload > /dev/null 2>&1
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,7 +261,8 @@ mca_count_routes() {
|
|||||||
MCA_ROUTES=()
|
MCA_ROUTES=()
|
||||||
|
|
||||||
for i in "${!MCA_IDS[@]}"; do
|
for i in "${!MCA_IDS[@]}"; do
|
||||||
mca_route "${MCA_KINDS[i]}" "${MCA_IDS[i]}" "${MCA_PROGS[i]}"
|
mca_route "${MCA_KINDS[i]}" "${MCA_IDS[i]}" "${MCA_PROGS[i]}" \
|
||||||
|
"${MCA_PACKAGING[i]}"
|
||||||
route="$MCA_ROUTE"
|
route="$MCA_ROUTE"
|
||||||
MCA_ROUTES[i]="$route"
|
MCA_ROUTES[i]="$route"
|
||||||
case "$route" in
|
case "$route" in
|
||||||
@@ -194,12 +273,28 @@ mca_count_routes() {
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# mca_steam_wanted
|
||||||
|
# Whether Steam gets patched, from the routes of the last scan: yes unless it
|
||||||
|
# was turned off in the applications list. Also yes when it has no entry there
|
||||||
|
# at all, so there is nothing to turn off.
|
||||||
|
mca_steam_wanted() {
|
||||||
|
local i seen=0
|
||||||
|
|
||||||
|
for i in "${!MCA_KINDS[@]}"; do
|
||||||
|
[[ ${MCA_KINDS[i]} == steam ]] || continue
|
||||||
|
[[ ${MCA_ROUTES[i]} == steam ]] && return 0
|
||||||
|
seen=1
|
||||||
|
done
|
||||||
|
(( ! seen ))
|
||||||
|
}
|
||||||
|
|
||||||
# mca_route_label <route>
|
# mca_route_label <route>
|
||||||
mca_route_label() {
|
mca_route_label() {
|
||||||
case "$1" in
|
case "$1" in
|
||||||
flags) mca_msg "flag file" ;;
|
flags) mca_msg "flag file" ;;
|
||||||
desktop) mca_msg "launcher" ;;
|
desktop) mca_msg "launcher" ;;
|
||||||
steam) mca_msg "Steam" ;;
|
steam) mca_msg "Steam" ;;
|
||||||
|
spotify) printf 'spotify-launcher' ;;
|
||||||
unknown) mca_msg "cannot tell" ;;
|
unknown) mca_msg "cannot tell" ;;
|
||||||
*) mca_msg "off" ;;
|
*) mca_msg "off" ;;
|
||||||
esac
|
esac
|
||||||
|
|||||||
+124
-19
@@ -3,7 +3,7 @@
|
|||||||
# Paths, translations, output helpers and the change ledger.
|
# Paths, translations, output helpers and the change ledger.
|
||||||
#
|
#
|
||||||
# Everything here runs unprivileged. This tool only ever writes inside the
|
# Everything here runs unprivileged. This tool only ever writes inside the
|
||||||
# user's own home - flag files, desktop entries, Steam's own scripts - so there
|
# user's own home (flag files, desktop entries, Steam's own scripts), so there
|
||||||
# is no system state to guard and nothing that needs root.
|
# is no system state to guard and nothing that needs root.
|
||||||
|
|
||||||
MCA_VERSION="@VERSION@"
|
MCA_VERSION="@VERSION@"
|
||||||
@@ -13,11 +13,53 @@ MCA_PRETTY="Middle-Click Autoscroll"
|
|||||||
# The whole point of the package. Blink implements Windows-style autoscroll
|
# The whole point of the package. Blink implements Windows-style autoscroll
|
||||||
# behind a runtime flag that Chromium does not turn on for Linux, because
|
# behind a runtime flag that Chromium does not turn on for Linux, because
|
||||||
# middle click is taken by primary-selection paste there.
|
# middle click is taken by primary-selection paste there.
|
||||||
|
#
|
||||||
|
# There are two ways to ask for that flag, and which one is right depends on
|
||||||
|
# what is being started:
|
||||||
|
#
|
||||||
|
# --enable-blink-features=MiddleClickAutoscroll is the one that works
|
||||||
|
# everywhere, and the only one that works in the Chromium versions embedded
|
||||||
|
# applications ship: Steam's CEF, an Electron a few years old, anything
|
||||||
|
# before Chromium 124. A browser started with it puts a yellow bar above the
|
||||||
|
# page saying an unsupported command line flag is in use, because Chromium
|
||||||
|
# keeps a list of flags worth warning about and this is on it.
|
||||||
|
#
|
||||||
|
# --enable-features=MiddleClickAutoscroll is not on that list, so a browser
|
||||||
|
# started with it says nothing. Blink generates a feature of the same name
|
||||||
|
# for every one of its runtime flags, which is what makes the two the same
|
||||||
|
# request. But only since Chromium 124. Before that the name means nothing
|
||||||
|
# and is ignored without a word.
|
||||||
|
#
|
||||||
|
# So a browser, which is the only thing that shows the bar and the one thing
|
||||||
|
# that keeps itself up to date, is given the quiet one; everything else keeps
|
||||||
|
# the one that always works.
|
||||||
MCA_FLAG="--enable-blink-features=MiddleClickAutoscroll"
|
MCA_FLAG="--enable-blink-features=MiddleClickAutoscroll"
|
||||||
|
|
||||||
# The Blink feature name on its own, for merging into an --enable-blink-features
|
# Two browsers do not answer to the Chromium name. Helium ships the feature
|
||||||
# list that an app (or the user) already carries.
|
# under its own name and sets the runtime flag from that alone. Brave takes
|
||||||
|
# the generated feature away and switches the flag on from one of its own,
|
||||||
|
# spelled MiddelButtonClickAutoscroll. The typo is in Brave's source, and the
|
||||||
|
# correct spelling does nothing. So browsers are asked for all three. A name a
|
||||||
|
# browser does not know is ignored, which is what makes one list safe to hand
|
||||||
|
# to all of them.
|
||||||
|
MCA_BROWSER_FLAG="--enable-features=MiddleClickAutoscroll,HeliumMiddleClickAutoscroll,MiddelButtonClickAutoscroll"
|
||||||
|
|
||||||
|
# The feature names on their own, for merging into a list that an application
|
||||||
|
# (or the user) already carries, and for taking them back out again.
|
||||||
MCA_FEATURE="MiddleClickAutoscroll"
|
MCA_FEATURE="MiddleClickAutoscroll"
|
||||||
|
MCA_BROWSER_FEATURES="MiddleClickAutoscroll,HeliumMiddleClickAutoscroll,MiddelButtonClickAutoscroll"
|
||||||
|
|
||||||
|
# Bumped when the flags above change, and when what gets written where does.
|
||||||
|
# An installation that was set up by a version with a different answer is taken
|
||||||
|
# back and done again once, because a file that is already patched is otherwise
|
||||||
|
# left alone. See mca_apply.
|
||||||
|
#
|
||||||
|
# 3 is what takes -noverifyfiles back out of the Steam entries an older version
|
||||||
|
# put it in.
|
||||||
|
#
|
||||||
|
# 4 adds Brave's name to the browser list, which an entry edited in place would
|
||||||
|
# otherwise never get.
|
||||||
|
MCA_FLAG_SCHEME=4
|
||||||
|
|
||||||
MCA_LIBDIR="${MCA_LIBDIR:-@LIBDIR@}"
|
MCA_LIBDIR="${MCA_LIBDIR:-@LIBDIR@}"
|
||||||
MCA_LOCALEDIR="${MCA_LOCALEDIR:-@LOCALEDIR@}"
|
MCA_LOCALEDIR="${MCA_LOCALEDIR:-@LOCALEDIR@}"
|
||||||
@@ -34,7 +76,7 @@ MCA_CACHEDIR="${MCA_CACHEDIR:-${MCA_XDG_CACHE}/${MCA_NAME}}"
|
|||||||
|
|
||||||
# Where generated desktop entries go. A file here shadows the one with the same
|
# Where generated desktop entries go. A file here shadows the one with the same
|
||||||
# name in /usr/share/applications, which is how an application gets extra
|
# name in /usr/share/applications, which is how an application gets extra
|
||||||
# command line arguments without touching anything pacman owns.
|
# command line arguments without touching a file the package manager owns.
|
||||||
MCA_APPDIR="${MCA_XDG_DATA}/applications"
|
MCA_APPDIR="${MCA_XDG_DATA}/applications"
|
||||||
|
|
||||||
# Copies of every file that is edited in place rather than shadowed.
|
# Copies of every file that is edited in place rather than shadowed.
|
||||||
@@ -44,6 +86,29 @@ MCA_BACKUPDIR="${MCA_STATEDIR}/backup"
|
|||||||
# else. See mca_ledger_add.
|
# else. See mca_ledger_add.
|
||||||
MCA_LEDGER="${MCA_STATEDIR}/ledger"
|
MCA_LEDGER="${MCA_STATEDIR}/ledger"
|
||||||
|
|
||||||
|
# The folder the desktop itself shows. Nothing in the XDG search path looks at
|
||||||
|
# it, so an entry that lives only there is invisible to a scan. A game
|
||||||
|
# shortcut dragged onto the desktop is exactly that.
|
||||||
|
#
|
||||||
|
# Its name is translated: Schreibtisch, Bureau, Escritorio. The name in use is
|
||||||
|
# in the file xdg-user-dirs writes, so it is read rather than guessed, and
|
||||||
|
# ~/Desktop is only the fallback for a system that has no such file.
|
||||||
|
mca_desktop_folder() {
|
||||||
|
local file="$MCA_XDG_CONFIG/user-dirs.dirs" line dir=''
|
||||||
|
|
||||||
|
if [[ -r $file ]]; then
|
||||||
|
while IFS= read -r line; do
|
||||||
|
[[ $line == XDG_DESKTOP_DIR=* ]] || continue
|
||||||
|
dir="${line#XDG_DESKTOP_DIR=}"
|
||||||
|
dir="${dir%\"}"; dir="${dir#\"}"
|
||||||
|
done < "$file"
|
||||||
|
dir="${dir/#\$HOME/$HOME}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ $dir == /* ]] || dir="$HOME/Desktop"
|
||||||
|
printf '%s\n' "${dir%/}"
|
||||||
|
}
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Translations
|
# Translations
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -60,8 +125,15 @@ mca_ui_locale() {
|
|||||||
[[ -z $l ]] && l="${LANG:-}"
|
[[ -z $l ]] && l="${LANG:-}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -z $l && -r /etc/locale.conf ]]; then
|
# systemd writes /etc/locale.conf and most distributions use it; Debian and
|
||||||
l="$(sed -n 's/^LANG=//p' /etc/locale.conf | tr -d '"' | head -n1)"
|
# Ubuntu keep the same LANG= line in /etc/default/locale instead.
|
||||||
|
if [[ -z $l ]]; then
|
||||||
|
local f
|
||||||
|
for f in /etc/locale.conf /etc/default/locale; do
|
||||||
|
[[ -r $f ]] || continue
|
||||||
|
l="$(sed -n 's/^LANG=//p' "$f" | tr -d '"' | head -n1)"
|
||||||
|
[[ -n $l ]] && break
|
||||||
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
printf '%s\n' "${l:-C}"
|
printf '%s\n' "${l:-C}"
|
||||||
@@ -143,12 +215,6 @@ else
|
|||||||
MCA_C_GREEN='' MCA_C_YELLOW='' MCA_C_RED=''
|
MCA_C_GREEN='' MCA_C_YELLOW='' MCA_C_RED=''
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Set by mca_bad and mca_note. The menu redraws straight after an action, which
|
|
||||||
# would wipe the screen; this marks that something was printed the user still
|
|
||||||
# has to read. A plain success needs no acknowledgement - the status block at
|
|
||||||
# the top of the menu already shows the new state.
|
|
||||||
MCA_UI_NEEDS_ACK=''
|
|
||||||
|
|
||||||
# --quiet silences progress chatter; errors still go to stderr. Used by the
|
# --quiet silences progress chatter; errors still go to stderr. Used by the
|
||||||
# systemd unit, which has no terminal and logs to the journal anyway.
|
# systemd unit, which has no terminal and logs to the journal anyway.
|
||||||
MCA_QUIET=''
|
MCA_QUIET=''
|
||||||
@@ -156,8 +222,8 @@ MCA_QUIET=''
|
|||||||
mca_say() { [[ -n $MCA_QUIET ]] || printf '%s\n' "$*"; }
|
mca_say() { [[ -n $MCA_QUIET ]] || printf '%s\n' "$*"; }
|
||||||
mca_head() { printf '\n%s%s%s\n\n' "$MCA_C_BOLD$MCA_C_BLUE" "$*" "$MCA_C_RESET"; }
|
mca_head() { printf '\n%s%s%s\n\n' "$MCA_C_BOLD$MCA_C_BLUE" "$*" "$MCA_C_RESET"; }
|
||||||
mca_ok() { [[ -n $MCA_QUIET ]] || printf '%s✔%s %s\n' "$MCA_C_GREEN" "$MCA_C_RESET" "$*"; }
|
mca_ok() { [[ -n $MCA_QUIET ]] || printf '%s✔%s %s\n' "$MCA_C_GREEN" "$MCA_C_RESET" "$*"; }
|
||||||
mca_bad() { MCA_UI_NEEDS_ACK=1; printf '%s✘%s %s\n' "$MCA_C_RED" "$MCA_C_RESET" "$*" >&2; }
|
mca_bad() { printf '%s✘%s %s\n' "$MCA_C_RED" "$MCA_C_RESET" "$*" >&2; }
|
||||||
mca_note() { MCA_UI_NEEDS_ACK=1; [[ -n $MCA_QUIET ]] || printf '%s•%s %s\n' "$MCA_C_DIM" "$MCA_C_RESET" "$*"; }
|
mca_note() { [[ -n $MCA_QUIET ]] || printf '%s•%s %s\n' "$MCA_C_DIM" "$MCA_C_RESET" "$*"; }
|
||||||
|
|
||||||
mca_have() { command -v "$1" > /dev/null 2>&1; }
|
mca_have() { command -v "$1" > /dev/null 2>&1; }
|
||||||
|
|
||||||
@@ -173,8 +239,11 @@ mca_time_ago() {
|
|||||||
(( delta < 0 )) && delta=0
|
(( delta < 0 )) && delta=0
|
||||||
|
|
||||||
if (( delta < 60 )); then mca_msg "just now"
|
if (( delta < 60 )); then mca_msg "just now"
|
||||||
|
elif (( delta < 120 )); then mca_msg "1 minute ago"
|
||||||
elif (( delta < 3600 )); then mca_msg "%d minutes ago" "$(( delta / 60 ))"
|
elif (( delta < 3600 )); then mca_msg "%d minutes ago" "$(( delta / 60 ))"
|
||||||
|
elif (( delta < 7200 )); then mca_msg "1 hour ago"
|
||||||
elif (( delta < 86400 )); then mca_msg "%d hours ago" "$(( delta / 3600 ))"
|
elif (( delta < 86400 )); then mca_msg "%d hours ago" "$(( delta / 3600 ))"
|
||||||
|
elif (( delta < 172800 )); then mca_msg "1 day ago"
|
||||||
else mca_msg "%d days ago" "$(( delta / 86400 ))"
|
else mca_msg "%d days ago" "$(( delta / 86400 ))"
|
||||||
fi
|
fi
|
||||||
printf '\n'
|
printf '\n'
|
||||||
@@ -203,7 +272,7 @@ mca_state_write() {
|
|||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# The change ledger
|
# The change ledger
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Reverting by pattern - "delete every desktop entry that mentions the flag" -
|
# Reverting by pattern ("delete every desktop entry that mentions the flag")
|
||||||
# would also delete entries the user wrote by hand. So every change is recorded
|
# would also delete entries the user wrote by hand. So every change is recorded
|
||||||
# instead, and `revert` replays the ledger backwards.
|
# instead, and `revert` replays the ledger backwards.
|
||||||
#
|
#
|
||||||
@@ -213,9 +282,12 @@ mca_state_write() {
|
|||||||
# shadow <generated desktop entry> <source entry it was generated from>
|
# shadow <generated desktop entry> <source entry it was generated from>
|
||||||
# inplace <edited file> <basename of its backup copy>
|
# inplace <edited file> <basename of its backup copy>
|
||||||
# flags <flag file> created | appended | merged
|
# flags <flag file> created | appended | merged
|
||||||
|
# kwin <kwinrc> what EnablePrimarySelection said before
|
||||||
#
|
#
|
||||||
# `inplace` and `flags` differ in how they are undone: a backup is restored
|
# The kinds differ in how they are undone: a backup is restored wholesale, a
|
||||||
# wholesale, a flag file only loses the one line that was added to it.
|
# flag file only loses the one line that was added to it, and kwinrc gets one
|
||||||
|
# key written back. It is a file KDE writes to itself, and putting a whole
|
||||||
|
# copy of it back would take everything else settled since with it.
|
||||||
|
|
||||||
mca_ledger_add() {
|
mca_ledger_add() {
|
||||||
local kind="$1" path="$2" detail="${3:-}"
|
local kind="$1" path="$2" detail="${3:-}"
|
||||||
@@ -228,6 +300,25 @@ mca_ledger_add() {
|
|||||||
printf '%s\t%s\t%s\n' "$kind" "$path" "$detail" >> "$MCA_LEDGER"
|
printf '%s\t%s\t%s\n' "$kind" "$path" "$detail" >> "$MCA_LEDGER"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# mca_ledger_has <path>
|
||||||
|
# Whether the ledger still knows about that file. Worth asking because the copy
|
||||||
|
# kept beside it is named after the path and outlives a ledger that was lost or
|
||||||
|
# truncated: a file nothing has a record of any more is one nothing would ever
|
||||||
|
# look at again.
|
||||||
|
mca_ledger_has() {
|
||||||
|
[[ -f $MCA_LEDGER ]] || return 1
|
||||||
|
awk -F'\t' -v p="$1" '$2 == p { found = 1 } END { exit !found }' "$MCA_LEDGER"
|
||||||
|
}
|
||||||
|
|
||||||
|
# mca_ledger_detail <path>
|
||||||
|
# The third column of that file's line, empty when the ledger has none. What it
|
||||||
|
# means is the kind's business; for `kwin` it is the value to put back.
|
||||||
|
mca_ledger_detail() {
|
||||||
|
[[ -f $MCA_LEDGER ]] || return 1
|
||||||
|
awk -F'\t' -v p="$1" '$2 == p { d = $3 } END { if (!length(d)) exit 1; print d }' \
|
||||||
|
"$MCA_LEDGER"
|
||||||
|
}
|
||||||
|
|
||||||
mca_ledger_forget() {
|
mca_ledger_forget() {
|
||||||
local path="$1" tmp
|
local path="$1" tmp
|
||||||
[[ -f $MCA_LEDGER ]] || return 0
|
[[ -f $MCA_LEDGER ]] || return 0
|
||||||
@@ -239,17 +330,31 @@ mca_ledger_forget() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# mca_backup_name <file>
|
||||||
|
# The name a backup copy of that file is stored under. Derived from the path
|
||||||
|
# rather than remembered, so a caller can ask whether a file has been backed up
|
||||||
|
# before without reading the ledger.
|
||||||
|
mca_backup_name() {
|
||||||
|
printf '%s' "$1" | sed 's|/|%|g'
|
||||||
|
}
|
||||||
|
|
||||||
# mca_backup <file>
|
# mca_backup <file>
|
||||||
# Copies a file aside before it is edited in place, and prints the name the
|
# Copies a file aside before it is edited in place, and prints the name the
|
||||||
# copy was stored under. Existing backups are never overwritten: the first copy
|
# copy was stored under. Existing backups are never overwritten: the first copy
|
||||||
# is the pristine one, and a second apply must not replace it with an already
|
# is the pristine one, and a second apply must not replace it with an already
|
||||||
# patched version.
|
# patched version.
|
||||||
|
#
|
||||||
|
# A symlink is kept as a symlink, so undo can put the link back. It is taken
|
||||||
|
# again every time: this program never writes a link, so one is always pristine.
|
||||||
mca_backup() {
|
mca_backup() {
|
||||||
local file="$1" name
|
local file="$1" name
|
||||||
name="$(printf '%s' "$file" | sed 's|/|%|g')"
|
name="$(mca_backup_name "$file")"
|
||||||
|
|
||||||
mkdir -p "$MCA_BACKUPDIR" 2>/dev/null || return 1
|
mkdir -p "$MCA_BACKUPDIR" 2>/dev/null || return 1
|
||||||
if [[ ! -e "$MCA_BACKUPDIR/$name" ]]; then
|
if [[ -L $file ]]; then
|
||||||
|
rm -f -- "$MCA_BACKUPDIR/$name"
|
||||||
|
cp -P -p -- "$file" "$MCA_BACKUPDIR/$name" 2>/dev/null || return 1
|
||||||
|
elif [[ ! -e "$MCA_BACKUPDIR/$name" && ! -L "$MCA_BACKUPDIR/$name" ]]; then
|
||||||
cp -p -- "$file" "$MCA_BACKUPDIR/$name" 2>/dev/null || return 1
|
cp -p -- "$file" "$MCA_BACKUPDIR/$name" 2>/dev/null || return 1
|
||||||
fi
|
fi
|
||||||
printf '%s\n' "$name"
|
printf '%s\n' "$name"
|
||||||
|
|||||||
+57
-6
@@ -101,6 +101,20 @@ mca_config_set() {
|
|||||||
MCA_CONFIG_CACHED=0
|
MCA_CONFIG_CACHED=0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# mca_config_del <Key>
|
||||||
|
mca_config_del() {
|
||||||
|
local key="$1" tmp
|
||||||
|
|
||||||
|
[[ -w $MCA_CONFIG ]] || return 1
|
||||||
|
grep -qE "^[[:space:]]*${key}[[:space:]]*=" "$MCA_CONFIG" || return 0
|
||||||
|
|
||||||
|
tmp="$(mktemp "${MCA_CONFIG}.XXXXXX")" || return 1
|
||||||
|
chmod --reference="$MCA_CONFIG" "$tmp" 2>/dev/null || chmod 0644 "$tmp"
|
||||||
|
grep -vE "^[[:space:]]*${key}[[:space:]]*=" "$MCA_CONFIG" > "$tmp"
|
||||||
|
mv -f "$tmp" "$MCA_CONFIG"
|
||||||
|
MCA_CONFIG_CACHED=0
|
||||||
|
}
|
||||||
|
|
||||||
# mca_config_list_has <Key> <item>
|
# mca_config_list_has <Key> <item>
|
||||||
# The per-application overrides are stored as space separated lists.
|
# The per-application overrides are stored as space separated lists.
|
||||||
mca_config_list_has() {
|
mca_config_list_has() {
|
||||||
@@ -136,13 +150,8 @@ mca_config_list_del() {
|
|||||||
|
|
||||||
mca_config_load() {
|
mca_config_load() {
|
||||||
CFG_ENABLED=no; mca_config_bool Enabled no && CFG_ENABLED=yes
|
CFG_ENABLED=no; mca_config_bool Enabled no && CFG_ENABLED=yes
|
||||||
CFG_APPS=no; mca_config_bool PatchApps yes && CFG_APPS=yes
|
|
||||||
CFG_BROWSERS=no; mca_config_bool PatchBrowsers yes && CFG_BROWSERS=yes
|
|
||||||
CFG_FLATPAK=no; mca_config_bool PatchFlatpak yes && CFG_FLATPAK=yes
|
|
||||||
CFG_AUTOSTART=no; mca_config_bool PatchAutostart yes && CFG_AUTOSTART=yes
|
|
||||||
CFG_STEAM=no; mca_config_bool PatchSteam yes && CFG_STEAM=yes
|
|
||||||
CFG_SPOTIFY=no; mca_config_bool PatchSpotify yes && CFG_SPOTIFY=yes
|
|
||||||
CFG_WATCH=no; mca_config_bool WatchNewApps yes && CFG_WATCH=yes
|
CFG_WATCH=no; mca_config_bool WatchNewApps yes && CFG_WATCH=yes
|
||||||
|
CFG_PASTE=no; mca_config_bool DisablePaste yes && CFG_PASTE=yes
|
||||||
|
|
||||||
CFG_EXTRA_FLAGS="$(mca_config_get ExtraFlags '')"
|
CFG_EXTRA_FLAGS="$(mca_config_get ExtraFlags '')"
|
||||||
|
|
||||||
@@ -153,10 +162,52 @@ mca_config_load() {
|
|||||||
CFG_SKIP="$(mca_config_get Skip '')"
|
CFG_SKIP="$(mca_config_get Skip '')"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# mca_config_migrate
|
||||||
|
# Up to 1.5 the settings had a switch per group: applications, browsers,
|
||||||
|
# Flatpak, snap, programs at login, Steam and Spotify. The applications list
|
||||||
|
# does that job now, one application at a time. So a group that was switched
|
||||||
|
# off turns into a Skip for each application in it, once, and the old keys go.
|
||||||
|
# Called at the end of a scan, because the groups come from there.
|
||||||
|
mca_config_migrate() {
|
||||||
|
local i key off='' group pack
|
||||||
|
|
||||||
|
_mca_config_slurp
|
||||||
|
[[ $MCA_CONFIG_CACHE == *Patch[A-Z]*=* ]] || return 0
|
||||||
|
|
||||||
|
for key in Apps Browsers Flatpak Snap Steam Spotify; do
|
||||||
|
mca_config_bool "Patch$key" yes || off+=" $key "
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ -n $off ]]; then
|
||||||
|
for i in "${!MCA_IDS[@]}"; do
|
||||||
|
mca_config_list_has Include "${MCA_IDS[i]}" && continue
|
||||||
|
group="${MCA_KINDS[i]^}"
|
||||||
|
[[ $group == App || $group == Browser ]] && group+=s
|
||||||
|
pack="${MCA_PACKAGING[i]^}"
|
||||||
|
if [[ $off == *" $group "* || $off == *" $pack "* ]]; then
|
||||||
|
mca_config_list_add Skip "${MCA_IDS[i]}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
for key in Apps Browsers Flatpak Snap Autostart Steam Spotify; do
|
||||||
|
mca_config_del "Patch$key"
|
||||||
|
done
|
||||||
|
mca_config_load
|
||||||
|
}
|
||||||
|
|
||||||
|
# mca_flags [kind]
|
||||||
# The full argument string that gets injected. Kept in one place so the flag
|
# The full argument string that gets injected. Kept in one place so the flag
|
||||||
# file writer and the desktop entry writer cannot drift apart.
|
# file writer and the desktop entry writer cannot drift apart.
|
||||||
|
#
|
||||||
|
# A browser gets the flag that leaves it without a warning bar; everything else
|
||||||
|
# gets the one that works in every Chromium there is. See MCA_FLAG.
|
||||||
mca_flags() {
|
mca_flags() {
|
||||||
|
if [[ ${1:-app} == browser ]]; then
|
||||||
|
printf '%s' "$MCA_BROWSER_FLAG"
|
||||||
|
else
|
||||||
printf '%s' "$MCA_FLAG"
|
printf '%s' "$MCA_FLAG"
|
||||||
|
fi
|
||||||
[[ -n ${CFG_EXTRA_FLAGS:-} ]] && printf ' %s' "$CFG_EXTRA_FLAGS"
|
[[ -n ${CFG_EXTRA_FLAGS:-} ]] && printf ' %s' "$CFG_EXTRA_FLAGS"
|
||||||
printf '\n'
|
printf '\n'
|
||||||
}
|
}
|
||||||
+751
-81
File diff suppressed because it is too large.
Load diff
+167
@@ -0,0 +1,167 @@
|
|||||||
|
# shellcheck shell=bash
|
||||||
|
#
|
||||||
|
# KDE's middle-click paste.
|
||||||
|
#
|
||||||
|
# Inside a Chromium application the flag settles this on its own: with
|
||||||
|
# autoscroll on, Blink stops pasting the primary selection on middle click,
|
||||||
|
# because the button is doing something else now. Everywhere else on the
|
||||||
|
# desktop middle click goes on pasting, which is the behaviour this whole
|
||||||
|
# program exists to get away from. So the desktop's own switch for it is
|
||||||
|
# turned off too.
|
||||||
|
#
|
||||||
|
# KWin has such a switch, and only for a Wayland session, where the paste is a
|
||||||
|
# protocol the compositor either offers or does not:
|
||||||
|
#
|
||||||
|
# ~/.config/kwinrc, [Wayland], EnablePrimarySelection=false
|
||||||
|
#
|
||||||
|
# On X11 there is nothing to switch. The primary selection is part of X itself
|
||||||
|
# and every toolkit reaches for it on its own; no one place can say no.
|
||||||
|
#
|
||||||
|
# KWin reads the key once, while it starts, so what is written here is true
|
||||||
|
# from the next login on rather than straight away.
|
||||||
|
|
||||||
|
MCA_KWINRC="${MCA_XDG_CONFIG}/kwinrc"
|
||||||
|
MCA_KWIN_GROUP="Wayland"
|
||||||
|
MCA_KWIN_KEY="EnablePrimarySelection"
|
||||||
|
|
||||||
|
# The kconfig command line tools, whichever generation this session has. They
|
||||||
|
# are what System Settings writes kwinrc with, and worth the fork: the file has
|
||||||
|
# a cascade behind it (/etc/xdg, the kdedefaults directory) and entries a
|
||||||
|
# distribution can mark immutable, and an edit that reaches past all that with
|
||||||
|
# sed writes something KDE goes on to ignore.
|
||||||
|
MCA_KDE_TOOL=''
|
||||||
|
MCA_KDE_TOOL_LOOKED=0
|
||||||
|
|
||||||
|
_mca_kde_tool() {
|
||||||
|
local gen
|
||||||
|
|
||||||
|
if (( ! MCA_KDE_TOOL_LOOKED )); then
|
||||||
|
MCA_KDE_TOOL_LOOKED=1
|
||||||
|
for gen in 6 5; do
|
||||||
|
if mca_have "kreadconfig$gen" && mca_have "kwriteconfig$gen"; then
|
||||||
|
MCA_KDE_TOOL="$gen"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ -n $MCA_KDE_TOOL ]] || return 1
|
||||||
|
printf '%s\n' "$MCA_KDE_TOOL"
|
||||||
|
}
|
||||||
|
|
||||||
|
# mca_kde_session
|
||||||
|
# Whether this is a KWin Wayland session.
|
||||||
|
mca_kde_session() {
|
||||||
|
local desktop="${XDG_CURRENT_DESKTOP:-}"
|
||||||
|
|
||||||
|
# The watcher is a systemd service, and one started before the session
|
||||||
|
# imported its environment sees none of these variables. A running
|
||||||
|
# kwin_wayland answers both halves of the question at once, and is what
|
||||||
|
# such a run ends up going by.
|
||||||
|
if [[ -z $desktop && -z ${KDE_FULL_SESSION:-} ]]; then
|
||||||
|
mca_have pgrep || return 1
|
||||||
|
pgrep -u "$(id -u)" -x kwin_wayland > /dev/null 2>&1
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# XDG_CURRENT_DESKTOP is the one every desktop sets, and the one to go by
|
||||||
|
# wherever it is set; KDE_FULL_SESSION is what answers when it is not.
|
||||||
|
[[ -z $desktop || ${desktop^^} == *KDE* ]] || return 1
|
||||||
|
|
||||||
|
[[ ${XDG_SESSION_TYPE:-} == wayland || -n ${WAYLAND_DISPLAY:-} ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
mca_kde_available() {
|
||||||
|
mca_kde_session && _mca_kde_tool > /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# mca_kde_read [file]
|
||||||
|
# What the key says now, lowercased, empty when it is not set at all.
|
||||||
|
mca_kde_read() {
|
||||||
|
local file="${1:-$MCA_KWINRC}" gen val
|
||||||
|
gen="$(_mca_kde_tool)" || return 1
|
||||||
|
|
||||||
|
# kreadconfig creates the file it is pointed at, and the status screen
|
||||||
|
# (which asks on every redraw) has no business writing anything. A file
|
||||||
|
# that is not there has no value in it to read anyway.
|
||||||
|
[[ -f $file ]] || return 0
|
||||||
|
|
||||||
|
val="$("kreadconfig$gen" --file "$file" --group "$MCA_KWIN_GROUP" \
|
||||||
|
--key "$MCA_KWIN_KEY" 2>/dev/null)"
|
||||||
|
printf '%s\n' "${val,,}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# mca_kde_write [file] <value>
|
||||||
|
# An empty value takes the key back out rather than writing nothing into it -
|
||||||
|
# a key that is missing and a key that says nothing are not the same thing to
|
||||||
|
# KDE, and only the first one is what an untouched kwinrc looks like.
|
||||||
|
mca_kde_write() {
|
||||||
|
local file="$1" value="$2" gen
|
||||||
|
gen="$(_mca_kde_tool)" || return 1
|
||||||
|
|
||||||
|
if [[ -z $value ]]; then
|
||||||
|
"kwriteconfig$gen" --file "$file" --group "$MCA_KWIN_GROUP" \
|
||||||
|
--key "$MCA_KWIN_KEY" --delete 2>/dev/null
|
||||||
|
else
|
||||||
|
"kwriteconfig$gen" --file "$file" --group "$MCA_KWIN_GROUP" \
|
||||||
|
--key "$MCA_KWIN_KEY" "$value" 2>/dev/null
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# mca_kde_paste_apply
|
||||||
|
# Turns the paste off, and remembers what the key said before so that undoing
|
||||||
|
# puts that back rather than a guess.
|
||||||
|
#
|
||||||
|
# A key that already says false without the ledger knowing about it was set by
|
||||||
|
# the user or by the distribution. That one is left alone and nothing is
|
||||||
|
# recorded, so `disable` cannot switch a paste back on that this program never
|
||||||
|
# switched off.
|
||||||
|
mca_kde_paste_apply() {
|
||||||
|
local current previous changed=0
|
||||||
|
|
||||||
|
mca_kde_available || return 1
|
||||||
|
current="$(mca_kde_read)" || return 1
|
||||||
|
|
||||||
|
if mca_ledger_has "$MCA_KWINRC"; then
|
||||||
|
# Ours already. What goes back is the value recorded the first time
|
||||||
|
# round, not what reading the file now would say. That is false, and
|
||||||
|
# false is what is being undone.
|
||||||
|
previous="$(mca_ledger_detail "$MCA_KWINRC")" || previous=unset
|
||||||
|
elif [[ $current == false ]]; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
previous="${current:-unset}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $current != false ]]; then
|
||||||
|
mca_kde_write "$MCA_KWINRC" false || return 1
|
||||||
|
MCA_CHANGES=$(( MCA_CHANGES + 1 ))
|
||||||
|
changed=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mca_ledger_add kwin "$MCA_KWINRC" "$previous"
|
||||||
|
|
||||||
|
(( changed )) && mca_note "$(mca_msg "Middle click stops pasting at the next login.")"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# mca_kde_paste_revert <file> <previous value>
|
||||||
|
mca_kde_paste_revert() {
|
||||||
|
local file="$1" previous="$2"
|
||||||
|
|
||||||
|
_mca_kde_tool > /dev/null || return 1
|
||||||
|
[[ -f $file ]] || return 1
|
||||||
|
|
||||||
|
# Only what is still recognisably ours. A key somebody has since put a
|
||||||
|
# value of their own into is theirs now.
|
||||||
|
[[ "$(mca_kde_read "$file")" == false ]] || return 1
|
||||||
|
|
||||||
|
[[ $previous == unset ]] && previous=''
|
||||||
|
mca_kde_write "$file" "$previous" || return 1
|
||||||
|
|
||||||
|
# Nothing was in the file but the key, which means there was no file before
|
||||||
|
# this program wrote one. An empty kwinrc says nothing that its absence
|
||||||
|
# does not say better.
|
||||||
|
[[ -s $file ]] || rm -f -- "$file"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
+188
-65
@@ -31,14 +31,25 @@ mca_ui_term_restore() {
|
|||||||
MCA_TERM_SAVED=''
|
MCA_TERM_SAVED=''
|
||||||
}
|
}
|
||||||
|
|
||||||
# Runs an action with the terminal handed back to normal line mode, so anything
|
# What the last action printed. The menu shows it under the status until the
|
||||||
# it prints - or prompts for - behaves the way a program expects.
|
# next key, so nothing has to wait for a key on a screen of its own.
|
||||||
mca_ui_cooked() {
|
MCA_UI_MSG=''
|
||||||
mca_ui_term_restore
|
|
||||||
"$@"
|
# Set while the menu runs. Its status block already says that running
|
||||||
local rc=$?
|
# applications need a restart, so the actions leave that line out there.
|
||||||
mca_ui_term_raw
|
MCA_IN_MENU=''
|
||||||
return $rc
|
|
||||||
|
# mca_ui_run <command...>
|
||||||
|
# Runs an action in this shell (so what it scans and loads stays) with its
|
||||||
|
# output kept for the menu. None of them asks anything.
|
||||||
|
mca_ui_run() {
|
||||||
|
local tmp
|
||||||
|
|
||||||
|
printf ' %s%s%s\n' "$MCA_C_DIM" "$(mca_msg "One moment...")" "$MCA_C_RESET"
|
||||||
|
tmp="$(mktemp)" || { "$@"; return; }
|
||||||
|
"$@" > "$tmp" 2>&1
|
||||||
|
MCA_UI_MSG="$(< "$tmp")"
|
||||||
|
rm -f -- "$tmp"
|
||||||
}
|
}
|
||||||
|
|
||||||
# mca_read_key
|
# mca_read_key
|
||||||
@@ -126,8 +137,8 @@ mca_pause() {
|
|||||||
# _mca_row <label> <value>
|
# _mca_row <label> <value>
|
||||||
# printf's %-28s pads by bytes, so a label containing "ü" comes out one column
|
# printf's %-28s pads by bytes, so a label containing "ü" comes out one column
|
||||||
# short. ${#s} counts characters in a UTF-8 locale, so the padding is computed
|
# short. ${#s} counts characters in a UTF-8 locale, so the padding is computed
|
||||||
# here instead - and applied inline, because command substitution would eat the
|
# here instead. It is applied inline, because command substitution would eat
|
||||||
# trailing spaces again.
|
# the trailing spaces again.
|
||||||
_mca_row() {
|
_mca_row() {
|
||||||
local label="$1" value="$2" pad
|
local label="$1" value="$2" pad
|
||||||
pad=$(( 30 - ${#label} ))
|
pad=$(( 30 - ${#label} ))
|
||||||
@@ -172,13 +183,13 @@ mca_ui_status() {
|
|||||||
|
|
||||||
if (( MCA_N_UNKNOWN )); then
|
if (( MCA_N_UNKNOWN )); then
|
||||||
_mca_row "$(mca_msg "Not identified")" \
|
_mca_row "$(mca_msg "Not identified")" \
|
||||||
"${MCA_C_DIM}$(mca_msg "%d - see the applications list" "$MCA_N_UNKNOWN")${MCA_C_RESET}"
|
"${MCA_C_DIM}$(mca_msg "%d (see the applications list)" "$MCA_N_UNKNOWN")${MCA_C_RESET}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if mca_steam_installed; then
|
if mca_steam_installed; then
|
||||||
if mca_steam_patched; then
|
if mca_steam_patched; then
|
||||||
_mca_row "$(mca_msg "Steam")" "$(_mca_onoff yes)"
|
_mca_row "$(mca_msg "Steam")" "$(_mca_onoff yes)"
|
||||||
elif [[ $CFG_STEAM == yes && $CFG_ENABLED == yes ]]; then
|
elif [[ $CFG_ENABLED == yes ]] && mca_steam_wanted; then
|
||||||
_mca_row "$(mca_msg "Steam")" \
|
_mca_row "$(mca_msg "Steam")" \
|
||||||
"${MCA_C_YELLOW}$(mca_msg "not patched yet")${MCA_C_RESET}"
|
"${MCA_C_YELLOW}$(mca_msg "not patched yet")${MCA_C_RESET}"
|
||||||
else
|
else
|
||||||
@@ -194,6 +205,18 @@ mca_ui_status() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Not an ON/OFF like the rows around it: what is being reported is the state
|
||||||
|
# of the paste, not of a switch, and off is the state this program is after.
|
||||||
|
if mca_kde_available; then
|
||||||
|
if [[ "$(mca_kde_read)" == false ]]; then
|
||||||
|
_mca_row "$(mca_msg "Middle-click paste")" \
|
||||||
|
"${MCA_C_GREEN}$(mca_msg "off")${MCA_C_RESET}"
|
||||||
|
else
|
||||||
|
_mca_row "$(mca_msg "Middle-click paste")" \
|
||||||
|
"${MCA_C_DIM}$(mca_msg "on")${MCA_C_RESET}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
_mca_row "$(mca_msg "Last applied")" "$(mca_time_ago "$last")"
|
_mca_row "$(mca_msg "Last applied")" "$(mca_time_ago "$last")"
|
||||||
|
|
||||||
if [[ $CFG_ENABLED == yes ]]; then
|
if [[ $CFG_ENABLED == yes ]]; then
|
||||||
@@ -206,17 +229,16 @@ mca_ui_status() {
|
|||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Settings
|
# Settings
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Format: Key|type|default|label-msgid
|
# Only what is not about one application. Which applications get autoscroll is
|
||||||
# type is bool or text.
|
# decided in the applications list.
|
||||||
|
#
|
||||||
|
# Format: Key|type|default|check|label-msgid|help-msgid
|
||||||
|
# type is bool or text. The row is only shown when the check passes: a switch
|
||||||
|
# for something this system does not have is only noise.
|
||||||
MCA_SETTINGS=(
|
MCA_SETTINGS=(
|
||||||
"PatchApps|bool|yes|Electron and CEF applications"
|
"DisablePaste|bool|yes|mca_kde_available|Turn off middle-click paste|Stops middle click from pasting anywhere else. Starts with the next login."
|
||||||
"PatchBrowsers|bool|yes|Chromium-based browsers"
|
"WatchNewApps|bool|yes|mca_watch_available|Cover new applications|Applications installed later get autoscroll on their own."
|
||||||
"PatchFlatpak|bool|yes|Flatpak applications"
|
"ExtraFlags|text|||More Chromium arguments|Passed to every application along with the autoscroll one."
|
||||||
"PatchAutostart|bool|yes|Programs that start themselves at login"
|
|
||||||
"PatchSteam|bool|yes|Steam"
|
|
||||||
"PatchSpotify|bool|yes|Spotify"
|
|
||||||
"WatchNewApps|bool|yes|Apply to newly installed applications"
|
|
||||||
"ExtraFlags|text||Additional Chromium arguments"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
_mca_is_true() {
|
_mca_is_true() {
|
||||||
@@ -261,10 +283,9 @@ _mca_setting_display() {
|
|||||||
#
|
#
|
||||||
# Returns 0 when something was changed, so the caller knows to re-apply.
|
# Returns 0 when something was changed, so the caller knows to re-apply.
|
||||||
mca_ui_settings() {
|
mca_ui_settings() {
|
||||||
local count=${#MCA_SETTINGS[@]}
|
local -a names=() types=() defaults=() labels=() helps=() values=()
|
||||||
local -a names=() types=() defaults=() labels=() values=()
|
local spec name type default check label help locale i key frame row pad
|
||||||
local spec name type default label locale i key frame row pad dirty=1 cursor=0
|
local count width=0 dirty=1 cursor=0 touched=0
|
||||||
local touched=0
|
|
||||||
|
|
||||||
locale="$(mca_ui_locale)"
|
locale="$(mca_ui_locale)"
|
||||||
mca_msg_into "$locale" "ON"; MCA_LBL_ON="$MCA_MSG_RESULT"
|
mca_msg_into "$locale" "ON"; MCA_LBL_ON="$MCA_MSG_RESULT"
|
||||||
@@ -272,15 +293,20 @@ mca_ui_settings() {
|
|||||||
mca_msg_into "$locale" "(none)"; MCA_LBL_NONE="$MCA_MSG_RESULT"
|
mca_msg_into "$locale" "(none)"; MCA_LBL_NONE="$MCA_MSG_RESULT"
|
||||||
|
|
||||||
for spec in "${MCA_SETTINGS[@]}"; do
|
for spec in "${MCA_SETTINGS[@]}"; do
|
||||||
IFS='|' read -r name type default label <<< "$spec"
|
IFS='|' read -r name type default check label help <<< "$spec"
|
||||||
|
[[ -z $check ]] || "$check" || continue
|
||||||
names+=("$name"); types+=("$type"); defaults+=("$default")
|
names+=("$name"); types+=("$type"); defaults+=("$default")
|
||||||
mca_msg_into "$locale" "$label"
|
mca_msg_into "$locale" "$label"
|
||||||
labels+=("$MCA_MSG_RESULT")
|
labels+=("$MCA_MSG_RESULT")
|
||||||
|
(( ${#MCA_MSG_RESULT} > width )) && width=${#MCA_MSG_RESULT}
|
||||||
|
mca_msg_into "$locale" "$help"
|
||||||
|
helps+=("$MCA_MSG_RESULT")
|
||||||
done
|
done
|
||||||
|
count=${#names[@]}
|
||||||
|
|
||||||
local title hint
|
local title hint
|
||||||
mca_msg_into "$locale" "Settings"; title="$MCA_MSG_RESULT"
|
mca_msg_into "$locale" "Settings"; title="$MCA_MSG_RESULT"
|
||||||
mca_msg_into "$locale" "Up/Down select - Space or Right changes - q goes back"
|
mca_msg_into "$locale" "Up/Down: select, Space: change, q: back"
|
||||||
hint="$MCA_MSG_RESULT"
|
hint="$MCA_MSG_RESULT"
|
||||||
|
|
||||||
local clearseq
|
local clearseq
|
||||||
@@ -300,7 +326,7 @@ mca_ui_settings() {
|
|||||||
local marker selected="${MCA_C_BLUE}▸${MCA_C_RESET} "
|
local marker selected="${MCA_C_BLUE}▸${MCA_C_RESET} "
|
||||||
for i in "${!names[@]}"; do
|
for i in "${!names[@]}"; do
|
||||||
_mca_setting_display "${types[i]}" "${values[i]}"
|
_mca_setting_display "${types[i]}" "${values[i]}"
|
||||||
pad=$(( 46 - ${#labels[i]} ))
|
pad=$(( width + 3 - ${#labels[i]} ))
|
||||||
(( pad < 0 )) && pad=0
|
(( pad < 0 )) && pad=0
|
||||||
if (( i == cursor )); then marker="$selected"; else marker=' '; fi
|
if (( i == cursor )); then marker="$selected"; else marker=' '; fi
|
||||||
printf -v row ' %s%s%*s %s' \
|
printf -v row ' %s%s%*s %s' \
|
||||||
@@ -308,6 +334,7 @@ mca_ui_settings() {
|
|||||||
frame+="$row"$'\n'
|
frame+="$row"$'\n'
|
||||||
done
|
done
|
||||||
|
|
||||||
|
frame+=$'\n'" ${helps[cursor]}"$'\n'
|
||||||
frame+=$'\n'" ${MCA_C_DIM}${hint}${MCA_C_RESET}"$'\n'
|
frame+=$'\n'" ${MCA_C_DIM}${hint}${MCA_C_RESET}"$'\n'
|
||||||
printf '%s' "$frame"
|
printf '%s' "$frame"
|
||||||
|
|
||||||
@@ -364,20 +391,29 @@ mca_ui_edit_text() {
|
|||||||
# turned on, and where a single application gets left out without having to
|
# turned on, and where a single application gets left out without having to
|
||||||
# switch off its whole category.
|
# switch off its whole category.
|
||||||
#
|
#
|
||||||
|
# The screen opens on a search field above the list, so typing filters it
|
||||||
|
# right away. The field is row -1: Down leaves it, Up from the top returns.
|
||||||
|
#
|
||||||
# Returns 0 when something was changed.
|
# Returns 0 when something was changed.
|
||||||
mca_ui_apps() {
|
mca_ui_apps() {
|
||||||
local count key frame row pad i cursor=0 dirty=1 touched=0 locale
|
local count key frame row pad i idx cursor=-1 dirty=1 touched=0 locale query='' needle
|
||||||
local -a labels=() states=()
|
local footer flines size rows height top=0
|
||||||
|
local -a labels=() lower=() states=() matches=()
|
||||||
|
|
||||||
locale="$(mca_ui_locale)"
|
locale="$(mca_ui_locale)"
|
||||||
|
|
||||||
local title hint legend warn
|
local title hint legend warn
|
||||||
mca_msg_into "$locale" "Applications"; title="$MCA_MSG_RESULT"
|
mca_msg_into "$locale" "Applications"; title="$MCA_MSG_RESULT"
|
||||||
mca_msg_into "$locale" "Up/Down select - Space turns one on or off - q goes back"
|
mca_msg_into "$locale" "Up/Down: select, Space: turn on or off, q: back"
|
||||||
hint="$MCA_MSG_RESULT"
|
hint="$MCA_MSG_RESULT"
|
||||||
mca_msg_into "$locale" "Anything not identified is left alone until it is turned on here."
|
local l_search hint_search nomatch
|
||||||
|
mca_msg_into "$locale" "Search:"; l_search="$MCA_MSG_RESULT"
|
||||||
|
mca_msg_into "$locale" "Type to search, Down: go to the list, Esc: back"
|
||||||
|
hint_search="$MCA_MSG_RESULT"
|
||||||
|
mca_msg_into "$locale" "No matches."; nomatch="$MCA_MSG_RESULT"
|
||||||
|
mca_msg_into "$locale" 'Anything marked "cannot tell" stays off until it is turned on here.'
|
||||||
legend="$MCA_MSG_RESULT"
|
legend="$MCA_MSG_RESULT"
|
||||||
mca_msg_into "$locale" "Autoscroll is off - this is what would be covered."
|
mca_msg_into "$locale" "Autoscroll is off. This is what would be covered."
|
||||||
warn="$MCA_MSG_RESULT"
|
warn="$MCA_MSG_RESULT"
|
||||||
|
|
||||||
# The per-row labels are resolved once, here. Looking them up inside the
|
# The per-row labels are resolved once, here. Looking them up inside the
|
||||||
@@ -397,6 +433,7 @@ mca_ui_apps() {
|
|||||||
local s_steam="${s_on} ${MCA_C_DIM}(${l_steam})${MCA_C_RESET}"
|
local s_steam="${s_on} ${MCA_C_DIM}(${l_steam})${MCA_C_RESET}"
|
||||||
local s_flags="${s_on} ${MCA_C_DIM}(${l_flagfile})${MCA_C_RESET}"
|
local s_flags="${s_on} ${MCA_C_DIM}(${l_flagfile})${MCA_C_RESET}"
|
||||||
local s_desktop="${s_on} ${MCA_C_DIM}(${l_launcher})${MCA_C_RESET}"
|
local s_desktop="${s_on} ${MCA_C_DIM}(${l_launcher})${MCA_C_RESET}"
|
||||||
|
local s_spotify="${s_on} ${MCA_C_DIM}(spotify-launcher)${MCA_C_RESET}"
|
||||||
|
|
||||||
local clearseq
|
local clearseq
|
||||||
clearseq="$(clear 2>/dev/null)" || clearseq=$'\033[H\033[2J'
|
clearseq="$(clear 2>/dev/null)" || clearseq=$'\033[H\033[2J'
|
||||||
@@ -407,8 +444,7 @@ mca_ui_apps() {
|
|||||||
count=${#MCA_IDS[@]}
|
count=${#MCA_IDS[@]}
|
||||||
|
|
||||||
if (( count == 0 )); then
|
if (( count == 0 )); then
|
||||||
printf '\n %s\n' "$(mca_msg "No Chromium-based applications found.")"
|
MCA_UI_MSG="$(mca_msg "No Chromium-based applications found.")"
|
||||||
mca_pause
|
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -416,56 +452,132 @@ mca_ui_apps() {
|
|||||||
if (( dirty )); then
|
if (( dirty )); then
|
||||||
mca_config_load
|
mca_config_load
|
||||||
mca_count_routes
|
mca_count_routes
|
||||||
labels=(); states=()
|
labels=(); lower=(); states=()
|
||||||
for i in "${!MCA_IDS[@]}"; do
|
for i in "${!MCA_IDS[@]}"; do
|
||||||
labels+=("${MCA_NAMES[i]}")
|
labels+=("${MCA_NAMES[i]}")
|
||||||
|
row="${MCA_NAMES[i],,}"
|
||||||
|
lower+=("${row//ı/i}")
|
||||||
states+=("${MCA_ROUTES[i]}")
|
states+=("${MCA_ROUTES[i]}")
|
||||||
done
|
done
|
||||||
dirty=0
|
dirty=0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# In a Turkish locale I lowercases to a dotless ı, so "office" would
|
||||||
|
# not find ONLYOFFICE. Both sides fold it back to i.
|
||||||
|
needle="${query,,}"
|
||||||
|
needle="${needle//ı/i}"
|
||||||
|
matches=()
|
||||||
|
for i in "${!labels[@]}"; do
|
||||||
|
[[ ${lower[i]} == *"$needle"* ]] && matches+=("$i")
|
||||||
|
done
|
||||||
|
count=${#matches[@]}
|
||||||
|
(( cursor >= count )) && cursor=$(( count - 1 ))
|
||||||
|
|
||||||
|
# The footer is built first: the list gets the rows it leaves over.
|
||||||
|
footer='' flines=1
|
||||||
|
# Without this the list reads as a list of what is switched on, which
|
||||||
|
# it is not while the whole thing is off.
|
||||||
|
if [[ $CFG_ENABLED != yes ]]; then
|
||||||
|
footer+=" ${MCA_C_YELLOW}${warn}${MCA_C_RESET}"$'\n'
|
||||||
|
flines=$(( flines + 1 ))
|
||||||
|
fi
|
||||||
|
# Only needed while there is something it explains.
|
||||||
|
if (( MCA_N_UNKNOWN )); then
|
||||||
|
footer+=" ${MCA_C_DIM}${legend}${MCA_C_RESET}"$'\n'
|
||||||
|
flines=$(( flines + 1 ))
|
||||||
|
fi
|
||||||
|
if (( cursor < 0 )); then
|
||||||
|
footer+=" ${MCA_C_DIM}${hint_search}${MCA_C_RESET}"$'\n'
|
||||||
|
# Puts the terminal cursor at the end of the query (row 4).
|
||||||
|
printf -v row '\033[4;%dH' $(( 6 + ${#l_search} + ${#query} ))
|
||||||
|
footer+="$row"
|
||||||
|
else
|
||||||
|
footer+=" ${MCA_C_DIM}${hint}${MCA_C_RESET}"$'\n'
|
||||||
|
fi
|
||||||
|
|
||||||
|
# A list longer than the terminal would scroll the search field off
|
||||||
|
# the top. So only a window of it is drawn, and it follows the cursor.
|
||||||
|
# Five rows above the list, one below it, the footer, and the row the
|
||||||
|
# terminal cursor ends up on.
|
||||||
|
# A terminal that does not know its size says 0; then all of it is drawn.
|
||||||
|
size="$(stty size 2>/dev/null)"
|
||||||
|
rows="${size%% *}"
|
||||||
|
[[ $rows =~ ^[1-9][0-9]*$ ]] || rows=10000
|
||||||
|
height=$(( rows - 7 - flines ))
|
||||||
|
(( height < 1 )) && height=1
|
||||||
|
(( top > count - height )) && top=$(( count - height ))
|
||||||
|
(( top < 0 )) && top=0
|
||||||
|
if (( cursor >= 0 )); then
|
||||||
|
(( cursor < top )) && top=$cursor
|
||||||
|
(( cursor >= top + height )) && top=$(( cursor - height + 1 ))
|
||||||
|
fi
|
||||||
|
|
||||||
frame="$clearseq"$'\n'"${MCA_C_BOLD}${MCA_C_BLUE} ${title}${MCA_C_RESET}"$'\n\n'
|
frame="$clearseq"$'\n'"${MCA_C_BOLD}${MCA_C_BLUE} ${title}${MCA_C_RESET}"$'\n\n'
|
||||||
|
|
||||||
local marker selected="${MCA_C_BLUE}▸${MCA_C_RESET} " shown
|
local marker selected="${MCA_C_BLUE}▸${MCA_C_RESET} " shown
|
||||||
for i in "${!labels[@]}"; do
|
if (( cursor < 0 )); then marker="$selected"; else marker=' '; fi
|
||||||
case "${states[i]}" in
|
frame+=" ${marker}${l_search} ${query}"$'\n\n'
|
||||||
|
|
||||||
|
for (( i = top; i < count && i < top + height; i++ )); do
|
||||||
|
idx=${matches[i]}
|
||||||
|
case "${states[idx]}" in
|
||||||
off) shown="$s_off" ;;
|
off) shown="$s_off" ;;
|
||||||
unknown) shown="$s_cannot" ;;
|
unknown) shown="$s_cannot" ;;
|
||||||
steam) shown="$s_steam" ;;
|
steam) shown="$s_steam" ;;
|
||||||
flags) shown="$s_flags" ;;
|
flags) shown="$s_flags" ;;
|
||||||
|
spotify) shown="$s_spotify" ;;
|
||||||
*) shown="$s_desktop" ;;
|
*) shown="$s_desktop" ;;
|
||||||
esac
|
esac
|
||||||
pad=$(( 34 - ${#labels[i]} ))
|
pad=$(( 34 - ${#labels[idx]} ))
|
||||||
(( pad < 0 )) && pad=0
|
(( pad < 0 )) && pad=0
|
||||||
if (( i == cursor )); then marker="$selected"; else marker=' '; fi
|
if (( i == cursor )); then marker="$selected"; else marker=' '; fi
|
||||||
printf -v row ' %s%s%*s %s' "$marker" "${labels[i]}" "$pad" '' "$shown"
|
printf -v row ' %s%s%*s %s' "$marker" "${labels[idx]}" "$pad" '' "$shown"
|
||||||
frame+="$row"$'\n'
|
frame+="$row"$'\n'
|
||||||
done
|
done
|
||||||
|
(( count )) || frame+=" ${MCA_C_DIM}${nomatch}${MCA_C_RESET}"$'\n'
|
||||||
|
|
||||||
|
# Where the window is, in the row under it, when there is more.
|
||||||
|
if (( count > height )); then
|
||||||
|
frame+=" ${MCA_C_DIM}$(( top + 1 ))–$(( i )) / ${count}${MCA_C_RESET}"$'\n'
|
||||||
|
else
|
||||||
frame+=$'\n'
|
frame+=$'\n'
|
||||||
# Without this the list reads as a list of what is switched on, which
|
|
||||||
# it is not while the whole thing is off.
|
|
||||||
if [[ $CFG_ENABLED != yes ]]; then
|
|
||||||
frame+=" ${MCA_C_YELLOW}${warn}${MCA_C_RESET}"$'\n'
|
|
||||||
fi
|
fi
|
||||||
frame+=" ${MCA_C_DIM}${legend}${MCA_C_RESET}"$'\n'
|
frame+="$footer"
|
||||||
frame+=" ${MCA_C_DIM}${hint}${MCA_C_RESET}"$'\n'
|
|
||||||
printf '%s' "$frame"
|
printf '%s' "$frame"
|
||||||
|
|
||||||
key="$(mca_read_key)" || return "$(( ! touched ))"
|
key="$(mca_read_key)" || return "$(( ! touched ))"
|
||||||
|
|
||||||
|
# In the search field every key that can be typed goes into the query,
|
||||||
|
# q and the vi keys too.
|
||||||
|
if (( cursor < 0 )); then
|
||||||
case "$key" in
|
case "$key" in
|
||||||
up|k) cursor=$(( (cursor - 1 + count) % count )) ;;
|
down|enter) (( count )) && cursor=0 ;;
|
||||||
down|j) cursor=$(( (cursor + 1) % count )) ;;
|
up) cursor=$(( count - 1 )) ;;
|
||||||
|
backspace) query="${query%?}" ;;
|
||||||
|
space) query+=' ' ;;
|
||||||
|
escape)
|
||||||
|
[[ -z $query ]] && return "$(( ! touched ))"
|
||||||
|
query=''
|
||||||
|
;;
|
||||||
|
left|right) ;;
|
||||||
|
*) [[ $key == [[:print:]] ]] && query+="$key" ;;
|
||||||
|
esac
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
idx=${matches[cursor]}
|
||||||
|
case "$key" in
|
||||||
|
up|k) cursor=$(( cursor - 1 )) ;;
|
||||||
|
down|j) cursor=$(( cursor + 1 < count ? cursor + 1 : -1 )) ;;
|
||||||
space|enter|right|left|l|h)
|
space|enter|right|left|l|h)
|
||||||
case "${states[cursor]}" in
|
case "${states[idx]}" in
|
||||||
off|unknown)
|
off|unknown)
|
||||||
mca_config_list_del Skip "${MCA_IDS[cursor]}"
|
mca_config_list_del Skip "${MCA_IDS[idx]}"
|
||||||
mca_config_list_add Include "${MCA_IDS[cursor]}"
|
mca_config_list_add Include "${MCA_IDS[idx]}"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
mca_config_list_del Include "${MCA_IDS[cursor]}"
|
mca_config_list_del Include "${MCA_IDS[idx]}"
|
||||||
mca_config_list_add Skip "${MCA_IDS[cursor]}"
|
mca_config_list_add Skip "${MCA_IDS[idx]}"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
touched=1
|
touched=1
|
||||||
@@ -482,8 +594,9 @@ mca_ui_apps() {
|
|||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
mca_ui_menu() {
|
mca_ui_menu() {
|
||||||
local choice
|
local choice line
|
||||||
|
|
||||||
|
MCA_IN_MENU=1
|
||||||
mca_ui_term_raw
|
mca_ui_term_raw
|
||||||
trap 'mca_ui_term_restore' EXIT INT TERM
|
trap 'mca_ui_term_restore' EXIT INT TERM
|
||||||
|
|
||||||
@@ -494,8 +607,15 @@ mca_ui_menu() {
|
|||||||
mca_head " $MCA_PRETTY"
|
mca_head " $MCA_PRETTY"
|
||||||
mca_ui_status
|
mca_ui_status
|
||||||
printf '\n'
|
printf '\n'
|
||||||
|
if [[ -n $MCA_UI_MSG ]]; then
|
||||||
|
while IFS= read -r line; do
|
||||||
|
printf ' %s\n' "$line"
|
||||||
|
done <<< "$MCA_UI_MSG"
|
||||||
|
printf '\n'
|
||||||
|
MCA_UI_MSG=''
|
||||||
|
fi
|
||||||
printf ' [1] %s\n' "$(mca_msg "Turn autoscroll on or off")"
|
printf ' [1] %s\n' "$(mca_msg "Turn autoscroll on or off")"
|
||||||
printf ' [2] %s\n' "$(mca_msg "Apply now")"
|
printf ' [2] %s\n' "$(mca_msg "Re-apply everything")"
|
||||||
printf ' [3] %s\n' "$(mca_msg "Applications")"
|
printf ' [3] %s\n' "$(mca_msg "Applications")"
|
||||||
printf ' [4] %s\n' "$(mca_msg "Settings")"
|
printf ' [4] %s\n' "$(mca_msg "Settings")"
|
||||||
printf ' [q] %s\n' "$(mca_msg "Quit")"
|
printf ' [q] %s\n' "$(mca_msg "Quit")"
|
||||||
@@ -511,30 +631,33 @@ mca_ui_menu() {
|
|||||||
|
|
||||||
case "$choice" in
|
case "$choice" in
|
||||||
1)
|
1)
|
||||||
MCA_UI_NEEDS_ACK=''
|
|
||||||
if [[ $CFG_ENABLED == yes ]]; then
|
if [[ $CFG_ENABLED == yes ]]; then
|
||||||
mca_ui_cooked mca_do_disable
|
mca_ui_run mca_do_disable
|
||||||
else
|
else
|
||||||
mca_ui_cooked mca_do_enable
|
mca_ui_run mca_do_enable
|
||||||
fi
|
fi
|
||||||
[[ -n $MCA_UI_NEEDS_ACK ]] && mca_pause
|
|
||||||
;;
|
;;
|
||||||
|
# Not a plain apply: with the watcher running there is never
|
||||||
|
# anything left for one to do, and a menu entry that answers
|
||||||
|
# "already done" every time is not an action. This is the repair -
|
||||||
|
# everything is taken back and written again from scratch, which is
|
||||||
|
# what fixes an application that drifted, a flag file somebody
|
||||||
|
# edited, or Steam after it restored its own script.
|
||||||
2)
|
2)
|
||||||
mca_ui_cooked mca_do_apply
|
mca_ui_run mca_do_apply --rebuild
|
||||||
mca_pause
|
|
||||||
;;
|
;;
|
||||||
3)
|
3)
|
||||||
if mca_ui_apps; then
|
if mca_ui_apps; then
|
||||||
[[ $CFG_ENABLED == yes ]] && mca_ui_cooked mca_do_apply --changed
|
[[ $CFG_ENABLED == yes ]] && mca_ui_run mca_do_apply --rebuild
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
4)
|
4)
|
||||||
if mca_ui_settings; then
|
if mca_ui_settings; then
|
||||||
[[ $CFG_ENABLED == yes ]] && mca_ui_cooked mca_do_apply --changed
|
[[ $CFG_ENABLED == yes ]] && mca_ui_run mca_do_apply --rebuild
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
q|Q) mca_ui_term_restore; trap - EXIT INT TERM; return 0 ;;
|
q|Q) mca_ui_term_restore; trap - EXIT INT TERM; return 0 ;;
|
||||||
# Anything else - Enter, arrow keys, stray characters - just
|
# Anything else (Enter, arrow keys, stray characters) just
|
||||||
# redraws. Escape is deliberately not a quit key, so a mistyped
|
# redraws. Escape is deliberately not a quit key, so a mistyped
|
||||||
# arrow key cannot close the menu.
|
# arrow key cannot close the menu.
|
||||||
*) ;;
|
*) ;;
|
||||||
|
|||||||
+289
-74
@@ -4,21 +4,65 @@
|
|||||||
#
|
#
|
||||||
# There are two ways in, and the order matters:
|
# There are two ways in, and the order matters:
|
||||||
#
|
#
|
||||||
# 1. A flag file. Arch's Electron and Chromium wrappers read extra arguments
|
# 1. A flag file. Some distributions wrap Electron and Chromium in a
|
||||||
# from $XDG_CONFIG_HOME/<name>-flags.conf. This is the good one - it is the
|
# launcher script that reads extra arguments from
|
||||||
# supported way to pass arguments, it survives package upgrades untouched,
|
# $XDG_CONFIG_HOME/<name>-flags.conf. Arch and its derivatives do, and
|
||||||
# and it applies however the program is started, including from a terminal.
|
# their packages follow that convention. Where it exists, this is the good
|
||||||
|
# way in: it is the supported way to pass arguments, it survives package upgrades
|
||||||
|
# untouched, and it applies however the program is started, including from
|
||||||
|
# a terminal.
|
||||||
|
#
|
||||||
|
# Nothing is assumed about which distribution this is. The launcher itself
|
||||||
|
# is read, and the route is taken only for a launcher that really does
|
||||||
|
# name such a file. On Debian, Ubuntu, Fedora and openSUSE the
|
||||||
|
# equivalent file lives under /etc and is the system's to write. There is
|
||||||
|
# no flag file to use there, and route 2 answers for everything.
|
||||||
#
|
#
|
||||||
# 2. A desktop entry. For applications that ship their own binary with no
|
# 2. A desktop entry. For applications that ship their own binary with no
|
||||||
# wrapper - most vendor packages, every Flatpak - there is nowhere else to
|
# wrapper, and for everything a Flatpak or a snap contains, there is
|
||||||
# put an argument, so a copy of the entry with the flag appended goes into
|
# nowhere else to put an argument, so a copy of the entry with the flag
|
||||||
# ~/.local/share/applications, where it shadows the system one.
|
# appended goes into ~/.local/share/applications, where it shadows the
|
||||||
|
# system one.
|
||||||
#
|
#
|
||||||
# Nothing outside $HOME is ever written to.
|
# Nothing outside $HOME is ever written to.
|
||||||
|
|
||||||
MCA_MARK_BEGIN='# >>> middleclick-autoscroll'
|
MCA_MARK_BEGIN='# >>> middleclick-autoscroll'
|
||||||
MCA_MARK_END='# <<< middleclick-autoscroll'
|
MCA_MARK_END='# <<< middleclick-autoscroll'
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Feature lists
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Both --enable-features and --enable-blink-features take a comma separated
|
||||||
|
# list, and Chromium keeps the last one it is given and drops the rest. A
|
||||||
|
# second one of the same kind would therefore silently switch off whatever the
|
||||||
|
# first one turned on, so an option that is already there is extended instead.
|
||||||
|
|
||||||
|
# _mca_list_merge <list> <wanted>
|
||||||
|
# The two lists as one, in the order they came and without repeating anything.
|
||||||
|
_mca_list_merge() {
|
||||||
|
local out="$1" item
|
||||||
|
for item in ${2//,/ }; do
|
||||||
|
[[ ",$out," == *",$item,"* ]] && continue
|
||||||
|
out="${out:+$out,}$item"
|
||||||
|
done
|
||||||
|
printf '%s' "$out"
|
||||||
|
}
|
||||||
|
|
||||||
|
# _mca_list_strip <list> <unwanted>
|
||||||
|
# The list without any of the named entries.
|
||||||
|
_mca_list_strip() {
|
||||||
|
local out='' item
|
||||||
|
for item in ${1//,/ }; do
|
||||||
|
[[ ",$2," == *",$item,"* ]] && continue
|
||||||
|
out="${out:+$out,}$item"
|
||||||
|
done
|
||||||
|
printf '%s' "$out"
|
||||||
|
}
|
||||||
|
|
||||||
|
# The two options, as a regular expression branch, for the places that have to
|
||||||
|
# recognise either of them.
|
||||||
|
MCA_FEATURE_OPTS='--enable-blink-features|--enable-features'
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Command lines
|
# Command lines
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -27,6 +71,11 @@ MCA_MARK_END='# <<< middleclick-autoscroll'
|
|||||||
# Where an argument has to go: after the program and its own arguments, but
|
# Where an argument has to go: after the program and its own arguments, but
|
||||||
# before the first field code (%U and friends) or Flatpak's @@ markers, which
|
# before the first field code (%U and friends) or Flatpak's @@ markers, which
|
||||||
# are placeholders the launcher expands rather than arguments.
|
# are placeholders the launcher expands rather than arguments.
|
||||||
|
#
|
||||||
|
# A bare "--" stops it too. That is where Chromium stops reading switches and
|
||||||
|
# starts treating everything as an address, so a flag put after it is read as a
|
||||||
|
# page to open and the feature never comes on. Discord's entry is exactly that
|
||||||
|
# shape: `discord --url -- %u`.
|
||||||
_mca_exec_insert_at() {
|
_mca_exec_insert_at() {
|
||||||
local rest="$1" tok idx=0
|
local rest="$1" tok idx=0
|
||||||
|
|
||||||
@@ -35,7 +84,7 @@ _mca_exec_insert_at() {
|
|||||||
[[ -n $rest ]] || break
|
[[ -n $rest ]] || break
|
||||||
tok="${rest%% *}"
|
tok="${rest%% *}"
|
||||||
case "$tok" in
|
case "$tok" in
|
||||||
%[a-zA-Z]|@@|@@u) printf '%s\n' "$idx"; return 0 ;;
|
%[a-zA-Z]|@@|@@u|--) printf '%s\n' "$idx"; return 0 ;;
|
||||||
esac
|
esac
|
||||||
rest="${rest:${#tok}}"
|
rest="${rest:${#tok}}"
|
||||||
idx=$(( idx + ${#tok} ))
|
idx=$(( idx + ${#tok} ))
|
||||||
@@ -60,28 +109,32 @@ _mca_exec_after_program() {
|
|||||||
# Prints nothing and returns 1 when there was nothing to change, so callers can
|
# Prints nothing and returns 1 when there was nothing to change, so callers can
|
||||||
# tell a real edit from a no-op without diffing.
|
# tell a real edit from a no-op without diffing.
|
||||||
#
|
#
|
||||||
# An --enable-blink-features that is already there is extended rather than
|
# A feature list that is already on the line is extended rather than repeated.
|
||||||
# repeated: Chromium keeps the last occurrence of the option and drops the
|
# See _mca_list_merge.
|
||||||
# rest, so a second one would silently disable whatever the first turned on.
|
|
||||||
mca_exec_inject() {
|
mca_exec_inject() {
|
||||||
local line="$1" flagstr="${2:-}" where="${3:-before-fields}"
|
local line="$1" flagstr="${2:-}" where="${3:-before-fields}"
|
||||||
local flag value existing at changed=0
|
local flag opt value existing merged re at changed=0
|
||||||
local -a flags
|
local -a flags
|
||||||
|
|
||||||
[[ -n $flagstr ]] || flagstr="$(mca_flags)"
|
[[ -n $flagstr ]] || flagstr="$(mca_flags)"
|
||||||
read -r -a flags <<< "$flagstr"
|
read -r -a flags <<< "$flagstr"
|
||||||
|
|
||||||
for flag in "${flags[@]}"; do
|
for flag in "${flags[@]}"; do
|
||||||
if [[ $flag == --enable-blink-features=* ]]; then
|
case "$flag" in
|
||||||
value="${flag#--enable-blink-features=}"
|
--enable-blink-features=*|--enable-features=*)
|
||||||
if [[ $line =~ --enable-blink-features=([A-Za-z0-9,_-]*) ]]; then
|
opt="${flag%%=*}"
|
||||||
existing="${BASH_REMATCH[1]}"
|
value="${flag#*=}"
|
||||||
[[ ",$existing," == *",$value,"* ]] && continue
|
re="(^|[[:space:]])$opt=([^[:space:]]*)"
|
||||||
line="${line/--enable-blink-features=$existing/--enable-blink-features=${existing:+$existing,}$value}"
|
if [[ $line =~ $re ]]; then
|
||||||
|
existing="${BASH_REMATCH[2]}"
|
||||||
|
merged="$(_mca_list_merge "$existing" "$value")"
|
||||||
|
[[ $merged == "$existing" ]] && continue
|
||||||
|
line="${line/$opt=$existing/$opt=$merged}"
|
||||||
changed=1
|
changed=1
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
fi
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
[[ " $line " == *" $flag "* ]] && continue
|
[[ " $line " == *" $flag "* ]] && continue
|
||||||
|
|
||||||
@@ -107,12 +160,12 @@ mca_exec_inject() {
|
|||||||
# Flag files
|
# Flag files
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
# mca_flags_apply <program>
|
# mca_flags_apply <program> [kind]
|
||||||
# Writes the flags into the file the program's launcher reads. Returns 0 when
|
# Writes the flags into the file the program's launcher reads. Returns 0 when
|
||||||
# the program has such a file (whether or not anything needed changing), 1 when
|
# the program has such a file (whether or not anything needed changing), 1 when
|
||||||
# it has none and the desktop entry route has to be used instead.
|
# it has none and the desktop entry route has to be used instead.
|
||||||
mca_flags_apply() {
|
mca_flags_apply() {
|
||||||
local prog="$1" name target='' existing_target=''
|
local prog="$1" kind="${2:-app}" name target='' existing_target=''
|
||||||
local -a candidates=()
|
local -a candidates=()
|
||||||
|
|
||||||
mapfile -t candidates < <(mca_flags_candidates "$prog" | awk '!seen[$0]++')
|
mapfile -t candidates < <(mca_flags_candidates "$prog" | awk '!seen[$0]++')
|
||||||
@@ -123,29 +176,31 @@ mca_flags_apply() {
|
|||||||
for name in "${candidates[@]}"; do
|
for name in "${candidates[@]}"; do
|
||||||
if [[ -f "$MCA_XDG_CONFIG/$name" ]]; then
|
if [[ -f "$MCA_XDG_CONFIG/$name" ]]; then
|
||||||
existing_target="$name"
|
existing_target="$name"
|
||||||
_mca_flags_write "$MCA_XDG_CONFIG/$name"
|
_mca_flags_write "$MCA_XDG_CONFIG/$name" "$kind"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
[[ -n $existing_target ]] && return 0
|
[[ -n $existing_target ]] && return 0
|
||||||
|
|
||||||
# None exists yet. The last candidate is the wrapper's own fallback - the
|
# None exists yet. The last candidate is the wrapper's own fallback (the
|
||||||
# generic electron-flags.conf rather than electron43-flags.conf - so
|
# generic electron-flags.conf rather than electron43-flags.conf). So
|
||||||
# creating that one also covers every other application using the same
|
# creating that one also covers every other application using the same
|
||||||
# shared Electron.
|
# shared Electron.
|
||||||
target="${candidates[-1]}"
|
target="${candidates[-1]}"
|
||||||
_mca_flags_write "$MCA_XDG_CONFIG/$target"
|
_mca_flags_write "$MCA_XDG_CONFIG/$target" "$kind"
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
# _mca_flags_write <file>
|
# _mca_flags_write <file> [kind]
|
||||||
# Adds the flags as a marked block, or merges into an --enable-blink-features
|
# Adds the flags as a marked block, or merges into a feature list that is
|
||||||
# line that is already in the file.
|
# already in the file.
|
||||||
_mca_flags_write() {
|
_mca_flags_write() {
|
||||||
local file="$1" content='' line flag value existing merged=0 block=''
|
local file="$1" kind="${2:-app}"
|
||||||
|
local content='' line flag opt want existing merged=0 block=''
|
||||||
local -a flags
|
local -a flags
|
||||||
|
local -A merged_opts=()
|
||||||
local created=0
|
local created=0
|
||||||
|
|
||||||
read -r -a flags <<< "$(mca_flags)"
|
read -r -a flags <<< "$(mca_flags "$kind")"
|
||||||
|
|
||||||
[[ -f $file ]] || created=1
|
[[ -f $file ]] || created=1
|
||||||
if (( ! created )); then
|
if (( ! created )); then
|
||||||
@@ -156,24 +211,31 @@ _mca_flags_write() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Merge into a blink-features line the user (or a distribution) put there.
|
# Merge into a feature list the user (or a distribution) put there, rather
|
||||||
if [[ $content == *--enable-blink-features=* ]]; then
|
# than write a second line of the same option further down.
|
||||||
|
if [[ $content == *--enable-* ]]; then
|
||||||
local out=''
|
local out=''
|
||||||
while IFS= read -r line; do
|
while IFS= read -r line; do
|
||||||
if [[ $line =~ ^[[:space:]]*--enable-blink-features=([A-Za-z0-9,_-]*)[[:space:]]*$ ]]; then
|
if [[ $line =~ ^[[:space:]]*($MCA_FEATURE_OPTS)=([^[:space:]]*)[[:space:]]*$ ]]; then
|
||||||
existing="${BASH_REMATCH[1]}"
|
opt="${BASH_REMATCH[1]}"
|
||||||
if [[ ",$existing," != *",$MCA_FEATURE,"* ]]; then
|
existing="${BASH_REMATCH[2]}"
|
||||||
line="--enable-blink-features=${existing:+$existing,}$MCA_FEATURE"
|
want=''
|
||||||
fi
|
for flag in "${flags[@]}"; do
|
||||||
|
[[ $flag == "$opt="* ]] && want="${flag#*=}"
|
||||||
|
done
|
||||||
|
if [[ -n $want ]]; then
|
||||||
|
line="$opt=$(_mca_list_merge "$existing" "$want")"
|
||||||
|
merged_opts["$opt"]=1
|
||||||
merged=1
|
merged=1
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
out+="$line"$'\n'
|
out+="$line"$'\n'
|
||||||
done <<< "$content"
|
done <<< "$content"
|
||||||
content="${out%$'\n'}"
|
content="${out%$'\n'}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
for flag in "${flags[@]}"; do
|
for flag in "${flags[@]}"; do
|
||||||
(( merged )) && [[ $flag == --enable-blink-features=* ]] && continue
|
[[ -n ${merged_opts["${flag%%=*}"]:-} ]] && continue
|
||||||
block+="$flag"$'\n'
|
block+="$flag"$'\n'
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -208,7 +270,7 @@ _mca_flags_drop_block() {
|
|||||||
|
|
||||||
# mca_flags_revert <file> <detail>
|
# mca_flags_revert <file> <detail>
|
||||||
mca_flags_revert() {
|
mca_flags_revert() {
|
||||||
local file="$1" detail="$2" content line out='' existing new
|
local file="$1" detail="$2" content line out='' opt existing new
|
||||||
|
|
||||||
[[ -f $file ]] || return 0
|
[[ -f $file ]] || return 0
|
||||||
|
|
||||||
@@ -228,12 +290,13 @@ mca_flags_revert() {
|
|||||||
|
|
||||||
if [[ $detail == merged* ]]; then
|
if [[ $detail == merged* ]]; then
|
||||||
while IFS= read -r line; do
|
while IFS= read -r line; do
|
||||||
if [[ $line =~ ^[[:space:]]*--enable-blink-features=([A-Za-z0-9,_-]*)[[:space:]]*$ ]]; then
|
if [[ $line =~ ^[[:space:]]*($MCA_FEATURE_OPTS)=([^[:space:]]*)[[:space:]]*$ ]]; then
|
||||||
existing="${BASH_REMATCH[1]}"
|
opt="${BASH_REMATCH[1]}"
|
||||||
new="${existing//$MCA_FEATURE/}"
|
existing="${BASH_REMATCH[2]}"
|
||||||
new="${new//,,/,}"; new="${new#,}"; new="${new%,}"
|
# Either name, whichever version of this program put it there.
|
||||||
|
new="$(_mca_list_strip "$existing" "$MCA_BROWSER_FEATURES")"
|
||||||
[[ -z $new ]] && continue
|
[[ -z $new ]] && continue
|
||||||
line="--enable-blink-features=$new"
|
line="$opt=$new"
|
||||||
fi
|
fi
|
||||||
out+="$line"$'\n'
|
out+="$line"$'\n'
|
||||||
done <<< "$content"
|
done <<< "$content"
|
||||||
@@ -261,7 +324,7 @@ MCA_MARK_SHADOW='X-MCA-Generated'
|
|||||||
MCA_MARK_INPLACE='X-MCA-Patched'
|
MCA_MARK_INPLACE='X-MCA-Patched'
|
||||||
|
|
||||||
# _mca_desktop_transform <file> <marker> [flags] [position]
|
# _mca_desktop_transform <file> <marker> [flags] [position]
|
||||||
# The whole file with every Exec line rewritten - the main one and the one in
|
# The whole file with every Exec line rewritten: the main one and the one in
|
||||||
# each Desktop Action, because those are the right-click menu entries and a
|
# each Desktop Action, because those are the right-click menu entries and a
|
||||||
# user who starts Steam from "Library" expects the same behaviour there.
|
# user who starts Steam from "Library" expects the same behaviour there.
|
||||||
_mca_desktop_transform() {
|
_mca_desktop_transform() {
|
||||||
@@ -302,8 +365,8 @@ mca_desktop_apply() {
|
|||||||
local target="$MCA_APPDIR/$id.desktop" content backup
|
local target="$MCA_APPDIR/$id.desktop" content backup
|
||||||
|
|
||||||
if [[ "$src" == "$target" ]]; then
|
if [[ "$src" == "$target" ]]; then
|
||||||
# The user's own entry - an AppImage, a web app shortcut, something
|
# The user's own entry, like an AppImage, a web app shortcut or
|
||||||
# installed by hand. There is nowhere to shadow it from, so it is
|
# something installed by hand. There is nowhere to shadow it from, so it is
|
||||||
# edited directly and the original is kept.
|
# edited directly and the original is kept.
|
||||||
grep -q "^$MCA_MARK_INPLACE=" "$src" 2>/dev/null && return 0
|
grep -q "^$MCA_MARK_INPLACE=" "$src" 2>/dev/null && return 0
|
||||||
|
|
||||||
@@ -312,7 +375,7 @@ mca_desktop_apply() {
|
|||||||
[[ "$content" == "$(< "$src")" ]] && return 0
|
[[ "$content" == "$(< "$src")" ]] && return 0
|
||||||
|
|
||||||
backup="$(mca_backup "$src")" || return 1
|
backup="$(mca_backup "$src")" || return 1
|
||||||
if mca_write_if_changed "$src" "$content"$'\n'; then
|
if _mca_entry_write "$src" "$content"$'\n'; then
|
||||||
MCA_CHANGES=$(( MCA_CHANGES + 1 ))
|
MCA_CHANGES=$(( MCA_CHANGES + 1 ))
|
||||||
fi
|
fi
|
||||||
mca_ledger_add inplace "$src" "$backup"
|
mca_ledger_add inplace "$src" "$backup"
|
||||||
@@ -325,7 +388,7 @@ mca_desktop_apply() {
|
|||||||
mkdir -p "$MCA_APPDIR" 2>/dev/null || return 1
|
mkdir -p "$MCA_APPDIR" 2>/dev/null || return 1
|
||||||
|
|
||||||
# Something is already shadowing this entry. Unless it is a shadow of ours,
|
# Something is already shadowing this entry. Unless it is a shadow of ours,
|
||||||
# it is the user's own file - possibly one we edited in place earlier - and
|
# it is the user's own file (possibly one we edited in place earlier), and
|
||||||
# overwriting it here would lose it.
|
# overwriting it here would lose it.
|
||||||
if [[ -e $target ]] && ! grep -q "^$MCA_MARK_SHADOW=" "$target" 2>/dev/null; then
|
if [[ -e $target ]] && ! grep -q "^$MCA_MARK_SHADOW=" "$target" 2>/dev/null; then
|
||||||
return 1
|
return 1
|
||||||
@@ -339,38 +402,136 @@ mca_desktop_apply() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Autostart entries
|
# Entries outside the search path
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Applications that start themselves at login write their own entry into
|
# Two directories hold desktop entries that no part of the XDG search path
|
||||||
# ~/.config/autostart, pointing straight at their binary. Those bypass the
|
# looks at, so nothing the scan does can reach them:
|
||||||
# desktop entry in the menu completely, which is why Discord launched at login
|
#
|
||||||
# used to behave differently from Discord launched from the menu.
|
# ~/.config/autostart, where applications that start themselves at login
|
||||||
|
# write their own entry, pointing straight at their binary. Those bypass the
|
||||||
|
# entry in the menu completely, which is why Discord launched at login used
|
||||||
|
# to behave differently from Discord launched from the menu.
|
||||||
|
#
|
||||||
|
# The desktop folder, where a shortcut somebody dragged out of the menu
|
||||||
|
# (or asked Steam for) lives and nowhere else.
|
||||||
|
#
|
||||||
|
# Neither can be shadowed from anywhere, so both are edited where they stand,
|
||||||
|
# with the original kept.
|
||||||
|
|
||||||
|
# _mca_entry_write <file> <content>
|
||||||
|
# Writes an entry edited in place, like mca_write_if_changed. A symlink is
|
||||||
|
# replaced by the edited file instead of written through: it usually points at
|
||||||
|
# a package's entry in /usr, which is not ours to change. Undo puts the link
|
||||||
|
# back from the backup.
|
||||||
|
_mca_entry_write() {
|
||||||
|
local file="$1" content="$2" tmp
|
||||||
|
|
||||||
|
[[ -L $file ]] || { mca_write_if_changed "$file" "$content"; return; }
|
||||||
|
|
||||||
|
tmp="$(mktemp "$file.XXXXXX")" || return 2
|
||||||
|
chmod --reference="$file" -- "$tmp" 2>/dev/null || chmod 644 -- "$tmp"
|
||||||
|
|
||||||
|
# A link into /usr/share/applications is trusted for where it points. A
|
||||||
|
# copy on the desktop is only trusted by KDE when it can be run.
|
||||||
|
chmod u+x -- "$tmp" 2>/dev/null || true
|
||||||
|
|
||||||
|
if printf '%s' "$content" > "$tmp" && mv -f -- "$tmp" "$file"; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
rm -f -- "$tmp"
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
# _mca_entry_patch_inplace <file>
|
||||||
|
# One desktop entry that lives outside the XDG search path, edited where it is
|
||||||
|
# because there is nowhere to shadow it from. It follows the applications list
|
||||||
|
# under its own file name, which is the name of the application's own entry.
|
||||||
|
_mca_entry_patch_inplace() {
|
||||||
|
local file="$1"
|
||||||
|
local id prog packaging=native content backup kind copy
|
||||||
|
|
||||||
|
# Already ours, and normally that is the end of it: what is in there is what
|
||||||
|
# this version put there. Not so for a file the ledger has no record of -
|
||||||
|
# nothing would ever look at that one again, neither the undo a change of
|
||||||
|
# flags goes through nor this, which leaves a marked file alone, and it would
|
||||||
|
# keep an answer from an older version for good. The copy taken before the
|
||||||
|
# edit is named after the path and is still there, so the file goes back to
|
||||||
|
# what it was and is written again below.
|
||||||
|
if grep -q "^$MCA_MARK_INPLACE=" "$file" 2>/dev/null; then
|
||||||
|
mca_ledger_has "$file" && return 0
|
||||||
|
copy="$MCA_BACKUPDIR/$(mca_backup_name "$file")"
|
||||||
|
[[ -f $copy ]] || return 0
|
||||||
|
cp -p -- "$copy" "$file" 2>/dev/null || return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
_mca_desktop_read "$file"
|
||||||
|
[[ -n $DE_EXEC ]] || return 0
|
||||||
|
[[ $DE_HIDDEN == true ]] && return 0
|
||||||
|
|
||||||
|
mca_exec_program "$DE_EXEC" || return 0
|
||||||
|
prog="$MCA_PROG"
|
||||||
|
|
||||||
|
# A Flatpak or a snap entry names the wrapper rather than the application.
|
||||||
|
# The scan resolves those into an id; outside the scan the same has to
|
||||||
|
# happen here, or every Flatpak looks like the flatpak program itself.
|
||||||
|
if [[ ${prog##*/} == flatpak ]]; then
|
||||||
|
mca_exec_flatpak_id "$DE_EXEC" || return 0
|
||||||
|
prog="flatpak:$MCA_PROG"
|
||||||
|
packaging=flatpak
|
||||||
|
elif mca_snap_name "$prog"; then
|
||||||
|
prog="snap:$MCA_PROG"
|
||||||
|
packaging=snap
|
||||||
|
fi
|
||||||
|
|
||||||
|
# An entry that starts Steam is left where it is. Steam takes nothing
|
||||||
|
# from a command line that would help, and what it does take belongs to
|
||||||
|
# the web helper script in its own installation.
|
||||||
|
mca_prog_is_steam "$prog" && return 0
|
||||||
|
|
||||||
|
case "$packaging" in
|
||||||
|
flatpak) mca_flatpak_is_chromium "${prog#flatpak:}" || return 0 ;;
|
||||||
|
snap) mca_snap_is_chromium "${prog#snap:}" || return 0 ;;
|
||||||
|
*) mca_is_chromium "$prog" || return 0 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
mca_desktop_is_browser && kind=browser || kind=app
|
||||||
|
|
||||||
|
id="${file##*/}"; id="${id%.desktop}"
|
||||||
|
mca_kind_wanted "$kind" "$id" || return 0
|
||||||
|
|
||||||
|
content="$(_mca_desktop_transform "$file" "$MCA_MARK_INPLACE" \
|
||||||
|
"$(mca_flags "$kind")")"
|
||||||
|
|
||||||
|
[[ -n $content ]] || return 0
|
||||||
|
[[ "$content" == "$(< "$file")" ]] && return 0
|
||||||
|
|
||||||
|
backup="$(mca_backup "$file")" || return 0
|
||||||
|
if _mca_entry_write "$file" "$content"$'\n'; then
|
||||||
|
MCA_CHANGES=$(( MCA_CHANGES + 1 ))
|
||||||
|
fi
|
||||||
|
mca_ledger_add inplace "$file" "$backup"
|
||||||
|
}
|
||||||
|
|
||||||
mca_autostart_apply() {
|
mca_autostart_apply() {
|
||||||
local dir="$MCA_XDG_CONFIG/autostart" file exec_line prog content backup
|
local dir="$MCA_XDG_CONFIG/autostart" file
|
||||||
|
|
||||||
[[ -d $dir ]] || return 0
|
[[ -d $dir ]] || return 0
|
||||||
|
|
||||||
for file in "$dir"/*.desktop; do
|
for file in "$dir"/*.desktop; do
|
||||||
[[ -f $file ]] || continue
|
[[ -f $file ]] || continue
|
||||||
grep -q "^$MCA_MARK_INPLACE=" "$file" 2>/dev/null && continue
|
_mca_entry_patch_inplace "$file"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
exec_line="$(mca_desktop_get "$file" Exec)"
|
mca_shortcuts_apply() {
|
||||||
[[ -n $exec_line ]] || continue
|
local dir file
|
||||||
|
dir="$(mca_desktop_folder)"
|
||||||
|
|
||||||
mca_exec_program "$exec_line" || continue
|
[[ -d $dir ]] || return 0
|
||||||
prog="$MCA_PROG"
|
|
||||||
mca_is_chromium "$prog" || continue
|
|
||||||
|
|
||||||
content="$(_mca_desktop_transform "$file" "$MCA_MARK_INPLACE")"
|
for file in "$dir"/*.desktop; do
|
||||||
[[ -n $content ]] || continue
|
[[ -f $file ]] || continue
|
||||||
[[ "$content" == "$(< "$file")" ]] && continue
|
_mca_entry_patch_inplace "$file"
|
||||||
|
|
||||||
backup="$(mca_backup "$file")" || continue
|
|
||||||
if mca_write_if_changed "$file" "$content"$'\n'; then
|
|
||||||
MCA_CHANGES=$(( MCA_CHANGES + 1 ))
|
|
||||||
fi
|
|
||||||
mca_ledger_add inplace "$file" "$backup"
|
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,12 +579,59 @@ mca_spotify_apply() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Leftovers
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# mca_prune_orphans
|
||||||
|
# Forgets changes there is no longer anything to undo.
|
||||||
|
#
|
||||||
|
# Uninstalling something deletes its entry from /usr/share/applications, but the
|
||||||
|
# copy shadowing it is in the user's home and pacman knows nothing about it. It
|
||||||
|
# would sit in the menu forever, offering to start a program that is no longer
|
||||||
|
# installed. And the watcher would not notice, because a plain apply only ever
|
||||||
|
# looks at what is there now. A file that was edited where it stood and has
|
||||||
|
# since been deleted is the same problem from the other side: its record would
|
||||||
|
# have `disable` put the file back.
|
||||||
|
mca_prune_orphans() {
|
||||||
|
local kind path source line
|
||||||
|
local -a lines=()
|
||||||
|
|
||||||
|
[[ -f $MCA_LEDGER ]] || return 0
|
||||||
|
mapfile -t lines < "$MCA_LEDGER"
|
||||||
|
|
||||||
|
for line in "${lines[@]}"; do
|
||||||
|
IFS=$'\t' read -r kind path source <<< "$line"
|
||||||
|
|
||||||
|
# An entry that was edited where it stood and has since been deleted -
|
||||||
|
# a game shortcut dragged to the wastebasket, an autostart entry the
|
||||||
|
# application removed. There is nothing left to put back, and keeping
|
||||||
|
# the record would have `disable` recreate a file the user threw away.
|
||||||
|
if [[ $kind == inplace && ! -e $path ]]; then
|
||||||
|
[[ -n $source ]] && rm -f -- "$MCA_BACKUPDIR/$source"
|
||||||
|
mca_ledger_forget "$path"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ $kind == shadow && -n $source ]] || continue
|
||||||
|
[[ -e $source ]] && continue
|
||||||
|
|
||||||
|
# Only ever remove something still recognisably ours.
|
||||||
|
if [[ -f $path ]] && grep -q "^$MCA_MARK_SHADOW=" "$path" 2>/dev/null; then
|
||||||
|
rm -f -- "$path"
|
||||||
|
MCA_CHANGES=$(( MCA_CHANGES + 1 ))
|
||||||
|
fi
|
||||||
|
mca_ledger_forget "$path"
|
||||||
|
done
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Undo
|
# Undo
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
mca_revert_all() {
|
mca_revert_all() {
|
||||||
local kind path detail
|
local kind path detail backup
|
||||||
|
|
||||||
[[ -f $MCA_LEDGER ]] || return 0
|
[[ -f $MCA_LEDGER ]] || return 0
|
||||||
|
|
||||||
@@ -439,12 +647,15 @@ mca_revert_all() {
|
|||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
inplace)
|
inplace)
|
||||||
if [[ -n $detail && -f "$MCA_BACKUPDIR/$detail" ]]; then
|
backup="$MCA_BACKUPDIR/$detail"
|
||||||
|
if [[ -n $detail ]] && [[ -f $backup || -L $backup ]]; then
|
||||||
if [[ -e $path ]] || [[ -d "$(dirname -- "$path")" ]]; then
|
if [[ -e $path ]] || [[ -d "$(dirname -- "$path")" ]]; then
|
||||||
cp -p -- "$MCA_BACKUPDIR/$detail" "$path" 2>/dev/null \
|
# A link goes back as a link, not written through.
|
||||||
|
[[ -L $backup ]] && rm -f -- "$path"
|
||||||
|
cp -P -p -- "$backup" "$path" 2>/dev/null \
|
||||||
&& MCA_CHANGES=$(( MCA_CHANGES + 1 ))
|
&& MCA_CHANGES=$(( MCA_CHANGES + 1 ))
|
||||||
fi
|
fi
|
||||||
rm -f -- "$MCA_BACKUPDIR/$detail"
|
rm -f -- "$backup"
|
||||||
elif [[ -f $path ]]; then
|
elif [[ -f $path ]]; then
|
||||||
# No backup: the file did not exist before we wrote it.
|
# No backup: the file did not exist before we wrote it.
|
||||||
rm -f -- "$path"
|
rm -f -- "$path"
|
||||||
@@ -459,6 +670,10 @@ mca_revert_all() {
|
|||||||
mca_steam_revert "$path" "$detail" \
|
mca_steam_revert "$path" "$detail" \
|
||||||
&& MCA_CHANGES=$(( MCA_CHANGES + 1 ))
|
&& MCA_CHANGES=$(( MCA_CHANGES + 1 ))
|
||||||
;;
|
;;
|
||||||
|
kwin)
|
||||||
|
mca_kde_paste_revert "$path" "$detail" \
|
||||||
|
&& MCA_CHANGES=$(( MCA_CHANGES + 1 ))
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
done < <(tac "$MCA_LEDGER" 2>/dev/null)
|
done < <(tac "$MCA_LEDGER" 2>/dev/null)
|
||||||
|
|
||||||
|
|||||||
+271
-52
@@ -2,26 +2,50 @@
|
|||||||
#
|
#
|
||||||
# Steam.
|
# Steam.
|
||||||
#
|
#
|
||||||
# Steam's interface is CEF, so the feature is there - but Steam builds the
|
# Steam's interface is CEF, so the feature is there. But Steam builds the
|
||||||
# command line for its web helper itself and offers no way to add to it. The
|
# command line for its web helper itself and offers no way to add to it. The
|
||||||
# only place to get an argument in is the shell script that starts the helper,
|
# only place to get an argument in is the shell script that starts the helper,
|
||||||
# which lives inside Steam's own installation:
|
# which lives inside Steam's own installation:
|
||||||
#
|
#
|
||||||
# ~/.local/share/Steam/ubuntu12_64/steamwebhelper_sniper_wrap.sh
|
# ~/.local/share/Steam/ubuntu12_64/steamwebhelper_sniper_wrap.sh
|
||||||
#
|
#
|
||||||
# Steam checksums that script at every start and restores it when it differs,
|
# The steamrt3 client, a beta for now, has a script of its own:
|
||||||
# which is why the launcher gets -noverifyfiles as well. The trade-off is real
|
#
|
||||||
# and belongs to the user, so this is a switch of its own rather than part of
|
# ~/.local/share/Steam/steamrt64/steamwebhelper.sh
|
||||||
# the general application handling: with verification off, Steam no longer
|
#
|
||||||
# repairs a damaged installation by itself.
|
# Steam compares the installed files against its manifest at every start (by
|
||||||
|
# size and timestamp, not by content) and restores whatever differs.
|
||||||
|
# So the patch is written to look untouched: the bytes the flag costs are taken
|
||||||
|
# back out of the script's comments and the timestamp is put back afterwards,
|
||||||
|
# which leaves a file that is byte-for-byte the size Steam recorded and as old
|
||||||
|
# as Steam left it. A client that verifies its files finds nothing to repair
|
||||||
|
# and the flag survives however Steam was started: from the menu, from a game
|
||||||
|
# shortcut, from a launcher like Heroic, or from a terminal.
|
||||||
|
#
|
||||||
|
# A patch that changes the length is not an option, and no switch covers for
|
||||||
|
# one. Steam checks its files at a start it was given arguments for, but also
|
||||||
|
# at the shutdown it runs itself. That one has no -noverifyfiles on its
|
||||||
|
# command line, whatever the session was started with. What a single wrong
|
||||||
|
# length costs is the whole client package downloaded, extracted and installed
|
||||||
|
# again, and a client that quits at the end of it instead of coming up. So the
|
||||||
|
# flag either fits in the space the comments give back, or it is not written at
|
||||||
|
# all: no autoscroll in the interface is a smaller thing than a client that
|
||||||
|
# reinstalls itself.
|
||||||
|
#
|
||||||
|
# The steamrt3 script has no comments to give back. So it is copied aside, as
|
||||||
|
# it is, and replaced by a stub of the same size that runs the copy with the
|
||||||
|
# flag. See _mca_steam_stub.
|
||||||
#
|
#
|
||||||
# The file comes back on every client update, and the watcher re-applies the
|
# The file comes back on every client update, and the watcher re-applies the
|
||||||
# patch when that happens.
|
# patch when that happens.
|
||||||
|
|
||||||
MCA_STEAM_LAUNCH_FLAG='-noverifyfiles'
|
|
||||||
|
|
||||||
# Every place a Steam installation is known to live, resolved and de-duplicated
|
# Every place a Steam installation is known to live, resolved and de-duplicated
|
||||||
# because ~/.steam/steam is normally a symlink into ~/.local/share.
|
# because ~/.steam/steam is normally a symlink into ~/.local/share.
|
||||||
|
#
|
||||||
|
# Which of these is the real one depends on how Steam was installed: Valve's
|
||||||
|
# own package and the Arch one use ~/.local/share/Steam, Debian's puts it in
|
||||||
|
# ~/.steam/debian-installation, and the Flatpak and the snap each keep it
|
||||||
|
# inside the private tree their sandbox gives them.
|
||||||
mca_steam_roots() {
|
mca_steam_roots() {
|
||||||
local candidates=(
|
local candidates=(
|
||||||
"$MCA_XDG_DATA/Steam"
|
"$MCA_XDG_DATA/Steam"
|
||||||
@@ -29,6 +53,8 @@ mca_steam_roots() {
|
|||||||
"$HOME/.steam/root"
|
"$HOME/.steam/root"
|
||||||
"$HOME/.steam/debian-installation"
|
"$HOME/.steam/debian-installation"
|
||||||
"$HOME/.var/app/com.valvesoftware.Steam/.local/share/Steam"
|
"$HOME/.var/app/com.valvesoftware.Steam/.local/share/Steam"
|
||||||
|
"$HOME/.var/app/com.valvesoftware.Steam/data/Steam"
|
||||||
|
"$HOME/snap/steam/common/.local/share/Steam"
|
||||||
)
|
)
|
||||||
local dir real
|
local dir real
|
||||||
local -A seen=()
|
local -A seen=()
|
||||||
@@ -42,24 +68,28 @@ mca_steam_roots() {
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
# The script to patch inside a Steam installation. Newer clients start the
|
# The scripts to patch inside a Steam installation, one per client. The default
|
||||||
# helper through a wrapper inside the container runtime; older ones exec it
|
# client starts the helper through a wrapper inside the container runtime;
|
||||||
# from steamwebhelper.sh directly, and that one forwards its arguments too.
|
# older ones exec it from steamwebhelper.sh directly, and that one forwards its
|
||||||
mca_steam_script() {
|
# arguments too. The steamrt3 client has its own. Both clients are patched
|
||||||
local root="$1" f
|
# where both are there, so switching between them keeps autoscroll.
|
||||||
|
mca_steam_scripts() {
|
||||||
|
local root="$1" f found=1
|
||||||
for f in \
|
for f in \
|
||||||
"$root/ubuntu12_64/steamwebhelper_sniper_wrap.sh" \
|
"$root/ubuntu12_64/steamwebhelper_sniper_wrap.sh" \
|
||||||
"$root/ubuntu12_64/steamwebhelper.sh"
|
"$root/ubuntu12_64/steamwebhelper.sh"
|
||||||
do
|
do
|
||||||
[[ -f $f && -w $f ]] && { printf '%s\n' "$f"; return 0; }
|
[[ -f $f && -w $f ]] && { printf '%s\n' "$f"; found=0; break; }
|
||||||
done
|
done
|
||||||
return 1
|
f="$root/steamrt64/steamwebhelper.sh"
|
||||||
|
[[ -f $f && -w $f ]] && { printf '%s\n' "$f"; found=0; }
|
||||||
|
return "$found"
|
||||||
}
|
}
|
||||||
|
|
||||||
mca_steam_installed() {
|
mca_steam_installed() {
|
||||||
local root
|
local root
|
||||||
while IFS= read -r root; do
|
while IFS= read -r root; do
|
||||||
mca_steam_script "$root" > /dev/null && return 0
|
mca_steam_scripts "$root" > /dev/null && return 0
|
||||||
done < <(mca_steam_roots)
|
done < <(mca_steam_roots)
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
@@ -69,13 +99,17 @@ mca_steam_script_patched() {
|
|||||||
grep -q -- "$MCA_FEATURE" "$1" 2>/dev/null
|
grep -q -- "$MCA_FEATURE" "$1" 2>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Whether every script there is patched. One that is not is a client that
|
||||||
|
# starts without autoscroll.
|
||||||
mca_steam_patched() {
|
mca_steam_patched() {
|
||||||
local root script
|
local root script found=0
|
||||||
while IFS= read -r root; do
|
while IFS= read -r root; do
|
||||||
script="$(mca_steam_script "$root")" || continue
|
while IFS= read -r script; do
|
||||||
mca_steam_script_patched "$script" && return 0
|
mca_steam_script_patched "$script" || return 1
|
||||||
|
found=1
|
||||||
|
done < <(mca_steam_scripts "$root")
|
||||||
done < <(mca_steam_roots)
|
done < <(mca_steam_roots)
|
||||||
return 1
|
(( found ))
|
||||||
}
|
}
|
||||||
|
|
||||||
# _mca_steam_exec_line <script>
|
# _mca_steam_exec_line <script>
|
||||||
@@ -92,38 +126,223 @@ _mca_steam_exec_line() {
|
|||||||
' "$1" 2>/dev/null
|
' "$1" 2>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# _mca_steam_build <script> <flags>
|
||||||
|
# The patched script on stdout: the flags appended to the line that starts the
|
||||||
|
# web helper, and the same number of bytes taken back out of the script's
|
||||||
|
# comments, so that the file Steam finds is the length Steam wrote down.
|
||||||
|
# Everything else is left alone, like setting up the container runtime or
|
||||||
|
# deciding whether the sandbox can be used.
|
||||||
|
#
|
||||||
|
# Comments are eaten from the bottom up, so the header that says what the
|
||||||
|
# script is for is the last thing to lose anything, and the '#' itself always
|
||||||
|
# stays: a line that loses it stops being a comment and starts being a command.
|
||||||
|
# Fails when the comments are too short to pay for the flags.
|
||||||
|
_mca_steam_build() {
|
||||||
|
local script="$1" flags="$2" lineno need
|
||||||
|
|
||||||
|
lineno="$(_mca_steam_exec_line "$script")"
|
||||||
|
[[ -n $lineno ]] || return 1
|
||||||
|
|
||||||
|
need="$(printf '%s' " $flags" | wc -c)"
|
||||||
|
need="${need//[^0-9]/}"
|
||||||
|
|
||||||
|
# LC_ALL=C so awk counts bytes: a comment with an accent in it is shorter
|
||||||
|
# in characters than it is on disk, and it is the disk that Steam measures.
|
||||||
|
LC_ALL=C awk -v n="$lineno" -v f=" $flags" -v need="$need" '
|
||||||
|
{ lines[NR] = (NR == n ? $0 f : $0) }
|
||||||
|
END {
|
||||||
|
for (i = NR; i >= 2 && need > 0; i--) {
|
||||||
|
if (i == n) continue
|
||||||
|
p = index(lines[i], "#")
|
||||||
|
if (p == 0) continue
|
||||||
|
# Only a line that is nothing but a comment; a trailing one
|
||||||
|
# sits behind a command that has to stay intact.
|
||||||
|
if (substr(lines[i], 1, p - 1) ~ /[^ \t]/) continue
|
||||||
|
can = length(lines[i]) - p
|
||||||
|
if (can <= 0) continue
|
||||||
|
if (can > need) can = need
|
||||||
|
lines[i] = substr(lines[i], 1, length(lines[i]) - can)
|
||||||
|
need -= can
|
||||||
|
}
|
||||||
|
if (need > 0) exit 1
|
||||||
|
for (i = 1; i <= NR; i++) print lines[i]
|
||||||
|
}
|
||||||
|
' "$script"
|
||||||
|
}
|
||||||
|
|
||||||
|
# _mca_steam_same_size <script> <content>
|
||||||
|
# Whether writing that content leaves the file at the size it has now. Measured
|
||||||
|
# rather than worked out: a script without a final newline gains one on the way
|
||||||
|
# through awk, and one byte is all it takes for Steam to notice.
|
||||||
|
_mca_steam_same_size() {
|
||||||
|
local script="$1" content="$2"
|
||||||
|
(( $(wc -c < "$script") == $(printf '%s\n' "$content" | wc -c) ))
|
||||||
|
}
|
||||||
|
|
||||||
|
# Where a stub keeps Steam's own script, and the line that runs it from there.
|
||||||
|
MCA_STEAM_ORIG=.orig
|
||||||
|
MCA_STEAM_STUB="exec \"\$0$MCA_STEAM_ORIG\" \"\$@\""
|
||||||
|
|
||||||
|
# _mca_steam_stub <script> <flags>
|
||||||
|
# The stub on stdout, for a script with no comments to pay for the flags. It
|
||||||
|
# is exactly as long as the script and runs Steam's own script, kept next to
|
||||||
|
# it, with the flags added. That script hands its arguments on to the helper.
|
||||||
|
# Steam only checks the files in its manifest, and the copy is not one of them.
|
||||||
|
# Fails when the script does not hand its arguments on, has no #! line, or is
|
||||||
|
# too short to hold the stub.
|
||||||
|
_mca_steam_stub() {
|
||||||
|
local script="$1" flags="$2" head body pad
|
||||||
|
|
||||||
|
[[ -n "$(_mca_steam_exec_line "$script")" ]] || return 1
|
||||||
|
head="$(head -n 1 -- "$script")"
|
||||||
|
[[ $head == '#!'* ]] || return 1
|
||||||
|
|
||||||
|
body="$MCA_STEAM_STUB $flags"
|
||||||
|
pad=$(( $(wc -c < "$script") - $(printf '%s\n%s\n' "$head" "$body" | wc -c) ))
|
||||||
|
(( pad >= 0 )) || return 1
|
||||||
|
|
||||||
|
# The bytes left over go into a comment line.
|
||||||
|
printf '%s\n' "$head"
|
||||||
|
if (( pad == 1 )); then
|
||||||
|
printf '\n'
|
||||||
|
elif (( pad > 1 )); then
|
||||||
|
printf '#%*s\n' $(( pad - 2 )) ''
|
||||||
|
fi
|
||||||
|
printf '%s' "$body"
|
||||||
|
}
|
||||||
|
|
||||||
|
# _mca_steam_is_stub <script>
|
||||||
|
_mca_steam_is_stub() {
|
||||||
|
grep -qF -- "$MCA_STEAM_STUB" "$1" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# _mca_steam_text <script> <flags>
|
||||||
|
# The patched script on stdout: from the comments if they can pay for the
|
||||||
|
# flags, as a stub if not. Fails when neither keeps the size.
|
||||||
|
_mca_steam_text() {
|
||||||
|
local script="$1" flags="$2" out
|
||||||
|
|
||||||
|
if ! { out="$(_mca_steam_build "$script" "$flags")" \
|
||||||
|
&& _mca_steam_same_size "$script" "$out"; }
|
||||||
|
then
|
||||||
|
out="$(_mca_steam_stub "$script" "$flags")" \
|
||||||
|
&& _mca_steam_same_size "$script" "$out" || return 1
|
||||||
|
fi
|
||||||
|
printf '%s' "$out"
|
||||||
|
}
|
||||||
|
|
||||||
|
# _mca_steam_write <script> <backup> <content>
|
||||||
|
# Writes the patched script. <backup> is the untouched copy kept for undoing.
|
||||||
|
_mca_steam_write() {
|
||||||
|
local script="$1" backup="$2" content="$3"
|
||||||
|
|
||||||
|
# A stub needs Steam's script next to it before it can start anything.
|
||||||
|
if [[ $content == *"$MCA_STEAM_STUB"* ]]; then
|
||||||
|
cp -p -- "$backup" "$script$MCA_STEAM_ORIG" 2>/dev/null || return 1
|
||||||
|
chmod +x -- "$script$MCA_STEAM_ORIG" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if mca_write_if_changed "$script" "$content"$'\n'; then
|
||||||
|
MCA_CHANGES=$(( MCA_CHANGES + 1 ))
|
||||||
|
fi
|
||||||
|
chmod +x -- "$script" 2>/dev/null || true
|
||||||
|
|
||||||
|
# Steam looks at when the file was last written as well as at how big
|
||||||
|
# it is, and the copy taken before the edit still carries the original
|
||||||
|
# timestamp. Putting it back costs nothing and removes the other half
|
||||||
|
# of what the client would notice.
|
||||||
|
touch -r "$backup" -- "$script" 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
# _mca_steam_refresh_backup <script>
|
||||||
|
# A client update brings a new version of the script, and the copy kept from
|
||||||
|
# before it is no longer what putting it back means. Only ever done while the
|
||||||
|
# script is unpatched, so the copy that replaces it is Steam's own.
|
||||||
|
_mca_steam_refresh_backup() {
|
||||||
|
local script="$1" name
|
||||||
|
name="$(mca_backup_name "$script")"
|
||||||
|
|
||||||
|
[[ -e "$MCA_BACKUPDIR/$name" ]] || return 0
|
||||||
|
cmp -s -- "$script" "$MCA_BACKUPDIR/$name" && return 0
|
||||||
|
cp -p -- "$script" "$MCA_BACKUPDIR/$name" 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
# _mca_steam_settle <script> <flags>
|
||||||
|
# The script is already patched. Whether that is a patch Steam can live with is
|
||||||
|
# a question of length: an earlier version of this program appended the flag
|
||||||
|
# where the comments could not pay for it, which leaves the script longer than
|
||||||
|
# the file Steam wrote down. A client that checks its files reinstalls itself
|
||||||
|
# over that, then quits instead of starting.
|
||||||
|
#
|
||||||
|
# Rebuilt from the untouched original kept when the script was first patched,
|
||||||
|
# never from the patched file, the flag either fits this time or the original
|
||||||
|
# goes back and Steam is left with a client it recognises.
|
||||||
|
_mca_steam_settle() {
|
||||||
|
local script="$1" flags="$2" name copy out
|
||||||
|
|
||||||
|
name="$(mca_backup_name "$script")"
|
||||||
|
copy="$MCA_BACKUPDIR/$name"
|
||||||
|
|
||||||
|
# Nothing to compare against, so nothing can be said about the length.
|
||||||
|
[[ -f $copy ]] || return 0
|
||||||
|
|
||||||
|
# Already the length Steam expects: the patch is a good one. Unless it is
|
||||||
|
# a stub that lost Steam's script next to it, and would start nothing.
|
||||||
|
if (( $(wc -c < "$script") == $(wc -c < "$copy") )); then
|
||||||
|
if _mca_steam_is_stub "$script" && [[ ! -f $script$MCA_STEAM_ORIG ]]; then
|
||||||
|
cp -p -- "$copy" "$script$MCA_STEAM_ORIG" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if out="$(_mca_steam_text "$copy" "$flags")" \
|
||||||
|
&& _mca_steam_write "$script" "$copy" "$out"
|
||||||
|
then
|
||||||
|
mca_ledger_add steam "$script" "$name"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
mca_steam_revert "$script" "$name"
|
||||||
|
mca_ledger_forget "$script"
|
||||||
|
mca_note "$(mca_msg "Steam's interface cannot be given the flag without leaving a file Steam would reinstall; the change has been taken back.")"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
# mca_steam_apply
|
# mca_steam_apply
|
||||||
# Appends the flags to the line that starts the web helper. Everything else in
|
# Puts the flags into every Steam installation that has the script, and only
|
||||||
# the script - setting up the container runtime, deciding whether the sandbox
|
# where that can be done without changing how long the file is. Returns 1 when
|
||||||
# can be used - is left alone.
|
# there is no Steam to patch at all.
|
||||||
mca_steam_apply() {
|
mca_steam_apply() {
|
||||||
local root script backup flags lineno found=0 out
|
local root script backup flags found=0 out
|
||||||
|
|
||||||
flags="$(mca_flags)"
|
flags="$(mca_flags)"
|
||||||
|
|
||||||
while IFS= read -r root; do
|
while IFS= read -r root; do
|
||||||
script="$(mca_steam_script "$root")" || continue
|
while IFS= read -r script; do
|
||||||
found=1
|
found=1
|
||||||
|
|
||||||
mca_steam_script_patched "$script" && continue
|
if mca_steam_script_patched "$script"; then
|
||||||
|
_mca_steam_settle "$script" "$flags"
|
||||||
lineno="$(_mca_steam_exec_line "$script")"
|
|
||||||
if [[ -z $lineno ]]; then
|
|
||||||
# A client update changed how the helper is started. Leaving the
|
|
||||||
# file alone is the only safe answer: this script is what starts
|
|
||||||
# Steam's entire interface.
|
|
||||||
mca_note "$(mca_msg "Steam starts its interface in a way this version does not recognise; leaving it alone.")"
|
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
out="$(awk -v n="$lineno" -v f=" $flags" 'NR == n { $0 = $0 f } { print }' "$script")" || continue
|
_mca_steam_refresh_backup "$script"
|
||||||
|
|
||||||
|
# Either the file keeps its length or nothing is written. A
|
||||||
|
# longer file is one Steam reinstalls itself over; a client
|
||||||
|
# update that changed how the helper is started leaves no line
|
||||||
|
# to patch at all. Both end here, and this script is what starts
|
||||||
|
# Steam's entire interface, so leaving it alone is the only safe
|
||||||
|
# answer to either.
|
||||||
|
if ! out="$(_mca_steam_text "$script" "$flags")"; then
|
||||||
|
mca_note "$(mca_msg "Steam starts its interface in a way this version cannot change without Steam noticing; leaving it alone.")"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
backup="$(mca_backup "$script")" || continue
|
backup="$(mca_backup "$script")" || continue
|
||||||
if mca_write_if_changed "$script" "$out"$'\n'; then
|
_mca_steam_write "$script" "$MCA_BACKUPDIR/$backup" "$out" || continue
|
||||||
MCA_CHANGES=$(( MCA_CHANGES + 1 ))
|
|
||||||
fi
|
|
||||||
chmod +x -- "$script" 2>/dev/null || true
|
|
||||||
mca_ledger_add steam "$script" "$backup"
|
mca_ledger_add steam "$script" "$backup"
|
||||||
|
done < <(mca_steam_scripts "$root")
|
||||||
done < <(mca_steam_roots)
|
done < <(mca_steam_roots)
|
||||||
|
|
||||||
(( found ))
|
(( found ))
|
||||||
@@ -131,7 +350,9 @@ mca_steam_apply() {
|
|||||||
|
|
||||||
# mca_steam_revert <script> <backup name>
|
# mca_steam_revert <script> <backup name>
|
||||||
mca_steam_revert() {
|
mca_steam_revert() {
|
||||||
local script="$1" backup="$2"
|
local script="$1" backup="$2" orig="$1$MCA_STEAM_ORIG" stub=1 tmp
|
||||||
|
|
||||||
|
_mca_steam_is_stub "$script" || stub=0
|
||||||
|
|
||||||
if [[ -n $backup && -f "$MCA_BACKUPDIR/$backup" ]]; then
|
if [[ -n $backup && -f "$MCA_BACKUPDIR/$backup" ]]; then
|
||||||
if [[ -e $script ]]; then
|
if [[ -e $script ]]; then
|
||||||
@@ -139,23 +360,21 @@ mca_steam_revert() {
|
|||||||
chmod +x -- "$script" 2>/dev/null || true
|
chmod +x -- "$script" 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
rm -f -- "$MCA_BACKUPDIR/$backup"
|
rm -f -- "$MCA_BACKUPDIR/$backup"
|
||||||
return 0
|
elif (( stub )) && [[ -f $orig ]]; then
|
||||||
fi
|
# No backup, but a stub keeps Steam's own script right next to it.
|
||||||
|
cp -p -- "$orig" "$script" 2>/dev/null || return 1
|
||||||
# No backup to fall back on - take the flags back out of the exec line.
|
else
|
||||||
|
# No backup to fall back on, so take the flags back out of the exec line.
|
||||||
[[ -f $script ]] || return 1
|
[[ -f $script ]] || return 1
|
||||||
local tmp
|
|
||||||
tmp="$(mktemp "${script}.XXXXXX")" || return 1
|
tmp="$(mktemp "${script}.XXXXXX")" || return 1
|
||||||
sed "s| $MCA_FLAG||g" "$script" > "$tmp" && mv -f "$tmp" "$script" || { rm -f "$tmp"; return 1; }
|
sed "s| $MCA_FLAG||g" "$script" > "$tmp" && mv -f "$tmp" "$script" || { rm -f "$tmp"; return 1; }
|
||||||
chmod +x -- "$script" 2>/dev/null || true
|
chmod +x -- "$script" 2>/dev/null || true
|
||||||
return 0
|
return 0
|
||||||
}
|
fi
|
||||||
|
|
||||||
# mca_steam_desktop_apply <id> <source entry>
|
# The copy goes once the stub that ran it is gone.
|
||||||
# Steam restores its own files at every start unless it is told not to verify
|
if (( stub )) && ! _mca_steam_is_stub "$script"; then
|
||||||
# them, so the launcher entry carries that switch. It goes directly after the
|
rm -f -- "$orig"
|
||||||
# program because Steam reads its options before the steam:// argument that the
|
fi
|
||||||
# right-click actions pass.
|
return 0
|
||||||
mca_steam_desktop_apply() {
|
|
||||||
mca_desktop_apply "$1" "$2" "$MCA_STEAM_LAUNCH_FLAG" after-program
|
|
||||||
}
|
}
|
||||||
+30
-19
@@ -1,11 +1,11 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
#
|
#
|
||||||
# middleclick-autoscroll - middle-click autoscroll for Chromium-based
|
# middleclick-autoscroll: middle-click autoscroll for Chromium-based
|
||||||
# applications on Linux
|
# applications on Linux
|
||||||
#
|
#
|
||||||
# Blink has had Windows-style autoscroll for years, behind a runtime flag that
|
# Blink has had Windows-style autoscroll for years, behind a runtime flag that
|
||||||
# is not turned on for Linux because middle click is taken by primary-selection
|
# is not turned on for Linux because middle click is taken by primary-selection
|
||||||
# paste there. Turning it on is a matter of one command line argument - the
|
# paste there. Turning it on is a matter of one command line argument. The
|
||||||
# work is finding every application that needs it, putting the argument
|
# work is finding every application that needs it, putting the argument
|
||||||
# somewhere it survives an update, and doing the same for the two programs that
|
# somewhere it survives an update, and doing the same for the two programs that
|
||||||
# do not take arguments at all.
|
# do not take arguments at all.
|
||||||
@@ -17,7 +17,7 @@ set -uo pipefail
|
|||||||
|
|
||||||
MCA_LIBDIR="${MCA_LIBDIR:-@LIBDIR@}"
|
MCA_LIBDIR="${MCA_LIBDIR:-@LIBDIR@}"
|
||||||
|
|
||||||
for _mod in common config detect patch steam apply menu; do
|
for _mod in common config detect patch steam kde apply menu; do
|
||||||
# shellcheck source=/dev/null
|
# shellcheck source=/dev/null
|
||||||
if ! source "$MCA_LIBDIR/$_mod.sh"; then
|
if ! source "$MCA_LIBDIR/$_mod.sh"; then
|
||||||
printf 'middleclick-autoscroll: cannot load %s/%s.sh\n' "$MCA_LIBDIR" "$_mod" >&2
|
printf 'middleclick-autoscroll: cannot load %s/%s.sh\n' "$MCA_LIBDIR" "$_mod" >&2
|
||||||
@@ -50,17 +50,14 @@ mca_do_enable() {
|
|||||||
if mca_watch_available; then
|
if mca_watch_available; then
|
||||||
mca_watch_enable || mca_note "$(mca_msg "Could not start the watcher for newly installed applications.")"
|
mca_watch_enable || mca_note "$(mca_msg "Could not start the watcher for newly installed applications.")"
|
||||||
else
|
else
|
||||||
mca_note "$(mca_msg "No systemd user session - newly installed applications will not be picked up on their own.")"
|
mca_note "$(mca_msg "No systemd user session, so newly installed applications will not be picked up on their own.")"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mca_ok "$(mca_msg "Autoscroll is on for %d applications." "$MCA_N_ON")"
|
mca_ok "$(mca_msg "Autoscroll is on for %d applications." "$MCA_N_ON")"
|
||||||
|
|
||||||
if [[ $CFG_STEAM == yes ]] && mca_steam_installed; then
|
[[ -n $MCA_IN_MENU ]] \
|
||||||
mca_note "$(mca_msg "Steam's launcher now skips its file check, which is what keeps the change from being undone at every start.")"
|
|| mca_note "$(mca_msg "Applications that are already running pick this up when they are restarted.")"
|
||||||
fi
|
|
||||||
|
|
||||||
mca_note "$(mca_msg "Applications that are already running pick this up when they are restarted.")"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mca_do_disable() {
|
mca_do_disable() {
|
||||||
@@ -76,11 +73,11 @@ mca_do_disable() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mca_do_apply() {
|
mca_do_apply() {
|
||||||
local changed=0 arg
|
local rebuild=0 arg
|
||||||
|
|
||||||
for arg in "$@"; do
|
for arg in "$@"; do
|
||||||
case "$arg" in
|
case "$arg" in
|
||||||
--changed) changed=1 ;;
|
--rebuild) rebuild=1 ;;
|
||||||
--quiet) MCA_QUIET=1 ;;
|
--quiet) MCA_QUIET=1 ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
@@ -95,25 +92,38 @@ mca_do_apply() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# A settings change can take an application out of scope as well as bring
|
# Start from a clean slate. Needed after a settings change, which can take
|
||||||
# one in, and only a full undo can tell the difference, so that path starts
|
# an application out of scope as well as bring one in and where only a full
|
||||||
# from a clean slate. The watcher never does this: rewriting files that are
|
# undo can tell the difference, and it is what makes the repair a repair:
|
||||||
# already correct would make it trigger itself.
|
# whatever drifted is written again rather than left because it is "already
|
||||||
if (( changed )); then
|
# applied".
|
||||||
|
#
|
||||||
|
# The watcher never does this. Rewriting files that are already correct
|
||||||
|
# would change their timestamps, and it is watching those directories.
|
||||||
|
if (( rebuild )); then
|
||||||
mca_revert
|
mca_revert
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mca_apply
|
mca_apply
|
||||||
|
|
||||||
if (( MCA_CHANGES )); then
|
if (( rebuild )); then
|
||||||
|
mca_ok "$(mca_msg "Applied again to %d applications." "$MCA_N_ON")"
|
||||||
|
[[ -n $MCA_IN_MENU ]] \
|
||||||
|
|| mca_say " $(mca_msg "Applications that are already running pick this up when they are restarted.")"
|
||||||
|
elif (( MCA_CHANGES )); then
|
||||||
mca_ok "$(mca_msg "Applied to %d applications." "$MCA_N_ON")"
|
mca_ok "$(mca_msg "Applied to %d applications." "$MCA_N_ON")"
|
||||||
mca_say " $(mca_msg "Applications that are already running pick this up when they are restarted.")"
|
[[ -n $MCA_IN_MENU ]] \
|
||||||
|
|| mca_say " $(mca_msg "Applications that are already running pick this up when they are restarted.")"
|
||||||
else
|
else
|
||||||
mca_ok "$(mca_msg "Already applied to %d applications." "$MCA_N_ON")"
|
mca_ok "$(mca_msg "Already applied to %d applications." "$MCA_N_ON")"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $CFG_WATCH == yes ]] && mca_watch_available && ! mca_watch_enabled; then
|
if [[ $CFG_WATCH == yes ]] && mca_watch_available; then
|
||||||
|
if mca_watch_enabled; then
|
||||||
|
mca_watch_refresh
|
||||||
|
else
|
||||||
mca_watch_enable || true
|
mca_watch_enable || true
|
||||||
|
fi
|
||||||
elif [[ $CFG_WATCH != yes ]] && mca_watch_enabled; then
|
elif [[ $CFG_WATCH != yes ]] && mca_watch_enabled; then
|
||||||
mca_watch_disable
|
mca_watch_disable
|
||||||
fi
|
fi
|
||||||
@@ -160,6 +170,7 @@ mca_do_help() {
|
|||||||
enable $(mca_msg "Turn autoscroll on")
|
enable $(mca_msg "Turn autoscroll on")
|
||||||
disable $(mca_msg "Turn it off and put everything back")
|
disable $(mca_msg "Turn it off and put everything back")
|
||||||
apply $(mca_msg "Apply to anything installed since the last run")
|
apply $(mca_msg "Apply to anything installed since the last run")
|
||||||
|
apply --rebuild $(mca_msg "Take everything back and apply it again")
|
||||||
status $(mca_msg "Show what is covered")
|
status $(mca_msg "Show what is covered")
|
||||||
list $(mca_msg "List every application that was found")
|
list $(mca_msg "List every application that was found")
|
||||||
-h, --help $(mca_msg "Show this help")
|
-h, --help $(mca_msg "Show this help")
|
||||||
|
|||||||
Reference in new issue
Block a user