Как показать (повышают) все окна приложения?

У меня есть приложение с помощью нескольких окон. Как я могу быстро принести все окна того приложения к переднему плану?

Когда я просматриваю приложения путем прокрутки с колесиком прокрутки, оно только показывает одно окно. При движении в следующее окно последнее окно принесено к фону снова.

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

Мое лучшее решение до сих пор минимизирует все окна (Ctrl+Super+D), и затем покажите окна моего приложения с помощью колесика прокрутки.

Существует ли лучшее решение?

21
задан 16 November 2016 в 07:56

4 ответа

РЕДАКТИРОВАНИЕ - новый ответ -

Ответ (ответы) ниже все еще полностью действителен, и таким образом, предложенные опции. Продолжающееся понимание однако заставило меня добавить эту опцию использовать индикатор ниже, который является, вероятно, самым изящным решением.

По сути, это должно, вероятно, заменить опцию 5 (использующий .desktop файл).

Просто выберите приложение из списка, и все окна соответствующего приложения (подарок на текущей области просмотра) повысят:

enter image description here

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

от ppa:

sudo add-apt-repository ppa:vlijm/upfront
sudo apt-get update
sudo apt-get install upfront

... или вручную:

#!/usr/bin/env python3
import signal
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('AppIndicator3', '0.1')
from gi.repository import Gtk, AppIndicator3, GObject
import time
from threading import Thread
import os
import subprocess
import getpass

currpath = os.path.dirname(os.path.realpath(__file__))

class Indicator():
    def __init__(self):
        self.app = 'raise_apps'
        iconpath = os.path.join(currpath, "raise.png")
        self.indicator = AppIndicator3.Indicator.new(
            self.app, iconpath,
            AppIndicator3.IndicatorCategory.OTHER)
        self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE)       
        self.indicator.set_menu(self.create_menu())
        # the thread:
        self.update = Thread(target=self.check_recent)
        # daemonize the thread to make the indicator stopable
        self.update.setDaemon(True)
        self.update.start()

    def create_menu(self):
        # creates the (initial) menu
        self.menu = Gtk.Menu()
        # separator
        initial = Gtk.MenuItem("Fetching list...")
        menu_sep = Gtk.SeparatorMenuItem()
        self.menu.append(initial)
        self.menu.append(menu_sep)
        # item_quit.show() 
        self.menu.show_all()
        return self.menu

    def raise_wins(self, *args):
        index = self.menu.get_children().index(self.menu.get_active())
        selection = self.menu_items2[index][1]
        for w in selection:
            execute(["wmctrl", "-ia", w])

    def set_new(self):
        # update the list, appearing in the menu
        for i in self.menu.get_children():
            self.menu.remove(i)
        for app in self.menu_items2:

            sub = Gtk.MenuItem(app[0])
            self.menu.append(sub)
            sub.connect('activate', self.raise_wins)
        # separator
        menu_sep = Gtk.SeparatorMenuItem()
        self.menu.append(menu_sep)
        # quit
        item_quit = Gtk.MenuItem('Quit')
        item_quit.connect('activate', self.stop)
        self.menu.append(item_quit)
        self.menu.show_all()

    def get_apps(self):
        # calculate screen resolution
        res_output = get("xrandr").split(); idf = res_output.index("current")
        res = (int(res_output[idf+1]), int(res_output[idf+3].replace(",", "")))
        # creating window list on current viewport / id's / application names
        w_data = [l.split() for l in get(["wmctrl", "-lpG"]).splitlines()]
        # windows on current viewport
        relevant = [w for w in w_data if 0 < int(w[3]) < res[0] and 0 < int(w[4]) < res[1]]
        # pids
        pids = [l.split() for l in get(["ps", "-u", getpass.getuser()]).splitlines()]
        matches = [[p[-1], [w[0] for w in relevant if w[2] == p[0]]] for p in pids]
        return [m for m in matches if m[1]]

    def check_recent(self):
        self.menu_items1 = []
        while True:
            time.sleep(4)
            self.menu_items2 = self.get_apps()
            for app in self.menu_items2:
                app[0] = "gnome-terminal" if "gnome-terminal" in app[0] else app[0]
            if self.menu_items2 != self.menu_items1:
                GObject.idle_add(
                    self.set_new, 
                    priority=GObject.PRIORITY_DEFAULT
                    )
            self.menu_items1 = self.menu_items2

    def stop(self, source):
        Gtk.main_quit()

def get(command):
    return subprocess.check_output(command).decode("utf-8")

def execute(command):
    subprocess.Popen(command)

Indicator()
GObject.threads_init()
signal.signal(signal.SIGINT, signal.SIG_DFL)
Gtk.main()
  • Потребности индикатора wmctrl

    sudo apt-get wmctrl
    
  • Скопируйте индикатор в пустой файл, сохраните его как raise_apps.py

  • Скопируйте изображение ниже, сохраните, оно точно назвало raise.png в одном и том же каталоге как индикатор.

    enter image description here

  • Затем просто выполните его командой:

    python3/path/to/raise_apps.py

  • Добавьте, хотите ли Вы Запустить Приложения:

    /bin/bash -c "sleep 10 && python3 /path/to/raise_apps.py" 
    

СТАРЫЙ ОТВЕТ:

О вопросе

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

Ниже пяти опций заботиться об этом, показать, как это может быть сделано. Все опции готовы использоваться. Последняя опция однако довольно экспериментальна; это хорошо работает, но имеет несколько незначительных косметических оборотных сторон, как объяснено в описании опции. Я добавил его, тем не менее, как понятие.

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

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

Для всех опций Вы должны:

  • установка wmctrl если это еще не находится в Вашей системе:

    sudo apt-get install wmctrl
    
  • создайте, если это еще не существует, каталог:

    ~/bin
    

    (объяснение: каталог ~/bin находится в $PATH, таким образом, можно выполнить исполняемые файлы их именем),

  • Скопируйте сценарий, соответствуя опции, вставьте его в пустой файл, сохраните его как raise_app (никакое расширение) в ~/bin и сделайте это исполняемым файлом

В отдельных опциях будут объяснены возможные дополнительные шаги.

Опция 1: выберите приложение путем ввода одного или нескольких символов

  • Нажмите сочетание клавиш, a zenity окно появится
  • Введите один или несколько символов названия приложения в поле записи
  • Нажмите Enter

Это сделает все окна приложения соответствия (на текущей области просмотра), прибывают в переднюю сторону.

повысьте все gnome-terminal окна на текущей области просмотра:

enter image description here

enter image description here

Как использовать:

  • Приведите в порядок набор, как описано в, "Как использовать"
  • Тестовый прогон это командой:

    raise_app
    
  • Если все хорошо работает, добавьте его к комбинации сочетания клавиш по Вашему выбору: Выберите: Параметры настройки системы> "Клавиатура"> "Ярлыки"> "Пользовательские Ярлыки". Нажмите "+" и добавьте команду

Сценарий:

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

def get(command):
    return subprocess.check_output(["/bin/bash", "-c", command]).decode("utf-8")

def execute(command):
    subprocess.Popen(["/bin/bash", "-c", command])
# calculate screen resolution
res_output = get("xrandr").split(); idf = res_output.index("current")
res = (int(res_output[idf+1]), int(res_output[idf+3].replace(",", "")))
# creating window list on current viewport / id's / application names
w_data = [l.split()[0:7] for l in get("wmctrl -lpG").splitlines()]
windows = [[get("ps -u "+getpass.getuser()+" | grep "+w[2]).split()[-1], w[0]]
           for w in w_data if 0 < int(w[3]) < res[0] and 0 < int(w[4]) < res[1]]
# ask user for first characters
try:
    arg = get('zenity --entry --text "first characters" --title "application"').strip()
