Files
ha-kiosk-dashboard/rotate-display-wayland.py
2025-12-31 04:26:53 -08:00

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()