Wie werden alle Fenster einer Anwendung angezeigt (erhöht)?

21

Ich habe eine Anwendung mit mehreren Fenstern. Wie kann ich schnell alle Fenster dieser Anwendung in den Vordergrund bringen?

Wenn ich mit dem Scrollrad durch die Anwendungen scrolle, wird nur ein Fenster angezeigt. Wenn Sie zum nächsten Fenster wechseln, wird das letzte Fenster wieder in den Hintergrund gerückt.

Wenn ich auf das Anwendungssymbol klicke, erhalte ich eine Vollbildübersicht aller Fenster. Ich muss jedes Fenster manuell auswählen und die Maus mehrmals über die Hälfte des Bildschirms bewegen.

Meine bisher beste Lösung besteht darin, alle Fenster zu minimieren ( Ctrl+ Super+ D) und dann die Fenster meiner Anwendung mit dem Scrollrad anzuzeigen.

Gibt es eine bessere Lösung?

peq
quelle
@Joschua Es ist nicht allzu schwierig, alle Fenster einer Anwendung nach vorne zu bringen, aber wie möchten Sie die Anwendung definieren? Würde eine Tastenkombination + Klicken auf das Fenster einer Anwendung helfen?
Jacob Vlijm,
@Joschua oder vielleicht eleganter, eine Tastenkombination + 1. Zeichen des Anwendungsnamens?
Jacob Vlijm,
Ich denke, das Verhalten ist bei allen Anwendungen gleich. Ich vermisse diese Funktion am häufigsten bei Terminalfenstern, bei denen oft zwei oder mehr Fenster nebeneinander geöffnet sind. Dann wechsle ich in ein Vollbildfenster (zB Firefox) und wenn ich wieder zu den beiden Terminalfenstern wechseln möchte, ist es ein bisschen schwierig. Der beste Weg, den ich bisher gefunden habe, ist ein Maus-Mittel-Klick auf die Firefox-Anwendungsleiste, der Firefox in den Hintergrund bringt, sodass ich die beiden Terminals wieder vorne habe. Dies funktioniert jedoch nur dann gut, wenn nicht zu viele Anwendungen darauf gestapelt sind: D
peq
auch wäre @Joschua es möglich , eine Tastenkombination müssen Frontfenster zu bringen Gruppen ; einmal drücken -> alle Firefox-Fenster werden angezeigt, erneut drücken -> alle Terminal-Fenster werden angezeigt usw. könnten sehr flüssig sein. interessant. daran zu arbeiten. wird allerdings ein wenig Arbeit in Anspruch nehmen.
Jacob Vlijm
@JacobVlijm Klingt nach der richtigen Richtung .. :) Was mir am wichtigsten erscheint, ist, dass eine Tastenkombination plus Klicken auf das Symbol alle Fenster dieser Anwendung (z. B. viele Terminals wie oben erwähnt) nach vorne bringt, vorzugsweise verteilt raus, damit sie sich nicht überlappen .. (Vielleicht könnte so etwas Teil von Unity werden ?!)
Joschua

Antworten:

21

BEARBEITEN -neue Antwort-

Die Antwort (en) unten sind immer noch gültig, und daher die vorgeschlagenen Optionen. Aufgrund der fortwährenden Erkenntnisse habe ich diese Option hinzugefügt, um den folgenden Indikator zu verwenden, der wahrscheinlich die eleganteste Lösung ist.

Als solches sollte es wahrscheinlich Option 5 ersetzen (unter Verwendung einer .desktop-Datei).

Wählen Sie einfach die Anwendung aus der Liste aus, und alle Fenster der entsprechenden Anwendung (im aktuellen Ansichtsfenster vorhanden) werden geöffnet:

Bildbeschreibung hier eingeben

Wie benutzt man

von ppa:

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

... oder manuell:

#!/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()
  • Der Indikator benötigt wmctrl

    sudo apt-get wmctrl
    
  • Kopieren Sie den Indikator in eine leere Datei und speichern Sie ihn als raise_apps.py

  • Kopieren Sie das Bild unten und speichern Sie es genau mit dem Namen raise.png in ein und demselben Verzeichnis wie der Indikator.

    Bildbeschreibung hier eingeben

  • Dann führen Sie es einfach mit dem Befehl:

    python3 /path/to/raise_apps.py

  • Hinzufügen, wenn Sie Anwendungen starten möchten:

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

ALTE ANTWORT:

Über die Frage

