Используйте несколько WM_CLASS Firefox в одном профиле.

Вопрос или проблема

Я создал профиль Firefox, называемый “app”, с парой расширений для скрытия адресной строки и панели вкладок. Моя цель — создать файлы .desktop для Google Inbox, Calendar и т. д., имитирующие функцию “Добавить на рабочий стол” в Chrome. На данный момент у меня есть файлы .desktop, похожие на

#!/usr/bin/env xdg-open
[Desktop Entry]
Version=1.0
Terminal=false
Type=Application
Name=Google Inbox (Firefox)
Exec=firefox -P app -new-window --class googleinbox inbox.google.com
Icon=email
StartupWMClass=googleinbox

Однако, когда у меня есть более одного из них, все окна группируются под значком первого. Когда я использую xprop WM_CLASS на каждом окне, я обнаруживаю, что у всех действительно WM_CLASS того, которое я открыл первым.

Как можно заставить Firefox обрабатывать флаг -class для каждого окна, а не для каждого профиля?

Правка: Теперь я использую /usr/bin/firefox -P "PROFILE NAME" --class=WMCLASS вместо ужасного скрипта, который я привел ниже, и просто сталкиваюсь с необходимостью создавать новые профили для каждого веб-приложения. Кроме того, я использую этот userChrome.css для удаления адресной строки и панели вкладок.

Поскольку никто, похоже, не имеет специфического ответа для Firefox (вероятно, потому, что этот флаг -class, не будучи задокументированным на странице руководства, не работает должным образом), я просто размещу своё уродливое решение как решение. Если кто-то сможет существенно улучшить его, я дам им ответ.

Я написал следующий скрипт, назвал его firefoxApp.sh и поместил в ~/bin/. Это отвратительный хак, и я стыжусь его. И в то же время горжусь. Я отказался от отдельного профиля Firefox и вместо этого использовал wmctrl, grep и xprop, чтобы изменить WM_CLASS нового окна после задержки (так как окна иногда требуют значительного времени для появления и получения названия). Если бы кто-то мог подсказать мне более точный и надежный способ найти окна для реклассификации, который не страдает от проблем с синхронизацией, этот скрипт был бы значительно улучшен. Я пытался и не смог сделать это с помощью PID запущенного процесса (предположительно, потому что у всего профиля Firefox один корневой PID). Я не буду размещать здесь код этой попытки, поскольку я его больше не имею.

#!/bin/sh
targetclass=$1
url=$2
titlegrep=$3
if [ "$#" -ne 3 ]
then
    echo "USAGE: $0 TARGETCLASS URL TITLEGREP" 1>&2
    exit 1
fi

firefox -P default -new-window "$url" &

sleep 10

# Убедитесь, что только переводы строки разделяют элементы в предстоящем цикле:
IFS='
'

for wid in `wmctrl -l -x | grep $titlegrep | awk '{ print \$1 }'`
do
    xprop -id $wid -f WM_CLASS 8s -set WM_CLASS $targetclass
done

Этот скрипт я вызываю, используя файлы .desktop в ~/.local/share/applications, которые выглядят следующим образом.

#!/usr/bin/env xdg-open
[Desktop Entry]
Version=1.0
Terminal=false
Type=Application
Name=Calendar (Firefox)
Exec=firefoxApp.sh googlecalendar calendar.google.com Calendar
Icon=calendar
StartupWMClass=googlecalendar

Если я захочу, могу использовать более специфическое имя значка, например google-calendar-firefox-app, и затем поместить файл с именем google-calendar-firefox-app.svg в ~/.local/share/icons.

Обновление: Теперь я использую настоятельно отдельные профили для каждого такого “приложения”. Это немного больше работы для настройки, но это можно значительно автоматизировать с помощью другого скрипта который я просто оставлю здесь как Gist, и это работает с Firefox вместо того, чтобы обойти его, уменьшая условия гонок подхода к переименованию окна.

