You are not logged in.
Hi there,
For quite a while, I've been trying to get a udev-rule running, which checks if I plugged in my notebook to my monitor via a TB3-cable.
I've studied following post: https://bbs.archlinux.org/viewtopic.php … 5#p1329375 but didn't get a working solution ready.
My goal is, to automatically set the resolution of the monitor to 5K, since it's a 5K monitor, by default it's set to 2.5K.
Right now, my script looks like this:
#!/bin/sh
export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$(id -u)/bus"
export DISPLAY=:0
export XAUTHORITY=/home/$(who | grep tty | awk '{print $1}')/.Xauthority
sleep 1
function connect {
OUTPUT=$(gnome-randr | grep DELL | head -n1 | cut -c2- | awk '{print $1}')
echo $OUTPUT | systemd-cat -p emerg
}
function disconnect {
echo "Monitor unplugged" | systemd-cat -p emerg
}
xrandr | grep "930mm x 390mm" &> /dev/null && connect || disconnectSince I use wayland as my compositor, the .Xauthority file seems to be non-existent.
My udev-rule looks like this:
KERNEL=="card0", SUBSYSTEM=="drm", ENV{DISPLAY}=":0", RUN+="/usr/bin/hotplug_monitor.sh"As you can see, I print the "Monitor unplugged" via systemd-cat, to check if the script is even being executed, which happens.
The problem however is, when I connect to my monitor, it prints "Monitor unplugged", which is obviously not true.
The `xrandr | grep "930mm x 390mm"` is working fine, if I execute this command in the cli.
If I execute the script manually by typing `monitor_hotplug.sh` in the cli, it returns:
Authorization required, but no authorization protocol specified
Can't open dislay :0Moving the script into my $HOME and setting the u:g to my user, it doesn't change the behaviour of the script.
When I googled the first sentence, I've stumbled across, that it's a missing Xauthority in the script/udev-rule.
But everytime when I look for a .Xauthority file, there's nothing.
Does anyone know how to solve this problem for GNOME on Wayland?
Thanks
Last edited by Veldora (2023-02-24 17:16:04)
Offline
You can completely forget about xrandr in a wayland context, https://aur.archlinux.org/packages/wlr-randr - but idk. whether that'll work w/ gnome.
Offline
You cant and don't want to use xrandr and need to forfeit any and all attempts of handling this like you would be handling it on xorg stop thinking about xrandr, xauthority, or the DISPLAY variable, they have no meaning on wayland and you cannot manipulate a physical device with these.
If it doesn't retain this from a known config you need to report this to the gnome developers. Otherwise check whether gnome provides a cmdline tool to affect this. Seeing as we are talking about GNOME chances are there isn't, quickest thing I've found on a googler is this 6 year old tool https://github.com/xytovl/display-config no clue if it still works. Second quickest thing was a DBus API for mutter: https://gitlab.gnome.org/GNOME/mutter/- … Config.xml ... third thing, and likely the most fruitful if you just want to use something: https://aur.archlinux.org/packages/gnome-randr-rust
Last edited by V1del (2023-02-23 14:59:24)
Offline
Also forget about XAUTHORITY and DISPLAY completely. You may need to export WAYLAND_DISPLAY for gnome-randr to work, but I have no experience with that tool. Unfortunately quite a lot of wayland software just assumes WAYLAND_DISPLAY is "wayland-0" which can work slightly in your favor if you run just a single session with no nested sessions (but is an absolute pain for any other configuration).
I suspect the proximate problem is that there is something wrong with that obscenely complex pipeline following gnome-randr. There is absolutely no reason for all of that. You should use gnome-randr flags to get the information you need, or even if you need to pipe it to other tools, ONE of those tools can do everything you need.
But even further, I see no reason to do all this testing. Just unconditionally call gnome-randr/wlr-randr to specify the settings you want for each monitor. If a specified output is not connected, the setting will fail with no harm done. So your script should just be one line, which in fact could then just be put directly in the udev rule:
... RUN+='/bin/wlr-randr --output <output-name> --mode <whatever>'(edit: cross posted w/ V1del)
EDIT: fwiw, your whole gnome-randr pipeline can be replaced with a single awk (or sed):
gnome-randr | awk '/DELL/ {print substr($1,2); exit; }'Last edited by Trilby (2023-02-23 16:57:40)
"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman
Offline
Also forget about XAUTHORITY and DISPLAY completely. You may need to export WAYLAND_DISPLAY for gnome-randr to work, but I have no experience with that tool. Unfortunately quite a lot of wayland software just assumes WAYLAND_DISPLAY is "wayland-0" which can work slightly in your favor if you run just a single session with no nested sessions (but is an absolute pain for any other configuration).
I suspect the proximate problem is that there is something wrong with that obscenely complex pipeline following gnome-randr. There is absolutely no reason for all of that. You should use gnome-randr flags to get the information you need, or even if you need to pipe it to other tools, ONE of those tools can do everything you need.
But even further, I see no reason to do all this testing. Just unconditionally call gnome-randr/wlr-randr to specify the settings you want for each monitor. If a specified output is not connected, the setting will fail with no harm done. So your script should just be one line, which in fact could then just be put directly in the udev rule:
... RUN+='/bin/wlr-randr --output <output-name> --mode <whatever>'
Hi there Trilby
Thank you for your answer.
I assume, you mean this pipline
OUTPUT=$(gnome-randr | grep DELL | head -n1 | cut -c2- | awk '{print $1}')if so, I can assure, that this is only getting me the value required for <output-name>.
Otherwise, a single `gnome-randr` would print everything.
Since I only need to get the output-name of the DELL monitor, I've decided to pipe the output through alot of commands, which at the end, outputs DP-3. (I've tested it and it's working)
So my part is to get the script executed, when the udev-rule fires, when I plug-in my DELL monitor.
But that's more over an execution-problem I have to fix with my udev-rule.
Last edited by Veldora (2023-02-23 15:02:36)
Offline
Trilby wrote:Also forget about XAUTHORITY and DISPLAY completely. You may need to export WAYLAND_DISPLAY for gnome-randr to work, but I have no experience with that tool. Unfortunately quite a lot of wayland software just assumes WAYLAND_DISPLAY is "wayland-0" which can work slightly in your favor if you run just a single session with no nested sessions (but is an absolute pain for any other configuration).
I suspect the proximate problem is that there is something wrong with that obscenely complex pipeline following gnome-randr. There is absolutely no reason for all of that. You should use gnome-randr flags to get the information you need, or even if you need to pipe it to other tools, ONE of those tools can do everything you need.
But even further, I see no reason to do all this testing. Just unconditionally call gnome-randr/wlr-randr to specify the settings you want for each monitor. If a specified output is not connected, the setting will fail with no harm done. So your script should just be one line, which in fact could then just be put directly in the udev rule:
... RUN+='/bin/wlr-randr --output <output-name> --mode <whatever>'Hi there Trilby
Thank you for your answer.
I assume, you mean this piplineOUTPUT=$(gnome-randr | grep DELL | head -n1 | cut -c2- | awk '{print $1}')if so, I can assure, that this is only getting me the value required for <output-name>.
Otherwise, a single `gnome-randr` would print everything.Since I only need to get the output-name of the DELL monitor, I've decided to pipe the output through alot of commands, which at the end, outputs DP-3. (I've tested it and it's working)
So my part is to get the script executed, when the udev-rule fires, when I plug-in my DELL monitor.
But that's more over an execution-problem I have to fix with my udev-rule.
Okay, I've managed to get the udev-rule execution working.
But still, gnome-randr doesn't generate an output, when executed by udev and I redirect stdout to a file via `gnome-randr | grep "DELL" > /tmp/gnome-randr-out`.
When I execute the script `hotplug_monitor.sh` standalone in the cli, following output gets generated.
Traceback (most recent call last):
File "/usr/lib/python3.10/site-packages/dbus/bus.py", line 177, in activate_name_owner
return self.get_name_owner(bus_name)
File "/usr/lib/python3.10/site-packages/dbus/bus.py", line 361, in get_name_owner
return self.call_blocking(BUS_DAEMON_NAME, BUS_DAEMON_PATH,
File "/usr/lib/python3.10/site-packages/dbus/connection.py", line 652, in call_blocking
reply_message = self.send_message_with_reply_and_block(
dbus.exceptions.DBusException: org.freedesktop.DBus.Error.NameHasNoOwner: Could not get owner of name 'org.gnome.Mutter.DisplayConfig': no such name
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/bin/gnome-randr", line 831, in <module>
dc = bus.get_object('org.gnome.Mutter.DisplayConfig',
File "/usr/lib/python3.10/site-packages/dbus/bus.py", line 241, in get_object
return self.ProxyObjectClass(self, bus_name, object_path,
File "/usr/lib/python3.10/site-packages/dbus/proxies.py", line 250, in __init__
self._named_service = conn.activate_name_owner(bus_name)
File "/usr/lib/python3.10/site-packages/dbus/bus.py", line 182, in activate_name_owner
self.start_service_by_name(bus_name)
File "/usr/lib/python3.10/site-packages/dbus/bus.py", line 277, in start_service_by_name
return (True, self.call_blocking(BUS_DAEMON_NAME, BUS_DAEMON_PATH,
File "/usr/lib/python3.10/site-packages/dbus/connection.py", line 652, in call_blocking
reply_message = self.send_message_with_reply_and_block(
dbus.exceptions.DBusException: org.freedesktop.DBus.Error.ServiceUnknown: The name org.gnome.Mutter.DisplayConfig was not provided by any .service filesAccording to the last error message, some could say it's moreover a service error, but when I DDG the error-message, nothing useful comes up. The same with the first error-message about `NameHasNoOwner`.
Thanks
Offline
Your session bus will make no sense if executed from the udev rule with the logistics you have in the script. You need to get the DBUS_SESSION_BUS_ADDRESS of your user not from root (you can peek the proper value from a process you know to be running, like gnome-shell: https://gist.github.com/AladW/de1c5676d93d05a5a0e1 ) . and generally for logical safety you might run all of the commands as your own user. And from what I'm seeing that gnome-randr tool is dead and outdated, try the rust version I linked.
Last edited by V1del (2023-02-23 16:34:44)
Offline
Your session bus will make no sense if executed from the udev rule with the logistics you have in the script. You need to get the DBUS_SESSION_BUS_ADDRESS of your user not from root (you can peek the proper value from a process you know to be running, like gnome-shell: https://gist.github.com/AladW/de1c5676d93d05a5a0e1 ) . and generally for logical safety you might run all of the commands as your own user. And from what I'm seeing that gnome-randr tool is dead and outdated, try the rust version I linked.
Hi V1del
Thank you for your response.
It worked using the script you linked and I've uninstalled gnome-randr and installed the gnome-randr-rust version (however, the last update was also on 2022-03-27, which isn't very up-to-date).
I've edited my script and now it's looking like this:
#!/bin/sh
pid=$(ps au | grep /usr/bin/gnome-session | grep tty$(fgconsole) |grep -v grep | awk '{print $2}' | head -n1)
pid=$(pgrep -P $pid -n)
import_environment() {
(( pid )) && for var; do
IFS='=' read key val < <(grep -E -z "$var" /proc/$pid/environ)
printf -v "$key" %s "$val"
[[ ${!key} ]] && export "$key"
done
}
import_environment DBUS_SESSION_BUS_ADDRESS
function connect {
OUTPUT=$(gnome-randr | grep DELL | head -n1 | cut -c2- | awk '{print $1}')
echo $OUTPUT | systemd-cat -p emerg
}
function disconnect {
echo "Monitor unplugged" | systemd-cat -p emerg
}
gnome-randr | grep "DELL" && connect || disconnectThe first pid=() is different from the original, but that's because when asking for gnome-session, it outputs the pid of gnome-session-binary, which is the parent of gnome-session (when checking with the corresponding pid of gnome-session using pgrep -P). That's why I'm grepping it with the exact path of /usr/bin/gnome-session, so that the second pid=() works as intended. In case there are two gnome-session (why so ever, since there is only one user actively logged-in on the notebook), I'm also getting the first entry using head -n1.
The script is working so far in combination with the udev-rule, I've also edited to run as the logged-in user using /usr/bin/su <username> -c /usr/bin/hotplug_monitor.sh
BUT, there's a new problem.
Whenever I replug the monitor, it seems to wait for the udev-rule to execute first and then sending a signal to the monitor. Adding the ACTION=="change" to the udev-rule doesn't change the behaviour.
This results, that the script prints the output of the connect() function when disconnecting and when connecting the monitor the output of the disconnect() function.
Do you think, I have to go via a systemd-service, which gets executed from the udev-rule and then executes the script at the end or is there an other way to fix this misbehaviour?
Thanks
Offline
Okay.. I've worked a little with ChatGPT and we've come to a solution.
Using a udev rule in combination with a systemd-service and a sleep 5, there's enough time for the system to detect the monitor and it won't block the udev rule from execution, since it calls a systemd-service.
Here's my working solution, for everyone else who's also struggling with it.
Udev-Rule:
KERNEL=="card0", SUBSYSTEM=="drm", TAG+="systemd", ENV{SYSTEMD_WANTS}+="hotplug_monitor.service"Systemd-Service:
[Unit]
Description=Monitor hotplug service
[Service]
Type=oneshot
ExecStart=/usr/bin/su <user> -c /usr/bin/hotplug_monitor.sh
[Install]
WantedBy=multi-user.targethotplug_monitor script:
#!/bin/sh
sleep 5
pid=$(ps au | grep /usr/bin/gnome-session | grep tty$(fgconsole) |grep -v grep | awk '{print $2}' | head -n1)
pid=$(pgrep -P $pid -n)
import_environment() {
(( pid )) && for var; do
IFS='=' read key val < <(grep -E -z "$var" /proc/$pid/environ)
printf -v "$key" %s "$val"
[[ ${!key} ]] && export "$key"
done
}
import_environment DBUS_SESSION_BUS_ADDRESS
function connect {
OUTPUT=$(gnome-randr | grep "DELL" | head -n1 | cut -c2- | awk '{print $1}')
echo $OUTPUT | systemd-cat -p emerg
gnome-randr modify $OUTPUT --primary
}
function disconnect {
echo "Monitor unplugged" | systemd-cat -p emerg
}
gnome-randr | grep "DELL U4021QW" && connect || disconnectin the script, just exchange stuff with your setup, if you have a different monitor for example.
A big thank you goes to V1del and Trilby for helping me getting on the right track.
I'm marking this post as solved.
Offline