except subprocess.CalledProcessError:
    pass
# raise matching windows
try:
    [execute("wmctrl -ia "+item[1]) for item in windows if item[0].startswith(arg)]
except (subprocess.CalledProcessError, NameError):
    pass



Опция 2: цикл через приложения и повышение их окна с сочетанием клавиш:

Скажем, у меня есть сценарий ниже под сочетанием клавиш Alt+1. У меня есть несколько окон, открытых из:

  • Firefox
  • терминал гнома
  • наутилус

Текущее состояние:

enter image description here

Я нажимаю однажды Alt+1, все nautilus окна повышены:

<image>

Я нажимаю снова Alt+1, все firefox окна повышены:

<image>

Я нажимаю снова Alt+1, все gnome-terminal окна повышены снова, цикл запускается:

<image>

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

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

    raise_app
    

Затем цикл через Ваши приложения со сгруппированными окнами приложения с Вашим сочетанием клавиш.

Сценарий:

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

include_single = True # set to False if you only want to cycle through apps with multiple windows

def get(command):
    return subprocess.check_output(["/bin/bash", "-c", command]).decode("utf-8")

def execute(command):
    subprocess.Popen(["/bin/bash", "-c", command])

def get_frontmost():
    cmd = "xprop -root"
    frontmost = [l for l in get(cmd).splitlines() if\
                 "ACTIVE_WINDOW(WINDOW)" in l][0].split()[-1]
    return frontmost[:2]+"0"+frontmost[2:]
# calculate screen resolution
res_output = get("xrandr").split(); idf = res_output.index("current")
res = (int(res_output[idf+1]), int(res_output[idf+3].replace(",", "")))
# creating window list on current viewport / id's / application names
w_data = [l.split()[0:7] for l in get("wmctrl -lpG").splitlines()]
windows = [[get("ps -u "+getpass.getuser()+" | grep "+w[2]).split()[-1], w[0]]
           for w in w_data if 0 < int(w[3]) < res[0] and 0 < int(w[4]) < res[1]]
# create application list to cycle through
if include_single == False:
    pre = [it[0] for it in windows]
    apps = sorted(list(set([it for it in pre if pre.count(it) > 1])))
else:
    apps = sorted(list(set([it[0] for it in windows])))
if len(apps) == 0:
    pass
else:
    # get the frontmost window as a last itm in the cycle
    front = get_frontmost()
    front_pid = [l.split()[2] for l in get("wmctrl -lp").splitlines() if front in l][0]
    last_infront = get("ps -u "+getpass.getuser()+" | grep "+front_pid).split()[-1]
    # determine next apllication to raise
    if not last_infront in apps or last_infront == apps[-1]:
        arg = apps[0]
        print(arg)
    else:
        arg = apps[apps.index(last_infront)+1]
    # raise matching windows
    try:
        [execute("wmctrl -ia "+item[1]) for item in windows if item[0] == arg]
    except (subprocess.CalledProcessError, NameError):
        pass



Опция 3: нажмите сочетание клавиш + нажимают на значок средства запуска - или окно приложения для повышения всех окон на текущей области просмотра

Это - вероятно, опция, которая является самой близкой к тому, что описано в вопросе / комментарий.

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

<image>

Повысить все окна наутилуса (ярлык в качестве примера: Alt+1):

  • Нажмите Alt+1, выпуск (!)
  • В течение 3 секунд, также:

    нажмите на значок приложения в средстве запуска

    <image>

    или:

    нажмите на одно из окон приложения

    <image>

    результат:

    <image>


Как использовать:

  • Приведите в порядок набор, как описано в, "Как использовать"
  • Тестовый прогон это командой:

    raise_app
    
  • Если все хорошо работает, добавьте его к комбинации сочетания клавиш по Вашему выбору: Выберите: Параметры настройки системы> "Клавиатура"> "Ярлыки"> "Пользовательские Ярлыки". Нажмите "+" и добавьте команду

Затем:

  • Нажмите свое сочетание клавиш и в течение 3 секунд, также:

    • нажмите на значок приложения в средстве запуска
    • нажмите на одно из окон приложения

Сценарий

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

def get(command):
    return subprocess.check_output(["/bin/bash", "-c", command]).decode("utf-8")

def execute(command):
    subprocess.Popen(["/bin/bash", "-c", command])

def get_frontmost():
    cmd = "xprop -root"
    frontmost = [l for l in get(cmd).splitlines() if\
                 "ACTIVE_WINDOW(WINDOW)" in l][0].split()[-1]
    return frontmost[:2]+"0"+frontmost[2:]

# calculate screen resolution
res_output = get("xrandr").split(); idf = res_output.index("current")
res = (int(res_output[idf+1]), int(res_output[idf+3].replace(",", "")))
# get window data for various purposes
w_data = get("wmctrl -lpG").splitlines()
non_windows = sum([[l.split()[0] for l in w_data if it in l]\
               for it in ("unity-launcher", "unity-panel", "unity-dash", "Hud")], [])
# get id of current window
curr_window = get_frontmost()
# user gets 3 seconds to pick an application window (or launcher icon)
t = 0
while t < 4:
    w_id1 = get_frontmost()
    time.sleep(1)
    w_id2 = get_frontmost()
    if w_id1 == w_id2 or w_id2 in non_windows+[curr_window]:
        t = t+1
    else:
        new_frontmost = w_id2
        break
# raise
try:
    pid = [l.split()[2] for l in w_data if new_frontmost in l]
    wl_data = [l.split() for l in w_data]
    raise_windows = [l[0] for l in wl_data if pid[0] == l[2] and\
                     0 < int(l[3]) < res[0] and 0 < int(l[4]) < res[1]]
    [execute("wmctrl -ia "+item) for item in raise_windows]
except NameError:
    pass


Опция 4: сочетание клавиш называет список опций, показывая количество окон на приложение на текущей области просмотра

Этот оказался более удобным затем, я принял:

При нажатии (снова пример-) сочетание клавиш Alt+1 называет a zenity окно, перечисляя все приложения и количество их окон на текущей области просмотра:

enter image description here

Просто нажатие или стрелок принесет Вам к правильной опции. Нажмите Enter, и все окна выбранного приложения повышены.

Как использовать:

  • Приведите в порядок набор, как описано в, "Как использовать"
  • Тестовый прогон это командой:

    raise_app
    
  • Если все хорошо работает, добавьте его к комбинации сочетания клавиш по Вашему выбору: Выберите: Параметры настройки системы> "Клавиатура"> "Ярлыки"> "Пользовательские Ярлыки". Нажмите "+" и добавьте команду

Сценарий

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

def get(command):
    return subprocess.check_output(["/bin/bash", "-c", command]).decode("utf-8")

def execute(command):
    subprocess.Popen(["/bin/bash", "-c", command])
# calculate screen resolution
res_output = get("xrandr").split(); idf = res_output.index("current")
res = (int(res_output[idf+1]), int(res_output[idf+3].replace(",", "")))
# creating window list on current viewport / id's / application names
w_data = [l.split()[0:7] for l in get("wmctrl -lpG").splitlines()]
windows = [[get("ps -u "+getpass.getuser()+" | grep "+w[2]).split()[-1], w[0]]
           for w in w_data if 0 < int(w[3]) < res[0] and 0 < int(w[4]) < res[1]]
# preparing zenity optionlist
apps = [item[0] for item in windows]
# prevent multiple zenity windows
if apps.count("zenity") > 1:
    pass
elif apps.count("zenity") > 0:
    execute('zenity --info --text "Another Zenity window is open already"')
