How to show (raise) all windows of an application?Bring all windows of the same application to front on focus in UnityWindow switcher (alt+tab) raises all windowsScript to Alt+Tab till application is foundHow can I bring all windows of an application to the front?Is there a way to add a window list on the panel in Unity?How to make Alt+Tab return to same application window as last used (Unity)Is there any way to open all instances of a particular application without having to click on its icon multiple times?Link minimize/maximize/on top between parent/child app windowsShow all open windows in 11.04?How can I bring all windows of an application to the front?How can I show all non-minimized windows?How can I open multiple windows in one application, and show them at the same time?Move semi- maximized windows across multiple (2 or more) monitorsHow can I use Devilspie2 to bring a window to the foreground when opened?How can I make wmctrl raise the most recently fosused window of an application?Moving Ubuntu WindowsBring all windows of the same application to front on focus in UnityIs there any way to crop windows (not images) in Ubuntu?
Can I Retrieve Email Addresses from BCC?
Freedom of speech and where it applies
Pronouncing Homer as in modern Greek
Resetting two CD4017 counters simultaneously, only one resets
What (else) happened July 1st 1858 in London?
Identify a stage play about a VR experience in which participants are encouraged to simulate performing horrific activities
For airliners, what prevents wing strikes on landing in bad weather?
How can I raise concerns with a new DM about XP splitting?
A known event to a history junkie
How to prevent YouTube from showing already watched videos?
Should my PhD thesis be submitted under my legal name?
How to check participants in at events?
Lifted its hind leg on or lifted its hind leg towards?
Is there an Impartial Brexit Deal comparison site?
Organic chemistry Iodoform Reaction
Meta programming: Declare a new struct on the fly
Can I rely on these GitHub repository files?
Stereotypical names
How to deal with or prevent idle in the test team?
A workplace installs custom certificates on personal devices, can this be used to decrypt HTTPS traffic?
What is the opposite of 'gravitas'?
What does the "3am" section means in manpages?
Hostile work environment after whistle-blowing on coworker and our boss. What do I do?
Is there a problem with hiding "forgot password" until it's needed?
How to show (raise) all windows of an application?
Bring all windows of the same application to front on focus in UnityWindow switcher (alt+tab) raises all windowsScript to Alt+Tab till application is foundHow can I bring all windows of an application to the front?Is there a way to add a window list on the panel in Unity?How to make Alt+Tab return to same application window as last used (Unity)Is there any way to open all instances of a particular application without having to click on its icon multiple times?Link minimize/maximize/on top between parent/child app windowsShow all open windows in 11.04?How can I bring all windows of an application to the front?How can I show all non-minimized windows?How can I open multiple windows in one application, and show them at the same time?Move semi- maximized windows across multiple (2 or more) monitorsHow can I use Devilspie2 to bring a window to the foreground when opened?How can I make wmctrl raise the most recently fosused window of an application?Moving Ubuntu WindowsBring all windows of the same application to front on focus in UnityIs there any way to crop windows (not images) in Ubuntu?
I have an application using multiple windows. How can I quickly bring all the windows of that application to the foreground?
When I scroll through the applications with the scroll-wheel it only shows one window. When going to the next window, the last window is brought to the background again.
When I click on the application icon, I get a full-screen overview of all the windows. I have to select each window manually and move my mouse across half the screen several times.
My best solution so far is minimizing all windows (Ctrl+Super+D) and then show the windows of my application using the scroll-wheel.
Is there a better solution?
unity window-manager
add a comment |
I have an application using multiple windows. How can I quickly bring all the windows of that application to the foreground?
When I scroll through the applications with the scroll-wheel it only shows one window. When going to the next window, the last window is brought to the background again.
When I click on the application icon, I get a full-screen overview of all the windows. I have to select each window manually and move my mouse across half the screen several times.
My best solution so far is minimizing all windows (Ctrl+Super+D) and then show the windows of my application using the scroll-wheel.
Is there a better solution?
unity window-manager
@Joschua Bringing all windows of an application to the front is not too difficult, but how would you like to define the application? would a key combination+clicking an application's window do?
– Jacob Vlijm
Jan 5 '15 at 20:24
@Joschua or mayby more elegant, a key combo + 1st character of application name?
– Jacob Vlijm
Jan 5 '15 at 20:51
I think the behavior ist the same with all applications. I most often miss this feature with terminal windows, where I often have two or more windows open side by side. Then I switch to a full screen window (e.g. Firefox) and when I want to switch back to the two terminal windows it is kinda difficult. The best way I found so far is a mouse-middle-click on the Firefox application bar which brings Firefox to the background so that I have the two terminals at the front again. However this only works well, when There are not too many applications piled on top :D
– peq
Jan 5 '15 at 22:08
also @Joschua It would be possible to have a key combination to bring to front application window groups; press once -> all firefox windows show up, pres again -> all terminal windows show up etc. could be made really smooth. interesting. working on it. will take a little work though.
– Jacob Vlijm
Jan 5 '15 at 22:22
@JacobVlijm Sounds like the right direction.. :) What seems most important to me, is that a key combination plus clicking on the icon brings all windows of that application (for example, many terminals as peq mentioned) to the front, preferably spread out, so that they are non-overlapping.. (Maybe, something like this could become part of Unity?!)
– Joschua
Jan 6 '15 at 0:06
add a comment |
I have an application using multiple windows. How can I quickly bring all the windows of that application to the foreground?
When I scroll through the applications with the scroll-wheel it only shows one window. When going to the next window, the last window is brought to the background again.
When I click on the application icon, I get a full-screen overview of all the windows. I have to select each window manually and move my mouse across half the screen several times.
My best solution so far is minimizing all windows (Ctrl+Super+D) and then show the windows of my application using the scroll-wheel.
Is there a better solution?
unity window-manager
I have an application using multiple windows. How can I quickly bring all the windows of that application to the foreground?
When I scroll through the applications with the scroll-wheel it only shows one window. When going to the next window, the last window is brought to the background again.
When I click on the application icon, I get a full-screen overview of all the windows. I have to select each window manually and move my mouse across half the screen several times.
My best solution so far is minimizing all windows (Ctrl+Super+D) and then show the windows of my application using the scroll-wheel.
Is there a better solution?
unity window-manager
unity window-manager
edited Nov 16 '16 at 14:56
Jacob Vlijm
65.5k9130226
65.5k9130226
asked Apr 11 '14 at 15:43
peqpeq
665610
665610
@Joschua Bringing all windows of an application to the front is not too difficult, but how would you like to define the application? would a key combination+clicking an application's window do?
– Jacob Vlijm
Jan 5 '15 at 20:24
@Joschua or mayby more elegant, a key combo + 1st character of application name?
– Jacob Vlijm
Jan 5 '15 at 20:51
I think the behavior ist the same with all applications. I most often miss this feature with terminal windows, where I often have two or more windows open side by side. Then I switch to a full screen window (e.g. Firefox) and when I want to switch back to the two terminal windows it is kinda difficult. The best way I found so far is a mouse-middle-click on the Firefox application bar which brings Firefox to the background so that I have the two terminals at the front again. However this only works well, when There are not too many applications piled on top :D
– peq
Jan 5 '15 at 22:08
also @Joschua It would be possible to have a key combination to bring to front application window groups; press once -> all firefox windows show up, pres again -> all terminal windows show up etc. could be made really smooth. interesting. working on it. will take a little work though.
– Jacob Vlijm
Jan 5 '15 at 22:22
@JacobVlijm Sounds like the right direction.. :) What seems most important to me, is that a key combination plus clicking on the icon brings all windows of that application (for example, many terminals as peq mentioned) to the front, preferably spread out, so that they are non-overlapping.. (Maybe, something like this could become part of Unity?!)
– Joschua
Jan 6 '15 at 0:06
add a comment |
@Joschua Bringing all windows of an application to the front is not too difficult, but how would you like to define the application? would a key combination+clicking an application's window do?
– Jacob Vlijm
Jan 5 '15 at 20:24
@Joschua or mayby more elegant, a key combo + 1st character of application name?
– Jacob Vlijm
Jan 5 '15 at 20:51
I think the behavior ist the same with all applications. I most often miss this feature with terminal windows, where I often have two or more windows open side by side. Then I switch to a full screen window (e.g. Firefox) and when I want to switch back to the two terminal windows it is kinda difficult. The best way I found so far is a mouse-middle-click on the Firefox application bar which brings Firefox to the background so that I have the two terminals at the front again. However this only works well, when There are not too many applications piled on top :D
– peq
Jan 5 '15 at 22:08
also @Joschua It would be possible to have a key combination to bring to front application window groups; press once -> all firefox windows show up, pres again -> all terminal windows show up etc. could be made really smooth. interesting. working on it. will take a little work though.
– Jacob Vlijm
Jan 5 '15 at 22:22
@JacobVlijm Sounds like the right direction.. :) What seems most important to me, is that a key combination plus clicking on the icon brings all windows of that application (for example, many terminals as peq mentioned) to the front, preferably spread out, so that they are non-overlapping.. (Maybe, something like this could become part of Unity?!)
– Joschua
Jan 6 '15 at 0:06
@Joschua Bringing all windows of an application to the front is not too difficult, but how would you like to define the application? would a key combination+clicking an application's window do?
– Jacob Vlijm
Jan 5 '15 at 20:24
@Joschua Bringing all windows of an application to the front is not too difficult, but how would you like to define the application? would a key combination+clicking an application's window do?
– Jacob Vlijm
Jan 5 '15 at 20:24
@Joschua or mayby more elegant, a key combo + 1st character of application name?
– Jacob Vlijm
Jan 5 '15 at 20:51
@Joschua or mayby more elegant, a key combo + 1st character of application name?
– Jacob Vlijm
Jan 5 '15 at 20:51
I think the behavior ist the same with all applications. I most often miss this feature with terminal windows, where I often have two or more windows open side by side. Then I switch to a full screen window (e.g. Firefox) and when I want to switch back to the two terminal windows it is kinda difficult. The best way I found so far is a mouse-middle-click on the Firefox application bar which brings Firefox to the background so that I have the two terminals at the front again. However this only works well, when There are not too many applications piled on top :D
– peq
Jan 5 '15 at 22:08
I think the behavior ist the same with all applications. I most often miss this feature with terminal windows, where I often have two or more windows open side by side. Then I switch to a full screen window (e.g. Firefox) and when I want to switch back to the two terminal windows it is kinda difficult. The best way I found so far is a mouse-middle-click on the Firefox application bar which brings Firefox to the background so that I have the two terminals at the front again. However this only works well, when There are not too many applications piled on top :D
– peq
Jan 5 '15 at 22:08
also @Joschua It would be possible to have a key combination to bring to front application window groups; press once -> all firefox windows show up, pres again -> all terminal windows show up etc. could be made really smooth. interesting. working on it. will take a little work though.
– Jacob Vlijm
Jan 5 '15 at 22:22
also @Joschua It would be possible to have a key combination to bring to front application window groups; press once -> all firefox windows show up, pres again -> all terminal windows show up etc. could be made really smooth. interesting. working on it. will take a little work though.
– Jacob Vlijm
Jan 5 '15 at 22:22
@JacobVlijm Sounds like the right direction.. :) What seems most important to me, is that a key combination plus clicking on the icon brings all windows of that application (for example, many terminals as peq mentioned) to the front, preferably spread out, so that they are non-overlapping.. (Maybe, something like this could become part of Unity?!)
– Joschua
Jan 6 '15 at 0:06
@JacobVlijm Sounds like the right direction.. :) What seems most important to me, is that a key combination plus clicking on the icon brings all windows of that application (for example, many terminals as peq mentioned) to the front, preferably spread out, so that they are non-overlapping.. (Maybe, something like this could become part of Unity?!)
– Joschua
Jan 6 '15 at 0:06
add a comment |
4 Answers
4
active
oldest
votes
EDIT -new answer-
The answer(s) below is/are still totally valid, and so the suggested options. Ongoing insight however made me add this option to use the indicator below, which is probably the most elegant solution.
As such, it should probably replace option 5 (using a .desktop file).
Simply choose the application from the list, and all windows of the corresponding application (present on the current viewport) will raise:
How to use
from ppa:
sudo add-apt-repository ppa:vlijm/upfront
sudo apt-get update
sudo apt-get install upfront
...or manually:
#!/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()
The indicator needs
wmctrl
sudo apt-get wmctrl
Copy the indicator into an empty file, save it as
raise_apps.py
Copy the image below, save it exactly named
raise.png
in one and the same directory as the indicator.Then simply run it by the command:
python3 /path/to/raise_apps.py
Add if you want to Startup Applications:
/bin/bash -c "sleep 10 && python3 /path/to/raise_apps.py"
OLD ANSWER:
About the question
With the right tools, it is not very complicated to "just" raise all windows of an application. It is a bit more complicated to make sure only the windows of the current viewport are raised. The real challenge however is to find a convenient way to make the action available to the user.
Below five options to take care of that, to show how it can be done. All options are ready to be used. The last option however is kind of experimental; it works fine but has a few minor cosmetic downsides, as explained in the description of the option. I added it nevertheless as a concept.
Spreading the windows automatically in a non- overlapping way, as suggested in a comment, seems not a practical idea to me; if you work in an (application-wise) grouped window setup, the script would possibly unwantedly rearrange windows.
How to use
For all options you need to:
install
wmctrl
if it is not yet on your system:sudo apt-get install wmctrl
create, if it does not exist yet, the directory:
~/bin
(explanation: the directory
~/bin
is in $PATH, so you can run executables by their name)Copy the script, corresponding to the option, paste it into an empty file, save it as
raise_app
(no extension) in~/bin
and make it executable
In the separate options, possible additional steps will be explained.
Option 1: choose the application by entering one or more characters
- Press a key combination, a
zenity
window will appear - Enter one or more characters of the application's name in the entry box
- Press enter
This will make all windows of the matching application (on the current viewport) come to front.
raise all gnome-terminal
windows on the current viewport:
How to use:
- Do the set up as described in "How to use"
Test-run it by the command:
raise_app
If all works fine, add it to a shortcut key combination of your choice: Choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command
The script:
#!/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
Option 2: cycle through applications and raise their windows with a key combination:
Let's say I have the script below under a key combination Alt+1. I have several windows open of:
- firefox
- gnome-terminal
- nautilus
The current state:
I press once Alt+1, all nautilus
windows are raised:
I press again Alt+1, all firefox
windows are raised:
I press again Alt+1, all gnome-terminal
windows are raised again, the cycle starts over:
How to use
- Do the set up as described in "How to use"
Add it to a shortcut key combination of your choice: Choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command
raise_app
Then cycle through your applications with grouped application windows with your key combination.
The script:
#!/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
Option 3: press key combination + click on launcher icon -or- application window to raise all windows on the current viewport
This is probably the option that is closest to what is described in the question / comment.
Let's say I have a messy desktop with three nautilus
windows buried under other windows.
To raise all nautilus windows (example shortcut: Alt+1):
- Press Alt+1, release (!)
Within 3 seconds, either:
click on the application's icon in the launcher
or:
click on one of the application's windows
result:
How to use:
- Do the set up as described in "How to use"
Test-run it by the command:
raise_app
If all works fine, add it to a shortcut key combination of your choice: Choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command
Then:
Press your key combination and within 3 seconds, either:
- click on the application's icon in the launcher
- click on one of the application's windows
The script
#!/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
Option 4: a key combination calls an option list, showing the number of windows per application on the current viewport
This one turned out to be more convenient then I assumed:
Pressing the (again example-) key combination Alt+1 calls a zenity
window, listing all applications and the number of their windows on the current viewport:
Simply pressing the ▴ or ▾ arrows will bring you to the right option. Press Enter and all windows of the chosen application are raised.
How to use:
- Do the set up as described in "How to use"
Test-run it by the command:
raise_app
If all works fine, add it to a shortcut key combination of your choice: Choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command
The script
#!/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"')
Option 5: raise windows of running applications from a launcher icon
This option exists of a launcher icon, with the currently running applications in a quicklist. Choose one, and all windows of the applications will be raised.
The launcher is automatically updated when the list of running applications (on the current viewport) changes. The quicklist shows a different list on other viewports, where windows of other applications are opened (will take 1-2 seconds to adapt).
As mentioned, although fully functional, this option is a meant as a concept. It has a few minor cosmetic downsides as it is. The most important:
- The cursor "wheel" keeps spinning for a few seconds after an action. Although it does not effect the functionality, it is a cosmetic downside.
- It takes 1-2 seconds for the applicationlist in the launcher icon to be updated after the list of running applications changes.
Furthermore the setup is slightly more complicated (although explained in detail below):
How to use
Below you will find:
two scripts / an icon / a .desktop
file
- Prepare the setup as in "How to use", save the first (main-) script as
raise_app
in~/bin
Save the icon below (right-click, save as) as
raise.png
Copy the
.desktop
file into an empty file, edit the lineIcon=/path/to/raise.png
to the real path to the icon (paths with spaces between quotes)
Save it asraise.desktop
in~/.local/share/applications
Drag the
.desktop
file to the launcher to add it- copy the second script, paste it into an empty file, save it as
update_apps
in~/bin
, make it executable. Add the following command to your startup applications (Dash > Startup Applications > Add):
update_apps
- Log out and back in to make it work.
The first script
#!/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
The second script
#!/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;nn",
]for it in apps2]
update_dtfile(apps2, text)
The .desktop file
[Desktop Entry]
Name=Raise application windows
Comment=Raise groups of windows
Icon=/path/to/raise.png
Terminal=false
Type=Application
Version=1.0
Actions=
Brief Explanation
All solutions above use wmctrl
to create a window list, using the wmctrl -lpG
command. This command produces lines, looking like:
0x044000b3 0 3429 65 24 1615 1026 jacob-System-Product-Name unity - How to show all windows of an application? - Ask Ubuntu - Mozilla Firefox
These lines include:
- 1st column: the window's id (that we can use to raise it)
- 3rd column: the pid that owns the window.
- 4th / 5th column: the window's geometry x-y (that we use to see if the window is on the current viewport, i.c.w
xrandr
)
The pid is looked up in the output of ps -u <username>
to get a "user-readable" identification (name) of the application.
Thus we can allocate windows to applications. Subsequently we can raise the windows of a given application in a for
loop with the command wmctrl -ia
.
In option 3
the script starts a 3- second "waiting" loop, using the xprop -root
command repeatedly to see if there is any change in what is the frontmost window; this will happen if the user either clicks on a launcher icon to raise an application's window, or clicks on a window directly. If so, the while- loop breaks and looks up the "new" frontmost application, and subsequently raises all other windows of that application.
I agree, and thanks again for all your effort! :) || There's a weird thing that I didn't notice before. Sometimes after using theOption 2
script, when an application window is focused (that is not maximized) and I click on another window that is visible "below", the application below below doesn't get the focus.
– Joschua
Jan 8 '15 at 22:47
@Joschua the OP of this question: askubuntu.com/questions/575830/… attended me of a bug that was introduced at the latest "feature" update. True/False were mixed up, causing the script to crash when no applications have more then one window. If you use option2, please update to the latest version.
– Jacob Vlijm
Jan 21 '15 at 19:22
Option 1 not working for me on ubuntu xenial. something@something:~/bin$ ./raise_app Gtk-Message: GtkDialog mapped without a transient parent. This is discouraged. I was trying to open terminal windows. Nothing happened.
– xtrinch
Sep 17 '16 at 12:33
@Nirri what application name did you use? The message is quite normal if a zenity window runs without a Gtk parent. "Discouraged" is not an error.
– Jacob Vlijm
Sep 17 '16 at 12:39
First chars of terminal. It works - kind of - it raises a window of any app - but only one of them, not all of them as expected @user72216
– xtrinch
Sep 17 '16 at 12:42
|
show 9 more comments
There is Super+W shortcut which will show expo of all the currently open windows, though that will include other applications. This comes by default, and doesn't require any changes, so perhaps it's a simplest option available.
Among other things, you could position windows on right and left halves of the screen with Ctrl+Super+Left/Right buttons, and switch between them with Alt+~ (tilde, the one next to number one key).
That doesn't bring all the windows of an application to the top though. You can see them, but you can't use them without having to click a lot.
– Joschua
Jan 8 '15 at 11:49
add a comment |
If you press Alt+Tab to cycle through applications, and you get to one with multiple windows, just keep holding the alt key down and after about 1 full second the icon will be replaced with a view of all of the windows for that application.
That may or may not be what you're looking for, but it works for me and is a ton simpler, so I figured I'd share the option!
1
You can also press the down arrow key to have the application windows show up straight away.
– Kris
Aug 2 '16 at 16:12
add a comment |
I took @JacobVlijm's raise_apps.py script and made some enhancements to it, including making it more robust.
Specifically, I had found that after a day or two, @JacobVlijm's script would stop working, and I'd have to manually the script, to get it working again. In retrospect, my best guess is that the numerous calls to xrandr eventually cause issues.
Anyways, I adapted his code, increased the polling frequency from 5 seconds to every 1 second, as it doesn't use much CPU anyways, and made it more robust. I can typically have it running for days/weeks without issues.
One caveat is that I only call xrandr once during startup, to get screen resolution dimensions. So if you change your screen resolution (e.g. from 1920x1080 to some other resolution), you'll probably want to manually restart raise-apps.py so that it will pick up the new resolution. Personally, I never change my screen resolution, so this is a non-issue for me. Additionally, I have strong reason to believe that too many calls to xrandr were what was causing @JacobVlijm's version of the script to stop working after a day or two, so I would strongly recommend not simply putting the numerous calls to xrandr back in..
BTW, you need to place the raise.png image in the /usr/local/icons/ directory. Or if you want to put raise.png in a different directory make the appropriate change to the script, so that the script can find the image file.
Hopefully, Ubuntu will integrate this type of 'raise all windows' functionality into their system sooner than later as it's very useful:
#!/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()
add a comment |
Your Answer
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "89"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2faskubuntu.com%2fquestions%2f446521%2fhow-to-show-raise-all-windows-of-an-application%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
EDIT -new answer-
The answer(s) below is/are still totally valid, and so the suggested options. Ongoing insight however made me add this option to use the indicator below, which is probably the most elegant solution.
As such, it should probably replace option 5 (using a .desktop file).
Simply choose the application from the list, and all windows of the corresponding application (present on the current viewport) will raise:
How to use
from ppa:
sudo add-apt-repository ppa:vlijm/upfront
sudo apt-get update
sudo apt-get install upfront
...or manually:
#!/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()
The indicator needs
wmctrl
sudo apt-get wmctrl
Copy the indicator into an empty file, save it as
raise_apps.py
Copy the image below, save it exactly named
raise.png
in one and the same directory as the indicator.Then simply run it by the command:
python3 /path/to/raise_apps.py
Add if you want to Startup Applications:
/bin/bash -c "sleep 10 && python3 /path/to/raise_apps.py"
OLD ANSWER:
About the question
With the right tools, it is not very complicated to "just" raise all windows of an application. It is a bit more complicated to make sure only the windows of the current viewport are raised. The real challenge however is to find a convenient way to make the action available to the user.
Below five options to take care of that, to show how it can be done. All options are ready to be used. The last option however is kind of experimental; it works fine but has a few minor cosmetic downsides, as explained in the description of the option. I added it nevertheless as a concept.
Spreading the windows automatically in a non- overlapping way, as suggested in a comment, seems not a practical idea to me; if you work in an (application-wise) grouped window setup, the script would possibly unwantedly rearrange windows.
How to use
For all options you need to:
install
wmctrl
if it is not yet on your system:sudo apt-get install wmctrl
create, if it does not exist yet, the directory:
~/bin
(explanation: the directory
~/bin
is in $PATH, so you can run executables by their name)Copy the script, corresponding to the option, paste it into an empty file, save it as
raise_app
(no extension) in~/bin
and make it executable
In the separate options, possible additional steps will be explained.
Option 1: choose the application by entering one or more characters
- Press a key combination, a
zenity
window will appear - Enter one or more characters of the application's name in the entry box
- Press enter
This will make all windows of the matching application (on the current viewport) come to front.
raise all gnome-terminal
windows on the current viewport:
How to use:
- Do the set up as described in "How to use"
Test-run it by the command:
raise_app
If all works fine, add it to a shortcut key combination of your choice: Choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command
The script:
#!/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
Option 2: cycle through applications and raise their windows with a key combination:
Let's say I have the script below under a key combination Alt+1. I have several windows open of:
- firefox
- gnome-terminal
- nautilus
The current state:
I press once Alt+1, all nautilus
windows are raised:
I press again Alt+1, all firefox
windows are raised:
I press again Alt+1, all gnome-terminal
windows are raised again, the cycle starts over:
How to use
- Do the set up as described in "How to use"
Add it to a shortcut key combination of your choice: Choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command
raise_app
Then cycle through your applications with grouped application windows with your key combination.
The script:
#!/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
Option 3: press key combination + click on launcher icon -or- application window to raise all windows on the current viewport
This is probably the option that is closest to what is described in the question / comment.
Let's say I have a messy desktop with three nautilus
windows buried under other windows.
To raise all nautilus windows (example shortcut: Alt+1):
- Press Alt+1, release (!)
Within 3 seconds, either:
click on the application's icon in the launcher
or:
click on one of the application's windows
result:
How to use:
- Do the set up as described in "How to use"
Test-run it by the command:
raise_app
If all works fine, add it to a shortcut key combination of your choice: Choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command
Then:
Press your key combination and within 3 seconds, either:
- click on the application's icon in the launcher
- click on one of the application's windows
The script
#!/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
Option 4: a key combination calls an option list, showing the number of windows per application on the current viewport
This one turned out to be more convenient then I assumed:
Pressing the (again example-) key combination Alt+1 calls a zenity
window, listing all applications and the number of their windows on the current viewport:
Simply pressing the ▴ or ▾ arrows will bring you to the right option. Press Enter and all windows of the chosen application are raised.
How to use:
- Do the set up as described in "How to use"
Test-run it by the command:
raise_app
If all works fine, add it to a shortcut key combination of your choice: Choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command
The script
#!/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"')
Option 5: raise windows of running applications from a launcher icon
This option exists of a launcher icon, with the currently running applications in a quicklist. Choose one, and all windows of the applications will be raised.
The launcher is automatically updated when the list of running applications (on the current viewport) changes. The quicklist shows a different list on other viewports, where windows of other applications are opened (will take 1-2 seconds to adapt).
As mentioned, although fully functional, this option is a meant as a concept. It has a few minor cosmetic downsides as it is. The most important:
- The cursor "wheel" keeps spinning for a few seconds after an action. Although it does not effect the functionality, it is a cosmetic downside.
- It takes 1-2 seconds for the applicationlist in the launcher icon to be updated after the list of running applications changes.
Furthermore the setup is slightly more complicated (although explained in detail below):
How to use
Below you will find:
two scripts / an icon / a .desktop
file
- Prepare the setup as in "How to use", save the first (main-) script as
raise_app
in~/bin
Save the icon below (right-click, save as) as
raise.png
Copy the
.desktop
file into an empty file, edit the lineIcon=/path/to/raise.png
to the real path to the icon (paths with spaces between quotes)
Save it asraise.desktop
in~/.local/share/applications
Drag the
.desktop
file to the launcher to add it- copy the second script, paste it into an empty file, save it as
update_apps
in~/bin
, make it executable. Add the following command to your startup applications (Dash > Startup Applications > Add):
update_apps
- Log out and back in to make it work.
The first script
#!/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
The second script
#!/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;nn",
]for it in apps2]
update_dtfile(apps2, text)
The .desktop file
[Desktop Entry]
Name=Raise application windows
Comment=Raise groups of windows
Icon=/path/to/raise.png
Terminal=false
Type=Application
Version=1.0
Actions=
Brief Explanation
All solutions above use wmctrl
to create a window list, using the wmctrl -lpG
command. This command produces lines, looking like:
0x044000b3 0 3429 65 24 1615 1026 jacob-System-Product-Name unity - How to show all windows of an application? - Ask Ubuntu - Mozilla Firefox
These lines include:
- 1st column: the window's id (that we can use to raise it)
- 3rd column: the pid that owns the window.
- 4th / 5th column: the window's geometry x-y (that we use to see if the window is on the current viewport, i.c.w
xrandr
)
The pid is looked up in the output of ps -u <username>
to get a "user-readable" identification (name) of the application.
Thus we can allocate windows to applications. Subsequently we can raise the windows of a given application in a for
loop with the command wmctrl -ia
.
In option 3
the script starts a 3- second "waiting" loop, using the xprop -root
command repeatedly to see if there is any change in what is the frontmost window; this will happen if the user either clicks on a launcher icon to raise an application's window, or clicks on a window directly. If so, the while- loop breaks and looks up the "new" frontmost application, and subsequently raises all other windows of that application.
I agree, and thanks again for all your effort! :) || There's a weird thing that I didn't notice before. Sometimes after using theOption 2
script, when an application window is focused (that is not maximized) and I click on another window that is visible "below", the application below below doesn't get the focus.
– Joschua
Jan 8 '15 at 22:47
@Joschua the OP of this question: askubuntu.com/questions/575830/… attended me of a bug that was introduced at the latest "feature" update. True/False were mixed up, causing the script to crash when no applications have more then one window. If you use option2, please update to the latest version.
– Jacob Vlijm
Jan 21 '15 at 19:22
Option 1 not working for me on ubuntu xenial. something@something:~/bin$ ./raise_app Gtk-Message: GtkDialog mapped without a transient parent. This is discouraged. I was trying to open terminal windows. Nothing happened.
– xtrinch
Sep 17 '16 at 12:33
@Nirri what application name did you use? The message is quite normal if a zenity window runs without a Gtk parent. "Discouraged" is not an error.
– Jacob Vlijm
Sep 17 '16 at 12:39
First chars of terminal. It works - kind of - it raises a window of any app - but only one of them, not all of them as expected @user72216
– xtrinch
Sep 17 '16 at 12:42
|
show 9 more comments
EDIT -new answer-
The answer(s) below is/are still totally valid, and so the suggested options. Ongoing insight however made me add this option to use the indicator below, which is probably the most elegant solution.
As such, it should probably replace option 5 (using a .desktop file).
Simply choose the application from the list, and all windows of the corresponding application (present on the current viewport) will raise:
How to use
from ppa:
sudo add-apt-repository ppa:vlijm/upfront
sudo apt-get update
sudo apt-get install upfront
...or manually:
#!/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()
The indicator needs
wmctrl
sudo apt-get wmctrl
Copy the indicator into an empty file, save it as
raise_apps.py
Copy the image below, save it exactly named
raise.png
in one and the same directory as the indicator.Then simply run it by the command:
python3 /path/to/raise_apps.py
Add if you want to Startup Applications:
/bin/bash -c "sleep 10 && python3 /path/to/raise_apps.py"
OLD ANSWER:
About the question
With the right tools, it is not very complicated to "just" raise all windows of an application. It is a bit more complicated to make sure only the windows of the current viewport are raised. The real challenge however is to find a convenient way to make the action available to the user.
Below five options to take care of that, to show how it can be done. All options are ready to be used. The last option however is kind of experimental; it works fine but has a few minor cosmetic downsides, as explained in the description of the option. I added it nevertheless as a concept.
Spreading the windows automatically in a non- overlapping way, as suggested in a comment, seems not a practical idea to me; if you work in an (application-wise) grouped window setup, the script would possibly unwantedly rearrange windows.
How to use
For all options you need to:
install
wmctrl
if it is not yet on your system:sudo apt-get install wmctrl
create, if it does not exist yet, the directory:
~/bin
(explanation: the directory
~/bin
is in $PATH, so you can run executables by their name)Copy the script, corresponding to the option, paste it into an empty file, save it as
raise_app
(no extension) in~/bin
and make it executable
In the separate options, possible additional steps will be explained.
Option 1: choose the application by entering one or more characters
- Press a key combination, a
zenity
window will appear - Enter one or more characters of the application's name in the entry box
- Press enter
This will make all windows of the matching application (on the current viewport) come to front.
raise all gnome-terminal
windows on the current viewport:
How to use:
- Do the set up as described in "How to use"
Test-run it by the command:
raise_app
If all works fine, add it to a shortcut key combination of your choice: Choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command
The script:
#!/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
Option 2: cycle through applications and raise their windows with a key combination:
Let's say I have the script below under a key combination Alt+1. I have several windows open of:
- firefox
- gnome-terminal
- nautilus
The current state:
I press once Alt+1, all nautilus
windows are raised:
I press again Alt+1, all firefox
windows are raised:
I press again Alt+1, all gnome-terminal
windows are raised again, the cycle starts over:
How to use
- Do the set up as described in "How to use"
Add it to a shortcut key combination of your choice: Choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command
raise_app
Then cycle through your applications with grouped application windows with your key combination.
The script:
#!/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
Option 3: press key combination + click on launcher icon -or- application window to raise all windows on the current viewport
This is probably the option that is closest to what is described in the question / comment.
Let's say I have a messy desktop with three nautilus
windows buried under other windows.
To raise all nautilus windows (example shortcut: Alt+1):
- Press Alt+1, release (!)
Within 3 seconds, either:
click on the application's icon in the launcher
or:
click on one of the application's windows
result:
How to use:
- Do the set up as described in "How to use"
Test-run it by the command:
raise_app
If all works fine, add it to a shortcut key combination of your choice: Choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command
Then:
Press your key combination and within 3 seconds, either:
- click on the application's icon in the launcher
- click on one of the application's windows
The script
#!/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
Option 4: a key combination calls an option list, showing the number of windows per application on the current viewport
This one turned out to be more convenient then I assumed:
Pressing the (again example-) key combination Alt+1 calls a zenity
window, listing all applications and the number of their windows on the current viewport:
Simply pressing the ▴ or ▾ arrows will bring you to the right option. Press Enter and all windows of the chosen application are raised.
How to use:
- Do the set up as described in "How to use"
Test-run it by the command:
raise_app
If all works fine, add it to a shortcut key combination of your choice: Choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command
The script
#!/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"')
Option 5: raise windows of running applications from a launcher icon
This option exists of a launcher icon, with the currently running applications in a quicklist. Choose one, and all windows of the applications will be raised.
The launcher is automatically updated when the list of running applications (on the current viewport) changes. The quicklist shows a different list on other viewports, where windows of other applications are opened (will take 1-2 seconds to adapt).
As mentioned, although fully functional, this option is a meant as a concept. It has a few minor cosmetic downsides as it is. The most important:
- The cursor "wheel" keeps spinning for a few seconds after an action. Although it does not effect the functionality, it is a cosmetic downside.
- It takes 1-2 seconds for the applicationlist in the launcher icon to be updated after the list of running applications changes.
Furthermore the setup is slightly more complicated (although explained in detail below):
How to use
Below you will find:
two scripts / an icon / a .desktop
file
- Prepare the setup as in "How to use", save the first (main-) script as
raise_app
in~/bin
Save the icon below (right-click, save as) as
raise.png
Copy the
.desktop
file into an empty file, edit the lineIcon=/path/to/raise.png
to the real path to the icon (paths with spaces between quotes)
Save it asraise.desktop
in~/.local/share/applications
Drag the
.desktop
file to the launcher to add it- copy the second script, paste it into an empty file, save it as
update_apps
in~/bin
, make it executable. Add the following command to your startup applications (Dash > Startup Applications > Add):
update_apps
- Log out and back in to make it work.
The first script
#!/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
The second script
#!/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;nn",
]for it in apps2]
update_dtfile(apps2, text)
The .desktop file
[Desktop Entry]
Name=Raise application windows
Comment=Raise groups of windows
Icon=/path/to/raise.png
Terminal=false
Type=Application
Version=1.0
Actions=
Brief Explanation
All solutions above use wmctrl
to create a window list, using the wmctrl -lpG
command. This command produces lines, looking like:
0x044000b3 0 3429 65 24 1615 1026 jacob-System-Product-Name unity - How to show all windows of an application? - Ask Ubuntu - Mozilla Firefox
These lines include:
- 1st column: the window's id (that we can use to raise it)
- 3rd column: the pid that owns the window.
- 4th / 5th column: the window's geometry x-y (that we use to see if the window is on the current viewport, i.c.w
xrandr
)
The pid is looked up in the output of ps -u <username>
to get a "user-readable" identification (name) of the application.
Thus we can allocate windows to applications. Subsequently we can raise the windows of a given application in a for
loop with the command wmctrl -ia
.
In option 3
the script starts a 3- second "waiting" loop, using the xprop -root
command repeatedly to see if there is any change in what is the frontmost window; this will happen if the user either clicks on a launcher icon to raise an application's window, or clicks on a window directly. If so, the while- loop breaks and looks up the "new" frontmost application, and subsequently raises all other windows of that application.
I agree, and thanks again for all your effort! :) || There's a weird thing that I didn't notice before. Sometimes after using theOption 2
script, when an application window is focused (that is not maximized) and I click on another window that is visible "below", the application below below doesn't get the focus.
– Joschua
Jan 8 '15 at 22:47
@Joschua the OP of this question: askubuntu.com/questions/575830/… attended me of a bug that was introduced at the latest "feature" update. True/False were mixed up, causing the script to crash when no applications have more then one window. If you use option2, please update to the latest version.
– Jacob Vlijm
Jan 21 '15 at 19:22
Option 1 not working for me on ubuntu xenial. something@something:~/bin$ ./raise_app Gtk-Message: GtkDialog mapped without a transient parent. This is discouraged. I was trying to open terminal windows. Nothing happened.
– xtrinch
Sep 17 '16 at 12:33
@Nirri what application name did you use? The message is quite normal if a zenity window runs without a Gtk parent. "Discouraged" is not an error.
– Jacob Vlijm
Sep 17 '16 at 12:39
First chars of terminal. It works - kind of - it raises a window of any app - but only one of them, not all of them as expected @user72216
– xtrinch
Sep 17 '16 at 12:42
|
show 9 more comments
EDIT -new answer-
The answer(s) below is/are still totally valid, and so the suggested options. Ongoing insight however made me add this option to use the indicator below, which is probably the most elegant solution.
As such, it should probably replace option 5 (using a .desktop file).
Simply choose the application from the list, and all windows of the corresponding application (present on the current viewport) will raise:
How to use
from ppa:
sudo add-apt-repository ppa:vlijm/upfront
sudo apt-get update
sudo apt-get install upfront
...or manually:
#!/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()
The indicator needs
wmctrl
sudo apt-get wmctrl
Copy the indicator into an empty file, save it as
raise_apps.py
Copy the image below, save it exactly named
raise.png
in one and the same directory as the indicator.Then simply run it by the command:
python3 /path/to/raise_apps.py
Add if you want to Startup Applications:
/bin/bash -c "sleep 10 && python3 /path/to/raise_apps.py"
OLD ANSWER:
About the question
With the right tools, it is not very complicated to "just" raise all windows of an application. It is a bit more complicated to make sure only the windows of the current viewport are raised. The real challenge however is to find a convenient way to make the action available to the user.
Below five options to take care of that, to show how it can be done. All options are ready to be used. The last option however is kind of experimental; it works fine but has a few minor cosmetic downsides, as explained in the description of the option. I added it nevertheless as a concept.
Spreading the windows automatically in a non- overlapping way, as suggested in a comment, seems not a practical idea to me; if you work in an (application-wise) grouped window setup, the script would possibly unwantedly rearrange windows.
How to use
For all options you need to:
install
wmctrl
if it is not yet on your system:sudo apt-get install wmctrl
create, if it does not exist yet, the directory:
~/bin
(explanation: the directory
~/bin
is in $PATH, so you can run executables by their name)Copy the script, corresponding to the option, paste it into an empty file, save it as
raise_app
(no extension) in~/bin
and make it executable
In the separate options, possible additional steps will be explained.
Option 1: choose the application by entering one or more characters
- Press a key combination, a
zenity
window will appear - Enter one or more characters of the application's name in the entry box
- Press enter
This will make all windows of the matching application (on the current viewport) come to front.
raise all gnome-terminal
windows on the current viewport:
How to use:
- Do the set up as described in "How to use"
Test-run it by the command:
raise_app
If all works fine, add it to a shortcut key combination of your choice: Choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command
The script:
#!/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
Option 2: cycle through applications and raise their windows with a key combination:
Let's say I have the script below under a key combination Alt+1. I have several windows open of:
- firefox
- gnome-terminal
- nautilus
The current state:
I press once Alt+1, all nautilus
windows are raised:
I press again Alt+1, all firefox
windows are raised:
I press again Alt+1, all gnome-terminal
windows are raised again, the cycle starts over:
How to use
- Do the set up as described in "How to use"
Add it to a shortcut key combination of your choice: Choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command
raise_app
Then cycle through your applications with grouped application windows with your key combination.
The script:
#!/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
Option 3: press key combination + click on launcher icon -or- application window to raise all windows on the current viewport
This is probably the option that is closest to what is described in the question / comment.
Let's say I have a messy desktop with three nautilus
windows buried under other windows.
To raise all nautilus windows (example shortcut: Alt+1):
- Press Alt+1, release (!)
Within 3 seconds, either:
click on the application's icon in the launcher
or:
click on one of the application's windows
result:
How to use:
- Do the set up as described in "How to use"
Test-run it by the command:
raise_app
If all works fine, add it to a shortcut key combination of your choice: Choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command
Then:
Press your key combination and within 3 seconds, either:
- click on the application's icon in the launcher
- click on one of the application's windows
The script
#!/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
Option 4: a key combination calls an option list, showing the number of windows per application on the current viewport
This one turned out to be more convenient then I assumed:
Pressing the (again example-) key combination Alt+1 calls a zenity
window, listing all applications and the number of their windows on the current viewport:
Simply pressing the ▴ or ▾ arrows will bring you to the right option. Press Enter and all windows of the chosen application are raised.
How to use:
- Do the set up as described in "How to use"
Test-run it by the command:
raise_app
If all works fine, add it to a shortcut key combination of your choice: Choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command
The script
#!/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"')
Option 5: raise windows of running applications from a launcher icon
This option exists of a launcher icon, with the currently running applications in a quicklist. Choose one, and all windows of the applications will be raised.
The launcher is automatically updated when the list of running applications (on the current viewport) changes. The quicklist shows a different list on other viewports, where windows of other applications are opened (will take 1-2 seconds to adapt).
As mentioned, although fully functional, this option is a meant as a concept. It has a few minor cosmetic downsides as it is. The most important:
- The cursor "wheel" keeps spinning for a few seconds after an action. Although it does not effect the functionality, it is a cosmetic downside.
- It takes 1-2 seconds for the applicationlist in the launcher icon to be updated after the list of running applications changes.
Furthermore the setup is slightly more complicated (although explained in detail below):
How to use
Below you will find:
two scripts / an icon / a .desktop
file
- Prepare the setup as in "How to use", save the first (main-) script as
raise_app
in~/bin
Save the icon below (right-click, save as) as
raise.png
Copy the
.desktop
file into an empty file, edit the lineIcon=/path/to/raise.png
to the real path to the icon (paths with spaces between quotes)
Save it asraise.desktop
in~/.local/share/applications
Drag the
.desktop
file to the launcher to add it- copy the second script, paste it into an empty file, save it as
update_apps
in~/bin
, make it executable. Add the following command to your startup applications (Dash > Startup Applications > Add):
update_apps
- Log out and back in to make it work.
The first script
#!/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
The second script
#!/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;nn",
]for it in apps2]
update_dtfile(apps2, text)
The .desktop file
[Desktop Entry]
Name=Raise application windows
Comment=Raise groups of windows
Icon=/path/to/raise.png
Terminal=false
Type=Application
Version=1.0
Actions=
Brief Explanation
All solutions above use wmctrl
to create a window list, using the wmctrl -lpG
command. This command produces lines, looking like:
0x044000b3 0 3429 65 24 1615 1026 jacob-System-Product-Name unity - How to show all windows of an application? - Ask Ubuntu - Mozilla Firefox
These lines include:
- 1st column: the window's id (that we can use to raise it)
- 3rd column: the pid that owns the window.
- 4th / 5th column: the window's geometry x-y (that we use to see if the window is on the current viewport, i.c.w
xrandr
)
The pid is looked up in the output of ps -u <username>
to get a "user-readable" identification (name) of the application.
Thus we can allocate windows to applications. Subsequently we can raise the windows of a given application in a for
loop with the command wmctrl -ia
.
In option 3
the script starts a 3- second "waiting" loop, using the xprop -root
command repeatedly to see if there is any change in what is the frontmost window; this will happen if the user either clicks on a launcher icon to raise an application's window, or clicks on a window directly. If so, the while- loop breaks and looks up the "new" frontmost application, and subsequently raises all other windows of that application.
EDIT -new answer-
The answer(s) below is/are still totally valid, and so the suggested options. Ongoing insight however made me add this option to use the indicator below, which is probably the most elegant solution.
As such, it should probably replace option 5 (using a .desktop file).
Simply choose the application from the list, and all windows of the corresponding application (present on the current viewport) will raise:
How to use
from ppa:
sudo add-apt-repository ppa:vlijm/upfront
sudo apt-get update
sudo apt-get install upfront
...or manually:
#!/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()
The indicator needs
wmctrl
sudo apt-get wmctrl
Copy the indicator into an empty file, save it as
raise_apps.py
Copy the image below, save it exactly named
raise.png
in one and the same directory as the indicator.Then simply run it by the command:
python3 /path/to/raise_apps.py
Add if you want to Startup Applications:
/bin/bash -c "sleep 10 && python3 /path/to/raise_apps.py"
OLD ANSWER:
About the question
With the right tools, it is not very complicated to "just" raise all windows of an application. It is a bit more complicated to make sure only the windows of the current viewport are raised. The real challenge however is to find a convenient way to make the action available to the user.
Below five options to take care of that, to show how it can be done. All options are ready to be used. The last option however is kind of experimental; it works fine but has a few minor cosmetic downsides, as explained in the description of the option. I added it nevertheless as a concept.
Spreading the windows automatically in a non- overlapping way, as suggested in a comment, seems not a practical idea to me; if you work in an (application-wise) grouped window setup, the script would possibly unwantedly rearrange windows.
How to use
For all options you need to:
install
wmctrl
if it is not yet on your system:sudo apt-get install wmctrl
create, if it does not exist yet, the directory:
~/bin
(explanation: the directory
~/bin
is in $PATH, so you can run executables by their name)Copy the script, corresponding to the option, paste it into an empty file, save it as
raise_app
(no extension) in~/bin
and make it executable
In the separate options, possible additional steps will be explained.
Option 1: choose the application by entering one or more characters
- Press a key combination, a
zenity
window will appear - Enter one or more characters of the application's name in the entry box
- Press enter
This will make all windows of the matching application (on the current viewport) come to front.
raise all gnome-terminal
windows on the current viewport:
How to use:
- Do the set up as described in "How to use"
Test-run it by the command:
raise_app
If all works fine, add it to a shortcut key combination of your choice: Choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command
The script:
#!/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
Option 2: cycle through applications and raise their windows with a key combination:
Let's say I have the script below under a key combination Alt+1. I have several windows open of:
- firefox
- gnome-terminal
- nautilus
The current state:
I press once Alt+1, all nautilus
windows are raised:
I press again Alt+1, all firefox
windows are raised:
I press again Alt+1, all gnome-terminal
windows are raised again, the cycle starts over:
How to use
- Do the set up as described in "How to use"
Add it to a shortcut key combination of your choice: Choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command
raise_app
Then cycle through your applications with grouped application windows with your key combination.
The script:
#!/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
Option 3: press key combination + click on launcher icon -or- application window to raise all windows on the current viewport
This is probably the option that is closest to what is described in the question / comment.
Let's say I have a messy desktop with three nautilus
windows buried under other windows.
To raise all nautilus windows (example shortcut: Alt+1):
- Press Alt+1, release (!)
Within 3 seconds, either:
click on the application's icon in the launcher
or:
click on one of the application's windows
result:
How to use:
- Do the set up as described in "How to use"
Test-run it by the command:
raise_app
If all works fine, add it to a shortcut key combination of your choice: Choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command
Then:
Press your key combination and within 3 seconds, either:
- click on the application's icon in the launcher
- click on one of the application's windows
The script
#!/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
Option 4: a key combination calls an option list, showing the number of windows per application on the current viewport
This one turned out to be more convenient then I assumed:
Pressing the (again example-) key combination Alt+1 calls a zenity
window, listing all applications and the number of their windows on the current viewport:
Simply pressing the ▴ or ▾ arrows will bring you to the right option. Press Enter and all windows of the chosen application are raised.
How to use:
- Do the set up as described in "How to use"
Test-run it by the command:
raise_app
If all works fine, add it to a shortcut key combination of your choice: Choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command
The script
#!/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"')
Option 5: raise windows of running applications from a launcher icon
This option exists of a launcher icon, with the currently running applications in a quicklist. Choose one, and all windows of the applications will be raised.
The launcher is automatically updated when the list of running applications (on the current viewport) changes. The quicklist shows a different list on other viewports, where windows of other applications are opened (will take 1-2 seconds to adapt).
As mentioned, although fully functional, this option is a meant as a concept. It has a few minor cosmetic downsides as it is. The most important:
- The cursor "wheel" keeps spinning for a few seconds after an action. Although it does not effect the functionality, it is a cosmetic downside.
- It takes 1-2 seconds for the applicationlist in the launcher icon to be updated after the list of running applications changes.
Furthermore the setup is slightly more complicated (although explained in detail below):
How to use
Below you will find:
two scripts / an icon / a .desktop
file
- Prepare the setup as in "How to use", save the first (main-) script as
raise_app
in~/bin
Save the icon below (right-click, save as) as
raise.png
Copy the
.desktop
file into an empty file, edit the lineIcon=/path/to/raise.png
to the real path to the icon (paths with spaces between quotes)
Save it asraise.desktop
in~/.local/share/applications
Drag the
.desktop
file to the launcher to add it- copy the second script, paste it into an empty file, save it as
update_apps
in~/bin
, make it executable. Add the following command to your startup applications (Dash > Startup Applications > Add):
update_apps
- Log out and back in to make it work.
The first script
#!/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
The second script
#!/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;nn",
]for it in apps2]
update_dtfile(apps2, text)
The .desktop file
[Desktop Entry]
Name=Raise application windows
Comment=Raise groups of windows
Icon=/path/to/raise.png
Terminal=false
Type=Application
Version=1.0
Actions=
Brief Explanation
All solutions above use wmctrl
to create a window list, using the wmctrl -lpG
command. This command produces lines, looking like:
0x044000b3 0 3429 65 24 1615 1026 jacob-System-Product-Name unity - How to show all windows of an application? - Ask Ubuntu - Mozilla Firefox
These lines include:
- 1st column: the window's id (that we can use to raise it)
- 3rd column: the pid that owns the window.
- 4th / 5th column: the window's geometry x-y (that we use to see if the window is on the current viewport, i.c.w
xrandr
)
The pid is looked up in the output of ps -u <username>
to get a "user-readable" identification (name) of the application.
Thus we can allocate windows to applications. Subsequently we can raise the windows of a given application in a for
loop with the command wmctrl -ia
.
In option 3
the script starts a 3- second "waiting" loop, using the xprop -root
command repeatedly to see if there is any change in what is the frontmost window; this will happen if the user either clicks on a launcher icon to raise an application's window, or clicks on a window directly. If so, the while- loop breaks and looks up the "new" frontmost application, and subsequently raises all other windows of that application.
edited Nov 17 '16 at 15:35
answered Jan 6 '15 at 9:59
Jacob VlijmJacob Vlijm
65.5k9130226
65.5k9130226
I agree, and thanks again for all your effort! :) || There's a weird thing that I didn't notice before. Sometimes after using theOption 2
script, when an application window is focused (that is not maximized) and I click on another window that is visible "below", the application below below doesn't get the focus.
– Joschua
Jan 8 '15 at 22:47
@Joschua the OP of this question: askubuntu.com/questions/575830/… attended me of a bug that was introduced at the latest "feature" update. True/False were mixed up, causing the script to crash when no applications have more then one window. If you use option2, please update to the latest version.
– Jacob Vlijm
Jan 21 '15 at 19:22
Option 1 not working for me on ubuntu xenial. something@something:~/bin$ ./raise_app Gtk-Message: GtkDialog mapped without a transient parent. This is discouraged. I was trying to open terminal windows. Nothing happened.
– xtrinch
Sep 17 '16 at 12:33
@Nirri what application name did you use? The message is quite normal if a zenity window runs without a Gtk parent. "Discouraged" is not an error.
– Jacob Vlijm
Sep 17 '16 at 12:39
First chars of terminal. It works - kind of - it raises a window of any app - but only one of them, not all of them as expected @user72216
– xtrinch
Sep 17 '16 at 12:42
|
show 9 more comments
I agree, and thanks again for all your effort! :) || There's a weird thing that I didn't notice before. Sometimes after using theOption 2
script, when an application window is focused (that is not maximized) and I click on another window that is visible "below", the application below below doesn't get the focus.
– Joschua
Jan 8 '15 at 22:47
@Joschua the OP of this question: askubuntu.com/questions/575830/… attended me of a bug that was introduced at the latest "feature" update. True/False were mixed up, causing the script to crash when no applications have more then one window. If you use option2, please update to the latest version.
– Jacob Vlijm
Jan 21 '15 at 19:22
Option 1 not working for me on ubuntu xenial. something@something:~/bin$ ./raise_app Gtk-Message: GtkDialog mapped without a transient parent. This is discouraged. I was trying to open terminal windows. Nothing happened.
– xtrinch
Sep 17 '16 at 12:33
@Nirri what application name did you use? The message is quite normal if a zenity window runs without a Gtk parent. "Discouraged" is not an error.
– Jacob Vlijm
Sep 17 '16 at 12:39
First chars of terminal. It works - kind of - it raises a window of any app - but only one of them, not all of them as expected @user72216
– xtrinch
Sep 17 '16 at 12:42
I agree, and thanks again for all your effort! :) || There's a weird thing that I didn't notice before. Sometimes after using the
Option 2
script, when an application window is focused (that is not maximized) and I click on another window that is visible "below", the application below below doesn't get the focus.– Joschua
Jan 8 '15 at 22:47
I agree, and thanks again for all your effort! :) || There's a weird thing that I didn't notice before. Sometimes after using the
Option 2
script, when an application window is focused (that is not maximized) and I click on another window that is visible "below", the application below below doesn't get the focus.– Joschua
Jan 8 '15 at 22:47
@Joschua the OP of this question: askubuntu.com/questions/575830/… attended me of a bug that was introduced at the latest "feature" update. True/False were mixed up, causing the script to crash when no applications have more then one window. If you use option2, please update to the latest version.
– Jacob Vlijm
Jan 21 '15 at 19:22
@Joschua the OP of this question: askubuntu.com/questions/575830/… attended me of a bug that was introduced at the latest "feature" update. True/False were mixed up, causing the script to crash when no applications have more then one window. If you use option2, please update to the latest version.
– Jacob Vlijm
Jan 21 '15 at 19:22
Option 1 not working for me on ubuntu xenial. something@something:~/bin$ ./raise_app Gtk-Message: GtkDialog mapped without a transient parent. This is discouraged. I was trying to open terminal windows. Nothing happened.
– xtrinch
Sep 17 '16 at 12:33
Option 1 not working for me on ubuntu xenial. something@something:~/bin$ ./raise_app Gtk-Message: GtkDialog mapped without a transient parent. This is discouraged. I was trying to open terminal windows. Nothing happened.
– xtrinch
Sep 17 '16 at 12:33
@Nirri what application name did you use? The message is quite normal if a zenity window runs without a Gtk parent. "Discouraged" is not an error.
– Jacob Vlijm
Sep 17 '16 at 12:39
@Nirri what application name did you use? The message is quite normal if a zenity window runs without a Gtk parent. "Discouraged" is not an error.
– Jacob Vlijm
Sep 17 '16 at 12:39
First chars of terminal. It works - kind of - it raises a window of any app - but only one of them, not all of them as expected @user72216
– xtrinch
Sep 17 '16 at 12:42
First chars of terminal. It works - kind of - it raises a window of any app - but only one of them, not all of them as expected @user72216
– xtrinch
Sep 17 '16 at 12:42
|
show 9 more comments
There is Super+W shortcut which will show expo of all the currently open windows, though that will include other applications. This comes by default, and doesn't require any changes, so perhaps it's a simplest option available.
Among other things, you could position windows on right and left halves of the screen with Ctrl+Super+Left/Right buttons, and switch between them with Alt+~ (tilde, the one next to number one key).
That doesn't bring all the windows of an application to the top though. You can see them, but you can't use them without having to click a lot.
– Joschua
Jan 8 '15 at 11:49
add a comment |
There is Super+W shortcut which will show expo of all the currently open windows, though that will include other applications. This comes by default, and doesn't require any changes, so perhaps it's a simplest option available.
Among other things, you could position windows on right and left halves of the screen with Ctrl+Super+Left/Right buttons, and switch between them with Alt+~ (tilde, the one next to number one key).
That doesn't bring all the windows of an application to the top though. You can see them, but you can't use them without having to click a lot.
– Joschua
Jan 8 '15 at 11:49
add a comment |
There is Super+W shortcut which will show expo of all the currently open windows, though that will include other applications. This comes by default, and doesn't require any changes, so perhaps it's a simplest option available.
Among other things, you could position windows on right and left halves of the screen with Ctrl+Super+Left/Right buttons, and switch between them with Alt+~ (tilde, the one next to number one key).
There is Super+W shortcut which will show expo of all the currently open windows, though that will include other applications. This comes by default, and doesn't require any changes, so perhaps it's a simplest option available.
Among other things, you could position windows on right and left halves of the screen with Ctrl+Super+Left/Right buttons, and switch between them with Alt+~ (tilde, the one next to number one key).
edited Jan 6 '15 at 23:47
answered Jan 6 '15 at 23:41
Sergiy KolodyazhnyySergiy Kolodyazhnyy
74.5k9155325
74.5k9155325
That doesn't bring all the windows of an application to the top though. You can see them, but you can't use them without having to click a lot.
– Joschua
Jan 8 '15 at 11:49
add a comment |
That doesn't bring all the windows of an application to the top though. You can see them, but you can't use them without having to click a lot.
– Joschua
Jan 8 '15 at 11:49
That doesn't bring all the windows of an application to the top though. You can see them, but you can't use them without having to click a lot.
– Joschua
Jan 8 '15 at 11:49
That doesn't bring all the windows of an application to the top though. You can see them, but you can't use them without having to click a lot.
– Joschua
Jan 8 '15 at 11:49
add a comment |
If you press Alt+Tab to cycle through applications, and you get to one with multiple windows, just keep holding the alt key down and after about 1 full second the icon will be replaced with a view of all of the windows for that application.
That may or may not be what you're looking for, but it works for me and is a ton simpler, so I figured I'd share the option!
1
You can also press the down arrow key to have the application windows show up straight away.
– Kris
Aug 2 '16 at 16:12
add a comment |
If you press Alt+Tab to cycle through applications, and you get to one with multiple windows, just keep holding the alt key down and after about 1 full second the icon will be replaced with a view of all of the windows for that application.
That may or may not be what you're looking for, but it works for me and is a ton simpler, so I figured I'd share the option!
1
You can also press the down arrow key to have the application windows show up straight away.
– Kris
Aug 2 '16 at 16:12
add a comment |
If you press Alt+Tab to cycle through applications, and you get to one with multiple windows, just keep holding the alt key down and after about 1 full second the icon will be replaced with a view of all of the windows for that application.
That may or may not be what you're looking for, but it works for me and is a ton simpler, so I figured I'd share the option!
If you press Alt+Tab to cycle through applications, and you get to one with multiple windows, just keep holding the alt key down and after about 1 full second the icon will be replaced with a view of all of the windows for that application.
That may or may not be what you're looking for, but it works for me and is a ton simpler, so I figured I'd share the option!
answered Sep 11 '15 at 0:48
Sean ColomboSean Colombo
1113
1113
1
You can also press the down arrow key to have the application windows show up straight away.
– Kris
Aug 2 '16 at 16:12
add a comment |
1
You can also press the down arrow key to have the application windows show up straight away.
– Kris
Aug 2 '16 at 16:12
1
1
You can also press the down arrow key to have the application windows show up straight away.
– Kris
Aug 2 '16 at 16:12
You can also press the down arrow key to have the application windows show up straight away.
– Kris
Aug 2 '16 at 16:12
add a comment |
I took @JacobVlijm's raise_apps.py script and made some enhancements to it, including making it more robust.
Specifically, I had found that after a day or two, @JacobVlijm's script would stop working, and I'd have to manually the script, to get it working again. In retrospect, my best guess is that the numerous calls to xrandr eventually cause issues.
Anyways, I adapted his code, increased the polling frequency from 5 seconds to every 1 second, as it doesn't use much CPU anyways, and made it more robust. I can typically have it running for days/weeks without issues.
One caveat is that I only call xrandr once during startup, to get screen resolution dimensions. So if you change your screen resolution (e.g. from 1920x1080 to some other resolution), you'll probably want to manually restart raise-apps.py so that it will pick up the new resolution. Personally, I never change my screen resolution, so this is a non-issue for me. Additionally, I have strong reason to believe that too many calls to xrandr were what was causing @JacobVlijm's version of the script to stop working after a day or two, so I would strongly recommend not simply putting the numerous calls to xrandr back in..
BTW, you need to place the raise.png image in the /usr/local/icons/ directory. Or if you want to put raise.png in a different directory make the appropriate change to the script, so that the script can find the image file.
Hopefully, Ubuntu will integrate this type of 'raise all windows' functionality into their system sooner than later as it's very useful:
#!/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()
add a comment |
I took @JacobVlijm's raise_apps.py script and made some enhancements to it, including making it more robust.
Specifically, I had found that after a day or two, @JacobVlijm's script would stop working, and I'd have to manually the script, to get it working again. In retrospect, my best guess is that the numerous calls to xrandr eventually cause issues.
Anyways, I adapted his code, increased the polling frequency from 5 seconds to every 1 second, as it doesn't use much CPU anyways, and made it more robust. I can typically have it running for days/weeks without issues.
One caveat is that I only call xrandr once during startup, to get screen resolution dimensions. So if you change your screen resolution (e.g. from 1920x1080 to some other resolution), you'll probably want to manually restart raise-apps.py so that it will pick up the new resolution. Personally, I never change my screen resolution, so this is a non-issue for me. Additionally, I have strong reason to believe that too many calls to xrandr were what was causing @JacobVlijm's version of the script to stop working after a day or two, so I would strongly recommend not simply putting the numerous calls to xrandr back in..
BTW, you need to place the raise.png image in the /usr/local/icons/ directory. Or if you want to put raise.png in a different directory make the appropriate change to the script, so that the script can find the image file.
Hopefully, Ubuntu will integrate this type of 'raise all windows' functionality into their system sooner than later as it's very useful:
#!/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()
add a comment |
I took @JacobVlijm's raise_apps.py script and made some enhancements to it, including making it more robust.
Specifically, I had found that after a day or two, @JacobVlijm's script would stop working, and I'd have to manually the script, to get it working again. In retrospect, my best guess is that the numerous calls to xrandr eventually cause issues.
Anyways, I adapted his code, increased the polling frequency from 5 seconds to every 1 second, as it doesn't use much CPU anyways, and made it more robust. I can typically have it running for days/weeks without issues.
One caveat is that I only call xrandr once during startup, to get screen resolution dimensions. So if you change your screen resolution (e.g. from 1920x1080 to some other resolution), you'll probably want to manually restart raise-apps.py so that it will pick up the new resolution. Personally, I never change my screen resolution, so this is a non-issue for me. Additionally, I have strong reason to believe that too many calls to xrandr were what was causing @JacobVlijm's version of the script to stop working after a day or two, so I would strongly recommend not simply putting the numerous calls to xrandr back in..
BTW, you need to place the raise.png image in the /usr/local/icons/ directory. Or if you want to put raise.png in a different directory make the appropriate change to the script, so that the script can find the image file.
Hopefully, Ubuntu will integrate this type of 'raise all windows' functionality into their system sooner than later as it's very useful:
#!/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()
I took @JacobVlijm's raise_apps.py script and made some enhancements to it, including making it more robust.
Specifically, I had found that after a day or two, @JacobVlijm's script would stop working, and I'd have to manually the script, to get it working again. In retrospect, my best guess is that the numerous calls to xrandr eventually cause issues.
Anyways, I adapted his code, increased the polling frequency from 5 seconds to every 1 second, as it doesn't use much CPU anyways, and made it more robust. I can typically have it running for days/weeks without issues.
One caveat is that I only call xrandr once during startup, to get screen resolution dimensions. So if you change your screen resolution (e.g. from 1920x1080 to some other resolution), you'll probably want to manually restart raise-apps.py so that it will pick up the new resolution. Personally, I never change my screen resolution, so this is a non-issue for me. Additionally, I have strong reason to believe that too many calls to xrandr were what was causing @JacobVlijm's version of the script to stop working after a day or two, so I would strongly recommend not simply putting the numerous calls to xrandr back in..
BTW, you need to place the raise.png image in the /usr/local/icons/ directory. Or if you want to put raise.png in a different directory make the appropriate change to the script, so that the script can find the image file.
Hopefully, Ubuntu will integrate this type of 'raise all windows' functionality into their system sooner than later as it's very useful:
#!/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()
answered 1 hour ago
GinoGino
1413
1413
add a comment |
add a comment |
Thanks for contributing an answer to Ask Ubuntu!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2faskubuntu.com%2fquestions%2f446521%2fhow-to-show-raise-all-windows-of-an-application%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
@Joschua Bringing all windows of an application to the front is not too difficult, but how would you like to define the application? would a key combination+clicking an application's window do?
– Jacob Vlijm
Jan 5 '15 at 20:24
@Joschua or mayby more elegant, a key combo + 1st character of application name?
– Jacob Vlijm
Jan 5 '15 at 20:51
I think the behavior ist the same with all applications. I most often miss this feature with terminal windows, where I often have two or more windows open side by side. Then I switch to a full screen window (e.g. Firefox) and when I want to switch back to the two terminal windows it is kinda difficult. The best way I found so far is a mouse-middle-click on the Firefox application bar which brings Firefox to the background so that I have the two terminals at the front again. However this only works well, when There are not too many applications piled on top :D
– peq
Jan 5 '15 at 22:08
also @Joschua It would be possible to have a key combination to bring to front application window groups; press once -> all firefox windows show up, pres again -> all terminal windows show up etc. could be made really smooth. interesting. working on it. will take a little work though.
– Jacob Vlijm
Jan 5 '15 at 22:22
@JacobVlijm Sounds like the right direction.. :) What seems most important to me, is that a key combination plus clicking on the icon brings all windows of that application (for example, many terminals as peq mentioned) to the front, preferably spread out, so that they are non-overlapping.. (Maybe, something like this could become part of Unity?!)
– Joschua
Jan 6 '15 at 0:06