-
-
Notifications
You must be signed in to change notification settings - Fork 110
Description
I haven't looked closely at the code for other OSs yet, but the Linux code will populate _monitors once, and then leave it alone. It doesn't ever change, even if the user plugs an external monitor into a laptop or something.
It would be a good idea to watch for XRROutputChangeNotifyEvent and XRRCrtcChangeNotifyEvent (or if RandR isn't available, then ConfigureNotify on the root). When one arrives, invalidate _monitors.
For instance, this can be done by having the user-facing entry points (.monitors, .grab, etc.) call some backend method like _bookkeeping() or something. In the XCB backends, that would check the XCB queues, and invalidate _monitors if those events arrive. MSSBase would need to do that before testing to see if _monitors is populated, of course.
I don't know as much about the other two OSs that MSS supports, but here's some of my initial thoughts.
For Windows, to get WM_DISPLAYCHANGE etc. messages, you need to hook into an event loop. That may mean putting it on a separate thread, since I think that Windows manages event queues per-thread, and we don't want to mess with the app's main event queue. It might be simpler to just recheck the display state (EnumDisplayMonitors) every time .monitors is accessed. That's much simpler, and probably isn't a lot of overhead compared to the actual BitBlt. Of course, timing _monitors_impl would be important, to make sure it's fast enough.
For macOS, the relevant mechanism would be to use CGDisplayRegisterReconfigurationCallback. But that is very tricky in Python: the callback can be called at any time, on any thread. You just can't safely run Python code in that callback; it might be on a thread that isn't even running the Python interpreter, the interpreter might have the GIL locked, etc. As with Windows, it might be best to recheck CGGetActiveDisplayList etc. each time .monitors is accessed. Again, timing is important, but my intuition is that it would be plenty fast.
I probably would still maintain the _monitors cache on Linux, since there's a straightforward technique to get the necessary events, and querying the monitor configuration is more expensive than on the other OSs. (Linux needs at least a round-trip to the X server, while I gather that Windows keeps the monitor configuration in the kernel, and macOS mostly uses a shared IPC cache.)