EasyOS 3.4.7 / external monitor / resolution / permanent settings / hot plug
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
used udevadmin and followed hints e.g. at <https://linuxconfig.org/tutorial-on-how ... s-in-linux>
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
.
.