จะแสดง (เพิ่ม) หน้าต่างทั้งหมดของแอปพลิเคชันได้อย่างไร


21

ฉันมีแอปพลิเคชันที่ใช้หลาย windows ฉันจะนำหน้าต่างทั้งหมดของแอปพลิเคชั่นนั้นไปยังเบื้องหน้าได้อย่างรวดเร็วได้อย่างไร

เมื่อฉันเลื่อนดูแอพพลิเคชั่นด้วยล้อเลื่อนมันจะแสดงเพียงหน้าต่างเดียวเท่านั้น เมื่อไปที่หน้าต่างถัดไปหน้าต่างสุดท้ายจะถูกนำมาที่พื้นหลังอีกครั้ง

เมื่อฉันคลิกที่ไอคอนแอปพลิเคชันฉันจะได้รับภาพรวมเต็มหน้าจอของหน้าต่างทั้งหมด ฉันต้องเลือกแต่ละหน้าต่างด้วยตนเองและเลื่อนเมาส์ไปครึ่งหน้าจอหลายครั้ง

ทางออกที่ดีที่สุดของฉันจนถึงตอนนี้ก็ลดขนาดหน้าต่างทั้งหมด ( Ctrl+ Super+ D) แล้วแสดงหน้าต่างของแอปพลิเคชันของฉันโดยใช้ล้อเลื่อน

มีวิธีแก้ปัญหาที่ดีกว่านี้ไหม?


@Joschua การนำหน้าต่างทั้งหมดของแอปพลิเคชั่นไปด้านหน้านั้นไม่ยากเกินไป แต่คุณต้องการกำหนดแอปพลิเคชันอย่างไร คีย์ผสม + การคลิกหน้าต่างแอปพลิเคชันจะทำอย่างไร
Jacob Vlijm

@Joschua หรืออาจจะดูสง่างามยิ่งขึ้นคีย์ผสม + อักขระตัวที่ 1 ของชื่อแอปพลิเคชัน?
Jacob Vlijm

ฉันคิดว่าพฤติกรรมนี้ไม่เหมือนกันกับทุกแอป ฉันมักพลาดคุณลักษณะนี้ด้วยหน้าต่างเทอร์มินัลซึ่งฉันมักจะเปิดหน้าต่างสองบานขึ้นไปเคียงข้างกัน จากนั้นฉันเปลี่ยนเป็นหน้าต่างเต็มหน้าจอ (เช่น Firefox) และเมื่อฉันต้องการสลับกลับไปที่หน้าต่างเทอร์มินัลสองเครื่องมันค่อนข้างยาก วิธีที่ดีที่สุดที่ฉันพบคือการคลิกเมาส์กลางบนแถบแอพพลิเคชั่นของ Firefox ซึ่งนำ Firefox ไปสู่พื้นหลังเพื่อให้ฉันมีเทอร์มินัลสองตัวที่อยู่ด้านหน้า อย่างไรก็ตามวิธีนี้ใช้งานได้ดีเมื่อมีแอปพลิเคชันไม่มากเกินไปซ้อนอยู่ด้านบน: D
peq

ยัง @Joschua มันเป็นไปได้ที่จะมีการรวมกันที่สำคัญเพื่อนำไปสู่กลุ่มหน้าต่างแอปพลิเคชันด้านหน้า; กดหนึ่งครั้ง -> หน้าต่าง Firefox ทั้งหมดแสดงขึ้นแสดงอีกครั้ง -> หน้าต่างเทอร์มินัลทั้งหมดปรากฏขึ้น ฯลฯ อาจทำให้ราบรื่นจริงๆ น่าสนใจ ทำงานกับมัน จะใช้เวลาทำงานเล็กน้อย
Jacob Vlijm

@JacobVlijm ฟังดูเหมือนกับทิศทางที่ถูกต้อง .. :) สิ่งที่สำคัญที่สุดสำหรับฉันคือการรวมคีย์และการคลิกที่ไอคอนจะนำหน้าต่างทั้งหมดของแอปพลิเคชันนั้นมา (ตัวอย่างเช่นเทอร์มินัลจำนวนมากตามที่กล่าวถึง) ออกมาเพื่อที่พวกเขาจะไม่ทับซ้อน .. (อาจจะบางสิ่งเช่นนี้อาจกลายเป็นส่วนหนึ่งของ Unity ?!)
Joschua

คำตอบ:


21

แก้ไข - คำตอบใหม่ -

คำตอบด้านล่างนี้ / ยังคงใช้ได้ทั้งหมดและตัวเลือกที่แนะนำ ข้อมูลเชิงลึกอย่างต่อเนื่องทำให้ฉันเพิ่มตัวเลือกนี้เพื่อใช้ตัวบ่งชี้ด้านล่างซึ่งอาจเป็นทางออกที่หรูหราที่สุด

ดังนั้นจึงควรแทนที่ตัวเลือก 5 (โดยใช้ไฟล์ .desktop)

เพียงเลือกแอปพลิเคชันจากรายการและหน้าต่างทั้งหมดของแอปพลิเคชั่นที่เกี่ยวข้อง (ปรากฏบนวิวพอร์ตปัจจุบัน) จะเพิ่ม:

ป้อนคำอธิบายรูปภาพที่นี่

วิธีใช้

จาก ppa:

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

... หรือด้วยตนเอง:

#!/usr/bin/env python3
import signal
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('AppIndicator3', '0.1')
from gi.repository import Gtk, AppIndicator3, GObject
import time
from threading import Thread
import os
import subprocess
import getpass

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

class Indicator():
    def __init__(self):
        self.app = 'raise_apps'
        iconpath = os.path.join(currpath, "raise.png")
        self.indicator = AppIndicator3.Indicator.new(
            self.app, iconpath,
            AppIndicator3.IndicatorCategory.OTHER)
        self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE)       
        self.indicator.set_menu(self.create_menu())
        # the thread:
        self.update = Thread(target=self.check_recent)
        # daemonize the thread to make the indicator stopable
        self.update.setDaemon(True)
        self.update.start()

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

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

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

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

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

    def check_recent(self):
        self.menu_items1 = []
        while True:
            time.sleep(4)
            self.menu_items2 = self.get_apps()
            for app in self.menu_items2:
                app[0] = "gnome-terminal" if "gnome-terminal" in app[0] else app[0]
            if self.menu_items2 != self.menu_items1:
                GObject.idle_add(
                    self.set_new, 
                    priority=GObject.PRIORITY_DEFAULT
                    )
            self.menu_items1 = self.menu_items2

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

def get(command):
    return subprocess.check_output(command).decode("utf-8")

def execute(command):
    subprocess.Popen(command)

Indicator()
GObject.threads_init()
signal.signal(signal.SIGINT, signal.SIG_DFL)
Gtk.main()
  • ตัวบ่งชี้ที่ต้องการ wmctrl

    sudo apt-get wmctrl
    
  • คัดลอกตัวบ่งชี้ลงในไฟล์เปล่าแล้วบันทึกเป็น raise_apps.py

  • คัดลอกภาพด้านล่างบันทึกเป็นชื่อที่แน่นอน raise.pngในไดเรกทอรีเดียวกับตัวบ่งชี้

    ป้อนคำอธิบายรูปภาพที่นี่

  • จากนั้นให้รันโดยใช้คำสั่ง:

    python3 /path/to/raise_apps.py

  • เพิ่มถ้าคุณต้องการเริ่มต้นแอปพลิเคชัน:

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

คำตอบเดิม:

เกี่ยวกับคำถาม

ด้วยเครื่องมือที่เหมาะสมมันไม่ซับซ้อนมากนักที่จะ "เพิ่ม" หน้าต่างทั้งหมดของแอปพลิเคชัน มันซับซ้อนกว่านี้เล็กน้อยเพื่อให้แน่ใจว่าจะเพิ่มเฉพาะหน้าต่างของวิวพอร์ตปัจจุบันเท่านั้น อย่างไรก็ตามความท้าทายที่แท้จริงคือการหาวิธีที่สะดวกในการทำให้ผู้ใช้สามารถดำเนินการได้

ด้านล่างห้าตัวเลือกที่จะดูแลที่แสดงให้เห็นว่ามันสามารถทำได้ ตัวเลือกทั้งหมดพร้อมใช้งาน ตัวเลือกสุดท้ายคือประเภทของการทดลอง มันทำงานได้ดี แต่มีข้อเสียเล็ก ๆ น้อย ๆ เครื่องสำอางตามที่อธิบายไว้ในคำอธิบายของตัวเลือก ฉันเพิ่ม แต่อย่างไรก็ตามมันเป็นแนวคิด

การแพร่กระจายหน้าต่างโดยอัตโนมัติในลักษณะที่ไม่ทับซ้อนกันตามที่แนะนำในความคิดเห็นดูเหมือนจะไม่ใช่ความคิดที่เป็นประโยชน์สำหรับฉัน หากคุณทำงานในการตั้งค่าหน้าต่าง (แอปพลิเคชันที่ฉลาด) จัดกลุ่มสคริปต์อาจจัดเรียงหน้าต่างใหม่โดยไม่ต้องการ

