非 GTK 应用程序中的 GTK+3 文件选择器

GTK+3 file chooser in a non-GTK application

我有一个完全不使用 GTK 的 C 项目(在 Linux 上),但我只想将 GTK 用于某些特定任务,例如 selecting 文件(文件选择器对话)。所以我没有 GTK 父 window,没有 gtk 主循环等,我只想要一个文件选择器对话框,它应该阻止我的程序的执行,直到用户 select 编辑了一个文件(或取消)并且之后我不再使用 GTK。我尝试过的:

https://developer.gnome.org/gtk3/stable/GtkFileChooserDialog.html

我使用了 "Typical usage" 中的代码,第一个例子。我将 gtk_init(&argc, &argv) 放在程序的开头,当我需要文件选择器时,我使用该示例中的代码调用一个函数(我将父级用作 NULL,因为没有父级)。结果是闪烁 window 几分之一秒,然后是 SIGSEGV。在此之前我有这条消息:

Gtk-Message: GtkDialog mapped without a transient parent. This is discouraged.

我已经在 Whosebug 上阅读了 questions/answers 关于此消息的信息,但使应用程序崩溃对我来说是一件更严重的事情。我也试着把这个:

gtk_widget_show_all(dialog);

在 gtk_file_chooser_dialog_new() 之后不会导致崩溃,我可以 select 文件,但随后我又在 gtk_file_chooser_get_filename() 附近有了 SIGSEGV。

使用 gdb 时,我得到了这个:

Program received signal SIGSEGV, Segmentation fault.
__GI___pthread_mutex_lock (mutex=0x3c3) at ../nptl/pthread_mutex_lock.c:67

你能帮我看看我做错了什么吗?我不太熟悉GTK编程,所以我尝试使用手册中的示例,但似乎不起作用。非常感谢!

没有 gtk 主循环就不能使用小部件。

嗯,看来我错了。诚挚的歉意!我 曾经 之前确实尝试过这样做,结论正是我所描述的。但是最近几天这个问题一直困扰着我,所以我做了更多的挖掘和试验,并提出了以下程序:

/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*-  */
/*
 * main.c
 * Copyright (C) 2015 John Coppens <john@jcoppens.com>
 * 
 * standalone_filechooser is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * standalone_filechooser is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <gtk/gtk.h>

GtkWidget *
create_filechooser_dialog(char *init_path, GtkFileChooserAction action)
{
  GtkWidget *wdg = NULL;

  switch (action) {
    case GTK_FILE_CHOOSER_ACTION_SAVE:
      wdg = gtk_file_chooser_dialog_new("Save file", NULL, action,
        "Cancel", GTK_RESPONSE_CANCEL,
        "Save", GTK_RESPONSE_OK,
        NULL);
      break;

    case GTK_FILE_CHOOSER_ACTION_OPEN:
      wdg = gtk_file_chooser_dialog_new("Open file", NULL, action,
        "Cancel", GTK_RESPONSE_CANCEL,
        "Open", GTK_RESPONSE_OK,
        NULL);
      break;

    case GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER:
    case GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER:
      break;
  }

  return wdg;
}

int main(int argc, char *argv[])
{
  GtkWidget *wdg;
  char *fname = "";

  if (argc == 2)
    fname = argv[1];

  gtk_init(&argc, &argv);

  wdg = create_filechooser_dialog(fname, GTK_FILE_CHOOSER_ACTION_OPEN);
  if (gtk_dialog_run(GTK_DIALOG(wdg)) == GTK_RESPONSE_OK) {
    printf("%s", gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(wdg)));
    return(0);
  } else  
    return (1);
}

您可以使用

从另一个程序(甚至终端)调用对话框
standalone_filechooser [default file]

如果提供 default file(无括号),它将被选中。如果选择了一个文件,它将在 stdout 上打印,否则程序将 return 错误=1

运行 没有主要 window 的小部件仍然存在一个小问题,这会导致将消息发送到 stderrGtkDialog mapped without a transient parent. This is discouraged。我认为这确实是一个错误(在更新版本的 gtk3 中 it might be solved)。由于消息已发送至 stderr,因此不应影响正常使用。