Запускать приложение, только если оно еще не открыто

Я хотел бы имитировать использование Alfred в Mac OS X, где, если вы попытаетесь открыть приложение после его поиска, оно откроет новое окно только в том случае, если программа еще не запущена, в противном случае она установит фокус на в данный момент запущен экземпляр этого приложения. Есть ли способ изменить поведение модуля запуска по умолчанию, чтобы проверить это перед открытием нового окна?

3 ответа

Обновление 7 апреля: добавлена ​​другая версия и найден Альберт, см. Обновление и Бонус ниже!

Относительно функциональности тире: Вы спросили: " Есть ли способ изменить поведение модуля запуска по умолчанию, чтобы проверить это перед открытием нового окна". Основной ответ: нет, как обычный пользователь, у вас нет возможности добавить это поведение в dash. Однако, если бы был разработчик единой области, который хотел бы реализовать это, вы можете обратиться к ним или разработать его самостоятельно, если у вас есть решимость и желание учиться. Мои навыки кодирования очень скромны, поэтому я использую сценарии оболочки и доступный графический интерфейс для сценариев в качестве обходного пути.

Связанная информация

Исходное сообщение:

Я написал скрипт, который использует диалог zenity и wmctrl для достижения того, что вы просили. Обратите внимание, что это графический скрипт, то есть он будет работать только с окнами в графическом интерфейсе и не будет работать, если вы попытаетесь запустить что-то в tty. Кроме того, насколько я понимаю, Альфред делает то же самое. Вы можете создать ярлык на рабочем столе или ярлык для запуска, как описано здесь и здесь.

Сценарий:

#!/bin/bash
# Author: Serg Kolo
# Description: A launcher script that checks whether
#       or not a window of a particular program already exists
#       If a window of such program is open, bring it to focus
#       Otherwise - launch a new window
#       Written for https://Ask-ubuntu.ru/q/440142/295286
# Date: April 6 , 2015
#


MYPROG=$( zenity --entry --title='MY LAUNCHER' --text='Type the name of application to run' )
sleep 0.5
wmctrl -lx | awk '{print $3}' | grep -i "$MYPROG"

if [ $? -eq 0 ]; then
    sleep 1         
    wmctrl -xa $MYPROG
   #as an alternative try the line bellow
   #wmctrl -a $MYPROG
    exit 1
else 
    $MYPROG &
    exit 0
fi

Примечания: в предыдущей версии скрипт использовал echo $? Для проверки успешного завершения предыдущих выражений. Согласно предложению Муру (из редактирования), я изменил код на несколько более компактную версию, поэтому я предлагаю вам взглянуть на предыдущую версию и текущую.

Также ранее wmctrl -a $MYPROG не работал с тестированием Google-Chrome или Chromium-браузера; по какой-то глупой причине некоторые программы имеют свойство WM_CLASS заглавной буквы окна, в то время как программа, перечисленная dpkg --get-selections в нижнем регистре (только что прочитал man wmctrl и беги wmctrl -lxузнаешь) Добавление -ax должно позаботиться об этом. Скрипт вызывает уже открытое окно хрома, как и должно

Другое дело - wmctlr несколько странно, потому что иногда ему нужна задержка (имел опыт работы с ним в другом скрипте), поэтому мне пришлось добавить sleep 1 линия. Раньше с Firefox он включался и выключался, но теперь работает плавно.

Сценарий в действии

В приведенной ниже анимации вы можете видеть, что при первом запуске скрипта открывается один экземпляр firefox, и скрипт переключает фокус на это окно; Во втором тесте я открываю новый экземпляр Google-Chrome, который не был открыт ранее. (Примечание: если вы не любите рабочий стол, кстати, это openbox с док-станцией cairo)

Согласно предложению в комментариях, встроенная анимация удалена, размещена только ссылка. Сообщите, если он сломан, пожалуйста!

Обновление, 7 апреля

Я несколько улучшил сценарий, чтобы все программы, перечисленные в выпадающем списке zenity, были перечислены. Теперь пользователю не нужно запоминать каждую программу, а можно просто прокрутить их список с помощью клавиш со стрелками или просто открыть раскрывающееся меню. Кроме того, эта улучшенная версия поднимает окна не по имени, а по идентификатору окна, что дает гораздо лучшую производительность. Обратите внимание, что способ, которым я просматриваю файлы.desktop, отчасти избыточен, с помощью команды cut дважды, но поскольку мой скрипт-фу пока не так хорош, это все, что я могу сделать. Предложения по улучшению приветствуются!

