1 /*
2  * This file is part of gedit
3  *
4  * Copyright (C) 2020 Sébastien Wilmet <swilmet@gnome.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program 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
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "gedit-file-chooser.h"
21 #include <glib/gi18n.h>
22 #include "gedit-settings.h"
23 
24 /* Common code between the different GeditFileChooser's. */
25 
26 struct _GeditFileChooserPrivate
27 {
28 	GtkFileChooser *gtk_chooser;
29 };
30 
31 enum
32 {
33 	SIGNAL_DONE,
34 	N_SIGNALS
35 };
36 
37 static guint signals[N_SIGNALS];
38 
G_DEFINE_TYPE_WITH_PRIVATE(GeditFileChooser,_gedit_file_chooser,G_TYPE_OBJECT)39 G_DEFINE_TYPE_WITH_PRIVATE (GeditFileChooser, _gedit_file_chooser, G_TYPE_OBJECT)
40 
41 #define ALL_FILES		_("All Files")
42 #define ALL_TEXT_FILES		_("All Text Files")
43 
44 /* Whether to use GtkFileChooserNative or GtkFileChooserDialog. */
45 gboolean
46 _gedit_file_chooser_is_native (void)
47 {
48 	/* TODO: finish the implementation of the native variants. */
49 	return FALSE;
50 }
51 
52 static gboolean
mime_types_are_supported(void)53 mime_types_are_supported (void)
54 {
55 /* Note that the #ifdef could be moved to where this function is called, to have
56  * much more code between the #ifdef/#else/#endif. The goal is to always compile
57  * all the code on all platforms, to catch compilation problems earlier.
58  */
59 #ifdef G_OS_WIN32
60 	/* See the GtkFileChooserNative documentation, a GtkFileFilter with
61 	 * mime-types is not supported on Windows.
62 	 */
63 	return FALSE;
64 #else
65 	return TRUE;
66 #endif
67 }
68 
69 /* Returns: (transfer none) (element-type utf8): a list containing "text/plain"
70  * first and then the list of mime-types unrelated to "text/plain" that
71  * GtkSourceView supports for the syntax highlighting.
72  */
73 static GSList *
get_supported_mime_types(void)74 get_supported_mime_types (void)
75 {
76 	static GSList *supported_mime_types = NULL;
77 	static gboolean initialized = FALSE;
78 
79 	GtkSourceLanguageManager *language_manager;
80 	const gchar * const *language_ids;
81 	gint language_num;
82 
83 	if (initialized)
84 	{
85 		return supported_mime_types;
86 	}
87 
88 	language_manager = gtk_source_language_manager_get_default ();
89 	language_ids = gtk_source_language_manager_get_language_ids (language_manager);
90 	for (language_num = 0; language_ids != NULL && language_ids[language_num] != NULL; language_num++)
91 	{
92 		const gchar *cur_language_id = language_ids[language_num];
93 		GtkSourceLanguage *language;
94 		gchar **mime_types;
95 		gint mime_type_num;
96 
97 		language = gtk_source_language_manager_get_language (language_manager, cur_language_id);
98 		mime_types = gtk_source_language_get_mime_types (language);
99 
100 		if (mime_types == NULL)
101 		{
102 			continue;
103 		}
104 
105 		for (mime_type_num = 0; mime_types[mime_type_num] != NULL; mime_type_num++)
106 		{
107 			const gchar *cur_mime_type = mime_types[mime_type_num];
108 
109 			if (!g_content_type_is_a (cur_mime_type, "text/plain"))
110 			{
111 				//g_message ("Mime-type '%s' is not related to 'text/plain'", cur_mime_type);
112 				supported_mime_types = g_slist_prepend (supported_mime_types,
113 									g_strdup (cur_mime_type));
114 			}
115 		}
116 
117 		g_strfreev (mime_types);
118 	}
119 
120 	// Note that all "text/*" mime-types are subclasses of "text/plain", see:
121 	// https://specifications.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html#subclassing
122 	supported_mime_types = g_slist_prepend (supported_mime_types, g_strdup ("text/plain"));
123 
124 	initialized = TRUE;
125 	return supported_mime_types;
126 }
127 
128 static const gchar * const *
get_supported_globs(void)129 get_supported_globs (void)
130 {
131 	/* List generated with Tepl's shared-mime-info-list-text-plain-globs
132 	 * tool.
133 	 *
134 	 * TODO: can be improved by including globs from GtkSourceLanguage's.
135 	 */
136 	static const gchar * const supported_globs[] =
137 	{
138 		"*.abw",
139 		"*.adb",
140 		"*.ads",
141 		"*.al",
142 		"*.asc",
143 		"*.asp",
144 		"*.ass",
145 		"*.atom",
146 		"*.automount",
147 		"*.awk",
148 		"*.bib",
149 		"*.build",
150 		"*.c",
151 		"*.c++",
152 		"*.cbl",
153 		"*.cc",
154 		"*.ccmx",
155 		"*.cl",
156 		"*.cls",
157 		"*.cmake",
158 		"*.cob",
159 		"*.coffee",
160 		"*.cpp",
161 		"*.cs",
162 		"*.csh",
163 		"*.css",
164 		"*.csv",
165 		"*.csvs",
166 		"*.cue",
167 		"*.cxx",
168 		"*.d",
169 		"*.dbk",
170 		"*.dcl",
171 		"*.desktop",
172 		"*.device",
173 		"*.di",
174 		"*.dia",
175 		"*.diff",
176 		"*.docbook",
177 		"*.dot",
178 		"*.dsl",
179 		"*.dtd",
180 		"*.dtx",
181 		"*.e",
182 		"*.eif",
183 		"*.el",
184 		"*.eml",
185 		"*.ent",
186 		"*.eps",
187 		"*.epsf",
188 		"*.epsi",
189 		"*.erl",
190 		"*.es",
191 		"*.etx",
192 		"*.f",
193 		"*.f90",
194 		"*.f95",
195 		"*.fb2",
196 		"*.feature",
197 		"*.fl",
198 		"*.flatpakref",
199 		"*.flatpakrepo",
200 		"*.fo",
201 		"*.fodg",
202 		"*.fodp",
203 		"*.fods",
204 		"*.fodt",
205 		"*.for",
206 		"*.gcode",
207 		"*.gcrd",
208 		"*.geojson",
209 		"*.glade",
210 		"*.gml",
211 		"*.gnuplot",
212 		"*.go",
213 		"*.gp",
214 		"*.gpg",
215 		"*.gplt",
216 		"*.gpx",
217 		"*.gradle",
218 		"*.groovy",
219 		"*.gs",
220 		"*.gsf",
221 		"*.gsh",
222 		"*.gv",
223 		"*.gvp",
224 		"*.gvy",
225 		"*.gy",
226 		"*.h",
227 		"*.h++",
228 		"*.hh",
229 		"*.hp",
230 		"*.hpp",
231 		"*.hs",
232 		"*.htm",
233 		"*.html",
234 		"*.hxx",
235 		"*.ica",
236 		"*.ics",
237 		"*.idl",
238 		"*.iges",
239 		"*.igs",
240 		"*.ime",
241 		"*.imy",
242 		"*.ins",
243 		"*.iptables",
244 		"*.ipynb",
245 		"*.it87",
246 		"*.jad",
247 		"*.java",
248 		"*.jnlp",
249 		"*.jrd",
250 		"*.js",
251 		"*.jsm",
252 		"*.json",
253 		"*.jsonld",
254 		"*.json-patch",
255 		"*.kdelnk",
256 		"*.key",
257 		"*.kino",
258 		"*.kml",
259 		"*.la",
260 		"*.latex",
261 		"*.ldif",
262 		"*.lhs",
263 		"*.log",
264 		"*.ltx",
265 		"*.lua",
266 		"*.ly",
267 		"*.lyx",
268 		"*.m",
269 		"*.m1u",
270 		"*.m3u",
271 		"*.m3u8",
272 		"*.m4",
273 		"*.m4u",
274 		"*.mab",
275 		"*.mak",
276 		"*.man",
277 		"*.manifest",
278 		"*.markdown",
279 		"*.mbox",
280 		"*.mc2",
281 		"*.md",
282 		"*.me",
283 		"*.meta4",
284 		"*.metalink",
285 		"*.mgp",
286 		"*.mjs",
287 		"*.mk",
288 		"*.mkd",
289 		"*.ml",
290 		"*.mli",
291 		"*.mm",
292 		"*.mml",
293 		"*.mo",
294 		"*.moc",
295 		"*.mof",
296 		"*.mount",
297 		"*.mrl",
298 		"*.mrml",
299 		"*.ms",
300 		"*.mup",
301 		"*.mxu",
302 		"*.nb",
303 		"*.nfo",
304 		"*.not",
305 		"*.nzb",
306 		"*.ocl",
307 		"*.ooc",
308 		"*.opml",
309 		"*.owl",
310 		"*.owx",
311 		"*.p",
312 		"*.p7s",
313 		"*.pas",
314 		"*.patch",
315 		"*.path",
316 		"*.perl",
317 		"*.pfa",
318 		"*.pfb",
319 		"*.pgn",
320 		"*.pgp",
321 		"*.php",
322 		"*.php3",
323 		"*.php4",
324 		"*.php5",
325 		"*.phps",
326 		"*.pkr",
327 		"*.pl",
328 		"*.pm",
329 		"*.po",
330 		"*.pod",
331 		"*.pot",
332 		"*.ps",
333 		"*.py",
334 		"*.py3",
335 		"*.py3x",
336 		"*.pyx",
337 		"*.qml",
338 		"*.qmlproject",
339 		"*.qmltypes",
340 		"*.qti",
341 		"*.raml",
342 		"*.rb",
343 		"*.rdf",
344 		"*.rdfs",
345 		"*.rej",
346 		"*.rnc",
347 		"*.rng",
348 		"*.roff",
349 		"*.rs",
350 		"*.rss",
351 		"*.rst",
352 		"*.rt",
353 		"*.rtf",
354 		"*.rtx",
355 		"*.sami",
356 		"*.sass",
357 		"*.scala",
358 		"*.scm",
359 		"*.scope",
360 		"*.scss",
361 		"*.sdp",
362 		"*.service",
363 		"*.sgf",
364 		"*.sgm",
365 		"*.sgml",
366 		"*.sh",
367 		"*.shape",
368 		"*.sig",
369 		"*.siv",
370 		"*.skr",
371 		"*.slice",
372 		"*.slk",
373 		"*.smi",
374 		"*.smil",
375 		"*.sml",
376 		"*.socket",
377 		"*.spec",
378 		"*.sql",
379 		"*.src",
380 		"*.srt",
381 		"*.ss",
382 		"*.ssa",
383 		"*.sty",
384 		"*.sub",
385 		"*.sv",
386 		"*.svg",
387 		"*.svh",
388 		"*.swap",
389 		"*.sylk",
390 		"*.t",
391 		"*.t2t",
392 		"*.target",
393 		"*.tcl",
394 		"*.tex",
395 		"*.texi",
396 		"*.texinfo",
397 		"*.theme",
398 		"*.timer",
399 		"*.tk",
400 		"*.toc",
401 		"*.tr",
402 		"*.trig",
403 		"*.ts",
404 		"*.tsv",
405 		"*.ttl",
406 		"*.ttx",
407 		"*.twig",
408 		"*.txt",
409 		"*.ufraw",
410 		"*.ui",
411 		"*.uil",
412 		"*.uue",
413 		"*.v",
414 		"*.vala",
415 		"*.vapi",
416 		"*.vcard",
417 		"*.vcf",
418 		"*.vcs",
419 		"*.vct",
420 		"*.vhd",
421 		"*.vhdl",
422 		"*.vlc",
423 		"*.vrm",
424 		"*.vrml",
425 		"*.vtt",
426 		"*.wml",
427 		"*.wmls",
428 		"*.wrl",
429 		"*.wsgi",
430 		"*.xbel",
431 		"*.xbl",
432 		"*.xht",
433 		"*.xhtml",
434 		"*.xlf",
435 		"*.xliff",
436 		"*.xmi",
437 		"*.xml",
438 		"*.xsd",
439 		"*.xsl",
440 		"*.xslfo",
441 		"*.xslt",
442 		"*.xspf",
443 		"*.xul",
444 		"*.yaml",
445 		"*.yml",
446 		"*.zabw",
447 		NULL
448 	};
449 
450 	return supported_globs;
451 }
452 
453 static GtkFileFilter *
create_all_text_files_filter(void)454 create_all_text_files_filter (void)
455 {
456 	GtkFileFilter *filter;
457 
458 	filter = gtk_file_filter_new ();
459 	gtk_file_filter_set_name (filter, ALL_TEXT_FILES);
460 
461 	if (mime_types_are_supported ())
462 	{
463 		GSList *supported_mime_types;
464 		GSList *l;
465 
466 		supported_mime_types = get_supported_mime_types ();
467 		for (l = supported_mime_types; l != NULL; l = l->next)
468 		{
469 			const gchar *mime_type = l->data;
470 
471 			gtk_file_filter_add_mime_type (filter, mime_type);
472 		}
473 
474 		/* FIXME: use globs too - Paolo (Aug. 27, 2007).
475 		 *
476 		 * Yes, use globs too - swilmet (June 2020). Get the list of
477 		 * globs from GtkSourceLanguage's, and add them to the filter
478 		 * (only those that are not covered by a previously added
479 		 * mime-type). Note that the list of extra globs here must be
480 		 * computed differently than the list of extra globs for
481 		 * get_supported_globs() (see the TODO comment there).
482 		 */
483 	}
484 	else
485 	{
486 		const gchar * const *supported_globs;
487 		gint i;
488 
489 		supported_globs = get_supported_globs ();
490 		for (i = 0; supported_globs != NULL && supported_globs[i] != NULL; i++)
491 		{
492 			const gchar *glob = supported_globs[i];
493 
494 			gtk_file_filter_add_pattern (filter, glob);
495 		}
496 	}
497 
498 	return filter;
499 }
500 
501 static void
notify_filter_cb(GtkFileChooser * gtk_chooser,GParamSpec * pspec,gpointer user_data)502 notify_filter_cb (GtkFileChooser *gtk_chooser,
503 		  GParamSpec     *pspec,
504 		  gpointer        user_data)
505 {
506 	GtkFileFilter *filter;
507 	const gchar *name;
508 	gint id = 0;
509 	GeditSettings *settings;
510 	GSettings *file_chooser_state_settings;
511 
512 	/* Remember the selected filter. */
513 
514 	filter = gtk_file_chooser_get_filter (gtk_chooser);
515 	if (filter == NULL)
516 	{
517 		return;
518 	}
519 
520 	name = gtk_file_filter_get_name (filter);
521 	if (g_strcmp0 (name, ALL_FILES) == 0)
522 	{
523 		id = 1;
524 	}
525 
526 	settings = _gedit_settings_get_singleton ();
527 	file_chooser_state_settings = _gedit_settings_peek_file_chooser_state_settings (settings);
528 	g_settings_set_int (file_chooser_state_settings, GEDIT_SETTINGS_ACTIVE_FILE_FILTER, id);
529 }
530 
531 static void
setup_filters(GeditFileChooser * chooser)532 setup_filters (GeditFileChooser *chooser)
533 {
534 	GeditSettings *settings;
535 	GSettings *file_chooser_state_settings;
536 	gint active_filter;
537 	GtkFileFilter *filter;
538 
539 	settings = _gedit_settings_get_singleton ();
540 	file_chooser_state_settings = _gedit_settings_peek_file_chooser_state_settings (settings);
541 	active_filter = g_settings_get_int (file_chooser_state_settings, GEDIT_SETTINGS_ACTIVE_FILE_FILTER);
542 
543 	/* "All Text Files" filter */
544 	filter = create_all_text_files_filter ();
545 
546 	g_object_ref_sink (filter);
547 	gtk_file_chooser_add_filter (chooser->priv->gtk_chooser, filter);
548 	if (active_filter != 1)
549 	{
550 		/* Use this filter if set by user and as default. */
551 		gtk_file_chooser_set_filter (chooser->priv->gtk_chooser, filter);
552 	}
553 	g_object_unref (filter);
554 
555 	/* "All Files" filter */
556 	filter = gtk_file_filter_new ();
557 	gtk_file_filter_set_name (filter, ALL_FILES);
558 	gtk_file_filter_add_pattern (filter, "*");
559 
560 	g_object_ref_sink (filter);
561 	gtk_file_chooser_add_filter (chooser->priv->gtk_chooser, filter);
562 	if (active_filter == 1)
563 	{
564 		/* Use this filter if set by user. */
565 		gtk_file_chooser_set_filter (chooser->priv->gtk_chooser, filter);
566 	}
567 	g_object_unref (filter);
568 
569 	g_signal_connect (chooser->priv->gtk_chooser,
570 			  "notify::filter",
571 			  G_CALLBACK (notify_filter_cb),
572 			  NULL);
573 }
574 
575 /* Set the dialog as modal. It's a workaround for this bug:
576  * https://gitlab.gnome.org/GNOME/gtk/issues/2824
577  * "GtkNativeDialog: non-modal and gtk_native_dialog_show(), doesn't present the
578  * window"
579  *
580  * - For opening files: drag-and-drop files from the file chooser to the
581  *   GeditWindow: OK, it still works.
582  * - Other main windows not being "blocked"/insensitive (GtkWindowGroup): OK,
583  *   calling gtk_native_dialog_set_transient_for() does the right thing.
584  *
585  * Even if the above GTK bug is fixed, the file chooser can be kept modal,
586  * except if there was a good reason for not being modal (what reason(s)?).
587  */
588 static void
set_modal(GeditFileChooser * chooser)589 set_modal (GeditFileChooser *chooser)
590 {
591 	if (_gedit_file_chooser_is_native ())
592 	{
593 		gtk_native_dialog_set_modal (GTK_NATIVE_DIALOG (chooser->priv->gtk_chooser), TRUE);
594 	}
595 	else
596 	{
597 		gtk_window_set_modal (GTK_WINDOW (chooser->priv->gtk_chooser), TRUE);
598 	}
599 }
600 
601 static void
response_cb(GtkFileChooser * gtk_chooser,gint response_id,GeditFileChooser * chooser)602 response_cb (GtkFileChooser   *gtk_chooser,
603 	     gint              response_id,
604 	     GeditFileChooser *chooser)
605 {
606 	gboolean accept;
607 
608 	accept = response_id == GTK_RESPONSE_ACCEPT;
609 	g_signal_emit (chooser, signals[SIGNAL_DONE], 0, accept);
610 }
611 
612 static void
_gedit_file_chooser_constructed(GObject * object)613 _gedit_file_chooser_constructed (GObject *object)
614 {
615 	GeditFileChooser *chooser = GEDIT_FILE_CHOOSER (object);
616 	GeditFileChooserClass *klass = GEDIT_FILE_CHOOSER_GET_CLASS (chooser);
617 
618 	if (G_OBJECT_CLASS (_gedit_file_chooser_parent_class)->constructed != NULL)
619 	{
620 		G_OBJECT_CLASS (_gedit_file_chooser_parent_class)->constructed (object);
621 	}
622 
623 	if (klass->create_gtk_file_chooser != NULL)
624 	{
625 		g_return_if_fail (chooser->priv->gtk_chooser == NULL);
626 		chooser->priv->gtk_chooser = klass->create_gtk_file_chooser (chooser);
627 
628 		setup_filters (chooser);
629 		set_modal (chooser);
630 		gtk_file_chooser_set_local_only (chooser->priv->gtk_chooser, FALSE);
631 
632 		g_signal_connect_object (chooser->priv->gtk_chooser,
633 					 "response",
634 					 G_CALLBACK (response_cb),
635 					 chooser,
636 					 0);
637 	}
638 }
639 
640 static void
_gedit_file_chooser_dispose(GObject * object)641 _gedit_file_chooser_dispose (GObject *object)
642 {
643 	GeditFileChooser *chooser = GEDIT_FILE_CHOOSER (object);
644 
645 	if (chooser->priv->gtk_chooser != NULL)
646 	{
647 		if (_gedit_file_chooser_is_native ())
648 		{
649 			g_object_unref (chooser->priv->gtk_chooser);
650 		}
651 		else
652 		{
653 			gtk_widget_destroy (GTK_WIDGET (chooser->priv->gtk_chooser));
654 		}
655 
656 		chooser->priv->gtk_chooser = NULL;
657 	}
658 
659 	G_OBJECT_CLASS (_gedit_file_chooser_parent_class)->dispose (object);
660 }
661 
662 static void
_gedit_file_chooser_class_init(GeditFileChooserClass * klass)663 _gedit_file_chooser_class_init (GeditFileChooserClass *klass)
664 {
665 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
666 
667 	object_class->constructed = _gedit_file_chooser_constructed;
668 	object_class->dispose = _gedit_file_chooser_dispose;
669 
670 	/*
671 	 * GeditFileChooser::done:
672 	 * @chooser: the #GeditFileChooser emitting the signal.
673 	 * @accept: whether the response code is %GTK_RESPONSE_ACCEPT.
674 	 */
675 	signals[SIGNAL_DONE] =
676 		g_signal_new ("done",
677 			      G_TYPE_FROM_CLASS (klass),
678 			      G_SIGNAL_RUN_FIRST,
679 			      0, NULL, NULL, NULL,
680 			      G_TYPE_NONE,
681 			      1, G_TYPE_BOOLEAN);
682 }
683 
684 static void
_gedit_file_chooser_init(GeditFileChooser * chooser)685 _gedit_file_chooser_init (GeditFileChooser *chooser)
686 {
687 	chooser->priv = _gedit_file_chooser_get_instance_private (chooser);
688 }
689 
690 GeditFileChooser *
_gedit_file_chooser_new(void)691 _gedit_file_chooser_new (void)
692 {
693 	return g_object_new (GEDIT_TYPE_FILE_CHOOSER, NULL);
694 }
695 
696 /* TODO: this function will go away. */
697 void
_gedit_file_chooser_set_gtk_file_chooser(GeditFileChooser * chooser,GtkFileChooser * gtk_chooser)698 _gedit_file_chooser_set_gtk_file_chooser (GeditFileChooser *chooser,
699 					  GtkFileChooser   *gtk_chooser)
700 {
701 	g_return_if_fail (GEDIT_IS_FILE_CHOOSER (chooser));
702 	g_return_if_fail (GTK_IS_FILE_CHOOSER (gtk_chooser));
703 	g_return_if_fail (chooser->priv->gtk_chooser == NULL);
704 
705 	chooser->priv->gtk_chooser = g_object_ref_sink (gtk_chooser);
706 	setup_filters (chooser);
707 }
708 
709 GtkFileChooser *
_gedit_file_chooser_get_gtk_file_chooser(GeditFileChooser * chooser)710 _gedit_file_chooser_get_gtk_file_chooser (GeditFileChooser *chooser)
711 {
712 	g_return_val_if_fail (GEDIT_IS_FILE_CHOOSER (chooser), NULL);
713 	return chooser->priv->gtk_chooser;
714 }
715 
716 void
_gedit_file_chooser_set_transient_for(GeditFileChooser * chooser,GtkWindow * parent)717 _gedit_file_chooser_set_transient_for (GeditFileChooser *chooser,
718 				       GtkWindow        *parent)
719 {
720 	g_return_if_fail (GEDIT_IS_FILE_CHOOSER (chooser));
721 	g_return_if_fail (parent == NULL || GTK_IS_WINDOW (parent));
722 
723 	if (_gedit_file_chooser_is_native ())
724 	{
725 		gtk_native_dialog_set_transient_for (GTK_NATIVE_DIALOG (chooser->priv->gtk_chooser), parent);
726 	}
727 	else
728 	{
729 		gtk_window_set_transient_for (GTK_WINDOW (chooser->priv->gtk_chooser), parent);
730 
731 		if (parent != NULL)
732 		{
733 			gtk_window_set_destroy_with_parent (GTK_WINDOW (chooser->priv->gtk_chooser), TRUE);
734 		}
735 	}
736 }
737 
738 void
_gedit_file_chooser_show(GeditFileChooser * chooser)739 _gedit_file_chooser_show (GeditFileChooser *chooser)
740 {
741 	g_return_if_fail (GEDIT_IS_FILE_CHOOSER (chooser));
742 
743 	if (_gedit_file_chooser_is_native ())
744 	{
745 		gtk_native_dialog_show (GTK_NATIVE_DIALOG (chooser->priv->gtk_chooser));
746 	}
747 	else
748 	{
749 		gtk_window_present (GTK_WINDOW (chooser->priv->gtk_chooser));
750 	}
751 }
752 
753 gchar *
_gedit_file_chooser_get_current_folder_uri(GeditFileChooser * chooser)754 _gedit_file_chooser_get_current_folder_uri (GeditFileChooser *chooser)
755 {
756 	g_return_val_if_fail (GEDIT_IS_FILE_CHOOSER (chooser), NULL);
757 
758 	return gtk_file_chooser_get_current_folder_uri (chooser->priv->gtk_chooser);
759 }
760 
761 void
_gedit_file_chooser_set_current_folder_uri(GeditFileChooser * chooser,const gchar * uri)762 _gedit_file_chooser_set_current_folder_uri (GeditFileChooser *chooser,
763 					    const gchar      *uri)
764 {
765 	g_return_if_fail (GEDIT_IS_FILE_CHOOSER (chooser));
766 
767 	gtk_file_chooser_set_current_folder_uri (chooser->priv->gtk_chooser, uri);
768 }
769 
770 const GtkSourceEncoding *
_gedit_file_chooser_get_encoding(GeditFileChooser * chooser)771 _gedit_file_chooser_get_encoding (GeditFileChooser *chooser)
772 {
773 	GeditFileChooserClass *klass;
774 
775 	g_return_val_if_fail (GEDIT_IS_FILE_CHOOSER (chooser), NULL);
776 
777 	klass = GEDIT_FILE_CHOOSER_GET_CLASS (chooser);
778 	g_return_val_if_fail (klass->get_encoding != NULL, NULL);
779 
780 	return klass->get_encoding (chooser);
781 }
782