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

21

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

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

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

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

Есть ли лучшее решение?

реч
источник
@Joschua Вывести все окна приложения на передний план не так уж сложно, но как бы вы хотели определить приложение? будет комбинация клавиш + нажатие окна приложения?
Джейкоб Влейм
@ Джошуа или, может быть, более элегантный, ключевая комбинация + 1-й символ имени приложения?
Джейкоб Влейм
Я думаю, что поведение одинаково со всеми приложениями. Я чаще всего скучаю по этой функции в окнах терминалов, где у меня часто два или более окон открыты рядом. Затем я переключаюсь в полноэкранное окно (например, Firefox), и когда я хочу переключиться обратно на два окна терминала, это довольно сложно. Наилучший способ, который я нашел на данный момент, - это щелчок средней кнопкой мыши на панели приложений Firefox, который переносит Firefox на задний план, чтобы у меня снова были два терминала на передней панели. Однако это работает только хорошо, когда не слишком много приложений, сложенных сверху: D
peq
также @Joschua Можно было бы использовать комбинацию клавиш для вывода на передний план оконных групп приложений ; нажмите один раз -> все окна Firefox появятся, нажмите еще раз -> все окна терминала появятся и т. д. можно сделать действительно гладкими. интересный. работаю над этим. займет немного работы, хотя.
Джейкоб Влейм
@JacobVlijm Звучит как правильное направление .. :) Что мне кажется наиболее важным, так это то, что комбинация клавиш плюс нажатие на иконку выводит все окна этого приложения (например, многие терминалы, как упоминалось выше) на передний план, предпочтительно с разворотом. так, чтобы они не перекрывали друг друга .. (Может быть, что-то подобное может стать частью Unity ?!)
Иошуа

Ответы:

21

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

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

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

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

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

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

из 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 в том же каталоге, что и индикатор.

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

  • Затем просто запустите его командой:

    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: выберите приложение, введя один или несколько символов

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

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

поднять все gnome-terminalокна в текущем окне просмотра:

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

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

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

  • Выполните настройку, как описано в разделе «Как использовать»
  • Протестируйте его командой:

    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. У меня есть несколько открытых окон:

  • Fire Fox
  • гном-терминал
  • кораблик

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

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

Жму один раз Alt+ 1, все nautilusокна подняты:

<Изображение>

Жму снова Alt+ 1, все firefoxокна подняты:

<Изображение>

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

<Изображение>

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

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

    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окнами под другими окнами.

<Изображение>

Чтобы поднять все окна nautilus (пример ярлыка: Alt+ 1):

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

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

    <Изображение>

    или:

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

    <Изображение>

    результат:

    <Изображение>


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

  • Выполните настройку, как описано в разделе «Как использовать»
  • Протестируйте его командой:

    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вызывает zenityокно, в котором перечислены все приложения и количество их окон в текущем окне просмотра:

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

Простое нажатие стрелок или приведет вас к правильному варианту. Нажмите 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: поднять окна запущенных приложений с помощью значка запуска

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

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

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

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

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

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

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

Ниже вы найдете:

два скрипта / иконка / .desktopфайл

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

    <Значок>

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

        Icon=/path/to/raise.png
    

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

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

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

    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-й столбец: геометрия окна xy (которую мы используем, чтобы увидеть, находится ли окно в текущем окне просмотра, icw xrandr)

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

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

Якоб Влейм
источник
Я согласен и еще раз спасибо за все ваши усилия! :) || Есть странная вещь, которую я раньше не замечал. Иногда после использования Option 2сценария, когда окно приложения сфокусировано (оно не развернуто), и я щелкаю другое окно, которое видно «внизу», приложение ниже не получает фокус.
Иошуа
@Joschua ОП этого вопроса: askubuntu.com/questions/575830/… сообщил мне об ошибке, которая была обнаружена при последнем обновлении «функции». Истина / Ложь были перепутаны, вызывая сбой скрипта, когда ни у одного приложения не было больше одного окна. Если вы используете вариант 2, пожалуйста, обновите его до последней версии.
Джейкоб Влейм
Вариант 1 не работает для меня на Ubuntu Xenial. что-то @ что-то: ~ / bin $ ./raise_app Gtk-Message: GtkDialog отображается без переходного родителя. Это не рекомендуется. Я пытался открыть окна терминала. Ничего не произошло.
Отрывок
@Nirri какое имя приложения ты использовал? Сообщение вполне нормально, если окно zenity работает без родителя Gtk. «Обескураженный» не является ошибкой.
Джейкоб Влейм
Первые символы терминала. Это работает - вроде - это поднимает окно любого приложения - но только одно из них, а не все, как ожидалось @ user72216
xtrinch
1

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

Помимо прочего, вы можете расположить окна в правой и левой частях экрана с помощью кнопок Ctrl+ Super+ Left/ Rightи переключаться между ними с помощью Alt + ~ (тильда, та, которая находится рядом с клавишей номер один).

Сергей Колодяжный
источник
Это не приносит все окна приложения к вершине, хотя. Вы можете видеть их, но вы не можете использовать их, не нажимая много.
Иошуа
1

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

Это может или не может быть то, что вы ищете, но это работает для меня и намного проще, поэтому я решил, что поделюсь этим вариантом!

Шон Коломбо
источник
1
Вы также можете нажать клавишу со стрелкой вниз, чтобы окна приложений отображались сразу.
Крис
1

Я взял скрипт @ JacobVlijm Raise_apps.py и внес в него некоторые улучшения, в том числе сделав его более надежным.

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

В любом случае, я адаптировал его код, увеличил частоту опроса с 5 секунд до 1 секунды, так как он все равно не потребляет много ресурсов процессора, и сделал его более устойчивым. Обычно я могу запустить его в течение нескольких дней / недель без проблем.

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

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

Надеемся, что Ubuntu интегрирует этот тип функциональности «поднять все окна» в свою систему раньше, чем позже, поскольку это очень полезно:

#!/usr/bin/python2
#
# Note to self:
# You need to add raise.png to /usr/local/icons/ directory.
#
# This script was taken from: /ubuntu/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()
Джино
источник