jakehilborn / displayplacer

macOS command line utility to configure multi-display resolutions and arrangements. Essentially XRandR for macOS.
MIT License
3.77k stars 135 forks source link

Great tool, some remarks #5

Closed mabam closed 5 years ago

mabam commented 5 years ago

One of my screens sometimes stays black after boot, though it is recognised in System Preferences –> Displays. If I change settings there, the screen turns on and I can then change the settings back to what they were. I was looking for a command line tool in order to automate that, so I wouldn’t have to do it manually anymore.

I’ve tried other tools and they also do the job for changing the resolution, but still the screen stays black. Somehow, displayplacer “initiates” (or whatever it’s called) the screen resulting in a black screen actually turning on! Next to that, displayplacer is still maintained – the last summit is only 10 days old! So I use your tool to have my screen turn alive.

However, there’s two things I came across in displayplacer:

These are my findings so far. But I’m happy to have found a tool that is able to bring up my black screen. So thank you very much for your work!

jakehilborn commented 5 years ago

Good to know about the color depth thing. I had considered adding better support for it before but now I have a reason to. In the mean time, you can try setting a "mode" explicitly. When you run displayplacer list you'll see duplicated resolutions. Those duplicated resolutions, I assume, have different color depths so you could experiment with that.

I'll see if I can change the syntax to avoid special characters and quotes while maintaining backward compatibility.

mabam commented 5 years ago

Wow, thank you for replying so quickly and for taking up my remarks!

I just tried using “mode”. I already saw that the modes were duplicated in the list but didn’t know the reason (and didn’t actually test them). It turns out the first one (even number) of each pair results in 24-bit and the second one (uneven number) in 30-bit. Is this order consistent or could it happen that the 30-bit one takes the first position when, e. g. using the tool on a different machine (still with an iGPU supporting the same colour depths as mine) or for any other reason?

I ask ’cause there are others in a forum with the same “black screen problem”. I am writing a tool using AppleScript that will offer a simple GUI to choose the desired resolution, and then configure a Launch Agent that will automatically set that resolution while in the Login Window in order to bring up the screen after every boot.

If it is always the uneven list items resulting in 30-bit, I can filter out the others and let the user choose his resolution from that list. However, as not all resolutions desired by the user and supported by a certain screen are necessarily listed (depending on, e. g. EDID, as far as I know), I also want to give the possibility of setting a custom resolution – alongside with an appropriate warning.

By the way, here is where I found the info on UHD 630 colour depths.

mabam commented 5 years ago

Something else popping up in my mind:

Do you know of a way to permanently identify a screen, independently of the port where it’s connected to or which GPU is used? I read that CGDisplayCreateUUIDFromDisplayID is deprecated and CGDirectDisplayID changes when the system GPU does (on multi GPU MacBooks – see here). Not that I’d now how to use the CG…ID’s as I’m not a programmer, but I came across these terms when I searched for a solution. Also, someone suggested to get the S/N from the screen, but not every screen provides that to the system.

Actually, I was investigating on this for my script. But I thought it might be an interesting question for displayplacer as well so I mention it here.

jakehilborn commented 5 years ago

I have not experimented with color depth so I'm not sure if ordering is guaranteed. I can add color depth info to the displayplacer list output and add a param for it on input though. Probably won't have time until mid May unfortunately.

I've heard here that you can identify screens independent of the port by examining only a portion of the screen id. I haven't experimented with this yet though.

I also haven't heard of CGDisplayCreateUUIDFromDisplayID so I'd like to investigate that too. There are some other deprecated methods to get the display name as well. Maybe something somewhere in those APIs can uniquely identify a screen no matter how it is plugged in.

mabam commented 5 years ago

I'll see if I can change the syntax to avoid special characters and quotes while maintaining backward compatibility.

At first I wanted to use Display Manager (the old version supported setting of colour depth), but as it turned out, it isn’t able to activate the screen. I like the syntax of the new version though, because it is very simple. Maybe that’s something of interest for you when you get to having a look at displayplacer’s syntax. But I don’t know whether backwards compatibility would be given.

I have not experimented with color depth so I'm not sure if ordering is guaranteed. I can add color depth info to the displayplacer list output and add a param for it on input though. Probably won't have time until mid May unfortunately.

Well, you’d definitely make me happy with that :-) I’ll be away from tomorrow until the end of this month. And when I’m back it will still take me quite some time to work on my AppleScript. So mid May sounds like good timing :-)

I've heard here that you can identify screens independent of the port by examining only a portion of the screen id. I haven't experimented with this yet though.

I also haven't heard of CGDisplayCreateUUIDFromDisplayID so I'd like to investigate that too. There are some other deprecated methods to get the display name as well. Maybe something somewhere in those APIs can uniquely identify a screen no matter how it is plugged in.

I wish I’d understand more about that, but I’m afraid I don’t. AppleScript and a little command line (with a lot of googling) is as far as “coding” gets for me. So I’m curious as to where your investigations will take displayplacer.

Thank you again!

mochaslave commented 5 years ago

I want to give you one hundred stars!

heilei commented 5 years ago

Incredibly useful tool, thanks!

jakehilborn commented 5 years ago

@mabam I have implemented your suggestions and pushed them to GitHub.

  1. Replaced single quotes with double quotes to make bash variables easier to use. This was actually supported the whole time so all I had to do was update the documentation.
  2. Switched IDs to UUIDs that stay the same even if you change GPUs or ports.
  3. Added color_depth support.

Can you try out the color_depth functionality and let me know if it's working for you? I see the color_depth options do apply, but it doesn't affect my monitors visually. If all is well, I'll publish a new release on HomeBrew. Since I haven't updated HomeBrew yet you'll need to download the latest displayplacer executable directly from GitHub (not the releases tab, the executable in the source code).

mabam commented 5 years ago

Good timing, I’m almost done with my script and can implement the syntax changes and different parsing. Thank you for your work!

  1. Good to know, I didn’t think of trying that myself. That makes things easier/more elegant using variables.
  2. Wow, great you were able to implement the possibility to identify the screen by UUID, thanks for that! In one situation I want to address a screen by a fixed ID, but in a different situation I have a script preconfigured to set the screen to a certain mode that has been chosen earlier. But if it got connected to a different port or GPU in the meantime (some MacBook models even switch from iGPU to eGPU automatically if e. g., Photoshop is started), the colour depth and/or frequency supported by that GPU might be different. In that case a changed screen ID could be used to trigger a warning or a dialog asking the user to change settings or something like that. Do you think it would be possible to have both options – identify a screen with displayplacer by either ID or UUID? Maybe having id:<displayID> and uuid:<displayUUID> as arguments to choose from? Or by just leaving it id:<displayID> and have displayplacer discern between the two by their length or the hyphens in the UUID?
  3. Perfect! Works as advertised.
jakehilborn commented 5 years ago

Support for using the 10 character screen ids is still there, but the displayplacer list output doesn't show it anymore. I could add it back if there's a good reason to.

Does your tool automatically run when there is a screen layout change? E.g. a cable is plugged in or Photoshop is started?

mabam commented 5 years ago

Does your tool automatically run when there is a screen layout change? E.g. a cable is plugged in or Photoshop is started?

Part of that are examples from others I brought in here. I’ll try to briefly explain what my tool does:

I have an AppleScript providing a simple GUI and doing some automatic parsing in order to prepare a preference file. That file is picked up by a shell script which again gets triggered by a Launch Agent. The Launch Agent runs in either the Login Window or right after login (depending on auto login being enabled or not) in order to change screen settings.

The tool covers machines with iGPU only and machines with both, iGPU and eGPU. As action is performed right before or after the first login after boot, configuration needs to be done before shutdown. If a screen gets plugged from one GPU into the port of the other GPU in the meantime, the colour depth and/or frequency supported might change. In that situation the change of screen ID will prevent setting the screen to a wrong mode.

jakehilborn commented 5 years ago

Good point, the mode list does change when the 10 character screen id changes. I see this when I switch from integrated graphics to the Nvidia card in my MacBook. I've added it back such that both id types are supported.

I see your parsing the output of displayplacer list. I didn't write that output to be consumed programmatically so I'm sure it's a pain haha. I'll try to not change it too much in the future.

Can you try the latest executable and let me know if it helps?

mabam commented 5 years ago

I see your parsing the output of displayplacer list. I didn't write that output to be consumed programmatically so I'm sure it's a pain haha.

:-) I pre-parse some stuff when reading the required info into AppleScript using “do shell script”. But most of that output I parse in AppleScript. There I don’t find it that much of a pain as I can easily set text item delimiters to any character string, even if that includes line breaks. Independently from those delimiters I can get characters, words, or paragraphs counting from either the beginning or the end … AppleScript is slower than command line utilities, though. But I need it for the GUI anyway and the automatic change of screen settings after every boot is done by a Launch Agent and shell script, not AppleScript. So there’s no “waste” of computing power here. (And, honestly, in human perception the AppleScript seems to do everything instantly.)

I'll try to not change it too much in the future.

I’ll provide my tool as a script bundle containing everything else, including displayplacer which I then call by its full path. So as long as I don’t update my bundle, displayplacer within it isn’t updated either. Neither would it be affected by a more recent version of displayplacer in /usr/local/bin/ or elsewhere on the machine. So change what you need/want to change in the future. As long as displayplacer list will output ID’s and modes with frequencies and colour depths, it should also work for me when I update my tool. I can always adapt the parsing where necessary.

I’ll give credits to you for displayplacer on the download page where I’ll provide my tool (probably on GitHub). So anyone who likes to use it independently from my tool can find it here.

Can you try the latest executable and let me know if it helps?

Again, works as advertised!

Thank you again!

jakehilborn commented 5 years ago

Sounds great. I'll update the README and publish these new changes to Homebrew soon.