feat: rework the settings

This commit is contained in:
Felitendo committed 2026-09-24 10:44:52 +02:00
1 parent 677660c1c6
commit 82afefe5f8
8 files changed
+151 -116

No files matched your search

+8 -3
View File
@@ -36,7 +36,10 @@ assumed from where the launcher came from.
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
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
is refused.
@@ -112,7 +115,8 @@ Two ways, chosen per application.
Programs that start themselves at login write their own entry into
_~/.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.
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
@@ -170,7 +174,8 @@ rather than the one from before the update.
The official client is CEF rather than Electron. Installed through
*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
where the flag goes. Installed as a plain package, a Flatpak or a snap, it is
where the flag goes, and the launcher shows up in the applications list like
any other application. Installed as a plain package, a Flatpak or a snap, it is
an ordinary desktop entry and needs nothing special.
# MIDDLE-CLICK PASTE
+16 -23
View File
@@ -95,35 +95,28 @@ msgid "Press any key to continue..."
msgstr "Beliebige Taste drücken …"
#. Settings
msgid "Electron and CEF applications"
msgstr "Electron- und CEF-Anwendungen"
msgid "Turn off middle-click paste"
msgstr "Mittelklick-Einfügen abschalten"
msgid "Chromium-based browsers"
msgstr "Chromium-basierte Browser"
msgid ""
"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"
msgstr "Flatpak-Anwendungen"
msgid "Cover new applications"
msgstr "Neue Anwendungen abdecken"
msgid "Snap applications"
msgstr "Snap-Anwendungen"
msgid "Applications installed later get autoscroll on their own."
msgstr "Später installierte Anwendungen bekommen Autoscroll von selbst."
msgid "Programs that start themselves at login"
msgstr "Programme, die sich beim Anmelden selbst starten"
msgid "More Chromium arguments"
msgstr "Weitere Chromium-Argumente"
msgid "Spotify"
msgstr "Spotify"
msgid "Passed to every application along with the autoscroll one."
msgstr "Gehen zusammen mit dem Autoscroll-Argument an jede Anwendung."
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"
msgid "Additional Chromium arguments"
msgstr "Zusätzliche Chromium-Argumente"
msgid "Up/Down: select, Space or Right: change, q: back"
msgstr "Hoch/Runter: wählen, Leertaste oder Rechts: ändern, q: zurück"
msgid "Up/Down: select, Space: change, q: back"
msgstr "Hoch/Runter: wählen, Leertaste: ändern, q: zurück"
msgid "Arguments separated by spaces, empty for none:"
msgstr "Argumente mit Leerzeichen getrennt, leer für keine:"
+8 -16
View File
@@ -95,34 +95,26 @@ msgid "Press any key to continue..."
msgstr ""
#. Settings
msgid "Electron and CEF applications"
msgid "Turn off middle-click paste"
msgstr ""
msgid "Chromium-based browsers"
msgid ""
"Stops middle click from pasting anywhere else. Starts with the next login."
msgstr ""
msgid "Flatpak applications"
msgid "Cover new applications"
msgstr ""
msgid "Snap applications"
msgid "Applications installed later get autoscroll on their own."
msgstr ""
msgid "Programs that start themselves at login"
msgid "More Chromium arguments"
msgstr ""
msgid "Spotify"
msgid "Passed to every application along with the autoscroll one."
msgstr ""
msgid "Turn off KDE's middle-click paste"
msgstr ""
msgid "Apply to newly installed applications"
msgstr ""
msgid "Additional Chromium arguments"
msgstr ""
msgid "Up/Down: select, Space or Right: change, q: back"
msgid "Up/Down: select, Space: change, q: back"
msgstr ""
msgid "Arguments separated by spaces, empty for none:"
+28 -11
View File
@@ -15,6 +15,7 @@ MCA_ROUTES=()
# flags - the launcher reads a flag file; write it there
# desktop - no flag file; shadow or edit the desktop entry
# 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
# off - detected, but switched off
#
@@ -26,16 +27,16 @@ MCA_ROUTE=''
mca_route() {
local kind="$1" id="$2" prog="$3" packaging="${4:-native}"
if [[ $kind == steam ]]; then
if mca_config_list_has Skip "$id" || [[ $CFG_STEAM != yes ]]; then
if [[ $kind == steam || $kind == spotify ]]; then
if mca_config_list_has Skip "$id"; then
MCA_ROUTE=off
else
MCA_ROUTE=steam
MCA_ROUTE="$kind"
fi
return
fi
if ! mca_kind_wanted "$kind" "$id" "$packaging"; then
if ! mca_kind_wanted "$kind" "$id"; then
[[ $kind == unknown ]] && MCA_ROUTE=unknown || MCA_ROUTE=off
return
fi
@@ -59,7 +60,7 @@ mca_route() {
# as it likes to be. It writes only what differs, which is what keeps the
# watcher from chasing its own changes.
mca_apply() {
local i id file prog kind packaging route steam_done=0
local i id file prog kind packaging route steam_done=0 spotify_done=0
MCA_CHANGES=0
MCA_ROUTES=()
@@ -111,29 +112,29 @@ mca_apply() {
steam_done=1
fi
;;
spotify)
(( spotify_done )) || mca_spotify_apply
spotify_done=1
;;
esac
done
# 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.
if [[ $CFG_STEAM == yes ]] && (( ! steam_done )) && mca_steam_installed; then
if (( ! steam_done )) && mca_steam_wanted && mca_steam_installed; then
mca_steam_apply
fi
# Autostart entries. A Chromium application that starts itself at login
# 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.
if [[ $CFG_AUTOSTART == yes ]]; then
mca_autostart_apply
fi
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
[[ $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.
@@ -272,12 +273,28 @@ mca_count_routes() {
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() {
case "$1" in
flags) mca_msg "flag file" ;;
desktop) mca_msg "launcher" ;;
steam) mca_msg "Steam" ;;
spotify) printf 'spotify-launcher' ;;
unknown) mca_msg "cannot tell" ;;
*) mca_msg "off" ;;
esac
+48 -7
View File
@@ -101,6 +101,20 @@ mca_config_set() {
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>
# The per-application overrides are stored as space separated lists.
mca_config_list_has() {
@@ -136,13 +150,6 @@ mca_config_list_del() {
mca_config_load() {
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_SNAP=no; mca_config_bool PatchSnap yes && CFG_SNAP=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_PASTE=no; mca_config_bool DisablePaste yes && CFG_PASTE=yes
@@ -155,6 +162,40 @@ mca_config_load() {
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
# file writer and the desktop entry writer cannot drift apart.
+11 -20
View File
@@ -989,7 +989,7 @@ MCA_IDS=() # desktop file id, without the .desktop suffix
MCA_FILES=() # the desktop entry that is in effect for that id
MCA_NAMES=() # display name
MCA_PROGS=() # resolved program, or a Flatpak app id or a snap name
MCA_KINDS=() # app | browser | steam | unknown | no
MCA_KINDS=() # app | browser | steam | spotify | unknown | no
MCA_PACKAGING=() # native | flatpak | snap
# A scan reads every desktop entry on the system, so the menu does it once and
@@ -1094,6 +1094,10 @@ mca_scan() {
# Steam is Chromium inside, but nothing about it can be changed
# from a command line argument; it has its own module.
kind=steam
elif [[ ${prog##*/} == spotify-launcher ]]; then
# Not Chromium itself, but it starts Spotify, which is CEF. It
# takes the flag from its own configuration file.
kind=spotify
else
mca_detect_verdict "$prog"
case "$MCA_VERDICT" in
@@ -1114,6 +1118,7 @@ mca_scan() {
mca_cache_flush
MCA_SCANNED=1
mca_config_migrate
}
# mca_has_flags_file <program>
@@ -1224,28 +1229,14 @@ mca_flatpak_is_chromium() {
return 1
}
# mca_kind_wanted <kind> <id> [packaging]
# Whether the current settings say this entry should be patched. Skip beats
# everything, an explicit include beats detection, and detection beats nothing.
#
# Packaging is a gate in front of the category rather than a category of its
# own: a Flatpak or a snap sees none of the host's configuration and is worth
# switching off as a group, but it is still an application or a browser and
# whichever of those the user turned off applies to it too.
# mca_kind_wanted <kind> <id>
# Whether this entry should be patched. Skip beats everything, an explicit
# include beats detection, and detection beats nothing.
mca_kind_wanted() {
local kind="$1" id="$2" packaging="${3:-native}"
local kind="$1" id="$2"
mca_config_list_has Skip "$id" && return 1
mca_config_list_has Include "$id" && return 0
case "$packaging" in
flatpak) [[ $CFG_FLATPAK == yes ]] || return 1 ;;
snap) [[ $CFG_SNAP == yes ]] || return 1 ;;
esac
case "$kind" in
app) [[ $CFG_APPS == yes ]] ;;
browser) [[ $CFG_BROWSERS == yes ]] ;;
*) return 1 ;;
esac
[[ $kind == app || $kind == browser ]]
}
+24 -20
View File
@@ -178,7 +178,7 @@ mca_ui_status() {
if mca_steam_installed; then
if mca_steam_patched; then
_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_C_YELLOW}$(mca_msg "not patched yet")${MCA_C_RESET}"
else
@@ -218,19 +218,16 @@ mca_ui_status() {
# ---------------------------------------------------------------------------
# Settings
# ---------------------------------------------------------------------------
# Format: Key|type|default|label-msgid
# type is bool or text.
# Only what is not about one application. Which applications get autoscroll is
# 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=(
"PatchApps|bool|yes|Electron and CEF applications"
"PatchBrowsers|bool|yes|Chromium-based browsers"
"PatchFlatpak|bool|yes|Flatpak applications"
"PatchSnap|bool|yes|Snap applications"
"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"
"DisablePaste|bool|yes|mca_kde_available|Turn off middle-click paste|Stops middle click from pasting anywhere else. Starts with the next login."
"WatchNewApps|bool|yes|mca_watch_available|Cover new applications|Applications installed later get autoscroll on their own."
"ExtraFlags|text|||More Chromium arguments|Passed to every application along with the autoscroll one."
)
_mca_is_true() {
@@ -275,10 +272,9 @@ _mca_setting_display() {
#
# Returns 0 when something was changed, so the caller knows to re-apply.
mca_ui_settings() {
local count=${#MCA_SETTINGS[@]}
local -a names=() types=() defaults=() labels=() values=()
local spec name type default label locale i key frame row pad dirty=1 cursor=0
local touched=0
local -a names=() types=() defaults=() labels=() helps=() values=()
local spec name type default check label help locale i key frame row pad
local count width=0 dirty=1 cursor=0 touched=0
locale="$(mca_ui_locale)"
mca_msg_into "$locale" "ON"; MCA_LBL_ON="$MCA_MSG_RESULT"
@@ -286,15 +282,20 @@ mca_ui_settings() {
mca_msg_into "$locale" "(none)"; MCA_LBL_NONE="$MCA_MSG_RESULT"
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")
mca_msg_into "$locale" "$label"
labels+=("$MCA_MSG_RESULT")
(( ${#MCA_MSG_RESULT} > width )) && width=${#MCA_MSG_RESULT}
mca_msg_into "$locale" "$help"
helps+=("$MCA_MSG_RESULT")
done
count=${#names[@]}
local title hint
mca_msg_into "$locale" "Settings"; title="$MCA_MSG_RESULT"
mca_msg_into "$locale" "Up/Down: select, Space or Right: change, q: back"
mca_msg_into "$locale" "Up/Down: select, Space: change, q: back"
hint="$MCA_MSG_RESULT"
local clearseq
@@ -314,7 +315,7 @@ mca_ui_settings() {
local marker selected="${MCA_C_BLUE}▸${MCA_C_RESET} "
for i in "${!names[@]}"; do
_mca_setting_display "${types[i]}" "${values[i]}"
pad=$(( 46 - ${#labels[i]} ))
pad=$(( width + 3 - ${#labels[i]} ))
(( pad < 0 )) && pad=0
if (( i == cursor )); then marker="$selected"; else marker=' '; fi
printf -v row ' %s%s%*s %s' \
@@ -322,6 +323,7 @@ mca_ui_settings() {
frame+="$row"$'\n'
done
frame+=$'\n'" ${helps[cursor]}"$'\n'
frame+=$'\n'" ${MCA_C_DIM}${hint}${MCA_C_RESET}"$'\n'
printf '%s' "$frame"
@@ -419,6 +421,7 @@ mca_ui_apps() {
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_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
clearseq="$(clear 2>/dev/null)" || clearseq=$'\033[H\033[2J'
@@ -467,6 +470,7 @@ mca_ui_apps() {
unknown) shown="$s_cannot" ;;
steam) shown="$s_steam" ;;
flags) shown="$s_flags" ;;
spotify) shown="$s_spotify" ;;
*) shown="$s_desktop" ;;
esac
pad=$(( 34 - ${#labels[idx]} ))
+8 -16
View File
@@ -418,16 +418,12 @@ mca_desktop_apply() {
# Neither can be shadowed from anywhere, so both are edited where they stand,
# with the original kept.
# _mca_entry_patch_inplace <file> <gate: autostart|apps>
# _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.
#
# What decides whether an application here is in scope differs by where the
# entry came from, which is what the gate says: an autostart entry follows the
# autostart setting, a shortcut follows the same rules as the application it is
# a shortcut to.
# 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" gate="$2"
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
@@ -476,12 +472,8 @@ _mca_entry_patch_inplace() {
mca_desktop_is_browser && kind=browser || kind=app
if [[ $gate == autostart ]]; then
[[ $CFG_AUTOSTART == yes ]] || return 0
else
id="${file##*/}"; id="${id%.desktop}"
mca_kind_wanted "$kind" "$id" "$packaging" || return 0
fi
id="${file##*/}"; id="${id%.desktop}"
mca_kind_wanted "$kind" "$id" || return 0
content="$(_mca_desktop_transform "$file" "$MCA_MARK_INPLACE" \
"$(mca_flags "$kind")")"
@@ -503,7 +495,7 @@ mca_autostart_apply() {
for file in "$dir"/*.desktop; do
[[ -f $file ]] || continue
_mca_entry_patch_inplace "$file" autostart
_mca_entry_patch_inplace "$file"
done
}
@@ -515,7 +507,7 @@ mca_shortcuts_apply() {
for file in "$dir"/*.desktop; do
[[ -f $file ]] || continue
_mca_entry_patch_inplace "$file" apps
_mca_entry_patch_inplace "$file"
done
}