# preventing empty windowlist
elif len(apps) > 0:
    applist = [[app, str(apps.count(app))] for app in set(apps)]
    applist.sort(key=lambda x: x[1])
    # calling zenity window
    try:
        arg = get('zenity  --list  --text "Choose an application" '+\
               '--title "Current windows" '+\
               '--column "application" '+\
               '--column "windows" '+\
               '--height 250 '+\
               '--width 250 '+\
               (" ").join(sum(applist, [])))
    except subprocess.CalledProcessError:
        pass
    # raise matching windows
    try:
        [execute("wmctrl -ia "+item[1]) \
         for item in windows if arg.startswith(item[0])]
    except (subprocess.CalledProcessError, NameError):
        pass
else:
    execute('zenity --info --text "No windows to list"')



Опция 5: окна повышения запущенных приложений от значка средства запуска

Эта опция существует значка средства запуска с в настоящее время запущенными приложениями в quicklist. Выберите один, и все окна приложений будут повышены.

enter image description here

Средство запуска автоматически обновляется, когда список запущенных приложений (на текущей области просмотра) изменяется. quicklist показывает другой список на других областях просмотра, где окна других приложений открыты (займет 1-2 секунды для адаптации).

Как упомянуто, хотя полностью функциональный, эта опция является предназначенным как понятием. Это имеет несколько незначительных косметических оборотных сторон как есть. Самое важное:

  • Курсор "колесо" продолжает вращаться в течение нескольких секунд после действия. Хотя это не производит функциональность, это - косметическая оборотная сторона.
  • Требуется 1-2 секунды для applicationlist в значке средства запуска, который будет обновлен после списка изменений запущенных приложений.

Кроме того, установка немного более сложна (хотя объяснено подробно ниже):

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

Ниже Вас найдет:

два сценария / значок / a .desktop файл

  1. Подготовьте установку как в, "Как использовать", сохраняют первые (основной-) сценарий как raise_app в ~/bin
  2. Сохраните значок ниже (щелкните правой кнопкой, сохраните как), как raise.png

    <icon>

  3. Скопируйте .desktop файл в пустой файл, отредактируйте строку

        Icon=/path/to/raise.png
    

    к реальному пути к значку (соединяет каналом с пробелами между кавычками),
    Сохраните его как raise.desktop в ~/.local/share/applications

  4. Перетащите .desktop файл к средству запуска для добавления его

  5. скопируйте второй сценарий, вставьте его в пустой файл, сохраните его как update_apps в ~/bin, сделайте это исполняемым файлом.
  6. Добавьте следующую команду к своим приложениям запуска (Тире>, Приложения Запуска> Добавляют):

    update_apps
    
  7. Выйдите из системы и въезжайте задним ходом, чтобы заставить его работать.

Первый сценарий

#!/usr/bin/env python3
import subprocess
import getpass
import sys

arg = sys.argv[1]

def get(command):
    return subprocess.check_output(["/bin/bash", "-c", command]).decode("utf-8")

def execute(command):
    subprocess.Popen(["/bin/bash", "-c", command])
# calculate screen resolution
res_output = get("xrandr").split(); idf = res_output.index("current")
res = (int(res_output[idf+1]), int(res_output[idf+3].replace(",", "")))
# creating window list on current viewport / id's / application names
w_data = [l.split()[0:7] for l in get("wmctrl -lpG").splitlines()]
windows = [[get("ps -u "+getpass.getuser()+" | grep "+w[2]).split()[-1], w[0]]
           for w in w_data if 0 < int(w[3]) < res[0] and 0 < int(w[4]) < res[1]]
try:
    [execute("wmctrl -ia "+item[1]) for item in windows if item[0].startswith(arg)]
except (subprocess.CalledProcessError, NameError):
    pass

Второй сценарий

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

dtfile = os.environ["HOME"]+"/.local/share/applications/raise.desktop"

def get(command):
    return subprocess.check_output(["/bin/bash", "-c", command]).decode("utf-8")

