fvwmorg/fvwm3

Disabling/enabling monitor does not call RandRFunc

Closed this issue · 8 comments

Upfront Information

  • Fvwm3 version: fvwm3 1.0.7 (1.0.6a-8-g2327aac1)

  • Linux distribution or BSD name/version: Debian 11.6 Bullseye

  • Platform (run: uname -sp): Linux unknown

Expected Behaviour

I expected RandRFunc to trigger when connecting/disconnecting a monitor. Basically on xrandr --output HDMI-1 --off and xrandr --output HDMI-1 --auto.

Actual Behaviour

The RandRFunc is not triggered.

FvwmEvent's monitor_enabled/monitor_enabled functions are also not triggered.

RandRFunc is called correctly on resolution and position change (for example xrandr --output HDMI-1 --right-of DP-1)

Steps to Reproduce

I'm using this minimal configuration file:

BugOpts DebugRandR true

DestroyFunc RandRFunc
AddToFunc   RandRFunc
+ I Echo "randrfunc called"

Then executing xrandr --output HDMI-1 --auto followed by xrandr --output HDMI-1 --off gives the following output in the log, but "randrfunc called" is not logged.

[1676715323.394479] monitor_output_change: monitor_output_change: outputs have changed
[1676715323.397734] monitor_update_ewmh: monitor debug...
[1676715323.397788] monitor_dump_state: Monitor Debug
[1676715323.397808] monitor_dump_state:         number of outputs: 2
[1676715323.397833] monitor_dump_state:         Name:   DP-1
        Disabled:       false
        Is Primary:     yes
        Is Current:     yes
        Is Previous:    yes
        Output: 68
        Coords: {x: 0, y: 0, w: 2560, h: 1440}
        VirtScr: {
                VxMax: 0, VyMax: 0, Vx: 0, Vy: 0
                EdgeScrollX: 0, EdgeScrollY: 0
                CurrentDesk: 0
                CurrentPage: {x: 0, y: 0}
                MyDisplayWidth: 2560, MyDisplayHeight: 1440
        }
        Desktops:       yes
        Flags:global

[1676715323.397884] monitor_dump_state:         Name:   HDMI-1
        Disabled:       false
        Is Primary:     no
        Is Current:     no
        Is Previous:    no
        Output: 71
        Coords: {x: 0, y: 0, w: 1920, h: 1080}
        VirtScr: {
                VxMax: 0, VyMax: 0, Vx: 0, Vy: 0
                EdgeScrollX: 0, EdgeScrollY: 0
                CurrentDesk: 0
                CurrentPage: {x: 0, y: 0}
                MyDisplayWidth: 2560, MyDisplayHeight: 1440
        }
        Desktops:       yes
        Flags:global

[1676715323.417977] ewmh_ComputeAndSetWorkArea: monitor 'DP-1': {l: 0, r: 0, t: 0, b: 0} {x: 0, y: 0, w: 2560, h: 1440}
[1676715323.419066] ewmh_ComputeAndSetWorkArea: monitor 'HDMI-1': {l: 0, r: 0, t: 0, b: 0} {x: 0, y: 0, w: 1920, h: 1080}
[1676715329.950613] monitor_output_change: monitor_output_change: outputs have changed
[1676715329.954508] monitor_update_ewmh: monitor debug...
[1676715329.954562] monitor_dump_state: Monitor Debug
[1676715329.954579] monitor_dump_state:         number of outputs: 2
[1676715329.954593] monitor_dump_state:         Name:   DP-1
        Disabled:       false
        Is Primary:     yes
        Is Current:     yes
        Is Previous:    yes
        Output: 68
        Coords: {x: 0, y: 0, w: 2560, h: 1440}
        VirtScr: {
                VxMax: 0, VyMax: 0, Vx: 0, Vy: 0
                EdgeScrollX: 0, EdgeScrollY: 0
                CurrentDesk: 0
                CurrentPage: {x: 0, y: 0}
                MyDisplayWidth: 2560, MyDisplayHeight: 1440
        }
        Desktops:       yes
        Flags:global

[1676715329.954656] monitor_dump_state:         Name:   HDMI-1
        Disabled:       false
        Is Primary:     no
        Is Current:     no
        Is Previous:    no
        Output: 71
        Coords: {x: 0, y: 0, w: 1920, h: 1080}
        VirtScr: {
                VxMax: 0, VyMax: 0, Vx: 0, Vy: 0
                EdgeScrollX: 0, EdgeScrollY: 0
                CurrentDesk: 0
                CurrentPage: {x: 0, y: 0}
                MyDisplayWidth: 2560, MyDisplayHeight: 1440
        }
        Desktops:       yes
        Flags:global

[1676715329.956858] ewmh_ComputeAndSetWorkArea: monitor 'DP-1': {l: 0, r: 0, t: 0, b: 0} {x: 0, y: 0, w: 2560, h: 1440}
[1676715329.957642] ewmh_ComputeAndSetWorkArea: monitor 'HDMI-1': {l: 0, r: 0, t: 0, b: 0} {x: 0, y: 0, w: 1920, h: 1080}

@entropic77

Yes. I'm sure when I last looked into this, using xrandr --off isn't the same thing as yanking an HDMI cable out the back of the monitor...

Ah, ok. I was trying to debug a multimonitor-problem and thought it would be easier to run an xrandr-command than to reach under the table to yank the cable.

After actually trying to unplug/replug the cable I should maybe describe the original problem I had:

The problem I'm trying to solve is to automatically move FvwmButtons to the currently primary monitor.

  • If the external monitor is not plugged in, the laptop's monitor is primary
  • If the external monitor is plugged in, this monitor is primary

I'm using autorandr to reconfigure which monitor is primary, based on if the external monitor is plugged in or not.

So in summary the actual issue is that RandRFunc is not called when autorandr reconfigures the screens, including changing the primary screen. So if fvwm can't do this I might have to find another way. Or perhaps functionality to detect randr's changing of primary screen could be implemented in fvwm somehow?

I'll look into it.

@entropic77

Have a look at the ta/add-prev-primary branch, which now introduces a new variable $[monitor.prev_primary] which you can use to ascertain the name of a previous monitor which was marked as primary. Hence:

DestroyFunc RandRFunc
DestroyFunc RandRFunc
+ I Echo "Primary is: $[monitor.primary], previous: $[monitor.prev_primary]"

To your earlier observations, I was remembering correctly. If you use xrandr to turn off one of your monitors, have a look at the output from xrandr -- it will still show as connected.

Your patch works fine when executing the xrandr-commands manually. But annoyingly enough not when letting autorandr handle the monitors.

I think I traced autorandr's behaviour to the following. At least I get the same end result:

(HDMI-1 is my external monitor and DP-1 internal)

  • connect cable
  • xrandr --output HDMI-1 --right-of DP-1 --primary --auto
  • disconnect cable
  • xrandr --output HDMI-1 --off I think this is the culprit
  • xrandr --output DP-1 --primary

End result: RandrFunc is not called when setting primary in the last step. Maybe because the HDMI monitor has been turned off and fvwm cannot keep track of it anymore?

These steps works as expected. And will cause RandRFunc to be called when setting primary:

  • connect cable
  • xrandr --output HDMI-1 --right-of DP-1 --primary --auto
  • disconnect cable
  • xrandr --output DP-1 --primary

End result: RandrFunc is not called when setting primary in the last step. Maybe because the HDMI monitor has been turned off and fvwm cannot keep track of it anymore?

Yup.

Ok, but how about ignoring which other monitor was primary, and just check if the monitor in question was not primary. Like this:

diff --git a/fvwm/events.c b/fvwm/events.c
index 1ae159fa..10218213 100644
--- a/fvwm/events.c
+++ b/fvwm/events.c
@@ -1855,12 +1855,7 @@ monitor_emit_broadcast(void)
 		}
 
 		if (m->flags & MONITOR_PRIMARY) {
-			struct monitor *pm = m, *mnew;
-
-			if ((mnew = monitor_by_last_primary()) == NULL)
-				break;
-
-			if (pm != mnew) {
+			if (m->flags & MONITOR_PRIMARY && !m->was_primary) {
 				execute_function_override_window(
 				    NULL, NULL, randrfunc, NULL, 0, NULL);
 			}

@entropic77

Perhaps. This is already an ugly hack as it is. At least my version mirrors other variables where there's a previous state.