解读 GtkFileChooser
GTK+ 中的文件打开对话框

1。Shortcuts (快捷连接):“家目录”,“桌面”
在 "gtkfilechooserdefault.c" 8765 行
/* Creates the list model for shortcuts */
static void
shortcuts_model_create (GtkFileChooserDefault *impl)
{
...
if (impl->file_system)
{
shortcuts_append_home (impl);
shortcuts_append_desktop (impl);
shortcuts_add_volumes (impl);
}
...
这里添加了默认的“家目录”,“桌面” 两项,然后是由不同的 GtkFilesystem 后端(实现了 GtkFileSystemIface)提供的所有卷列表(接口 list_volumes)。
2。卷:gtk+ 默认 GtkFilesystem 后端
gtkfilesystemunix.c:476 中的 list_volumes 实现提供了一个指向 '/' (文件系统) 的卷。
static GSList *
gtk_file_system_unix_list_volumes (GtkFileSystem *file_system)
{
return g_slist_append (NULL, get_root_volume ());
}
3。卷:gnome-vfs 后端
由 libgnomeui/file-chooser/gtkfilesystemgnomevfs.[ch] 提供的基于 gnome-vfs 后端则提供了更多的可访问卷:
1。已连接的,当前用户可访问的卷
2。已挂载的,当前用户可访问的卷
3。网络服务器(即 Samba 网络)
4。文件系统 ('/')
这里卷包括所有 gnome-vfs 支持的“卷”,如光驱,U盘,移动硬盘,数码相机,MP3 等可移动设备,还有通过“连接到服务器”创建的到 FTP/SSH/WebDAV/Samba 的连接等。
GtkFilesystem 后端实现还要提供获取卷显示名称,图标,挂载状态,执行挂载(对于已经连接尝未挂载的卷)等函数。其中由 gtkfilechooserdefault.c 默认添加的“家目录”,“桌面” 两项的图标也需要由后端提供,我认为这是不合理的,既然 Gtk+ 中自带一个 GtkFilesystem 后端的实现(名为 "gtk+"),那么就不应该在 gtkfilechooserdefault.c 添加默认项,这里的默认项大可由后端实现自行添加(就多两行代码)。目前这样的做法不方便定制:)
4。标签支持
iface->insert_bookmark = gtk_file_system_gnome_vfs_insert_bookmark;
iface->remove_bookmark = gtk_file_system_gnome_vfs_remove_bookmark;
iface->list_bookmarks = gtk_file_system_gnome_vfs_list_bookmarks;
#if GTK_CHECK_VERSION(2,7,0)
iface->get_bookmark_label = gtk_file_system_gnome_vfs_get_bookmark_label;
iface->set_bookmark_label = gtk_file_system_gnome_vfs_set_bookmark_label;
#endif
Gtk+ >= 2.7.0 中的文件对话框支持自定义标签名,所以有 get/set_bookmark_label 接口(应该说 GtkFileSystemIface 有了这两接口,才有前者)。
目前标签支持的代码在 gtk+ 后端和 gnome-vfs 后端是一样的,是重复了,和以上的获取卷图标名一样是重复的。为什么不实现一基类来更好地重用相同的代码呢?
5。与 GNOME 桌面的集成
通过 gnome-setting-daemon 监视 /desktop/gnome/interface/file_chooser_backend 的值,并设置相应的 xsetting (-> GtkSettings) 值 "gtk-file-chooser-backend",
xsetting 与 gtk-settings 的转换:
gtk+/gdk/x11/gdksettings.c
static const char gdk_settings_names[] =
...
"Gtk/FileChooserBackend\0" "gtk-file-chooser-backend\0"
...
gnome-settings-daemon/gnome-settings-xsettings.c:102
static TranslationEntry translations [] = {
...
{ "/desktop/gnome/interface/file_chooser_backend", "Gtk/FileChooserBackend",
GCONF_VALUE_STRING, translate_string_string },
...
当 file_chooser_backend 改变时,gnome-setting-daemon 设置对应的 X 属性 "Gtk/FileChooserBackend",这时 Gtk+ 程序会调用对应的回调函数,并生成一个 GdkEvent :
gdk/x11/gdkevents-x11.c:2835
static void
gdk_xsettings_notify_cb (const char *name,
XSettingsAction action,
XSettingsSetting *setting,
void *data)
{
...
new_event.type = GDK_SETTING;
new_event.setting.window = gdk_screen_get_root_window (screen);
new_event.setting.send_event = FALSE;
new_event.setting.name = NULL;
...
gdk_event_put (&new_event);
}
gtk/gtkfilechooserdefault.c:463
static void
_gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
{
...
gtk_settings_install_property (g_param_spec_string ("gtk-file-chooser-backend",
P_("Default file chooser backend"),
P_("Name of the GtkFileChooser backend to use by default"),
NULL,
GTK_PARAM_READWRITE));
}
安装了这个属性,使得后续的程序中能获取到这个属性。
这样 Gtk+ 客户端就能通过 gtk_settings_get_default () 正确的获取到这个设置,并应用到自己的程序中。
GtkFileChooser 通过 "gtk-file-chooser-backend" 的值来装入默认的 file-system.
gtkfilechooserdefault.c:4835,在没有指定 file_system 参数时,通过 gtk_settings_get_default () 来获取默认设置,即可装入桌面系统中的默认值。
if (backend)
impl->file_system = gtk_file_system_create (backend);
else
{
GtkSettings *settings = gtk_settings_get_default ();
gchar *default_backend = NULL;
g_object_get (settings, "gtk-file-chooser-backend", &default_backend, NULL);
if (default_backend)
{
impl->file_system = gtk_file_system_create (default_backend);
g_free (default_backend);
}
}

