Page 1 of 1

EasyOS 3.4.7 / external monitor / resolution / permanent settings / hot plug

Posted: Mon May 30, 2022 1:59 am
by NNI

Most of the time my laptop is connected to a large external display with higher resolution than the internal laptop display. I wanted to have EOS display normally on the internal display, or at higher res on the external display if present, and to have hot plug/unplug work. Working with the ROX desktop, I could not find a solution with xorgwizard, xorg.conf, or Zarfy that would display at correct resolution in either configuration, position icons and taskbar reliably, and remember configuration between reboots. So I bit the bullet and put together a framework that works at least on my Lenovo Thinkpad X1 Carbon gen 6 i7-8550. Maybe with a bit more work from readers it could be further tested and generalized.

6 elements in this setup:
1. added to /root/.xinitrc

  • at the top there is a callout to a new script, /root/.xinitrc-callout

  • further on at #20220208, the invocation of the rox desktop is buffered with 'sleep 1' calls to reduce udev pinging (see below)

2. new script /root/.xinitrc-callout

  • interrogates xrandr and records the connected monitor ports and their native resolutions

  • returns to .xinitrc

3. added to /usr/sbin/delayedrun

  • some code inserted following #20211111

  • activate udev rule detecting changes at monitor port

  • disable X display timeouts with xset s off

4. new rule /etc/udev/rules.d/95-monitor-connect.rules

  • engaged when system detects change on monitor port

  • deactivate/activate by simply renaming from xxx.rules to xxx.bak

  • invokes /root/udev-rox_reset if change on monitor port

5. new script /root/udev-rox-reset

  • responds to monitor port plug/unplug events

  • uses xrandr to turn on/off monitors at native resolution

6. added to /etc/rc.d/rc.shutdown

  • some code inserted just before #100315

  • disable udev rule so no pinging during the next bootup

  • save a copy of the current ROX PuppyPin at current resolution

steps along the way are logged to /root/mon_log

1. top of /root/.xinitrc

Code: Select all

. /etc/rc.d/PUPSTATE

#NNI  --------------------------------------------------
# run xrandr commands here, before ROX-Filer started
/root/.xinitrc-callout
--------------------------------------------------------

2. /root/.xinitrc-callout

Code: Select all

#!/bin/sh
#called from /root/.xinitrc

#allow time to settle before xrandr call
sleep 5

tmp0=$(xrandr |grep -A 1 " connected" |cut -d "("  -f 1 |grep -v "\-\-")
   # executed from shell:
   #   eDP1 connected primary [(normal left .....]            # n.b. res missing!
   #      1920x1080     60.05 +  59.93
   #   HDMI1 connected 2560x1440+0+0 [(normal left .....
   #      2560x1440     59.95*+ 
   #
   # executed within script:
   #   eDP1 connected primary 1920x1080+0+0 [(normal left .....]
   #      1920x1080     60.05*+  59.93  
   #   HDMI1 connected 2560x1440+0+0 [(normal left .....]
   #      2560x1440     59.95*+

tmp1=$(echo "$tmp0" |head -n 1 |cut -d " " -f 1)              #eDP1
tmp2=$(echo "$tmp0" |head -n 1 |cut -d " " -f 3)              #primary
tmp3=$(echo "$tmp0" |head -n 2 |grep "   " |cut -d " " -f 4)  #1920x1080
tmp4=$(echo "$tmp0" |tail -n 2 |cut -d " " -f 1)              #HDMI1
tmp5=$(echo "$tmp0" |tail -n 1 |cut -d " " -f 4)              #2560x1440

#relying on xrandr 2nd line always to indicate native resolution ("+")
#could add grep "+" to actually test for this

if [ "$tmp2" == "primary" ];then
     echo "$tmp1" >/root/primary_mon
     echo "$tmp3" >/root/primary_res	#$tmp13
  else
     echo tmp2 test failed >>/root/mon_log
fi

if [ "$tmp1" != "$tmp4" ]; then
     #primary monitor not the only one connected
     echo "$tmp4" >/root/external_mon
     echo "$tmp5" >/root/external_res
     xrandr --output $tmp1 --off                            # eDP1
     xrandr --output $tmp4 --mode $tmp5 --brightness 0.85   # HDMI1
     echo 1 >/root/state
     echo .xinitrc-callout: external monitor detected: >>/root/mon_log
     echo .xinitrc-callout:   "$tmp1" --off, "$tmp4" --on, state = 1 >>/root/mon_log
  else
     #only the primary monitor is connected
     xrandr --output $tmp1 --mode $tmp3 --brightness 1      # eDP1
     echo 0 >/root/state
     echo .xinitrc-callout: no external monitor detected: >>/root/mon_log
     echo .xinitrc-callout:   "$tmp1" --on, state = 0 >>/root/mon_log
fi

echo ".xinitrc-callout: returning to .xinitrc" >>/root/mon_log

sleep 1

#return to .xinitrc

3. /usr/sbin/delayedrun

Code: Select all

  .
  .
  #20211111 moved up
  if [ -d /root/Startup ];then
   .
   .
  fi

#NNI   ----------------------------------------------------------------------------
  echo "/usr/bin/delayedrun: DELAYFACTOR='$DELAYFACTOR'" >>/root/mon_log

  sleep 3

  if [ -f /etc/udev/rules.d/95-monitor-connect.bak ];then
     #activate udev detection of HDMI connection change
     mv /etc/udev/rules.d/95-monitor-connect.bak /etc/udev/rules.d/95-monitor-connect.rules
     echo "/usr/bin/delayedrun: udev pinging enabled" >>/root/mon_log
  fi
  
  if [ ! -f /tmp/delayedrun_firstboot_flag ];then
    xset s off
    echo "/usr/bin/delayedrun: screen blanking disabled" >>/root/mon_log
    echo "/usr/bin/delayedrun: not first boot, exit" >>/root/mon_log
    exit
  fi
-----------------------------------------------------------------------------------
.
.

4. /etc/udev/rules.d/95-monitor-connect.rules

Code: Select all

#detect removal or insertion of monitor plug

KERNEL=="card0", SUBSYSTEM=="drm", ACTION=="change", ENV{DISPLAY}=":0", ENV{XAUTHORITY}="/root/.Xauthority", RUN+="/root/udev_rox_reset"

5. /root/udev-rox-reset

Code: Select all

#!/bin/sh
#  rearrange desktop to comply with changed monitor output/resolution
#  entry via /etc/udev/rules.d/95-monitor-connect.rules

  curstate="`cat /root/state`"
  prim_mon="`cat /root/primary_mon`"
  prim_res="`cat /root/primary_res`"
  ext_mon="`cat /root/external_mon`"
  ext_res="`cat /root/external_res`"

  echo "udev_rox_reset: state = $curstate" >>/root/mon_log
  sleep 2   #give xrandr enough time between successive calls
  if xrandr | grep $ext_mon" connected"; then
       if [ "$curstate" = "0" ]; then
              #ext monitor was just connected  
              echo 1 >/root/state
              echo udev_rox_reset: "$ext_mon" was just plugged in >>/root/mon_log
              xrandr --output $prim_mon --off --output $ext_mon --mode $ext_res --brightness 0.85
              sleep 2
              rox --pinboard=/root/Choices/ROX-Filer/PuppyPin-external
              echo udev_rox_reset: "$prim_mon" --off, "$ext_mon" --on, state = 1 >>/root/mon_log
              sleep 2
         else
              # state is 1, no change needed
              echo "udev_rox_reset: no monitor change" >>/root/mon_log
              exit
       fi
    else
       # ext monitor is not connected
       if [ "$curstate" = "1" ]; then
              #ext monitor was just unplugged
              echo 0 >/root/state
              echo "udev_rox_reset: "$ext_mon" was just unplugged" >>/root/mon_log
              xrandr --output $ext_mon --off --output $prim_mon --mode $prim_res --brightness 0.9
              sleep 1
              rox --pinboard=/root/Choices/ROX-Filer/PuppyPin-internal
              echo udev_rox_reset: "$prim_mon" --on, "$ext_mon" --off, state = 0 >>/root/mon_log
              sleep 1
         else
              # state is 0, no change needed
              echo "udev_rox_reset: no monitor change" >>/root/mon_log
       fi
  fi

#NOTES
# /sys/devices/pci0000:00/0000:00:02.0/drm/card0/card0-HDMI-A-1/status
# set_bg /usr/share/backgrounds/WhitePuppy.jpg also adjusts
# cat /sys/devices/pci0000:00/0000:00:02.0/drm/card0/card0-HDMI-A-1/status | grep "disconnected"

6. /etc/rc.d/rc.shutdown

Code: Select all

.
.
#NNI  ----------------------------------------------------------
#disable udev ext monitor plug detection through next boot
  if [ -f /etc/udev/rules.d/95-HDMI-connect.rules ];then
     mv /etc/udev/rules.d/95-HDMI-connect.rules /etc/udev/rules.d/95-HDMI-connect.bak
     echo "rc.shutdown: udev pinging blocked" >/root/mon_log
  fi

#copy current PuppyPin to PuppyPin-xxx
  curstate="`cat /root/state`"
  echo rc.shutdown: state = "$curstate" >>/root/mon_log
  if [ "$curstate" = "1" ];then
      cp /root/Choices/ROX-Filer/PuppyPin  /root/Choices/ROX-Filer/PuppyPin-external
    else
     cp /root/Choices/ROX-Filer/PuppyPin  /root/Choices/ROX-Filer/PuppyPin-internal
  fi
  echo rc.shutdown: PuppyPin-(state) copied >>/root/mon_log
-----------------------------------------------------------------

#100315 improper shutdown check
.
.

Re: EasyOS 3.4.7 / external monitor / resolution / permanent settings / hot plug

Posted: Mon May 30, 2022 7:20 am
by user1111

xrandr -s 1440x900

... or whatever works for me (in Fatdog).

That can have the drive icons out of place, one option is to set the taskbar at the top of screen and drive icons placed just below that (near top left). Another is to use a window manager more appropriate for jumping between machines/resolutions - such as cwm.

When I vnc into my server (desktop with 1440x900 screen) from my laptop (1366x768) vnc adjusts the display to a common 1024x768 resolution, so I just run that xrandr -s 1440x900 to reset the server. The laptop then has a panning region where moving the mouse to screen edges pans the 1366x768 within the 1440x900 screen area. Alternatively to that you could also set the laptop to a 1440x900 scaled level so it all fitted.


Re: EasyOS 3.4.7 / external monitor / resolution / permanent settings / hot plug

Posted: Mon May 30, 2022 9:45 am
by BarryK

NNI,
My mind is very much in a different groove right now, will make a note to come back to this thread and topic soon.


Re: EasyOS 3.4.7 / external monitor / resolution / permanent settings / hot plug

Posted: Tue May 31, 2022 2:36 pm
by NNI

Significant bug squash here in the inserted code in rc.shutdown:

Code: Select all

#NNI  ----------------------------------------------------------
#disable udev ext monitor plug detection through next boot
  if [ -f /etc/udev/rules.d/95-monitor-connect.rules ];then
     mv /etc/udev/rules.d/95-monitor-connect.rules /etc/udev/rules.d/95-monitor-connect.bak
     echo "rc.shutdown: udev pinging blocked" >/root/mon_log
  fi
#copy current PuppyPin to PuppyPin-xxx
  curstate="`cat /root/state`"
  echo rc.shutdown: state = "$curstate" >>/root/mon_log
  if [ "$curstate" = "1" ];then
      cp /root/Choices/ROX-Filer/PuppyPin  /root/Choices/ROX-Filer/PuppyPin-external
    else
      cp /root/Choices/ROX-Filer/PuppyPin  /root/Choices/ROX-Filer/PuppyPin-internal
  fi
  echo rc.shutdown: PuppyPin-(state) copied >>/root/mon_log
-----------------------------------------------------------------