Mit den richtigen Tools ist es nicht sehr kompliziert, "nur" alle Fenster einer Anwendung zu öffnen. Es ist etwas komplizierter sicherzustellen, dass nur die Fenster des aktuellen Ansichtsfensters geöffnet sind. Die eigentliche Herausforderung besteht jedoch darin, einen bequemen Weg zu finden, um die Aktion dem Benutzer zur Verfügung zu stellen.

Nachfolgend fünf Optionen, um das zu erledigen und zu zeigen, wie es gemacht werden kann. Alle Optionen können jetzt verwendet werden. Die letzte Option ist jedoch eher experimentell. es funktioniert gut, hat aber ein paar kleinere kosmetische Nachteile, wie in der Beschreibung der Option erläutert. Ich habe es trotzdem als Konzept hinzugefügt .

Das automatische Verbreiten der Fenster in nicht überlappender Weise, wie in einem Kommentar vorgeschlagen, scheint mir keine praktische Idee zu sein. Wenn Sie in einer (anwendungsspezifisch) gruppierten Fensterkonfiguration arbeiten, ordnet das Skript möglicherweise Fenster ungewollt neu an.

Wie benutzt man

Für alle Optionen müssen Sie:

  • installieren, wmctrlwenn es noch nicht auf Ihrem System ist:

    sudo apt-get install wmctrl
    
  • erstelle, falls noch nicht vorhanden, das Verzeichnis:

    ~/bin
    

    (Erklärung: Das Verzeichnis ~/binbefindet sich in $ PATH, so dass Sie ausführbare Dateien nach ihrem Namen ausführen können.)

  • Kopieren Sie das Skript entsprechend der Option, fügen Sie es in eine leere Datei ein, speichern Sie es unter raise_app(keine Erweiterung) ~/binund machen Sie es ausführbar

In den separaten Optionen werden mögliche zusätzliche Schritte erläutert.

Option 1: Wählen Sie die Anwendung aus, indem Sie ein oder mehrere Zeichen eingeben

  • Durch Drücken einer Tastenkombination wird ein zenityFenster angezeigt
  • Geben Sie ein oder mehrere Zeichen des Anwendungsnamens in das Eingabefeld ein
  • Drücken Sie Enter

Dadurch werden alle Fenster der entsprechenden Anwendung (im aktuellen Ansichtsfenster) in den Vordergrund gerückt.

Heben Sie alle gnome-terminalFenster im aktuellen Ansichtsfenster an:

Bildbeschreibung hier eingeben

Bildbeschreibung hier eingeben

Wie benutzt man:

  • Führen Sie die Einrichtung wie unter "Verwendung" beschrieben durch.
  • Führen Sie es mit dem folgenden Befehl aus:

    raise_app
    
  • Wenn alles funktioniert, fügen Sie es einer Tastenkombination Ihrer Wahl hinzu: Wählen Sie: Systemeinstellungen> "Tastatur"> "Tastenkombinationen"> "Benutzerdefinierte Tastenkombinationen". Klicken Sie auf das "+" und fügen Sie den Befehl hinzu

Das Drehbuch:

#!/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: Anwendungen durchlaufen und Fenster mit einer Tastenkombination öffnen:

Angenommen, ich habe das folgende Skript unter einer Tastenkombination Alt+ 1. Ich habe mehrere Fenster geöffnet von:

  • Feuerfuchs
  • gnome-terminal
  • Nautilus

Der momentane Zustand:

Bildbeschreibung hier eingeben

Ich drücke einmal Alt+ 1, alle nautilusFenster werden geöffnet:

<image>

Ich drücke erneut Alt+ 1, alle firefoxFenster werden geöffnet:

<image>

Ich drücke erneut Alt+ 1, alle gnome-terminalFenster werden wieder geöffnet, der Zyklus beginnt von vorne:

<image>

Wie benutzt man

  • Führen Sie die Einrichtung wie unter "Verwendung" beschrieben durch.
  • Fügen Sie es einer Tastenkombination Ihrer Wahl hinzu: Wählen Sie: Systemeinstellungen> "Tastatur"> "Verknüpfungen"> "Benutzerdefinierte Verknüpfungen". Klicken Sie auf das "+" und fügen Sie den Befehl hinzu

    raise_app
    

Wechseln Sie dann mit Ihrer Tastenkombination durch Ihre Anwendungen mit gruppierten Anwendungsfenstern.

Das Drehbuch:

#!/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: Drücken Sie die Tastenkombination und klicken Sie auf das Startsymbol -oder- das Anwendungsfenster, um alle Fenster im aktuellen Ansichtsfenster zu öffnen

Dies ist wahrscheinlich die Option, die der Beschreibung in Frage / Kommentar am nächsten kommt.

Angenommen, ich habe einen unordentlichen Desktop mit drei nautilusFenstern, die unter anderen Fenstern verborgen sind.

<image>

So heben Sie alle Nautilus-Fenster an (Beispielverknüpfung: Alt+ 1):

  • Drücken Sie Alt+ 1, lassen Sie (!) Los
  • Innerhalb von 3 Sekunden entweder:

    Klicken Sie im Launcher auf das Anwendungssymbol

    <image>

    oder:

    Klicken Sie auf eines der Fenster der Anwendung

    <image>

    Ergebnis:

    <image>


Wie benutzt man:

  • Führen Sie die Einrichtung wie unter "Verwendung" beschrieben durch.
  • Führen Sie es mit dem folgenden Befehl aus:

    raise_app
    
  • Wenn alles funktioniert, fügen Sie es einer Tastenkombination Ihrer Wahl hinzu: Wählen Sie: Systemeinstellungen> "Tastatur"> "Tastenkombinationen"> "Benutzerdefinierte Tastenkombinationen". Klicken Sie auf das "+" und fügen Sie den Befehl hinzu

Dann:

  • Drücken Sie Ihre Tastenkombination und innerhalb von 3 Sekunden entweder:

    • Klicken Sie im Launcher auf das Anwendungssymbol
    • Klicken Sie auf eines der Fenster der Anwendung

Das Drehbuch

#!/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: Eine Tastenkombination ruft eine Optionsliste auf, in der die Anzahl der Fenster pro Anwendung im aktuellen Ansichtsfenster angezeigt wird

Dieser erwies sich als praktischer, als ich angenommen hatte:

Durch Drücken der (erneuten Beispiel-) Tastenkombination Alt+ wird 1ein zenityFenster aufgerufen , in dem alle Anwendungen und die Anzahl ihrer Fenster im aktuellen Ansichtsfenster aufgelistet sind:

Bildbeschreibung hier eingeben

Durch einfaches Drücken der Pfeiltasten oder gelangen Sie zur richtigen Option. Drücken Sie Enterund alle Fenster der gewählten Anwendung werden geöffnet.

Wie benutzt man:

  • Führen Sie die Einrichtung wie unter "Verwendung" beschrieben durch.
  • Führen Sie es mit dem folgenden Befehl aus:

    raise_app
    
  • Wenn alles funktioniert, fügen Sie es einer Tastenkombination Ihrer Wahl hinzu: Wählen Sie: Systemeinstellungen> "Tastatur"> "Tastenkombinationen"> "Benutzerdefinierte Tastenkombinationen". Klicken Sie auf das "+" und fügen Sie den Befehl hinzu

Das Drehbuch

#!/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: Öffnen Sie die Fenster ausgeführter Anwendungen über ein Startsymbol

Diese Option besteht aus einem Startsymbol, in dem sich die derzeit ausgeführten Anwendungen in einer Schnellliste befinden. Wenn Sie eines auswählen, werden alle Fenster der Anwendungen geöffnet.

Bildbeschreibung hier eingeben

Der Starter wird automatisch aktualisiert, wenn sich die Liste der ausgeführten Anwendungen (im aktuellen Ansichtsfenster) ändert. Die Schnellliste zeigt eine andere Liste in anderen Ansichtsfenstern an, in denen Fenster anderer Anwendungen geöffnet sind (die Anpassung dauert 1-2 Sekunden).

Wie bereits erwähnt, ist diese Option, obwohl sie voll funktionsfähig ist, als Konzept gedacht . Es hat ein paar kleinere kosmetische Nachteile, wie es ist. Das wichtigste:

  • Nach einer Aktion dreht sich das Cursor- "Rad" einige Sekunden lang. Obwohl es die Funktionalität nicht beeinträchtigt, ist es ein kosmetischer Nachteil.
  • Es dauert 1-2 Sekunden, bis die Anwendungsliste im Launcher-Symbol aktualisiert ist, nachdem sich die Liste der ausgeführten Anwendungen geändert hat.

Darüber hinaus ist das Setup etwas komplizierter (obwohl im Folgenden ausführlich erläutert):

Wie benutzt man

