ฉันจะจัดกลุ่ม windows ให้เป็นหนึ่งเดียวได้อย่างไร


10

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

ฉันเข้าใจว่าการใช้เวิร์กสเปซหลายตัวเป็นทางเลือกอื่น แต่สงสัยว่ามันจะเป็นไปได้ไหม


การสั่งซื้อ z นั้นไม่สำคัญอย่างยิ่ง แต่ถ้าเป็นไปได้มันจะยิ่งใหญ่ขึ้น
ไซมอนตง

ฉันคิดว่าสถานที่ทำงานหลายแห่งเป็นทางออกที่ง่ายที่สุด คุณรู้จักการผสมผสานที่สำคัญสำหรับการสลับระหว่างกันหรือไม่
thomasrutter

1
คุณเป็นผู้ยอมรับอย่างรวดเร็ว :) อย่างไรก็ตามจะขอบคุณถ้าคุณให้ความเห็นเกี่ยวกับคำตอบของฉัน
Jacob Vlijm

5
มีความซ้ำซ้อนของWindow 'grouping' หรือไม่

คำตอบ:


9

บทนำ

สคริปต์ต่อไปนี้อนุญาตให้เลือกสองหน้าต่างและในขณะที่หน้าต่างทั้งสองเปิดอยู่จะเพิ่มหน้าต่างทั้งสองเมื่อผู้ใช้ทำการโฟกัส ตัวอย่างเช่นหากมีลิงค์ม่าย A และ B การสลับไปที่ A หรือ B จะทำให้ทั้งคู่เพิ่มขึ้นเหนือหญิงม่ายคนอื่น

หากต้องการหยุดสคริปต์คุณสามารถใช้killall link_windows.pyในเทอร์มินัลหรือปิดและเปิดหน้าต่างใหม่อีกครั้ง นอกจากนี้คุณยังสามารถยกเลิกการดำเนินการได้โดยการกดปุ่มปิดXบนกล่องโต้ตอบป็อปอัพการเลือกหน้าต่าง

การปรับแต่งที่มีศักยภาพ:

  • สามารถใช้สคริปต์หลายอินสแตนซ์กับกลุ่มคู่ของหน้าต่างสองบาน ตัวอย่างเช่นถ้าเรามี windows A, B, C และ D เราสามารถเชื่อมโยง A และ B เข้าด้วยกันและเชื่อมโยง C และ D เข้าด้วยกัน
  • สามารถจัดกลุ่มหลายหน้าต่างได้ภายใต้หน้าต่างเดียว ตัวอย่างเช่นถ้าฉันเชื่อมโยงหน้าต่าง B กับ A, C ถึง A และ D กับ A นั่นหมายความว่าถ้าฉันสลับไปที่ A เสมอฉันสามารถยกทั้ง 4 windows ได้ในเวลาเดียวกัน

การใช้

เรียกใช้สคริปต์เป็น:

python link_windows.py

สคริปต์เข้ากันได้กับ Python 3 ดังนั้นจึงสามารถเรียกใช้เป็น

python3 link_windows.py

มีสองตัวเลือกบรรทัดคำสั่ง:

  • --quietหรือ-qอนุญาตให้ปิดเสียงหน้าต่าง GUI ได้ ด้วยตัวเลือกนี้คุณสามารถคลิกด้วยเมาส์บนสองหน้าต่างและสคริปต์จะเริ่มเชื่อมโยงหน้าต่างเหล่านั้น
  • --helpหรือ-hพิมพ์ข้อมูลการใช้งานและคำอธิบาย

-hตัวเลือกผลิตข้อมูลต่อไปนี้:

$ python3 link_windows.py  -h                                                                                            
usage: link_windows.py [-h] [--quiet]

Linker for two X11 windows.Allows raising two user selected windows together

optional arguments:
  -h, --help  show this help message and exit
  -q, --quiet  Blocks GUI dialogs.

สามารถดูข้อมูลทางเทคนิคเพิ่มเติมผ่านทางpydoc ./link_windows.pyซึ่ง./หมายความว่าคุณจะต้องอยู่ในไดเรกทอรีเดียวกับสคริปต์

