87 lines
3.2 KiB
Python
87 lines
3.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Rotate display using GNOME Mutter DisplayConfig API (Wayland)"""
|
|
import sys
|
|
from gi.repository import Gio, GLib
|
|
|
|
def rotate_display():
|
|
bus = Gio.bus_get_sync(Gio.BusType.SESSION, None)
|
|
proxy = Gio.DBusProxy.new_sync(
|
|
bus,
|
|
Gio.DBusProxyFlags.NONE,
|
|
None,
|
|
'org.gnome.Mutter.DisplayConfig',
|
|
'/org/gnome/Mutter/DisplayConfig',
|
|
'org.gnome.Mutter.DisplayConfig',
|
|
None
|
|
)
|
|
|
|
# Get current state
|
|
result = proxy.GetCurrentState()
|
|
serial = result[0]
|
|
monitors = result[1]
|
|
logical_monitors = result[2]
|
|
properties = result[3]
|
|
|
|
print(f"Found {len(logical_monitors)} logical monitor(s)")
|
|
|
|
# Find HDMI-1 and rotate it
|
|
new_logical_monitors = []
|
|
found_hdmi = False
|
|
|
|
for lm in logical_monitors:
|
|
x, y, scale, transform, primary, monitors_list, props = lm
|
|
print(f"Logical monitor: x={x}, y={y}, scale={scale}, transform={transform}, primary={primary}")
|
|
|
|
# Check if this logical monitor contains HDMI-1
|
|
hdmi_in_this_lm = False
|
|
for monitor_info in monitors_list:
|
|
# monitor_info is a tuple: (connector, vendor, product, serial, ...)
|
|
connector = monitor_info[0] if isinstance(monitor_info, tuple) else monitor_info
|
|
print(f" Monitor: {connector}")
|
|
if connector == "HDMI-1":
|
|
hdmi_in_this_lm = True
|
|
found_hdmi = True
|
|
break
|
|
|
|
if hdmi_in_this_lm:
|
|
# Rotate left (90° CCW) = transform 1
|
|
# 0=normal, 1=90° left, 2=180°, 3=270° right
|
|
new_transform = 1 # 90° left (portrait)
|
|
# Ensure monitors_list is a list of tuples (not just a list)
|
|
monitors_tuple_list = tuple(monitors_list) if isinstance(monitors_list, list) else monitors_list
|
|
new_lm = (x, y, scale, new_transform, primary, monitors_tuple_list, props)
|
|
new_logical_monitors.append(new_lm)
|
|
print(f"✓ Rotating HDMI-1 to portrait (90° left, transform={new_transform})")
|
|
else:
|
|
# Keep other monitors unchanged
|
|
new_logical_monitors.append(lm)
|
|
|
|
if not found_hdmi:
|
|
print("Error: HDMI-1 not found in any logical monitor")
|
|
return False
|
|
|
|
if not new_logical_monitors:
|
|
print("Error: No logical monitors to configure")
|
|
return False
|
|
|
|
# Apply the new configuration
|
|
# Method: 1 = logical, 2 = physical
|
|
# The actual structure is: (i, i, d, u, b, a(ssss), a{sv})
|
|
# i=int32 (x), i=int32 (y), d=double (scale), u=uint32 (transform),
|
|
# b=boolean (primary), a(ssss)=array of 4-strings (monitor info), a{sv}=props
|
|
try:
|
|
# Use the exact structure we see from GetCurrentState
|
|
result = proxy.ApplyMonitorsConfig('(uua(iiiduba(ssss)a{sv})a{sv})',
|
|
serial, 1, new_logical_monitors, properties)
|
|
print("✓ Display rotation applied successfully!")
|
|
print("✓ Check your screen - HDMI-1 should now be in portrait mode (90° left)!")
|
|
return True
|
|
except Exception as e:
|
|
print(f"Error: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
return False
|
|
|
|
if __name__ == '__main__':
|
|
rotate_display()
|