Trying to access files from `Gtk::FileChooserDialog` fails with "Failed to wrap object of type 'GLocalFile'"

Hello.

I’m still stuck with gtkmm v4.8 because I’m using Manjaro, so I have no access to the new FileDialog, but from what I’ve seen of its API I’d probably get the same problem.

I’m trying to get access to the list of selected files returned by a FileChooserDialog, which returns a Glib::ListModel. When I try to convert the pointer type returned by its get_object method, nothing is returned and the following message appears on the logs:

Failed to wrap object of type 'GLocalFile'. Hint: this error is commonly caused by failing to call a library init() function.

The following is the way I set up the dialog. The first method is triggered by a signal, the second is the one called by the FileChooser.

void QxplayerApplication::on_playlist_insert()
{
    auto add_files_dialog = new Gtk::FileChooserDialog(
        *main_window, "Selecione as m\u00FAsicas a inserir", Gtk::FileChooser::Action::OPEN);

    add_files_dialog->set_transient_for(*main_window);
    add_files_dialog->set_modal();
    add_files_dialog->set_select_multiple();
    add_files_dialog->set_create_folders(false);
    add_files_dialog->set_current_folder(
        Gio::File::create_for_path(Glib::get_user_special_dir(Glib::UserDirectory::MUSIC)));

    add_files_dialog->add_button("_Cancelar", Gtk::ResponseType::CANCEL);
    add_files_dialog->add_button("_Inserir", Gtk::ResponseType::ACCEPT);

    auto audio_filter = Gtk::FileFilter::create();

    audio_filter->add_mime_type("audio/aac");
    audio_filter->add_mime_type("audio/ac3");
    audio_filter->add_mime_type("audio/mpeg");
    audio_filter->add_mime_type("audio/ogg");
    audio_filter->add_mime_type("audio/vorbis");
    audio_filter->set_name("Arquivos de \u00E1udio");

    add_files_dialog->add_filter(audio_filter);

    add_files_dialog->signal_response().connect(sigc::bind(
        sigc::mem_fun(*this, &QxplayerApplication::on_files_dialog_response), add_files_dialog));

    add_files_dialog->show();
}

void QxplayerApplication::on_files_dialog_response(int response_id, Gtk::FileChooserDialog *dialog)
{
    switch (response_id) {
        case Gtk::ResponseType::ACCEPT:
            sig_files_chosen.emit(dialog->get_files());
            break;
        case Gtk::ResponseType::CANCEL:
            break;
        default:
            std::cerr << "Resposta inv\u00E1lida do di\u00E1logo de arquivos: " << response_id
                      << std::endl;
    }

    delete dialog;
}

Then, there is the method that gets called from the signal in the second method above.

void QxplayerPlaylistController::on_files_chosen(Glib::RefPtr<Gio::ListModel const> selected_files)
{
    g_log("QxPlayer/PlaylistController", GLogLevelFlags::G_LOG_LEVEL_DEBUG,
          "Recebido sinal de novos itens a adicionar.");

    // * NOTE: This is the suggested way by the Glibmm docs.
    {
        guint i = 0;
        Glib::RefPtr<Gio::File const> item = nullptr;

        while ((item = dynamic_pointer_cast<Gio::File const>(selected_files->get_object(i++))) !=
               nullptr)
        {
            // TODO: Passar novos itens para a lista criada pelos alunos
            g_log("QxPlayer/PlaylistController", GLogLevelFlags::G_LOG_LEVEL_INFO, "Novo item = %s",
                  item->get_path().c_str());
        }
    }
    sig_items_changed.emit();
}

The log message appears when executing the dynamic_pointer_cast within the while.

Am I missing something? I’ve checked that the init functions from Gio and Glib are actually being called, and they are. Am I doing the conversion in the wrong way?

I already searched for this error and got nothing. I also tried looking for how other apps do this, but couldn’t figure out their code yet, so I’m asking you guys.

Thank you.

Hi, Arthur!
I has this problem too.
Try it with C lang level.

void ContentPage::on_file_dialog_response(int response_id, Gtk::FileChooserDialog *dialog)
{
	GListModel *gmodel = gtk_file_chooser_get_files(((Gtk::FileChooser *)dialog)->gobj());
    guint n = g_list_model_get_n_items(gmodel);
        
    for (guint i = 0; i < n; i++)
    {
        GObject *gobject_i = g_list_model_get_object(gmodel, i);
        GFile *gfile = (GFile *)gobject_i;
        Glib::RefPtr<Gio::File> file_mm = Glib::wrap(gfile, true);
        std::cout << file_mm->get_path() << std::endl;
    }
}
1 Like

See issues gtkmm#132 and glibmm#93.

From gtkmm#132:

Gtk::FileChooser::get_files(), get_shortcut_folders(), Gtk::FileDialog::open_multiple_finish(), select_multiple_folders_finish() return a Gio::ListModel whose elements are objects that implement the Gio::File interface.

The returned C objects may be instances of a private glib/gtk class, such as GLocalFile. This class is not wrapped in C++ code. Gio::ListModel::get_object() fails to find a suitable C++ wrapper, and returns an empty RefPtr.

Since a few days there are fixed versions in the git repository. They return
vectors of Gio::File instead of Gio::ListModel.

std::vector<Glib::RefPtr<Gio::File>> Gtk::FileChooser::get_files2()
std::vector<Glib::RefPtr<Gio::File>> Gtk::FileChooser::get_shortcut_folders2()

std::vector<Glib::RefPtr<Gio::File>> Gtk::FileDialog::open_multiple_finish()
std::vector<Glib::RefPtr<Gio::File>> Gtk::FileDialog::select_multiple_folders_finish()
1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.