feat: turn off 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. Everywhere else on the desktop middle click goes on pasting, which is the thing this whole program exists to get away from. KWin has a switch for it, on Wayland, where the paste is a protocol the compositor either offers or does not: EnablePrimarySelection in kwinrc. Written with kwriteconfig, the way System Settings would, because kwinrc has a cascade behind it. What the key said before goes in the ledger, so disable puts it back - and a key that already said false is left alone and not recorded, so a paste the user switched off themselves is never switched back on. X11 has no such switch and nothing is written there.
This commit is contained in:
1 parent
0c4e7645d0
commit
004094ef78
11 files changed
+259
-4
No files matched your search
@@ -18,6 +18,7 @@ Just run `middleclick-autoscroll`. This will open the configuration TUI that loo
|
||||
Not identified 1 - see the applications list
|
||||
Steam ON
|
||||
New applications ON
|
||||
Middle-click paste off
|
||||
Last applied 2 minutes ago
|
||||
|
||||
Applications pick this up the next time they are started.
|
||||
|
||||
@@ -172,6 +172,35 @@ and has a configuration file with a slot for extra arguments; that slot is
|
||||
where the flag goes. Installed as a plain package, a Flatpak or a snap, it is
|
||||
an ordinary desktop entry and needs nothing special.
|
||||
|
||||
# MIDDLE-CLICK PASTE
|
||||
|
||||
Inside a Chromium application the argument 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, 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.
|
||||
|
||||
# WHAT CANNOT BE DETECTED
|
||||
|
||||
An AppImage keeps its payload in a compressed filesystem, so there is no way to
|
||||
@@ -190,6 +219,11 @@ _~/.local/state/middleclick-autoscroll/ledger_
|
||||
_~/.local/state/middleclick-autoscroll/backup/_
|
||||
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_
|
||||
Which programs were found to be Chromium, keyed by size and modification
|
||||
time. Safe to delete.
|
||||
@@ -207,7 +241,7 @@ up at the next *apply* rather than on their own.
|
||||
|
||||
# SEE ALSO
|
||||
|
||||
*systemctl*(1), *flatpak*(1), *snap*(8)
|
||||
*systemctl*(1), *flatpak*(1), *snap*(8), *kwriteconfig6*(1)
|
||||
|
||||
# AUTHORS
|
||||
|
||||
|
||||
@@ -63,6 +63,9 @@ msgstr "%d – siehe Anwendungsliste"
|
||||
msgid "Steam"
|
||||
msgstr "Steam"
|
||||
|
||||
msgid "Middle-click paste"
|
||||
msgstr "Mittelklick-Einfügen"
|
||||
|
||||
msgid "New applications"
|
||||
msgstr "Neue Anwendungen"
|
||||
|
||||
@@ -112,6 +115,9 @@ msgstr "Programme, die sich beim Anmelden selbst starten"
|
||||
msgid "Spotify"
|
||||
msgstr "Spotify"
|
||||
|
||||
msgid "Turn off KDE's middle-click paste"
|
||||
msgstr "KDEs Mittelklick-Einfügen abschalten"
|
||||
|
||||
msgid "Apply to newly installed applications"
|
||||
msgstr "Auf neu installierte Anwendungen anwenden"
|
||||
|
||||
@@ -179,6 +185,9 @@ msgstr "Steam startet seine Oberfläche auf eine Art, die diese Version nicht ä
|
||||
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
|
||||
msgid "Usage: middleclick-autoscroll [command]"
|
||||
|
||||
@@ -63,6 +63,9 @@ msgstr ""
|
||||
msgid "Steam"
|
||||
msgstr ""
|
||||
|
||||
msgid "Middle-click paste"
|
||||
msgstr ""
|
||||
|
||||
msgid "New applications"
|
||||
msgstr ""
|
||||
|
||||
@@ -112,6 +115,9 @@ msgstr ""
|
||||
msgid "Spotify"
|
||||
msgstr ""
|
||||
|
||||
msgid "Turn off KDE's middle-click paste"
|
||||
msgstr ""
|
||||
|
||||
msgid "Apply to newly installed applications"
|
||||
msgstr ""
|
||||
|
||||
@@ -179,6 +185,9 @@ 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
|
||||
msgid "Usage: middleclick-autoscroll [command]"
|
||||
|
||||
@@ -134,6 +134,11 @@ mca_apply() {
|
||||
|
||||
[[ $CFG_SPOTIFY == yes ]] && mca_spotify_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
|
||||
|
||||
+14
-2
@@ -278,9 +278,12 @@ mca_state_write() {
|
||||
# shadow <generated desktop entry> <source entry it was generated from>
|
||||
# inplace <edited file> <basename of its backup copy>
|
||||
# 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
|
||||
# wholesale, a flag file only loses the one line that was added to it.
|
||||
# The kinds differ in how they are undone: a backup is restored wholesale, a
|
||||
# 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() {
|
||||
local kind="$1" path="$2" detail="${3:-}"
|
||||
@@ -303,6 +306,15 @@ mca_ledger_has() {
|
||||
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() {
|
||||
local path="$1" tmp
|
||||
[[ -f $MCA_LEDGER ]] || return 0
|
||||
|
||||
@@ -144,6 +144,7 @@ mca_config_load() {
|
||||
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_PASTE=no; mca_config_bool DisablePaste yes && CFG_PASTE=yes
|
||||
|
||||
CFG_EXTRA_FLAGS="$(mca_config_get ExtraFlags '')"
|
||||
|
||||
|
||||
+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
|
||||
}
|
||||
@@ -194,6 +194,18 @@ mca_ui_status() {
|
||||
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")"
|
||||
|
||||
if [[ $CFG_ENABLED == yes ]]; then
|
||||
@@ -216,6 +228,7 @@ MCA_SETTINGS=(
|
||||
"PatchAutostart|bool|yes|Programs that start themselves at login"
|
||||
"PatchSteam|bool|yes|Steam"
|
||||
"PatchSpotify|bool|yes|Spotify"
|
||||
"DisablePaste|bool|yes|Turn off KDE's middle-click paste"
|
||||
"WatchNewApps|bool|yes|Apply to newly installed applications"
|
||||
"ExtraFlags|text||Additional Chromium arguments"
|
||||
)
|
||||
|
||||
@@ -646,6 +646,10 @@ mca_revert_all() {
|
||||
mca_steam_revert "$path" "$detail" \
|
||||
&& MCA_CHANGES=$(( MCA_CHANGES + 1 ))
|
||||
;;
|
||||
kwin)
|
||||
mca_kde_paste_revert "$path" "$detail" \
|
||||
&& MCA_CHANGES=$(( MCA_CHANGES + 1 ))
|
||||
;;
|
||||
esac
|
||||
done < <(tac "$MCA_LEDGER" 2>/dev/null)
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ set -uo pipefail
|
||||
|
||||
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
|
||||
if ! source "$MCA_LIBDIR/$_mod.sh"; then
|
||||
printf 'middleclick-autoscroll: cannot load %s/%s.sh\n' "$MCA_LIBDIR" "$_mod" >&2
|
||||
|
||||
Reference in new issue
Block a user