#!/bin/bash
# Author: Serg Kolo
# Description: Second version of a launcher script that checks whether
#       or not a window of a particular program already exists
#       If a window of such program is open, bring it to focus
#       Otherwise - launch a new window
#       Written for https://Ask-ubuntu.ru/q/440142/295286
# Date: April 7 , 2015
#

set -x

MYPROG=$(zenity --entry --text 'Select program from list' --entry-text $(ls /usr/share/applications/*.desktop | cut -d'/' -f5 | cut -d'.' -f1 | xargs echo))
sleep 0.5
# Do we have a window of such program ?
wmctrl -lx| awk '{print $3}'  | grep -i $MYPROG

if [ $? -eq 0 ]; then
    sleep 0.5 # if yes, find that window id, and raise it
    WINID=$(wmctrl -lx | grep -i $MYPROG | awk 'NR==1{print $1}')
    wmctrl -ia $WINID &
 #  exit 0  
else
    echo $MYPROG | grep -i libreoffice
    if [ $? -eq 0  ]
    then
        MYPROG=$(echo $MYPROG | sed 's/-/ --/g')
    fi
    $MYPROG &

#  exit 0 
fi

введите описание изображения здесь

Бонус:

Я действительно нашел Альберта, который является версией Альфреда для Linux, но сам не пробовал. Стоит проверить, хотя. Однако, как уже отметил Джейкоб, он все еще глючит.

Существует приложение под названием Gnome-Do, которое графически похоже на Alfred, однако оно не обладает такой же функциональностью, как этот скрипт.

введите описание изображения здесь

Дайте мне знать, если вам понравился этот скрипт, если что-то нужно исправить, и не забудьте высказать ответ, если вы найдете его полезным

1. Даш Второй

Ниже приведен сценарий, который можно использовать в качестве альтернативы Dash, когда дело доходит до запуска приложений, как описано в вашем вопросе.

Он существует из окна с той же функциональностью, что и Dash; если ввести один или несколько символов приложения, приложение появится в списке. Нажмите Enter, чтобы запустить или поднять приложение, в зависимости от того, запущено оно или нет.

Вы можете вызвать его с помощью комбинации клавиш быстрого доступа или установить значок в панели запуска, чтобы использовать его аналогично Dash (см. Далее ниже) или обоим.

введите описание здесь

Сценарий

#!/usr/bin/env python3
import subprocess
import os
import getpass
import time

user = getpass.getuser()
get = lambda x: subprocess.check_output(["/bin/bash", "-c", x]).decode("utf-8")
skip = ["%F", "%U", "%f", "%u"]; trim = ["chrome", "chromium", "nautilus"]

def apply(command):
    if "libreoffice" in command:
        proc = [l.split()[0] for l in get("ps -u "+user).splitlines() if "soffice.bin" in l]
        module = command.split("--")[-1]
        time.sleep(0.1)
        try:
            ws = sum([[w.split()[0] for w in get("wmctrl -lp").splitlines() if process in w and module in w.lower()] for process in proc], [])[0]
            subprocess.call(["wmctrl", "-ia", ws])
        except IndexError:
            subprocess.Popen(["/bin/bash", "-c", command+"&"])
    else:
        check = command.split("/")[-1][:14]
        proc = [p.split()[0] for p in get("ps -u "+user).splitlines() if check in p]
        time.sleep(0.5)
        try:
            ws = sum([[w.split()[0] for w in get("wmctrl -lp").splitlines() if process in w] for process in proc], [])
            if command == "nautilus":
                real_window = [w for w in ws if "_NET_WM_WINDOW_TYPE_NORMAL" in get("xprop -id "+w)][0]
            else:
                real_window = ws[0]
            subprocess.call(["wmctrl", "-ia", real_window])
        except IndexError:
            subprocess.Popen(["/bin/bash", "-c", command+"&"])
# default directories of .desktop files; globally, locally, LibreOffice- specific when separately installed
globally = "/usr/share/applications"; locally = os.environ["HOME"]+"/.local/share/applications"; lo_dir = "/opt/libreoffice4.4/share/xdg"
# create list of .desktop files; local ones have preference
local_files = [it for it in os.listdir(locally) if it.endswith(".desktop")]
global_files = [it for it in os.listdir(globally) if it.endswith(".desktop")]
lo_spec = [it for it in os.listdir(lo_dir) if it.endswith(".desktop")] if os.path.exists(lo_dir) else []
for f in [f for f in local_files if f in global_files]:
    global_files.remove(f)
for f in [f for f in local_files if f in lo_spec]:
    lo_spec.remove(f)
dtfiles = [globally+"/"+f for f in global_files]+[locally+"/"+f for f in local_files]+[lo_dir+"/"+f for f in lo_spec]
# create list of application names / commands
valid = []
for f in dtfiles:
    content = open(f).read()
    if all(["NoDisplay=true" not in content,"Exec=" in content]):
        lines = content.splitlines()
        name = [l.replace("Name=", "") for l in lines if "Name=" in l][0]
        command = [l.replace("Exec=", "") for l in lines if all(["Exec=" in l, not "TryExec=" in l])][0]
        valid.append((name, command))
valid.sort(key=lambda x: x[0])
# create zenity list + window
list_items = '"'+'" "'.join([f[0] for f in valid])+'"'
proposed = 'zenity --list --text "Type one or more characters... " --column="Application List" '+\
           '--title="Dash the Second" --height 450 --width 300 '+list_items
try:
    choice = subprocess.check_output(["/bin/bash", "-c", proposed]).decode("utf-8").strip().split("|")[0]
    command = [r[1] for r in valid if r[0] == choice][0]
    # command fixes:
    for s in skip:
        command = command.replace(" "+s, "")
    for t in trim:
        if t in command:
            command = t
    apply(command)
except subprocess.CalledProcessError:
    pass

Как пользоваться

Скрипт нужен wmctrl установлены:

sudo apt-get install wmctrl

Затем:

  1. Вставьте скрипт выше в пустой файл, сохраните его как dash_alternative.py
  2. Добавьте его к комбинации клавиш быстрого доступа: Выберите: "Системные настройки" > "Клавиатура" > "Ярлыки" > "Пользовательские ярлыки". Нажмите "+" и добавьте команду:

    python3 /path/to/dash_alternative.py
    

объяснение

Когда скрипт запускается, он перечисляет все приложения, представленные в /usr/share/applications, Он ищет .dektop файлы, создавая список всех имен приложений (из первой строки "Name=") и команду для запуска приложения (из первой строки "Exec=").

Впоследствии создается список Zenity, в котором все приложения представлены в отсортированном виде.

Когда приложение выбрано, скрипт просматривает список запущенных процессов, если приложение запущено. Если это так, соответствующее окно поднимается. Если нет, новый экземпляр открывается.

Заметки

  1. Для запуска скрипта 12.04 (так как оригинальный вопрос был помечен 12.04 просто измените Шебанг на #!/usr/bin/env python и запустить его по команде

    python /path/to/dash_alternative.py
    
  2. Насколько я тестировал, скрипт работает нормально. Команды и их (не) соответствующие имена процессов (например, LibreOffice <> soffice.bin), разные типы окон (nautilus имеет несколько разных типов окон, кроме "настоящих" окон), несколько пидов на приложение (Chromium, Google-chrome) может вызвать исключения, которые я исправил в приведенных выше примерах. Если у кого-то возникнут проблемы, пожалуйста, укажите это.

2. Дополнительно: установка его в качестве альтернативы "настоящему" Dash для запуска приложений

  1. Скопируйте и сохраните скрипт, как указано выше
  2. Сохраните значок ниже (щелкните правой кнопкой мыши> Safe as) как dash_alternative.png

    введите описание здесь

  3. Скопируйте приведенный ниже код в пустой файл и сохраните его в ~/.local/share/applications как dash_thesecond.desktop, Установите правильные пути для /path/to/dash_alternative.py (сценарий) и /path/to/dash_alternative.png (значок)

    [Desktop Entry]
    Name=Dash the Second
    Exec=python3 /path/to/dash_alternative.py
    Icon=/path/to/dash_alternative.png
    Type=Application
    Hidden=false
    
  4. Перетащите .desktop подать на панель запуска:

Для модуля запуска (вертикальная панель в левой части экрана) это уже поведение по умолчанию, так как это интерфейс переключения задач.

Для тире (большой бит, который открывается при нажатии на логотип Ubuntu), нет способа изменить поведение таким образом, без предположительно существенной модификации самого исходного кода.

Однако некоторые приложения уже могут делать это, так как они предназначены для такого поведения. Все приложения, однако, не обязательно должны быть реализованы таким образом.

Однако, как еще одна функция, если вы откроете окно, развернутое с помощью Super+W, и начнете вводить имя приложения, будут показаны только окна для этого приложения.

Другие вопросы по тегам