วิธีใช้

สำหรับตัวเลือกทั้งหมดคุณต้อง:

  • ติดตั้งwmctrlหากยังไม่ได้อยู่ในระบบของคุณ:

    sudo apt-get install wmctrl
    
  • สร้างถ้ายังไม่มีไดเรกทอรี:

    ~/bin
    

    (คำอธิบาย: ไดเรกทอรี~/binอยู่ใน $ PATH เพื่อให้คุณสามารถเรียกใช้ไฟล์ปฏิบัติการได้โดยใช้ชื่อของพวกเขา)

  • คัดลอกสคริปต์ที่ตรงกับตัวเลือกวางลงในไฟล์เปล่าบันทึกเป็นraise_app(ไม่มีส่วนขยาย) ~/binและทำให้สามารถเรียกใช้งานได้

ในตัวเลือกที่แยกต่างหากจะอธิบายขั้นตอนเพิ่มเติมที่เป็นไปได้

ตัวเลือกที่ 1: เลือกแอปพลิเคชันโดยป้อนอักขระหนึ่งตัวขึ้นไป

  • กดคีย์ผสมzenityหน้าต่างจะปรากฏขึ้น
  • ป้อนชื่อแอปพลิเคชันอย่างน้อยหนึ่งตัวในกล่องป้อน
  • กดปุ่มตกลง

สิ่งนี้จะทำให้หน้าต่างทั้งหมดของแอปพลิเคชันที่ตรงกัน (บนวิวพอร์ตปัจจุบัน ) ปรากฏขึ้นด้านหน้า

ยกgnome-terminalหน้าต่างทั้งหมดในวิวพอร์ตปัจจุบัน:

ป้อนคำอธิบายรูปภาพที่นี่

ป้อนคำอธิบายรูปภาพที่นี่

วิธีใช้:

  • ทำการตั้งค่าตามที่อธิบายไว้ใน "วิธีใช้"
  • ทดสอบเรียกใช้โดยคำสั่ง:

    raise_app
    
  • หากใช้งานได้ดีให้เพิ่มลงในชุดคีย์ลัดที่คุณเลือก: เลือก: การตั้งค่าระบบ> "คีย์บอร์ด"> "ทางลัด"> "ทางลัดที่กำหนดเอง" คลิกที่ "+" และเพิ่มคำสั่ง

บท:

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

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

def execute(command):
    subprocess.Popen(["/bin/bash", "-c", command])
# calculate screen resolution
res_output = get("xrandr").split(); idf = res_output.index("current")
res = (int(res_output[idf+1]), int(res_output[idf+3].replace(",", "")))
# creating window list on current viewport / id's / application names
w_data = [l.split()[0:7] for l in get("wmctrl -lpG").splitlines()]
windows = [[get("ps -u "+getpass.getuser()+" | grep "+w[2]).split()[-1], w[0]]
           for w in w_data if 0 < int(w[3]) < res[0] and 0 < int(w[4]) < res[1]]
# ask user for first characters
try:
    arg = get('zenity --entry --text "first characters" --title "application"').strip()
except subprocess.CalledProcessError:
    pass
# raise matching windows
try:
    [execute("wmctrl -ia "+item[1]) for item in windows if item[0].startswith(arg)]
except (subprocess.CalledProcessError, NameError):
    pass



ตัวเลือกที่ 2: วนรอบแอปพลิเคชันและยกระดับหน้าต่างด้วยคีย์ผสม:

สมมติว่าผมมีสคริปต์ด้านล่างภายใต้คีย์ผสม+Alt 1ฉันเปิดหน้าต่างหลายบาน:

  • Firefox
  • คำพังเพยขั้ว
  • หอยโข่ง

สถานะปัจจุบัน:

ป้อนคำอธิบายรูปภาพที่นี่

ฉันกดหนึ่งครั้งAlt+ 1ทุกnautilusหน้าต่างยกขึ้น:

<ภาพ>

ฉันกดอีกครั้งAlt+ หน้าต่าง1ทุกfirefoxบานยกขึ้น:

<ภาพ>

ฉันกดอีกครั้งAlt+ หน้าต่าง1ทั้งหมดgnome-terminalจะถูกยกขึ้นอีกรอบจะเริ่มต้นใหม่:

<ภาพ>

วิธีใช้

  • ทำการตั้งค่าตามที่อธิบายไว้ใน "วิธีใช้"
  • เพิ่มลงในชุดคีย์ลัดที่คุณเลือก: เลือก: การตั้งค่าระบบ> "แป้นพิมพ์"> "ทางลัด"> "ทางลัดที่กำหนดเอง" คลิกที่ "+" และเพิ่มคำสั่ง

    raise_app
    

จากนั้นวนรอบแอปพลิเคชันของคุณด้วยหน้าต่างแอปพลิเคชันที่จัดกลุ่มด้วยชุดคีย์ของคุณ

บท:

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

include_single = True # set to False if you only want to cycle through apps with multiple windows

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

def execute(command):
    subprocess.Popen(["/bin/bash", "-c", command])

def get_frontmost():
    cmd = "xprop -root"
    frontmost = [l for l in get(cmd).splitlines() if\
                 "ACTIVE_WINDOW(WINDOW)" in l][0].split()[-1]
    return frontmost[:2]+"0"+frontmost[2:]
# calculate screen resolution
res_output = get("xrandr").split(); idf = res_output.index("current")
res = (int(res_output[idf+1]), int(res_output[idf+3].replace(",", "")))
# creating window list on current viewport / id's / application names
w_data = [l.split()[0:7] for l in get("wmctrl -lpG").splitlines()]
windows = [[get("ps -u "+getpass.getuser()+" | grep "+w[2]).split()[-1], w[0]]
           for w in w_data if 0 < int(w[3]) < res[0] and 0 < int(w[4]) < res[1]]
# create application list to cycle through
if include_single == False:
    pre = [it[0] for it in windows]
    apps = sorted(list(set([it for it in pre if pre.count(it) > 1])))
else:
    apps = sorted(list(set([it[0] for it in windows])))
if len(apps) == 0:
    pass
else:
    # get the frontmost window as a last itm in the cycle
    front = get_frontmost()
    front_pid = [l.split()[2] for l in get("wmctrl -lp").splitlines() if front in l][0]
    last_infront = get("ps -u "+getpass.getuser()+" | grep "+front_pid).split()[-1]
    # determine next apllication to raise
    if not last_infront in apps or last_infront == apps[-1]:
        arg = apps[0]
        print(arg)
    else:
        arg = apps[apps.index(last_infront)+1]
    # raise matching windows
    try:
        [execute("wmctrl -ia "+item[1]) for item in windows if item[0] == arg]
    except (subprocess.CalledProcessError, NameError):
        pass



ตัวเลือกที่ 3: กดปุ่มการรวมกัน + คลิกที่ไอคอนตัวเรียกใช้- หรือ -หน้าต่างแอปพลิเคชันเพื่อยกหน้าต่างทั้งหมดในวิวพอร์ตปัจจุบัน

นี่อาจเป็นตัวเลือกที่ใกล้เคียงที่สุดกับที่อธิบายไว้ในคำถาม / ความคิดเห็น

สมมติว่าฉันมีเดสก์ท็อปยุ่งกับnautiluswindows สามฝังอยู่ภายใต้ windows อื่น

<ภาพ>

วิธียกหน้าต่าง nautilus ทั้งหมด (ทางลัดตัวอย่าง: Alt+ 1):

  • กดAlt+ 1ปล่อย (!)
  • ภายใน 3 วินาทีอย่างใดอย่างหนึ่ง:

    คลิกที่ไอคอนของแอปพลิเคชั่นในตัวเรียกใช้งาน

    <ภาพ>

    หรือ:

    คลิกที่หนึ่งในหน้าต่างของแอปพลิเคชัน

    <ภาพ>

    ผล:

    <ภาพ>


วิธีใช้:

  • ทำการตั้งค่าตามที่อธิบายไว้ใน "วิธีใช้"
  • ทดสอบเรียกใช้โดยคำสั่ง:

    raise_app
    
  • หากใช้งานได้ดีให้เพิ่มลงในชุดคีย์ลัดที่คุณเลือก: เลือก: การตั้งค่าระบบ> "คีย์บอร์ด"> "ทางลัด"> "ทางลัดที่กำหนดเอง" คลิกที่ "+" และเพิ่มคำสั่ง

แล้ว:

  • กดคีย์ผสมของคุณและภายใน 3 วินาที:

    • คลิกที่ไอคอนของแอปพลิเคชั่นในตัวเรียกใช้งาน
    • คลิกที่หนึ่งในหน้าต่างของแอปพลิเคชัน

บท

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

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

def execute(command):
    subprocess.Popen(["/bin/bash", "-c", command])

def get_frontmost():
    cmd = "xprop -root"
    frontmost = [l for l in get(cmd).splitlines() if\
                 "ACTIVE_WINDOW(WINDOW)" in l][0].split()[-1]
    return frontmost[:2]+"0"+frontmost[2:]

# calculate screen resolution
res_output = get("xrandr").split(); idf = res_output.index("current")
res = (int(res_output[idf+1]), int(res_output[idf+3].replace(",", "")))
# get window data for various purposes
w_data = get("wmctrl -lpG").splitlines()
non_windows = sum([[l.split()[0] for l in w_data if it in l]\
               for it in ("unity-launcher", "unity-panel", "unity-dash", "Hud")], [])
# get id of current window
curr_window = get_frontmost()
# user gets 3 seconds to pick an application window (or launcher icon)
t = 0
while t < 4:
    w_id1 = get_frontmost()
    time.sleep(1)
    w_id2 = get_frontmost()
    if w_id1 == w_id2 or w_id2 in non_windows+[curr_window]:
        t = t+1
    else:
        new_frontmost = w_id2
        break
# raise
try:
    pid = [l.split()[2] for l in w_data if new_frontmost in l]
    wl_data = [l.split() for l in w_data]
    raise_windows = [l[0] for l in wl_data if pid[0] == l[2] and\
                     0 < int(l[3]) < res[0] and 0 < int(l[4]) < res[1]]
    [execute("wmctrl -ia "+item) for item in raise_windows]
except NameError:
    pass


ตัวเลือก 4: การผสมคีย์เรียกรายการตัวเลือกโดยแสดงจำนวนหน้าต่างต่อแอปพลิเคชันในวิวพอร์ตปัจจุบัน

อันนี้เปิดออกเพื่อความสะดวกมากขึ้นแล้วฉันคิดว่า:

การกดคีย์ผสม (อีกครั้งตัวอย่าง -) Alt+ จะ1เรียกzenityหน้าต่างแสดงรายการแอปพลิเคชันทั้งหมดและจำนวนหน้าต่างในวิวพอร์ตปัจจุบัน:

ป้อนคำอธิบายรูปภาพที่นี่

เพียงแค่กดปุ่มหรือลูกศรจะพาคุณไปยังตัวเลือกที่เหมาะสม กดEnterและหน้าต่างทั้งหมดของแอปพลิเคชันที่เลือกจะถูกยกขึ้น

วิธีใช้:

  • ทำการตั้งค่าตามที่อธิบายไว้ใน "วิธีใช้"
  • ทดสอบเรียกใช้โดยคำสั่ง:

    raise_app
    
  • หากใช้งานได้ดีให้เพิ่มลงในชุดคีย์ลัดที่คุณเลือก: เลือก: การตั้งค่าระบบ> "คีย์บอร์ด"> "ทางลัด"> "ทางลัดที่กำหนดเอง" คลิกที่ "+" และเพิ่มคำสั่ง

บท

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

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

def execute(command):
    subprocess.Popen(["/bin/bash", "-c", command])
# calculate screen resolution
res_output = get("xrandr").split(); idf = res_output.index("current")
res = (int(res_output[idf+1]), int(res_output[idf+3].replace(",", "")))
# creating window list on current viewport / id's / application names
w_data = [l.split()[0:7] for l in get("wmctrl -lpG").splitlines()]
windows = [[get("ps -u "+getpass.getuser()+" | grep "+w[2]).split()[-1], w[0]]
           for w in w_data if 0 < int(w[3]) < res[0] and 0 < int(w[4]) < res[1]]
# preparing zenity optionlist
apps = [item[0] for item in windows]
# prevent multiple zenity windows
if apps.count("zenity") > 1:
    pass
elif apps.count("zenity") > 0:
    execute('zenity --info --text "Another Zenity window is open already"')
# preventing empty windowlist
elif len(apps) > 0:
    applist = [[app, str(apps.count(app))] for app in set(apps)]
    applist.sort(key=lambda x: x[1])
    # calling zenity window
    try:
        arg = get('zenity  --list  --text "Choose an application" '+\
               '--title "Current windows" '+\
               '--column "application" '+\
               '--column "windows" '+\
               '--height 250 '+\
               '--width 250 '+\
               (" ").join(sum(applist, [])))
    except subprocess.CalledProcessError:
        pass
    # raise matching windows
    try:
        [execute("wmctrl -ia "+item[1]) \
         for item in windows if arg.startswith(item[0])]
    except (subprocess.CalledProcessError, NameError):
        pass
else:
    execute('zenity --info --text "No windows to list"')