Конечно, значительное недостаток преимущество этого подхода заключается в том, что эти приложения изолированы от основного профиля Firefox и не будут делиться ни одним плагином или расширением с ним. Так, например, вам может понадобиться вручную копировать пароли из LastPass.

Как бонус, скрипт также заполняет файл userChrome.css, чтобы скрыть хром окон в новом профиле, что способствует созданию иллюзии веб-“приложений”. Его можно вызвать с --help, чтобы получить

usage: create_firefox_app.py [-h] [--app_name APP_NAME]
                             [--hide_user_chrome HIDE_USER_CHROME]
                             [--run_after_creating RUN_AFTER_CREATING]
                             URL icon_name

позиционные аргументы:
  URL                   Домашняя страница, которая будет использоваться при открытии новых окон в
                        профиле через файл .desktop.
  icon_name             Имя значка для использования в файле .desktop. Явный путь
                        может быть задан, или что-то, что разрешается с использованием
                        обычного поиска значков (однако это работает; например,
                        для ~/.local/share/icons/gmail.svg вы можете просто ввести
                        gmail.svg).

необязательные аргументы:
  -h, --help            показать это справочное сообщение и выйти
  --app_name APP_NAME   Имя для созданного "приложения" для использования в файле .desktop.
                        Если не указано, будет использована версия URL. (по умолчанию: Нет)
  --hide_user_chrome HIDE_USER_CHROME
                        Указывает, нужно ли генерировать файл userChrome.css, который будет скрывать
                        хром окон во всех окнах, созданных в новом профиле.
                        Полезно для придания веб-приложениям большей схожести с приложениями.
                        (по умолчанию: True)
  --run_after_creating RUN_AFTER_CREATING
                        Указывает, нужно ли запускать новое приложение после его создания.
                        (по умолчанию: True)

Если вы включите опцию hide_user_chrome и вам нужно будет её вернуть по какой-либо причине, например, чтобы установить расширение, просто удалите сгенерированный файл ~/.mozilla/firefox/PROFILE/chrome/userChrome.css и перезапустите профиль.

Думаю, это тоже сюда подходит:
Я придумал это чудовище (личное мнение… Я бы хотел, чтобы оно работало с sh 🙂 ) Оно содержит несколько трюков, но довольно надёжно для двух окон.. Вы могли бы также указать другие окна, но они должны быть добавлены вручную, добавив больше "specificprofile1" вместе с соответствующей функцией.. Может быть, кто-то мог бы сделать это более.. логичным!

#!/bin/bash
# chromium-start.sh $1 
# например, укажите: 
# chrome-start.sh "Profile 1" в .desktop Exec=
# wmctrl -o 1366,0 ; chromium-browser %U --profile-directory=Profile\ 2 & sleep 3; wmctrl -o 0,0

# $1 = Имя папки профиля

profilename=$1

#2-ой профиль Chromium
specificprofile1="Profile 1"

echo "запуск Chromium"
echo "аргументы: " $1
echo "Имя профиля: " $profilename
echo "Специфический профиль: " $specificprofile1

# Просто устанавливаю переменную масштабирования Chromium, потому что, конечно, разработчики Google не заботятся об отсутствии дробного масштабирования на Linux
scale_var=0.8

# Проверка, существует ли окно Chromium с указанным классом
# Также позволяет использовать значки в качестве "переключателей панели задач" (нажатие на значок переходит в соответствующее окно Chromium)
if wmctrl -l -x | grep "chromium-$profilename"
then
echo "Окно Chromium существует, перемещаем фокус на него"
wmctrl -x -R chromium-"$profilename"
echo "верно"

# Проверка, был ли запущен второй профиль $specifiedprofile1 или нет. Классы WMCLASS должны быть установлены правильно...
elif [[ "$specificprofile1" == "$profilename" ]] && [[ ! "`wmctrl -l -x | grep chromium-"$specificprofile1"`" ]]
then
    # TODO: Вложенность
    if [ "$specificprofile1" == "$profilename" ]
    then
    echo $specificprofile1 "равно" $profilename
    fi