Nachfolgend finden Sie:

zwei Skripte / ein Icon / eine .desktopDatei

  1. Bereiten Sie das Setup wie in "How to use" vor, speichern Sie das erste (Haupt-) Skript wie raise_appin~/bin
  2. Speichern Sie das unten stehende Symbol (Rechtsklick, Speichern unter) unter raise.png

    <icon>

  3. Kopieren Sie die .desktopDatei in eine leere Datei und bearbeiten Sie die Zeile

        Icon=/path/to/raise.png
    

    den realen Pfad zum Symbol (Pfade mit Leerzeichen zwischen Anführungszeichen)
    speichern Sie es als raise.desktopin~/.local/share/applications

  4. Ziehen Sie die .desktopDatei in den Launcher, um sie hinzuzufügen

  5. Kopieren Sie das zweite Skript, fügen Sie ihn in eine leere Datei, speichern Sie es als update_appsin ~/bin, machen es ausführbar.
  6. Fügen Sie Ihren Startanwendungen den folgenden Befehl hinzu (Dash> Startanwendungen> Hinzufügen):

    update_apps
    
  7. Melden Sie sich ab und wieder an, damit es funktioniert.

Das erste Drehbuch

#!/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

Das zweite Drehbuch

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

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

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

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

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

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

Die .desktop-Datei

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

Actions=



Kurze Erklärung

Alle oben genannten Lösungen werden verwendet wmctrl, um mit dem wmctrl -lpGBefehl eine Fensterliste zu erstellen . Dieser Befehl erzeugt Zeilen, die wie folgt aussehen:

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

Diese Zeilen umfassen:

  • 1. Spalte: die ID des Fensters (mit der wir es erhöhen können)
  • 3. Spalte: Die PID, die das Fenster besitzt.
  • 4./5. Spalte: Die Fenstergeometrie xy (anhand derer wir sehen, ob sich das Fenster im aktuellen Ansichtsfenster befindet, icw xrandr)

Die pid wird in der Ausgabe von nachgeschlagen ps -u <username>, um eine "benutzerlesbare" Identifikation (Name) der Anwendung zu erhalten.
So können wir den Anwendungen Fenster zuweisen. Anschließend können wir formit dem Befehl die Fenster einer bestimmten Anwendung in einer Schleife öffnenwmctrl -ia .

In Option 3
startet das Skript eine Warteschleife von 3 Sekunden, wobei der xprop -rootBefehl wiederholt verwendet wird, um festzustellen, ob sich am vordersten Fenster etwas geändert hat. Dies geschieht, wenn der Benutzer entweder auf ein Startsymbol klickt, um das Fenster einer Anwendung zu öffnen, oder direkt auf ein Fenster klickt. In diesem Fall unterbricht die while-Schleife die "neue" vorderste Anwendung, schlägt sie nach und öffnet anschließend alle anderen Fenster dieser Anwendung.

Jacob Vlijm
quelle
Ich stimme zu und danke nochmals für all Ihre Bemühungen! :) || Es gibt eine seltsame Sache, die ich vorher nicht bemerkt habe. Option 2Wenn ein Anwendungsfenster nach der Verwendung des Skripts fokussiert ist (das nicht maximiert ist) und ich auf ein anderes Fenster klicke, das "unten" sichtbar ist, erhält die Anwendung unten nicht den Fokus.
Joschua
@Joschua das OP dieser Frage: askubuntu.com/questions/575830/… hat mich über einen Fehler informiert , der beim neuesten "Feature" -Update eingeführt wurde. True / False wurden vertauscht und das Skript stürzte ab, wenn keine Anwendung mehr als ein Fenster hat. Wenn Sie Option2 verwenden, aktualisieren Sie bitte auf die neueste Version.
Jacob Vlijm
Option 1 funktioniert bei Ubuntu Xenial nicht. something @ something: ~ / bin $ ./raise_app Gtk-Meldung: GtkDialog wird ohne ein vorübergehendes übergeordnetes Element zugeordnet. Dies wird abgeraten. Ich habe versucht, Terminalfenster zu öffnen. Nichts ist passiert.
Xtrinch
@Nirri welchen Anwendungsnamen hast du benutzt? Die Meldung ist ganz normal, wenn ein Zenity-Fenster ohne ein übergeordnetes Gtk-Element ausgeführt wird. "Entmutigt" ist kein Fehler.
Jacob Vlijm
Erste Zeichen des Terminals. Es funktioniert - irgendwie - es öffnet ein Fenster jeder App - aber nur eines von ihnen, nicht alle wie erwartet @ user72216
xtrinch
1

Es gibt eine Super+ WVerknüpfung, die die Expos aller aktuell geöffneten Fenster anzeigt, aber auch andere Anwendungen enthält. Dies ist standardmäßig aktiviert und erfordert keine Änderungen. Daher ist dies möglicherweise die einfachste verfügbare Option.

Unter anderem können Sie mit den Tasten Ctrl+ Super+ Left/ die Fenster in der rechten und linken Bildschirmhälfte positionieren und mit der RightTaste Alt + ~ (Tilde, die Taste neben der ersten) zwischen ihnen wechseln.

Sergiy Kolodyazhnyy
quelle
Das bringt jedoch nicht alle Fenster einer Anwendung nach oben. Sie können sie sehen, aber Sie können sie nicht verwenden, ohne viel klicken zu müssen.
Joschua
1

Wenn Sie Alt + Tab drücken, um durch Anwendungen zu blättern, und eine mit mehreren Fenstern angezeigt wird, halten Sie einfach die Alt-Taste gedrückt, und nach etwa einer vollen Sekunde wird das Symbol durch eine Ansicht aller Fenster für diese Anwendung ersetzt.

Das mag sein oder auch nicht, wonach Sie suchen, aber es funktioniert für mich und ist viel einfacher, also dachte ich mir, ich würde die Option teilen!

Sean Colombo
quelle
1
Sie können auch die Abwärtspfeiltaste drücken, um die Anwendungsfenster sofort anzuzeigen.
Kris
1

Ich habe @ JacobVlijms raise_apps.py-Skript verwendet und einige Verbesserungen vorgenommen, einschließlich der Verbesserung der Robustheit.

Insbesondere hatte ich festgestellt, dass das Skript von @ JacobVlijm nach ein oder zwei Tagen nicht mehr funktioniert, und ich musste das Skript manuell neu starten, damit es wieder funktioniert. Rückblickend schätze ich, dass die zahlreichen Aufrufe von xrandr letztendlich zu Problemen führen.

Jedenfalls habe ich seinen Code angepasst und die Abfragefrequenz von 5 Sekunden auf 1 Sekunde erhöht, da er sowieso nicht viel CPU verbraucht und robuster gemacht hat. Ich kann es normalerweise Tage / Wochen ohne Probleme laufen lassen.

Eine Einschränkung ist, dass ich xrandr nur einmal während des Startvorgangs aufrufe, um die Bildschirmauflösung zu ermitteln. Wenn Sie also Ihre Bildschirmauflösung ändern (z. B. von 1920 x 1080 auf eine andere Auflösung), möchten Sie raise-apps.py wahrscheinlich manuell neu starten, damit die neue Auflösung übernommen wird. Ich persönlich ändere meine Bildschirmauflösung nie, daher ist dies für mich kein Problem. Darüber hinaus habe ich guten Grund zu der Annahme, dass zu viele Aufrufe von xrandr dazu geführt haben, dass die @ JacobVlijm-Version des Skripts nach ein oder zwei Tagen nicht mehr funktioniert. Daher würde ich nachdrücklich empfehlen, die zahlreichen Aufrufe von xrandr nicht einfach wieder zu verwenden.

Übrigens müssen Sie das Bild raise.png im Verzeichnis / usr / local / icons / ablegen. Wenn Sie raise.png in einem anderen Verzeichnis ablegen möchten, nehmen Sie die entsprechenden Änderungen am Skript vor, damit das Skript die Image-Datei finden kann.

Ubuntu wird hoffentlich diese Art der "Erhöhung aller Fenster" -Funktionalität früher als später in sein System integrieren, da dies sehr nützlich ist:

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

from sys import stderr, exit
import signal
import gi

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

import logging
import logging.handlers

import time
import os
import subprocess
import getpass

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

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

logger.addHandler(log_handler)


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

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

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

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

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

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

        GLib.timeout_add_seconds(1.0, self.check_recent)

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

        self.menu.show_all()
        return self.menu

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

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

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

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

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

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

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

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

        GLib.timeout_add_seconds(1.0, self.check_recent)


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


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

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

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

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


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

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

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

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

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


logger.info("(raise-apps.py is starting up..)")
Indicator()
signal.signal(signal.SIGINT, signal.SIG_DFL)
Gtk.main()
Gino
quelle