New Gtk4 App. model : CLI positional arguments

Hi!

I’m trying to understand how to define CLI arguments using the new Gtk4 model but I only managed to define non-positional / flagged arguments:

# (...)
class MyApp(Adw.Application):
    def __init__(self, *args, **kwargs):
        super().__init__(
            *args,
            application_id="org.example.myapp",
            flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE | 
                        Gio.ApplicationFlags.HANDLES_OPEN,
            **kwargs
        )
        self.connect('activate', self.on_activate)

        self.add_main_option(
            "test",
            ord("t"),  # <= This works
            GLib.OptionFlags.NONE,
            GLib.OptionArg.NONE,
            "Command line test",
            None,
        )

        self.add_main_option(
            "file",
            0,  # <= This doesn't
            GLib.OptionFlags.NONE,
            GLib.OptionArg.FILENAME,
            "File to load",
            None,
        )

    def on_activate(self, app):
        self.win = MainWindow(application=app)
        self.win.present()

    def on_quit(self, action, param):
        self.quit()

    def do_open(self, action, param):
        print("Now what")

    def do_command_line(self, command_line):
        options = command_line.get_options_dict()
        options = options.end().unpack()

        if "test" in options:
            print("Argument:  %s" % options["test"])

        if "file" in options: # <= And so this never fires
            print("Argument: %s" % options["file"])

        self.activate()
        return 0

app = MyApp()
app.run(sys.argv)

Of course I tried every combination of OptionArg and OptionFlag constants.
This is really hard to google for, given that this API replaced argparse, that itself (If I’m not mistaking) replaced something else before, so there is a lot of stale documentation out there :flashlight:
I can get the arguments by using

argv = command_line.get_arguments()
self.loaded_file = argv[1]

But that is not right, it’s totally bypassing the GtkApplication logic, and the help is not right:

# ./fwomaj -h                                 
Usage:
  fwomaj [OPTION…]

Help Options:
  -h, --help                 Show help options
  --help-all                 Show all help options
  --help-gapplication        Show GApplication options

Application Options:
  -t, --test                 Command line test
  --file                     Video file to load

It should say

Usage:
  fwomaj [OPTION…] FILE
(...)
  -t, --test                 Command line test
  FILE                       Video file to load

So there is really something that I’m missing there.

You can use GLib.OPTION_REMAINING as the name of the argument, both when adding the option and when getting the value out of the dictionary. You must use GLib.OptionArg.FILENAME_ARRAY, which means you’ll get a list of binary blobs, as files use the OS encoding, not UTF-8.

In general, though, you should only be parsing named options; if you’re passing files, you can leave HANDLES_OPEN and let GApplication send the files over to the running instance. The only reason why you would be adding GLib.OPTION_REMAINING as a main option is if you wanted to do some pre-processing before reaching the “open” phase, or if you wanted to do local command line handling.

1 Like

In general, though, you should only be parsing named options; if you’re passing files, you can leave HANDLES_OPEN

Yes, but what about the help? The option of passing file(s) wouldn’t even show up in it…?

# ./fwomaj -h
Usage:
  fwomaj [OPTION…]

Help Options:
  -h, --help                 Show help options
  --help-all                 Show all help options
  --help-gapplication        Show GApplication options

and let GApplication send the files over to the running instance.

Seems a bit magical ; I’d like to see an example of that, do you know where I can find one?

Again, I can get the args ; I’m just trying to understand the new logic, and I need the --help to reflect what the app does.

You should use Gio.Application.set_option_context_parameter_string():

self.set_option_context_parameter_string("FILE")

I don’t think we have many examples, mainly because it’s rare to add arguments to applications. While Gio.Application can be used for CLI tools, it’s mainly meant to be used as a way to write complete applications, likely with a GUI.

1 Like

You should use Gio.Application.set_option_context_parameter_string():

This is so close to what I need, I’m gonna mark this solved :slight_smile:

Using

self.set_option_context_parameter_string("FILE")
self.set_option_context_summary("  FILE is The video file to load")
self.set_option_context_description("Aaand the epilog")

This is what I get:

# ./fwomaj -h
Usage:
  fwomaj [OPTION…] FILE

  FILE is The video file to load

Help Options:
  -h, --help                 Show help options
  --help-all                 Show all help options
  --help-gapplication        Show GApplication options

Application Options:
  -t, --test                 Command line test

Aaand the epilog

I couldn’t find the method to add an entry to the “Application Options:” section, but for now it works.

it’s rare to add arguments to applications. While Gio.Application can be used for CLI tools, it’s mainly meant to be used as a way to write complete applications, likely with a GUI

But… What about “Open with”…? I mean, take a GUI Behemoth like The Gimp, how could it open files from the file manager without a CLI interface? And what a bout the CLI help, isn’t it required of any app, GUI or not?

Anyway ; Thank you very much for your guidance, Emmanuel.

For that, you don’t need options at all: you only need HANDLES_OPEN and then override the open() virtual function.

1 Like

For that, you don’t need options at all: you only need HANDLES_OPEN and then override the open() virtual function.

You know what I just did gimp --help and what you’re implying is right: The file opening capability is only mentioned, but not detailed / documented in the help:

# gimp --help
Usage:
  gimp [OPTION…] [FILE|URI...]

GNU Image Manipulation Program

Help Options:
  -h, --help                              Show help options
  --help-all                              Show all help options
  --help-gegl                             Show GEGL Options
  --help-gtk                              Show GTK+ Options

Application Options:
  -v, --version                           Show version information and exit
  --license                               Show license information and exit
  --verbose                               Be more verbose
  -n, --new-instance                      Start a new GIMP instance
  -a, --as-new                            Open images as new
  -i, --no-interface                      Run without a user interface
  -d, --no-data                           Do not load brushes, gradients, patterns, ...
  -f, --no-fonts                          Do not load any fonts
  -s, --no-splash                         Do not show a splash screen
  --no-shm                                Do not use shared memory between GIMP and plug-ins
  --no-cpu-accel                          Do not use special CPU acceleration functions
  --session=<name>                        Use an alternate sessionrc file
  -g, --gimprc=<filename>                 Use an alternate user gimprc file
  --system-gimprc=<filename>              Use an alternate system gimprc file
  -b, --batch=<command>                   Batch command to run (can be used multiple times)
  --batch-interpreter=<proc>              The procedure to process batch commands with
  -c, --console-messages                  Send messages to console instead of using a dialog
  --pdb-compat-mode=<mode>                PDB compatibility mode (off|on|warn)
  --stack-trace-mode=<mode>               Debug in case of a crash (never|query|always)
  --debug-handlers                        Enable non-fatal debugging signal handlers
  --g-fatal-warnings                      Make all warnings fatal
  --dump-gimprc                           Output a gimprc file with default settings
  --show-playground                       Show a preferences page with experimental features
  --display=DISPLAY                       X display to use

So there. Problem solved ; Thanks again :slight_smile: