Gnome Extensions - Run shell command
Asked Answered
M

2

7

I am writing a simple extension to open browser by clicking the extension button. I would like to know if there is a function which can execute passed shell command as argument. Also, it'd be really helpful if anyone can suggest a good simple reference for extension development.

Margeret answered 11/4, 2017 at 22:41 Comment(1)
Are you looking for something like thisAts
B
10

From https://github.com/GNOME/gnome-shell/blob/master/js/misc/util.js:

// Runs @command_line in the background, handling any errors that
// occur when trying to parse or start the program.
function spawnCommandLine(command_line) {
    try {
        let [success, argv] = GLib.shell_parse_argv(command_line);
        trySpawn(argv);
    } catch (err) {
        _handleSpawnError(command_line, err);
    }
}

There are a few variations on that method in there. Save yourself mountains of headaches and just bookmark the GitHub repository.

Some quick links:

  • popupMenu.js: working with popup menus
  • panel.js: a good read for implementing "tray" icons
  • modalDialog.js: some UI elements were made to be reused, runDialog.js uses this for example
  • mpris.js: there are also good examples of using frameworks like DBus in gjs

I can't stress enough how much you'll get out of reading the gnome-shell source. Unfortunately, it's compiled into a resource file now so we don't have local copies to stumble upon.

UPDATE (2021)

If you're reading this, please instead see the documentation available on gjs.guide. Specifically the documentation on Spawning Subprocesses, which covers why this is a bad idea in extensions and how to do it slightly less bad.

Basion answered 14/6, 2017 at 4:3 Comment(8)
I'm missing a way to use these functions in my extension without copy & paste. Is there any?Dropsy
You just import them as modules then instantiate or subclass the Classes and call the functions: const Util = imports.misc.util; Util.spawnCommandLine("...");Basion
What should be done if the command requires sudo? Do you include sudo in your command, or will Gnome ask for password window-style?Epitasis
If it's not a GUI program that can request permissions itself, you should first examine whether that's a good idea since your user may not have feedback as to the results. But if you're sure it's a good idea, you would probably have to use pkexec or maybe gksudo.Basion
@Basion any idea how to get the output of the bash command we spawn?Revolute
@Revolute Use Gio.Subprocess instead: andyholmes.github.io/articles/…Basion
This is exactly what I was looking for, communicate_utf8(stdin_buf, cancellable) does the job for meRevolute
I think you should add the usage information (imports + invoking Utils functions) to the answer, as it is not obvious that these functions should be just imported without reading the comments.Repercussion
J
0

If you're not interested in the result - i.e. when you want to open a browser window - you can just use GLib.spawn_command_line_async like so:

const GLib = imports.gi.GLib;
...
(this._menuEntries[i]).connect('activate', () => {
       GLib.spawn_command_line_async('firefox http://example.com?p='+ my_params[i]);
});

If you need a synchronous result, read https://gjs.guide/guides/gio/subprocesses.html

Jephthah answered 10/7, 2021 at 14:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.