echo "#2 Окно Chromium для $specificprofile1 не существует"
# wmctrl перемещает в конкретное положение на рабочем столе (1366 означает переход на следующее рабочее пространство, так как моё разрешение 1366x768)
# Будьте осторожны при использовании тайминга сна, так как команда должна иметь достаточно времени для выполнения, чтобы окно находилось в правильном рабочем пространстве
wmctrl -o 1366,0
chromium-browser  --profile-directory="$profilename" --force-device-scale-factor=$scale_var %U &
# https://askubuntu.com/a/626524/654028
# Устанавливает последнее открытое окно Chromium, чтобы оно имело пользовательский класс, так как Chromium не заботится о флаге --class=...
# Это имеет свои ограничения, но должно быть достаточно надёжным для большинства использования... Не было протестировано в долгосрочной перспективе.. Что-то, вероятно, может снова сбросить WM_CLASS
# xprop -id "$(wmctrl -l -x| grep "chromium-browser" | tail -n 1 |awk '{ print $1 }')" -f WM_CLASS 8s -set WM_CLASS "chromium-browser.chromium-$specificprofile1"

# Альтернативный метод проверки, существует ли окно с указанным классом
# xprop -id "$(wmctrl -l -x| grep "chromium-$profilename" | tail -n 1 |awk '{ print $1 }')" | grep -o "WM_CLASS(STRING) = ".*"" | grep -o '".*"' | tr -d '"'

# https://stackoverflow.com/a/19441380/5776626
winrep=""
while [[ ! "`echo $winrep | grep -l "Map State: IsViewable"`" ]]
do
    winid="$(wmctrl -l -x| grep "chromium-$profilename" | tail -n 1 |awk '{ print $1 }')"
    # print $winid
    winrep="$(xwininfo -id $winid | grep -o 'Map State: IsViewable')"
    # print $winrep
    sleep 0.75
    xprop -id "$(wmctrl -l -x| grep "chromium-browser" | tail -n 1 |awk '{ print $1 }')" -f WM_CLASS 8s -set WM_CLASS "chromium-browser.chromium-$specificprofile1"
done
# sleep 3

# Перемещение окна непосредственно на рабочее пространство (#2 с разрешением 1366x768 x = 1366), опционально отключите wmctrl -o 1366,0
# wmctrl -v -i -r $winid -e 0,1366,0,-1,-1

# sleep 5
# Возврат на рабочее пространство #1
wmctrl -o 0,0

elif ! wmctrl -l -x | grep chromium-"$profilename"
then
echo "#3 Окно Chromium $profilename не существует"
wmctrl -o 0,0
chromium-browser  --profile-directory="$profilename" --force-device-scale-factor=$scale_var %U &

# https://askubuntu.com/a/626524/654028
# ....
# sleep 3

winrep=""
while [[ ! "`echo $winrep | grep -l "Map State: IsViewable"`" ]]
do
    winid="$(wmctrl -l -x| grep "chromium-$profilename" | tail -n 1 |awk '{ print $1 }')"
    # print $winid
    winrep="$(xwininfo -id $winid | grep -o 'Map State: IsViewable')"
    # print $winrep
    sleep 0.75
    xprop -id "$(wmctrl -l -x| grep "chromium-browser" | tail -n 1 |awk '{ print $1 }')" -f WM_CLASS 8s -set WM_CLASS "chromium-browser.chromium-$profilename"
done
wmctrl -o 0,0
# xprop -id "$(wmctrl -l -x| grep "chromium-browser" | tail -n 1 |awk '{ print $1 }')" -f WM_CLASS 8s -set WM_CLASS "chromium-browser.chromium-$profilename"
fi

Проблемы:

При печати возникают ошибки (предупреждения об устаревании..):

Unescaped left brace in regex is deprecated, passed through in regex; marked by <-- HERE in m/%{ <-- HERE (.*?)}/ at /usr/bin/print line 528.

Для отладки вы можете использовать следующее, чтобы выводить ошибки при использовании фактических значков:
https://askubuntu.com/a/664272/654028 (# Ручная альтернатива)

