If you're writing a simple GTK application in Rust (e.g. with gtk4-rs) and you get this error
GLib-GIO-CRITICAL **: 13:39:45.953: This application can not open files.
and go "But I'm not opening any files, and I didn't ask to?!", you might want to be more explicit about that.
It might be because you're taking command-line arguments intended for other purposes, but gtk4 for Rust's Application::run() 'helpfully' collects any CLI arguments on your behalf without being asked to, even though you did not provide them directly (e.g. with Application::run_with_args()).
So, if you'd like to parse some CLI arguments for other reasons, you'll need to explicitly not provide them to your GTK application, or you'll need to pretend to handle them.
Approach 1: Explicitly ignore arguments
Instead of running your Application `app` like this:
let exit_code : ExitCode = app.run ();
Be explicit, like this:
let no_args : [&str; 0] = []; let exit_code : ExitCode = app.run_with_args (&no_args);
Approach 2: Claim to handle files (and then don't!)
let app : Application = Application::builder ()
.application_id (APP_ID)
.flags (ApplicationFlags::HANDLES_OPEN)
.build ();
...
app.connect_open (open_cb);
let exit_code : ExitCode = app.run ();
...
pub fn open_cb (_app : &Application, _files : &[File], _hint: &str) { }
This can be unintuitive, because in C, if you don't claim to handle opening of files, and don't explicitly provide argc/argv to g_application_run (), it does not assume you want to handle open. But C is a bit like approach 1, in that you are explicitly not providing them, since you have to pass 0 and NULL for argc and argv respectively.
Simple C application
This will simply and naively pop-up a window that shows the text provided in argv[1].
main.c#include <gtk/gtk.h>
int activate (GApplication *app, gpointer *user_data) {
GtkWidget *window = gtk_application_window_new (GTK_APPLICATION (app));
gtk_window_set_title (GTK_WINDOW (window), "Demo");
gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
GtkWidget *label = gtk_label_new ((char*)user_data);
gtk_window_set_child (GTK_WINDOW (window), label);
gtk_window_present (GTK_WINDOW (window));
}
int main (int argc, char **argv) {
GtkApplication *app = gtk_application_new ("org.kosmokaryote.test20240415.C", G_APPLICATION_DEFAULT_FLAGS);
g_signal_connect (G_APPLICATION (app), "activate", G_CALLBACK (activate), argv[1]);
return g_application_run (G_APPLICATION (app), 0, NULL);
}
Compiled with:
gcc `pkg-config --cflags --libs gtk4` main.c -o main
Corresponding Rust
cargo new test cargo add gtk4 --features v4_12src/main.rs
use gtk4::{Application,gio::ApplicationFlags, glib::ExitCode, prelude::*, ApplicationWindow, Label};
use std::env::{self, Args};
fn activate (app : &Application) {
let mut args : Args = env::args ();
let window : ApplicationWindow = ApplicationWindow::builder ()
.application (app)
.title ("Demo")
.default_width (600)
.default_height (400)
.build ();
let label : Label = match args.nth (1) {
Some(s) => Label::new (Some (s.as_str ())),
None => Label::new (None)
};
window.set_child (Some(&label));
window.present ();
}
fn main() -> ExitCode {
let app : Application = Application::new (Some ("org.kosmokaryote.test20240415.Rust"), ApplicationFlags::FLAGS_NONE);
app.connect_activate (activate);
// app.run ()
let no_args : [&str; 0] = [];
app.run_with_args (&no_args)
}