LOL. Hi, Stefan. “Interesting?” What’s that supposed to mean, eh?
And, dang it, I should have mentioned right up front that I’m doing this on Windows where some things are (I think) still not exactly up to snuff. I did read somewhere that the Windows implementation of Gio.ApplicationCommandLine isn’t working, but it does. But then, maybe that poster was referring to the problem I’ve run into here.
Yup, I’ve been digging through those pages (and similar hits) off and on all day. Either—as I mentioned above—it’s just not a 100% implementation on Windows or I’m having more trouble than usual translating from C. (sigh)
Nothing’s jumping out at me that seems like it would affect this, no extra flags or signal hook-ups seem to be explicitly needed. But it could be something that’s NOT needed in C, but IS needed in D… because of the wrapper. I don’t know. I’m jumping at ghosts now.
Can’t wait to see what you may come up with, Stefan. Later, dude.
Yup, I’m getting either/or, but not both. Odd stuff, this.
It occurred to me that this might have something to do with processing a chain of signals. Like, if you have a series of bool-return callbacks hooked up and you have to make sure to return ‘false’ for each so the either chain is triggered. But, the onCommandLine callback returns an int. I haven’t yet figured out the significance of that return value. I’ve tried assigning a couple of different values (the obvious ones: 1, 0, -1) but nothing changes.
My understanding is GApplication::activate will not be emitted in this case. For reference, this section should clarify that somewhat. You can also simply search the source there for g_application_activate to see when this vfunc/signal will be emitted.
However, I do believe you should be passing G_APPLICATION_HANDLES_COMMAND_LINE in the flags to get GApplication::command-line.
Well, I watched your D GTK blog in the past, and for a long time the content was what most of us already know from GTK2 and the Krause book. With the GApplication stuff you have arrived at the more difficult parts of GTK3/4
Thanks for that link, I have seen that content before, but forget about it yesterday.
I think the GApplication startup signal handling is one of the most difficult parts of GTK3/4 unfortunately, and it may interfere with the command line handling of our host languages. Nim has advanced handling of command line parameters already, and I assume D and Rust too.
When I started writing the long Readme for the Nim bindings some years ago, I initially had the feeling that I should try to write something about the GApplication startup process, but I never managed to do it. It would be at least ten pages I guess, and maybe such a long description would even scare off Nim GTK users. One of the terms I do remember about GApplication is “remote app” – no idea what this really is, I think I should read all of the above links…
Ain’t that the truth! Still, I was just kidding around with that mock indignation stuff.
AFAIK, the GTK4 bindings for D are still some way off, but I’m not involved at that level, so I can’t say for sure. Last I spoke with Mike Wey about it, we’re lagging behind, even in the GTK3 stuff. The latest version covered is 3.24.x or thereabouts. The wrapper version is 3.9x, which may be misleading.
Being mostly interested in the GUI side, I haven’t really dug into that, so I couldn’t tell you.
It should be similar to handling multiple GDK signals, shouldn’t it? At least, that would make sense to me. Why reinvent the wheel? But what’s puzzling to me is that 1) the only callback method returning a non-void value is onCommandLine(), and 2) there’s no indication (in what I’ve read so far) as to what onCommandLine()'s return value means or what it’s used for. It must mean something or why bother returning an int?
Perhaps it’s ‘remote’ as in VDI. That’s the only thing that comes to mind.
That seems to be the case, but I have to wonder why it’s designed like this. If a file-name is supplied on the command line on start-up, I would expect the file to be opened in the app. It shouldn’t matter if the app has a GUI or not, so a GUI app should open its window under these circumstances.
Thanks for the link, Andy. This seems to imply that I have to designate the app as ‘local’ before a window opens. Huh. Must try that.
The hint of andyholmes was indeed important, we need the G_APPLICATION_HANDLES_COMMAND_LINE flag of course.
And I think your solution calling g_application_activate (app) in the command-line callback makes indeed sense. Because depending on command line parameters maybe we do not want to open GUI windows at all. Unfortunately I have not found API docs confirming this assumption yet.
For the GApplication explanations, I think we should split it in too parts. One simplified early in our books, so that beginners can use app style tools from the beginning and don’t have to use the old GTK2 style with init_gtk(), and an extended explanation in a later section. At least that would be the plain for Nim.
Do you have already an idea about the int return value of the command-line callback? For what is that return value used?
From what I’ve read so far, it’s just success (0) or continue (-1), similar to bool return values in the GDK signal handling system which makes me wonder why it wasn’t set up the same way… unless it’s got something to do with local/remote or primary/local instantiation of the app.
I’m going to give this a little more time, but if I don’t find an answer soon, I’m just going to put it on the back burner and move on. It’s peripheral to my main cause anyway.
The blog is rather narrow in scope, aiming to get people up and running with GUI programming and isn’t intended as a comprehensive guide to GTK/GIO/etc.
I don’t think calling activate() manually yourself is a bad idea per se. My understanding of the process goes something like this:
This means “local to the calling process”, or the process the user just typed into a terminal. Here you might catch a --version arg and just print and exit.
Since GApplication uses DBus names to ensure single-instance behaviour, this is where the application discovers whether it is the “primary instance” or a “remote instance”. The “primary” instance is the one that owns the DBus name (eg. org.gnome.Software).
Next up is the if-then chain
Here is where a background service would start running.
Unlike ::handle-local-options (and the more powerful ::local-command-line), this ::command-line signal is emitted in the “primary” instance. This is how you get command line arguments from a secondary (aka “remote”) terminal invocation to an already running GApplication (aka “primary”).
If no command line routes are taken, another split between two options may happen:
::open, the signal for G_APPLICATION_HANDLES_OPEN
This is also emitted in the “primary” instance. The reason this doesn’t result in the ::activate signal being emitted by default, is so you can select a different UI response for files (if you want) such as a solo GtkFileChooserDialog or in the case of a text editor you might open a second editor window.
Failing anything else being requested, ::activate is emitted in the “primary” instance.
Usually this results in the main window of an application opening or being presented. For context, this is also the signal emitted when a notification banner is clicked (by default).
Just pass G_APPLICATION_HANDLES_COMMAND_LINE and from the ::command-line callback handle your options and open your window. You can just call g_application_activate() if that function is setup to open your main window; there’s nothing wrong with that.
By contrast, just imagine a command line option called --hide-window. Clearly this option would have to be passed to the “primary” instance, but obviously shouldn’t result in the window opening.
Okay, thanks, Andy. I did do that, but thought I might be violating the spirit of GIO signals. It does seem strange that I have to deliberately call activate() under these circumstances when I don’t if I’m not handling the command-line signal. It seems like a cheat or a cludge, but as long as it works, I’m moving on.
What matters is the order in which you hook up the callback signals. The void-return callbacks are hooked up first. Anything that returns an int needs to be hooked up last. Then I don’t have to make an activate() call. Everything works in a sane way similar to the GDK system of signals and callbacks where callbacks returning a bool can interrupt the chain of signals being processed by returning true, all others returning false (meaning: we ain’t done yet).
Well, if you compare it to GDK signals/callbacks, there is logic to it, but you have to think in terms of signal chains rather than individual signals. With GDK, returning true from a single signal in a chain will halt signal processing for the entire chain. As long as false is being returned by any particular signal, the chain continues. In GIO, void takes the place of false.
I’m not 100% sure of this yet, but it seems like a theory worth testing. And this morning, I’ll be experimenting with multiple int callbacks to see if the signal chain can be halted by changing what’s returned.