ตัวเลือกที่ 5: ยก windows ของแอปพลิเคชันที่กำลังเรียกใช้จากไอคอนตัวเรียกใช้

ตัวเลือกนี้มีไอคอนตัวเรียกใช้พร้อมกับแอปพลิเคชันที่ทำงานอยู่ในรายการด่วน เลือกหนึ่งหน้าต่างจากนั้นแอปพลิเคชันทั้งหมดจะได้รับการยกขึ้น

ป้อนคำอธิบายรูปภาพที่นี่

ตัวเรียกใช้งานจะได้รับการอัปเดตโดยอัตโนมัติเมื่อรายการแอปพลิเคชันที่รันอยู่ (บนวิวพอร์ตปัจจุบัน) เปลี่ยนแปลง รายการด่วนแสดงรายการต่าง ๆ ในวิวพอร์ตอื่น ๆ ที่เปิดหน้าต่างของแอปพลิเคชั่นอื่น (จะใช้เวลา 1-2 วินาทีในการปรับ)

เป็นที่กล่าวถึงแม้จะทำงานอย่างเต็มที่ตัวเลือกนี้เป็นความหมายเป็นแนวคิด มันมีข้อเสียเล็ก ๆ น้อย ๆ เครื่องสำอางตามที่มันเป็น ที่สำคัญที่สุด:

  • เคอร์เซอร์ "วงล้อ" หมุนอย่างต่อเนื่องไม่กี่วินาทีหลังจากการกระทำ แม้ว่ามันจะไม่ส่งผลกระทบต่อฟังก์ชั่น แต่เป็นข้อเสียของเครื่องสำอาง
  • รายการแอปพลิเคชันในไอคอนตัวเรียกใช้งานจะใช้เวลาอัปเดต 1-2 วินาทีหลังจากรายการแอปพลิเคชันที่รันอยู่เปลี่ยนแปลง

นอกจากนี้การตั้งค่ามีความซับซ้อนเล็กน้อย (แม้ว่าจะอธิบายรายละเอียดด้านล่าง)

วิธีใช้

ด้านล่างคุณจะพบกับ:

สองสคริปต์ / ไอคอน / .desktopไฟล์

  1. เตรียมการตั้งค่าเช่นเดียวกับใน "วิธีใช้" ให้บันทึกสคริปต์ (main-) ตัวแรกเช่นเดียวกับraise_appใน~/bin
  2. บันทึกไอคอนด้านล่าง (คลิกขวา, บันทึกเป็น) เป็น raise.png

    <ไอคอน>

  3. คัดลอก.desktopไฟล์ลงในไฟล์ว่างแก้ไขบรรทัด

        Icon=/path/to/raise.png
    

    ไปยังเส้นทางที่แท้จริงไปที่ไอคอน (เส้นทางที่มีช่องว่างระหว่างเครื่องหมายคำพูด)
    บันทึกเป็นraise.desktopใน~/.local/share/applications

  4. ลาก.desktopไฟล์ไปที่ตัวเรียกใช้งานเพื่อเพิ่ม

  5. คัดลอกสคริปต์ที่สองวางลงในไฟล์ที่ว่างเปล่าบันทึกเป็นupdate_appsใน~/binให้มันปฏิบัติการ
  6. เพิ่มคำสั่งต่อไปนี้ไปยังแอปพลิเคชันเริ่มต้นของคุณ (Dash> แอปพลิเคชันเริ่มต้น> เพิ่ม):

    update_apps
    
  7. ออกจากระบบและกลับเข้ามาใหม่เพื่อให้ใช้งานได้

สคริปต์แรก

#!/usr/bin/env python3
import subprocess
import getpass
import sys

arg = sys.argv[1]

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

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

สคริปต์ที่สอง

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

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

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

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

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

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

ไฟล์ .desktop

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

Actions=



คำอธิบายสั้น ๆ

โซลูชันทั้งหมดข้างต้นใช้wmctrlเพื่อสร้างรายการหน้าต่างโดยใช้wmctrl -lpGคำสั่ง คำสั่งนี้สร้างบรรทัดที่มีลักษณะดังนี้:

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

บรรทัดเหล่านี้รวมถึง:

  • คอลัมน์ที่ 1: รหัสของหน้าต่าง (ที่เราสามารถใช้ยกมัน)
  • คอลัมน์ที่ 3: pid ที่เป็นเจ้าของหน้าต่าง
  • คอลัมน์ที่ 4 / 5th: เรขาคณิตของหน้าต่าง xy (ที่เราใช้เพื่อดูว่าหน้าต่างอยู่ในวิวพอร์ตปัจจุบันหรือไม่xrandr)

