Я пытаюсь использовать argv-обработку GTK, но, похоже, есть некоторые проблемы с основным циклом.
Моя цель состоит в том, чтобы разобрать командную строку после того, как GTK удалил ее параметры (например, --display
), но перед открытием окна, потому что я хочу, чтобы мое приложение также можно было использовать с интерфейсом только для CLI, причем оба варианта используют Glib и т. д. Вот почему я пытаюсь открыть окно в command_line
обработчик сигнала.
Работает как положено, выходит при закрытии окна.
#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);
}
Но просто добавив HANDLES_COMMAND_LINE
флаг уничтожает это: окно никогда не отображается.
#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);
}
Итак, я понял, что command_line
обработчик не должен возвращаться? Но в документации сказано run
запускает основной цикл. Я не нашел метод, который просто ожидает завершения основного цикла, поэтому провернул его вручную. Окно показывается снова, но, конечно, цикл продолжается после его закрытия, что является наименьшей проблемой для этого кода:
#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 версия 3.5.13)
Оказывается, ключ зовет activate
по заявке. Обработчик по умолчанию, который выполняется, когда HANDLES_COMMAND_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);
}
Вот подклассное приложение, которое анализирует командную строку, используя Glib, и если --gui
присутствует, открывает окно и завершает работу только после закрытия окна.
С помощью gtk_get_option_group
добавляет параметры GTK (и помощь) к нему, так --help-all
действительно показывает все применимые варианты, и нам не нужно полагаться на gtk_main(argc, argv)
чтобы удалить параметры GTK, то есть аргументы могут быть отложены до run(argc, argv)
вызов (но не обязан. Если конструктору приложения задаются аргументы, он удалит параметры GTK, кроме --help-gtk
наш обработчик просто не видит их, но может отображать справку. Кажется, не имеет значения в любом случае)
#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);
}
Других решений пока нет …