feat: support firefox and other gecko apps
This commit is contained in:
1 parent
9b6c64bd97
commit
95d602e1c4
23 files changed
+472
-59
No files matched your search
@@ -7,7 +7,7 @@
|
||||
<h3 align="center">Middle-click autoscroll in every app that supports it.</h3>
|
||||
|
||||
<p align="center">
|
||||
Browsers, Electron apps like Discord and Spotify, Steam and anything else built on Chromium.
|
||||
Firefox, Chromium browsers, Electron apps like Discord and Spotify, Steam and anything else built on Chromium.
|
||||
</p>
|
||||
|
||||
<h5 align="center">
|
||||
@@ -126,6 +126,9 @@ Adding it to every app by hand is a pain, and updates can undo it. This tool doe
|
||||
**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.
|
||||
|
||||
**Firefox** has autoscroll too, but as a setting, not a flag. It goes into the `user.js` of each
|
||||
profile. The same works for LibreWolf, Zen, Floorp, Waterfox and Thunderbird.
|
||||
|
||||
**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,
|
||||
|
||||
@@ -34,10 +34,13 @@ 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.
|
||||
|
||||
Firefox and everything else built on Gecko has autoscroll as well, behind a
|
||||
setting rather than a flag. See *FIREFOX*.
|
||||
|
||||
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. Its applications list turns single applications on or off,
|
||||
Steam and Spotify included. Its settings hold the rest: the desktop's
|
||||
Steam, Spotify and Firefox included. Its settings hold the rest: the desktop's
|
||||
middle-click paste, the watcher, and more Chromium arguments for every
|
||||
application.
|
||||
|
||||
@@ -69,8 +72,7 @@ is refused.
|
||||
last run was.
|
||||
|
||||
*list*
|
||||
Every Chromium-based application that was found, and how each one is
|
||||
handled.
|
||||
Every application that was found, and how each one is handled.
|
||||
|
||||
*-h*, *--help*
|
||||
Show a summary of the commands.
|
||||
@@ -191,6 +193,29 @@ 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.
|
||||
|
||||
# FIREFOX
|
||||
|
||||
Firefox has autoscroll of its own, switched off on Linux. There is no flag for
|
||||
it, only a setting: *general.autoScroll*. It goes into _user.js_ in every
|
||||
profile, as a marked block, and Firefox reads that file at every start. The
|
||||
same goes for everything built on Gecko: LibreWolf, Zen, Floorp, Waterfox and
|
||||
Thunderbird.
|
||||
|
||||
Where the profiles are is read from the application's own _application.ini_,
|
||||
the way Firefox works it out: _~/.mozilla/firefox_, or
|
||||
_~/.config/mozilla/firefox_ for a new install of Firefox 147 or later. A Flatpak
|
||||
or a snap has the same inside its own folder. Every profile in _profiles.ini_
|
||||
is covered. The watcher looks at that file too, so a new profile is covered
|
||||
from its second start on.
|
||||
|
||||
A profile where the setting is already on, in Firefox's own settings or in
|
||||
_user.js_, is left alone and not recorded.
|
||||
|
||||
Firefox copies the setting into _prefs.js_, so *disable* takes it out of both
|
||||
files. A Firefox that is still open would write it back when it quits. So for
|
||||
that profile _user.js_ says *false* instead, and the next *disable* or
|
||||
*enable* clears it up.
|
||||
|
||||
# MIDDLE-CLICK PASTE
|
||||
|
||||
Inside a Chromium application the argument settles this on its own: with
|
||||
@@ -269,8 +294,12 @@ _~/.config/kwinrc_
|
||||
written when the desktop's middle-click paste is turned off, and put
|
||||
back by *disable*.
|
||||
|
||||
_user.js_ in every Firefox profile
|
||||
Gets a block between *// >>> middleclick-autoscroll* and
|
||||
*// <<< middleclick-autoscroll*. Nothing else in the file is touched.
|
||||
|
||||
_~/.cache/middleclick-autoscroll/detect_
|
||||
Which programs were found to be Chromium, keyed by size and modification
|
||||
Which programs were found to be Chromium or Gecko, keyed by size and modification
|
||||
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.
|
||||
|
||||
@@ -39,6 +39,9 @@ msgstr "soubor s příznaky"
|
||||
msgid "launcher"
|
||||
msgstr "spouštěč"
|
||||
|
||||
msgid "profile"
|
||||
msgstr "profil"
|
||||
|
||||
msgid "cannot tell"
|
||||
msgstr "nelze určit"
|
||||
|
||||
@@ -131,8 +134,8 @@ msgstr "Nastavení se nepodařilo uložit."
|
||||
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 "No supported applications found."
|
||||
msgstr "Nenalezeny žádné podporované aplikace."
|
||||
|
||||
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."
|
||||
|
||||
@@ -38,6 +38,9 @@ msgstr "Flag-Datei"
|
||||
msgid "launcher"
|
||||
msgstr "Startereintrag"
|
||||
|
||||
msgid "profile"
|
||||
msgstr "Profil"
|
||||
|
||||
msgid "cannot tell"
|
||||
msgstr "nicht erkennbar"
|
||||
|
||||
@@ -131,8 +134,8 @@ msgstr "Einstellung konnte nicht gespeichert werden."
|
||||
msgid "Looking at the installed applications..."
|
||||
msgstr "Installierte Anwendungen werden durchgesehen …"
|
||||
|
||||
msgid "No Chromium-based applications found."
|
||||
msgstr "Keine Chromium-basierten Anwendungen gefunden."
|
||||
msgid "No supported applications found."
|
||||
msgstr "Keine unterstützten Anwendungen gefunden."
|
||||
|
||||
msgid "Anything marked \"cannot tell\" stays off until it is turned on here."
|
||||
msgstr "Was „nicht erkennbar“ ist, bleibt aus, bis es hier eingeschaltet wird."
|
||||
|
||||
@@ -39,6 +39,9 @@ msgstr "archivo de flags"
|
||||
msgid "launcher"
|
||||
msgstr "lanzador"
|
||||
|
||||
msgid "profile"
|
||||
msgstr "perfil"
|
||||
|
||||
msgid "cannot tell"
|
||||
msgstr "no se sabe"
|
||||
|
||||
@@ -132,8 +135,8 @@ msgstr "No se pudo guardar el ajuste."
|
||||
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 "No supported applications found."
|
||||
msgstr "No se encontraron aplicaciones compatibles."
|
||||
|
||||
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í."
|
||||
|
||||
@@ -39,6 +39,9 @@ msgstr "fichier de flags"
|
||||
msgid "launcher"
|
||||
msgstr "lanceur"
|
||||
|
||||
msgid "profile"
|
||||
msgstr "profil"
|
||||
|
||||
msgid "cannot tell"
|
||||
msgstr "indéterminé"
|
||||
|
||||
@@ -132,8 +135,8 @@ msgstr "Impossible d'enregistrer le paramètre."
|
||||
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 "No supported applications found."
|
||||
msgstr "Aucune application prise en charge trouvée."
|
||||
|
||||
msgid "Anything marked \"cannot tell\" stays off until it is turned on here."
|
||||
msgstr ""
|
||||
|
||||
@@ -39,6 +39,9 @@ msgstr "file di flag"
|
||||
msgid "launcher"
|
||||
msgstr "lanciatore"
|
||||
|
||||
msgid "profile"
|
||||
msgstr "profilo"
|
||||
|
||||
msgid "cannot tell"
|
||||
msgstr "incerto"
|
||||
|
||||
@@ -132,8 +135,8 @@ msgstr "Impossibile salvare l'impostazione."
|
||||
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 "No supported applications found."
|
||||
msgstr "Nessuna applicazione supportata trovata."
|
||||
|
||||
msgid "Anything marked \"cannot tell\" stays off until it is turned on here."
|
||||
msgstr ""
|
||||
|
||||
@@ -38,6 +38,9 @@ msgstr ""
|
||||
msgid "launcher"
|
||||
msgstr ""
|
||||
|
||||
msgid "profile"
|
||||
msgstr ""
|
||||
|
||||
msgid "cannot tell"
|
||||
msgstr ""
|
||||
|
||||
@@ -130,7 +133,7 @@ msgstr ""
|
||||
msgid "Looking at the installed applications..."
|
||||
msgstr ""
|
||||
|
||||
msgid "No Chromium-based applications found."
|
||||
msgid "No supported applications found."
|
||||
msgstr ""
|
||||
|
||||
msgid "Anything marked \"cannot tell\" stays off until it is turned on here."
|
||||
|
||||
@@ -39,6 +39,9 @@ msgstr "flagbestand"
|
||||
msgid "launcher"
|
||||
msgstr "starter"
|
||||
|
||||
msgid "profile"
|
||||
msgstr "profiel"
|
||||
|
||||
msgid "cannot tell"
|
||||
msgstr "onbekend"
|
||||
|
||||
@@ -132,8 +135,8 @@ msgstr "De instelling kon niet worden opgeslagen."
|
||||
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 "No supported applications found."
|
||||
msgstr "Geen ondersteunde toepassingen gevonden."
|
||||
|
||||
msgid "Anything marked \"cannot tell\" stays off until it is turned on here."
|
||||
msgstr ""
|
||||
|
||||
@@ -39,6 +39,9 @@ msgstr "plik flag"
|
||||
msgid "launcher"
|
||||
msgstr "skrót"
|
||||
|
||||
msgid "profile"
|
||||
msgstr "profil"
|
||||
|
||||
msgid "cannot tell"
|
||||
msgstr "nie wiadomo"
|
||||
|
||||
@@ -131,8 +134,8 @@ msgstr "Nie udało się zapisać ustawienia."
|
||||
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 "No supported applications found."
|
||||
msgstr "Nie znaleziono obsługiwanych aplikacji."
|
||||
|
||||
msgid "Anything marked \"cannot tell\" stays off until it is turned on here."
|
||||
msgstr ""
|
||||
|
||||
+5
-2
@@ -39,6 +39,9 @@ msgstr "arquivo de flags"
|
||||
msgid "launcher"
|
||||
msgstr "lançador"
|
||||
|
||||
msgid "profile"
|
||||
msgstr "perfil"
|
||||
|
||||
msgid "cannot tell"
|
||||
msgstr "indeterminado"
|
||||
|
||||
@@ -132,8 +135,8 @@ msgstr "Não foi possível salvar a configuração."
|
||||
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 "No supported applications found."
|
||||
msgstr "Nenhum aplicativo compatível encontrado."
|
||||
|
||||
msgid "Anything marked \"cannot tell\" stays off until it is turned on here."
|
||||
msgstr ""
|
||||
|
||||
@@ -39,6 +39,9 @@ msgstr "файл флагов"
|
||||
msgid "launcher"
|
||||
msgstr "ярлык"
|
||||
|
||||
msgid "profile"
|
||||
msgstr "профиль"
|
||||
|
||||
msgid "cannot tell"
|
||||
msgstr "неизвестно"
|
||||
|
||||
@@ -132,8 +135,8 @@ msgstr "Не удалось сохранить настройку."
|
||||
msgid "Looking at the installed applications..."
|
||||
msgstr "Просмотр установленных приложений..."
|
||||
|
||||
msgid "No Chromium-based applications found."
|
||||
msgstr "Приложения на основе Chromium не найдены."
|
||||
msgid "No supported applications found."
|
||||
msgstr "Поддерживаемые приложения не найдены."
|
||||
|
||||
msgid "Anything marked \"cannot tell\" stays off until it is turned on here."
|
||||
msgstr ""
|
||||
|
||||
@@ -39,6 +39,9 @@ msgstr "bayrak dosyası"
|
||||
msgid "launcher"
|
||||
msgstr "başlatıcı"
|
||||
|
||||
msgid "profile"
|
||||
msgstr "profil"
|
||||
|
||||
msgid "cannot tell"
|
||||
msgstr "belirsiz"
|
||||
|
||||
@@ -132,8 +135,8 @@ msgstr "Ayar kaydedilemedi."
|
||||
msgid "Looking at the installed applications..."
|
||||
msgstr "Kurulu uygulamalara bakılıyor..."
|
||||
|
||||
msgid "No Chromium-based applications found."
|
||||
msgstr "Chromium tabanlı uygulama bulunamadı."
|
||||
msgid "No supported applications found."
|
||||
msgstr "Desteklenen 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."
|
||||
|
||||
@@ -39,6 +39,9 @@ msgstr "файл прапорців"
|
||||
msgid "launcher"
|
||||
msgstr "ярлик"
|
||||
|
||||
msgid "profile"
|
||||
msgstr "профіль"
|
||||
|
||||
msgid "cannot tell"
|
||||
msgstr "невідомо"
|
||||
|
||||
@@ -131,8 +134,8 @@ msgstr "Не вдалося зберегти налаштування."
|
||||
msgid "Looking at the installed applications..."
|
||||
msgstr "Перегляд встановлених застосунків..."
|
||||
|
||||
msgid "No Chromium-based applications found."
|
||||
msgstr "Застосунків на основі Chromium не знайдено."
|
||||
msgid "No supported applications found."
|
||||
msgstr "Підтримуваних застосунків не знайдено."
|
||||
|
||||
msgid "Anything marked \"cannot tell\" stays off until it is turned on here."
|
||||
msgstr ""
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[Unit]
|
||||
Description=Watch for newly installed Chromium-based applications
|
||||
Description=Watch for newly installed applications
|
||||
Documentation=man:middleclick-autoscroll(1)
|
||||
|
||||
[Path]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[Unit]
|
||||
Description=Apply middle-click autoscroll to Chromium-based applications
|
||||
Description=Apply middle-click autoscroll
|
||||
Documentation=man:middleclick-autoscroll(1)
|
||||
|
||||
[Service]
|
||||
|
||||
+45
-13
@@ -16,6 +16,7 @@ MCA_ROUTES=()
|
||||
# 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
|
||||
# gecko - a setting in each of the application's profiles
|
||||
# unknown - cannot tell what engine this is (an AppImage), so nothing is done
|
||||
# off - detected, but switched off
|
||||
#
|
||||
@@ -27,7 +28,7 @@ MCA_ROUTE=''
|
||||
mca_route() {
|
||||
local kind="$1" id="$2" prog="$3" packaging="${4:-native}"
|
||||
|
||||
if [[ $kind == steam || $kind == spotify ]]; then
|
||||
if [[ $kind == steam || $kind == spotify || $kind == gecko ]]; then
|
||||
if mca_config_list_has Skip "$id"; then
|
||||
MCA_ROUTE=off
|
||||
else
|
||||
@@ -65,6 +66,7 @@ mca_apply() {
|
||||
MCA_CHANGES=0
|
||||
MCA_ROUTES=()
|
||||
MCA_N_ON=0; MCA_N_OFF=0; MCA_N_UNKNOWN=0
|
||||
MCA_GECKO_SEEN=(); MCA_GECKO_WATCH=()
|
||||
|
||||
mca_config_load
|
||||
|
||||
@@ -116,6 +118,9 @@ mca_apply() {
|
||||
(( spotify_done )) || mca_spotify_apply
|
||||
spotify_done=1
|
||||
;;
|
||||
gecko)
|
||||
mca_gecko_apply "${MCA_PROFILES[i]}" "$packaging" "$prog"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -178,7 +183,8 @@ 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.
|
||||
# name this system actually uses. The same goes for where Firefox and its forks
|
||||
# keep their profiles, which depends on what is installed.
|
||||
MCA_UNIT_DROPIN="${MCA_XDG_CONFIG}/systemd/user/${MCA_UNIT_PATH}.d"
|
||||
|
||||
mca_watch_available() {
|
||||
@@ -196,23 +202,47 @@ mca_watch_enabled() {
|
||||
# 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 $?; }
|
||||
local dir path content='' changed=1
|
||||
|
||||
# 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'
|
||||
dir="$(mca_desktop_folder)"
|
||||
[[ -d $dir ]] && content="[Path]"$'\n'"PathModified=${dir//%/%%}"$'\n'
|
||||
_mca_watch_conf desktop.conf "$content" && changed=0
|
||||
|
||||
mca_write_if_changed "$file" "$content"
|
||||
# Filled by the apply that ran just before. A new profile is added there.
|
||||
content=''
|
||||
for path in "${MCA_GECKO_WATCH[@]}"; do
|
||||
content+="PathChanged=${path//%/%%}"$'\n'
|
||||
done
|
||||
[[ -n $content ]] && content="[Path]"$'\n'"$content"
|
||||
_mca_watch_conf profiles.conf "$content" && changed=0
|
||||
|
||||
return "$changed"
|
||||
}
|
||||
|
||||
# _mca_watch_conf <name> <content>
|
||||
# Writes one drop-in, or removes it when the content is empty. Returns 0 when
|
||||
# it changed.
|
||||
_mca_watch_conf() {
|
||||
local file="$MCA_UNIT_DROPIN/$1"
|
||||
|
||||
if [[ -n $2 ]]; then
|
||||
mca_write_if_changed "$file" "$2"
|
||||
return
|
||||
fi
|
||||
|
||||
[[ -e $file ]] || return 1
|
||||
rm -f -- "$file"
|
||||
rmdir "$MCA_UNIT_DROPIN" 2>/dev/null || true
|
||||
return 0
|
||||
}
|
||||
|
||||
_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
|
||||
local changed=1
|
||||
_mca_watch_conf desktop.conf '' && changed=0
|
||||
_mca_watch_conf profiles.conf '' && changed=0
|
||||
return "$changed"
|
||||
}
|
||||
|
||||
mca_watch_enable() {
|
||||
@@ -226,7 +256,8 @@ mca_watch_enable() {
|
||||
|
||||
# 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.
|
||||
# which is what a change of session language does to it, and with the Firefox
|
||||
# profiles there are now.
|
||||
mca_watch_refresh() {
|
||||
mca_watch_available || return 0
|
||||
_mca_watch_dropin_write || return 0
|
||||
@@ -295,6 +326,7 @@ mca_route_label() {
|
||||
desktop) mca_msg "launcher" ;;
|
||||
steam) mca_msg "Steam" ;;
|
||||
spotify) printf 'spotify-launcher' ;;
|
||||
gecko) mca_msg "profile" ;;
|
||||
unknown) mca_msg "cannot tell" ;;
|
||||
*) mca_msg "off" ;;
|
||||
esac
|
||||
|
||||
+3
-1
@@ -283,11 +283,13 @@ mca_state_write() {
|
||||
# inplace <edited file> <basename of its backup copy>
|
||||
# flags <flag file> created | appended | merged
|
||||
# kwin <kwinrc> what EnablePrimarySelection said before
|
||||
# gecko <user.js in a profile> created | block
|
||||
#
|
||||
# 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.
|
||||
# copy of it back would take everything else settled since with it. A user.js
|
||||
# loses its block, and prefs.js the line Firefox copied out of it.
|
||||
|
||||
mca_ledger_add() {
|
||||
local kind="$1" path="$2" detail="${3:-}"
|
||||
|
||||
+53
-8
@@ -343,7 +343,9 @@ _mca_stat_batch() {
|
||||
# taught the hint scan about Discord's launcher, and Discord stayed out of the
|
||||
# list anyway, because /usr/bin/discord had not changed and its old "no" was
|
||||
# still in here.
|
||||
MCA_CACHE_FORMAT="# middleclick-autoscroll detect 2 $MCA_VERSION"
|
||||
#
|
||||
# 3 adds the gecko verdict.
|
||||
MCA_CACHE_FORMAT="# middleclick-autoscroll detect 3 $MCA_VERSION"
|
||||
|
||||
_mca_cache_load() {
|
||||
local path stamp verdict first=1
|
||||
@@ -862,6 +864,8 @@ _mca_appimage_verdict() {
|
||||
# no - something else
|
||||
# unknown - an image whose payload could not be read, so neither answer has
|
||||
# been earned and the applications screen offers it as a choice
|
||||
# gecko:<rel> - Firefox or another Gecko application, which keeps its
|
||||
# profiles in <rel>. See gecko.sh.
|
||||
#
|
||||
# Assigns rather than returns three states through an exit code, and is the one
|
||||
# place the memo and the on-disk cache are consulted.
|
||||
@@ -900,8 +904,11 @@ mca_detect_verdict() {
|
||||
real="$(readlink -f -- "$prog" 2>/dev/null)" || real="$prog"
|
||||
|
||||
MCA_DETECT_UNSURE=0
|
||||
MCA_DETECT_GECKO=''
|
||||
if _mca_detect_uncached "$real"; then
|
||||
MCA_VERDICT=yes
|
||||
elif [[ -n $MCA_DETECT_GECKO ]]; then
|
||||
MCA_VERDICT="gecko:$MCA_DETECT_GECKO"
|
||||
elif (( MCA_DETECT_UNSURE )); then
|
||||
MCA_VERDICT=unknown
|
||||
else
|
||||
@@ -930,6 +937,10 @@ mca_is_chromium() {
|
||||
# was nothing there. Only mca_detect_verdict reads it, straight after the call.
|
||||
MCA_DETECT_UNSURE=0
|
||||
|
||||
# Set by _mca_detect_uncached to where the profiles are, when the program turned
|
||||
# out to be Gecko rather than Chromium.
|
||||
MCA_DETECT_GECKO=''
|
||||
|
||||
_mca_detect_uncached() {
|
||||
local real="$1" depth="${2:-0}" dir target
|
||||
|
||||
@@ -943,6 +954,7 @@ _mca_detect_uncached() {
|
||||
if target="$(_mca_script_target "$real")" && [[ -n $target ]]; then
|
||||
_mca_detect_uncached "$(readlink -f -- "$target" 2>/dev/null || printf '%s' "$target")" \
|
||||
$(( depth + 1 )) && return 0
|
||||
[[ -n $MCA_DETECT_GECKO ]] && return 1
|
||||
fi
|
||||
grep -qE "$MCA_SCRIPT_HINTS" -- "$real" 2>/dev/null && return 0
|
||||
return 1
|
||||
@@ -954,6 +966,14 @@ _mca_detect_uncached() {
|
||||
_mca_has_markers "$dir" && return 0
|
||||
[[ ${dir##*/} == bin ]] && _mca_has_markers "${dir%/*}" && return 0
|
||||
|
||||
# Not Chromium but Gecko, which has autoscroll of its own.
|
||||
if _mca_gecko_rel "$dir" \
|
||||
|| { [[ ${dir##*/} == bin ]] && _mca_gecko_rel "${dir%/*}"; }
|
||||
then
|
||||
MCA_DETECT_GECKO="$MCA_GECKO_REL"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# An AppImage keeps all of that inside a filesystem appended to itself, so
|
||||
# there is nothing next to the binary to find. But the names of everything
|
||||
# in there can be read, and that settles it either way.
|
||||
@@ -989,8 +1009,9 @@ 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 | spotify | unknown | no
|
||||
MCA_KINDS=() # app | browser | steam | spotify | gecko | unknown | no
|
||||
MCA_PACKAGING=() # native | flatpak | snap
|
||||
MCA_PROFILES=() # where a Gecko application keeps its profiles, see gecko.sh
|
||||
|
||||
# A scan reads every desktop entry on the system, so the menu does it once and
|
||||
# then redraws from what it found. Applying rescans on its own, so nothing else
|
||||
@@ -1003,12 +1024,12 @@ mca_scan_once() {
|
||||
}
|
||||
|
||||
mca_scan() {
|
||||
local dir file id name exec_line prog kind packaging i
|
||||
local dir file id name exec_line prog kind packaging profiles i
|
||||
local -A seen=()
|
||||
local -a c_ids=() c_files=() c_names=() c_progs=() c_browser=() c_stat=()
|
||||
|
||||
MCA_IDS=(); MCA_FILES=(); MCA_NAMES=(); MCA_PROGS=(); MCA_KINDS=()
|
||||
MCA_PACKAGING=()
|
||||
MCA_PACKAGING=(); MCA_PROFILES=()
|
||||
|
||||
# Pass one: read the entries and work out what each of them starts. No
|
||||
# detection yet: that needs a stat per program, and those are collected so
|
||||
@@ -1073,6 +1094,7 @@ mca_scan() {
|
||||
prog="${c_progs[i]}"
|
||||
kind=no
|
||||
packaging=native
|
||||
profiles=''
|
||||
|
||||
if [[ $prog == flatpak:* ]]; then
|
||||
packaging=flatpak
|
||||
@@ -1080,6 +1102,8 @@ mca_scan() {
|
||||
kind=steam
|
||||
elif mca_flatpak_is_chromium "${prog#flatpak:}"; then
|
||||
(( c_browser[i] )) && kind=browser || kind=app
|
||||
elif mca_flatpak_gecko "${prog#flatpak:}"; then
|
||||
kind=gecko profiles="$MCA_GECKO_REL"
|
||||
fi
|
||||
prog="${prog#flatpak:}"
|
||||
elif [[ $prog == snap:* ]]; then
|
||||
@@ -1089,6 +1113,8 @@ mca_scan() {
|
||||
kind=steam
|
||||
elif mca_snap_is_chromium "$prog"; then
|
||||
(( c_browser[i] )) && kind=browser || kind=app
|
||||
elif mca_snap_gecko "$prog"; then
|
||||
kind=gecko profiles="$MCA_GECKO_REL"
|
||||
fi
|
||||
elif mca_prog_is_steam "$prog"; then
|
||||
# Steam is Chromium inside, but nothing about it can be changed
|
||||
@@ -1103,6 +1129,7 @@ mca_scan() {
|
||||
case "$MCA_VERDICT" in
|
||||
yes) (( c_browser[i] )) && kind=browser || kind=app ;;
|
||||
unknown) kind=unknown ;;
|
||||
gecko:*) kind=gecko profiles="${MCA_VERDICT#gecko:}" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
@@ -1114,6 +1141,7 @@ mca_scan() {
|
||||
MCA_PROGS+=("$prog")
|
||||
MCA_KINDS+=("$kind")
|
||||
MCA_PACKAGING+=("$packaging")
|
||||
MCA_PROFILES+=("$profiles")
|
||||
done
|
||||
|
||||
mca_cache_flush
|
||||
@@ -1211,16 +1239,14 @@ mca_snap_is_chromium() {
|
||||
# Flatpak keeps every application in its own tree, so the marker check works the
|
||||
# same way once that tree has been located.
|
||||
mca_flatpak_is_chromium() {
|
||||
local id="$1" loc
|
||||
mca_have flatpak || return 1
|
||||
local id="$1"
|
||||
|
||||
if [[ -n ${MCA_DETECT_MEMO[flatpak:$id]+set} ]]; then
|
||||
[[ ${MCA_DETECT_MEMO[flatpak:$id]} == yes ]]
|
||||
return $?
|
||||
fi
|
||||
|
||||
loc="$(flatpak info --show-location "$id" 2>/dev/null)"
|
||||
if [[ -n $loc ]] && _mca_find_markers "$loc/files" 4; then
|
||||
if mca_flatpak_location "$id" && _mca_find_markers "$MCA_FLATPAK_AT/files" 4; then
|
||||
MCA_DETECT_MEMO[flatpak:$id]=yes
|
||||
return 0
|
||||
fi
|
||||
@@ -1229,6 +1255,25 @@ mca_flatpak_is_chromium() {
|
||||
return 1
|
||||
}
|
||||
|
||||
# mca_flatpak_location <app id>
|
||||
# Where Flatpak keeps the application, in MCA_FLATPAK_AT. Assigned rather than
|
||||
# printed so the memo survives: both the Chromium and the Gecko check ask.
|
||||
declare -A MCA_FLATPAK_LOC=()
|
||||
MCA_FLATPAK_AT=''
|
||||
|
||||
mca_flatpak_location() {
|
||||
local id="$1"
|
||||
|
||||
if [[ -z ${MCA_FLATPAK_LOC[$id]+set} ]]; then
|
||||
MCA_FLATPAK_LOC[$id]=''
|
||||
mca_have flatpak \
|
||||
&& MCA_FLATPAK_LOC[$id]="$(flatpak info --show-location "$id" 2>/dev/null)"
|
||||
fi
|
||||
|
||||
MCA_FLATPAK_AT="${MCA_FLATPAK_LOC[$id]}"
|
||||
[[ -n $MCA_FLATPAK_AT ]]
|
||||
}
|
||||
|
||||
# mca_kind_wanted <kind> <id>
|
||||
# Whether this entry should be patched. Skip beats everything, an explicit
|
||||
# include beats detection, and detection beats nothing.
|
||||
|
||||
@@ -0,0 +1,254 @@
|
||||
# shellcheck shell=bash
|
||||
#
|
||||
# Firefox, and everything else built on Gecko: LibreWolf, Zen, Floorp,
|
||||
# Waterfox, Thunderbird.
|
||||
#
|
||||
# Gecko has autoscroll of its own, off on Linux. There is no command line flag
|
||||
# for it, only a setting: general.autoScroll. Settings live in each profile, so
|
||||
# the line goes into the profile's user.js, which Gecko reads at every start.
|
||||
#
|
||||
# Gecko copies what user.js sets into prefs.js. So undoing takes the line out
|
||||
# of prefs.js as well. A browser that is still open would write it back when it
|
||||
# quits, so for that profile user.js says false instead, and the record stays
|
||||
# until the next undo can finish the job.
|
||||
|
||||
MCA_GECKO_BEGIN='// >>> middleclick-autoscroll'
|
||||
MCA_GECKO_END='// <<< middleclick-autoscroll'
|
||||
MCA_GECKO_ON='user_pref("general.autoScroll", true);'
|
||||
MCA_GECKO_OFF='user_pref("general.autoScroll", false);'
|
||||
|
||||
# The profile folders one apply has done already, and the profiles.ini files
|
||||
# the watcher should look at. Both are filled by mca_gecko_apply.
|
||||
declare -A MCA_GECKO_SEEN=()
|
||||
MCA_GECKO_WATCH=()
|
||||
|
||||
# Set by mca_gecko_revert when a profile is still open and has to be undone
|
||||
# again later.
|
||||
MCA_GECKO_PENDING=0
|
||||
|
||||
# _mca_gecko_rel <directory>
|
||||
# Whether a Gecko application is installed there. If so, where it keeps its
|
||||
# profiles, relative to the home or config folder, in MCA_GECKO_REL. Read from
|
||||
# application.ini the way Gecko does it: [App] Profile= when it is set, else
|
||||
# Vendor/Name, in lowercase.
|
||||
MCA_GECKO_REL=''
|
||||
|
||||
_mca_gecko_rel() {
|
||||
local dir="$1" line group='' vendor='' name='' profile='' rel=''
|
||||
|
||||
MCA_GECKO_REL=''
|
||||
[[ -e $dir/libxul.so && -r $dir/application.ini ]] || return 1
|
||||
|
||||
while IFS= read -r line || [[ -n $line ]]; do
|
||||
line="${line%$'\r'}"
|
||||
case "$line" in
|
||||
'['*) group="$line" ;;
|
||||
Vendor=*) [[ $group == '[App]' ]] && vendor="${line#*=}" ;;
|
||||
Name=*) [[ $group == '[App]' ]] && name="${line#*=}" ;;
|
||||
Profile=*) [[ $group == '[App]' ]] && profile="${line#*=}" ;;
|
||||
esac
|
||||
done < "$dir/application.ini"
|
||||
|
||||
if [[ -n $profile ]]; then
|
||||
rel="${profile//\\//}"
|
||||
while [[ $rel == /* ]]; do rel="${rel#/}"; done
|
||||
rel="${rel#.}"
|
||||
elif [[ -n $name ]]; then
|
||||
rel="${vendor:+$vendor/}$name"
|
||||
fi
|
||||
|
||||
# Gecko lowercases in ASCII. A Turkish locale turns I into a dotless ı.
|
||||
rel="${rel,,}"
|
||||
rel="${rel//ı/i}"
|
||||
|
||||
[[ -n $rel && /$rel/ != */../* ]] || return 1
|
||||
MCA_GECKO_REL="$rel"
|
||||
}
|
||||
|
||||
# _mca_gecko_tree <root> <depth>
|
||||
# The same for a Flatpak or a snap, where libxul.so is somewhere in the tree.
|
||||
_mca_gecko_tree() {
|
||||
local lib
|
||||
|
||||
MCA_GECKO_REL=''
|
||||
[[ -d $1 ]] || return 1
|
||||
lib="$(find "$1" -maxdepth "$2" -name libxul.so -print -quit 2>/dev/null)"
|
||||
[[ -n $lib ]] && _mca_gecko_rel "${lib%/*}"
|
||||
}
|
||||
|
||||
# mca_flatpak_gecko <app id> / mca_snap_gecko <snap name>
|
||||
# Whether it is Gecko, with the folder in MCA_GECKO_REL. Memoized like the
|
||||
# Chromium check, and an empty answer means no.
|
||||
declare -A MCA_GECKO_MEMO=()
|
||||
|
||||
mca_flatpak_gecko() {
|
||||
local key="flatpak:$1"
|
||||
|
||||
if [[ -z ${MCA_GECKO_MEMO[$key]+set} ]]; then
|
||||
MCA_GECKO_REL=''
|
||||
mca_flatpak_location "$1" && _mca_gecko_tree "$MCA_FLATPAK_AT/files" 4
|
||||
MCA_GECKO_MEMO[$key]="$MCA_GECKO_REL"
|
||||
fi
|
||||
|
||||
MCA_GECKO_REL="${MCA_GECKO_MEMO[$key]}"
|
||||
[[ -n $MCA_GECKO_REL ]]
|
||||
}
|
||||
|
||||
mca_snap_gecko() {
|
||||
local key="snap:$1" d
|
||||
|
||||
if [[ -z ${MCA_GECKO_MEMO[$key]+set} ]]; then
|
||||
MCA_GECKO_REL=''
|
||||
for d in "${MCA_SNAP_DIRS[@]}"; do
|
||||
_mca_gecko_tree "$d/$1/current" 5 && break
|
||||
done
|
||||
MCA_GECKO_MEMO[$key]="$MCA_GECKO_REL"
|
||||
fi
|
||||
|
||||
MCA_GECKO_REL="${MCA_GECKO_MEMO[$key]}"
|
||||
[[ -n $MCA_GECKO_REL ]]
|
||||
}
|
||||
|
||||
# mca_gecko_roots <rel> <packaging> <name>
|
||||
# Every folder that can hold the application's profiles.ini. An older install
|
||||
# uses ~/.<rel>. A new one (Firefox 147 and later) uses $XDG_CONFIG_HOME/<rel>,
|
||||
# or ~/<rel> for a fork with a profile name of its own. A Flatpak or a snap has
|
||||
# the same inside its own folder.
|
||||
mca_gecko_roots() {
|
||||
local rel="$1" packaging="$2" name="$3" d
|
||||
|
||||
case "$packaging" in
|
||||
flatpak)
|
||||
printf '%s\n' "$HOME/.var/app/$name/.$rel" "$HOME/.var/app/$name/config/$rel"
|
||||
;;
|
||||
snap)
|
||||
for d in common current; do
|
||||
printf '%s\n' "$HOME/snap/$name/$d/.$rel" "$HOME/snap/$name/$d/.config/$rel"
|
||||
done
|
||||
;;
|
||||
*)
|
||||
printf '%s\n' "$HOME/.$rel" "$MCA_XDG_CONFIG/$rel"
|
||||
[[ $rel == */* ]] || printf '%s\n' "$HOME/$rel"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# mca_gecko_profiles <root>
|
||||
# Every profile folder that profiles.ini there lists.
|
||||
mca_gecko_profiles() {
|
||||
local root="$1" line path='' relative=1 inprofile=0
|
||||
|
||||
[[ -r $root/profiles.ini ]] || return 0
|
||||
|
||||
while IFS= read -r line || [[ -n $line ]]; do
|
||||
line="${line%$'\r'}"
|
||||
case "$line" in
|
||||
'['*)
|
||||
_mca_gecko_profile_emit
|
||||
[[ $line == '[Profile'* ]] && inprofile=1 || inprofile=0
|
||||
path='' relative=1
|
||||
;;
|
||||
Path=*) path="${line#Path=}" ;;
|
||||
IsRelative=*) relative="${line#IsRelative=}" ;;
|
||||
esac
|
||||
done < "$root/profiles.ini"
|
||||
_mca_gecko_profile_emit
|
||||
}
|
||||
|
||||
_mca_gecko_profile_emit() {
|
||||
(( inprofile )) && [[ -n $path ]] || return 0
|
||||
[[ $relative == 1 ]] && path="$root/$path"
|
||||
[[ -d $path ]] && printf '%s\n' "$path"
|
||||
return 0
|
||||
}
|
||||
|
||||
# _mca_gecko_write <user.js> <line>
|
||||
# Puts the line into user.js as a marked block, replacing an older block.
|
||||
# Returns like mca_write_if_changed.
|
||||
_mca_gecko_write() {
|
||||
local file="$1" line="$2" content=''
|
||||
|
||||
[[ -f $file ]] && content="$(_mca_flags_drop_block "$file" "$MCA_GECKO_BEGIN" "$MCA_GECKO_END")"
|
||||
content="${content:+$content$'\n'}$MCA_GECKO_BEGIN"$'\n'"$line"$'\n'"$MCA_GECKO_END"
|
||||
mca_write_if_changed "$file" "$content"$'\n'
|
||||
}
|
||||
|
||||
# mca_gecko_apply <rel> <packaging> <name>
|
||||
# Turns autoscroll on in every profile of the application.
|
||||
mca_gecko_apply() {
|
||||
local root profile
|
||||
|
||||
while IFS= read -r root; do
|
||||
[[ -n ${MCA_GECKO_SEEN[$root]+set} ]] && continue
|
||||
MCA_GECKO_SEEN[$root]=1
|
||||
|
||||
# A new profile is written into profiles.ini, so the watcher can pick
|
||||
# it up.
|
||||
MCA_GECKO_WATCH+=("$root/profiles.ini")
|
||||
|
||||
while IFS= read -r profile; do
|
||||
_mca_gecko_profile_apply "$profile"
|
||||
done < <(mca_gecko_profiles "$root")
|
||||
done < <(mca_gecko_roots "$@")
|
||||
}
|
||||
|
||||
_mca_gecko_profile_apply() {
|
||||
local dir="$1" file="$1/user.js" detail=created
|
||||
|
||||
# A user.js that links somewhere else is part of a setup of its own.
|
||||
[[ -L $file ]] && return 0
|
||||
[[ -f $file ]] && detail=block
|
||||
|
||||
if ! grep -qxF -- "$MCA_GECKO_BEGIN" "$file" 2>/dev/null; then
|
||||
# Set by the user already, in user.js or in the browser's own
|
||||
# settings. Their choice: nothing is written and nothing recorded.
|
||||
grep -qE '^[[:space:]]*user_pref\([[:space:]]*"general\.autoScroll"' \
|
||||
-- "$file" 2>/dev/null && return 0
|
||||
grep -qxF -- "$MCA_GECKO_ON" "$dir/prefs.js" 2>/dev/null && return 0
|
||||
fi
|
||||
|
||||
_mca_gecko_write "$file" "$MCA_GECKO_ON"
|
||||
case $? in
|
||||
0) MCA_CHANGES=$(( MCA_CHANGES + 1 )) ;;
|
||||
2) return 0 ;;
|
||||
esac
|
||||
|
||||
# A file this program created stays one it created.
|
||||
mca_ledger_has "$file" && detail="$(mca_ledger_detail "$file")"
|
||||
mca_ledger_add gecko "$file" "$detail"
|
||||
}
|
||||
|
||||
# mca_gecko_revert <user.js> <created|block>
|
||||
# Returns 0 when something changed. Sets MCA_GECKO_PENDING when the profile is
|
||||
# open and the record has to stay.
|
||||
mca_gecko_revert() {
|
||||
local file="$1" detail="$2" dir="${1%/*}" prefs content tmp rc=0
|
||||
|
||||
MCA_GECKO_PENDING=0
|
||||
[[ -f $file && ! -L $file ]] || return 1
|
||||
grep -qxF -- "$MCA_GECKO_BEGIN" "$file" 2>/dev/null || return 1
|
||||
|
||||
# The lock link only exists while the profile is open.
|
||||
if [[ -L $dir/lock ]]; then
|
||||
MCA_GECKO_PENDING=1
|
||||
_mca_gecko_write "$file" "$MCA_GECKO_OFF"
|
||||
return
|
||||
fi
|
||||
|
||||
content="$(_mca_flags_drop_block "$file" "$MCA_GECKO_BEGIN" "$MCA_GECKO_END")"
|
||||
if [[ $detail == created && -z ${content//[[:space:]]/} ]]; then
|
||||
rm -f -- "$file"
|
||||
else
|
||||
printf '%s\n' "$content" > "$file"
|
||||
fi
|
||||
|
||||
prefs="$dir/prefs.js"
|
||||
if [[ -f $prefs && ! -L $prefs ]] && grep -qxF -- "$MCA_GECKO_ON" "$prefs"; then
|
||||
tmp="$(mktemp "$prefs.XXXXXX")" || return 0
|
||||
chmod --reference="$prefs" -- "$tmp" 2>/dev/null || chmod 600 -- "$tmp"
|
||||
# grep says 1 when no line is left, which is fine here.
|
||||
grep -vxF -- "$MCA_GECKO_ON" "$prefs" > "$tmp" || rc=$?
|
||||
if (( rc <= 1 )); then mv -f -- "$tmp" "$prefs"; else rm -f -- "$tmp"; fi
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
+5
-2
@@ -419,13 +419,14 @@ mca_ui_apps() {
|
||||
# The per-row labels are resolved once, here. Looking them up inside the
|
||||
# drawing loop is a fork per row per keypress, and that is enough to make
|
||||
# the arrow keys feel like the screen is reloading.
|
||||
local l_off l_cannot l_on l_steam l_flagfile l_launcher
|
||||
local l_off l_cannot l_on l_steam l_flagfile l_launcher l_profile
|
||||
mca_msg_into "$locale" "off"; l_off="$MCA_MSG_RESULT"
|
||||
mca_msg_into "$locale" "cannot tell"; l_cannot="$MCA_MSG_RESULT"
|
||||
mca_msg_into "$locale" "on"; l_on="$MCA_MSG_RESULT"
|
||||
mca_msg_into "$locale" "Steam"; l_steam="$MCA_MSG_RESULT"
|
||||
mca_msg_into "$locale" "flag file"; l_flagfile="$MCA_MSG_RESULT"
|
||||
mca_msg_into "$locale" "launcher"; l_launcher="$MCA_MSG_RESULT"
|
||||
mca_msg_into "$locale" "profile"; l_profile="$MCA_MSG_RESULT"
|
||||
|
||||
local s_off="${MCA_C_DIM}${l_off}${MCA_C_RESET}"
|
||||
local s_cannot="${MCA_C_DIM}${l_cannot}${MCA_C_RESET}"
|
||||
@@ -434,6 +435,7 @@ mca_ui_apps() {
|
||||
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 s_gecko="${s_on} ${MCA_C_DIM}(${l_profile})${MCA_C_RESET}"
|
||||
|
||||
local clearseq
|
||||
clearseq="$(clear 2>/dev/null)" || clearseq=$'\033[H\033[2J'
|
||||
@@ -444,7 +446,7 @@ mca_ui_apps() {
|
||||
count=${#MCA_IDS[@]}
|
||||
|
||||
if (( count == 0 )); then
|
||||
MCA_UI_MSG="$(mca_msg "No Chromium-based applications found.")"
|
||||
MCA_UI_MSG="$(mca_msg "No supported applications found.")"
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -526,6 +528,7 @@ mca_ui_apps() {
|
||||
steam) shown="$s_steam" ;;
|
||||
flags) shown="$s_flags" ;;
|
||||
spotify) shown="$s_spotify" ;;
|
||||
gecko) shown="$s_gecko" ;;
|
||||
*) shown="$s_desktop" ;;
|
||||
esac
|
||||
pad=$(( 34 - ${#labels[idx]} ))
|
||||
|
||||
+10
-1
@@ -260,8 +260,9 @@ _mca_flags_write() {
|
||||
return 0
|
||||
}
|
||||
|
||||
# _mca_flags_drop_block <file> [begin marker] [end marker]
|
||||
_mca_flags_drop_block() {
|
||||
awk -v b="$MCA_MARK_BEGIN" -v e="$MCA_MARK_END" '
|
||||
awk -v b="${2:-$MCA_MARK_BEGIN}" -v e="${3:-$MCA_MARK_END}" '
|
||||
$0 == b { skip = 1; next }
|
||||
$0 == e { skip = 0; next }
|
||||
!skip
|
||||
@@ -632,6 +633,7 @@ mca_prune_orphans() {
|
||||
|
||||
mca_revert_all() {
|
||||
local kind path detail backup
|
||||
local -a keep=()
|
||||
|
||||
[[ -f $MCA_LEDGER ]] || return 0
|
||||
|
||||
@@ -674,10 +676,17 @@ mca_revert_all() {
|
||||
mca_kde_paste_revert "$path" "$detail" \
|
||||
&& MCA_CHANGES=$(( MCA_CHANGES + 1 ))
|
||||
;;
|
||||
gecko)
|
||||
mca_gecko_revert "$path" "$detail" \
|
||||
&& MCA_CHANGES=$(( MCA_CHANGES + 1 ))
|
||||
# Still open, so not done yet. See gecko.sh.
|
||||
(( MCA_GECKO_PENDING )) && keep+=("$kind"$'\t'"$path"$'\t'"$detail")
|
||||
;;
|
||||
esac
|
||||
done < <(tac "$MCA_LEDGER" 2>/dev/null)
|
||||
|
||||
rm -f -- "$MCA_LEDGER"
|
||||
(( ${#keep[@]} )) && printf '%s\n' "${keep[@]}" > "$MCA_LEDGER"
|
||||
rmdir "$MCA_BACKUPDIR" 2>/dev/null || true
|
||||
return 0
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# middleclick-autoscroll: middle-click autoscroll for Chromium-based
|
||||
# applications on Linux
|
||||
# applications and Firefox on Linux
|
||||
#
|
||||
# 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
|
||||
# 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
|
||||
# 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. Firefox has the same feature behind a setting.
|
||||
#
|
||||
# Copyright (C) 2026 Felitendo
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
@@ -17,7 +17,7 @@ set -uo pipefail
|
||||
|
||||
MCA_LIBDIR="${MCA_LIBDIR:-@LIBDIR@}"
|
||||
|
||||
for _mod in common config detect patch steam kde apply menu; do
|
||||
for _mod in common config detect patch steam gecko 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
|
||||
@@ -144,7 +144,7 @@ mca_do_list() {
|
||||
mca_count_routes
|
||||
|
||||
if (( ${#MCA_IDS[@]} == 0 )); then
|
||||
mca_note "$(mca_msg "No Chromium-based applications found.")"
|
||||
mca_note "$(mca_msg "No supported applications found.")"
|
||||
return 0
|
||||
fi
|
||||
|
||||
|
||||
Reference in new issue
Block a user