diff --git a/rotate-display-wayland.py b/rotate-display-wayland.py new file mode 100644 index 0000000..a591708 --- /dev/null +++ b/rotate-display-wayland.py @@ -0,0 +1,86 @@ +#!/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()