กระบวนการใช้งานที่ง่ายสำหรับสองหน้าต่าง:

  1. ป๊อปอัพจะปรากฏขอให้คุณเลือกหน้าต่าง # 1 กดหรือตีOK Enterตัวชี้เมาส์จะเปลี่ยนเป็นกากบาท คลิกที่หนึ่งในหน้าต่างที่คุณต้องการเชื่อมโยง

  2. ป๊อปอัพที่สองจะปรากฏขอให้คุณเลือกหน้าต่าง # 2 กดหรือตีOK Enterตัวชี้เมาส์จะกลายเป็นกากบาทคลิกบนหน้าต่างอื่นที่คุณต้องการเชื่อมโยง หลังจากนั้นการประหารจะเริ่มต้นขึ้น

  3. เมื่อใดก็ตามที่คุณโฟกัสหน้าต่างใดหน้าต่างหนึ่งสคริปต์จะยกหน้าต่างอื่นขึ้น แต่กลับโฟกัสไปที่หน้าต่างที่เลือกไว้เดิม (หมายเหตุ - ด้วยการหน่วงเวลาหนึ่งในสี่วินาทีเพื่อประสิทธิภาพที่ดีที่สุด) ดังนั้นการสร้างความรู้สึกว่าหน้าต่างเชื่อมโยงกัน

หากคุณเลือกหน้าต่างเดียวกันทั้งสองครั้งสคริปต์จะหยุดทำงาน หากในขณะใดก็ตามที่คุณคลิกปุ่มปิดของกล่องโต้ตอบป๊อปอัพสคริปต์จะหยุดทำงาน

แหล่งสคริปต์

นอกจากนี้ยังมีเป็นGitHub Gist

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Author: Sergiy Kolodyazhnyy
Date:  August 2nd, 2016
Written for: https://askubuntu.com/q/805515/295286
Tested on Ubuntu 16.04 LTS
"""
import gi
gi.require_version('Gdk', '3.0')
gi.require_version('Gtk', '3.0')
from gi.repository import Gdk, Gtk
import time
import subprocess
import sys
import argparse


def run_cmd(cmdlist):
    """ Reusable function for running shell commands"""
    try:
        stdout = subprocess.check_output(cmdlist)
    except subprocess.CalledProcessError:
        sys.exit(1)
    else:
        if stdout:
            return stdout


def focus_windows_in_order(first, second, scr):
    """Raise two user-defined windows above others.
       Takes two XID integers and screen object.
       Window with first XID will have the focus"""

    first_obj = None
    second_obj = None

    for window in scr.get_window_stack():
        if window.get_xid() == first:
            first_obj = window
        if window.get_xid() == second:
            second_obj = window

    # When this  function is called first_obj is alread
    # raised. Therefore we must raise second one, and switch
    # back to first
    second_obj.focus(int(time.time()))
    second_obj.get_update_area()
    # time.sleep(0.25)
    first_obj.focus(int(time.time()))
    first_obj.get_update_area()


def get_user_window():
    """Select two windows via mouse. Returns integer value of window's id"""
    window_id = None
    while not window_id:
        for line in run_cmd(['xwininfo', '-int']).decode().split('\n'):
            if 'Window id:' in line:
                window_id = line.split()[3]
    return int(window_id)


def main():
    """ Main function. This is where polling for window stack is done"""

    # Parse command line arguments
    arg_parser = argparse.ArgumentParser(
        description="""Linker for two X11 windows.Allows raising """ +
                    """two user selected windows together""")
    arg_parser.add_argument(
                '-q','--quiet', action='store_true',
                help='Blocks GUI dialogs.',
                required=False)
    args = arg_parser.parse_args()

    # Obtain list of two user windows
    user_windows = [None, None]
    if not args.quiet:
        run_cmd(['zenity', '--info', '--text="select first window"'])
    user_windows[0] = get_user_window()
    if not args.quiet:
        run_cmd(['zenity', '--info', '--text="select second window"'])
    user_windows[1] = get_user_window()

    if user_windows[0] == user_windows[1]:
        run_cmd(
            ['zenity', '--error', '--text="Same window selected. Exiting"'])
        sys.exit(1)

    screen = Gdk.Screen.get_default()
    flag = False

    # begin watching for changes in window stack
    while True:

        window_stack = [window.get_xid()
                        for window in screen.get_window_stack()]

        if user_windows[0] in window_stack and user_windows[1] in window_stack:

            active_xid = screen.get_active_window().get_xid()
            if active_xid not in user_windows:
                flag = True

            if flag and active_xid == user_windows[0]:
                focus_windows_in_order(
                    user_windows[0], user_windows[1], screen)
                flag = False

            elif flag and active_xid == user_windows[1]:
                focus_windows_in_order(
                    user_windows[1], user_windows[0], screen)
                flag = False

        else:
            break

        time.sleep(0.15)


if __name__ == "__main__":
    main()

หมายเหตุ:


ไชโยฉันประทับใจจริงๆ time.sleepบิตระหว่างเปลี่ยนฉันสามารถที่จะนำที่จะเป็นศูนย์? มีเหตุผลสำหรับความล่าช้าหรือไม่
Simon ตอง

1
@simontong คุณสามารถลองคอมเม้นท์ในบรรทัด# time.sleep(0.25)นั้นได้ สาเหตุที่ทำให้แน่ใจว่าแต่ละหน้าต่างได้รับการยกอย่างเหมาะสม จากประสบการณ์ของฉันในอดีตฉันจำเป็นต้องมีความล่าช้าในการใช้งานบน windows ฉันคิดว่าความล่าช้าในไตรมาสสองนั้นไม่มาก ที่จริงฉันขอเพิ่มอีกหนึ่งบรรทัดในสคริปต์ที่สามารถเพิ่มความเร็วได้ ตกลง ?
Sergiy Kolodyazhnyy

@simontong ตกลงฉันได้อัปเดตสคริปต์แล้ว ลองเลย ควรมีการสลับที่เร็วขึ้น
Sergiy Kolodyazhnyy

@simontong ฉันจะปรับปรุงสคริปต์ด้วยการเพิ่มเล็กน้อยเพื่อเพิ่มคุณสมบัติพิเศษบางอย่าง ฉันจะแจ้งให้คุณทราบเมื่อมันพร้อมแล้วโปรดแจ้งให้เราทราบว่าคุณคิดอย่างไร
Sergiy Kolodyazhnyy

@simontong เพิ่มตัวเลือกพิเศษให้กับสคริปต์โปรดตรวจสอบ
Sergiy Kolodyazhnyy

6

เพิ่มจำนวนหน้าต่างโดยพลการเป็นหนึ่ง

วิธีการแก้ปัญหาด้านล่างจะช่วยให้คุณเลือกการรวมกันของสอง, สามหรือมากกว่าหน้าต่างเพื่อรวมและยกระดับเป็นหนึ่งเดียวกับแป้นพิมพ์ลัด

สคริปต์ทำงานกับอาร์กิวเมนต์สามตัว:

add

เพื่อเพิ่มหน้าต่างที่ใช้งานอยู่ในกลุ่ม

raise

เพื่อยกกลุ่มชุด

clear

เพื่อล้างกลุ่มพร้อมที่จะกำหนดกลุ่มใหม่

สคริปต์

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

wlist = os.path.join(os.environ["HOME"], ".windowlist")

arg = sys.argv[1]

if arg == "add":
    active = subprocess.check_output([
        "xdotool", "getactivewindow"
        ]).decode("utf-8").strip()
    try:
        currlist = open(wlist).read()
    except FileNotFoundError:
        currlist = []
    if not active in currlist:
        open(wlist, "a").write(active + "\n")
elif arg == "raise":
    group = [w.strip() for w in open(wlist).readlines()]
    [subprocess.call(["wmctrl", "-ia", w]) for w in group]
elif arg == "clear":
    os.remove(wlist)

