Comments (12)
Your "environment stealing" is a very clever workaround by the way. It might even be worthwhile to
extract that to its own script
I'll leave it in place here, because I've made the promise that autorandr would always remain a contained, single-file script without dependencies. But feel free to extract it into its own tool anyway if you feel you'd find some use for it :-) (Might be an idea to use psutil to be cross-platform compatible in that case.)
from autorandr.
why does autorandr use an system wide service file instead of systemd-user?
Is it possible to have something for this by default per user then?
from autorandr.
I'm not sure what you mean. I'm talking about systemd user units.
from autorandr.
When autorandr gets triggered by udev, I get the following logs:
This seems to be correct. No need to worry about the first two errors, they mean that the instance run as root does not have access to the display. The last line is the important one: It states that the global (batch) instance of autorandr forks a new instance of autorandr, running as your user, and that copy will have XAUTHORITY set properly (if it didn't, you'd see another error message from that copy).
..or do you have reason to believe that autorandr doesn't work?
As an aside, why does autorandr use an system wide service file instead of systemd-user?
For two reasons, (1) I don't know whether user instances of systemd trigger sleep.target
, (2) it's much easier to invoke a system service from udev than to invoke any existing user instance that might have a unit named autorandr.service.
from autorandr.
the global (batch) instance of autorandr forks a new instance of autorandr
Why does it just do this after first triggering the error?
..or do you have reason to believe that autorandr doesn't work?
Yes, it doesn't apply the profile after those logs are shown. If I manually run autorandr -c
however, it does.
(1) I don't know whether user instances of systemd trigger sleep.target
I'm pretty sure systemd-user works with the same targets as the global systemd.
(2) it's much easier to invoke a system service from udev than to invoke any existing user instance that might have a unit named autorandr.service.
That's true. I did a little research how you could acomplish this, and I came up with a kind-of-but-not-quite working solution:
- Having this
autorandr.service
file as a systemd-user service:
[Service]
Type=oneshot
ExecStart=/usr/bin/autorandr -c
- Having this udev rule, using the horribly underdocumented
SYSTEMD_USER_WANTS
(seeman systemd.device
):
ACTION=="change", SUBSYSTEM=="drm", TAG+="systemd", ENV{SYSTEMD_USER_WANTS}="autorandr.service"
Now for some reason that works the first time I plug in the monitor after a reboot, but not after that.
It might have something to do with the following part of the documentation:
Note that systemd will only act on Wants dependencies when a device first becomes active. It will not act on them if they are added to devices that are already active. Use SYSTEMD_READY= (see below) to influence on which udev event to trigger the dependencies.
But I'm not quite sure what that means. I tried asking in the systemd IRC, but didn't get an answer yet.
from autorandr.
Yes, it doesn't apply the profile after those logs are shown.
Hmm ok. Please add some debug output to autorandr:
- After
print("Running autorandr as %s for display %s" % (pwent.pw_name, display))
add
print(process_environ)
and check whether XAUTHORITY/DISPLAY are set correctly - Before
if "--batch" in options:
in the main function, add
print("autorandr started as uid %d" % os.getuid())
- Also, add
--debug
to the command line in the systemd unit
This should generate enough info to see what's going on, hopefully.
I'm pretty sure systemd-user works with the same targets as the global systemd.
Just found this as the first result on google. Might have changed in the meantime, of course.
..
SYSTEMD_USER_WANTS
..
That's a really nice feature, and it would be a great solution, but - alas - it won't work. See here, where we found exactly what you did find, too - this only works once.
(A workaround that might work would be to make the systemd unit a service instead of a OneShot script, but write it such that it cleanly stops itself shortly after invocation. Maybe systemd is intelligent enough to see "oh, it's a service, I should restart it because this new device needs it"?!)
from autorandr.
Hmm ok. Please add some debug output to autorandr:
I did that, and for some inexplicable reason it just works now. After switching back to the "vanilla" version, it still works.
I'm sorry for bothering you with this, it was probably not working for some other reason. Thanks for the support.
Just found this as the first result on google. Might have changed in the meantime, of course.
Looks like you're right, and thats still the case:
That's a really nice feature, and it would be a great solution, but - alas - it won't work.
We could ask on the systemd mailing list. But if the missing sleep.target
is a blocker for systemd-user anyways, that may not be neccessary.
from autorandr.
Okay, while I was fiddeling with postswitch scripts it stopped working again.
Here's the output:
-- Logs begin at Mon 2017-08-28 22:21:00 CDT. --
Oct 14 16:02:49 pad systemd[1]: Started autorandr execution hook.
Oct 14 16:03:33 pad systemd[1]: Starting autorandr execution hook...
Oct 14 16:03:34 pad autorandr[26554]: No protocol specified
Oct 14 16:03:34 pad autorandr[26554]: Can't open display :0
Oct 14 16:03:34 pad autorandr[26554]: Failed to run xrandr (line 440)
Oct 14 16:03:34 pad autorandr[26554]: autorandr started as uid 1000
Oct 14 16:03:34 pad autorandr[26554]: autorandr started as uid 0
Oct 14 16:03:34 pad autorandr[26554]: Running autorandr as timo for display :0
Oct 14 16:03:34 pad autorandr[26554]: {'DESKTOP_SESSION': '/nix/store/j93sjhrv8axb4f0nw2ilwcpwagk0s6gi-desktops/none+herbstluftwm', 'DISPLAY': ':0', 'PATH': '/bin:/usr/bin:/usr/local/bin', 'XDG_CURRENT_DESKTOP': '', 'XDG_SEAT': 'seat0', 'XDG_SEAT_PATH': '/org/freedesktop/DisplayManager/Seat0', 'XDG_SESSION_CLASS': 'user', 'XDG_SESSION_DESKTOP': '', 'XDG_SESSION_PATH': '/org/freedesktop/DisplayManager/Session1', 'XDG_SESSION_TYPE': 'x11', 'XDG_VTNR': '7', 'LANG': 'en_US.UTF-8', 'LD_LIBRARY_PATH': '/run/opengl-driver/lib', 'LOCALE_ARCHIVE': '/run/current-system/sw/lib/locale/locale-archive', 'NIX_CONF_DIR': '/etc/nix', 'NIX_OTHER_STORES': '/run/nix/remote-stores/*/nix', 'NIX_PATH': 'nixpkgs=/tmp/:nixos-config=/etc/nixos/configuration.nix:unstable=http://nixos.org/channels/nixos-unstable/nixexprs.tar.xz', 'TZDIR': '/etc/zoneinfo', 'XDG_SESSION_ID': '2', 'XDG_RUNTIME_DIR': '/run/user/1000', 'PAM_KWALLET5_LOGIN': '/run/user/1000/kwallet5.socket', 'AUTORANDR_BATCH_PID': '26554'}
Oct 14 16:03:34 pad systemd[1]: Started autorandr execution hook.
from autorandr.
Okay, so the user instance is executed but XAUTHORITY
is missing. Interesting: autorandr obtains its environment by scanning through any applications run by your user that have the DISPLAY
environment variable set and cloning its environment. Apparently, your user runs a process that has DISPLAY
set, but doesn't actually use X11 (It can't without having access..)
To see which process this is, you can add before
print("Running autorandr as %s for display %s" % (pwent.pw_name, display))
the line
print("Copied environment from %s" % " ".join(open(os.path.join(directory, "cmdline")).read().split("\0")))
And to resolve the issue, try adding after
display = process_environ["DISPLAY"] if "DISPLAY" in process_environ else None
a line
if "XAUTHORITY" not in process_environ:
display = None
from autorandr.
"Unfortunately" right now it works again (which makes sense if your explanation is correct: it depends on which process autorandr semi-randomly selects).
Instead I ran the following script to test:
import os
for directory in os.listdir("/proc"):
directory = os.path.join("/proc/", directory)
if not os.path.isdir(directory):
continue
environ_file = os.path.join(directory, "environ")
if not os.path.isfile(environ_file):
continue
uid = os.stat(environ_file).st_uid
if uid < 1000:
continue
process_environ = {}
try:
for environ_entry in open(environ_file).read().split("\0"):
if "=" in environ_entry:
name, value = environ_entry.split("=", 1)
if name == "DISPLAY" and "." in value:
value = value[:value.find(".")]
process_environ[name] = value
if "DISPLAY" in process_environ and "XAUTHORITY" not in process_environ:
print("Found %s" % " ".join(open(os.path.join(directory, "cmdline")).read().split("\0")))
except IOError:
pass
And got the following results:
Found /nix/store/shq2an5pmbjmgmrjwzn8ixjaxnfspnxj-kwallet-5.37.0-bin/bin/kwalletd5 --
Found /nix/store/rr1vxmwdy7risbsiwcz3iawabnv8w8jn-redshift-1.11/bin/redshift -l xx.yy
I don't know anything about kwalletd5
, but redshift
is running as a systemd-user service. Maybe that has something to do with it.
Note that I ignored all IOErrors. That's because I got an Permisison denied
for /proc/2411/environ
. It might be a good idea to handle that case in the real autorandr code.
from autorandr.
Interesting that redshift
still works - it also uses XRandr to set the gamma curve (e.g.) so it should be restricted by the same ACL as every other process.
However, there should be a simple fix: Prefer processes with XAUTHORITY
set as template environments for forking user instances of autorandr. I've made a commit that does this just now.
from autorandr.
Yes, that is weird. Maybe it does some hacks to discover XAUTHORITY
at runtime.
Your "environment stealing" is a very clever workaround by the way. It might even be worthwhile to extract that to its own script:
for auth in $( detect_running_xsesions ); do
XAUTHORITY="$auth" autorandr --change
done
or something like that. I could have used that on multiple occasions already (like when trying to notify-send
in a cronjob or something).
Thank you for fixing it!
from autorandr.
Related Issues (20)
- /home/thinker/./autorandr:49: DeprecationWarning: The distutils package is deprecated and slated for removal in Python 3.12. Use setuptools or check PEP 632 for potential alternatives from distutils.version import LooseVersion as Version HOT 1
- Question: should autorandr systemd service change profile when external monitor is unplugged? HOT 2
- Use of --skip-options breaks --current HOT 1
- Parsing XRandR output failed HOT 1
- Detected Wayland session 'wayland-0'. Exiting.
- Failed to apply profile because xrandr cannot find mode
- postscript loses authentication for systemctl commands after suspending HOT 1
- Unhandled exception (local variable 'output' referenced before assignment) HOT 1
- Broken regexes due to missing `r` string literal HOT 6
- Unable to save lid state when using NVIDIA GPU (no eDP / LVDS output)
- Total system crash + soundloop could be caused by autorandr
- Total system crash + soundloop could be caused by autorandr
- No XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE events HOT 2
- Prevent profile change with screen lock HOT 1
- Additional Documentation HOT 7
- autorandr.service "Failed to load profile: 'xxx' : Profile not found" althoug profile exists HOT 1
- Failed to apply profile due to `--crtc` option HOT 2
- Incorrect profile settings HOT 1
- autorandr /usr/bin/autorandr:210: SyntaxWarning: invalid escape sequence '\s' XRANDR_OUTPUT_REGEXP = """(?x) /usr/bin/autorandr:236: SyntaxWarning: invalid escape sequence '\s' """ + XRANDR_PROPERTIES_REGEXP + """ | # Properties to include in the profile /usr/bin/autorandr:248: SyntaxWarning: invalid escape sequence '\S' XRANDR_OUTPUT_MODES_REGEXP = """(?x) /usr/bin/autorandr:592: SyntaxWarning: invalid escape sequence '\s' version = re.search("xrandr program version\s+([0-9\.]+)", version_string).group(1) /usr/bin/autorandr:888: SyntaxWarning: invalid escape sequence '\+' match = re.match("(?P<w>[0-9]+)x(?P<h>[0-9]+)(?:\+(?P<x>[0-9]+))?(?:\+(?P<y>[0-9]+))?.*", output.options["panning"]) HOT 4
- please support appimage , or binary file HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from autorandr.