EDIT - нова відповідь-
Відповіді, які наведено нижче, є і надалі є абсолютно достовірними, тому пропоновані варіанти. Постійне розуміння, однак, змусило мене додати цей варіант, щоб використовувати індикатор нижче, який, мабуть, є найелегантнішим рішенням.
Як такий, він, ймовірно, повинен замінити варіант 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
вікно
- Введіть один або кілька символів імені програми у поле введення
- Натисніть Enter
Це призведе до того, що всі вікна відповідної програми (у поточному вікні перегляду) будуть передні.
підняти всі 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. У мене відкрито кілька вікон:
- firefox
- гном-термінал
- nautilus
Поточний стан:
Я натискаю один раз Alt+ 1, всі nautilus
вікна піднімаються:
Я знову натискаю Alt+ 1, усі firefox
вікна піднімаються:
Я знову натискаю Alt+ 1, всі gnome-terminal
вікна знову піднімаються, цикл починається з початку:
Як користуватись
Потім оберіть свої програми за допомогою згрупованих вікон додатків із комбінацією клавіш.
Сценарій:
#!/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 windows (приклад ярлика: Alt+ 1):
Як користуватись:
- Виконайте налаштування, як описано в "Як користуватися"
Перевірте його за допомогою команди:
raise_app
Якщо все працює добре, додайте його до комбінації клавіш швидкого вибору за вибором: Виберіть: Налаштування системи> "Клавіатура"> "Ярлики"> "Спеціальні ярлики". Клацніть "+" і додайте команду
Потім:
Сценарій
#!/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
файл
- Підготуйте налаштування як у "Як користуватися", збережіть перший (основний) скрипт як
raise_app
у~/bin
Збережіть піктограму нижче (клацніть правою кнопкою миші, збережіть як) як raise.png
Скопіюйте .desktop
файл у порожній файл, відредагуйте рядок
Icon=/path/to/raise.png
до реального шляху до піктограми (шляхи з пробілами між цитатами)
Збережіть її як raise.desktop
в~/.local/share/applications
Перетягніть .desktop
файл до панелі запуску, щоб додати його
- скопіюйте другий скрипт, вставте його в порожній файл, збережіть як
update_apps
у ~/bin
, зробіть його виконуваним.
Додайте таку команду до своїх програм запуску (тире> програми запуску> Додати):
update_apps
- Вийдіть і поверніться, щоб він працював.
Перший сценарій
#!/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 розбиває і шукає "новий" передній додаток, а згодом піднімає всі інші вікна цього додатка.