JuliaGraphics / Gtk.jl

Julia interface to Gtk windowing toolkit.
Other
286 stars 80 forks source link

Gtk sets environment variables that break other applications #647

Open mgkuhn opened 2 years ago

mgkuhn commented 2 years ago

Simply loading Gtk.jl causes emacs invoked from the REPL shell mode to no longer work (Ubuntu Linux 20.04 with X11):

$ julia
shell> emacs

julia> using Gtk

shell> emacs

(emacs:14248): Gtk-WARNING **: 15:38:46.870: Could not load a pixbuf from icon theme.
This may indicate that pixbuf loaders or the mime database could not be found.
**
Gtk:ERROR:../../../../gtk/gtkiconhelper.c:494:ensure_surface_for_gicon: assertion failed (error == NULL): Failed to load /usr/share/icons/Tango/24x24/status/image-missing.png: Unrecognised image file format (gdk-pixbuf-error-quark, 3)
Bail out! Gtk:ERROR:../../../../gtk/gtkiconhelper.c:494:ensure_surface_for_gicon: assertion failed (error == NULL): Failed to load /usr/share/icons/Tango/24x24/status/image-missing.png: Unrecognised image file format (gdk-pixbuf-error-quark, 3)
Fatal error 6: Aborted

This seems caused by src/Gtk.jl:init() setting these environment variables globally

# Point gdk to our cached loaders
ENV["GDK_PIXBUF_MODULE_FILE"] = joinpath(artifact_path(loaders_cache_hash), "loaders.cache")
ENV["GDK_PIXBUF_MODULEDIR"] = Librsvg_jll.is_available() && loaders_dir_hash !== nothing ?
                                joinpath(artifact_path(loaders_dir_hash), "loaders_dir") :
                                gdk_pixbuf_loaders_dir

which overrides the system-wide default, which Ubuntu-packaged applications, such as emacs, require. To demonstrate the cause: simply deleting GDK_PIXBUF_MODULE_FILE from ENV causes emacs to work again:

julia> delete!(ENV, "GDK_PIXBUF_MODULE_FILE");

shell> emacs

Is there no other way to pass these parameters to GDK, one that will not also affect every other GDK application called from within Julia?

giordano commented 2 years ago

This seems caused by src/Gtk.jl:init() setting these environment variables globally

There aren't many ways to have local environment variables. That's how they are. They aren't even thread-safe. There is addenv, but that's only for spawning processes, not calling into libraries.

mgkuhn commented 2 years ago

One (ugly) workaround would be for Gtk.jl to provide to users a list of environment variables that it modified, along with their original values, such that users can restore their values with withenv before calling another application. Something like

GTK_ORIG_ENV = ["GDK_PIXBUF_MODULE_FILE" => nothing, ...]

to be used like

withenv(GTK_ORIG_ENV...) do ; run(`emacs`) ; end;

To implement this, __init__() could first write its changes into a local dictionary NEW_ENV and the (to be added) loop that then applies all the changes collected in NEW_ENV to ENV could at the same time also produce a backup of the changed environment variables in GTK_ORIG_ENV. (Or does Julia already keep somewhere a read-only copy of the original environment variables it was called with?)