pid ถูกค้นหาในเอาต์พุตของps -u <username>เพื่อรับการระบุ "ชื่อผู้ใช้" (ชื่อ) ของแอปพลิเคชัน
ดังนั้นเราสามารถจัดสรร windows ให้กับแอปพลิเคชัน ต่อจากนั้นเราสามารถเพิ่มหน้าต่างของโปรแกรมที่กำหนดในวงที่มีคำสั่งforwmctrl -ia

ในตัวเลือก 3
สคริปต์เริ่มการวนรอบ "รอ" ที่ 3 วินาทีโดยใช้xprop -rootคำสั่งซ้ำ ๆ เพื่อดูว่ามีการเปลี่ยนแปลงใด ๆ ในหน้าต่างที่อยู่ข้างหน้าหรือไม่ สิ่งนี้จะเกิดขึ้นหากผู้ใช้คลิกที่ไอคอนตัวเรียกใช้เพื่อยกระดับหน้าต่างแอปพลิเคชันหรือคลิกที่หน้าต่างโดยตรง ถ้าเป็นเช่นนั้น while-loop จะแบ่งและค้นหาแอพพลิเคชั่นส่วนหน้า "ใหม่" และจากนั้นจะเพิ่มหน้าต่างอื่น ๆ ทั้งหมดของแอปพลิเคชันนั้น


ฉันเห็นด้วยและขอขอบคุณอีกครั้งสำหรับความพยายามของคุณ! :) || มีเรื่องแปลกประหลาดที่ฉันไม่ได้สังเกตมาก่อน บางครั้งหลังจากใช้Option 2สคริปต์เมื่อมีการโฟกัสหน้าต่างแอปพลิเคชัน (ที่ไม่ขยายใหญ่สุด) และฉันคลิกที่หน้าต่างอื่นที่มองเห็น "ด้านล่าง" แอปพลิเคชันด้านล่างไม่ได้รับโฟกัส
Joschua

@Joschua OP ของคำถามนี้: askubuntu.com/questions/575830/…ได้พบกับข้อผิดพลาดที่ได้รับการแนะนำในการอัปเดต "คุณสมบัติ" ล่าสุด True / False ถูกผสมกันทำให้สคริปต์ทำงานผิดพลาดเมื่อไม่มีแอปพลิเคชันมากกว่าหนึ่งหน้าต่าง หากคุณใช้ตัวเลือก 2 โปรดอัปเดตเป็นเวอร์ชันล่าสุด
Jacob Vlijm

ตัวเลือก 1 ไม่ทำงานสำหรับฉันบน Ubuntu xenial บางสิ่งบางอย่าง @ บางสิ่ง: ~ / bin $ ./raise_app Gtk- ข้อความ: GtkDialog ที่แมปโดยไม่มีพาเรนต์ชั่วคราว สิ่งนี้เป็นสิ่งที่ท้อแท้ ฉันพยายามเปิดหน้าต่างเทอร์มินัล ไม่มีอะไรเกิดขึ้น.
xtrinch

@Nirri คุณใช้ชื่อแอปพลิเคชันชื่ออะไร ข้อความค่อนข้างปกติหากหน้าต่าง zenity ทำงานโดยไม่มีพาเรนต์ Gtk "หมดกำลังใจ" ไม่ใช่ข้อผิดพลาด
Jacob Vlijm

ตัวอักษรแรกของเทอร์มินัล มันใช้งานได้ - ชนิดของ - มันเพิ่มหน้าต่างของแอพใด ๆ - แต่มีเพียงอันเดียวเท่านั้นที่ไม่ได้เป็นไปตามที่คาดไว้ @ user72216
xtrinch

1

มีSuper+ Wทางลัดซึ่งจะแสดงงานแสดงของหน้าต่างที่เปิดอยู่ทั้งหมดในขณะนั้นซึ่งจะรวมถึงแอปพลิเคชันอื่น ๆ สิ่งนี้เกิดขึ้นตามค่าเริ่มต้นและไม่ต้องการการเปลี่ยนแปลงใด ๆ ดังนั้นจึงอาจเป็นตัวเลือกที่ง่ายที่สุด

เหนือสิ่งอื่นใดคุณสามารถวางตำแหน่งหน้าต่างบนครึ่งทางขวาและซ้ายของหน้าจอด้วยปุ่มCtrl+ Super+ Left/ Rightและสลับระหว่างหน้าต่างเหล่านั้นด้วย Alt + ~ (tilde ซึ่งอยู่ถัดจากปุ่มหมายเลขหนึ่ง)