awk '/^Exec=/ {sub("^Exec=", ""); gsub(" ?%[cDdFfikmNnUuv]", ""); exit system($0)}' chrome-ws2.desktop

цикл while зависает, вероятно, из-за интервала цикла

Error: no such file "at while function"
xwininfo: error: -id требует аргумент
xprop: ошибка: Неправильный формат id окна: .
xwininfo: ошибка: -id требует аргумент
xprop: ошибка: Неправильный формат id окна: .
xwininfo: ошибка: -id требует аргумент
xprop: ошибка: Неправильный формат id окна: .

Также при слишком быстром нажатии соответствующего значка .desktop (до того, как пользовательский класс был установлен?), откроется новое окно..

(значительно) Иногда при запуске из обоих Chromium слишком быстро (~<3с), класс ранее открытого окна сбрасывается на chromium-browser.chromium-browser..
Тогда можно ожидать, что значки поменяются местами или будет неожиданное поведение.

Это известная ошибка, исправленная в Firefox 112.

.

Ответ или решение

Для пользователей, стремящихся настроить браузер Firefox так, чтобы он работал подобно Chrome в режиме "Добавить на рабочий стол", существует ряд проблем и решений. Основная цель заключается в том, чтобы использовать Firefox для создания ярлыков приложений, таких как Google Inbox и Calendar, которые визуально и функционально неотличимы от нативных приложений.

Проблема

Возникновение проблемы связано с тем, что Firefox интерпретирует флаг --class как относящийся ко всему профилю, а не к отдельным окнам. Это приводит к группировке всех окон под один значок в панели задач, что неудобно для пользователей, стремящихся к более точной организации рабочего процесса.

Решение

На момент написания, одним из решений было использование скрипта на Bash, который изменял WM_CLASS окон Firefox в обход. Однако этот подход подвержен гонкам условий. Озвучу рассмотренное решение:

Скрипт на Bash

Скрипт выполняет следующие шаги:

  1. Открывает новое окно Firefox с указанным URL.
  2. Ждет 10 секунд, чтобы окно загружалось.
  3. Использует утилиты wmctrl, grep, и xprop для изменения WM_CLASS нового окна.
#!/bin/sh
targetclass=$1
url=$2
titlegrep=$3
if [ "$#" -ne 3 ]
then
    echo "USAGE: $0 TARGETCLASS URL TITLEGREP" 1>&2
    exit 1
fi

firefox -P default -new-window "$url" &

sleep 10

IFS='
'

for wid in `wmctrl -l -x | grep $titlegrep | awk '{ print \$1 }'`
do
    xprop -id $wid -f WM_CLASS 8s -set WM_CLASS $targetclass
done

Этот скрипт можно вызвать из .desktop файлов, что позволяет создавать отдельные "псевдо-приложения" на рабочем столе.

Альтернативное решение

Позже была предложена идея создания отдельного профиля для каждого "приложения". Хотя это требует дополнительной настройки, этот метод устраняет проблему гонок условий и обеспечивает большую надежность.

Преимущества изоляции

  1. Повышенная безопасность: Каждый профиль действует в изоляции, что ограничивает потенциальные угрозы безопасности.
  2. Настройки и расширения: Хотя профили требуют отдельной установки расширений и плагинов, это позволяет более точно настраивать каждое приложение под конкретные задачи.

Заключение

Важным аспектом является постоянная поддержка и обновления со стороны сообщества Firefox. Вопросы, связанные с WM_CLASS, были подняты в сообществе разработчиков и фиксируются в более поздних версиях браузера. Важно следить за обновлениями, чтобы иметь доступ к новейшим возможностям и исправлению ошибок.

Используйте предлагаемые решения, чтобы повысить эффективность работы и создать более организованное рабочее окружение, используя Firefox в Linux. Помните, что разработка и поддержка пользователей – это динамичный процесс, который требует адаптации и постоянного поиска инновационных решений.

Оцените материал
Добавить комментарий

Капча загружается...