]> Pileus Git - ~andy/gtk/blob - gtk/gtkfilechooserdialog.c
More of the same
[~andy/gtk] / gtk / gtkfilechooserdialog.c
1 /* GTK - The GIMP Toolkit
2  * gtkfilechooserdialog.c: File selector dialog
3  * Copyright (C) 2003, Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #include <config.h>
22 #include "gtkfilechooserprivate.h"
23 #include "gtkfilechooserdialog.h"
24 #include "gtkfilechooserwidget.h"
25 #include "gtkfilechooserutils.h"
26 #include "gtkfilechooserembed.h"
27 #include "gtkfilesystem.h"
28 #include "gtktypebuiltins.h"
29 #include "gtkintl.h"
30 #include "gtkalias.h"
31
32 #include <stdarg.h>
33
34 #define GTK_FILE_CHOOSER_DIALOG_GET_PRIVATE(o)  (GTK_FILE_CHOOSER_DIALOG (o)->priv)
35
36 static void gtk_file_chooser_dialog_finalize   (GObject                   *object);
37
38 static GObject* gtk_file_chooser_dialog_constructor  (GType                  type,
39                                                       guint                  n_construct_properties,
40                                                       GObjectConstructParam *construct_params);
41 static void     gtk_file_chooser_dialog_set_property (GObject               *object,
42                                                       guint                  prop_id,
43                                                       const GValue          *value,
44                                                       GParamSpec            *pspec);
45 static void     gtk_file_chooser_dialog_get_property (GObject               *object,
46                                                       guint                  prop_id,
47                                                       GValue                *value,
48                                                       GParamSpec            *pspec);
49
50 static void     gtk_file_chooser_dialog_map          (GtkWidget             *widget);
51 static void     gtk_file_chooser_dialog_unmap        (GtkWidget             *widget);
52 static void     gtk_file_chooser_dialog_style_set    (GtkWidget             *widget,
53                                                       GtkStyle              *previous_style);
54
55 static void response_cb (GtkDialog *dialog,
56                          gint       response_id);
57
58 G_DEFINE_TYPE_WITH_CODE (GtkFileChooserDialog, gtk_file_chooser_dialog, GTK_TYPE_DIALOG,
59                          G_IMPLEMENT_INTERFACE (GTK_TYPE_FILE_CHOOSER,
60                                                 _gtk_file_chooser_delegate_iface_init))
61
62 static void
63 gtk_file_chooser_dialog_class_init (GtkFileChooserDialogClass *class)
64 {
65   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
66   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
67
68   gobject_class->constructor = gtk_file_chooser_dialog_constructor;
69   gobject_class->set_property = gtk_file_chooser_dialog_set_property;
70   gobject_class->get_property = gtk_file_chooser_dialog_get_property;
71   gobject_class->finalize = gtk_file_chooser_dialog_finalize;
72
73   widget_class->map       = gtk_file_chooser_dialog_map;
74   widget_class->unmap     = gtk_file_chooser_dialog_unmap;
75   widget_class->style_set = gtk_file_chooser_dialog_style_set;
76
77   _gtk_file_chooser_install_properties (gobject_class);
78
79   g_type_class_add_private (class, sizeof (GtkFileChooserDialogPrivate));
80 }
81
82 static void
83 gtk_file_chooser_dialog_init (GtkFileChooserDialog *dialog)
84 {
85   GtkFileChooserDialogPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (dialog,
86                                                                    GTK_TYPE_FILE_CHOOSER_DIALOG,
87                                                                    GtkFileChooserDialogPrivate);
88   dialog->priv = priv;
89   dialog->priv->default_width = -1;
90   dialog->priv->default_height = -1;
91   dialog->priv->resize_horizontally = TRUE;
92   dialog->priv->resize_vertically = TRUE;
93   dialog->priv->response_requested = FALSE;
94
95   gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
96
97   /* We do a signal connection here rather than overriding the method in
98    * class_init because GtkDialog::response is a RUN_LAST signal.  We want *our*
99    * handler to be run *first*, regardless of whether the user installs response
100    * handlers of his own.
101    */
102   g_signal_connect (dialog, "response",
103                     G_CALLBACK (response_cb), NULL);
104 }
105
106 static void
107 gtk_file_chooser_dialog_finalize (GObject *object)
108 {
109   GtkFileChooserDialog *dialog = GTK_FILE_CHOOSER_DIALOG (object);
110
111   g_free (dialog->priv->file_system);
112
113   G_OBJECT_CLASS (gtk_file_chooser_dialog_parent_class)->finalize (object);  
114 }
115
116 /* Callback used when the user activates a file in the file chooser widget */
117 static void
118 file_chooser_widget_file_activated (GtkFileChooser       *chooser,
119                                     GtkFileChooserDialog *dialog)
120 {
121   GList *children, *l;
122
123   if (gtk_window_activate_default (GTK_WINDOW (dialog)))
124     return;
125
126   /* There probably isn't a default widget, so make things easier for the
127    * programmer by looking for a reasonable button on our own.
128    */
129
130   children = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
131
132   for (l = children; l; l = l->next)
133     {
134       GtkWidget *widget;
135       int response_id;
136
137       widget = GTK_WIDGET (l->data);
138       response_id = gtk_dialog_get_response_for_widget (GTK_DIALOG (dialog), widget);
139       if (response_id == GTK_RESPONSE_ACCEPT
140           || response_id == GTK_RESPONSE_OK
141           || response_id == GTK_RESPONSE_YES
142           || response_id == GTK_RESPONSE_APPLY)
143         {
144           gtk_widget_activate (widget); /* Should we gtk_dialog_response (dialog, response_id) instead? */
145           break;
146         }
147     }
148
149   g_list_free (children);
150 }
151
152 static void
153 file_chooser_widget_update_hints (GtkFileChooserDialog *dialog)
154 {
155   GtkFileChooserDialogPrivate *priv;
156   GdkGeometry geometry;
157
158   priv = GTK_FILE_CHOOSER_DIALOG_GET_PRIVATE (dialog);
159
160   geometry.min_width = -1;
161   geometry.min_height = -1;
162   geometry.max_width = (priv->resize_horizontally?G_MAXSHORT:-1);
163   geometry.max_height = (priv->resize_vertically?G_MAXSHORT:-1);
164
165   gtk_window_set_geometry_hints (GTK_WINDOW (dialog), NULL,
166                                  &geometry,
167                                  GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE);
168 }
169
170 static void
171 clamp_to_screen (GtkWidget *widget,
172                  gint      *width,
173                  gint      *height)
174 {
175   GdkScreen *screen;
176   int monitor_num;
177   GdkRectangle monitor;
178
179   g_return_if_fail (GTK_WIDGET_REALIZED (widget));
180   
181   screen = gtk_widget_get_screen (widget);
182   monitor_num = gdk_screen_get_monitor_at_window (screen, widget->window);
183
184   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
185
186   if (width)
187     *width = MIN (*width, (monitor.width * 3) / 4);
188
189   if (height)
190     *height = MIN (*height, (monitor.height * 3) / 4);
191 }
192
193 static void
194 file_chooser_widget_default_realized_size_changed (GtkWidget            *widget,
195                                                    GtkFileChooserDialog *dialog)
196 {
197   GtkFileChooserDialogPrivate *priv;
198   gint width;
199   gint height;
200   gint default_width, default_height;
201   GtkRequisition req;
202   gboolean resize_horizontally;
203   gboolean resize_vertically;
204   gboolean update_hints;
205   gint dx = 0, dy = 0;
206   gint cur_width, cur_height;
207
208   priv = GTK_FILE_CHOOSER_DIALOG_GET_PRIVATE (dialog);
209
210   /* Force a size request of everything before we start.  This will make sure
211    * that widget->requisition is meaningful. */
212   gtk_widget_size_request (GTK_WIDGET (dialog), &req);
213   gtk_window_get_size (GTK_WINDOW (dialog), &cur_width, &cur_height);
214   width = GTK_WIDGET (dialog)->requisition.width - priv->widget->requisition.width;
215   height = GTK_WIDGET (dialog)->requisition.height - priv->widget->requisition.height;
216   _gtk_file_chooser_embed_get_default_size (GTK_FILE_CHOOSER_EMBED (priv->widget),
217                                             &default_width, &default_height);
218
219   /* Ideal target size modulo any resizing */
220   width = default_width + width;
221   height = default_height + height;
222
223   /* Now, we test for resizability */
224   update_hints = FALSE;
225   _gtk_file_chooser_embed_get_resizable_hints (GTK_FILE_CHOOSER_EMBED (priv->widget),
226                                                &resize_horizontally,
227                                                &resize_vertically);
228   resize_vertically = (!! resize_vertically);     /* normalize */
229   resize_horizontally = (!! resize_horizontally);
230
231   if (resize_horizontally && priv->resize_horizontally)
232     {
233       dx = default_width - priv->default_width;
234       priv->default_width = default_width;
235     }
236   else if (resize_horizontally && ! priv->resize_horizontally)
237     {
238       /* We restore to the ideal size + any change in default_size (which is not
239        * expected).  It would be nicer to store the older size to restore to in
240        * the future. */
241       dx = default_width - priv->default_width;
242       dx += width - cur_width;
243       priv->default_width = default_width;
244       update_hints = TRUE;
245     }
246   else
247     {
248       update_hints = TRUE;
249     }
250   
251   if (resize_vertically && priv->resize_vertically)
252     {
253       dy = default_height - priv->default_height;
254       priv->default_height = default_height;
255     }
256   else if (resize_vertically && ! priv->resize_vertically)
257     {
258       dy = default_height - priv->default_height;
259       dy += height - cur_height;
260       priv->default_height = default_height;
261       update_hints = TRUE;
262     }
263   else
264     {
265       update_hints = TRUE;
266     }
267
268   priv->resize_horizontally = resize_horizontally;
269   priv->resize_vertically = resize_vertically;
270
271   if (dx != 0 || dy != 0)
272     {
273       gint new_width = cur_width + dx;
274       gint new_height = cur_height + dy;
275
276       clamp_to_screen (GTK_WIDGET (dialog), &new_width, &new_height);
277       
278       gtk_window_resize (GTK_WINDOW (dialog), new_width, new_height);
279     }
280
281   /* Only store the size if we can resize in that direction. */
282   if (update_hints)
283     file_chooser_widget_update_hints (dialog);
284 }
285
286 static void
287 file_chooser_widget_default_unrealized_size_changed (GtkWidget            *widget,
288                                                      GtkFileChooserDialog *dialog)
289 {
290   GtkFileChooserDialogPrivate *priv;
291   GtkRequisition req;
292   gint width, height;
293
294   priv = GTK_FILE_CHOOSER_DIALOG_GET_PRIVATE (dialog);
295   gtk_widget_size_request (GTK_WIDGET (dialog), &req);
296
297   _gtk_file_chooser_embed_get_resizable_hints (GTK_FILE_CHOOSER_EMBED (priv->widget),
298                                                &(priv->resize_horizontally),
299                                                &(priv->resize_vertically));
300   _gtk_file_chooser_embed_get_default_size (GTK_FILE_CHOOSER_EMBED (priv->widget),
301                                             &(priv->default_width), &(priv->default_height));
302   
303   /* Determine how much space the rest of the dialog uses compared to priv->widget */
304   width = priv->default_width + GTK_WIDGET (dialog)->requisition.width - priv->widget->requisition.width;
305   height = priv->default_height + GTK_WIDGET (dialog)->requisition.height - priv->widget->requisition.height;
306
307   gtk_window_set_default_size (GTK_WINDOW (dialog), width, height);
308   file_chooser_widget_update_hints (dialog);
309 }
310
311 static void
312 file_chooser_widget_default_size_changed (GtkWidget            *widget,
313                                           GtkFileChooserDialog *dialog)
314 {
315   if (GTK_WIDGET_REALIZED (dialog))
316     file_chooser_widget_default_realized_size_changed (widget, dialog);
317   else
318     file_chooser_widget_default_unrealized_size_changed (widget, dialog);
319 }
320
321 static void
322 file_chooser_widget_response_requested (GtkWidget            *widget,
323                                         GtkFileChooserDialog *dialog)
324 {
325   GList *children, *l;
326
327   /* There probably isn't a default widget, so make things easier for the
328    * programmer by looking for a reasonable button on our own.
329    */
330
331   children = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
332
333   for (l = children; l; l = l->next)
334     {
335       GtkWidget *widget;
336       int response_id;
337
338       widget = GTK_WIDGET (l->data);
339       response_id = gtk_dialog_get_response_for_widget (GTK_DIALOG (dialog), widget);
340       if (response_id == GTK_RESPONSE_ACCEPT
341           || response_id == GTK_RESPONSE_OK
342           || response_id == GTK_RESPONSE_YES
343           || response_id == GTK_RESPONSE_APPLY)
344         {
345           dialog->priv->response_requested = TRUE;
346           gtk_widget_activate (widget); /* Should we gtk_dialog_response (dialog, response_id) instead? */
347           break;
348         }
349     }
350
351   g_list_free (children);
352 }
353   
354 static GObject*
355 gtk_file_chooser_dialog_constructor (GType                  type,
356                                      guint                  n_construct_properties,
357                                      GObjectConstructParam *construct_params)
358 {
359   GtkFileChooserDialogPrivate *priv;
360   GObject *object;
361
362   object = G_OBJECT_CLASS (gtk_file_chooser_dialog_parent_class)->constructor (type,
363                                                                                n_construct_properties,
364                                                                                construct_params);
365   priv = GTK_FILE_CHOOSER_DIALOG_GET_PRIVATE (object);
366
367   gtk_widget_push_composite_child ();
368
369   if (priv->file_system)
370     priv->widget = g_object_new (GTK_TYPE_FILE_CHOOSER_WIDGET,
371                                  "file-system-backend", priv->file_system,
372                                  NULL);
373   else
374     priv->widget = g_object_new (GTK_TYPE_FILE_CHOOSER_WIDGET, NULL);
375
376   g_signal_connect (priv->widget, "file-activated",
377                     G_CALLBACK (file_chooser_widget_file_activated), object);
378   g_signal_connect (priv->widget, "default-size-changed",
379                     G_CALLBACK (file_chooser_widget_default_size_changed), object);
380   g_signal_connect (priv->widget, "response-requested",
381                     G_CALLBACK (file_chooser_widget_response_requested), object);
382
383   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (object)->vbox), priv->widget, TRUE, TRUE, 0);
384
385   gtk_widget_show (priv->widget);
386
387   _gtk_file_chooser_set_delegate (GTK_FILE_CHOOSER (object),
388                                   GTK_FILE_CHOOSER (priv->widget));
389
390   gtk_widget_pop_composite_child ();
391
392   return object;
393 }
394
395 static void
396 gtk_file_chooser_dialog_set_property (GObject         *object,
397                                       guint            prop_id,
398                                       const GValue    *value,
399                                       GParamSpec      *pspec)
400
401 {
402   GtkFileChooserDialogPrivate *priv = GTK_FILE_CHOOSER_DIALOG_GET_PRIVATE (object);
403
404   switch (prop_id)
405     {
406     case GTK_FILE_CHOOSER_PROP_FILE_SYSTEM_BACKEND:
407       g_free (priv->file_system);
408       priv->file_system = g_value_dup_string (value);
409       break;
410     default:
411       g_object_set_property (G_OBJECT (priv->widget), pspec->name, value);
412       break;
413     }
414 }
415
416 static void
417 gtk_file_chooser_dialog_get_property (GObject         *object,
418                                       guint            prop_id,
419                                       GValue          *value,
420                                       GParamSpec      *pspec)
421 {
422   GtkFileChooserDialogPrivate *priv = GTK_FILE_CHOOSER_DIALOG_GET_PRIVATE (object);
423
424   g_object_get_property (G_OBJECT (priv->widget), pspec->name, value);
425 }
426
427 #if 0
428 static void
429 set_default_size (GtkFileChooserDialog *dialog)
430 {
431   GtkWidget *widget;
432   GtkWindow *window;
433   int default_width, default_height;
434   int width, height;
435   int font_size;
436   GdkScreen *screen;
437   int monitor_num;
438   GtkRequisition req;
439   GdkRectangle monitor;
440
441   widget = GTK_WIDGET (dialog);
442   window = GTK_WINDOW (dialog);
443
444   /* Size based on characters */
445
446   font_size = pango_font_description_get_size (widget->style->font_desc);
447   font_size = PANGO_PIXELS (font_size);
448
449   width = font_size * NUM_CHARS;
450   height = font_size * NUM_LINES;
451
452   /* Use at least the requisition size... */
453
454   gtk_widget_size_request (widget, &req);
455   width = MAX (width, req.width);
456   height = MAX (height, req.height);
457
458   /* ... but no larger than the monitor */
459
460   screen = gtk_widget_get_screen (widget);
461   monitor_num = gdk_screen_get_monitor_at_window (screen, widget->window);
462
463   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
464
465   width = MIN (width, monitor.width * 3 / 4);
466   height = MIN (height, monitor.height * 3 / 4);
467
468   /* Set size */
469
470   gtk_window_get_default_size (window, &default_width, &default_height);
471
472   gtk_window_set_default_size (window,
473                                (default_width == -1) ? width : default_width,
474                                (default_height == -1) ? height : default_height);
475 }
476 #endif
477
478 /* GtkWidget::map handler */
479 static void
480 gtk_file_chooser_dialog_map (GtkWidget *widget)
481 {
482   GtkFileChooserDialog *dialog = GTK_FILE_CHOOSER_DIALOG (widget);
483   GtkFileChooserDialogPrivate *priv = GTK_FILE_CHOOSER_DIALOG_GET_PRIVATE (dialog);
484
485   if (!GTK_WIDGET_MAPPED (priv->widget))
486     gtk_widget_map (priv->widget);
487
488   _gtk_file_chooser_embed_initial_focus (GTK_FILE_CHOOSER_EMBED (priv->widget));
489
490   GTK_WIDGET_CLASS (gtk_file_chooser_dialog_parent_class)->map (widget);
491 }
492
493 /* GtkWidget::unmap handler */
494 static void
495 gtk_file_chooser_dialog_unmap (GtkWidget *widget)
496 {
497   GtkFileChooserDialog *dialog = GTK_FILE_CHOOSER_DIALOG (widget);
498   GtkFileChooserDialogPrivate *priv = GTK_FILE_CHOOSER_DIALOG_GET_PRIVATE (dialog);
499
500   GTK_WIDGET_CLASS (gtk_file_chooser_dialog_parent_class)->unmap (widget);
501
502   /* See bug #145470.  We unmap the GtkFileChooserWidget so that if the dialog
503    * is remapped, the widget will be remapped as well.  Implementations should
504    * refresh their contents when this happens, as some applications keep a
505    * single file chooser alive and map/unmap it as needed, rather than creating
506    * a new file chooser every time they need one.
507    */
508   gtk_widget_unmap (priv->widget);
509 }
510
511 static void
512 gtk_file_chooser_dialog_style_set (GtkWidget *widget,
513                                    GtkStyle  *previous_style)
514 {
515   GtkDialog *dialog;
516
517   if (GTK_WIDGET_CLASS (gtk_file_chooser_dialog_parent_class)->style_set)
518     GTK_WIDGET_CLASS (gtk_file_chooser_dialog_parent_class)->style_set (widget, previous_style);
519
520   dialog = GTK_DIALOG (widget);
521
522   /* Override the style properties with HIG-compliant spacings.  Ugh.
523    * http://developer.gnome.org/projects/gup/hig/1.0/layout.html#layout-dialogs
524    * http://developer.gnome.org/projects/gup/hig/1.0/windows.html#alert-spacing
525    */
526
527   gtk_container_set_border_width (GTK_CONTAINER (dialog->vbox), 12);
528   gtk_box_set_spacing (GTK_BOX (dialog->vbox), 24);
529
530   gtk_container_set_border_width (GTK_CONTAINER (dialog->action_area), 0);
531   gtk_box_set_spacing (GTK_BOX (dialog->action_area), 6);
532 }
533
534 /* GtkDialog::response handler */
535 static void
536 response_cb (GtkDialog *dialog,
537              gint       response_id)
538 {
539   GtkFileChooserDialogPrivate *priv;
540
541   priv = GTK_FILE_CHOOSER_DIALOG_GET_PRIVATE (dialog);
542
543   /* Act only on response IDs we recognize */
544   if (!(response_id == GTK_RESPONSE_ACCEPT
545         || response_id == GTK_RESPONSE_OK
546         || response_id == GTK_RESPONSE_YES
547         || response_id == GTK_RESPONSE_APPLY))
548     return;
549
550   if (!priv->response_requested && !_gtk_file_chooser_embed_should_respond (GTK_FILE_CHOOSER_EMBED (priv->widget)))
551     {
552       g_signal_stop_emission_by_name (dialog, "response");
553       priv->response_requested = FALSE;
554     }
555 }
556
557 static GtkWidget *
558 gtk_file_chooser_dialog_new_valist (const gchar          *title,
559                                     GtkWindow            *parent,
560                                     GtkFileChooserAction  action,
561                                     const gchar          *backend,
562                                     const gchar          *first_button_text,
563                                     va_list               varargs)
564 {
565   GtkWidget *result;
566   const char *button_text = first_button_text;
567   gint response_id;
568
569   result = g_object_new (GTK_TYPE_FILE_CHOOSER_DIALOG,
570                          "title", title,
571                          "action", action,
572                          "file-system-backend", backend,
573                          NULL);
574
575   if (parent)
576     gtk_window_set_transient_for (GTK_WINDOW (result), parent);
577
578   while (button_text)
579     {
580       response_id = va_arg (varargs, gint);
581       gtk_dialog_add_button (GTK_DIALOG (result), button_text, response_id);
582       button_text = va_arg (varargs, const gchar *);
583     }
584
585   return result;
586 }
587
588 /**
589  * gtk_file_chooser_dialog_new:
590  * @title: Title of the dialog, or %NULL
591  * @parent: Transient parent of the dialog, or %NULL
592  * @action: Open or save mode for the dialog
593  * @first_button_text: stock ID or text to go in the first button, or %NULL
594  * @Varargs: response ID for the first button, then additional (button, id) pairs, ending with %NULL
595  *
596  * Creates a new #GtkFileChooserDialog.  This function is analogous to
597  * gtk_dialog_new_with_buttons().
598  *
599  * Return value: a new #GtkFileChooserDialog
600  *
601  * Since: 2.4
602  **/
603 GtkWidget *
604 gtk_file_chooser_dialog_new (const gchar         *title,
605                              GtkWindow           *parent,
606                              GtkFileChooserAction action,
607                              const gchar         *first_button_text,
608                              ...)
609 {
610   GtkWidget *result;
611   va_list varargs;
612   
613   va_start (varargs, first_button_text);
614   result = gtk_file_chooser_dialog_new_valist (title, parent, action,
615                                                NULL, first_button_text,
616                                                varargs);
617   va_end (varargs);
618
619   return result;
620 }
621
622 /**
623  * gtk_file_chooser_dialog_new_with_backend:
624  * @title: Title of the dialog, or %NULL
625  * @parent: Transient parent of the dialog, or %NULL
626  * @action: Open or save mode for the dialog
627  * @backend: The name of the specific filesystem backend to use.
628  * @first_button_text: stock ID or text to go in the first button, or %NULL
629  * @Varargs: response ID for the first button, then additional (button, id) pairs, ending with %NULL
630  *
631  * Creates a new #GtkFileChooserDialog with a specified backend. This is
632  * especially useful if you use gtk_file_chooser_set_local_only() to allow
633  * non-local files and you use a more expressive vfs, such as gnome-vfs,
634  * to load files.
635  *
636  * Return value: a new #GtkFileChooserDialog
637  *
638  * Since: 2.4
639  **/
640 GtkWidget *
641 gtk_file_chooser_dialog_new_with_backend (const gchar          *title,
642                                           GtkWindow            *parent,
643                                           GtkFileChooserAction  action,
644                                           const gchar          *backend,
645                                           const gchar          *first_button_text,
646                                           ...)
647 {
648   GtkWidget *result;
649   va_list varargs;
650   
651   va_start (varargs, first_button_text);
652   result = gtk_file_chooser_dialog_new_valist (title, parent, action,
653                                                backend, first_button_text,
654                                                varargs);
655   va_end (varargs);
656
657   return result;
658 }
659
660 #define __GTK_FILE_CHOOSER_DIALOG_C__
661 #include "gtkaliasdef.c"