Set application display name and icon without an installed desktop file?

How can I set the application name that appears in the top bar etc for a gjs application? It seems to be hardwired to “gjs”. According to the GLib docs, when using GApplication, g_application_run() reads the executable name from argv[0] and calls g_set_prgname(). But gjs’ ARGV strips off argv[0], so that can’t work. I’ve tried putting in a fake argv[0], but that makes no difference. I’ve tried calling g_set_application_name() manually, but that doesn’t work either. I’ve tried it before calling app.run(), in vfunc_startup() and in vfunc_command_line(), none of them work.

This is for GTK3. I’ve noticed different behaviour in another app for GTK4; that uses the application_id, but that’s also not really the right thing to do because the id is supposed to look like a backwards URL, not a human-readable name. I haven’t tested that app to see whether calling g_set_prgname/application_name manually work.

1 Like

It comes from the desktop entry, written in gjs or not

Of course when you haven’t setup an entry shell will guess - since gjs apps run in the gjs interpreter you’ll probably end up with gjs (since that’s the binary your running)

GTK seems to be able to override the guess somehow though, because a GTK4 GtkApplication uses the app id.

The app I’m currently working on doesn’t have a desktop entry because it’s launched from an extension’s panel widget. I could add a desktop file and use gtk-launch, but I think that would require the desktop file to be installed separately in /usr/share/applications or ~/.local/share/applications. Maybe I can make gtk-launch use a path inside the extension folder by setting XDG_DATA_DIRS?

Ah yes gtk3 had a semi-bug around setting the surface app-id (mostly that it didn’t use the app-id…), either way, to actually map that to a human name you still need an entry

Remember you can NoDisplay=true - just because it shouldn’t be showing in the app list doesn’t mean it can’t (or shouldn’t) have an entry, e.g. xdg-desktop-portal-gtk.desktop

image

You won’t find it in the app list (it’s not an app after all) but it shows windows so registers a desktop entry

Or anywhere XDG_DATA_DIRS/applications yes

Not sure how gtk-launch is involved here? Remember it’s shell that needs to find the entry so you’d need to modify the users global XDG_DATA_DIRS if you want to use a custom location

Surely I have to use gtk-launch to run the app via its desktop file. How is GNOME supposed to know that this desktop file is associated with it otherwise?

Ah now that is a complicated fun mess for another day

But gtk-launch is somewhere unneccsiarry - esp if your in an extension where you can use Gio.AppInfo to launch a desktop-id

EDIT
Docs: https://gjs-docs.gnome.org/gio20~2.66p/gio.desktopappinfo#constructor-new

Basically

ctx = Global.create_app_launch_context(0, -1)
Gio.DesktopAppInfo("org.your.thing.desktop").launch([], ctx)

I think the problem I’m facing at the moment is that with the desktop file in a non-standard location, it’s no good setting XDG_DATA_DIRS just before launching it, because that has no effect on gnome-shell. Would using Gio.DesktopAppInfo.new_from_filename() and then appinfo.launch() from the extension fix that, or would the info from the desktop file still be “lost” by the time the app opens?

Wouldn’t be so much lost as shell never knowing it exists

Anyway, even if it did work, I’d still have a problem with the desktop file needing an absolute path or one relative to PATH. I could work around that by generating a GKeyFile in memory and using Gio.DesktopAppInfo.new_from_keyfile(), but from what you’re saying it still won’t work.

I think there are some other mechanisms it can fall back on, eg something to do with WM_CLASS, but that would probably only work in xorg, not in Wayland.

Not sure what your thinking here, but yes that would be X only

You’d probably be better of with Gio.AppInfo.create_from_commandline but as you infered this wouldn’t help you much - Shell needs to be able to find the entry via Gio.DesktopAppInfo.new, which means having a file in XDG_DATA_DIRS/applications (as shell sees it)

I’m not quite following why you can’t drop a NoDisplay=true in ~/.local/share/applications?

I just don’t want to have to install a desktop file, because it will make my extension harder to install. At the moment I can just git clone it (with the right name) in ~/.local/share/gnome-shell/extensions then enable it with the Extensions app (formerly gnome-tweaks) or gnome-extensions. If it has to install a desktop file it will either need to be installed as root, or via a script to set the $HOME component of the Exec field. Does the browser integration support additional actions to be performed during installation?

Must admit I know little of extensions, my approach would be to try doing Gio.DesktopAppInfo.new, if you get null build a GKeyFIle and write it to ~/.local/share/applications

Not necessarily pretty but should work - perhaps generating entries for extensions is something shell should support (assuming there isn’t some hidden method already)

Yes, that sounds like a good idea. I should also check the Exec field in case the extension gets moved.

That would need a fair bit of convincing. Extensions are really meant as a way to modify the compositor, not as an alternative app distribution system …

Or maybe ship the .desktop file with the extension, and symlink it to .local/share/applications from the extension’s enable() method.

1 Like

I’ve got it working now. Thanks for your help. Just a couple of points:

I mistook that for a static method, but it’s actually an instance method on a singleton, so you either have to do something like this:

const Global = imports.gi.Shell.Global.get();
...
ctx = Global.create_app_launch_context(0, -1);

or like this:

const Shell = imports.gi.Shell;
...
ctx = Shell.Global.get().create_app_launch_context(0, -1);

I think you mean one of:

Gio.DesktopAppInfo.new("org.your.thing").launch([], ctx)

or:

Gio.DesktopAppInfo.new_from_filename("/<path>/org.your.thing.desktop").launch([], ctx)
2 Likes

Ah, I was just guessing based off skimming gjs-docs.gnome.org

Yes Gio.DesktopAppInfo.new( is what I meant - thanks for posting for future visitors

1 Like

Just

global.create_app_launch_context(0, -1);

works as well.

global is a global variable for the Global singleton :smirk:

So global is the global scope object, like window in a web app? I’ve been using window in gjs too; it seems to work, so it’s an alias for global?

No, window has been deprecated in gjs for globalThis (but the former still works).

In gnome-shell, global is a convenient global accessor for the Shell.Global singleton. It’s assigned on startup with

globalThis.global = Shell.Global.get();

Indeed, when Gnome Shell cannot read the information from .desktop file (Gio.DesktopAppInfo.get_name), it sets name from wm_class (Meta.Window.get_wm_class).

Manually renaming wm_class should work on Xorg: Gdk.set_program_class in Gtk.Application startup handler, or Gtk.Window.set_wmclass before window is realized in activate handler.
Simple naming the program is more universal solution: GLib.set_prgname before Gtk.Application.run (Gdk using GLib.get_prgname to automatically set wm_class) - that should work also in Wayland.

However, wm_class method has a noticeable limitation: the name cannot be localized.