Comment afficher (augmenter) toutes les fenêtres d'une application?

21

J'ai une application utilisant plusieurs fenêtres. Comment mettre rapidement toutes les fenêtres de cette application au premier plan?

Lorsque je fais défiler les applications avec la molette de défilement, une seule fenêtre s'affiche. Lorsque vous passez à la fenêtre suivante, la dernière fenêtre est à nouveau mise en arrière-plan.

Lorsque je clique sur l'icône de l'application, j'obtiens un aperçu plein écran de toutes les fenêtres. Je dois sélectionner chaque fenêtre manuellement et déplacer ma souris sur la moitié de l'écran plusieurs fois.

Ma meilleure solution jusqu'à présent est de minimiser toutes les fenêtres ( Ctrl+ Super+ D), puis d'afficher les fenêtres de mon application à l'aide de la molette de défilement.

Y a-t-il une meilleure solution?

peq
la source
@Joschua Faire passer toutes les fenêtres d'une application au premier plan n'est pas trop difficile, mais comment aimeriez-vous définir l'application? une combinaison de touches + un clic sur la fenêtre d'une application ferait-elle l'affaire?
Jacob Vlijm
@Joschua ou mayby ​​plus élégant, un combo clé + 1er caractère du nom de l'application?
Jacob Vlijm
Je pense que le comportement est le même pour toutes les applications. Cette fonctionnalité me manque le plus souvent avec les fenêtres de terminal, où j'ai souvent deux ou plusieurs fenêtres ouvertes côte à côte. Ensuite, je passe à une fenêtre plein écran (par exemple Firefox) et quand je veux revenir aux deux fenêtres de terminal, c'est un peu difficile. La meilleure façon que j'ai trouvée jusqu'à présent est un clic du milieu de la souris sur la barre d'application de Firefox qui ramène Firefox à l'arrière-plan afin que j'ai à nouveau les deux terminaux à l'avant. Cependant cela ne fonctionne que bien, quand il n'y a pas trop d'applications empilées sur le dessus: D
peq
aussi @Joschua Il serait possible d'avoir une combinaison de touches pour mettre en avant les groupes de fenêtres d'application ; appuyez une fois -> toutes les fenêtres firefox s'affichent, pressez à nouveau -> toutes les fenêtres du terminal s'affichent, etc. pourraient être rendues très fluides. intéressant. J'y travaille. prendra un peu de travail cependant.
Jacob Vlijm
@JacobVlijm Cela ressemble à la bonne direction .. :) Ce qui me semble le plus important, c'est qu'une combinaison de touches plus un clic sur l'icône amène toutes les fenêtres de cette application (par exemple, de nombreux terminaux comme mentionné ci-dessus) à l'avant, de préférence réparties dehors, afin qu'ils ne se chevauchent pas .. (Peut-être, quelque chose comme ça pourrait faire partie de Unity?!)
Joschua

Réponses:

21

EDIT -nouvelle réponse-

La ou les réponses ci-dessous sont / sont toujours totalement valables, et donc les options suggérées. Cependant, un aperçu continu m'a fait ajouter cette option pour utiliser l'indicateur ci-dessous, qui est probablement la solution la plus élégante.

En tant que tel, il devrait probablement remplacer l'option 5 (en utilisant un fichier .desktop).

Choisissez simplement l'application dans la liste et toutes les fenêtres de l'application correspondante (présentes dans la fenêtre courante) afficheront:

entrez la description de l'image ici

Comment utiliser

de ppa:

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

... ou manuellement:

#!/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()
  • L'indicateur a besoin wmctrl

    sudo apt-get wmctrl
    
  • Copiez l'indicateur dans un fichier vide, enregistrez-le sous raise_apps.py

  • Copiez l'image ci-dessous, enregistrez-la exactement raise.png dans un seul et même répertoire que l'indicateur.

    entrez la description de l'image ici

  • Ensuite, exécutez-le simplement par la commande:

    python3 /path/to/raise_apps.py

  • Ajoutez si vous souhaitez démarrer des applications:

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

ANCIENNE RÉPONSE:

À propos de la question

Avec les bons outils, il n'est pas très compliqué de "simplement" soulever toutes les fenêtres d'une application. Il est un peu plus compliqué de s'assurer que seules les fenêtres de la fenêtre courante sont levées. Le vrai défi est cependant de trouver un moyen pratique de mettre l'action à la disposition de l'utilisateur.

Ci-dessous cinq options pour prendre soin de cela, pour montrer comment cela peut être fait. Toutes les options sont prêtes à être utilisées. Cependant, la dernière option est plutôt expérimentale; cela fonctionne bien mais a quelques inconvénients cosmétiques mineurs, comme expliqué dans la description de l'option. Je l'ai quand même ajouté comme concept .

Répartir les fenêtres automatiquement de manière non superposée, comme suggéré dans un commentaire, ne me semble pas une idée pratique; si vous travaillez dans une configuration de fenêtre groupée (au niveau de l'application), le script pourrait éventuellement réorganiser les fenêtres.

Comment utiliser

Pour toutes les options, vous devez:

  • installer wmctrls'il n'est pas encore sur votre système:

    sudo apt-get install wmctrl
    
  • créer, s'il n'existe pas encore, le répertoire:

    ~/bin
    

    (explication: le répertoire ~/binest dans $ PATH, vous pouvez donc exécuter les exécutables par leur nom)

  • Copiez le script, correspondant à l'option, collez-le dans un fichier vide, enregistrez-le sous raise_app(sans extension) ~/binet rendez-le exécutable

Dans les options séparées, les étapes supplémentaires possibles seront expliquées.

Option 1: choisissez l'application en saisissant un ou plusieurs caractères

  • Appuyez sur une combinaison de touches, une zenityfenêtre apparaîtra
  • Entrez un ou plusieurs caractères du nom de l'application dans la zone de saisie
  • Appuyez sur Entrée

Cela fera apparaître toutes les fenêtres de l'application correspondante (dans la fenêtre courante ).

ouvrir toutes les gnome-terminalfenêtres de la fenêtre courante:

entrez la description de l'image ici

entrez la description de l'image ici

Comment utiliser:

  • Effectuez la configuration comme décrit dans "Comment utiliser"
  • Testez-le par la commande:

    raise_app
    
  • Si tout fonctionne correctement, ajoutez-le à une combinaison de touches de raccourci de votre choix: Choisissez: Paramètres système> "Clavier"> "Raccourcis"> "Raccourcis personnalisés". Cliquez sur le "+" et ajoutez la commande

Le 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: parcourir les applications et augmenter leurs fenêtres avec une combinaison de touches:

Disons que j'ai le script ci-dessous sous une combinaison de touches Alt+ 1. J'ai plusieurs fenêtres ouvertes de:

  • Firefox
  • gnome-terminal
  • nautile

L'état actuel:

entrez la description de l'image ici

J'appuie une fois Alt+ 1, toutes les nautilusfenêtres sont levées:

<image>

J'appuie à nouveau sur Alt+ 1, toutes les firefoxfenêtres sont relevées:

<image>

J'appuie à nouveau sur Alt+ 1, toutes les gnome-terminalfenêtres se relèvent, le cycle recommence:

<image>

Comment utiliser

  • Effectuez la configuration comme décrit dans "Comment utiliser"
  • Ajoutez-le à une combinaison de touches de raccourci de votre choix: Choisissez: Paramètres système> "Clavier"> "Raccourcis"> "Raccourcis personnalisés". Cliquez sur le "+" et ajoutez la commande

    raise_app
    

Parcourez ensuite vos applications avec des fenêtres d'applications regroupées avec votre combinaison de touches.

Le 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: appuyez sur la combinaison de touches + cliquez sur l'icône du lanceur -ou- fenêtre d'application pour afficher toutes les fenêtres de la fenêtre courante

C'est probablement l'option qui se rapproche le plus de ce qui est décrit dans la question / le commentaire.

Disons que j'ai un bureau en désordre avec trois nautilusfenêtres enfouies sous d'autres fenêtres.

<image>

Pour ouvrir toutes les fenêtres nautilus (exemple de raccourci: Alt+ 1):

  • Appuyez sur Alt+ 1, relâchez (!)
  • Dans les 3 secondes, soit:

    cliquez sur l'icône de l'application dans le lanceur

    <image>

    ou:

    cliquez sur l'une des fenêtres de l'application

    <image>

    résultat:

    <image>


Comment utiliser:

  • Effectuez la configuration comme décrit dans "Comment utiliser"
  • Testez-le par la commande:

    raise_app
    
  • Si tout fonctionne correctement, ajoutez-le à une combinaison de touches de raccourci de votre choix: Choisissez: Paramètres système> "Clavier"> "Raccourcis"> "Raccourcis personnalisés". Cliquez sur le "+" et ajoutez la commande

Alors:

  • Appuyez sur votre combinaison de touches et dans les 3 secondes, soit:

    • cliquez sur l'icône de l'application dans le lanceur
    • cliquez sur l'une des fenêtres de l'application

Le 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: une combinaison de touches appelle une liste d'options, indiquant le nombre de fenêtres par application dans la fenêtre courante

Celui-ci s'est avéré plus pratique que j'ai supposé:

En appuyant sur (encore une fois l'exemple-) combinaison de touches Alt+ 1appelle une zenityfenêtre, répertoriant toutes les applications et le nombre de leurs fenêtres dans la fenêtre actuelle:

entrez la description de l'image ici

Une simple pression sur les flèches ou vous amènera à la bonne option. Appuyez sur Enteret toutes les fenêtres de l'application choisie sont ouvertes.

Comment utiliser:

  • Effectuez la configuration comme décrit dans "Comment utiliser"
  • Testez-le par la commande:

    raise_app
    
  • Si tout fonctionne correctement, ajoutez-le à une combinaison de touches de raccourci de votre choix: Choisissez: Paramètres système> "Clavier"> "Raccourcis"> "Raccourcis personnalisés". Cliquez sur le "+" et ajoutez la commande

Le 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: augmenter les fenêtres des applications en cours d'exécution à partir d'une icône de lancement

Cette option existe d'une icône de lanceur, avec les applications en cours d'exécution dans une liste rapide. Choisissez-en une et toutes les fenêtres des applications seront ouvertes.

entrez la description de l'image ici

Le lanceur est automatiquement mis à jour lorsque la liste des applications en cours d'exécution (dans la fenêtre actuelle) change. La liste rapide affiche une liste différente sur d'autres fenêtres, où les fenêtres d'autres applications sont ouvertes (cela prendra 1 à 2 secondes pour s'adapter).

Comme mentionné, bien que pleinement fonctionnelle, cette option est conçue comme un concept . Il a quelques inconvénients cosmétiques mineurs. Le plus important:

  • Le curseur "roue" continue de tourner pendant quelques secondes après une action. Bien que cela n'affecte pas la fonctionnalité, c'est un inconvénient cosmétique.
  • Il faut 1 à 2 secondes pour que la liste des applications de l'icône du lanceur soit mise à jour après la modification de la liste des applications en cours d'exécution.

De plus, la configuration est légèrement plus compliquée (bien qu'expliquée en détail ci-dessous):

Comment utiliser

Vous trouverez ci-dessous:

deux scripts / une icône / un .desktopfichier

  1. Préparez la configuration comme dans "Comment utiliser", enregistrez le premier script (principal) comme raise_appdans~/bin
  2. Enregistrez l'icône ci-dessous (clic droit, enregistrer sous) sous raise.png

    <icon>

  3. Copiez le .desktopfichier dans un fichier vide, modifiez la ligne

        Icon=/path/to/raise.png
    

    vers le chemin réel vers l'icône (chemins avec des espaces entre guillemets)
    Enregistrez-le comme raise.desktopdans~/.local/share/applications

  4. Faites glisser le .desktopfichier vers le lanceur pour l'ajouter

  5. copier le second script, collez - le dans un fichier vide, enregistrez comme update_appsdans ~/bin, le rendre exécutable.
  6. Ajoutez la commande suivante à vos applications de démarrage (Dash> Applications de démarrage> Ajouter):

    update_apps
    
  7. Déconnectez-vous et reconnectez-vous pour le faire fonctionner.

Le premier 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

Le deuxième 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;\n\n",
            ]for it in apps2]
        update_dtfile(apps2, text)