def execute(command):
    subprocess.Popen(["/bin/bash", "-c", command])
# calculate screen resolution
res_output = get("xrandr").split(); idf = res_output.index("current")
res = (int(res_output[idf+1]), int(res_output[idf+3].replace(",", "")))
# creating window list on current viewport / id's / application names
def applist():
    try:
        w_data = [l.split()[0:7] for l in get("wmctrl -lpG").splitlines()]
        windows = [[get("ps -u "+getpass.getuser()+" | grep "+w[2]).split()[-1], w[0]]
                   for w in w_data if 0 < int(w[3]) < res[0] and 0 < int(w[4]) < res[1]]
    except subprocess.CalledProcessError:
        return []
    else:
        return set([app[0] for app in windows])

def update_dtfile(applications, text):
    actionline = "Actions="+(";").join(applications)+";\n"
    with open(dtfile) as src:
        lines = src.readlines()
    lines = lines[:[i for i in range(len(lines)) \
                 if lines[i].startswith("Actions=")][0]]+[actionline]
    for item in text:
        for it in item:
            lines.append(it)
    with open(dtfile, "wt") as out:
        for line in lines:
            out.write(line)

while True:
    apps1 = applist()
    time.sleep(1)
    apps2 = applist()
    if apps1 != apps2: 
        text = [["[Desktop Action "+it+"]\n", "Name="+it+"\n",
            "Exec=raise_app "+it+"\n", "OnlyShowIn=Unity;\n\n",
            ]for it in apps2]
        update_dtfile(apps2, text)

.desktop файл

[Desktop Entry]
Name=Raise application windows
Comment=Raise groups of windows
Icon=/path/to/raise.png
Terminal=false
Type=Application
Version=1.0

Actions=



Краткое объяснение

Все решения выше использования wmctrl создать список окна, с помощью wmctrl -lpG команда. Эта команда продолжает линии, будучи похож:

0x044000b3  0 3429   65   24   1615 1026 jacob-System-Product-Name unity - How to show all windows of an application? - Ask Ubuntu - Mozilla Firefox

Эти строки включают:

  • 1-й столбец: идентификатор окна (что мы можем использовать для повышения его),
  • 3-й столбец: pid, который владеет окном.
  • 4-й / 5-й столбец: геометрия окна x-y (что мы используем, чтобы видеть, находится ли окно на текущей области просмотра, i.c.w xrandr)

Pid ищется в выводе ps -u <username> получить "читаемую пользователем" идентификацию (название) приложения.
Таким образом мы можем выделить окна приложениям. Впоследствии мы можем повысить окна данного приложения в a for цикл с командой wmctrl -ia.

В опции 3
сценарий запускает 3-вторых циклов "ожидания", с помощью xprop -root управляйте неоднократно, чтобы видеть, существует ли какое-либо изменение в том, что является frontmost окном; это произойдет, если пользователь или нажмет на значок средства запуска для повышения окна приложения или нажмет на окно непосредственно. Если так, цикл с условием продолжения повреждается и ищет "новое" frontmost приложение и впоследствии повышает все другие окна того приложения.

21
ответ дан 23 November 2019 в 01:44

Если Вы нажимаете Alt+Tab для циклического повторения через приложения, и Вы добираетесь до одного с несколькими окнами, просто продолжаете удерживать клавишу Alt и приблизительно после 1 целой секунды, значок будет заменен в целях всех окон для того приложения.

, Который может или не может быть тем, что Вы ищете, но это работает на меня и является более простой тонной, таким образом, я полагал, что совместно использую опцию!

1
ответ дан 23 November 2019 в 01:44

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

Среди прочего, Вы могли расположить окна на правые и левые половины экрана с Ctrl + Супер + Левый / кнопки Right и переключиться между ними с Высоким звуком + ~ (тильда, та рядом с ключом номер один).

1
ответ дан 23 November 2019 в 01:44

