问题
I'm trying to use GTK's argv-handling, but there seem to be some issues with the main loop.
My goal is to parse the command line after GTK removed its options (like --display
), but before opening a window, because I want my app to be usable with a CLI-only interface, too, with both variants making use of Glib etc. This is why I'm trying to open the window in the command_line
signal handler.
This works as expected, exits when the window is closed.
#include <gtkmm.h>
int main(int argc, char **argv) {
auto app = Gtk::Application::create(argc, argv, "my.app");
Gtk::ApplicationWindow win;
return app->run(win);
}
But simply adding the HANDLES_COMMAND_LINE
flag destroys that: The window is never shown.
#include <gtkmm.h>
int on_cmd(const Glib::RefPtr<Gio::ApplicationCommandLine> &) {
return 0;
}
int main(int argc, char **argv) {
auto app = Gtk::Application::create(argc, argv, "my.app",
Gio::APPLICATION_HANDLES_COMMAND_LINE);
app->signal_command_line().connect(sigc::ptr_fun(on_cmd), false);
Gtk::ApplicationWindow win;
return app->run(win);
}
So I figured that the command_line
handler isn't actually suppposed to return? But the documentation says run
starts the main loop. I haven't found a method that simply waits for the main loop to finish, so I crank it manually. The window is being shown again, but of course the loop continues once it's closed, which is the least problem with that code:
#include <gtkmm.h>
int on_cmd(const Glib::RefPtr<Gio::ApplicationCommandLine> &,
Glib::RefPtr<Gtk::Application> &app) {
Gtk::ApplicationWindow win(app);
// app->run(win); --- lands here again -> stack overflow.
win.show();
// This looks very wrong but seems to work?!
while(true)
Glib::MainContext::get_default()->iteration(true);
// never reach this
return 0;
}
int main(int argc, char **argv) {
auto app = Gtk::Application::create(argc, argv, "my.app",
Gio::APPLICATION_HANDLES_COMMAND_LINE);
app->signal_command_line().connect(
sigc::bind(sigc::ptr_fun(on_cmd), app), false);
return app->run();
}
(gtkmm-3.0 version 3.5.13)
回答1:
Turns out, the key is calling activate
on the application. The default handler which is executed when HANDLES_COMMAND_LINE
is not given does that automatically.
My second example was just missing one line:
#include <gtkmm.h>
int on_cmd(const Glib::RefPtr<Gio::ApplicationCommandLine> &,
Glib::RefPtr<Gtk::Application> &app) {
app->activate(); // <----
return 0;
}
int main(int argc, char **argv) {
auto app = Gtk::Application::create(argc, argv, "my.app",
Gio::APPLICATION_HANDLES_COMMAND_LINE);
app->signal_command_line().connect(
sigc::bind(sigc::ptr_fun(on_cmd), app), false);
Gtk::ApplicationWindow win;
return app->run(win);
}
Here's a subclassed application which parses the command line using Glib, and if --gui
is present, opens a window and only terminates after the window is closed.
Using gtk_get_option_group
adds the GTK options (and help) to it, so --help-all
really shows all applicable options, and we don't have to rely on gtk_main(argc, argv)
to remove the GTK options, i.e. the argments can be deferred to the run(argc, argv)
call (but don't have to. If the application constructor is given the arguments, it will remove the GTK options, except --help-gtk
, our handler just never sees them but can still display help for it. Doesn't seem to matter either way)
#include <gtkmm.h>
struct MyApp : Gtk::Application {
MyApp() : Gtk::Application("my.app",
Gio::APPLICATION_HANDLES_COMMAND_LINE) {}
int on_command_line(const Glib::RefPtr<Gio::ApplicationCommandLine> &cmd) {
// parse arguments:
Glib::OptionContext ctx;
Glib::OptionGroup group("options", "main options");
bool show_gui = false;
Glib::OptionEntry entry;
entry.set_long_name("gui");
entry.set_description("show the gui.");
group.add_entry(entry, show_gui);
ctx.add_group(group);
// add GTK options, --help-gtk, etc
Glib::OptionGroup gtkgroup(gtk_get_option_group(true));
ctx.add_group(gtkgroup);
int argc;
char **argv = cmd->get_arguments(argc);
ctx.parse(argc, argv);
// maybe show the gui
if(show_gui)
activate();
return 0;
}
Gtk::ApplicationWindow *main;
void on_activate() {
// can't use Gtk::manage, so we have to keep
// the reference or the main loop quits.
main = new Gtk::ApplicationWindow();
add_window(*main);
main->show();
}
};
int main(int argc, char **argv) {
return MyApp().run(argc, argv);
}
来源:https://stackoverflow.com/questions/13852421/gtkmm-3-parse-command-line-with-gtkapplication