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

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

16
задан 9 April 2015 в 14:28

3 ответа

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

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

Информация по теме

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

Я написал сценарий, который использует диалоги 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://askubuntu.com/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 или chrome-browser; по какой-то глупой причине в некоторых программах свойство окна WM_CLASS написано заглавными буквами, тогда как программа, указанная в dpkg --get-selections , написана в нижнем регистре (просто прочтите man wmctrl и запустите wmctrl -lx , вы знаете). Добавление этого -ax должно позаботиться об этом. Сценарий вызывает уже открытое окно хрома, как и должно

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

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

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

Согласно предложению в комментариях, встроенная анимация удалена, только опубликованная ссылка. Сообщите, если он сломан! http://i.stack.imgur.com/puuPZ.gif

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

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

#!/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://askubuntu.com/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

enter image description here

Бонус:

Я действительно нашел Albert , который является версией Альфреда для Linux, но сам не пробовал. Тем не менее, стоит проверить. Однако, как уже заметил Джейкоб, в нем все еще есть ошибки.

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

enter image description here

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

6
ответ дан 9 April 2015 в 14:28

1. Dash the Second

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

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

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

enter image description here

Сценарий

#!/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 , помимо "настоящие" окна), несколько идентификаторов pid для каждого приложения ( Chromium , Google-chrome ) могут вызывать исключения, которые я исправил в примерах выше. Если у кого-то возникнет проблема, укажите ее.

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

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

    enter image description here

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

      [Desktop Entry]
    Имя = Рывок Второй
    Exec = python3 /path/to/dash_alternative.py
    Значок = / путь / к / dash_alternative.png
    Тип = Приложение
    Скрытый = ложь
     
  4. Перетащите файл .desktop в программу запуска:

5
ответ дан 9 April 2015 в 14:28

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

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

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

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

0
ответ дан 9 April 2015 в 14:28

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

Похожие вопросы: