albertosottile / darkdetect

Detect OS Dark Mode from Python
Other
171 stars 18 forks source link

ENH: Add some support for Linux #8

Closed larsoner closed 3 years ago

larsoner commented 3 years ago

I tried to match local conventions and update the README, let me know if it makes sense and seems worthwhile! At least on Ubuntu 20.10 with Adiwata-dark on GTK I get:

$ python -c "import darkdetect; print(darkdetect.theme())"
Dark

Closes #7

larsoner commented 3 years ago

Okay @cbrnr @albertosottile I couldn't resist the temptation to suffer through the ctypes gymnastics:

from gi.repository import Gio
settings = Gio.Settings.new('org.gnome.desktop.interface')
print(settings['gtk-theme'])

from ctypes import util, cdll, c_void_p, c_char_p, byref
lib = util.find_library('gtk-3')
assert lib is not None
gtklib = cdll.LoadLibrary(lib)
gtklib.gtk_init(None, None)
settings = gtklib.gtk_settings_get_default()
res = c_char_p()
gtklib.g_object_get(settings, b"gtk-theme-name", byref(res), 0)
print(res.value.decode())

Gives

Adwaita-dark
Adwaita-dark

Should I switch the code over to the ctypes version? I don't love the fact that it calls gtk_init but maybe we have to live with it...

cbrnr commented 3 years ago

I'll probably steal that and integrate it into MNELAB (of course with proper attribution).

albertosottile commented 3 years ago

Should I switch the code over to the ctypes version? I don't love the fact that it calls gtk_init but maybe we have to live with it...

I would leave this to you. As you can imagine, I would prefer the ctypes-based implementation and I do not mind that gtk_init is called (as you can see from the macOS version, some extra libraries are needed also there). However, I could also merge the PR as it is now.

Please let me know what you would rather do. Thanks again for this contribution.

cbrnr commented 3 years ago

@larsoner I was wondering if ctypes is really necessary. Does the Gio module not provide an API to access configuration keys (e.g. get_value)? Here's a SO question which seems to read a value like this: https://stackoverflow.com/questions/24407025/how-do-i-use-g-settings-schema-get-key-from-python

Since I'm WFH I don't have access to my Linux machine so unfortunately I can't tinker around myself.

larsoner commented 3 years ago

In the code snippet above, indeed I already use Gio to validate the ctypes approach. The disadvantage of Gio is that it adds a dependency, which is not good in general as @albertosottile mentioned in the issue.

And in this particular case, the Ubuntu packaged version of python3-gi / Gio didn't even work out of the box for me on python-3.9 that is packaged by Ubuntu, so I had to build it from source because there are no wheels. So it seems to be not all that easy to work with.

cbrnr commented 3 years ago

In the code snippet above, indeed I already use Gio to validate the ctypes approach. The disadvantage of Gio is that it adds a dependency, which is not good in general as @albertosottile mentioned in the issue.

Nice, I didn't see that.

And in this particular case, the Ubuntu packaged version of python3-gi / Gio didn't even work out of the box for me on python-3.9 that is packaged by Ubuntu, so I had to build it from source because there are no wheels. So it seems to be not all that easy to work with.

Does it work when installed from PyPI? Even on Linux I tend to prefer to install Python packages with pip, and what I'm reading on Twitter this seems to be the best option because Linux distributions (especially Debian) seem to heavily modify Python packages to the point that they don't work as expected.

You also mentioned that you need to call gtk_init - what are the implications of this command and why would you want to avoid it?

larsoner commented 3 years ago

Does it work when installed from PyPI?

Yes for me but it builds from source, so requires headers and compliers and compile time, which isn't pretty. I wouldn't want to force this on people. And it doesn't seem useful to continue discussion of this approach since adding a dependency is a non starter at this point

what are the implications of this command and why would you want to avoid it

I don't really know which is why it might be nice to avoid it, but we can't really avoid it (even Gio will almost certainly call it). I'm assuming there are no serious ramifications, but I'm not confident in it and don't know / haven't read enough about Gtk to know. But I'd be willing to just put it (the cries ctypes solution) in, though, and see if problems arise, especially since it (including the init call) is mentioned as a way to query the theme in some C/C++ threads I saw.

cbrnr commented 3 years ago

Yes for me but it builds from source, so requires headers and compliers and compile time, which isn't pretty. I wouldn't want to force this on people. And it doesn't seem useful to continue discussion of this approach since adding a dependency is a non starter at this point

I was just interested and didn't mean to argue for including in this project. I agree PyGObject isn't the best solution if it requires headers which people will likely not have installed.

I'd also go with the ctypes approach here as it seems better than the subprocess call and it is already used for macOS.

albertosottile commented 3 years ago

But I'd be willing to just put it (the cries ctypes solution) in, though, and see if problems arise, especially since it (including the init call) is mentioned as a way to query the theme in some C/C++ threads I saw.

As I said before, I would really appreciate a ctypes-based implementation along the lines of the code you wrote above. Would you prefer to adapt this PR or to open a new one? Thanks

larsoner commented 3 years ago

I should be able to do it in this PR on Monday

larsoner commented 3 years ago

Okay pushed a commit using ctypes that still seems to work on my system!

albertosottile commented 3 years ago

LGTM, thanks for this work. Medium term, we can think of catching some of the specific exceptions that could happen in the theme try block, instead of everything blindly.