Le fichier .desktop

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

Actions=



Brève explication

Toutes les solutions ci-dessus utilisent wmctrlpour créer une liste de fenêtres, à l'aide de la wmctrl -lpGcommande. Cette commande produit des lignes, ressemblant à:

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

Ces lignes comprennent:

  • 1ère colonne: l'identifiant de la fenêtre (que nous pouvons utiliser pour l'augmenter)
  • 3ème colonne: le pid propriétaire de la fenêtre.
  • 4ème / 5ème colonne: la géométrie de la fenêtre xy (que nous utilisons pour voir si la fenêtre est sur la fenêtre courante, icw xrandr)

Le pid est recherché dans la sortie de ps -u <username>pour obtenir une identification (nom) "lisible par l'utilisateur" de l'application.
Ainsi, nous pouvons allouer des fenêtres aux applications. Par la suite, nous pouvons soulever les fenêtres d'une application donnée en forboucle avec la commande wmctrl -ia.

Dans l'option 3,
le script démarre une boucle "en attente" de 3 secondes, en utilisant la xprop -rootcommande à plusieurs reprises pour voir s'il y a un changement dans la fenêtre la plus en avant; cela se produira si l'utilisateur clique sur une icône de lanceur pour ouvrir la fenêtre d'une application ou clique directement sur une fenêtre. Si c'est le cas, la boucle while se rompt et recherche la "nouvelle" application la plus en avant, puis ouvre toutes les autres fenêtres de cette application.

Jacob Vlijm
la source
Je suis d'accord et merci encore pour tous vos efforts! :) || Il y a une chose étrange que je n'avais pas remarquée auparavant. Parfois, après avoir utilisé le Option 2script, lorsqu'une fenêtre d'application est focalisée (qui n'est pas agrandie) et que je clique sur une autre fenêtre qui est visible "ci-dessous", l'application ci-dessous ne reçoit pas le focus.
Joschua
@Joschua l'OP de cette question: askubuntu.com/questions/575830/… m'a assisté d'un bug qui a été introduit lors de la dernière mise à jour "fonctionnalité". Vrai / Faux ont été mélangés, provoquant le blocage du script lorsqu'aucune application n'a plus d'une fenêtre. Si vous utilisez l'option 2, veuillez mettre à jour vers la dernière version.
Jacob Vlijm
L'option 1 ne fonctionne pas pour moi sur Ubuntu Xenial. quelque chose @ quelque chose: ~ / bin $ ./raise_app Gtk-Message: GtkDialog mappé sans parent transitoire. C'est découragé. J'essayais d'ouvrir les fenêtres du terminal. Rien ne s'est passé.
xtrinch
@Nirri quel nom d'application avez-vous utilisé? Le message est tout à fait normal si une fenêtre de zénité s'exécute sans parent Gtk. "Découragé" n'est pas une erreur.
Jacob Vlijm
Premiers caractères du terminal. Cela fonctionne - en quelque sorte - il ouvre une fenêtre de n'importe quelle application - mais une seule d'entre elles, pas toutes comme prévu @ user72216
xtrinch
1

Il y a un raccourci Super+ Wqui affichera l'expo de toutes les fenêtres actuellement ouvertes, mais cela inclura d'autres applications. Cela vient par défaut et ne nécessite aucune modification, donc c'est peut-être une option la plus simple disponible.

Entre autres choses, vous pouvez positionner les fenêtres sur les moitiés droite et gauche de l'écran avec les boutons Ctrl+ Super+ Left/ Right, et basculer entre elles avec Alt + ~ (tilde, celui à côté de la touche numéro un).

Sergiy Kolodyazhnyy
la source
Cela ne met cependant pas toutes les fenêtres d'une application au sommet. Vous pouvez les voir, mais vous ne pouvez pas les utiliser sans avoir à cliquer beaucoup.
Joschua
1

Si vous appuyez sur Alt + Tab pour parcourir les applications et que vous en arrivez à une avec plusieurs fenêtres, maintenez simplement la touche alt enfoncée et après environ 1 seconde complète, l'icône sera remplacée par une vue de toutes les fenêtres de cette application.

C'est peut-être ce que vous cherchez, mais cela fonctionne pour moi et c'est beaucoup plus simple, alors j'ai pensé que je partagerais l'option!

Sean Colombo
la source
1
Vous pouvez également appuyer sur la flèche vers le bas pour afficher immédiatement les fenêtres d'application.
Kris
1

J'ai pris le script raise_apps.py de @ JacobVlijm et y ai apporté quelques améliorations, notamment en le rendant plus robuste.

Plus précisément, j'avais constaté qu'après un jour ou deux, le script de @ JacobVlijm cesserait de fonctionner, et je devrais redémarrer manuellement le script, pour le faire fonctionner à nouveau. Rétrospectivement, ma meilleure supposition est que les nombreux appels à xrandr finissent par causer des problèmes.

Quoi qu'il en soit, j'ai adapté son code, augmenté la fréquence d'interrogation de 5 secondes à toutes les 1 seconde, car il n'utilise pas beaucoup de CPU de toute façon et l'a rendu plus robuste. Je peux généralement le faire fonctionner pendant des jours / semaines sans problème.

Une mise en garde est que je n'appelle xrandr qu'une seule fois au démarrage, pour obtenir les dimensions de la résolution d'écran. Donc, si vous changez la résolution de votre écran (par exemple de 1920x1080 à une autre résolution), vous voudrez probablement redémarrer manuellement raise-apps.py afin qu'il récupère la nouvelle résolution. Personnellement, je ne change jamais ma résolution d'écran, donc ce n'est pas un problème pour moi. De plus, j'ai de bonnes raisons de croire que trop d'appels à xrandr étaient à l'origine de l'arrêt de la version @ JacobVlijm du script après un jour ou deux, donc je vous recommande fortement de ne pas simplement remettre les nombreux appels à xrandr.

BTW, vous devez placer l'image raise.png dans le répertoire / usr / local / icons /. Ou si vous souhaitez placer raise.png dans un répertoire différent, apportez la modification appropriée au script, afin que le script puisse trouver le fichier image.

Avec un peu de chance, Ubuntu intégrera ce type de fonctionnalité «augmenter toutes les fenêtres» dans leur système plus tôt que tard car il est très utile:

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