ที่ไม่ได้นำ windows ทั้งหมดของแอปพลิเคชันขึ้นไปด้านบน คุณสามารถเห็นพวกเขา แต่คุณไม่สามารถใช้พวกเขาโดยไม่ต้องคลิกมาก
Joschua

1

หากคุณกด Alt + Tab เพื่อวนรอบแอปพลิเคชันและคุณไปถึงหน้าต่างที่มีหลายหน้าต่างเพียงกดปุ่ม alt ค้างไว้และหลังจากนั้นประมาณ 1 วินาทีเต็มไอคอนจะถูกแทนที่ด้วยมุมมองของหน้าต่างทั้งหมดสำหรับแอปพลิเคชันนั้น

นั่นอาจจะใช่หรือไม่ใช่สิ่งที่คุณกำลังมองหา แต่มันใช้งานได้ดีสำหรับฉันและมันก็ง่ายกว่ามาก


1
คุณยังสามารถกดปุ่มลูกศรลงเพื่อให้หน้าต่างแอปพลิเคชันปรากฏขึ้นทันที
กริช

1

ฉันใช้สคริปต์การเพิ่มของ _ JacobVlijm และทำการปรับปรุงบางอย่างรวมถึงทำให้แข็งแกร่งขึ้น

โดยเฉพาะฉันพบว่าหลังจากหนึ่งหรือสองวันสคริปต์ของ @ JacobVlijm จะหยุดทำงานและฉันต้องรีสตาร์ทสคริปต์ด้วยตนเองเพื่อให้ทำงานได้อีกครั้ง ในการหวนกลับไปเดาที่ดีที่สุดของฉันคือการโทร xrandr จำนวนมากในที่สุดทำให้เกิดปัญหา

อย่างไรก็ตามฉันปรับรหัสของเขาเพิ่มความถี่การโพลจาก 5 วินาทีเป็นทุกๆ 1 วินาทีเนื่องจากมันไม่ได้ใช้ CPU มาก แต่อย่างใดและทำให้มันแข็งแกร่งขึ้น โดยปกติฉันสามารถใช้งานได้เป็นวัน / สัปดาห์โดยไม่มีปัญหา

ข้อแม้หนึ่งคือฉันเรียก xrandr เพียงครั้งเดียวในระหว่างการเริ่มต้นเพื่อรับขนาดความละเอียดของหน้าจอ ดังนั้นหากคุณเปลี่ยนความละเอียดหน้าจอของคุณ (เช่นจาก 1920x1080 เป็นความละเอียดอื่น ๆ ) คุณอาจต้องรีสตาร์ทแอปพลิเคชันด้วยตนเองเพื่อให้ได้ความละเอียดใหม่ โดยส่วนตัวฉันไม่เคยเปลี่ยนความละเอียดหน้าจอของฉันดังนั้นนี่ไม่ใช่ปัญหาสำหรับฉัน นอกจากนี้ฉันมีเหตุผลที่เชื่อได้ว่าการโทร xrandr มากเกินไปเป็นสาเหตุของสคริปต์เวอร์ชันของ @ JacobVlijm ที่จะหยุดการทำงานหลังจากผ่านไปหนึ่งหรือสองวัน

BTW คุณต้องวางอิมเมจ ra.png ในไดเร็กทอรี / usr / local / icons / หรือถ้าคุณต้องการที่จะนำ Raise.png ในไดเรกทอรีอื่นทำการเปลี่ยนแปลงที่เหมาะสมกับสคริปต์เพื่อให้สคริปต์สามารถค้นหาไฟล์ภาพ

หวังว่า Ubuntu จะรวมฟังก์ชัน 'ยกระดับหน้าต่างทั้งหมด' ในระบบของพวกเขาเร็วกว่านี้ในภายหลังเนื่องจากเป็นประโยชน์อย่างมาก:

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

from sys import stderr, exit
import signal
import gi

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

import logging
import logging.handlers

import time
import os
import subprocess
import getpass

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

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

logger.addHandler(log_handler)


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

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

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

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

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

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

        GLib.timeout_add_seconds(1.0, self.check_recent)

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

        self.menu.show_all()
        return self.menu

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

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

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

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

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

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

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

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

        GLib.timeout_add_seconds(1.0, self.check_recent)


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


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

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

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

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


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

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

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

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

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


logger.info("(raise-apps.py is starting up..)")
Indicator()
signal.signal(signal.SIGINT, signal.SIG_DFL)
Gtk.main()
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.