Я взял raise_apps.py сценарий @JacobVlijm и сделал некоторые улучшения к нему, включая создание его более устойчивыми.

А именно, я нашел, что после дня или два, сценарий @JacobVlijm прекратит работать, и я должен был бы вручную перезапустить сценарий, для получения его работающий снова. Ретроспективно, мое лучшее предположение - то, что многочисленные вызовы к xrandr в конечном счете вызывают проблемы.

Так или иначе я адаптировал его код, увеличил частоту запросов с 5 секунд до каждой 1 секунды, поскольку это не использует много ЦП так или иначе и сделало это более устойчивым. У меня может обычно быть он работающий в течение дней/недели без проблем.

Один протест состоит в том, что я только называю xrandr однажды во время запуска, для получения размеров разрешения экрана. Таким образом, при изменении разрешения экрана (например, от 1920x1080 до некоторого другого разрешения), Вы, вероятно, захотите вручную перезапустить повышение-apps.py так, чтобы оно взяло новое разрешение. Лично, я никогда не изменяю свое разрешение экрана, таким образом, это - надуманный вопрос для меня. Кроме того, у меня есть веская причина полагать, что слишком много вызовов к xrandr были тем, что заставляло версию @JacobVlijm сценария прекращать работать после дня или два, таким образом, я настоятельно рекомендую не просто поместить многочисленные вызовы в xrandr, въезжают задним ходом..

BTW, необходимо поместить изображение raise.png в/usr/local/icons/каталог. Или если Вы хотите поместить raise.png в другой каталог, вносят соответствующее изменение в сценарий, так, чтобы сценарий мог найти файл изображения.

Хотелось бы надеяться, Ubuntu интегрирует этот тип 'повышения все окна' функциональность в их систему раньше, чем позже, поскольку это очень полезно:

#!/usr/bin/python2
#
# Note to self:
# You need to add raise.png to /usr/local/icons/ directory.
#
# This script was taken from: https://askubuntu.com/questions/446521/how-to-show-raise-all-windows-of-an-application, 
# (@JacobVlijm's answer), and then improved to fix some
# issues, that were causing it to stop working after a day or two.
#
#
from __future__ import print_function

from sys import stderr, exit
import signal
import gi

gi.require_version('Gtk', '3.0')
gi.require_version('AppIndicator3', '0.1')
from gi.repository import Gtk, AppIndicator3, GObject, GLib

import logging
import logging.handlers

import time
import os
import subprocess
import getpass

logger = logging.getLogger('MyLogger')
logger.setLevel(logging.DEBUG)

log_handler = logging.handlers.SysLogHandler(address='/dev/log')

logger.addHandler(log_handler)


currpath = os.path.dirname(os.path.realpath(__file__))

