GTKmm 3:使用 Gtk::Application 解析命令行

GTKmm 3: Parse command line with Gtk::Application

本文关键字:Application 命令行 Gtk 使用 GTKmm      更新时间:2023-10-16

我正在尝试使用 GTK 的 argv 处理,但主循环似乎存在一些问题。

我的目标是在 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);
}