1/* GTK - The GIMP Toolkit
2 * gtkfilechooserutils.c: Private utility functions useful for
3 * implementing a GtkFileChooser interface
4 * Copyright (C) 2003, Red Hat, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "config.h"
21#include "gtkfilechooserutils.h"
22#include "gtkfilechooser.h"
23#include "gtktypebuiltins.h"
24#include "gtkintl.h"
25
26
27static gboolean delegate_set_current_folder (GtkFileChooser *chooser,
28 GFile *file,
29 GError **error);
30static GFile * delegate_get_current_folder (GtkFileChooser *chooser);
31static void delegate_set_current_name (GtkFileChooser *chooser,
32 const char *name);
33static char * delegate_get_current_name (GtkFileChooser *chooser);
34static gboolean delegate_select_file (GtkFileChooser *chooser,
35 GFile *file,
36 GError **error);
37static void delegate_unselect_file (GtkFileChooser *chooser,
38 GFile *file);
39static void delegate_select_all (GtkFileChooser *chooser);
40static void delegate_unselect_all (GtkFileChooser *chooser);
41static GListModel * delegate_get_files (GtkFileChooser *chooser);
42static void delegate_add_filter (GtkFileChooser *chooser,
43 GtkFileFilter *filter);
44static void delegate_remove_filter (GtkFileChooser *chooser,
45 GtkFileFilter *filter);
46static GListModel * delegate_get_filters (GtkFileChooser *chooser);
47static gboolean delegate_add_shortcut_folder (GtkFileChooser *chooser,
48 GFile *file,
49 GError **error);
50static gboolean delegate_remove_shortcut_folder (GtkFileChooser *chooser,
51 GFile *file,
52 GError **error);
53static GListModel * delegate_get_shortcut_folders (GtkFileChooser *chooser);
54static void delegate_notify (GObject *object,
55 GParamSpec *pspec,
56 gpointer data);
57
58static void delegate_add_choice (GtkFileChooser *chooser,
59 const char *id,
60 const char *label,
61 const char **options,
62 const char **option_labels);
63static void delegate_remove_choice (GtkFileChooser *chooser,
64 const char *id);
65static void delegate_set_choice (GtkFileChooser *chooser,
66 const char *id,
67 const char *option);
68static const char * delegate_get_choice (GtkFileChooser *chooser,
69 const char *id);
70
71
72/**
73 * _gtk_file_chooser_install_properties:
74 * @klass: the class structure for a type deriving from `GObject`
75 *
76 * Installs the necessary properties for a class implementing
77 * `GtkFileChooser`.
78 *
79 * A `GtkParamSpecOverride` property is installed for each property,
80 * using the values from the `GtkFileChooserProp` enumeration. The
81 * caller must make sure itself that the enumeration values don’t
82 * collide with some other property values they are using.
83 */
84void
85_gtk_file_chooser_install_properties (GObjectClass *klass)
86{
87 g_object_class_override_property (oclass: klass,
88 property_id: GTK_FILE_CHOOSER_PROP_ACTION,
89 name: "action");
90 g_object_class_override_property (oclass: klass,
91 property_id: GTK_FILE_CHOOSER_PROP_FILTER,
92 name: "filter");
93 g_object_class_override_property (oclass: klass,
94 property_id: GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE,
95 name: "select-multiple");
96 g_object_class_override_property (oclass: klass,
97 property_id: GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS,
98 name: "create-folders");
99 g_object_class_override_property (oclass: klass,
100 property_id: GTK_FILE_CHOOSER_PROP_FILTERS,
101 name: "filters");
102 g_object_class_override_property (oclass: klass,
103 property_id: GTK_FILE_CHOOSER_PROP_SHORTCUT_FOLDERS,
104 name: "shortcut-folders");
105}
106
107/**
108 * _gtk_file_chooser_delegate_iface_init:
109 * @iface: a `GtkFileChoserIface` structure
110 *
111 * An interface-initialization function for use in cases where
112 * an object is simply delegating the methods, signals of
113 * the `GtkFileChooser` interface to another object.
114 *
115 * _gtk_file_chooser_set_delegate() must be called on each
116 * instance of the object so that the delegate object can
117 * be found.
118 **/
119void
120_gtk_file_chooser_delegate_iface_init (GtkFileChooserIface *iface)
121{
122 iface->set_current_folder = delegate_set_current_folder;
123 iface->get_current_folder = delegate_get_current_folder;
124 iface->set_current_name = delegate_set_current_name;
125 iface->get_current_name = delegate_get_current_name;
126 iface->select_file = delegate_select_file;
127 iface->unselect_file = delegate_unselect_file;
128 iface->select_all = delegate_select_all;
129 iface->unselect_all = delegate_unselect_all;
130 iface->get_files = delegate_get_files;
131 iface->add_filter = delegate_add_filter;
132 iface->remove_filter = delegate_remove_filter;
133 iface->get_filters = delegate_get_filters;
134 iface->add_shortcut_folder = delegate_add_shortcut_folder;
135 iface->remove_shortcut_folder = delegate_remove_shortcut_folder;
136 iface->get_shortcut_folders = delegate_get_shortcut_folders;
137 iface->add_choice = delegate_add_choice;
138 iface->remove_choice = delegate_remove_choice;
139 iface->set_choice = delegate_set_choice;
140 iface->get_choice = delegate_get_choice;
141}
142
143/**
144 * _gtk_file_chooser_set_delegate:
145 * @receiver: a `GObject` implementing `GtkFileChooser`
146 * @delegate: another `GObject` implementing `GtkFileChooser`
147 *
148 * Establishes that calls on @receiver for `GtkFileChooser`
149 * methods should be delegated to @delegate, and that
150 * `GtkFileChooser` signals emitted on @delegate should be
151 * forwarded to @receiver. Must be used in conjunction with
152 * _gtk_file_chooser_delegate_iface_init().
153 **/
154void
155_gtk_file_chooser_set_delegate (GtkFileChooser *receiver,
156 GtkFileChooser *delegate)
157{
158 g_return_if_fail (GTK_IS_FILE_CHOOSER (receiver));
159 g_return_if_fail (GTK_IS_FILE_CHOOSER (delegate));
160
161 g_object_set_data (G_OBJECT (receiver), I_("gtk-file-chooser-delegate"), data: delegate);
162 g_signal_connect (delegate, "notify",
163 G_CALLBACK (delegate_notify), receiver);
164}
165
166GQuark
167_gtk_file_chooser_delegate_get_quark (void)
168{
169 static GQuark quark = 0;
170
171 if (G_UNLIKELY (quark == 0))
172 quark = g_quark_from_static_string (string: "gtk-file-chooser-delegate");
173
174 return quark;
175}
176
177static GtkFileChooser *
178get_delegate (GtkFileChooser *receiver)
179{
180 return g_object_get_qdata (G_OBJECT (receiver),
181 GTK_FILE_CHOOSER_DELEGATE_QUARK);
182}
183
184static gboolean
185delegate_select_file (GtkFileChooser *chooser,
186 GFile *file,
187 GError **error)
188{
189 return gtk_file_chooser_select_file (chooser: get_delegate (receiver: chooser), file, error);
190}
191
192static void
193delegate_unselect_file (GtkFileChooser *chooser,
194 GFile *file)
195{
196 gtk_file_chooser_unselect_file (chooser: get_delegate (receiver: chooser), file);
197}
198
199static void
200delegate_select_all (GtkFileChooser *chooser)
201{
202 gtk_file_chooser_select_all (chooser: get_delegate (receiver: chooser));
203}
204
205static void
206delegate_unselect_all (GtkFileChooser *chooser)
207{
208 gtk_file_chooser_unselect_all (chooser: get_delegate (receiver: chooser));
209}
210
211static GListModel *
212delegate_get_files (GtkFileChooser *chooser)
213{
214 return gtk_file_chooser_get_files (chooser: get_delegate (receiver: chooser));
215}
216
217static void
218delegate_add_filter (GtkFileChooser *chooser,
219 GtkFileFilter *filter)
220{
221 gtk_file_chooser_add_filter (chooser: get_delegate (receiver: chooser), filter);
222}
223
224static void
225delegate_remove_filter (GtkFileChooser *chooser,
226 GtkFileFilter *filter)
227{
228 gtk_file_chooser_remove_filter (chooser: get_delegate (receiver: chooser), filter);
229}
230
231static GListModel *
232delegate_get_filters (GtkFileChooser *chooser)
233{
234 return gtk_file_chooser_get_filters (chooser: get_delegate (receiver: chooser));
235}
236
237static gboolean
238delegate_add_shortcut_folder (GtkFileChooser *chooser,
239 GFile *file,
240 GError **error)
241{
242 return gtk_file_chooser_add_shortcut_folder (chooser: get_delegate (receiver: chooser), folder: file, error);
243}
244
245static gboolean
246delegate_remove_shortcut_folder (GtkFileChooser *chooser,
247 GFile *file,
248 GError **error)
249{
250 return gtk_file_chooser_remove_shortcut_folder (chooser: get_delegate (receiver: chooser), folder: file, error);
251}
252
253static GListModel *
254delegate_get_shortcut_folders (GtkFileChooser *chooser)
255{
256 return gtk_file_chooser_get_shortcut_folders (chooser: get_delegate (receiver: chooser));
257}
258
259static gboolean
260delegate_set_current_folder (GtkFileChooser *chooser,
261 GFile *file,
262 GError **error)
263{
264 return gtk_file_chooser_set_current_folder (chooser: get_delegate (receiver: chooser), file, error);
265}
266
267static GFile *
268delegate_get_current_folder (GtkFileChooser *chooser)
269{
270 return gtk_file_chooser_get_current_folder (chooser: get_delegate (receiver: chooser));
271}
272
273static void
274delegate_set_current_name (GtkFileChooser *chooser,
275 const char *name)
276{
277 gtk_file_chooser_set_current_name (chooser: get_delegate (receiver: chooser), name);
278}
279
280static char *
281delegate_get_current_name (GtkFileChooser *chooser)
282{
283 return gtk_file_chooser_get_current_name (chooser: get_delegate (receiver: chooser));
284}
285
286static void
287delegate_notify (GObject *object,
288 GParamSpec *pspec,
289 gpointer data)
290{
291 gpointer iface;
292
293 iface = g_type_interface_peek (instance_class: g_type_class_peek (G_OBJECT_TYPE (object)),
294 iface_type: gtk_file_chooser_get_type ());
295 if (g_object_interface_find_property (g_iface: iface, property_name: pspec->name))
296 g_object_notify (object: data, property_name: pspec->name);
297}
298
299GSettings *
300_gtk_file_chooser_get_settings_for_widget (GtkWidget *widget)
301{
302 static GQuark file_chooser_settings_quark = 0;
303 GtkSettings *gtksettings;
304 GSettings *settings;
305
306 if (G_UNLIKELY (file_chooser_settings_quark == 0))
307 file_chooser_settings_quark = g_quark_from_static_string (string: "-gtk-file-chooser-settings");
308
309 gtksettings = gtk_widget_get_settings (widget);
310 settings = g_object_get_qdata (G_OBJECT (gtksettings), quark: file_chooser_settings_quark);
311
312 if (G_UNLIKELY (settings == NULL))
313 {
314 settings = g_settings_new (schema_id: "org.gtk.gtk4.Settings.FileChooser");
315 g_settings_delay (settings);
316
317 g_object_set_qdata_full (G_OBJECT (gtksettings),
318 quark: file_chooser_settings_quark,
319 data: settings,
320 destroy: g_object_unref);
321 }
322
323 return settings;
324}
325
326char *
327_gtk_file_chooser_label_for_file (GFile *file)
328{
329 const char *path, *start, *end, *p;
330 char *uri, *host, *label;
331
332 uri = g_file_get_uri (file);
333
334 start = strstr (haystack: uri, needle: "://");
335 if (start)
336 {
337 start += 3;
338 path = strchr (s: start, c: '/');
339 if (path)
340 end = path;
341 else
342 {
343 end = uri + strlen (s: uri);
344 path = "/";
345 }
346
347 /* strip username */
348 p = strchr (s: start, c: '@');
349 if (p && p < end)
350 start = p + 1;
351
352 p = strchr (s: start, c: ':');
353 if (p && p < end)
354 end = p;
355
356 host = g_strndup (str: start, n: end - start);
357 /* Translators: the first string is a path and the second string
358 * is a hostname. Nautilus and the panel contain the same string
359 * to translate.
360 */
361 label = g_strdup_printf (_("%1$s on %2$s"), path, host);
362
363 g_free (mem: host);
364 }
365 else
366 {
367 label = g_strdup (str: uri);
368 }
369
370 g_free (mem: uri);
371
372 return label;
373}
374
375static void
376delegate_add_choice (GtkFileChooser *chooser,
377 const char *id,
378 const char *label,
379 const char **options,
380 const char **option_labels)
381{
382 gtk_file_chooser_add_choice (chooser: get_delegate (receiver: chooser),
383 id, label, options, option_labels);
384}
385static void
386delegate_remove_choice (GtkFileChooser *chooser,
387 const char *id)
388{
389 gtk_file_chooser_remove_choice (chooser: get_delegate (receiver: chooser), id);
390}
391
392static void
393delegate_set_choice (GtkFileChooser *chooser,
394 const char *id,
395 const char *option)
396{
397 gtk_file_chooser_set_choice (chooser: get_delegate (receiver: chooser), id, option);
398}
399
400
401static const char *
402delegate_get_choice (GtkFileChooser *chooser,
403 const char *id)
404{
405 return gtk_file_chooser_get_choice (chooser: get_delegate (receiver: chooser), id);
406}
407
408gboolean
409_gtk_file_info_consider_as_directory (GFileInfo *info)
410{
411 GFileType type = g_file_info_get_file_type (info);
412
413 return (type == G_FILE_TYPE_DIRECTORY ||
414 type == G_FILE_TYPE_MOUNTABLE ||
415 type == G_FILE_TYPE_SHORTCUT);
416}
417
418gboolean
419_gtk_file_has_native_path (GFile *file)
420{
421 char *local_file_path;
422 gboolean has_native_path;
423
424 /* Don't use g_file_is_native(), as we want to support FUSE paths if available */
425 local_file_path = g_file_get_path (file);
426 has_native_path = (local_file_path != NULL);
427 g_free (mem: local_file_path);
428
429 return has_native_path;
430}
431
432gboolean
433_gtk_file_consider_as_remote (GFile *file)
434{
435 GFileInfo *info;
436 gboolean is_remote;
437
438 info = g_file_query_filesystem_info (file, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE, NULL, NULL);
439 if (info)
440 {
441 is_remote = g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE);
442
443 g_object_unref (object: info);
444 }
445 else
446 is_remote = FALSE;
447
448 return is_remote;
449}
450
451GIcon *
452_gtk_file_info_get_icon (GFileInfo *info,
453 int icon_size,
454 int scale,
455 GtkIconTheme *icon_theme)
456{
457 GIcon *icon;
458 GdkPixbuf *pixbuf;
459 const char *thumbnail_path;
460
461 thumbnail_path = g_file_info_get_attribute_byte_string (info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH);
462
463 if (thumbnail_path)
464 {
465 pixbuf = gdk_pixbuf_new_from_file_at_size (filename: thumbnail_path,
466 width: icon_size*scale, height: icon_size*scale,
467 NULL);
468
469 if (pixbuf != NULL)
470 return G_ICON (pixbuf);
471 }
472
473 icon = g_file_info_get_icon (info);
474 if (icon && gtk_icon_theme_has_gicon (self: icon_theme, gicon: icon))
475 return g_object_ref (icon);
476
477 /* Use general fallback for all files without icon */
478 icon = g_themed_icon_new (iconname: "text-x-generic");
479 return icon;
480}
481

source code of gtk/gtk/gtkfilechooserutils.c