วิธีใช้

  1. สคริปต์ต้องการwmctrlและxdotool:

    sudo apt-get install wmctrl xdotool
  2. คัดลอกสคริปต์ด้านบนลงในไฟล์เปล่าแล้วบันทึกเป็น groupwindows.py
  3. ทดสอบรันสคริปต์: เปิดหน้าต่างเทอร์มินัลสองหน้าต่างเรียกใช้คำสั่ง:

    python3 /absolute/path/to/groupwindows.py add

    ในทั้งคู่ คลุมด้วยหน้าต่างอื่น ๆ (หรือย่อให้เล็กสุด) เปิดหน้าต่างเทอร์มินัลที่สามเรียกใช้คำสั่ง:

    python3 /absolute/path/to/groupwindows.py raise

    สองหน้าต่างแรกจะถูกยกขึ้นเป็นหนึ่ง

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

    ในระบบของฉันฉันใช้:

    Alt+ A, เรียกใช้คำสั่ง:

    python3 /absolute/path/to/groupwindows.py add

    ... เพื่อเพิ่มหน้าต่างในกลุ่ม

    Alt+ R, เรียกใช้คำสั่ง:

    python3 /absolute/path/to/groupwindows.py raise

    ... เพื่อยกระดับกลุ่ม

    Alt+ C, เรียกใช้คำสั่ง:

    python3 /absolute/path/to/groupwindows.py clear

    ... เพื่อล้างกลุ่ม

คำอธิบาย

สคริปต์ทำงานค่อนข้างง่าย:

  • เมื่อรันด้วยอาร์กิวเมนต์addสคริปต์จะจัดเก็บ / เพิ่มหน้าต่างของหน้าต่างที่ใช้งานอยู่ในไฟล์ที่ซ่อน~/.windowlist
  • เมื่อรันด้วยอาร์กิวเมนต์raiseสคริปต์จะอ่านไฟล์ยกหน้าต่างขึ้นในรายการด้วยคำสั่ง:

    wmctrl -ia <window_id>
  • เมื่อทำงานกับอาร์กิวเมนต์สคริปต์เอาไฟล์ที่ซ่อนอยู่clear~/.windowlist

หมายเหตุ

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

ความยืดหยุ่นมากขึ้น?

ตามที่กล่าวไว้สคริปต์ด้านบนอนุญาตให้เพิ่มหน้าต่างได้ตลอดเวลาในหน้าต่างที่จัดกลุ่ม รุ่นด้านล่างนี้ยังอนุญาตให้ลบหน้าต่างใด ๆ (ตลอดเวลา) ออกจากรายการที่จัดกลุ่ม:

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

wlist = os.path.join(os.environ["HOME"], ".windowlist")
arg = sys.argv[1]
# add windows to the group
if arg == "add":
    active = subprocess.check_output([
        "xdotool", "getactivewindow"
        ]).decode("utf-8").strip()
    try:
        currlist = open(wlist).read()
    except FileNotFoundError:
        currlist = []
    if not active in currlist:
        open(wlist, "a").write(active + "\n")
# delete window from the group
if arg == "delete":
    try:
        currlist = [w.strip() for w in open(wlist).readlines()]
    except FileNotFoundError:
        pass
    else:
        currlist.remove(subprocess.check_output([
            "xdotool", "getactivewindow"]).decode("utf-8").strip())      
        open(wlist, "w").write("\n".join(currlist)+"\n")
# raise the grouped windows
elif arg == "raise":
    group = [w.strip() for w in open(wlist).readlines()]
    [subprocess.call(["wmctrl", "-ia", w]) for w in group]
# clear the grouped window list
elif arg == "clear":
    os.remove(wlist)

อาร์กิวเมนต์เพิ่มเติมในการเรียกใช้สคริปต์คือdelete:

python3 /absolute/path/to/groupwindows.py delete

ลบหน้าต่างที่ใช้งานอยู่ออกจากหน้าต่างที่จัดกลุ่มไว้ ในการเรียกใช้คำสั่งนี้ในระบบของฉันฉันตั้งค่าAlt+ Dเป็นทางลัด

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.