class Indicator():
    def __init__(self):
        self.app = 'raise-apps'
        iconpath = '/usr/local/icons/raise.png'
        self.indicator = AppIndicator3.Indicator.new(
            self.app, iconpath,
            AppIndicator3.IndicatorCategory.OTHER)
        self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE)

        self.prev_menu_item_names = []
        self.menu_items = []

        res_output = get("xrandr").split()
        if (len(res_output) == 0):
            logger.error("raise-apps.py: invocation of xrandr failed! Unable to continue..")
            exit(-1)

        idf = res_output.index("current")
        res = (int(res_output[idf+1]), int(res_output[idf+3].replace(",", "")))
        (self.screen_width, self.screen_height) = res
        logger.info("raise-apps.py: screen resolution is %s x %s" % (self.screen_width, self.screen_height))

        self.indicator.set_menu(self.create_menu())

        GLib.timeout_add_seconds(1.0, self.check_recent)

    def create_menu(self):
        # creates the (initial) menu
        self.menu = Gtk.Menu()
        # separator
        initial = Gtk.MenuItem("Fetching list...")
        menu_sep = Gtk.SeparatorMenuItem()
        self.menu.append(initial)
        self.menu.append(menu_sep)

        self.menu.show_all()
        return self.menu

    def raise_wins(self, *args):
        index = self.menu.get_children().index(self.menu.get_active())
        selection = self.menu_items[index][1]
        for w in selection:
            execute(["wmctrl", "-ia", w])

    def set_new(self):
        # update the list, appearing in the menu
        for i in self.menu.get_children():
            self.menu.remove(i)
        for app in self.menu_items:

            sub = Gtk.MenuItem(app[0])
            self.menu.append(sub)
            sub.connect('activate', self.raise_wins)
        # separator
        menu_sep = Gtk.SeparatorMenuItem()
        self.menu.append(menu_sep)

        # quit
        item_quit = Gtk.MenuItem('Quit')
        item_quit.connect('activate', self.stop)
        self.menu.append(item_quit)
        self.menu.show_all()

    def get_apps(self):
        # creating window list on current viewport / id's / application names
        w_data = [l.split() for l in get(["wmctrl", "-lpG"]).splitlines()]
        # windows on current viewport
        relevant = [w for w in w_data if 0 < int(w[3]) < self.screen_width and 0 < int(w[4]) < self.screen_height]
        # pids
        pids = [l.split() for l in get(["ps", "-u", getpass.getuser()]).splitlines()]
        matches = [[p[-1], [w[0] for w in relevant if w[2] == p[0]]] for p in pids]
        return [m for m in matches if m[1]]

    def check_recent(self):
        # print("in check_recent()", file=stderr)
        self.menu_items = self.get_apps()
        for app in self.menu_items:
            app[0] = "gnome-terminal" if "gnome-terminal" in app[0] else app[0]
        # check if menu items have changed:
        has_changed = len(self.menu_items) != len(self.prev_menu_item_names)
        if (not has_changed):
            for i in range(len(self.menu_items)):
                if self.prev_menu_item_names[i] != self.menu_items[i][0]:
                    has_changed = True
                    break

        if has_changed:
            GObject.idle_add(
                self.set_new,
                priority=GObject.PRIORITY_DEFAULT)

            self.prev_menu_item_names = []
            for item in self.menu_items:
                self.prev_menu_item_names.append(item[0])

        GLib.timeout_add_seconds(1.0, self.check_recent)


    def stop(self, source):
        Gtk.main_quit()


    def recreate_menu(self, *args):
        logger.info("in recreate_menu()")
        self.prev_menu_item_names = []
        self.menu_items = []

        self.menu_items = self.get_apps()
        for app in self.menu_items:
            app[0] = "gnome-terminal" if "gnome-terminal" in app[0] else app[0]

        GObject.idle_add(
            self.set_new,
            priority=GObject.PRIORITY_DEFAULT)

        self.prev_menu_item_names = []
        for item in self.menu_items:
            self.prev_menu_item_names.append(item[0])


def get(command):
    # enable to get a feel for what this app is doing..
    # print("get", command, file=stderr)
    try:
        return subprocess.check_output(command).decode("utf-8")

    except subprocess.CalledProcessError as e:
        logger.error("raise-apps.py error: cmd=%s, error=%s" % (command, e))
        return ""

    except OSError as e:
        logger.error("raise-apps.py error: cmd=%s, error=%s" % (command, e))
        return ""

def execute(command):
    # enable to get a feel for what this app is doing..
    # print("exec", command, file=stderr)
    try:
        subprocess.call(command)

    except subprocess.CalledProcessError as e:
        logger.error("raise-apps.py error: cmd=%s, error=%s" % (command, e))
        return ""
    except OSError as e:
        logger.error("raise-apps.py error: cmd=%s, error=%s" % (command, e))
    return ""


logger.info("(raise-apps.py is starting up..)")
Indicator()
signal.signal(signal.SIGINT, signal.SIG_DFL)
Gtk.main()
1
ответ дан 23 November 2019 в 01:44

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

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