Last active
August 19, 2024 16:21
-
-
Save SergKolo/88ad3372d0a1aec47dcfd9d9780d67cc to your computer and use it in GitHub Desktop.
A script that allows linking two windows together such that switching focus on one, brings up the other as well
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
""" | |
Author: Sergiy Kolodyazhnyy | |
Date: August 2nd, 2016 | |
Written for: http://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( | |
'--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() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I'm very astonished. Thank you, but this only works on X11 right, does it work on Wayland?