Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python3
- import sys
- import subprocess
- import shutil
- import time
- # Validate required tools
- required_tools = ["xprop", "xdpyinfo", "xdotool", "wmctrl"]
- for tool in required_tools:
- if not shutil.which(tool):
- print(f"Error: {tool} is not installed.")
- sys.exit(1)
- def validate_percentage(value, name):
- if value < 0 or value > 100:
- print(f"Error: {name} must be between 0 and 100.")
- sys.exit(1)
- if len(sys.argv) < 5:
- print("Usage: tiling.py <width%> <height%> <x_offset%> <y_offset%>")
- sys.exit(1)
- width_percent = int(sys.argv[1])
- height_percent = int(sys.argv[2])
- x_offset_percent = int(sys.argv[3])
- y_offset_percent = int(sys.argv[4])
- # Validate percentages
- validate_percentage(width_percent, "Width")
- validate_percentage(height_percent, "Height")
- validate_percentage(x_offset_percent, "X Offset")
- validate_percentage(y_offset_percent, "Y Offset")
- # Buffer for window decorations (px)
- BUFFER_W = 10
- BUFFER_H = 33 # Default buffer height for titlebars etc.
- def get_workarea():
- try:
- xprop_output = subprocess.check_output(["xprop", "-root", "_NET_WORKAREA"]).decode()
- parts_all = xprop_output.split('=')[1].strip().split(',')
- workarea_values = [part.strip() for part in parts_all[:4]]
- if len(workarea_values) == 4:
- x, y, w, h = map(int, workarea_values)
- return x, y, w, h
- else:
- raise ValueError("Could not parse _NET_WORKAREA with 4 values.")
- except Exception:
- screen_info = subprocess.check_output(["xdpyinfo"]).decode()
- for line in screen_info.splitlines():
- if "dimensions:" in line:
- dims = line.strip().split()[1]
- w, h = map(int, dims.split("x"))
- return 0, 0, w, h
- def get_window_class(win_id):
- try:
- output = subprocess.check_output(["xprop", "-id", win_id, "WM_CLASS"]).decode().strip()
- if "WM_CLASS(STRING) = " in output:
- class_str = output.split("= ")[1].strip().replace('"', '')
- return class_str.split(', ')[1] # Usually app name is in second part
- return None
- except subprocess.CalledProcessError:
- return None
- def is_maximized(win_id):
- try:
- xprop_output = subprocess.check_output(["xprop", "-id", win_id, "_NET_WM_STATE"]).decode()
- return ("_NET_WM_STATE_MAXIMIZED_VERT" in xprop_output or
- "_NET_WM_STATE_MAXIMIZED_HORZ" in xprop_output)
- except subprocess.CalledProcessError:
- return False
- def unmaximize_window(win_id):
- print("Attempting to unmaximize window.")
- # Method 1: Try unmaximize using keyboard shortcut (works in XFCE, etc)
- subprocess.call(["xdotool", "key", "alt+F10"])
- time.sleep(0.2)
- # Method 2: Use wmctrl to remove maximized state
- subprocess.call(["wmctrl", "-ir", win_id, "-b", "remove,maximized_vert,maximized_horz"])
- time.sleep(0.2)
- # Get active window ID
- try:
- win_id = subprocess.check_output(["xdotool", "getactivewindow"]).decode().strip()
- except subprocess.CalledProcessError:
- print("Error: Could not retrieve active window ID.")
- sys.exit(1)
- app_class = get_window_class(win_id)
- print(f"Window class: {app_class}")
- # Check if the window is maximized and unmaximize if it is
- if is_maximized(win_id):
- unmaximize_window(win_id)
- # Get workarea dimensions
- work_x, work_y, work_w, work_h = get_workarea()
- # Calculate target size and position
- width = max(1, work_w * width_percent // 100 - BUFFER_W)
- if x_offset_percent == 0 and app_class in ["Brave-browser", "Google-chrome"]:
- width = max(1, int(work_w * (width_percent + 0.5) // 100) - BUFFER_W)
- height = work_h * height_percent // 100
- if app_class not in ["Brave-browser", "Google-chrome"]:
- height -= BUFFER_H
- height = max(1, height)
- x = work_x + (work_w * x_offset_percent // 100)
- y = work_y + (work_h * y_offset_percent // 100)
- print(f"Target width: {width}, height: {height}, x: {x}, y: {y}")
- # Move and resize the window
- subprocess.call(["xdotool", "windowmove", win_id, str(x), str(y)])
- subprocess.call(["xdotool", "windowsize", win_id, str(width), str(height)])
- print("Window moved and resized.")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement