1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 
3 /*
4  *  GThumb
5  *
6  *  Copyright (C) 2005-2019 Free Software Foundation, Inc.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <config.h>
23 #include <math.h>
24 #include <gtk/gtk.h>
25 #include <gdk/gdkkeysyms.h>
26 #if HAVE_LCMS2
27 #include <lcms2.h>
28 #endif
29 #include "dlg-personalize-filters.h"
30 #include "glib-utils.h"
31 #include "gtk-utils.h"
32 #include "gth-auto-paned.h"
33 #include "gth-browser.h"
34 #include "gth-browser-actions-callbacks.h"
35 #include "gth-browser-actions-entries.h"
36 #include "gth-duplicable.h"
37 #include "gth-enum-types.h"
38 #include "gth-error.h"
39 #include "gth-file-list.h"
40 #include "gth-file-view.h"
41 #include "gth-file-selection.h"
42 #include "gth-file-source-vfs.h"
43 #include "gth-file-tool.h"
44 #include "gth-filter.h"
45 #include "gth-filterbar.h"
46 #include "gth-folder-tree.h"
47 #include "gth-grid-view.h"
48 #include "gth-icon-cache.h"
49 #include "gth-info-bar.h"
50 #include "gth-image-preloader.h"
51 #include "gth-location-bar.h"
52 #include "gth-location-chooser.h"
53 #include "gth-main.h"
54 #include "gth-marshal.h"
55 #include "gth-metadata-provider.h"
56 #include "gth-paned.h"
57 #include "gth-preferences.h"
58 #include "gth-progress-dialog.h"
59 #include "gth-sidebar.h"
60 #include "gth-statusbar.h"
61 #include "gth-toolbox.h"
62 #include "gth-user-dir.h"
63 #include "gth-viewer-page.h"
64 #include "gth-window.h"
65 #include "main.h"
66 
67 #define GTH_BROWSER_CALLBACK(f) ((GthBrowserCallback) (f))
68 #define MAX_HISTORY_LENGTH 15
69 #define LOAD_FILE_DELAY 150
70 #define LOAD_METADATA_DELAY 150
71 #define HIDE_MOUSE_DELAY 1 /* in seconds */
72 #define MOTION_THRESHOLD 0
73 #define UPDATE_SELECTION_DELAY 200
74 #define MIN_SIDEBAR_SIZE 100
75 #define MIN_VIEWER_SIZE 256
76 #define STATUSBAR_SEPARATOR "  ·  "
77 #define FILE_PROPERTIES_MINIMUM_HEIGHT 100
78 #define HISTORY_FILE "history.xbel"
79 #define OVERLAY_MARGIN 10
80 #define AUTO_OPEN_FOLDER_DELAY 500
81 
82 
83 enum {
84 	LOCATION_READY,
85 	LAST_SIGNAL
86 };
87 
88 
89 typedef struct {
90 	gboolean        saved;
91 	GthBrowserPage  page;
92 	GFile          *location;
93 	GFile          *current_file;
94 	GList          *selected;
95 	double          vscroll;
96 } BrowserState;
97 
98 
99 struct _GthBrowserPrivate {
100 	/* UI staff */
101 
102 	GtkWidget         *infobar;
103 	GtkWidget         *statusbar;
104 	GtkWidget         *browser_right_container;
105 	GtkWidget         *browser_left_container;
106 	GtkWidget         *browser_sidebar;
107 	GtkWidget         *folder_tree;
108 	GtkWidget         *folder_popup;
109 	GtkWidget         *file_list_popup;
110 	GtkWidget         *file_popup;
111 	GtkWidget         *filterbar;
112 	GtkWidget         *file_list;
113 	GtkWidget         *list_extra_widget_container;
114 	GtkWidget         *list_info_bar;
115 	GtkWidget         *location_bar;
116 	GtkWidget         *file_properties;
117 	GtkWidget         *header_sections[GTH_BROWSER_N_HEADER_SECTIONS];
118 	GtkWidget         *browser_status_commands;
119 	GtkWidget         *viewer_status_commands;
120 	GtkWidget         *menu_button;
121 	GHashTable	  *menu_managers;
122 
123 	GtkWidget         *thumbnail_list;
124 
125 	GList             *viewer_pages;
126 	GtkOrientation     viewer_thumbnails_orientation;
127 	GtkWidget         *viewer_thumbnails_pane;
128 	GtkWidget         *viewer_sidebar_pane;
129 	GtkWidget         *viewer_sidebar_container;
130 	GtkWidget         *viewer_container;
131 	GthViewerPage     *viewer_page;
132 	GthImagePreloader *image_preloader;
133 
134 	GtkWidget         *progress_dialog;
135 
136 	GHashTable        *named_dialogs;
137 
138 	/* Browser data */
139 
140 	gulong             folder_changed_id;
141 	gulong             file_renamed_id;
142 	gulong             metadata_changed_id;
143 	gulong             emblems_changed_id;
144 	gulong             entry_points_changed_id;
145 	gulong             order_changed_id;
146 	gulong             shortcuts_changed_id;
147 	GthFileData       *location;
148 	GthFileData       *current_file;
149 	GthFileSource     *location_source;
150 	int                n_visibles;
151 	int                current_file_position;
152 	GFile             *monitor_location;
153 	gboolean           activity_ref;
154 	GthIconCache      *menu_icon_cache;
155 	GthFileDataSort   *current_sort_type;
156 	gboolean           current_sort_inverse;
157 	GthFileDataSort   *default_sort_type;
158 	gboolean           default_sort_inverse;
159 	gboolean           show_hidden_files;
160 	gboolean           fast_file_type;
161 	gboolean           closing;
162 	GthTask           *task;
163 	gulong             task_completed;
164 	gulong             task_progress;
165 	GList             *background_tasks;
166 	gboolean           close_with_task;
167 	GList             *load_data_queue;
168 	gpointer           last_folder_to_open;
169 	GList             *load_file_data_queue;
170 	guint              load_file_timeout;
171 	guint              load_metadata_timeout;
172 	char              *list_attributes;
173 	gboolean           constructed;
174 	guint              construct_step2_event;
175 	guint              selection_changed_event;
176 	GthFileData       *folder_popup_file_data;
177 	gboolean           properties_on_screen;
178 	char              *location_free_space;
179 	gboolean           recalc_location_free_space;
180 	gboolean           file_properties_on_the_right;
181 	GthSidebarState    viewer_sidebar;
182 	BrowserState       state;
183 	GthICCProfile     *screen_profile;
184 	GtkTreePath       *folder_tree_last_dest_row; /* used to open a folder during D&D */
185 	guint              folder_tree_open_folder_id;
186 	GtkWidget         *apply_editor_changes_button;
187 	gboolean           ask_to_save_modified_images;
188 	GthScrollAction    scroll_action;
189 
190 	/* settings */
191 
192 	GSettings         *browser_settings;
193 	GSettings         *messages_settings;
194 	GSettings         *desktop_interface_settings;
195 
196 	/* fullscreen */
197 
198 	gboolean           fullscreen;
199 	gboolean	   was_fullscreen;
200 	GtkWidget	  *fullscreen_toolbar;
201 	GtkWidget	  *fullscreen_headerbar;
202 	GtkWidget         *next_image_button;
203 	GtkWidget         *previous_image_button;
204 	GList             *viewer_controls;
205 	GList             *fixed_viewer_controls;
206 	gboolean           pointer_visible;
207 	guint              hide_mouse_timeout;
208 	guint              motion_signal;
209 	gdouble            last_mouse_x;
210 	gdouble            last_mouse_y;
211 	gboolean           view_files_in_fullscreen;
212 	gboolean           keep_mouse_visible;
213 	struct {
214 		int		page;
215 		gboolean	thumbnail_list;
216 		gboolean	browser_properties;
217 		GthSidebarState	viewer_sidebar;
218 	} before_fullscreen;
219 	struct {
220 		gboolean	thumbnail_list;
221 		GthSidebarState	sidebar;
222 	} fullscreen_state;
223 
224 	/* history */
225 
226 	GList             *history;
227 	GList             *history_current;
228 	GMenu             *history_menu;
229 };
230 
231 static guint gth_browser_signals[LAST_SIGNAL] = { 0 };
232 
233 
G_DEFINE_TYPE_WITH_CODE(GthBrowser,gth_browser,GTH_TYPE_WINDOW,G_ADD_PRIVATE (GthBrowser))234 G_DEFINE_TYPE_WITH_CODE (GthBrowser,
235 			 gth_browser,
236 			 GTH_TYPE_WINDOW,
237 			 G_ADD_PRIVATE (GthBrowser))
238 
239 
240 /* -- browser_state -- */
241 
242 
243 static void
244 browser_state_init (BrowserState *state)
245 {
246 	state->saved = FALSE;
247 	state->page = 0;
248 	state->location = NULL;
249 	state->current_file = NULL;
250 	state->selected = NULL;
251 }
252 
253 
254 static void
browser_state_free(BrowserState * state)255 browser_state_free (BrowserState *state)
256 {
257 	if (! state->saved)
258 		return;
259 
260 	_g_object_unref (state->location);
261 	_g_object_unref (state->current_file);
262 	g_list_foreach (state->selected, (GFunc) gtk_tree_path_free, NULL);
263 	g_list_free (state->selected);
264 
265 	state->location = NULL;
266 	state->current_file = NULL;
267 	state->selected = NULL;
268 	state->saved = FALSE;
269 }
270 
271 
272 /* -- monitor_event_data -- */
273 
274 
275 typedef struct {
276 	int              ref;
277 	GthFileSource   *file_source;
278 	GFile           *parent;
279 	int              position;
280 	GthMonitorEvent  event;
281 	GthBrowser      *browser;
282 	gboolean         update_file_list;
283 	gboolean         update_folder_tree;
284 } MonitorEventData;
285 
286 
287 static MonitorEventData *
monitor_event_data_new(void)288 monitor_event_data_new (void)
289 {
290 	MonitorEventData *monitor_data;
291 
292 	monitor_data = g_new0 (MonitorEventData, 1);
293 	monitor_data->ref = 1;
294 
295 	return monitor_data;
296 }
297 
298 
299 G_GNUC_UNUSED
300 static MonitorEventData *
monitor_event_data_ref(MonitorEventData * monitor_data)301 monitor_event_data_ref (MonitorEventData *monitor_data)
302 {
303 	monitor_data->ref++;
304 	return monitor_data;
305 }
306 
307 
308 static void
monitor_event_data_unref(MonitorEventData * monitor_data)309 monitor_event_data_unref (MonitorEventData *monitor_data)
310 {
311 	monitor_data->ref--;
312 
313 	if (monitor_data->ref > 0)
314 		return;
315 
316 	g_object_unref (monitor_data->file_source);
317 	g_object_unref (monitor_data->parent);
318 	g_free (monitor_data);
319 }
320 
321 
322 /* -- gth_browser -- */
323 
324 
325 static gboolean
gth_action_changes_folder(GthAction action)326 gth_action_changes_folder (GthAction action)
327 {
328 	gboolean result = FALSE;
329 
330 	switch (action) {
331 	case GTH_ACTION_GO_TO:
332 	case GTH_ACTION_GO_BACK:
333 	case GTH_ACTION_GO_FORWARD:
334 	case GTH_ACTION_GO_UP:
335 	case GTH_ACTION_TREE_OPEN:
336 		result = TRUE;
337 		break;
338 
339 	case GTH_ACTION_TREE_LIST_CHILDREN:
340 		result = FALSE;
341 		break;
342 	}
343 
344 	return result;
345 }
346 
347 
348 static void
_gth_browser_update_current_file_position(GthBrowser * browser)349 _gth_browser_update_current_file_position (GthBrowser *browser)
350 {
351 	GthFileStore *file_store;
352 
353 	file_store = gth_browser_get_file_store (browser);
354 	browser->priv->n_visibles = gth_file_store_n_visibles (file_store);
355 	browser->priv->current_file_position = -1;
356 
357 	if (browser->priv->current_file != NULL) {
358 		int pos;
359 
360 		pos = gth_file_store_get_pos (file_store, browser->priv->current_file->file);
361 		if (pos >= 0)
362 			browser->priv->current_file_position = pos;
363 	}
364 }
365 
366 
367 static gboolean
_gth_browser_file_tool_is_active(GthBrowser * browser)368 _gth_browser_file_tool_is_active (GthBrowser *browser)
369 {
370 	return  gth_toolbox_tool_is_active (GTH_TOOLBOX (gth_sidebar_get_toolbox (GTH_SIDEBAR (browser->priv->file_properties))));
371 }
372 
373 
374 void
gth_browser_update_title(GthBrowser * browser)375 gth_browser_update_title (GthBrowser *browser)
376 {
377 	GString    *title;
378 	const char *name = NULL;
379 	GList      *emblems = NULL;
380 
381 	title = g_string_new (NULL);
382 
383 	switch (gth_window_get_current_page (GTH_WINDOW (browser))) {
384 	case GTH_BROWSER_PAGE_BROWSER:
385 		if (browser->priv->location != NULL)
386 			name = g_file_info_get_display_name (browser->priv->location->info);
387 		if (name != NULL)
388 			g_string_append (title, name);
389 		break;
390 
391 	case GTH_BROWSER_PAGE_VIEWER:
392 		if (_gth_browser_file_tool_is_active (browser)) {
393 			GtkWidget *toolbox;
394 			GtkWidget *file_tool;
395 
396 			toolbox = gth_sidebar_get_toolbox (GTH_SIDEBAR (browser->priv->file_properties));
397 			file_tool = gth_toolbox_get_active_tool (GTH_TOOLBOX (toolbox));
398 			g_string_append (title, gth_file_tool_get_options_title (GTH_FILE_TOOL (file_tool)));
399 		}
400 		else {
401 			if (browser->priv->current_file != NULL)
402 				name = g_file_info_get_display_name (browser->priv->current_file->info);
403 			if (name != NULL)
404 				g_string_append (title, name);
405 
406 			if (gth_browser_get_file_modified (browser)) {
407 				g_string_append (title, " ");
408 				g_string_append (title, _("[modified]"));
409 			}
410 
411 			if (browser->priv->current_file != NULL) {
412 				GthStringList *string_list;
413 
414 				string_list = GTH_STRING_LIST (g_file_info_get_attribute_object (browser->priv->current_file->info, GTH_FILE_ATTRIBUTE_EMBLEMS));
415 				if (string_list != NULL)
416 					emblems = _g_string_list_dup (gth_string_list_get_list (string_list));
417 			}
418 		}
419 		break;
420 	}
421 
422 	if (title->len == 0)
423 		g_string_append (title, _("gThumb"));
424 
425 	gth_window_set_title (GTH_WINDOW (browser),
426 			      title->str,
427 			      emblems);
428 
429 	g_string_free (title, TRUE);
430 	_g_string_list_free (emblems);
431 }
432 
433 
434 void
gth_browser_update_sensitivity(GthBrowser * browser)435 gth_browser_update_sensitivity (GthBrowser *browser)
436 {
437 	GFile    *parent;
438 	gboolean  parent_available;
439 	gboolean  viewer_can_save;
440 	gboolean  modified;
441 	int       n_selected;
442 
443 	if (browser->priv->location != NULL)
444 		parent = g_file_get_parent (browser->priv->location->file);
445 	else
446 		parent = NULL;
447 	parent_available = (parent != NULL);
448 	_g_object_unref (parent);
449 
450 	viewer_can_save = (browser->priv->location != NULL) && (browser->priv->viewer_page != NULL) && gth_viewer_page_can_save (GTH_VIEWER_PAGE (browser->priv->viewer_page));
451 	modified = gth_browser_get_file_modified (browser);
452 	n_selected = gth_file_selection_get_n_selected (GTH_FILE_SELECTION (gth_browser_get_file_list_view (browser)));
453 
454 	gth_window_enable_action (GTH_WINDOW (browser), "show-thumbnail-list", gth_window_get_current_page (GTH_WINDOW (browser)) == GTH_BROWSER_PAGE_VIEWER);
455 	gth_window_enable_action (GTH_WINDOW (browser), "show-sidebar", gth_window_get_current_page (GTH_WINDOW (browser)) == GTH_BROWSER_PAGE_BROWSER);
456 	/* gth_window_enable_action (GTH_WINDOW (browser), "view-reload", gth_window_get_current_page (GTH_WINDOW (browser)) == GTH_BROWSER_PAGE_BROWSER);*/ /* FIXME add view-reload */
457 	gth_window_enable_action (GTH_WINDOW (browser), "save", viewer_can_save && modified);
458 	gth_window_enable_action (GTH_WINDOW (browser), "save-as", viewer_can_save);
459 	gth_window_enable_action (GTH_WINDOW (browser), "revert-to-saved", viewer_can_save && modified);
460 	gth_window_enable_action (GTH_WINDOW (browser), "clear-history", browser->priv->history != NULL);
461 	gth_window_enable_action (GTH_WINDOW (browser), "go-up", parent_available);
462 	gth_window_enable_action (GTH_WINDOW (browser), "browser-edit-file", n_selected == 1);
463 
464 	gth_sidebar_update_sensitivity (GTH_SIDEBAR (browser->priv->file_properties));
465 
466 	if (browser->priv->viewer_page != NULL)
467 		gth_viewer_page_update_sensitivity (browser->priv->viewer_page);
468 
469 	gth_hook_invoke ("gth-browser-update-sensitivity", browser);
470 }
471 
472 
473 void
gth_browser_update_extra_widget(GthBrowser * browser)474 gth_browser_update_extra_widget (GthBrowser *browser)
475 {
476 	GtkWidget *location_chooser;
477 
478 	gtk_widget_show (browser->priv->location_bar);
479 	_gtk_container_remove_children (GTK_CONTAINER (gth_location_bar_get_action_area (GTH_LOCATION_BAR (browser->priv->location_bar))), NULL, NULL);
480 
481 	location_chooser = gth_location_bar_get_chooser (GTH_LOCATION_BAR (browser->priv->location_bar));
482 	_g_signal_handlers_block_by_data (location_chooser, browser);
483 	gth_location_chooser_set_current (GTH_LOCATION_CHOOSER (location_chooser), browser->priv->location->file);
484 	_g_signal_handlers_unblock_by_data (location_chooser, browser);
485 
486 	gth_hook_invoke ("gth-browser-update-extra-widget", browser);
487 }
488 
489 
490 static void
491 _gth_browser_set_sort_order (GthBrowser      *browser,
492 			     GthFileDataSort *sort_type,
493 			     gboolean         inverse,
494 			     gboolean         save,
495 			     gboolean         update_view);
496 
497 
498 static void
_gth_browser_set_location(GthBrowser * browser,GthFileData * location)499 _gth_browser_set_location (GthBrowser  *browser,
500 			   GthFileData *location)
501 {
502 	GthFileDataSort *sort_type;
503 	gboolean         sort_inverse;
504 
505 	if (location == NULL)
506 		return;
507 
508 	if (location != browser->priv->location) {
509 		if (browser->priv->location != NULL)
510 			g_object_unref (browser->priv->location);
511 		browser->priv->location = gth_file_data_dup (location);
512 	}
513 
514 	sort_type = gth_main_get_sort_type (g_file_info_get_attribute_string (browser->priv->location->info, "sort::type"));
515 	sort_inverse = g_file_info_get_attribute_boolean (browser->priv->location->info, "sort::inverse");
516 	if (sort_type == NULL) {
517 		sort_type = browser->priv->default_sort_type;
518 		sort_inverse = browser->priv->default_sort_inverse;
519 	}
520 	_gth_browser_set_sort_order (browser,
521 				     sort_type,
522 				     sort_inverse,
523 				     FALSE,
524 				     FALSE);
525 }
526 
527 
528 static void
_gth_browser_update_location(GthBrowser * browser,GthFileData * location)529 _gth_browser_update_location (GthBrowser  *browser,
530 			      GthFileData *location)
531 {
532 	_gth_browser_set_location (browser, location);
533 
534 	_gth_browser_update_current_file_position (browser);
535 	gth_browser_update_title (browser);
536 	gth_browser_update_sensitivity (browser);
537 	gth_browser_update_extra_widget (browser);
538 }
539 
540 
541 static void
_gth_browser_update_go_sensitivity(GthBrowser * browser)542 _gth_browser_update_go_sensitivity (GthBrowser *browser)
543 {
544 	g_object_set (g_action_map_lookup_action (G_ACTION_MAP (browser), "go-back"),
545 		      "enabled",
546 		      (browser->priv->history_current != NULL) && (browser->priv->history_current->next != NULL),
547 		      NULL);
548 	g_object_set (g_action_map_lookup_action (G_ACTION_MAP (browser), "go-forward"),
549 		      "enabled",
550 		      (browser->priv->history_current != NULL) && (browser->priv->history_current->prev != NULL),
551 		      NULL);
552 }
553 
554 
555 #if 0
556 static void
557 _gth_browser_history_print (GthBrowser *browser)
558 {
559 	GList *scan;
560 
561 	g_print ("history:\n");
562 	for (scan = browser->priv->history; scan; scan = scan->next) {
563 		GFile *file = scan->data;
564 		char  *uri;
565 
566 		uri = g_file_get_uri (file);
567 		g_print (" %s%s\n", (browser->priv->history_current == scan) ? "*" : " ", uri);
568 
569 		g_free (uri);
570 	}
571 }
572 #endif
573 
574 
575 static void
_gth_browser_history_menu(GthBrowser * browser)576 _gth_browser_history_menu (GthBrowser *browser)
577 {
578 	_gth_browser_update_go_sensitivity (browser);
579 
580 	/* Update the history menu model for the headerbar button */
581 
582 	g_menu_remove_all (browser->priv->history_menu);
583 
584 	if (browser->priv->history != NULL) {
585 		GList *scan;
586 		int    i;
587 
588 		for (i = 0, scan = browser->priv->history;
589 		     scan;
590 		     scan = scan->next, i++)
591 		{
592 			GFile     *file = scan->data;
593 			GMenuItem *item;
594 			char      *target;
595 
596 			item = _g_menu_item_new_for_file (file, NULL);
597 			target = g_strdup_printf ("%d", i);
598 			g_menu_item_set_action_and_target (item, "win.go-to-history-position", "s", target);
599 			g_menu_append_item (browser->priv->history_menu, item);
600 
601 			if (browser->priv->history_current == scan) {
602 				GAction *action = g_action_map_lookup_action (G_ACTION_MAP (browser), "go-to-history-position");
603 				g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_string (target));
604 			}
605 
606 			g_free (target);
607 			g_object_unref (item);
608 		}
609 	}
610 }
611 
612 
613 static void
_gth_browser_history_add(GthBrowser * browser,GFile * file)614 _gth_browser_history_add (GthBrowser *browser,
615 			  GFile      *file)
616 {
617 	if (file == NULL)
618 		return;
619 
620 	if ((browser->priv->history_current == NULL)
621 		|| ! _g_file_equal (file, browser->priv->history_current->data))
622 	{
623 		GList *scan;
624 
625 		/* remove all files after the current position */
626 		for (scan = browser->priv->history; scan && (scan != browser->priv->history_current); /* void */) {
627 			GList *next = scan->next;
628 
629 			browser->priv->history = g_list_remove_link (browser->priv->history, scan);
630 			_g_object_list_unref (scan);
631 
632 			scan = next;
633 		}
634 
635 		browser->priv->history = g_list_prepend (browser->priv->history, g_object_ref (file));
636 		browser->priv->history_current = browser->priv->history;
637 	}
638 }
639 
640 
641 static void
_gth_browser_history_save(GthBrowser * browser)642 _gth_browser_history_save (GthBrowser *browser)
643 {
644 	GSettings     *privacy_settings;
645 	gboolean       save_history;
646 	GBookmarkFile *bookmarks;
647 	GFile         *file;
648 	char          *filename;
649 	GList         *scan;
650 	int            n;
651 
652 	privacy_settings = _g_settings_new_if_schema_installed ("org.gnome.desktop.privacy");
653         save_history = (privacy_settings == NULL) || g_settings_get_boolean (privacy_settings, "remember-recent-files");
654         _g_object_unref (privacy_settings);
655 
656 	if (! save_history) {
657 		file = gth_user_dir_get_file_for_read (GTH_DIR_CONFIG, GTHUMB_DIR, HISTORY_FILE, NULL);
658 		g_file_delete (file, NULL, NULL);
659 		g_object_unref (file);
660 		return;
661 	}
662 
663 	bookmarks = g_bookmark_file_new ();
664 	for (scan = browser->priv->history, n = 0; scan && (n < MAX_HISTORY_LENGTH); scan = scan->next, n++) {
665 		GFile *location = scan->data;
666 		char  *uri;
667 
668 		uri = g_file_get_uri (location);
669 		_g_bookmark_file_add_uri (bookmarks, uri);
670 
671 		g_free (uri);
672 	}
673 	file = gth_user_dir_get_file_for_write (GTH_DIR_CONFIG, GTHUMB_DIR, HISTORY_FILE, NULL);
674 	filename = g_file_get_path (file);
675 	g_bookmark_file_to_file (bookmarks, filename, NULL);
676 
677 	g_free (filename);
678 	g_object_unref (file);
679 	g_bookmark_file_free (bookmarks);
680 }
681 
682 
683 static void
_gth_browser_history_load(GthBrowser * browser)684 _gth_browser_history_load (GthBrowser *browser)
685 {
686 	GSettings     *privacy_settings;
687 	gboolean       load_history;
688 	GBookmarkFile *bookmarks;
689 	GFile         *file;
690 	char          *filename;
691 
692 	_g_object_list_unref (browser->priv->history);
693 	browser->priv->history = NULL;
694 	browser->priv->history_current = NULL;
695 
696 	privacy_settings = _g_settings_new_if_schema_installed ("org.gnome.desktop.privacy");
697 	load_history = (privacy_settings == NULL) || g_settings_get_boolean (privacy_settings, "remember-recent-files");
698 	_g_object_unref (privacy_settings);
699 
700 	if (! load_history)
701 		return;
702 
703 	bookmarks = g_bookmark_file_new ();
704 	file = gth_user_dir_get_file_for_read (GTH_DIR_CONFIG, GTHUMB_DIR, HISTORY_FILE, NULL);
705 	filename = g_file_get_path (file);
706 	if (g_bookmark_file_load_from_file (bookmarks, filename, NULL)) {
707 		char **uris;
708 		int    i;
709 
710 		uris = g_bookmark_file_get_uris (bookmarks, NULL);
711 		for (i = 0; (uris[i] != NULL) && (i < MAX_HISTORY_LENGTH); i++)
712 			browser->priv->history = g_list_prepend (browser->priv->history, g_file_new_for_uri (uris[i]));
713 		browser->priv->history = g_list_reverse (browser->priv->history);
714 
715 		g_strfreev (uris);
716 	}
717 
718 	browser->priv->history_current = browser->priv->history;
719 
720 	g_free (filename);
721 	g_object_unref (file);
722 	g_bookmark_file_free (bookmarks);
723 }
724 
725 
726 static void
_gth_browser_monitor_entry_points(GthBrowser * browser)727 _gth_browser_monitor_entry_points (GthBrowser *browser)
728 {
729 	GList *scan;
730 
731 	for (scan = gth_main_get_all_file_sources (); scan; scan = scan->next) {
732 		GthFileSource *file_source = scan->data;
733 		gth_file_source_monitor_entry_points (file_source);
734 	}
735 }
736 
737 
738 static void
_gth_browser_update_entry_point_list(GthBrowser * browser)739 _gth_browser_update_entry_point_list (GthBrowser *browser)
740 {
741 	GList *entry_points;
742 	GFile *root;
743 
744 	entry_points = gth_main_get_all_entry_points ();
745 	root = g_file_new_for_uri ("gthumb-vfs:///");
746 	gth_folder_tree_set_children (GTH_FOLDER_TREE (browser->priv->folder_tree), root, entry_points);
747 
748 	g_object_unref (root);
749 	_g_object_list_unref (entry_points);
750 }
751 
752 
753 static GthTest *
_gth_browser_get_file_filter(GthBrowser * browser)754 _gth_browser_get_file_filter (GthBrowser *browser)
755 {
756 	GthTest *filterbar_test;
757 	GthTest *test;
758 
759 	if (browser->priv->filterbar == NULL)
760 		return NULL;
761 
762 	filterbar_test = gth_filterbar_get_test (GTH_FILTERBAR (browser->priv->filterbar));
763 	test = gth_main_add_general_filter (filterbar_test);
764 
765 	_g_object_unref (filterbar_test);
766 
767 	return test;
768 }
769 
770 
771 static gboolean
_gth_browser_get_fast_file_type(GthBrowser * browser,GFile * file)772 _gth_browser_get_fast_file_type (GthBrowser *browser,
773 				 GFile      *file)
774 {
775 	gboolean fast_file_type;
776 
777 	fast_file_type = browser->priv->fast_file_type;
778 
779 	/* Force the value to FALSE when browsing a cache or a temporary files
780 	 * directory.
781 	 * This is mainly used to browse the Firefox cache without changing the
782 	 * general preference each time, but can be useful for other caches
783 	 * as well. */
784 	if (g_file_has_uri_scheme (file, "file")) {
785 		char  *uri;
786 		char  *tmp_uri;
787 		char **uri_v;
788 		int    i;
789 
790 		uri = g_file_get_uri (file);
791 
792 		tmp_uri = g_filename_to_uri (g_get_tmp_dir (), NULL, NULL);
793 		if (tmp_uri != NULL) {
794 			gboolean is_tmp_dir;
795 
796 			is_tmp_dir = (strcmp (uri, tmp_uri) == 0);
797 			g_free (tmp_uri);
798 
799 			if (is_tmp_dir) {
800 				g_free (uri);
801 				return FALSE;
802 			}
803 		}
804 
805 		uri_v = g_strsplit (uri, "/", -1);
806 		for (i = 0; uri_v[i] != NULL; i++)
807 			if (strstr (uri_v[i], "cache")
808 			    || strstr (uri_v[i], "CACHE")
809 			    || strstr (uri_v[i], "Cache"))
810 			{
811 				fast_file_type = FALSE;
812 				break;
813 			}
814 
815 		 g_strfreev (uri_v);
816 		 g_free (uri);
817 	}
818 
819 	return fast_file_type;
820 }
821 
822 
823 static void
_update_statusbar_list_info(GthBrowser * browser)824 _update_statusbar_list_info (GthBrowser *browser)
825 {
826 	GList   *file_list;
827 	int      n_total;
828 	goffset  size_total;
829 	GList   *scan;
830 	int      n_selected;
831 	goffset  size_selected;
832 	GList   *selected;
833 	char    *size_total_formatted;
834 	char    *size_selected_formatted;
835 	char    *text_total;
836 	char    *text_selected;
837 	GString *text;
838 
839 	/* total */
840 
841 	file_list = gth_file_store_get_visibles (gth_browser_get_file_store (browser));
842 	n_total = 0;
843 	size_total = 0;
844 	for (scan = file_list; scan; scan = scan->next) {
845 		GthFileData *file_data = scan->data;
846 
847 		n_total++;
848 		size_total += g_file_info_get_size (file_data->info);
849 	}
850 	_g_object_list_unref (file_list);
851 
852 	/* selected */
853 
854 	selected = gth_file_selection_get_selected (GTH_FILE_SELECTION (gth_browser_get_file_list_view (browser)));
855 	file_list = gth_file_list_get_files (GTH_FILE_LIST (gth_browser_get_file_list (browser)), selected);
856 
857 	n_selected = 0;
858 	size_selected = 0;
859 	for (scan = file_list; scan; scan = scan->next) {
860 		GthFileData *file_data = scan->data;
861 
862 		n_selected++;
863 		size_selected += g_file_info_get_size (file_data->info);
864 	}
865 	_g_object_list_unref (file_list);
866 	_gtk_tree_path_list_free (selected);
867 
868 	/**/
869 
870 	size_total_formatted = g_format_size (size_total);
871 	size_selected_formatted = g_format_size (size_selected);
872 	text_total = g_strdup_printf (g_dngettext (NULL, "%d file (%s)", "%d files (%s)", n_total), n_total, size_total_formatted);
873 	text_selected = g_strdup_printf (g_dngettext (NULL, "%d file selected (%s)", "%d files selected (%s)", n_selected), n_selected, size_selected_formatted);
874 
875 	text = g_string_new (text_total);
876 	if (n_selected > 0) {
877 		g_string_append (text, STATUSBAR_SEPARATOR);
878 		g_string_append (text, text_selected);
879 	}
880 	if (browser->priv->location_free_space != NULL) {
881 		g_string_append (text, STATUSBAR_SEPARATOR);
882 		g_string_append (text, browser->priv->location_free_space);
883 	}
884 	gth_statusbar_set_list_info (GTH_STATUSBAR (browser->priv->statusbar), text->str);
885 
886 	g_string_free (text, TRUE);
887 	g_free (text_selected);
888 	g_free (text_total);
889 	g_free (size_selected_formatted);
890 	g_free (size_total_formatted);
891 }
892 
893 
894 static void
get_free_space_ready_cb(GthFileSource * file_source,guint64 total_size,guint64 free_space,GError * error,gpointer data)895 get_free_space_ready_cb (GthFileSource *file_source,
896 			 guint64        total_size,
897 			 guint64        free_space,
898 			 GError        *error,
899 			 gpointer       data)
900 {
901 	GthBrowser *browser = data;
902 	char       *free_space_text;
903 
904 	if (error == NULL) {
905 		char *free_space_formatted;
906 
907 		free_space_formatted = g_format_size (free_space);
908 		free_space_text = g_strdup_printf (_("%s of free space"), free_space_formatted);
909 
910 		g_free (free_space_formatted);
911 	}
912 	else
913 		free_space_text = NULL;
914 
915 	g_free (browser->priv->location_free_space);
916 	browser->priv->location_free_space = NULL;
917 	if (free_space_text != NULL)
918 		browser->priv->location_free_space = g_strdup (free_space_text);
919 	g_free (free_space_text);
920 
921 	browser->priv->recalc_location_free_space = FALSE;
922 
923 	_update_statusbar_list_info (browser);
924 }
925 
926 
927 static void
_gth_browser_update_statusbar_list_info(GthBrowser * browser)928 _gth_browser_update_statusbar_list_info (GthBrowser *browser)
929 {
930 	if (browser->priv->recalc_location_free_space
931 	    && (browser->priv->location_source != NULL)
932 	    && (browser->priv->location != NULL))
933 	{
934 		gth_file_source_get_free_space (browser->priv->location_source,
935 						browser->priv->location->file,
936 						get_free_space_ready_cb,
937 						browser);
938 	}
939 	else {
940 		if ((browser->priv->location_source == NULL)
941 		    || (browser->priv->location == NULL))
942 		{
943 			g_free (browser->priv->location_free_space);
944 			browser->priv->location_free_space = NULL;
945 		}
946 		_update_statusbar_list_info (browser);
947 	}
948 }
949 
950 
951 typedef struct {
952 	GthBrowser    *browser;
953 	GthFileData   *requested_folder;
954 	GFile         *file_to_select;
955 	GList         *selected;
956 	double         vscroll;
957 	GthAction      action;
958 	gboolean       automatic;
959 	GList         *list;
960 	GList         *current;
961 	GFile         *entry_point;
962 	GthFileSource *file_source;
963 	GCancellable  *cancellable;
964 } LoadData;
965 
966 
967 static LoadData *
load_data_new(GthBrowser * browser,GFile * location,GFile * file_to_select,GList * selected,double vscroll,GthAction action,gboolean automatic,GFile * entry_point)968 load_data_new (GthBrowser *browser,
969 	       GFile      *location,
970 	       GFile      *file_to_select,
971 	       GList      *selected,
972 	       double      vscroll,
973 	       GthAction   action,
974 	       gboolean    automatic,
975 	       GFile      *entry_point)
976 {
977 	LoadData *load_data;
978 	GFile    *file;
979 
980 	load_data = g_new0 (LoadData, 1);
981 	load_data->browser = browser;
982 	load_data->requested_folder = gth_file_data_new (location, NULL);
983 	if (file_to_select != NULL)
984 		load_data->file_to_select = g_file_dup (file_to_select);
985 	else if (browser->priv->current_file != NULL)
986 		load_data->file_to_select = g_file_dup (browser->priv->current_file->file);
987 	load_data->selected = g_list_copy_deep (selected, (GCopyFunc) gtk_tree_path_copy, NULL);
988 	load_data->vscroll = vscroll;
989 	load_data->action = action;
990 	load_data->automatic = automatic;
991 	load_data->cancellable = g_cancellable_new ();
992 
993 	browser->priv->load_data_queue = g_list_prepend (browser->priv->load_data_queue, load_data);
994 	if (gth_action_changes_folder (load_data->action))
995 		browser->priv->last_folder_to_open = load_data;
996 
997 	if (entry_point == NULL)
998 		return load_data;
999 
1000 	load_data->entry_point = g_object_ref (entry_point);
1001 	load_data->file_source = gth_main_get_file_source (load_data->requested_folder->file);
1002 
1003 	file = g_object_ref (load_data->requested_folder->file);
1004 	load_data->list = g_list_prepend (NULL, g_object_ref (file));
1005 	while (! g_file_equal (load_data->entry_point, file)) {
1006 		GFile *parent;
1007 
1008 		parent = g_file_get_parent (file);
1009 		g_object_unref (file);
1010 		file = parent;
1011 
1012 		load_data->list = g_list_prepend (load_data->list, g_object_ref (file));
1013 	}
1014 	g_object_unref (file);
1015 	load_data->current = NULL;
1016 
1017 	return load_data;
1018 }
1019 
1020 
1021 static void
load_data_free(LoadData * data)1022 load_data_free (LoadData *data)
1023 {
1024 	if (data->browser->priv->last_folder_to_open == data)
1025 		data->browser->priv->last_folder_to_open = NULL;
1026 	data->browser->priv->load_data_queue = g_list_remove (data->browser->priv->load_data_queue, data);
1027 
1028 	g_object_unref (data->requested_folder);
1029 	_g_object_unref (data->file_to_select);
1030 	g_list_free_full (data->selected, (GDestroyNotify) gtk_tree_path_free);
1031 	_g_object_unref (data->file_source);
1032 	_g_object_list_unref (data->list);
1033 	_g_object_unref (data->entry_point);
1034 	g_object_unref (data->cancellable);
1035 	g_free (data);
1036 }
1037 
1038 
1039 static void
1040 _gth_browser_load (GthBrowser *browser,
1041 		   GFile      *location,
1042 		   GFile      *file_to_select,
1043 		   GList      *selected,
1044 		   double      vscroll,
1045 		   GthAction   action,
1046 		   gboolean    automatic);
1047 
1048 
1049 static void
_gth_browser_show_error(GthBrowser * browser,const char * title,GError * error)1050 _gth_browser_show_error (GthBrowser *browser,
1051 			 const char *title,
1052 			 GError     *error)
1053 {
1054 	/* _gtk_error_dialog_from_gerror_show (GTK_WINDOW (browser), title, error); */
1055 
1056 	gth_info_bar_set_primary_text (GTH_INFO_BAR (browser->priv->infobar), title);
1057 	gth_info_bar_set_secondary_text (GTH_INFO_BAR (browser->priv->infobar), error->message);
1058 
1059 	gtk_orientable_set_orientation (GTK_ORIENTABLE (gtk_info_bar_get_action_area (GTK_INFO_BAR (browser->priv->infobar))), GTK_ORIENTATION_HORIZONTAL);
1060 	gth_info_bar_set_icon_name (GTH_INFO_BAR (browser->priv->infobar), "dialog-error-symbolic", GTK_ICON_SIZE_DIALOG);
1061 	gtk_info_bar_set_message_type (GTK_INFO_BAR (browser->priv->infobar), GTK_MESSAGE_ERROR);
1062 	_gtk_info_bar_clear_action_area (GTK_INFO_BAR (browser->priv->infobar));
1063 	gtk_info_bar_add_buttons (GTK_INFO_BAR (browser->priv->infobar),
1064 				  _GTK_LABEL_CLOSE, GTK_RESPONSE_CLOSE,
1065 				  NULL);
1066 	gtk_widget_show (browser->priv->infobar);
1067 }
1068 
1069 
1070 static void
_gth_browser_update_activity(GthBrowser * browser,gboolean increment)1071 _gth_browser_update_activity (GthBrowser *browser,
1072 			      gboolean    increment)
1073 {
1074 	if (increment) {
1075 		browser->priv->activity_ref++;
1076 		if (browser->priv->activity_ref == 1) {
1077 			GdkCursor  *cursor = gdk_cursor_new_from_name (gtk_widget_get_display (GTK_WIDGET (browser)), "progress");
1078 			gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (browser)), cursor);
1079 			g_object_unref (cursor);
1080 		}
1081 	}
1082 	else {
1083 		browser->priv->activity_ref--;
1084 		if (browser->priv->activity_ref == 0) {
1085 			GdkCursor *cursor = gdk_cursor_new_from_name (gtk_widget_get_display (GTK_WIDGET (browser)), "default");
1086 			gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (browser)), cursor);
1087 			g_object_unref (cursor);
1088 		}
1089 	}
1090 }
1091 
1092 
1093 static void
_gth_browser_add_activity(GthBrowser * browser)1094 _gth_browser_add_activity (GthBrowser *browser)
1095 {
1096 	_gth_browser_update_activity (browser, TRUE);
1097 }
1098 
1099 
1100 static void
_gth_browser_remove_activity(GthBrowser * browser)1101 _gth_browser_remove_activity (GthBrowser *browser)
1102 {
1103 	_gth_browser_update_activity (browser, FALSE);
1104 }
1105 
1106 
1107 static gboolean
load_data_is_still_relevant(LoadData * load_data)1108 load_data_is_still_relevant (LoadData *load_data)
1109 {
1110 	return ! gth_action_changes_folder (load_data->action)
1111 		    || (load_data == load_data->browser->priv->last_folder_to_open);
1112 }
1113 
1114 
1115 static void
load_data_done(LoadData * load_data,GError * error)1116 load_data_done (LoadData *load_data,
1117 		GError   *error)
1118 {
1119 	GthBrowser *browser = load_data->browser;
1120 	char       *title;
1121 
1122 	{
1123 		char *uri;
1124 
1125 		uri = g_file_get_uri (load_data->requested_folder->file);
1126 		debug (DEBUG_INFO, "LOAD READY: %s [%s]\n", uri, (error == NULL ? "Ok" : "Error"));
1127 		performance (DEBUG_INFO, "load done for %s", uri);
1128 
1129 		g_free (uri);
1130 	}
1131 
1132 	_gth_browser_remove_activity (browser);
1133 
1134 	if (error == NULL)
1135 		return;
1136 
1137 	g_signal_emit (G_OBJECT (browser),
1138 		       gth_browser_signals[LOCATION_READY],
1139 		       0,
1140 		       load_data->requested_folder->file,
1141 		       TRUE);
1142 
1143 	if (! load_data_is_still_relevant (load_data)
1144 		|| g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
1145 	{
1146 		g_error_free (error);
1147 		return;
1148 	}
1149 
1150 	if (gth_action_changes_folder (load_data->action)
1151 		&& load_data->automatic)
1152 	{
1153 		GFile *parent;
1154 
1155 		parent = g_file_get_parent (load_data->requested_folder->file);
1156 		if (parent != NULL) {
1157 			_gth_browser_load (load_data->browser,
1158 					   parent,
1159 					   NULL,
1160 					   NULL,
1161 					   0,
1162 					   load_data->action,
1163 					   TRUE);
1164 			g_object_unref (parent);
1165 			return;
1166 		}
1167 	}
1168 
1169 	gth_browser_update_sensitivity (browser);
1170 	title = _g_format_str_for_file (_("Could not load the position “%s”"),
1171 					load_data->requested_folder->file);
1172 	_gth_browser_show_error (browser, title, error);
1173 
1174 	g_free (title);
1175 	g_error_free (error);
1176 }
1177 
1178 
1179 static void
load_data_error(LoadData * load_data,GError * error)1180 load_data_error (LoadData *load_data,
1181 		 GError   *error)
1182 {
1183 	gth_folder_tree_set_children (GTH_FOLDER_TREE (load_data->browser->priv->folder_tree),
1184 				      G_FILE (load_data->current->data),
1185 				      NULL);
1186 
1187 	load_data_done (load_data, error);
1188 	load_data_free (load_data);
1189 }
1190 
1191 
1192 static void
load_data_cancelled(LoadData * load_data)1193 load_data_cancelled (LoadData *load_data)
1194 {
1195 	load_data_done (load_data, g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED, ""));
1196 	load_data_free (load_data);
1197 }
1198 
1199 
1200 /* -- _gth_browser_set_sort_order -- */
1201 
1202 
1203 static const char *
_gth_browser_get_list_attributes(GthBrowser * browser,gboolean recalc)1204 _gth_browser_get_list_attributes (GthBrowser *browser,
1205 				  gboolean    recalc)
1206 {
1207 	GString *attributes;
1208 	GthTest *filter;
1209 	char    *thumbnail_caption;
1210 
1211 	if (recalc) {
1212 		g_free (browser->priv->list_attributes);
1213 		browser->priv->list_attributes = NULL;
1214 	}
1215 
1216 	if (browser->priv->list_attributes != NULL)
1217 		return browser->priv->list_attributes;
1218 
1219 	attributes = g_string_new ("");
1220 
1221 	/* standard attributes */
1222 
1223 	if (browser->priv->fast_file_type)
1224 		g_string_append (attributes, GFILE_STANDARD_ATTRIBUTES_WITH_FAST_CONTENT_TYPE);
1225 	else
1226 		g_string_append (attributes, GFILE_STANDARD_ATTRIBUTES_WITH_CONTENT_TYPE);
1227 
1228 	/* attributes required by the filter */
1229 
1230 	filter = _gth_browser_get_file_filter (browser);
1231 	if (filter != NULL) {
1232 		const char *filter_attributes;
1233 
1234 		filter_attributes = gth_test_get_attributes (GTH_TEST (filter));
1235 		if (filter_attributes[0] != '\0') {
1236 			g_string_append (attributes, ",");
1237 			g_string_append (attributes, filter_attributes);
1238 		}
1239 
1240 		g_object_unref (filter);
1241 	}
1242 
1243 	/* attributes required for sorting */
1244 
1245 	if ((browser->priv->current_sort_type != NULL) && (browser->priv->current_sort_type->required_attributes[0] != '\0')) {
1246 		g_string_append (attributes, ",");
1247 		g_string_append (attributes, browser->priv->current_sort_type->required_attributes);
1248 	}
1249 
1250 	/* attributes required for the thumbnail caption */
1251 
1252 	thumbnail_caption = g_settings_get_string (browser->priv->browser_settings, PREF_BROWSER_THUMBNAIL_CAPTION);
1253 	if ((thumbnail_caption[0] != '\0') && (strcmp (thumbnail_caption, "none") != 0)) {
1254 		g_string_append (attributes, ",");
1255 		g_string_append (attributes, thumbnail_caption);
1256 		g_free (thumbnail_caption);
1257 	}
1258 
1259 	/* other attributes */
1260 
1261 	g_string_append (attributes, ",");
1262 	g_string_append (attributes, GTH_FILE_ATTRIBUTE_EMBLEMS);
1263 
1264 	/* save in a variable to avoid recalculation */
1265 
1266 	browser->priv->list_attributes = g_string_free (attributes, FALSE);
1267 
1268 	return browser->priv->list_attributes;
1269 }
1270 
1271 
1272 static gboolean
_gth_browser_reload_required(GthBrowser * browser)1273 _gth_browser_reload_required (GthBrowser *browser)
1274 {
1275 	char       *old_attributes;
1276 	const char *new_attributes;
1277 	gboolean    reload_required;
1278 
1279 	old_attributes = g_strdup (_gth_browser_get_list_attributes (browser, FALSE));
1280 	new_attributes = _gth_browser_get_list_attributes (browser, TRUE);
1281 	reload_required = attribute_list_reload_required (old_attributes, new_attributes);
1282 
1283 	g_free (old_attributes);
1284 
1285 	return reload_required;
1286 }
1287 
1288 
1289 static void
write_sort_order_ready_cb(GObject * source,GError * error,gpointer user_data)1290 write_sort_order_ready_cb (GObject  *source,
1291 		           GError   *error,
1292 		           gpointer  user_data)
1293 {
1294 	GthBrowser *browser = user_data;
1295 
1296 	if (browser->priv->constructed && _gth_browser_reload_required (browser))
1297 		gth_browser_reload (browser);
1298 }
1299 
1300 
1301 static void
_gth_browser_set_sort_order(GthBrowser * browser,GthFileDataSort * sort_type,gboolean inverse,gboolean save,gboolean update_view)1302 _gth_browser_set_sort_order (GthBrowser      *browser,
1303 			     GthFileDataSort *sort_type,
1304 			     gboolean         inverse,
1305 			     gboolean         save,
1306 			     gboolean         update_view)
1307 {
1308 	g_return_if_fail (sort_type != NULL);
1309 
1310 	browser->priv->current_sort_type = sort_type;
1311 	browser->priv->current_sort_inverse = inverse;
1312 
1313 	gth_file_list_set_sort_func (GTH_FILE_LIST (browser->priv->file_list),
1314 				     sort_type->cmp_func,
1315 				     inverse);
1316 	gth_file_list_set_sort_func (GTH_FILE_LIST (browser->priv->thumbnail_list),
1317 				     sort_type->cmp_func,
1318 				     inverse);
1319 
1320 	if (! browser->priv->constructed || (browser->priv->location == NULL))
1321 		return;
1322 
1323 	g_file_info_set_attribute_string (browser->priv->location->info, "sort::type", (sort_type != NULL) ? sort_type->name : "general::unsorted");
1324 	g_file_info_set_attribute_boolean (browser->priv->location->info, "sort::inverse", (sort_type != NULL) ? inverse : FALSE);
1325 
1326 	if (update_view) {
1327 		_gth_browser_update_current_file_position (browser);
1328 		gth_browser_update_title (browser);
1329 	}
1330 
1331 	if (! save || (browser->priv->location_source == NULL))
1332 		return;
1333 
1334 	gth_file_source_write_metadata (browser->priv->location_source,
1335 					browser->priv->location,
1336 					"sort::type,sort::inverse",
1337 					write_sort_order_ready_cb,
1338 					browser);
1339 }
1340 
1341 
1342 static void _gth_browser_load_ready_cb (GthFileSource *file_source, GList *files, GError *error, gpointer user_data);
1343 
1344 
1345 static void
requested_folder_attributes_ready_cb(GObject * file_source,GError * error,gpointer user_data)1346 requested_folder_attributes_ready_cb (GObject  *file_source,
1347 				      GError   *error,
1348 				      gpointer  user_data)
1349 {
1350 	LoadData   *load_data = user_data;
1351 	GthBrowser *browser = load_data->browser;
1352 
1353 	if (error != NULL) {
1354 		load_data_error (load_data, error);
1355 		return;
1356 	}
1357 
1358 	gth_file_source_list (load_data->file_source,
1359 			      load_data->requested_folder->file,
1360 			      _gth_browser_get_fast_file_type (browser, load_data->requested_folder->file) ? GFILE_STANDARD_ATTRIBUTES_WITH_FAST_CONTENT_TYPE : GFILE_STANDARD_ATTRIBUTES_WITH_CONTENT_TYPE,
1361 			      _gth_browser_load_ready_cb,
1362 			      load_data);
1363 }
1364 
1365 
1366 static void
load_data_load_next_folder(LoadData * load_data)1367 load_data_load_next_folder (LoadData *load_data)
1368 {
1369 	GthFolderTree *folder_tree;
1370 	GFile         *folder_to_load = NULL;
1371 
1372 	folder_tree = GTH_FOLDER_TREE (load_data->browser->priv->folder_tree);
1373 	do {
1374 		GtkTreePath *path;
1375 
1376 		if (load_data->current == NULL)
1377 			load_data->current = load_data->list;
1378 		else
1379 			load_data->current = load_data->current->next;
1380 		folder_to_load = (GFile *) load_data->current->data;
1381 
1382 		if (g_file_equal (folder_to_load, load_data->requested_folder->file))
1383 			break;
1384 
1385 		path = gth_folder_tree_get_path (folder_tree, folder_to_load);
1386 		if (path == NULL)
1387 			break;
1388 
1389 		if (! gth_folder_tree_is_loaded (folder_tree, path)) {
1390 			gtk_tree_path_free (path);
1391 			break;
1392 		}
1393 
1394 		if (! g_file_equal (folder_to_load, load_data->requested_folder->file))
1395 			gth_folder_tree_expand_row (folder_tree, path, FALSE);
1396 
1397 		gtk_tree_path_free (path);
1398 	}
1399 	while (TRUE);
1400 
1401 	g_assert (folder_to_load != NULL);
1402 
1403 	if (gth_action_changes_folder (load_data->action)
1404 		&& g_file_equal (folder_to_load, load_data->requested_folder->file))
1405 	{
1406 		gth_file_source_read_metadata (load_data->file_source,
1407 					       load_data->requested_folder,
1408 					       "*",
1409 					       requested_folder_attributes_ready_cb,
1410 					       load_data);
1411 	}
1412 	else
1413 		gth_file_source_list (load_data->file_source,
1414 				      folder_to_load,
1415 				      GFILE_STANDARD_ATTRIBUTES_WITH_FAST_CONTENT_TYPE,
1416 				      _gth_browser_load_ready_cb,
1417 				      load_data);
1418 }
1419 
1420 
1421 static gboolean
_gth_browser_file_is_visible(GthBrowser * browser,GthFileData * file_data)1422 _gth_browser_file_is_visible (GthBrowser  *browser,
1423 				GthFileData *file_data)
1424 {
1425 	if (browser->priv->show_hidden_files)
1426 		return TRUE;
1427 	else
1428 		return ! g_file_info_get_is_hidden (file_data->info);
1429 }
1430 
1431 
1432 static GList *
_gth_browser_get_visible_files(GthBrowser * browser,GList * list)1433 _gth_browser_get_visible_files (GthBrowser *browser,
1434 			        GList      *list)
1435 {
1436 	GList *visible_list = NULL;
1437 	GList *scan;
1438 
1439 	for (scan = list; scan; scan = scan->next) {
1440 		GthFileData *file_data = scan->data;
1441 
1442 		if (_gth_browser_file_is_visible (browser, file_data))
1443 			visible_list = g_list_prepend (visible_list, g_object_ref (file_data));
1444 	}
1445 
1446 	return g_list_reverse (visible_list);
1447 }
1448 
1449 
1450 static gboolean _gth_browser_make_file_visible (GthBrowser  *browser,
1451 						GthFileData *file_data);
1452 
1453 
1454 static void
load_data_continue(LoadData * load_data,GList * loaded_files)1455 load_data_continue (LoadData *load_data,
1456 		    GList    *loaded_files)
1457 {
1458 	GthBrowser  *browser = load_data->browser;
1459 	GList       *files;
1460 	GFile       *loaded_folder;
1461 	gboolean     loaded_requested_folder;
1462 	GtkTreePath *path;
1463 	gboolean     changed_current_location;
1464 
1465 	if (! load_data_is_still_relevant (load_data)) {
1466 		load_data_cancelled (load_data);
1467 		return;
1468 	}
1469 
1470 	loaded_folder = (GFile *) load_data->current->data;
1471 	files = _gth_browser_get_visible_files (browser, loaded_files);
1472 	gth_folder_tree_set_children (GTH_FOLDER_TREE (browser->priv->folder_tree), loaded_folder, files);
1473 
1474 	path = gth_folder_tree_get_path (GTH_FOLDER_TREE (browser->priv->folder_tree), loaded_folder);
1475 	loaded_requested_folder = _g_file_equal (loaded_folder, load_data->requested_folder->file);
1476 	if ((path != NULL) && ! loaded_requested_folder)
1477 		gth_folder_tree_expand_row (GTH_FOLDER_TREE (browser->priv->folder_tree), path, FALSE);
1478 
1479 	if (! loaded_requested_folder) {
1480 		load_data_load_next_folder (load_data);
1481 
1482 		if (path != NULL)
1483 			gtk_tree_path_free (path);
1484 		_g_object_list_unref (files);
1485 		return;
1486 	}
1487 
1488 	load_data_done (load_data, NULL);
1489 
1490 	changed_current_location = gth_action_changes_folder (load_data->action);
1491 	if (changed_current_location) {
1492 		GthTest *filter;
1493 
1494 		if ((browser->priv->location_source != NULL)
1495 			&& (browser->priv->monitor_location != NULL))
1496 		{
1497 			gth_file_source_monitor_directory (browser->priv->location_source,
1498 							   browser->priv->monitor_location,
1499 							   FALSE);
1500 			_g_clear_object (&browser->priv->monitor_location);
1501 		}
1502 
1503 		_g_object_unref (browser->priv->location_source);
1504 		browser->priv->location_source = g_object_ref (load_data->file_source);
1505 
1506 		browser->priv->recalc_location_free_space = TRUE;
1507 
1508 		switch (load_data->action) {
1509 		case GTH_ACTION_GO_TO:
1510 		case GTH_ACTION_TREE_OPEN:
1511 			_gth_browser_set_location (browser, load_data->requested_folder);
1512 			if (browser->priv->location != NULL)
1513 				_gth_browser_history_add (browser, browser->priv->location->file);
1514 			_gth_browser_history_menu (browser);
1515 			break;
1516 		case GTH_ACTION_GO_BACK:
1517 		case GTH_ACTION_GO_FORWARD:
1518 			_gth_browser_set_location (browser, load_data->requested_folder);
1519 			_gth_browser_history_menu (browser);
1520 			break;
1521 		default:
1522 			break;
1523 		}
1524 
1525 		if (path != NULL) {
1526 			GList    *entry_points;
1527 			GList    *scan;
1528 			gboolean  is_entry_point = FALSE;
1529 
1530 			/* Collapse everything else after loading an entry point. */
1531 
1532 			entry_points = gth_main_get_all_entry_points ();
1533 			for (scan = entry_points; scan; scan = scan->next) {
1534 				GthFileData *file_data = scan->data;
1535 
1536 				if (g_file_equal (file_data->file, load_data->requested_folder->file)) {
1537 					gth_folder_tree_collapse_all (GTH_FOLDER_TREE (browser->priv->folder_tree));
1538 					is_entry_point = TRUE;
1539 					break;
1540 				}
1541 			}
1542 
1543 			gtk_tree_view_expand_row (GTK_TREE_VIEW (browser->priv->folder_tree), path, FALSE);
1544 			gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (browser->priv->folder_tree),
1545 						      path,
1546 						      NULL,
1547 						      is_entry_point,
1548 						      0.0,
1549 						      0.0);
1550 			gth_folder_tree_select_path (GTH_FOLDER_TREE (browser->priv->folder_tree), path);
1551 
1552 			_g_object_list_unref (entry_points);
1553 		}
1554 
1555 		filter = _gth_browser_get_file_filter (browser);
1556 		gth_file_list_set_filter (GTH_FILE_LIST (browser->priv->file_list), filter);
1557 		gth_file_list_set_files (GTH_FILE_LIST (browser->priv->file_list), files);
1558 		gth_file_list_set_filter (GTH_FILE_LIST (browser->priv->thumbnail_list), filter);
1559 		gth_file_list_set_files (GTH_FILE_LIST (browser->priv->thumbnail_list), files);
1560 		g_object_unref (filter);
1561 
1562 		if (gth_window_get_current_page (GTH_WINDOW (browser)) == GTH_BROWSER_PAGE_BROWSER)
1563 			gth_file_list_focus (GTH_FILE_LIST (browser->priv->file_list));
1564 
1565 		if (load_data->file_to_select != NULL)
1566 			gth_file_list_make_file_visible (GTH_FILE_LIST (browser->priv->file_list), load_data->file_to_select);
1567 		else if ((load_data->selected != NULL) || (load_data->vscroll > 0))
1568 			gth_file_list_restore_state (GTH_FILE_LIST (browser->priv->file_list), load_data->selected, load_data->vscroll);
1569 
1570 		_gth_browser_update_statusbar_list_info (browser);
1571 
1572 		g_assert (browser->priv->location_source != NULL);
1573 
1574 		if (browser->priv->monitor_location != NULL)
1575 			g_object_unref (browser->priv->monitor_location);
1576 		browser->priv->monitor_location = g_file_dup (browser->priv->location->file);
1577 		gth_file_source_monitor_directory (browser->priv->location_source,
1578 						   browser->priv->monitor_location,
1579 						   TRUE);
1580 
1581 		if (browser->priv->current_file != NULL) {
1582 			_gth_browser_update_current_file_position (browser);
1583 			gth_browser_update_title (browser);
1584 			gth_browser_update_statusbar_file_info (browser);
1585 			if (gth_window_get_current_page (GTH_WINDOW (browser)) == GTH_BROWSER_PAGE_VIEWER) {
1586 				_gth_browser_make_file_visible (browser, browser->priv->current_file);
1587 				if (browser->priv->viewer_page != NULL) {
1588 					gth_viewer_page_update_info (browser->priv->viewer_page, browser->priv->current_file);
1589 					gth_viewer_page_focus (browser->priv->viewer_page);
1590 				}
1591 			}
1592 		}
1593 
1594 		gth_browser_update_title (browser);
1595 		gth_browser_update_extra_widget (browser);
1596 
1597 		/* moving the "gth-browser-load-location-after" after the
1598 		 * LOCATION_READY signal emition can brake the extensions */
1599 
1600 		gth_hook_invoke ("gth-browser-load-location-after", browser, browser->priv->location);
1601 
1602 		g_signal_emit (G_OBJECT (browser),
1603 			       gth_browser_signals[LOCATION_READY],
1604 			       0,
1605 			       load_data->requested_folder->file,
1606 			       FALSE);
1607 
1608 		if (StartSlideshow) {
1609 			StartSlideshow = FALSE;
1610 			gth_hook_invoke ("slideshow", browser);
1611 		}
1612 
1613 		if (StartInFullscreen) {
1614 			StartInFullscreen = FALSE;
1615 			gth_browser_fullscreen (browser);
1616 		}
1617 	}
1618 
1619 	gth_browser_update_sensitivity (browser);
1620 
1621 	if (path != NULL)
1622 		gtk_tree_path_free (path);
1623 	_g_object_list_unref (files);
1624 	load_data_free (load_data);
1625 }
1626 
1627 
1628 static void
metadata_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)1629 metadata_ready_cb (GObject      *source_object,
1630 		   GAsyncResult *result,
1631 		   gpointer      user_data)
1632 {
1633 	LoadData *load_data = user_data;
1634 	GList    *files;
1635 	GError   *error = NULL;
1636 
1637 	files = _g_query_metadata_finish (result, &error);
1638 	if (error != NULL) {
1639 		load_data_error (load_data, error);
1640 		return;
1641 	}
1642 
1643 	load_data_continue (load_data, files);
1644 }
1645 
1646 
1647 static void
load_data_ready(LoadData * load_data,GList * files,GError * error)1648 load_data_ready (LoadData *load_data,
1649 		 GList    *files,
1650 		 GError   *error)
1651 {
1652 	if (error != NULL) {
1653 		load_data_error (load_data, error);
1654 	}
1655 	else if (gth_action_changes_folder (load_data->action)
1656 		 && _g_file_equal ((GFile *) load_data->current->data, load_data->requested_folder->file))
1657 	{
1658 		_g_query_metadata_async (files,
1659 					 _gth_browser_get_list_attributes (load_data->browser, TRUE),
1660 					 load_data->cancellable,
1661 					 metadata_ready_cb,
1662 					 load_data);
1663 	}
1664 	else
1665 		load_data_continue (load_data, files);
1666 }
1667 
1668 
1669 static void
_gth_browser_load_ready_cb(GthFileSource * file_source,GList * files,GError * error,gpointer user_data)1670 _gth_browser_load_ready_cb (GthFileSource *file_source,
1671 			    GList         *files,
1672 			    GError        *error,
1673 			    gpointer       user_data)
1674 {
1675 	load_data_ready ((LoadData *) user_data, files, error);
1676 }
1677 
1678 
1679 static void
mount_volume_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)1680 mount_volume_ready_cb (GObject      *source_object,
1681 		       GAsyncResult *result,
1682 		       gpointer      user_data)
1683 {
1684 	LoadData *load_data = user_data;
1685 	GError   *error = NULL;
1686 
1687 	if (! g_file_mount_enclosing_volume_finish (G_FILE (source_object),
1688 						    result,
1689 						    &error))
1690 	{
1691 		load_data_done (load_data, error);
1692 		load_data_free (load_data);
1693 		return;
1694 	}
1695 
1696 	gth_monitor_entry_points_changed (gth_main_get_default_monitor ());
1697 	_gth_browser_update_entry_point_list (load_data->browser);
1698 
1699 	/* try to load again */
1700 
1701 	if (! load_data_is_still_relevant (load_data)) {
1702 		load_data_cancelled (load_data);
1703 		return;
1704 	}
1705 
1706 	_gth_browser_remove_activity (load_data->browser);
1707 
1708 	_gth_browser_load (load_data->browser,
1709 			   load_data->requested_folder->file,
1710 			   load_data->file_to_select,
1711 			   NULL,
1712 			   0,
1713 			   load_data->action,
1714 			   load_data->automatic);
1715 
1716 	load_data_free (load_data);
1717 }
1718 
1719 
1720 static void
_gth_browser_hide_infobar(GthBrowser * browser)1721 _gth_browser_hide_infobar (GthBrowser *browser)
1722 {
1723 	if (gtk_widget_get_visible (browser->priv->infobar))
1724 		gtk_info_bar_response (GTK_INFO_BAR (browser->priv->infobar), GTK_RESPONSE_CLOSE);
1725 }
1726 
1727 
1728 static void
_gth_browser_load(GthBrowser * browser,GFile * location,GFile * file_to_select,GList * selected,double vscroll,GthAction action,gboolean automatic)1729 _gth_browser_load (GthBrowser *browser,
1730 		   GFile      *location,
1731 		   GFile      *file_to_select,
1732 		   GList      *selected,
1733 		   double      vscroll,
1734 		   GthAction   action,
1735 		   gboolean    automatic)
1736 {
1737 	LoadData *load_data;
1738 	GFile    *entry_point;
1739 
1740 	if (! automatic)
1741 		_gth_browser_hide_infobar (browser);
1742 
1743 	if (gth_action_changes_folder (action) && (browser->priv->last_folder_to_open != NULL)) {
1744 		LoadData *last_load_data = (LoadData *) browser->priv->last_folder_to_open;
1745 		g_cancellable_cancel (last_load_data->cancellable);
1746 	}
1747 
1748 	entry_point = gth_main_get_nearest_entry_point (location);
1749 	load_data = load_data_new (browser,
1750 				   location,
1751 				   file_to_select,
1752 				   selected,
1753 				   vscroll,
1754 				   action,
1755 				   automatic,
1756 				   entry_point);
1757 
1758 	_gth_browser_add_activity (browser);
1759 
1760 	if (entry_point == NULL) {
1761 		GMountOperation *mount_op;
1762 
1763 		/* try to mount the enclosing volume */
1764 
1765 		mount_op = gtk_mount_operation_new (GTK_WINDOW (browser));
1766 		g_file_mount_enclosing_volume (location,
1767 					       0,
1768 					       mount_op,
1769 					       load_data->cancellable,
1770 					       mount_volume_ready_cb,
1771 					       load_data);
1772 
1773 		g_object_unref (mount_op);
1774 
1775 		return;
1776 	}
1777 
1778 	if (gth_action_changes_folder (load_data->action))
1779 		gth_hook_invoke ("gth-browser-load-location-before", browser, load_data->requested_folder->file);
1780 
1781 	if (entry_point == NULL) {
1782 		GError *error;
1783 		char   *uri;
1784 
1785 		uri = g_file_get_uri (location);
1786 		error = g_error_new (GTH_ERROR, 0, _("No suitable module found for %s"), uri);
1787 		load_data_ready (load_data, NULL, error);
1788 
1789 		g_free (uri);
1790 
1791 		return;
1792 	}
1793 
1794 	if (action == GTH_ACTION_TREE_LIST_CHILDREN)
1795 		gth_folder_tree_loading_children (GTH_FOLDER_TREE (browser->priv->folder_tree), location);
1796 
1797 	if (load_data->file_source == NULL) {
1798 		GError *error;
1799 		char   *uri;
1800 
1801 		uri = g_file_get_uri (load_data->requested_folder->file);
1802 		error = g_error_new (GTH_ERROR, 0, _("No suitable module found for %s"), uri);
1803 		load_data_ready (load_data, NULL, error);
1804 
1805 		g_free (uri);
1806 
1807 		return;
1808 	}
1809 
1810 	if (! gth_file_source_shows_extra_widget (load_data->file_source))
1811 		gtk_widget_hide (browser->priv->list_info_bar);
1812 
1813 	{
1814 		char *uri;
1815 
1816 		uri = g_file_get_uri (load_data->requested_folder->file);
1817 
1818 		debug (DEBUG_INFO, "LOAD: %s\n", uri);
1819 		performance (DEBUG_INFO, "loading %s", uri);
1820 
1821 		g_free (uri);
1822 	}
1823 
1824 	load_data_load_next_folder (load_data);
1825 
1826 	g_object_unref (entry_point);
1827 }
1828 
1829 
1830 /* -- gth_browser_ask_whether_to_save -- */
1831 
1832 
1833 typedef struct {
1834 	GthBrowser         *browser;
1835 	GthBrowserCallback  callback;
1836 	gpointer            user_data;
1837 } AskSaveData;
1838 
1839 
1840 static void
ask_whether_to_save__done(AskSaveData * data,gboolean cancelled)1841 ask_whether_to_save__done (AskSaveData *data,
1842 			   gboolean     cancelled)
1843 {
1844 	if (data->browser->priv->current_file != NULL)
1845 		g_file_info_set_attribute_boolean (data->browser->priv->current_file->info, "gth::file::is-modified", cancelled);
1846 	if (data->callback != NULL)
1847 		(*data->callback) (data->browser, cancelled, data->user_data);
1848 	g_free (data);
1849 }
1850 
1851 
1852 static void
ask_whether_to_save__file_saved_cb(GthViewerPage * viewer_page,GthFileData * file_data,GError * error,gpointer user_data)1853 ask_whether_to_save__file_saved_cb (GthViewerPage *viewer_page,
1854 				    GthFileData   *file_data,
1855 				    GError        *error,
1856 				    gpointer       user_data)
1857 {
1858 	AskSaveData *data = user_data;
1859 	gboolean     error_occurred;
1860 
1861 	error_occurred = error != NULL;
1862 	if (error != NULL)
1863 		_gth_browser_show_error (data->browser, _("Could not save the file"), error);
1864 	ask_whether_to_save__done (data, error_occurred);
1865 }
1866 
1867 
1868 enum {
1869 	RESPONSE_SAVE,
1870 	RESPONSE_NO_SAVE,
1871 };
1872 
1873 
1874 static void
ask_whether_to_save__response_cb(GtkWidget * dialog,int response_id,AskSaveData * data)1875 ask_whether_to_save__response_cb (GtkWidget   *dialog,
1876 				  int          response_id,
1877 				  AskSaveData *data)
1878 {
1879 	gtk_widget_destroy (dialog);
1880 
1881 	if ((response_id == RESPONSE_SAVE) && (data->browser->priv->viewer_page != NULL))
1882 		gth_viewer_page_save (data->browser->priv->viewer_page,
1883 				      NULL,
1884 				      ask_whether_to_save__file_saved_cb,
1885 				      data);
1886 	else
1887 		ask_whether_to_save__done (data, response_id != RESPONSE_NO_SAVE);
1888 }
1889 
1890 
1891 void
gth_browser_ask_whether_to_save(GthBrowser * browser,GthBrowserCallback callback,gpointer user_data)1892 gth_browser_ask_whether_to_save (GthBrowser         *browser,
1893 				 GthBrowserCallback  callback,
1894 				 gpointer            user_data)
1895 {
1896 	AskSaveData *data;
1897 	char        *title;
1898 	GtkWidget   *d;
1899 
1900 	data = g_new0 (AskSaveData, 1);
1901 	data->browser = browser;
1902 	data->callback = callback;
1903 	data->user_data = user_data;
1904 
1905 	gtk_window_present (GTK_WINDOW (browser));
1906 
1907 	title = g_strdup_printf (_("Save changes to file “%s”?"), g_file_info_get_display_name (browser->priv->current_file->info));
1908 	d = _gtk_message_dialog_new (GTK_WINDOW (browser),
1909 				     GTK_DIALOG_MODAL,
1910 				     _GTK_ICON_NAME_DIALOG_QUESTION,
1911 				     title,
1912 				     _("If you don’t save, changes to the file will be permanently lost."),
1913 				     _("Do _Not Save"), RESPONSE_NO_SAVE,
1914 				     _GTK_LABEL_CANCEL, GTK_RESPONSE_CANCEL,
1915 				     _GTK_LABEL_SAVE, RESPONSE_SAVE,
1916 				     NULL);
1917 	g_signal_connect (G_OBJECT (d),
1918 			  "response",
1919 			  G_CALLBACK (ask_whether_to_save__response_cb),
1920 			  data);
1921 
1922 	gtk_widget_show (d);
1923 
1924 	g_free (title);
1925 }
1926 
1927 
1928 /* -- _gth_browser_close -- */
1929 
1930 
1931 static void
_gth_browser_show_pointer_on_viewer(GthBrowser * browser,gboolean show)1932 _gth_browser_show_pointer_on_viewer (GthBrowser *browser,
1933 				     gboolean    show)
1934 {
1935 	browser->priv->pointer_visible = show;
1936 	if (browser->priv->viewer_page != NULL)
1937 		gth_viewer_page_show_pointer (GTH_VIEWER_PAGE (browser->priv->viewer_page), show);
1938 }
1939 
1940 
1941 static void
_gth_browser_deactivate_viewer_page(GthBrowser * browser)1942 _gth_browser_deactivate_viewer_page (GthBrowser *browser)
1943 {
1944 	if (browser->priv->viewer_page != NULL) {
1945 		if (browser->priv->fullscreen)
1946 			_gth_browser_show_pointer_on_viewer (browser, TRUE);
1947 		gth_hook_invoke ("gth-browser-deactivate-viewer-page", browser);
1948 		gth_viewer_page_deactivate (browser->priv->viewer_page);
1949 		gth_browser_set_viewer_widget (browser, NULL);
1950 		g_object_unref (browser->priv->viewer_page);
1951 		browser->priv->viewer_page = NULL;
1952 	}
1953 }
1954 
1955 
1956 static void
_gth_browser_close_final_step(gpointer user_data)1957 _gth_browser_close_final_step (gpointer user_data)
1958 {
1959 	GthBrowser *browser = user_data;
1960 	gboolean    last_window;
1961 
1962 	last_window = g_list_length (gtk_application_get_windows (gtk_window_get_application (GTK_WINDOW (browser)))) == 1;
1963 
1964 	if (gtk_widget_get_realized (GTK_WIDGET (browser))) {
1965 		gboolean        maximized;
1966 		GtkAllocation   allocation;
1967 		char          **sidebar_sections;
1968 
1969 		/* Save visualization options only if the window is not maximized. */
1970 
1971 		maximized = _gtk_window_get_is_maximized (GTK_WINDOW (browser));
1972 		if (! maximized && ! browser->priv->fullscreen && gtk_widget_get_visible (GTK_WIDGET (browser))) {
1973 			int width, height;
1974 			int size_set = FALSE;
1975 
1976 			if (gth_window_get_current_page (GTH_WINDOW (browser)) == GTH_BROWSER_PAGE_BROWSER) {
1977 				gtk_window_get_size (GTK_WINDOW (browser), &width, &height);
1978 				size_set = TRUE;
1979 			}
1980 			else
1981 				size_set = gth_window_get_page_size (GTH_WINDOW (browser),
1982 								     GTH_BROWSER_PAGE_BROWSER,
1983 								     &width,
1984 								     &height);
1985 
1986 			if (size_set) {
1987 				g_settings_set_int (browser->priv->browser_settings, PREF_BROWSER_WINDOW_WIDTH, width);
1988 				g_settings_set_int (browser->priv->browser_settings, PREF_BROWSER_WINDOW_HEIGHT, height);
1989 			}
1990 		}
1991 
1992 		g_settings_set_boolean (browser->priv->browser_settings, PREF_BROWSER_WINDOW_MAXIMIZED, maximized);
1993 
1994 		gtk_widget_get_allocation (browser->priv->browser_sidebar, &allocation);
1995 		if (allocation.width > MIN_SIDEBAR_SIZE)
1996 			g_settings_set_int (browser->priv->browser_settings, PREF_BROWSER_BROWSER_SIDEBAR_WIDTH, allocation.width);
1997 
1998 		g_settings_set_enum (browser->priv->browser_settings, PREF_BROWSER_VIEWER_SIDEBAR, browser->priv->viewer_sidebar);
1999 
2000 		g_settings_set_enum (browser->priv->browser_settings, PREF_FULLSCREEN_SIDEBAR, browser->priv->fullscreen_state.sidebar);
2001 		g_settings_set_boolean (browser->priv->browser_settings, PREF_FULLSCREEN_THUMBNAILS_VISIBLE, browser->priv->fullscreen_state.thumbnail_list);
2002 
2003 		sidebar_sections = gth_sidebar_get_sections_status (GTH_SIDEBAR (browser->priv->file_properties));
2004 		g_settings_set_strv (browser->priv->browser_settings, PREF_BROWSER_SIDEBAR_SECTIONS, (const char **) sidebar_sections);
2005 		g_strfreev (sidebar_sections);
2006 	}
2007 
2008 	/**/
2009 
2010 	_gth_browser_deactivate_viewer_page (browser);
2011 
2012 	gth_hook_invoke ("gth-browser-close", browser);
2013 
2014 	if (gtk_widget_get_realized (GTK_WIDGET (browser)) && last_window) {
2015 		if (g_settings_get_boolean (browser->priv->browser_settings, PREF_BROWSER_GO_TO_LAST_LOCATION)
2016 		    && (browser->priv->location != NULL))
2017 		{
2018 			char *uri;
2019 
2020 			uri = g_file_get_uri (browser->priv->location->file);
2021 			_g_settings_set_uri (browser->priv->browser_settings, PREF_BROWSER_STARTUP_LOCATION, uri);
2022 			g_free (uri);
2023 
2024 			if (browser->priv->current_file != NULL) {
2025 				uri = g_file_get_uri (browser->priv->current_file->file);
2026 				_g_settings_set_uri (browser->priv->browser_settings, PREF_BROWSER_STARTUP_CURRENT_FILE, uri);
2027 				g_free (uri);
2028 			}
2029 			else
2030 				_g_settings_set_uri (browser->priv->browser_settings, PREF_BROWSER_STARTUP_CURRENT_FILE, "");
2031 		}
2032 
2033 		if (browser->priv->default_sort_type != NULL) {
2034 			g_settings_set_string (browser->priv->browser_settings, PREF_BROWSER_SORT_TYPE, browser->priv->default_sort_type->name);
2035 			g_settings_set_boolean (browser->priv->browser_settings, PREF_BROWSER_SORT_INVERSE, browser->priv->default_sort_inverse);
2036 		}
2037 
2038 		gth_filterbar_save_filter (GTH_FILTERBAR (browser->priv->filterbar), "active_filter.xml");
2039 
2040 		_gth_browser_history_save (browser);
2041 
2042 		gth_hook_invoke ("gth-browser-close-last-window", browser);
2043 	}
2044 
2045 	if (browser->priv->progress_dialog != NULL) {
2046 		g_object_remove_weak_pointer (G_OBJECT (browser->priv->progress_dialog), (gpointer*) &(browser->priv->progress_dialog));
2047 		gtk_widget_destroy (browser->priv->progress_dialog);
2048 	}
2049 
2050 	g_settings_sync ();
2051 
2052 	gtk_widget_destroy (GTK_WIDGET (browser));
2053 }
2054 
2055 
2056 static void
_gth_browser_close_step4(gpointer user_data)2057 _gth_browser_close_step4 (gpointer user_data)
2058 {
2059 	GthBrowser *browser = user_data;
2060 
2061 	gth_file_list_cancel (GTH_FILE_LIST (browser->priv->thumbnail_list),
2062 			      _gth_browser_close_final_step,
2063 			      browser);
2064 }
2065 
2066 
2067 static void
_gth_browser_close_step3(gpointer user_data)2068 _gth_browser_close_step3 (gpointer user_data)
2069 {
2070 	GthBrowser *browser = user_data;
2071 
2072 	gth_file_list_cancel (GTH_FILE_LIST (browser->priv->file_list),
2073 			      _gth_browser_close_step4,
2074 			      browser);
2075 }
2076 
2077 
2078 static void _gth_browser_cancel (GthBrowser *browser,
2079 				 DataFunc    done_func,
2080 				 gpointer    user_data);
2081 
2082 
2083 static void
_gth_browser_real_close(GthBrowser * browser)2084 _gth_browser_real_close (GthBrowser *browser)
2085 {
2086 	if (browser->priv->closing)
2087 		return;
2088 
2089 	browser->priv->closing = TRUE;
2090 
2091 	/* disconnect from the settings */
2092 
2093 	_g_signal_handlers_disconnect_by_data (browser->priv->browser_settings, browser);
2094 	_g_signal_handlers_disconnect_by_data (browser->priv->messages_settings, browser);
2095 	_g_signal_handlers_disconnect_by_data (browser->priv->desktop_interface_settings, browser);
2096 
2097 	/* disconnect from the monitor */
2098 
2099 	g_signal_handler_disconnect (gth_main_get_default_monitor (),
2100 				     browser->priv->folder_changed_id);
2101 	g_signal_handler_disconnect (gth_main_get_default_monitor (),
2102 				     browser->priv->file_renamed_id);
2103 	g_signal_handler_disconnect (gth_main_get_default_monitor (),
2104 				     browser->priv->metadata_changed_id);
2105 	g_signal_handler_disconnect (gth_main_get_default_monitor (),
2106 				     browser->priv->emblems_changed_id);
2107 	g_signal_handler_disconnect (gth_main_get_default_monitor (),
2108 				     browser->priv->entry_points_changed_id);
2109 	g_signal_handler_disconnect (gth_main_get_default_monitor (),
2110 				     browser->priv->order_changed_id);
2111 	g_signal_handler_disconnect (gth_main_get_default_monitor (),
2112 				     browser->priv->shortcuts_changed_id);
2113 
2114 	/* remove timeouts */
2115 
2116 	if (browser->priv->motion_signal != 0) {
2117 		g_signal_handler_disconnect (browser, browser->priv->motion_signal);
2118 		browser->priv->motion_signal = 0;
2119 	}
2120 
2121 	if (browser->priv->hide_mouse_timeout != 0) {
2122 		g_source_remove (browser->priv->hide_mouse_timeout);
2123 		browser->priv->hide_mouse_timeout = 0;
2124 	}
2125 
2126 	if (browser->priv->construct_step2_event != 0) {
2127 		g_source_remove (browser->priv->construct_step2_event);
2128 		browser->priv->construct_step2_event = 0;
2129 	}
2130 
2131 	if (browser->priv->selection_changed_event != 0) {
2132 		g_source_remove (browser->priv->selection_changed_event);
2133 		browser->priv->selection_changed_event = 0;
2134 	}
2135 
2136 	if (browser->priv->folder_tree_open_folder_id != 0) {
2137 		g_source_remove (browser->priv->folder_tree_open_folder_id);
2138 		browser->priv->folder_tree_open_folder_id = 0;
2139 	}
2140 
2141 	/* cancel async operations */
2142 
2143 	_gth_browser_cancel (browser, _gth_browser_close_step3, browser);
2144 }
2145 
2146 
2147 static void
close__file_saved_cb(GthBrowser * browser,gboolean cancelled,gpointer user_data)2148 close__file_saved_cb (GthBrowser *browser,
2149 		      gboolean    cancelled,
2150 		      gpointer    user_data)
2151 {
2152 	if (! cancelled)
2153 		_gth_browser_real_close (browser);
2154 }
2155 
2156 
2157 static void
_gth_browser_close(GthWindow * window)2158 _gth_browser_close (GthWindow *window)
2159 {
2160 	GthBrowser *browser = (GthBrowser *) window;
2161 
2162 	if (browser->priv->background_tasks != NULL) {
2163 		gtk_window_present (GTK_WINDOW (browser->priv->progress_dialog));
2164 		return;
2165 	}
2166 
2167 	if (g_settings_get_boolean (browser->priv->messages_settings, PREF_MSG_SAVE_MODIFIED_IMAGE)
2168 	    && gth_browser_get_file_modified (browser))
2169 	{
2170 		gth_browser_ask_whether_to_save (browser,
2171 						 close__file_saved_cb,
2172 						 NULL);
2173 	}
2174 	else
2175 		_gth_browser_real_close (browser);
2176 }
2177 
2178 
2179 /* --- _gth_browser_set_current_page --- */
2180 
2181 
2182 static GtkWidget *
_gth_browser_get_browser_file_properties_container(GthBrowser * browser)2183 _gth_browser_get_browser_file_properties_container (GthBrowser *browser)
2184 {
2185 	if (browser->priv->file_properties_on_the_right)
2186 		return browser->priv->browser_right_container;
2187 	else
2188 		return browser->priv->browser_sidebar;
2189 }
2190 
2191 
2192 static void
_gth_browser_update_header_section_visibility(GthBrowser * browser,GthBrowserHeaderSection section,gboolean visible)2193 _gth_browser_update_header_section_visibility (GthBrowser              *browser,
2194 					       GthBrowserHeaderSection  section,
2195 					       gboolean                 visible)
2196 {
2197 	GtkWidget *header_section;
2198 
2199 	header_section = browser->priv->header_sections[section];
2200 	gtk_widget_set_visible (header_section, visible);
2201 }
2202 
2203 
2204 /* -- hide_mouse_pointer_after_delay -- */
2205 
2206 
2207 typedef struct {
2208 	GthBrowser *browser;
2209 	GdkDevice  *device;
2210 } HideMouseData;
2211 
2212 
2213 static gboolean
pointer_on_widget(GtkWidget * widget,GdkDevice * device)2214 pointer_on_widget (GtkWidget *widget,
2215 		   GdkDevice *device)
2216 {
2217 	GdkWindow *widget_win;
2218 	int        px, py, w, h;
2219 
2220 	if (! gtk_widget_get_visible (widget) || ! gtk_widget_get_realized (widget))
2221 		return FALSE;
2222 
2223 	widget_win = gtk_widget_get_window (widget);
2224 	gdk_window_get_device_position (widget_win,
2225 					device,
2226 					&px,
2227 					&py,
2228 					0);
2229 	w = gdk_window_get_width (widget_win);
2230 	h = gdk_window_get_height (widget_win);
2231 
2232 	return ((px >= 0) && (px <= w) && (py >= 0) && (py <= h));
2233 }
2234 
2235 
2236 static gboolean
pointer_on_control(HideMouseData * hmdata,GList * controls)2237 pointer_on_control (HideMouseData *hmdata,
2238 		    GList         *controls)
2239 {
2240 	GList *scan;
2241 
2242 	if (hmdata->device == NULL)
2243 		return FALSE;
2244 
2245 	for (scan = controls; scan; scan = scan->next)
2246 		if (pointer_on_widget ((GtkWidget *) scan->data, hmdata->device))
2247 			return TRUE;
2248 
2249 	return FALSE;
2250 }
2251 
2252 
2253 static gboolean
hide_mouse_pointer_cb(gpointer data)2254 hide_mouse_pointer_cb (gpointer data)
2255 {
2256 	HideMouseData *hmdata = data;
2257 	GthBrowser    *browser = hmdata->browser;
2258 
2259 	browser->priv->hide_mouse_timeout = 0;
2260 
2261 	/* do not hide the pointer if it's over a viewer control */
2262 
2263 	if (browser->priv->keep_mouse_visible
2264 	    || pointer_on_control (hmdata, browser->priv->fixed_viewer_controls)
2265 	    || pointer_on_control (hmdata, browser->priv->viewer_controls)
2266 	    || pointer_on_widget (browser->priv->viewer_sidebar_container, hmdata->device))
2267 	{
2268 		return FALSE;
2269 	}
2270 
2271 	browser->priv->pointer_visible = FALSE;
2272 	gtk_widget_hide (browser->priv->fullscreen_toolbar);
2273 	g_list_foreach (browser->priv->fixed_viewer_controls, (GFunc) gtk_widget_hide, NULL);
2274 	_gth_browser_show_pointer_on_viewer (browser, FALSE);
2275 
2276 	return FALSE;
2277 }
2278 
2279 
2280 static void
hide_mouse_pointer_after_delay(GthBrowser * browser,GdkDevice * device)2281 hide_mouse_pointer_after_delay (GthBrowser *browser,
2282 				GdkDevice  *device)
2283 {
2284 	HideMouseData *hmdata;
2285 
2286 	if (browser->priv->hide_mouse_timeout != 0)
2287 		g_source_remove (browser->priv->hide_mouse_timeout);
2288 
2289 	hmdata = g_new0 (HideMouseData, 1);
2290 	hmdata->browser = browser;
2291 	hmdata->device = (device != NULL) ? device : _gtk_widget_get_client_pointer (GTK_WIDGET (browser));
2292 	browser->priv->hide_mouse_timeout = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT,
2293 									HIDE_MOUSE_DELAY,
2294 									hide_mouse_pointer_cb,
2295 									hmdata,
2296 									g_free);
2297 }
2298 
2299 
2300 static gboolean
_gth_browser_can_change_image(GthBrowser * browser)2301 _gth_browser_can_change_image (GthBrowser *browser)
2302 {
2303 	return ! gth_sidebar_tool_is_active (GTH_SIDEBAR (browser->priv->file_properties));
2304 }
2305 
2306 
2307 static void
show_fixed_viewer_control(GtkWidget * control,GthBrowser * browser)2308 show_fixed_viewer_control (GtkWidget  *control,
2309 		           GthBrowser *browser)
2310 {
2311 	if (! _gth_browser_can_change_image (browser)) {
2312 		if (control == browser->priv->next_image_button)
2313 			return;
2314 		if (control == browser->priv->previous_image_button)
2315 			return;
2316 	}
2317 
2318 	gtk_widget_show (control);
2319 }
2320 
2321 
2322 static gboolean
viewer_motion_notify_event_cb(GtkWidget * widget,GdkEventMotion * event,gpointer data)2323 viewer_motion_notify_event_cb (GtkWidget      *widget,
2324 			       GdkEventMotion *event,
2325 			       gpointer        data)
2326 {
2327 	GthBrowser *browser = data;
2328 
2329 	if (! pointer_on_widget (browser->priv->viewer_container, event->device))
2330 		return FALSE;
2331 
2332 	if (browser->priv->last_mouse_x == 0.0)
2333 		browser->priv->last_mouse_x = event->x;
2334 	if (browser->priv->last_mouse_y == 0.0)
2335 		browser->priv->last_mouse_y = event->y;
2336 
2337 	if ((abs (browser->priv->last_mouse_x - event->x) > MOTION_THRESHOLD)
2338 	    || (abs (browser->priv->last_mouse_y - event->y) > MOTION_THRESHOLD))
2339 	{
2340 		if (! browser->priv->pointer_visible) {
2341 			browser->priv->pointer_visible = TRUE;
2342 			if (browser->priv->fullscreen)
2343 				gtk_widget_show (browser->priv->fullscreen_toolbar);
2344 			g_list_foreach (browser->priv->fixed_viewer_controls, (GFunc) show_fixed_viewer_control, browser);
2345 		}
2346 		_gth_browser_show_pointer_on_viewer (browser, TRUE);
2347 	}
2348 
2349 	hide_mouse_pointer_after_delay (browser, event->device);
2350 
2351 	browser->priv->last_mouse_x = event->x;
2352 	browser->priv->last_mouse_y = event->y;
2353 
2354 	return FALSE;
2355 }
2356 
2357 
2358 static void
_gth_browser_update_header_bar_content(GthBrowser * browser)2359 _gth_browser_update_header_bar_content (GthBrowser *browser)
2360 {
2361 	int      page;
2362 	gboolean active_tool;
2363 	gboolean section_visible;
2364 
2365 	page = gth_window_get_current_page (GTH_WINDOW (browser));
2366 
2367         section_visible = (page == GTH_BROWSER_PAGE_BROWSER);
2368 	_gth_browser_update_header_section_visibility (browser, GTH_BROWSER_HEADER_SECTION_BROWSER_NAVIGATION, section_visible);
2369 	_gth_browser_update_header_section_visibility (browser, GTH_BROWSER_HEADER_SECTION_BROWSER_LOCATIONS, section_visible);
2370 	_gth_browser_update_header_section_visibility (browser, GTH_BROWSER_HEADER_SECTION_BROWSER_COMMANDS, section_visible);
2371 	_gth_browser_update_header_section_visibility (browser, GTH_BROWSER_HEADER_SECTION_BROWSER_VIEW, section_visible);
2372 	_gth_browser_update_header_section_visibility (browser, GTH_BROWSER_HEADER_SECTION_BROWSER_TOOLS, section_visible);
2373 	_gth_browser_update_header_section_visibility (browser, GTH_BROWSER_HEADER_SECTION_BROWSER_METADATA_TOOLS, section_visible);
2374 
2375 	active_tool = _gth_browser_file_tool_is_active (browser);
2376 	section_visible = (page == GTH_BROWSER_PAGE_VIEWER) && ! active_tool;
2377 	_gth_browser_update_header_section_visibility (browser, GTH_BROWSER_HEADER_SECTION_VIEWER_NAVIGATION, section_visible);
2378 	_gth_browser_update_header_section_visibility (browser, GTH_BROWSER_HEADER_SECTION_VIEWER_COMMANDS, section_visible);
2379 	_gth_browser_update_header_section_visibility (browser, GTH_BROWSER_HEADER_SECTION_VIEWER_VIEW, section_visible);
2380 	_gth_browser_update_header_section_visibility (browser, GTH_BROWSER_HEADER_SECTION_VIEWER_EDIT, section_visible);
2381 	_gth_browser_update_header_section_visibility (browser, GTH_BROWSER_HEADER_SECTION_VIEWER_EDIT_METADATA, section_visible);
2382 	_gth_browser_update_header_section_visibility (browser, GTH_BROWSER_HEADER_SECTION_VIEWER_SIDEBAR, section_visible);
2383 	_gth_browser_update_header_section_visibility (browser, GTH_BROWSER_HEADER_SECTION_VIEWER_OTHER_COMMANDS, section_visible);
2384 	_gth_browser_update_header_section_visibility (browser, GTH_BROWSER_HEADER_SECTION_VIEWER_OTHER_VIEW, section_visible);
2385 
2386 	section_visible = (page == GTH_BROWSER_PAGE_VIEWER) && active_tool;
2387 	_gth_browser_update_header_section_visibility (browser, GTH_BROWSER_HEADER_SECTION_EDITOR_NAVIGATION, section_visible);
2388 	_gth_browser_update_header_section_visibility (browser, GTH_BROWSER_HEADER_SECTION_EDITOR_VIEW, section_visible);
2389 	_gth_browser_update_header_section_visibility (browser, GTH_BROWSER_HEADER_SECTION_EDITOR_COMMANDS, section_visible);
2390 	_gth_browser_update_header_section_visibility (browser, GTH_BROWSER_HEADER_SECTION_EDITOR_APPLY, section_visible);
2391 
2392 	section_visible = (page == GTH_BROWSER_PAGE_VIEWER);
2393 	if (active_tool) {
2394 		GtkWidget *toolbox;
2395 		GtkWidget *file_tool;
2396 
2397 		toolbox = gth_sidebar_get_toolbox (GTH_SIDEBAR (browser->priv->file_properties));
2398 		file_tool = gth_toolbox_get_active_tool (GTH_TOOLBOX (toolbox));
2399 		section_visible = gth_file_tool_get_zoomable (GTH_FILE_TOOL (file_tool));
2400 		gtk_button_set_label (GTK_BUTTON (browser->priv->apply_editor_changes_button),
2401 				      gth_file_tool_get_changes_image (GTH_FILE_TOOL (file_tool)) ? _("Accept") : _("_Close"));
2402 	}
2403 	_gth_browser_update_header_section_visibility (browser, GTH_BROWSER_HEADER_SECTION_VIEWER_ZOOM, section_visible);
2404 
2405 	gtk_widget_set_visible (browser->priv->menu_button, ! ((page == GTH_BROWSER_PAGE_VIEWER) && active_tool));
2406 
2407 	gth_browser_update_title (browser);
2408 }
2409 
2410 
2411 static void
_gth_browser_real_set_current_page(GthWindow * window,int page)2412 _gth_browser_real_set_current_page (GthWindow *window,
2413 				    int        page)
2414 {
2415 	GthBrowser *browser = (GthBrowser *) window;
2416 	int         prev_page;
2417 	int         width;
2418 	int         height;
2419 
2420 	prev_page = gth_window_get_current_page (window);
2421 	if (page == prev_page)
2422 		return;
2423 
2424 	GTH_WINDOW_CLASS (gth_browser_parent_class)->set_current_page (window, page);
2425 
2426 	/* update the ui commands */
2427 
2428 	gth_statusbar_show_section (GTH_STATUSBAR (browser->priv->statusbar), (page == GTH_BROWSER_PAGE_BROWSER) ? GTH_STATUSBAR_SECTION_FILE_LIST : GTH_STATUSBAR_SECTION_FILE);
2429 	_gth_browser_hide_infobar (browser);
2430 
2431 	if (page == GTH_BROWSER_PAGE_VIEWER) {
2432 		if (browser->priv->viewer_page != NULL) {
2433 			gth_viewer_page_show (browser->priv->viewer_page);
2434 			_gth_browser_show_pointer_on_viewer (browser, FALSE);
2435 			hide_mouse_pointer_after_delay (browser, NULL);
2436 
2437 			browser->priv->last_mouse_x = 0.0;
2438 			browser->priv->last_mouse_y = 0.0;
2439 			if (browser->priv->motion_signal == 0)
2440 				browser->priv->motion_signal = g_signal_connect (browser,
2441 										 "motion_notify_event",
2442 										 G_CALLBACK (viewer_motion_notify_event_cb),
2443 										 browser);
2444 		}
2445 	}
2446 	else {
2447 		if (browser->priv->viewer_page != NULL)
2448 			gth_viewer_page_hide (browser->priv->viewer_page);
2449 
2450 		if (browser->priv->motion_signal != 0) {
2451 			g_signal_handler_disconnect (browser, browser->priv->motion_signal);
2452 			browser->priv->motion_signal = 0;
2453 		}
2454 		if (browser->priv->hide_mouse_timeout != 0) {
2455 			g_source_remove (browser->priv->hide_mouse_timeout);
2456 			browser->priv->hide_mouse_timeout = 0;
2457 		}
2458 	}
2459 
2460 	_gth_browser_update_header_bar_content (browser);
2461         gtk_widget_set_visible (browser->priv->browser_status_commands, page == GTH_BROWSER_PAGE_BROWSER);
2462 	gtk_widget_set_visible (browser->priv->viewer_status_commands, page == GTH_BROWSER_PAGE_VIEWER);
2463 
2464 	/* move the sidebar from the browser to the viewer and vice-versa */
2465 
2466 	gtk_widget_unrealize (browser->priv->file_properties);
2467 	if (page == GTH_BROWSER_PAGE_BROWSER) {
2468 		GtkWidget *file_properties_parent;
2469 
2470 		file_properties_parent = _gth_browser_get_browser_file_properties_container (browser);
2471 		_gtk_widget_reparent (browser->priv->file_properties, file_properties_parent);
2472 		/* restore the child properties that gtk_widget_reparent doesn't preserve. */
2473 		gtk_container_child_set (GTK_CONTAINER (file_properties_parent),
2474 					 browser->priv->file_properties,
2475 					 "resize", ! browser->priv->file_properties_on_the_right,
2476 					 "shrink", FALSE,
2477 					 NULL);
2478 	}
2479 	else
2480 		_gtk_widget_reparent (browser->priv->file_properties, browser->priv->viewer_sidebar_container);
2481 
2482 	/* update the sidebar state depending on the current visible page */
2483 
2484 	if (page == GTH_BROWSER_PAGE_BROWSER) {
2485 		gth_sidebar_show_properties (GTH_SIDEBAR (browser->priv->file_properties));
2486 		if (gth_window_get_action_state (GTH_WINDOW (browser), "browser-properties"))
2487 			gth_browser_show_file_properties (browser);
2488 		else
2489 			gth_browser_hide_sidebar (browser);
2490 	}
2491 	else if (page == GTH_BROWSER_PAGE_VIEWER) {
2492 		if (browser->priv->viewer_sidebar == GTH_SIDEBAR_STATE_PROPERTIES)
2493 			gth_browser_show_file_properties (browser);
2494 		else if (browser->priv->viewer_sidebar == GTH_SIDEBAR_STATE_TOOLS)
2495 			gth_browser_show_viewer_tools (browser);
2496 		else
2497 			gth_browser_hide_sidebar (browser);
2498 	}
2499 
2500 	/* save the browser window size */
2501 
2502 	if ((prev_page == GTH_BROWSER_PAGE_BROWSER) && ! (browser->priv->fullscreen || browser->priv->was_fullscreen)) {
2503 		gtk_window_get_size (GTK_WINDOW (browser), &width, &height);
2504 		gth_window_save_page_size (GTH_WINDOW (browser), prev_page, width, height);
2505 	}
2506 
2507 	/* restore the browser window size */
2508 
2509 	if ((page == GTH_BROWSER_PAGE_BROWSER) && ! (browser->priv->fullscreen || browser->priv->was_fullscreen))
2510 		gth_window_apply_saved_size (GTH_WINDOW (window), page);
2511 
2512 	/* set the focus */
2513 
2514 	if (page == GTH_BROWSER_PAGE_BROWSER)
2515 		gth_file_list_focus (GTH_FILE_LIST (browser->priv->file_list));
2516 	else if (page == GTH_BROWSER_PAGE_VIEWER)
2517 		_gth_browser_make_file_visible (browser, browser->priv->current_file);
2518 
2519 	/* exit from fullscreen after switching to the browser */
2520 
2521 	if ((page == GTH_BROWSER_PAGE_BROWSER) && gth_browser_get_is_fullscreen (browser))
2522 		gth_browser_unfullscreen (browser);
2523 
2524 	/* extension hook */
2525 
2526 	gth_hook_invoke ("gth-browser-set-current-page", browser);
2527 
2528 	/* final updates */
2529 
2530 	gth_browser_update_title (browser);
2531 	gth_browser_update_sensitivity (browser);
2532 }
2533 
2534 
2535 static void
set_current_page__file_saved_cb(GthBrowser * browser,gboolean cancelled,gpointer user_data)2536 set_current_page__file_saved_cb (GthBrowser *browser,
2537 				 gboolean    cancelled,
2538 				 gpointer    user_data)
2539 {
2540 	if (cancelled)
2541 		return;
2542 
2543 	if (browser->priv->current_file != NULL)
2544 		gth_viewer_page_revert (browser->priv->viewer_page);
2545 	_gth_browser_real_set_current_page (GTH_WINDOW (browser), GPOINTER_TO_INT (user_data));
2546 }
2547 
2548 
2549 static void
_gth_browser_set_current_page(GthWindow * window,int page)2550 _gth_browser_set_current_page (GthWindow *window,
2551 			       int        page)
2552 {
2553 	GthBrowser *browser = GTH_BROWSER (window);
2554 
2555 	if (page == gth_window_get_current_page (window))
2556 		return;
2557 
2558 	if (g_settings_get_boolean (browser->priv->messages_settings, PREF_MSG_SAVE_MODIFIED_IMAGE)
2559 	    && gth_browser_get_file_modified (browser))
2560 	{
2561 		gth_browser_ask_whether_to_save (browser,
2562 						 set_current_page__file_saved_cb,
2563 						 GINT_TO_POINTER (page));
2564 	}
2565 	else
2566 		_gth_browser_real_set_current_page (window, page);
2567 }
2568 
2569 
2570 static void
gth_browser_finalize(GObject * object)2571 gth_browser_finalize (GObject *object)
2572 {
2573 	GthBrowser *browser = GTH_BROWSER (object);
2574 
2575 	g_list_free (browser->priv->fixed_viewer_controls);
2576 	g_hash_table_destroy (browser->priv->menu_managers);
2577 	browser_state_free (&browser->priv->state);
2578 	_g_object_unref (browser->priv->browser_settings);
2579 	_g_object_unref (browser->priv->messages_settings);
2580 	_g_object_unref (browser->priv->desktop_interface_settings);
2581 	g_free (browser->priv->location_free_space);
2582 	_g_object_unref (browser->priv->location_source);
2583 	_g_object_unref (browser->priv->monitor_location);
2584 	_g_object_unref (browser->priv->location);
2585 	_g_object_unref (browser->priv->current_file);
2586 	_g_object_unref (browser->priv->viewer_page);
2587 	_g_object_unref (browser->priv->image_preloader);
2588 	_g_object_list_unref (browser->priv->viewer_pages);
2589 	_g_object_list_unref (browser->priv->history);
2590 	gth_icon_cache_free (browser->priv->menu_icon_cache);
2591 	g_hash_table_unref (browser->priv->named_dialogs);
2592 	g_free (browser->priv->list_attributes);
2593 	_g_object_unref (browser->priv->folder_popup_file_data);
2594 	_g_object_unref (browser->priv->history_menu);
2595 	_g_object_unref (browser->priv->screen_profile);
2596 	gtk_tree_path_free (browser->priv->folder_tree_last_dest_row);
2597 
2598 	G_OBJECT_CLASS (gth_browser_parent_class)->finalize (object);
2599 }
2600 
2601 
2602 static void
gth_browser_class_init(GthBrowserClass * klass)2603 gth_browser_class_init (GthBrowserClass *klass)
2604 {
2605 	GObjectClass   *gobject_class;
2606 	GthWindowClass *window_class;
2607 
2608 	gobject_class = G_OBJECT_CLASS (klass);
2609 	gobject_class->finalize = gth_browser_finalize;
2610 
2611 	window_class = GTH_WINDOW_CLASS (klass);
2612 	window_class->close = _gth_browser_close;
2613 	window_class->set_current_page = _gth_browser_set_current_page;
2614 
2615 	/* signals */
2616 
2617 	gth_browser_signals[LOCATION_READY] =
2618 		g_signal_new ("location-ready",
2619 			      G_TYPE_FROM_CLASS (klass),
2620 			      G_SIGNAL_RUN_LAST,
2621 			      G_STRUCT_OFFSET (GthBrowserClass, location_ready),
2622 			      NULL, NULL,
2623 			      gth_marshal_VOID__OBJECT_BOOLEAN,
2624 			      G_TYPE_NONE,
2625 			      2,
2626 			      G_TYPE_OBJECT,
2627 			      G_TYPE_BOOLEAN);
2628 }
2629 
2630 
2631 static gboolean
viewer_container_get_child_position_cb(GtkOverlay * overlay,GtkWidget * widget,GdkRectangle * allocation,gpointer user_data)2632 viewer_container_get_child_position_cb (GtkOverlay   *overlay,
2633 					GtkWidget    *widget,
2634 					GdkRectangle *allocation,
2635 					gpointer      user_data)
2636 {
2637 	GthBrowser     *browser = user_data;
2638 	GtkAllocation   main_alloc;
2639 	gboolean        allocation_filled = FALSE;
2640 	gboolean	rtl;
2641 
2642 	rtl = gtk_widget_get_direction (GTK_WIDGET (overlay)) == GTK_TEXT_DIR_RTL;
2643 
2644 	gtk_widget_get_allocation (gtk_bin_get_child (GTK_BIN (overlay)), &main_alloc);
2645 	gtk_widget_get_preferred_width (widget, NULL, &allocation->width);
2646 	gtk_widget_get_preferred_height (widget, NULL, &allocation->height);
2647 
2648 	if (widget == browser->priv->previous_image_button) {
2649 		allocation->x = rtl ? main_alloc.width - allocation->width - OVERLAY_MARGIN :
2650 				OVERLAY_MARGIN;
2651 		allocation->y = (main_alloc.height - allocation->height) / 2;
2652 		allocation_filled = TRUE;
2653 	}
2654 	else if (widget == browser->priv->next_image_button) {
2655 		allocation->x = rtl ? OVERLAY_MARGIN :
2656 				main_alloc.width - allocation->width - OVERLAY_MARGIN;
2657 		allocation->y = (main_alloc.height - allocation->height) / 2;
2658 		allocation_filled = TRUE;
2659 	}
2660 
2661 	return allocation_filled;
2662 }
2663 
2664 
2665 static gboolean
folder_tree_open_folder_cb(gpointer user_data)2666 folder_tree_open_folder_cb (gpointer user_data)
2667 {
2668 	GthBrowser *browser = user_data;
2669 
2670 	if (browser->priv->folder_tree_open_folder_id != 0) {
2671 		g_source_remove (browser->priv->folder_tree_open_folder_id);
2672 		browser->priv->folder_tree_open_folder_id = 0;
2673 	}
2674 
2675 	gtk_tree_view_expand_row (GTK_TREE_VIEW (browser->priv->folder_tree),
2676 				  browser->priv->folder_tree_last_dest_row,
2677 				  FALSE);
2678 
2679 	return FALSE;
2680 }
2681 
2682 
2683 static gboolean
folder_tree_drag_motion_cb(GtkWidget * file_view,GdkDragContext * context,gint x,gint y,guint time,gpointer user_data)2684 folder_tree_drag_motion_cb (GtkWidget      *file_view,
2685 			    GdkDragContext *context,
2686 			    gint            x,
2687 			    gint            y,
2688 			    guint           time,
2689 			    gpointer        user_data)
2690 {
2691 	GthBrowser              *browser = user_data;
2692 	GtkTreePath             *path;
2693 	GtkTreeViewDropPosition  pos;
2694 
2695 	if (gdk_drag_context_get_suggested_action (context) == GDK_ACTION_ASK) {
2696 		gdk_drag_status (context, GDK_ACTION_ASK, time);
2697 		return FALSE;
2698 	}
2699 
2700 	if (! gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (file_view),
2701 					         x,
2702 					         y,
2703 					         &path,
2704 					         &pos))
2705 	{
2706 		gtk_tree_path_free (browser->priv->folder_tree_last_dest_row);
2707 		browser->priv->folder_tree_last_dest_row = NULL;
2708 
2709 		if (browser->priv->folder_tree_open_folder_id != 0) {
2710 			g_source_remove (browser->priv->folder_tree_open_folder_id);
2711 			browser->priv->folder_tree_open_folder_id = 0;
2712 		}
2713 
2714 		gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (file_view), NULL, 0);
2715 		gdk_drag_status (context, 0, time);
2716 		return TRUE;
2717 	}
2718 
2719 	if (pos == GTK_TREE_VIEW_DROP_BEFORE)
2720 		pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
2721 	if (pos == GTK_TREE_VIEW_DROP_AFTER)
2722 		pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
2723 
2724 	gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (file_view), path, pos);
2725 
2726 	if ((browser->priv->folder_tree_last_dest_row == NULL) || gtk_tree_path_compare (path, browser->priv->folder_tree_last_dest_row) != 0) {
2727 		gtk_tree_path_free (browser->priv->folder_tree_last_dest_row);
2728 		browser->priv->folder_tree_last_dest_row = gtk_tree_path_copy (path);
2729 
2730 		if (browser->priv->folder_tree_open_folder_id != 0)
2731 			g_source_remove (browser->priv->folder_tree_open_folder_id);
2732 		browser->priv->folder_tree_open_folder_id = g_timeout_add (AUTO_OPEN_FOLDER_DELAY, folder_tree_open_folder_cb, browser);
2733 	}
2734 
2735 	gdk_drag_status (context, GDK_ACTION_MOVE, time);
2736 	gtk_tree_path_free (path);
2737 
2738 	return TRUE;
2739 }
2740 
2741 
2742 static void
folder_tree_drag_data_received(GtkWidget * tree_view,GdkDragContext * context,int x,int y,GtkSelectionData * selection_data,guint info,guint time,gpointer user_data)2743 folder_tree_drag_data_received (GtkWidget        *tree_view,
2744 				GdkDragContext   *context,
2745 				int               x,
2746 				int               y,
2747 				GtkSelectionData *selection_data,
2748 				guint             info,
2749 				guint             time,
2750 				gpointer          user_data)
2751 {
2752 	GthBrowser     *browser = user_data;
2753 	gboolean        success = FALSE;
2754 	GdkDragAction   suggested_action;
2755 	GtkTreePath    *path;
2756 	GthFileData    *destination;
2757 	char          **uris;
2758 	GList          *file_list;
2759 
2760 	suggested_action = gdk_drag_context_get_suggested_action (context);
2761 
2762 	if ((suggested_action == GDK_ACTION_COPY)
2763 	    || (suggested_action == GDK_ACTION_MOVE)
2764 	    || (suggested_action == GDK_ACTION_ASK))
2765 	{
2766 		success = TRUE;
2767 	}
2768 
2769 	if (! gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (browser->priv->folder_tree),
2770 						 x, y,
2771 						 &path,
2772 						 NULL))
2773 	{
2774 		success = FALSE;
2775 	}
2776 
2777 	if (success && (suggested_action == GDK_ACTION_ASK)) {
2778 		GdkDragAction action = _gtk_menu_ask_drag_drop_action (tree_view, gdk_drag_context_get_actions (context));
2779 		gdk_drag_status (context, action, time);
2780 		success = gdk_drag_context_get_selected_action (context) != 0;
2781 	}
2782 
2783 	if (! success) {
2784 		gtk_drag_finish (context, FALSE, FALSE, time);
2785 		return;
2786 	}
2787 
2788 	destination = gth_folder_tree_get_file (GTH_FOLDER_TREE (browser->priv->folder_tree), path);
2789 	uris = gtk_selection_data_get_uris (selection_data);
2790 	file_list = _g_file_list_new_from_uriv (uris);
2791 	if (file_list != NULL)
2792 		gth_hook_invoke ("gth-browser-folder-tree-drag-data-received",
2793 				 browser,
2794 				 destination,
2795 				 file_list,
2796 				 gdk_drag_context_get_selected_action (context));
2797 
2798 	gtk_drag_finish (context, TRUE, FALSE, time);
2799 
2800 	_g_object_list_unref (file_list);
2801 	g_strfreev (uris);
2802 	_g_object_unref (destination);
2803 }
2804 
2805 
2806 static void
folder_tree_drag_data_get_cb(GtkWidget * widget,GdkDragContext * drag_context,GtkSelectionData * selection_data,guint info,guint time,gpointer user_data)2807 folder_tree_drag_data_get_cb (GtkWidget        *widget,
2808 			      GdkDragContext   *drag_context,
2809 			      GtkSelectionData *selection_data,
2810 			      guint             info,
2811 			      guint             time,
2812 			      gpointer          user_data)
2813 {
2814 	GthBrowser     *browser = user_data;
2815 	GthFileData    *file_data;
2816 	GthFileSource  *file_source;
2817 	char          **uris;
2818 
2819 	file_data = gth_folder_tree_get_selected (GTH_FOLDER_TREE (browser->priv->folder_tree));
2820 	if (file_data == NULL)
2821 		return;
2822 
2823 	file_source = gth_main_get_file_source (file_data->file);
2824 	if (file_source == NULL)
2825 		return;
2826 
2827 	if (gdk_drag_context_get_actions (drag_context) & GDK_ACTION_MOVE) {
2828 		GdkDragAction action = gth_file_source_can_cut (file_source) ? GDK_ACTION_MOVE : GDK_ACTION_COPY;
2829 		gdk_drag_status (drag_context, action, time);
2830 	}
2831 
2832 	uris = g_new (char *, 2);
2833 	uris[0] = g_file_get_uri (file_data->file);
2834 	uris[1] = NULL;
2835 	gtk_selection_data_set_uris (selection_data, uris);
2836 
2837 	g_strfreev (uris);
2838 	g_object_unref (file_source);
2839 	g_object_unref (file_data);
2840 }
2841 
2842 
2843 static void
folder_tree_open_cb(GthFolderTree * folder_tree,GFile * file,GthBrowser * browser)2844 folder_tree_open_cb (GthFolderTree *folder_tree,
2845 		     GFile         *file,
2846 		     GthBrowser    *browser)
2847 {
2848 	_gth_browser_load (browser, file, NULL, NULL, 0, GTH_ACTION_TREE_OPEN, FALSE);
2849 }
2850 
2851 
2852 static void
folder_tree_open_parent_cb(GthFolderTree * folder_tree,GthBrowser * browser)2853 folder_tree_open_parent_cb (GthFolderTree *folder_tree,
2854 			    GthBrowser    *browser)
2855 {
2856 	gth_browser_go_up (browser, 1);
2857 }
2858 
2859 
2860 static void
folder_tree_list_children_cb(GthFolderTree * folder_tree,GFile * file,GthBrowser * browser)2861 folder_tree_list_children_cb (GthFolderTree *folder_tree,
2862 			      GFile         *file,
2863 			      GthBrowser    *browser)
2864 {
2865 	_gth_browser_load (browser, file, NULL, NULL, 0, GTH_ACTION_TREE_LIST_CHILDREN, FALSE);
2866 }
2867 
2868 
2869 static void
folder_tree_folder_popup_cb(GthFolderTree * folder_tree,GthFileData * file_data,guint time,gpointer user_data)2870 folder_tree_folder_popup_cb (GthFolderTree *folder_tree,
2871 			     GthFileData   *file_data,
2872 			     guint          time,
2873 			     gpointer       user_data)
2874 {
2875 	GthBrowser    *browser = user_data;
2876 	GthFileSource *file_source;
2877 
2878 	gth_window_enable_action (GTH_WINDOW (browser), "open-folder-in-new-window", (file_data != NULL));
2879 
2880 	_g_object_unref (browser->priv->folder_popup_file_data);
2881 	browser->priv->folder_popup_file_data = _g_object_ref (file_data);
2882 
2883 	if (file_data != NULL)
2884 		file_source = gth_main_get_file_source (file_data->file);
2885 	else
2886 		file_source = NULL;
2887 	gth_hook_invoke ("gth-browser-folder-tree-popup-before", browser, file_source, file_data);
2888 
2889 	gtk_menu_popup_at_pointer (GTK_MENU (browser->priv->folder_popup), NULL);
2890 
2891 	if (file_data != NULL) {
2892 		GtkTreePath *path;
2893 
2894 		path = gth_folder_tree_get_path (GTH_FOLDER_TREE (browser->priv->folder_tree), file_data->file);
2895 		gth_folder_tree_select_path (GTH_FOLDER_TREE (browser->priv->folder_tree), path);
2896 
2897 		gtk_tree_path_free (path);
2898 	}
2899 
2900 	_g_object_unref (file_source);
2901 }
2902 
2903 
2904 static void
folder_popup_hide_cb(GtkWidget * widget,gpointer user_data)2905 folder_popup_hide_cb (GtkWidget *widget,
2906 		      gpointer   user_data)
2907 {
2908 	GthBrowser  *browser = user_data;
2909 	GtkTreePath *path;
2910 
2911 	if (browser->priv->location == NULL)
2912 		return;
2913 
2914 	path = gth_folder_tree_get_path (GTH_FOLDER_TREE (browser->priv->folder_tree), browser->priv->location->file);
2915 	if (path != NULL) {
2916 		gth_folder_tree_select_path (GTH_FOLDER_TREE (browser->priv->folder_tree), path);
2917 		gtk_tree_path_free (path);
2918 	}
2919 }
2920 
2921 
2922 GthFileData *
gth_browser_get_folder_popup_file_data(GthBrowser * browser)2923 gth_browser_get_folder_popup_file_data (GthBrowser *browser)
2924 {
2925 	return _g_object_ref (browser->priv->folder_popup_file_data);
2926 }
2927 
2928 
2929 static void
file_source_rename_ready_cb(GObject * object,GError * error,gpointer user_data)2930 file_source_rename_ready_cb (GObject  *object,
2931 			     GError   *error,
2932 			     gpointer  user_data)
2933 {
2934 	GthBrowser *browser = user_data;
2935 
2936 	g_object_unref (object);
2937 
2938 	if (error != NULL)
2939 		_gth_browser_show_error (browser, _("Could not change name"), error);
2940 }
2941 
2942 
2943 static void
folder_tree_rename_cb(GthFolderTree * folder_tree,GFile * file,const char * new_name,GthBrowser * browser)2944 folder_tree_rename_cb (GthFolderTree *folder_tree,
2945 		       GFile         *file,
2946 		       const char    *new_name,
2947 		       GthBrowser    *browser)
2948 {
2949 	GthFileSource *file_source;
2950 
2951 	file_source = gth_main_get_file_source (file);
2952 	gth_file_source_rename (file_source,
2953 				file,
2954 				new_name,
2955 				file_source_rename_ready_cb,
2956 				browser);
2957 }
2958 
2959 
2960 static void
toolbox_options_visibility_cb(GthToolbox * toolbox,gboolean toolbox_options_visible,GthBrowser * browser)2961 toolbox_options_visibility_cb (GthToolbox *toolbox,
2962 			       gboolean    toolbox_options_visible,
2963 			       GthBrowser *browser)
2964 {
2965 	_gth_browser_update_header_bar_content (browser);
2966 
2967 	if (toolbox_options_visible) {
2968 		GtkWidget *file_tool;
2969 
2970 		gth_browser_show_viewer_tools (browser);
2971 
2972 		gtk_widget_hide (browser->priv->next_image_button);
2973 		gtk_widget_hide (browser->priv->previous_image_button);
2974 		browser->priv->pointer_visible = FALSE;
2975 
2976 		file_tool = gth_toolbox_get_active_tool (toolbox);
2977 		if (file_tool != NULL)
2978 			gth_file_tool_populate_headerbar (GTH_FILE_TOOL (file_tool), browser);
2979 	}
2980 	else {
2981 		if (browser->priv->pointer_visible) {
2982 			gtk_widget_show (browser->priv->next_image_button);
2983 			gtk_widget_show (browser->priv->previous_image_button);
2984 		}
2985 		_gtk_container_remove_children (GTK_CONTAINER (browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_EDITOR_COMMANDS]), NULL, NULL);
2986 	}
2987 }
2988 
2989 
2990 static void
filterbar_changed_cb(GthFilterbar * filterbar,GthBrowser * browser)2991 filterbar_changed_cb (GthFilterbar *filterbar,
2992 		      GthBrowser   *browser)
2993 {
2994 	GthTest *filter;
2995 
2996 	filter = _gth_browser_get_file_filter (browser);
2997 	gth_file_list_set_filter (GTH_FILE_LIST (browser->priv->file_list), filter);
2998 	gth_file_list_set_filter (GTH_FILE_LIST (browser->priv->thumbnail_list), filter);
2999 	g_object_unref (filter);
3000 
3001 	_gth_browser_update_statusbar_list_info (browser);
3002 	gth_browser_update_sensitivity (browser);
3003 
3004 	if (_gth_browser_reload_required (browser))
3005 		gth_browser_reload (browser);
3006 	else if (browser->priv->current_file != NULL)
3007 		gth_file_list_make_file_visible (GTH_FILE_LIST (browser->priv->file_list), browser->priv->current_file->file);
3008 }
3009 
3010 
3011 static void
filterbar_personalize_cb(GthFilterbar * filterbar,GthBrowser * browser)3012 filterbar_personalize_cb (GthFilterbar *filterbar,
3013 			  GthBrowser   *browser)
3014 {
3015 	dlg_personalize_filters (browser);
3016 }
3017 
3018 
3019 static void
_gth_browser_change_file_list_order(GthBrowser * browser,int * new_order)3020 _gth_browser_change_file_list_order (GthBrowser *browser,
3021 				     int        *new_order)
3022 {
3023 	g_file_info_set_attribute_string (browser->priv->location->info, "sort::type", "general::unsorted");
3024 	g_file_info_set_attribute_boolean (browser->priv->location->info, "sort::inverse", FALSE);
3025 	gth_file_store_reorder (GTH_FILE_STORE (gth_file_view_get_model (GTH_FILE_VIEW (gth_browser_get_file_list_view (browser)))), new_order);
3026 	gth_file_store_reorder (GTH_FILE_STORE (gth_file_view_get_model (GTH_FILE_VIEW (gth_browser_get_thumbnail_list_view (browser)))), new_order);
3027 	_gth_browser_update_current_file_position (browser);
3028 	gth_browser_update_title (browser);
3029 }
3030 
3031 
3032 static void
file_attributes_ready_cb(GthFileSource * file_source,GList * files,GError * error,gpointer user_data)3033 file_attributes_ready_cb (GthFileSource *file_source,
3034 			  GList         *files,
3035 			  GError        *error,
3036 			  gpointer       user_data)
3037 {
3038 	MonitorEventData *monitor_data = user_data;
3039 	GthBrowser       *browser = monitor_data->browser;
3040 	GList            *visible_folders;
3041 
3042 	if (error != NULL) {
3043 		monitor_event_data_unref (monitor_data);
3044 		g_clear_error (&error);
3045 		return;
3046 	}
3047 
3048 	visible_folders = _gth_browser_get_visible_files (browser, files);
3049 
3050 	if (monitor_data->event == GTH_MONITOR_EVENT_CREATED) {
3051 		if (monitor_data->update_folder_tree)
3052 			gth_folder_tree_add_children (GTH_FOLDER_TREE (browser->priv->folder_tree), monitor_data->parent, visible_folders);
3053 		if (monitor_data->update_file_list) {
3054 			if (monitor_data->position >= 0)
3055 				_gth_browser_set_sort_order (browser,
3056 							     gth_main_get_sort_type ("general::unsorted"),
3057 							     FALSE,
3058 							     FALSE,
3059 							     TRUE);
3060 			gth_file_list_add_files (GTH_FILE_LIST (browser->priv->file_list), files, monitor_data->position);
3061 			gth_file_list_update_files (GTH_FILE_LIST (browser->priv->file_list), files);
3062 			gth_file_list_add_files (GTH_FILE_LIST (browser->priv->thumbnail_list), files, monitor_data->position);
3063 			gth_file_list_update_files (GTH_FILE_LIST (browser->priv->thumbnail_list), files);
3064 		}
3065 	}
3066 	else if (monitor_data->event == GTH_MONITOR_EVENT_CHANGED) {
3067 		if (monitor_data->update_folder_tree)
3068 			gth_folder_tree_update_children (GTH_FOLDER_TREE (browser->priv->folder_tree), monitor_data->parent, visible_folders);
3069 		if (monitor_data->update_file_list) {
3070 			gth_file_list_update_files (GTH_FILE_LIST (browser->priv->file_list), files);
3071 			gth_file_list_update_files (GTH_FILE_LIST (browser->priv->thumbnail_list), files);
3072 		}
3073 	}
3074 
3075 	if (browser->priv->current_file != NULL) {
3076 		GList *link;
3077 
3078 		link = gth_file_data_list_find_file (files, browser->priv->current_file->file);
3079 		if (link != NULL) {
3080 			GthFileData *file_data = link->data;
3081 			gth_browser_load_file (browser, file_data, FALSE);
3082 		}
3083 	}
3084 
3085 	_gth_browser_update_current_file_position (browser);
3086 	gth_browser_update_title (browser);
3087 	gth_browser_update_sensitivity (browser);
3088 	_gth_browser_update_statusbar_list_info (browser);
3089 
3090 	_g_object_list_unref (visible_folders);
3091 	monitor_event_data_unref (monitor_data);
3092 }
3093 
3094 
3095 static gboolean
_g_file_list_only_contains(GList * l,GFile * file)3096 _g_file_list_only_contains (GList *l,
3097 			    GFile *file)
3098 {
3099 	return (l->next == NULL) && _g_file_equal (file, G_FILE (l->data));
3100 }
3101 
3102 
3103 static GList *
_g_file_list_find_file_or_ancestor(GList * l,GFile * file)3104 _g_file_list_find_file_or_ancestor (GList *l,
3105 				    GFile *file)
3106 {
3107 	GList *link = NULL;
3108 	GList *scan;
3109 
3110 	for (scan = l; (link == NULL) && scan; scan = scan->next) {
3111 		GFile *parent;
3112 
3113 		parent = g_object_ref (file);
3114 		while ((parent != NULL) && ! g_file_equal (parent, (GFile *) scan->data)) {
3115 			GFile *tmp;
3116 
3117 			tmp = g_file_get_parent (parent);
3118 			g_object_unref (parent);
3119 			parent = tmp;
3120 		}
3121 
3122 		if (parent != NULL) {
3123 			link = scan;
3124 			g_object_unref (parent);
3125 		}
3126 	}
3127 
3128 	return link;
3129 }
3130 
3131 
3132 static void _gth_browser_load_file_more_options (GthBrowser  *browser,
3133 						 GthFileData *file_data,
3134 						 gboolean     view,
3135 						 gboolean     fullscreen,
3136 						 gboolean     no_delay);
3137 
3138 
3139 static void
folder_changed_cb(GthMonitor * monitor,GFile * parent,GList * list,int position,GthMonitorEvent event,GthBrowser * browser)3140 folder_changed_cb (GthMonitor      *monitor,
3141 		   GFile           *parent,
3142 		   GList           *list,
3143 		   int              position,
3144 		   GthMonitorEvent  event,
3145 		   GthBrowser      *browser)
3146 {
3147 	GtkTreePath *path;
3148 	gboolean     update_folder_tree;
3149 	gboolean     update_file_list;
3150 
3151 	if (browser->priv->location == NULL)
3152 		return;
3153 
3154 	if ((event == GTH_MONITOR_EVENT_DELETED)
3155 		&& _g_file_list_only_contains (list, browser->priv->location->file))
3156 	{
3157 		/* current location deleted -> load the previous location in
3158 		 * the folder tree. */
3159 
3160 		GtkTreePath *location_path;
3161 
3162 		location_path = gth_folder_tree_get_path (GTH_FOLDER_TREE (browser->priv->folder_tree), browser->priv->location->file);
3163 		if (location_path != NULL) {
3164 			GtkTreePath *prev_path;
3165 
3166 			prev_path = _gtk_tree_path_get_previous_or_parent (location_path);
3167 			if (prev_path != NULL) {
3168 				GthFileData *prev_file;
3169 
3170 				prev_file = gth_folder_tree_get_file (GTH_FOLDER_TREE (browser->priv->folder_tree), prev_path);
3171 				if (prev_file != NULL) {
3172 					_gth_browser_load (browser, prev_file->file, NULL, NULL, 0, GTH_ACTION_GO_TO, TRUE);
3173 					_g_object_unref (prev_file);
3174 				}
3175 
3176 				gtk_tree_path_free (prev_path);
3177 			}
3178 
3179 			gtk_tree_path_free (location_path);
3180 		}
3181 	}
3182 	else if ((event == GTH_MONITOR_EVENT_DELETED)
3183 		&& (_g_file_list_find_file_or_ancestor (list, browser->priv->location->file) != NULL))
3184 	{
3185 		_gth_browser_load (browser, parent, NULL, NULL, 0, GTH_ACTION_GO_TO, TRUE);
3186 	}
3187 	else if ((event == GTH_MONITOR_EVENT_CHANGED)
3188 		&& (_g_file_list_find_file_or_ancestor (list, browser->priv->location->file) != NULL))
3189 	{
3190 		_gth_browser_load (browser, browser->priv->location->file, NULL, NULL, 0, GTH_ACTION_GO_TO, TRUE);
3191 	}
3192 
3193 #if 0
3194 {
3195 	GList *scan;
3196 	g_print ("folder changed: %s [%s]\n", g_file_get_uri (parent), _g_enum_type_get_value (GTH_TYPE_MONITOR_EVENT, event)->value_nick);
3197 	for (scan = list; scan; scan = scan->next)
3198 		g_print ("   %s\n", g_file_get_uri (scan->data));
3199 }
3200 #endif
3201 
3202 	path = gth_folder_tree_get_path (GTH_FOLDER_TREE (browser->priv->folder_tree), parent);
3203 	update_folder_tree = (g_file_equal (parent, gth_folder_tree_get_root (GTH_FOLDER_TREE (browser->priv->folder_tree)))
3204 			      || ((path != NULL) && gth_folder_tree_is_loaded (GTH_FOLDER_TREE (browser->priv->folder_tree), path)));
3205 
3206 	update_file_list = g_file_equal (parent, browser->priv->location->file);
3207 	if (! update_file_list && (event != GTH_MONITOR_EVENT_CREATED)) {
3208 		GthFileStore *file_store;
3209 		GList        *scan;
3210 
3211 		file_store = (GthFileStore *) gth_file_view_get_model (GTH_FILE_VIEW (gth_file_list_get_view (GTH_FILE_LIST (browser->priv->file_list))));
3212 		for (scan = list; scan; scan = scan->next) {
3213 			if (gth_file_store_find_visible (file_store, (GFile *) scan->data, NULL)) {
3214 				update_file_list = TRUE;
3215 				break;
3216 			}
3217 		}
3218 	}
3219 
3220 	if (update_folder_tree || update_file_list) {
3221 		MonitorEventData *monitor_data;
3222 		gboolean          current_file_deleted = FALSE;
3223 		GthFileData      *new_file = NULL;
3224 
3225 		browser->priv->recalc_location_free_space = TRUE;
3226 
3227 		switch (event) {
3228 		case GTH_MONITOR_EVENT_CREATED:
3229 		case GTH_MONITOR_EVENT_CHANGED:
3230 			monitor_data = monitor_event_data_new ();
3231 			monitor_data->file_source = gth_main_get_file_source (parent);
3232 			monitor_data->parent = g_file_dup (parent);
3233 			monitor_data->position = position;
3234 			monitor_data->event = event;
3235 			monitor_data->browser = browser;
3236 			monitor_data->update_file_list = update_file_list;
3237 			monitor_data->update_folder_tree = update_folder_tree;
3238 			gth_file_source_read_attributes (monitor_data->file_source,
3239 						 	 list,
3240 						 	 _gth_browser_get_list_attributes (browser, FALSE),
3241 						 	 file_attributes_ready_cb,
3242 						 	 monitor_data);
3243 			break;
3244 
3245 		case GTH_MONITOR_EVENT_REMOVED:
3246 		case GTH_MONITOR_EVENT_DELETED:
3247 			if ((event == GTH_MONITOR_EVENT_REMOVED) && ! g_file_equal (parent, browser->priv->location->file))
3248 				break;
3249 
3250 			if (browser->priv->current_file != NULL) {
3251 				GList *link;
3252 
3253 				link = _g_file_list_find_file (list, browser->priv->current_file->file);
3254 				if (link != NULL) {
3255 					GthFileStore *file_store;
3256 					GtkTreeIter   iter;
3257 					gboolean      found = FALSE;
3258 
3259 					current_file_deleted = TRUE;
3260 
3261 					file_store = gth_browser_get_file_store (browser);
3262 					if (gth_file_store_find_visible (file_store, browser->priv->current_file->file, &iter)) {
3263 						if (gth_file_store_get_next_visible (file_store, &iter))
3264 							found = TRUE;
3265 						else if (gth_file_store_get_prev_visible (file_store, &iter))
3266 							found = TRUE;
3267 					}
3268 
3269 					if (found)
3270 						new_file = g_object_ref (gth_file_store_get_file (file_store, &iter));
3271 				}
3272 			}
3273 
3274 			if (update_folder_tree)
3275 				gth_folder_tree_delete_children (GTH_FOLDER_TREE (browser->priv->folder_tree), parent, list);
3276 
3277 			if (update_file_list) {
3278 				if (current_file_deleted)
3279 					_g_signal_handlers_block_by_data (gth_browser_get_file_list_view (browser), browser);
3280 				gth_file_list_delete_files (GTH_FILE_LIST (browser->priv->file_list), list);
3281 				gth_file_list_delete_files (GTH_FILE_LIST (browser->priv->thumbnail_list), list);
3282 				if (event == GTH_MONITOR_EVENT_DELETED)
3283 					gth_file_source_deleted_from_disk (browser->priv->location_source, browser->priv->location, list);
3284 				if (current_file_deleted)
3285 					_g_signal_handlers_unblock_by_data (gth_browser_get_file_list_view (browser), browser);
3286 			}
3287 
3288 			if (current_file_deleted && ! gth_browser_get_file_modified (browser)) {
3289 				g_file_info_set_attribute_boolean (browser->priv->current_file->info, "gth::file::is-modified", FALSE);
3290 
3291 				if (new_file != NULL) {
3292 					if (gth_window_get_current_page (GTH_WINDOW (browser)) == GTH_BROWSER_PAGE_VIEWER)
3293 						gth_browser_load_file (browser, new_file, FALSE);
3294 					else if (gth_window_get_current_page (GTH_WINDOW (browser)) == GTH_BROWSER_PAGE_BROWSER)
3295 						gth_file_list_make_file_visible (GTH_FILE_LIST (browser->priv->file_list), new_file->file);
3296 
3297 					_g_object_unref (new_file);
3298 				}
3299 				else {
3300 					gth_window_set_current_page (GTH_WINDOW (browser), GTH_BROWSER_PAGE_BROWSER);
3301 					_gth_browser_load_file_more_options (browser, NULL, FALSE, FALSE, FALSE);
3302 				}
3303 			}
3304 
3305 			_gth_browser_update_statusbar_list_info (browser);
3306 			gth_browser_update_sensitivity (browser);
3307 			break;
3308 
3309 		default:
3310 			break;
3311 		}
3312 	}
3313 
3314 	gtk_tree_path_free (path);
3315 }
3316 
3317 
3318 typedef struct {
3319 	GthBrowser    *browser;
3320 	GthFileSource *file_source;
3321 	GFile         *file;
3322 	GFile         *new_file;
3323 } RenameData;
3324 
3325 
3326 static void
rename_data_free(RenameData * rename_data)3327 rename_data_free (RenameData *rename_data)
3328 {
3329 	g_object_unref (rename_data->file_source);
3330 	g_object_unref (rename_data->file);
3331 	g_object_unref (rename_data->new_file);
3332 	g_free (rename_data);
3333 }
3334 
3335 
3336 static void
renamed_file_attributes_ready_cb(GthFileSource * file_source,GList * files,GError * error,gpointer user_data)3337 renamed_file_attributes_ready_cb (GthFileSource *file_source,
3338 				  GList         *files,
3339 				  GError        *error,
3340 				  gpointer       user_data)
3341 {
3342 	RenameData  *rename_data = user_data;
3343 	GthBrowser  *browser = rename_data->browser;
3344 	GthFileData *file_data;
3345 
3346 	if (error != NULL) {
3347 		rename_data_free (rename_data);
3348 		g_clear_error (&error);
3349 		return;
3350 	}
3351 
3352 	file_data = files->data;
3353 
3354 	gth_folder_tree_update_child (GTH_FOLDER_TREE (browser->priv->folder_tree), rename_data->file, file_data);
3355 	gth_file_list_rename_file (GTH_FILE_LIST (browser->priv->file_list), rename_data->file, file_data);
3356 	gth_file_list_rename_file (GTH_FILE_LIST (browser->priv->thumbnail_list), rename_data->file, file_data);
3357 
3358 	if (g_file_equal (rename_data->file, browser->priv->location->file)) {
3359 		GthFileData *new_location;
3360 		GFileInfo   *new_info;
3361 
3362 		new_location = gth_file_data_new (rename_data->new_file, browser->priv->location->info);
3363 		new_info = gth_file_source_get_file_info (rename_data->file_source, new_location->file, GFILE_DISPLAY_ATTRIBUTES);
3364 		_g_file_info_update (new_location->info, new_info);
3365 
3366 		_gth_browser_update_location (browser, new_location);
3367 
3368 		g_object_unref (new_info);
3369 		g_object_unref (new_location);
3370 	}
3371 	else if ((browser->priv->current_file != NULL) && g_file_equal (rename_data->file, browser->priv->current_file->file) && ! gth_browser_get_file_modified (browser))
3372 		gth_browser_load_file (browser, file_data, FALSE);
3373 
3374 	rename_data_free (rename_data);
3375 }
3376 
3377 
3378 static void
file_renamed_cb(GthMonitor * monitor,GFile * file,GFile * new_file,GthBrowser * browser)3379 file_renamed_cb (GthMonitor *monitor,
3380 		 GFile      *file,
3381 		 GFile      *new_file,
3382 		 GthBrowser *browser)
3383 {
3384 	RenameData *rename_data;
3385 	GList      *list;
3386 
3387 	gth_hook_invoke ("gth-browser-file-renamed", browser, file, new_file);
3388 
3389 	rename_data = g_new0 (RenameData, 1);
3390 	rename_data->browser = browser;
3391 	rename_data->file_source = gth_main_get_file_source (new_file);
3392 	rename_data->file = g_file_dup (file);
3393 	rename_data->new_file = g_file_dup (new_file);
3394 
3395 	list = g_list_prepend (NULL, rename_data->new_file);
3396 	gth_file_source_read_attributes (rename_data->file_source,
3397 				 	 list,
3398 				 	 _gth_browser_get_list_attributes (browser, FALSE),
3399 				 	 renamed_file_attributes_ready_cb,
3400 				 	 rename_data);
3401 
3402 	g_list_free (list);
3403 }
3404 
3405 
3406 void
gth_browser_update_statusbar_file_info(GthBrowser * browser)3407 gth_browser_update_statusbar_file_info (GthBrowser *browser)
3408 {
3409 	const char  *extra_info;
3410 	const char  *image_size;
3411 	const char  *file_size;
3412 	GString     *status;
3413 
3414 	if (browser->priv->current_file == NULL) {
3415 		gth_statusbar_set_primary_text (GTH_STATUSBAR (browser->priv->statusbar), "");
3416 		gth_statusbar_set_secondary_text (GTH_STATUSBAR (browser->priv->statusbar), "");
3417 		return;
3418 	}
3419 
3420 	extra_info = g_file_info_get_attribute_string (browser->priv->current_file->info, "gthumb::statusbar-extra-info");
3421 	image_size = g_file_info_get_attribute_string (browser->priv->current_file->info, "general::dimensions");
3422 	file_size = g_file_info_get_attribute_string (browser->priv->current_file->info, "gth::file::display-size");
3423 
3424 	status = g_string_new ("");
3425 
3426 	if (browser->priv->current_file_position >= 0)
3427 		g_string_append_printf (status, "%d/%d", browser->priv->current_file_position + 1, browser->priv->n_visibles);
3428 
3429 	if (image_size != NULL) {
3430 		g_string_append (status, STATUSBAR_SEPARATOR);
3431 		g_string_append (status, image_size);
3432 	}
3433 
3434 	if (gth_browser_get_file_modified (browser)) {
3435 		g_string_append (status, STATUSBAR_SEPARATOR);
3436 		g_string_append (status, _("Modified"));
3437 	}
3438 	else {
3439 		if (file_size != NULL) {
3440 			g_string_append (status, STATUSBAR_SEPARATOR);
3441 			g_string_append (status, file_size);
3442 		}
3443 	}
3444 
3445 	if (extra_info != NULL) {
3446 		g_string_append (status, STATUSBAR_SEPARATOR);
3447 		g_string_append (status, extra_info);
3448 	}
3449 
3450 	gth_statusbar_set_primary_text (GTH_STATUSBAR (browser->priv->statusbar), status->str);
3451 
3452 	g_string_free (status, TRUE);
3453 }
3454 
3455 
3456 static void
metadata_changed_cb(GthMonitor * monitor,GthFileData * file_data,GthBrowser * browser)3457 metadata_changed_cb (GthMonitor  *monitor,
3458 		     GthFileData *file_data,
3459 		     GthBrowser  *browser)
3460 {
3461 	if ((browser->priv->location != NULL) && g_file_equal (browser->priv->location->file, file_data->file)) {
3462 		GtkWidget *location_chooser;
3463 
3464 		if (file_data->info != browser->priv->location->info)
3465 			g_file_info_copy_into (file_data->info, browser->priv->location->info);
3466 
3467 		location_chooser = gth_location_bar_get_chooser (GTH_LOCATION_BAR (browser->priv->location_bar));
3468 		gth_location_chooser_reload (GTH_LOCATION_CHOOSER (location_chooser));
3469 
3470 		_gth_browser_update_location (browser, browser->priv->location);
3471 	}
3472 
3473 	if ((browser->priv->current_file != NULL) && g_file_equal (browser->priv->current_file->file, file_data->file)) {
3474 		if (file_data->info != browser->priv->current_file->info)
3475 			g_file_info_copy_into (file_data->info, browser->priv->current_file->info);
3476 
3477 		gth_sidebar_set_file (GTH_SIDEBAR (browser->priv->file_properties), browser->priv->current_file);
3478 
3479 		gth_browser_update_statusbar_file_info (browser);
3480 		gth_browser_update_title (browser);
3481 		gth_browser_update_sensitivity (browser);
3482 	}
3483 
3484 	gth_folder_tree_update_child (GTH_FOLDER_TREE (browser->priv->folder_tree), file_data->file, file_data);
3485 }
3486 
3487 
3488 typedef struct {
3489 	GthBrowser    *browser;
3490 	GthFileSource *file_source;
3491 	GList         *files;
3492 } EmblemsData;
3493 
3494 
3495 static void
emblems_data_free(EmblemsData * data)3496 emblems_data_free (EmblemsData *data)
3497 {
3498 	_g_object_list_unref (data->files);
3499 	g_object_unref (data->file_source);
3500 	g_free (data);
3501 }
3502 
3503 
3504 static void
emblems_attributes_ready_cb(GthFileSource * file_source,GList * files,GError * error,gpointer user_data)3505 emblems_attributes_ready_cb (GthFileSource *file_source,
3506 			     GList         *files,
3507 			     GError        *error,
3508 			     gpointer       user_data)
3509 {
3510 	EmblemsData *data = user_data;
3511 
3512 	if (error == NULL) {
3513 		GthBrowser *browser = data->browser;
3514 
3515 		gth_file_list_update_emblems (GTH_FILE_LIST (browser->priv->file_list), files);
3516 		gth_file_list_update_emblems (GTH_FILE_LIST (browser->priv->thumbnail_list), files);
3517 
3518 		if (browser->priv->current_file != NULL) {
3519 			GList *link;
3520 
3521 			link = gth_file_data_list_find_file (files, browser->priv->current_file->file);
3522 			if (link != NULL) {
3523 				GthFileData *current_file_data = link->data;
3524 				GObject     *emblems;
3525 
3526 				emblems = g_file_info_get_attribute_object (current_file_data->info, GTH_FILE_ATTRIBUTE_EMBLEMS);
3527 				g_file_info_set_attribute_object (browser->priv->current_file->info, GTH_FILE_ATTRIBUTE_EMBLEMS, emblems);
3528 				gth_browser_update_title (browser);
3529 			}
3530 		}
3531 	}
3532 
3533 	emblems_data_free (data);
3534 }
3535 
3536 
3537 static void
emblems_changed_cb(GthMonitor * monitor,GList * files,GthBrowser * browser)3538 emblems_changed_cb (GthMonitor  *monitor,
3539 		    GList       *files, /* GFile list */
3540 		    GthBrowser  *browser)
3541 {
3542 	EmblemsData *data;
3543 
3544 	if (browser->priv->location_source == NULL)
3545 		return;
3546 
3547 	data = g_new0 (EmblemsData, 1);
3548 	data->browser = browser;
3549 	data->file_source = g_object_ref (browser->priv->location_source);
3550 	data->files = _g_object_list_ref (files);
3551 
3552 	gth_file_source_read_attributes (browser->priv->location_source,
3553 					 files,
3554 					 GTH_FILE_ATTRIBUTE_EMBLEMS,
3555 					 emblems_attributes_ready_cb,
3556 					 data);
3557 }
3558 
3559 
3560 static void
entry_points_changed_cb(GthMonitor * monitor,GthBrowser * browser)3561 entry_points_changed_cb (GthMonitor *monitor,
3562 			 GthBrowser *browser)
3563 {
3564 	call_when_idle ((DataFunc) _gth_browser_update_entry_point_list, browser);
3565 }
3566 
3567 
3568 static void
order_changed_cb(GthMonitor * monitor,GFile * file,int * new_order,GthBrowser * browser)3569 order_changed_cb (GthMonitor *monitor,
3570 		  GFile      *file,
3571 		  int        *new_order,
3572 		  GthBrowser *browser)
3573 {
3574 	if ((browser->priv->location != NULL) && g_file_equal (file, browser->priv->location->file))
3575 		_gth_browser_change_file_list_order (browser, new_order);
3576 }
3577 
3578 
3579 static void
shortcuts_changed_cb(GthMonitor * monitor,GthBrowser * browser)3580 shortcuts_changed_cb (GthMonitor *monitor,
3581 		      GthBrowser *browser)
3582 {
3583 	gth_window_load_shortcuts (GTH_WINDOW (browser));
3584 }
3585 
3586 
3587 static void
pref_general_filter_changed(GSettings * settings,const char * key,gpointer user_data)3588 pref_general_filter_changed (GSettings  *settings,
3589 			     const char *key,
3590 			     gpointer    user_data)
3591 {
3592 	GthBrowser *browser = user_data;
3593 	GthTest    *filter;
3594 
3595 	filter = _gth_browser_get_file_filter (browser);
3596 	gth_file_list_set_filter (GTH_FILE_LIST (browser->priv->file_list), filter);
3597 	gth_file_list_set_filter (GTH_FILE_LIST (browser->priv->thumbnail_list), filter);
3598 
3599 	g_object_unref (filter);
3600 }
3601 
3602 
3603 static void
gth_file_list_popup_menu(GthBrowser * browser,GdkEventButton * event)3604 gth_file_list_popup_menu (GthBrowser     *browser,
3605 			  GdkEventButton *event)
3606 {
3607 	gth_hook_invoke ("gth-browser-file-list-popup-before", browser);
3608 	gtk_menu_popup_at_pointer (GTK_MENU (browser->priv->file_list_popup), (GdkEvent *) event);
3609 }
3610 
3611 
3612 static void
location_chooser_changed_cb(GthLocationChooser * chooser,gpointer user_data)3613 location_chooser_changed_cb (GthLocationChooser *chooser,
3614 			     gpointer            user_data)
3615 {
3616 	gth_browser_go_to (GTH_BROWSER (user_data), gth_location_chooser_get_current (chooser), NULL);
3617 }
3618 
3619 
3620 static gboolean
gth_file_list_button_press_cb(GtkWidget * widget,GdkEventButton * event,gpointer user_data)3621 gth_file_list_button_press_cb  (GtkWidget      *widget,
3622 				GdkEventButton *event,
3623 				gpointer        user_data)
3624 {
3625 	GthBrowser *browser = user_data;
3626 
3627 	if ((event->type == GDK_BUTTON_PRESS) && (event->button == 3)) {
3628 		GtkWidget *file_view;
3629 		int        pos;
3630 
3631 		file_view = gth_browser_get_file_list_view (browser);
3632 		pos = gth_file_view_get_at_position (GTH_FILE_VIEW (file_view), event->x, event->y);
3633 		if ((pos >= 0) && ! gth_file_selection_is_selected (GTH_FILE_SELECTION (file_view), pos)) {
3634 			gth_file_selection_unselect_all (GTH_FILE_SELECTION (file_view));
3635 			gth_file_selection_select (GTH_FILE_SELECTION (file_view), pos);
3636 			gth_file_view_set_cursor (GTH_FILE_VIEW (file_view), pos);
3637 		}
3638 		gth_file_list_popup_menu (browser, event);
3639 
3640 		return FALSE;
3641 	}
3642 	else if ((event->type == GDK_BUTTON_PRESS) && (event->button == 2)) {
3643 		GtkWidget *file_view;
3644 		int        pos;
3645 
3646 		file_view = gth_browser_get_file_list_view (browser);
3647 		pos = gth_file_view_get_at_position (GTH_FILE_VIEW (file_view), event->x, event->y);
3648 		if ((pos >= 0) && ! gth_file_selection_is_selected (GTH_FILE_SELECTION (file_view), pos)) {
3649 			gth_file_selection_unselect_all (GTH_FILE_SELECTION (file_view));
3650 			gth_file_selection_select (GTH_FILE_SELECTION (file_view), pos);
3651 			gth_file_view_set_cursor (GTH_FILE_VIEW (file_view), pos);
3652 		}
3653 		return FALSE;
3654 	}
3655 	else if ((event->type == GDK_BUTTON_PRESS) && (event->button == 1) && (event->state & GDK_MOD1_MASK)) {
3656 		GtkWidget *file_view;
3657 		int        pos;
3658 
3659 		file_view = gth_browser_get_file_list_view (browser);
3660 		pos = gth_file_view_get_at_position (GTH_FILE_VIEW (file_view), event->x, event->y);
3661 		if (pos >= 0) {
3662 			GtkTreeModel *file_store = gth_file_view_get_model (GTH_FILE_VIEW (file_view));
3663 			GtkTreeIter   iter;
3664 
3665 			if (gth_file_store_get_nth_visible (GTH_FILE_STORE (file_store), pos, &iter)) {
3666 				GthFileData *file_data;
3667 
3668 				file_data = gth_file_store_get_file (GTH_FILE_STORE (file_store), &iter);
3669 				_gth_browser_load_file_more_options (browser, file_data, TRUE, ! browser->priv->view_files_in_fullscreen, TRUE);
3670 			}
3671 		}
3672 	}
3673 	else if ((event->type == GDK_2BUTTON_PRESS) && (event->button == 2)) {
3674 		gth_browser_fullscreen (browser);
3675 		return TRUE;
3676 	}
3677 
3678 	return FALSE;
3679 }
3680 
3681 
3682 static gboolean
gth_file_list_popup_menu_cb(GtkWidget * widget,gpointer user_data)3683 gth_file_list_popup_menu_cb (GtkWidget *widget,
3684 			     gpointer   user_data)
3685 {
3686 	gth_file_list_popup_menu (GTH_BROWSER (user_data), NULL);
3687 	return TRUE;
3688 }
3689 
3690 
3691 static gboolean
update_selection_cb(gpointer user_data)3692 update_selection_cb (gpointer user_data)
3693 {
3694 	GthBrowser *browser = user_data;
3695 	int         n_selected;
3696 
3697 	g_source_remove (browser->priv->selection_changed_event);
3698 	browser->priv->selection_changed_event = 0;
3699 
3700 	if (browser->priv->closing)
3701 		return FALSE;
3702 
3703 	gth_browser_update_sensitivity (browser);
3704 	_gth_browser_update_statusbar_list_info (browser);
3705 
3706 	n_selected = gth_file_selection_get_n_selected (GTH_FILE_SELECTION (gth_browser_get_file_list_view (browser)));
3707 	gth_hook_invoke ("gth-browser-selection-changed", browser, n_selected);
3708 
3709 	if (gth_window_get_current_page (GTH_WINDOW (browser)) != GTH_BROWSER_PAGE_BROWSER)
3710 		return FALSE;
3711 
3712 	if (n_selected == 1) {
3713 		GList       *items;
3714 		GList       *file_list;
3715 		GthFileData *selected_file_data;
3716 
3717 		items = gth_file_selection_get_selected (GTH_FILE_SELECTION (gth_browser_get_file_list_view (browser)));
3718 		file_list = gth_file_list_get_files (GTH_FILE_LIST (gth_browser_get_file_list (browser)), items);
3719 		selected_file_data = (GthFileData *) file_list->data;
3720 		gth_browser_load_file (browser, selected_file_data, FALSE);
3721 
3722 		_g_object_list_unref (file_list);
3723 		_gtk_tree_path_list_free (items);
3724 	}
3725 	else
3726 		gth_browser_load_file (browser, NULL, FALSE);
3727 
3728 	return FALSE;
3729 }
3730 
3731 
3732 static void
gth_file_view_selection_changed_cb(GtkIconView * iconview,gpointer user_data)3733 gth_file_view_selection_changed_cb (GtkIconView *iconview,
3734 				    gpointer     user_data)
3735 {
3736 	GthBrowser *browser = user_data;
3737 
3738 	if (browser->priv->closing)
3739 		return;
3740 
3741 	if (browser->priv->selection_changed_event != 0)
3742 		g_source_remove (browser->priv->selection_changed_event);
3743 
3744 	browser->priv->selection_changed_event = g_timeout_add (UPDATE_SELECTION_DELAY,
3745 								update_selection_cb,
3746 								browser);
3747 }
3748 
3749 
3750 static void
gth_thumbnail_view_selection_changed_cb(GtkIconView * iconview,gpointer user_data)3751 gth_thumbnail_view_selection_changed_cb (GtkIconView *iconview,
3752 					 gpointer     user_data)
3753 {
3754 	GthBrowser *browser = user_data;
3755 	int         n_selected;
3756 
3757 	if (gth_window_get_current_page (GTH_WINDOW (browser)) != GTH_BROWSER_PAGE_VIEWER)
3758 		return;
3759 
3760 	n_selected = gth_file_selection_get_n_selected (GTH_FILE_SELECTION (gth_browser_get_thumbnail_list_view (browser)));
3761 	if (n_selected == 1) {
3762 		GList       *items;
3763 		GList       *file_list;
3764 		GthFileData *selected_file_data;
3765 
3766 		items = gth_file_selection_get_selected (GTH_FILE_SELECTION (gth_browser_get_thumbnail_list_view (browser)));
3767 		file_list = gth_file_list_get_files (GTH_FILE_LIST (gth_browser_get_file_list (browser)), items);
3768 		selected_file_data = (GthFileData *) file_list->data;
3769 		gth_browser_load_file (browser, selected_file_data, FALSE);
3770 
3771 		_g_object_list_unref (file_list);
3772 		_gtk_tree_path_list_free (items);
3773 	}
3774 }
3775 
3776 
3777 static void
gth_file_view_file_activated_cb(GthFileView * file_view,GtkTreePath * path,gpointer user_data)3778 gth_file_view_file_activated_cb (GthFileView *file_view,
3779 				 GtkTreePath *path,
3780 				 gpointer     user_data)
3781 {
3782 	GthBrowser   *browser = user_data;
3783 	GthFileStore *file_store;
3784 	GtkTreeIter   iter;
3785 
3786 	file_store = gth_browser_get_file_store (browser);
3787 	if (gtk_tree_model_get_iter (GTK_TREE_MODEL (file_store), &iter, path)) {
3788 		GthFileData *file_data;
3789 
3790 		file_data = gth_file_store_get_file (file_store, &iter);
3791 		if (file_data != NULL)
3792 			_gth_browser_load_file_more_options (browser, file_data, TRUE, browser->priv->view_files_in_fullscreen, TRUE);
3793 	}
3794 }
3795 
3796 
3797 static gboolean
gth_browser_file_list_key_press_cb(GthBrowser * browser,GdkEventKey * event)3798 gth_browser_file_list_key_press_cb (GthBrowser  *browser,
3799 			            GdkEventKey *event)
3800 {
3801 	gboolean activated;
3802 
3803 	activated = gth_window_activate_shortcut (GTH_WINDOW (browser),
3804 						  GTH_SHORTCUT_CONTEXT_BROWSER,
3805 						  event->keyval,
3806 						  event->state);
3807 
3808 	if (! activated)
3809 		activated = gth_hook_invoke_get ("gth-browser-file-list-key-press", browser, event) != NULL;
3810 
3811 	return activated;
3812 }
3813 
3814 
3815 typedef struct {
3816 	GthBrowser *browser;
3817 	GFile      *location;
3818 	GFile      *file_to_select;
3819 } NewWindowData;
3820 
3821 
3822 static void
new_window_data_free(gpointer user_data)3823 new_window_data_free (gpointer user_data)
3824 {
3825 	NewWindowData *data = user_data;
3826 
3827 	_g_object_unref (data->location);
3828 	_g_object_unref (data->file_to_select);
3829 	g_free (data);
3830 }
3831 
3832 
3833 static void
_gth_browser_construct_step2(gpointer user_data)3834 _gth_browser_construct_step2 (gpointer user_data)
3835 {
3836 	NewWindowData *data = user_data;
3837 	GthBrowser    *browser = data->browser;
3838 
3839 	browser->priv->construct_step2_event = 0;
3840 
3841 	_gth_browser_update_entry_point_list (browser);
3842 	_gth_browser_monitor_entry_points (browser);
3843 
3844 	gth_hook_invoke ("gth-browser-construct-idle-callback", browser);
3845 	gth_hook_invoke ("gth-browser-selection-changed", browser, 0);
3846 
3847 	if (data->file_to_select != NULL)
3848 		gth_browser_go_to (browser, data->location, data->file_to_select);
3849 	else
3850 		gth_browser_load_location (browser, data->location);
3851 
3852 	new_window_data_free (data);
3853 }
3854 
3855 
3856 static void
pref_browser_properties_on_the_right_changed(GSettings * settings,const char * key,gpointer user_data)3857 pref_browser_properties_on_the_right_changed (GSettings  *settings,
3858 					      const char *key,
3859 					      gpointer    user_data)
3860 {
3861 	GthBrowser *browser = user_data;
3862 	GtkWidget  *old_parent;
3863 	GtkWidget  *new_parent;
3864 
3865 	old_parent = _gth_browser_get_browser_file_properties_container (browser);
3866 	browser->priv->file_properties_on_the_right = g_settings_get_boolean (browser->priv->browser_settings, PREF_BROWSER_PROPERTIES_ON_THE_RIGHT);
3867 	new_parent = _gth_browser_get_browser_file_properties_container (browser);
3868 
3869 	if (old_parent == new_parent)
3870 		return;
3871 
3872 	if (gth_window_get_current_page (GTH_WINDOW (browser)) != GTH_BROWSER_PAGE_BROWSER)
3873 		return;
3874 
3875 	gtk_widget_unrealize (browser->priv->file_properties);
3876 	_gtk_widget_reparent (browser->priv->file_properties, new_parent);
3877 	/* restore the child properties that gtk_widget_reparent doesn't preserve. */
3878 	gtk_container_child_set (GTK_CONTAINER (new_parent),
3879 				 browser->priv->file_properties,
3880 				 "resize", ! browser->priv->file_properties_on_the_right,
3881 				 "shrink", FALSE,
3882 				 NULL);
3883 }
3884 
3885 
3886 static void
pref_ui_viewer_thumbnails_orient_changed(GSettings * settings,const char * key,gpointer user_data)3887 pref_ui_viewer_thumbnails_orient_changed (GSettings  *settings,
3888 					  const char *key,
3889 					  gpointer    user_data)
3890 {
3891 	GthBrowser     *browser = user_data;
3892 	GtkOrientation  viewer_thumbnails_orientation;
3893 	GtkWidget      *viewer_thumbnails_pane;
3894 	GtkWidget      *child1;
3895 	GtkWidget      *child2;
3896 
3897 	viewer_thumbnails_orientation = g_settings_get_enum (browser->priv->browser_settings, PREF_BROWSER_VIEWER_THUMBNAILS_ORIENT);
3898 	if (viewer_thumbnails_orientation == browser->priv->viewer_thumbnails_orientation)
3899 		return;
3900 	browser->priv->viewer_thumbnails_orientation = viewer_thumbnails_orientation;
3901 	if (viewer_thumbnails_orientation == GTK_ORIENTATION_HORIZONTAL)
3902 		viewer_thumbnails_pane = gtk_paned_new (GTK_ORIENTATION_VERTICAL);
3903 	else
3904 		viewer_thumbnails_pane = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
3905 
3906 	child1 = gtk_paned_get_child1 (GTK_PANED (browser->priv->viewer_thumbnails_pane));
3907 	child2 = gtk_paned_get_child2 (GTK_PANED (browser->priv->viewer_thumbnails_pane));
3908 
3909 	g_object_ref (child1);
3910 	gtk_widget_set_visible (child1, FALSE);
3911 	gtk_widget_unrealize (child1);
3912 	gtk_container_remove (GTK_CONTAINER (browser->priv->viewer_thumbnails_pane), child1);
3913 
3914 	g_object_ref (child2);
3915 	gtk_widget_set_visible (child2, FALSE);
3916 	gtk_widget_unrealize (child2);
3917 	gtk_container_remove (GTK_CONTAINER (browser->priv->viewer_thumbnails_pane), child2);
3918 
3919 	if (viewer_thumbnails_orientation == GTK_ORIENTATION_HORIZONTAL) {
3920 		gtk_paned_pack1 (GTK_PANED (viewer_thumbnails_pane), browser->priv->viewer_sidebar_pane, TRUE, FALSE);
3921 		gtk_paned_pack2 (GTK_PANED (viewer_thumbnails_pane), browser->priv->thumbnail_list, FALSE, FALSE);
3922 	}
3923 	else {
3924 		gtk_paned_pack1 (GTK_PANED (viewer_thumbnails_pane), browser->priv->thumbnail_list, FALSE, FALSE);
3925 		gtk_paned_pack2 (GTK_PANED (viewer_thumbnails_pane), browser->priv->viewer_sidebar_pane, TRUE, FALSE);
3926 	}
3927 
3928 	gtk_widget_set_visible (child1, TRUE);
3929 	gtk_widget_set_visible (child2, TRUE);
3930 
3931 	g_object_notify (G_OBJECT (child1), "parent");
3932 	g_object_unref (child1);
3933 
3934 	g_object_notify (G_OBJECT (child2), "parent");
3935 	g_object_unref (child2);
3936 
3937 	gtk_widget_destroy (browser->priv->viewer_thumbnails_pane);
3938 	browser->priv->viewer_thumbnails_pane = viewer_thumbnails_pane;
3939 
3940 	if (viewer_thumbnails_orientation == GTK_ORIENTATION_HORIZONTAL)
3941 		gth_file_list_set_mode (GTH_FILE_LIST (browser->priv->thumbnail_list), GTH_FILE_LIST_MODE_H_SIDEBAR);
3942 	else
3943 		gth_file_list_set_mode (GTH_FILE_LIST (browser->priv->thumbnail_list), GTH_FILE_LIST_MODE_V_SIDEBAR);
3944 
3945 	gth_window_attach_content (GTH_WINDOW (browser), GTH_BROWSER_PAGE_VIEWER, browser->priv->viewer_thumbnails_pane);
3946 
3947 	if (gth_window_get_action_state (GTH_WINDOW (browser), "show-thumbnail-list"))
3948 		gtk_widget_show (browser->priv->thumbnail_list);
3949 	gtk_widget_show (browser->priv->viewer_sidebar_pane);
3950 	gtk_widget_show (browser->priv->viewer_thumbnails_pane);
3951 }
3952 
3953 
3954 static void
_gth_browser_set_statusbar_visibility(GthBrowser * browser,gboolean visible)3955 _gth_browser_set_statusbar_visibility (GthBrowser *browser,
3956 				       gboolean    visible)
3957 {
3958 	g_return_if_fail (browser != NULL);
3959 
3960 	gth_window_change_action_state (GTH_WINDOW (browser), "show-statusbar", visible);
3961 	if (browser->priv->fullscreen)
3962 		return;
3963 
3964 	if (visible)
3965 		gtk_widget_show (browser->priv->statusbar);
3966 	else
3967 		gtk_widget_hide (browser->priv->statusbar);
3968 }
3969 
3970 
3971 static void
pref_ui_statusbar_visible_changed(GSettings * settings,const char * key,gpointer user_data)3972 pref_ui_statusbar_visible_changed (GSettings  *settings,
3973 				   const char *key,
3974 				   gpointer    user_data)
3975 {
3976 	GthBrowser *browser = user_data;
3977 	_gth_browser_set_statusbar_visibility (browser, g_settings_get_boolean (settings, key));
3978 }
3979 
3980 
3981 static void
_gth_browser_set_sidebar_visibility(GthBrowser * browser,gboolean visible)3982 _gth_browser_set_sidebar_visibility  (GthBrowser *browser,
3983 				      gboolean    visible)
3984 {
3985 	g_return_if_fail (browser != NULL);
3986 
3987 	gth_window_change_action_state (GTH_WINDOW (browser), "show-sidebar", visible);
3988 	if (visible) {
3989 		gtk_widget_show (browser->priv->browser_sidebar);
3990 		gtk_paned_set_position (GTK_PANED (browser->priv->browser_left_container),
3991 				        g_settings_get_int (browser->priv->browser_settings, PREF_BROWSER_BROWSER_SIDEBAR_WIDTH));
3992 	}
3993 	else
3994 		gtk_widget_hide (browser->priv->browser_sidebar);
3995 }
3996 
3997 
3998 static void
pref_ui_sidebar_visible_changed(GSettings * settings,const char * key,gpointer user_data)3999 pref_ui_sidebar_visible_changed (GSettings  *settings,
4000 				 const char *key,
4001 				 gpointer    user_data)
4002 {
4003 	GthBrowser *browser = user_data;
4004 	_gth_browser_set_sidebar_visibility (browser, g_settings_get_boolean (settings, key));
4005 }
4006 
4007 
4008 static gboolean
_gth_browser_make_file_visible(GthBrowser * browser,GthFileData * file_data)4009 _gth_browser_make_file_visible (GthBrowser  *browser,
4010 				GthFileData *file_data)
4011 {
4012 	int        file_pos;
4013 	GtkWidget *view;
4014 
4015 	if (file_data == NULL)
4016 		return FALSE;
4017 
4018 	file_pos = gth_file_store_get_pos (GTH_FILE_STORE (gth_browser_get_file_store (browser)), file_data->file);
4019 	if (file_pos < 0)
4020 		return FALSE;
4021 
4022 	/* the main file list */
4023 
4024 	view = gth_browser_get_file_list_view (browser);
4025 	g_signal_handlers_block_by_func (view, gth_file_view_selection_changed_cb, browser);
4026 	gth_file_selection_unselect_all (GTH_FILE_SELECTION (view));
4027 	gth_file_selection_select (GTH_FILE_SELECTION (view), file_pos);
4028 	gth_file_view_set_cursor (GTH_FILE_VIEW (view), file_pos);
4029 	g_signal_handlers_unblock_by_func (view, gth_file_view_selection_changed_cb, browser);
4030 
4031 	/* the thumbnail list in viewer mode */
4032 
4033 	view = gth_browser_get_thumbnail_list_view (browser);
4034 	g_signal_handlers_block_by_func (view, gth_thumbnail_view_selection_changed_cb, browser);
4035 	gth_file_selection_unselect_all (GTH_FILE_SELECTION (view));
4036 	gth_file_selection_select (GTH_FILE_SELECTION (view), file_pos);
4037 	gth_file_view_set_cursor (GTH_FILE_VIEW (view), file_pos);
4038 	g_signal_handlers_unblock_by_func (view, gth_thumbnail_view_selection_changed_cb, browser);
4039 
4040 	return TRUE;
4041 }
4042 
4043 
4044 static void
_gth_browser_set_thumbnail_list_visibility(GthBrowser * browser,gboolean visible)4045 _gth_browser_set_thumbnail_list_visibility (GthBrowser *browser,
4046 					    gboolean    visible)
4047 {
4048 	g_return_if_fail (browser != NULL);
4049 
4050 	gth_window_change_action_state (GTH_WINDOW (browser), "show-thumbnail-list", visible);
4051 	if (visible) {
4052 		gtk_widget_show (browser->priv->thumbnail_list);
4053 		_gth_browser_make_file_visible (browser, browser->priv->current_file);
4054 	}
4055 	else
4056 		gtk_widget_hide (browser->priv->thumbnail_list);
4057 }
4058 
4059 
4060 static void
pref_ui_thumbnail_list_visible_changed(GSettings * settings,const char * key,gpointer user_data)4061 pref_ui_thumbnail_list_visible_changed (GSettings  *settings,
4062 					const char *key,
4063 					gpointer    user_data)
4064 {
4065 	GthBrowser *browser = user_data;
4066 	_gth_browser_set_thumbnail_list_visibility (browser, g_settings_get_boolean (settings, key));
4067 }
4068 
4069 
4070 static void
pref_show_hidden_files_changed(GSettings * settings,const char * key,gpointer user_data)4071 pref_show_hidden_files_changed (GSettings  *settings,
4072 				const char *key,
4073 				gpointer    user_data)
4074 {
4075 	GthBrowser *browser = user_data;
4076 	gboolean    show_hidden_files;
4077 
4078 	show_hidden_files = g_settings_get_boolean (settings, key);
4079 	if (show_hidden_files == browser->priv->show_hidden_files)
4080 		return;
4081 
4082 	gth_window_change_action_state (GTH_WINDOW (browser), "show-hidden-files", show_hidden_files);
4083 	browser->priv->show_hidden_files = show_hidden_files;
4084 	gth_folder_tree_reset_loaded (GTH_FOLDER_TREE (browser->priv->folder_tree));
4085 	gth_browser_reload (browser);
4086 }
4087 
4088 
4089 static void
pref_fast_file_type_changed(GSettings * settings,const char * key,gpointer user_data)4090 pref_fast_file_type_changed (GSettings  *settings,
4091 			     const char *key,
4092 			     gpointer    user_data)
4093 {
4094 	GthBrowser *browser = user_data;
4095 
4096 	browser->priv->fast_file_type = g_settings_get_boolean (settings, key);
4097 	gth_browser_reload (browser);
4098 }
4099 
4100 
4101 static void
pref_thumbnail_size_changed(GSettings * settings,const char * key,gpointer user_data)4102 pref_thumbnail_size_changed (GSettings  *settings,
4103 			     const char *key,
4104 			     gpointer    user_data)
4105 {
4106 	GthBrowser *browser = user_data;
4107 
4108 	gth_file_list_set_thumb_size (GTH_FILE_LIST (browser->priv->file_list), g_settings_get_int (settings, key));
4109 	gth_browser_reload (browser);
4110 }
4111 
4112 
4113 static void
pref_thumbnail_caption_changed(GSettings * settings,const char * key,gpointer user_data)4114 pref_thumbnail_caption_changed (GSettings  *settings,
4115 				const char *key,
4116 				gpointer    user_data)
4117 {
4118 	GthBrowser *browser = user_data;
4119 	char       *caption;
4120 
4121 	caption = g_settings_get_string (settings, key);
4122 	gth_file_list_set_caption (GTH_FILE_LIST (browser->priv->file_list), caption);
4123 
4124 	if (_gth_browser_reload_required (browser))
4125 		gth_browser_reload (browser);
4126 
4127 	g_free (caption);
4128 }
4129 
4130 
4131 static void
pref_single_click_activation_changed(GSettings * settings,const char * key,gpointer user_data)4132 pref_single_click_activation_changed (GSettings  *settings,
4133 				      const char *key,
4134 				      gpointer    user_data)
4135 {
4136 	GthBrowser *browser = user_data;
4137 	gboolean    single_click = g_settings_get_boolean (settings, key);
4138 
4139 	gth_file_view_set_activate_on_single_click (GTH_FILE_VIEW (gth_file_list_get_view (GTH_FILE_LIST (browser->priv->file_list))), single_click);
4140 }
4141 
4142 
4143 static void
pref_open_files_in_fullscreen_changed(GSettings * settings,const char * key,gpointer user_data)4144 pref_open_files_in_fullscreen_changed (GSettings  *settings,
4145 				       const char *key,
4146 				       gpointer    user_data)
4147 {
4148 	GthBrowser *browser = user_data;
4149 	browser->priv->view_files_in_fullscreen = g_settings_get_boolean (settings, key);
4150 }
4151 
4152 
4153 static void
pref_msg_save_modified_image_changed(GSettings * settings,const char * key,gpointer user_data)4154 pref_msg_save_modified_image_changed (GSettings  *settings,
4155 				      const char *key,
4156 				      gpointer    user_data)
4157 {
4158 	GthBrowser *browser = user_data;
4159 	browser->priv->ask_to_save_modified_images = g_settings_get_boolean (settings, key);
4160 }
4161 
4162 
4163 static void
pref_scroll_action_changed(GSettings * settings,const char * key,gpointer user_data)4164 pref_scroll_action_changed (GSettings  *settings,
4165 			    const char *key,
4166 			    gpointer    user_data)
4167 {
4168 	GthBrowser *browser = user_data;
4169 	browser->priv->scroll_action = g_settings_get_enum (settings, key);
4170 }
4171 
4172 
4173 static gboolean
_gth_browser_realize(GtkWidget * browser,gpointer * data)4174 _gth_browser_realize (GtkWidget *browser,
4175 		      gpointer  *data)
4176 {
4177 	gth_hook_invoke ("gth-browser-realize", browser);
4178 
4179 	return FALSE;
4180 }
4181 
4182 
4183 static gboolean
_gth_browser_unrealize(GtkWidget * browser,gpointer * data)4184 _gth_browser_unrealize (GtkWidget *browser,
4185 			gpointer  *data)
4186 {
4187 	gth_hook_invoke ("gth-browser-unrealize", browser);
4188 
4189 	return FALSE;
4190 }
4191 
4192 
4193 static void
_gth_browser_register_fixed_viewer_control(GthBrowser * browser,GtkWidget * widget)4194 _gth_browser_register_fixed_viewer_control (GthBrowser *browser,
4195 					    GtkWidget  *widget)
4196 {
4197 	browser->priv->fixed_viewer_controls = g_list_prepend (browser->priv->fixed_viewer_controls, widget);
4198 }
4199 
4200 
4201 static gboolean
browser_key_press_cb(GthBrowser * browser,GdkEventKey * event)4202 browser_key_press_cb (GthBrowser  *browser,
4203 		      GdkEventKey *event)
4204 {
4205 	GtkWidget *focus_widget;
4206 
4207 	switch (gth_window_get_current_page (GTH_WINDOW (browser))) {
4208 	case GTH_BROWSER_PAGE_VIEWER:
4209 		if (! _gth_browser_file_tool_is_active (browser))
4210 			return gth_browser_viewer_key_press_cb (browser, event);
4211 		break;
4212 
4213 	case GTH_BROWSER_PAGE_BROWSER:
4214 		focus_widget = gtk_window_get_focus (GTK_WINDOW (browser));
4215 		if (! GTK_IS_ENTRY (focus_widget) && ! GTK_IS_TREE_VIEW (focus_widget))
4216 			return gth_browser_file_list_key_press_cb (browser, event);
4217 		break;
4218 
4219 	default:
4220 		break;
4221 	}
4222 	return FALSE;
4223 }
4224 
4225 
4226 static void
gth_browser_init(GthBrowser * browser)4227 gth_browser_init (GthBrowser *browser)
4228 {
4229 	int             window_width;
4230 	int             window_height;
4231 	char          **sidebar_sections;
4232 	GtkWidget      *vbox;
4233 	GtkWidget      *scrolled_window;
4234 	char           *general_filter;
4235 	char           *sort_type;
4236 	char           *caption;
4237 	int             i;
4238 
4239 	g_object_set (browser,
4240 		      "n-pages", GTH_BROWSER_N_PAGES,
4241 		      "use-header-bar", TRUE,
4242 		      NULL);
4243 
4244 	gtk_widget_add_events (GTK_WIDGET (browser), GDK_POINTER_MOTION_HINT_MASK);
4245 
4246 	browser->priv = gth_browser_get_instance_private (browser);
4247 	browser->priv->viewer_pages = NULL;
4248 	browser->priv->viewer_page = NULL;
4249 	browser->priv->image_preloader = gth_image_preloader_new ();
4250 	browser->priv->progress_dialog = NULL;
4251 	browser->priv->named_dialogs = g_hash_table_new (g_str_hash, g_str_equal);
4252 	browser->priv->location = NULL;
4253 	browser->priv->current_file = NULL;
4254 	browser->priv->location_source = NULL;
4255 	browser->priv->n_visibles = 0;
4256 	browser->priv->current_file_position = -1;
4257 	browser->priv->monitor_location = NULL;
4258 	browser->priv->activity_ref = 0;
4259 	browser->priv->menu_icon_cache = gth_icon_cache_new_for_widget (GTK_WIDGET (browser), GTK_ICON_SIZE_MENU);
4260 	browser->priv->current_sort_type = NULL;
4261 	browser->priv->current_sort_inverse = FALSE;
4262 	browser->priv->default_sort_type = NULL;
4263 	browser->priv->default_sort_inverse = FALSE;
4264 	browser->priv->show_hidden_files = FALSE;
4265 	browser->priv->fast_file_type = FALSE;
4266 	browser->priv->closing = FALSE;
4267 	browser->priv->task = NULL;
4268 	browser->priv->task_completed = 0;
4269 	browser->priv->task_progress = 0;
4270 	browser->priv->background_tasks = NULL;
4271 	browser->priv->close_with_task = FALSE;
4272 	browser->priv->load_data_queue = NULL;
4273 	browser->priv->last_folder_to_open = NULL;
4274 	browser->priv->load_file_data_queue = NULL;
4275 	browser->priv->load_file_timeout = 0;
4276 	browser->priv->load_metadata_timeout = 0;
4277 	browser->priv->list_attributes = NULL;
4278 	browser->priv->constructed = FALSE;
4279 	browser->priv->selection_changed_event = 0;
4280 	browser->priv->folder_popup_file_data = NULL;
4281 	browser->priv->properties_on_screen = FALSE;
4282 	browser->priv->location_free_space = NULL;
4283 	browser->priv->recalc_location_free_space = TRUE;
4284 	browser->priv->fullscreen = FALSE;
4285 	browser->priv->fullscreen_headerbar = NULL;
4286 	browser->priv->was_fullscreen = FALSE;
4287 	browser->priv->viewer_controls = NULL;
4288 	browser->priv->fixed_viewer_controls = NULL;
4289 	browser->priv->pointer_visible = TRUE;
4290 	browser->priv->hide_mouse_timeout = 0;
4291 	browser->priv->motion_signal = 0;
4292 	browser->priv->last_mouse_x = 0.0;
4293 	browser->priv->last_mouse_y = 0.0;
4294 	browser->priv->history = NULL;
4295 	browser->priv->history_current = NULL;
4296 	browser->priv->browser_settings = g_settings_new (GTHUMB_BROWSER_SCHEMA);
4297 	browser->priv->messages_settings = g_settings_new (GTHUMB_MESSAGES_SCHEMA);
4298 	browser->priv->desktop_interface_settings = g_settings_new (GNOME_DESKTOP_INTERFACE_SCHEMA);
4299 	browser->priv->file_properties_on_the_right = g_settings_get_boolean (browser->priv->browser_settings, PREF_BROWSER_PROPERTIES_ON_THE_RIGHT);
4300 	browser->priv->menu_managers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
4301 	browser->priv->screen_profile = NULL;
4302 	browser->priv->folder_tree_last_dest_row = NULL;
4303 	browser->priv->folder_tree_open_folder_id = 0;
4304 	browser->priv->view_files_in_fullscreen = g_settings_get_boolean (browser->priv->browser_settings, PREF_BROWSER_OPEN_FILES_IN_FULLSCREEN);;
4305 	browser->priv->keep_mouse_visible = FALSE;
4306 	browser->priv->fullscreen_state.sidebar = g_settings_get_enum (browser->priv->browser_settings, PREF_FULLSCREEN_SIDEBAR);
4307 	browser->priv->fullscreen_state.thumbnail_list = g_settings_get_boolean (browser->priv->browser_settings, PREF_FULLSCREEN_THUMBNAILS_VISIBLE);
4308 
4309 	browser_state_init (&browser->priv->state);
4310 
4311 	/* find a suitable size for the window */
4312 
4313 	window_width = g_settings_get_int (browser->priv->browser_settings, PREF_BROWSER_WINDOW_WIDTH);
4314 	window_height = g_settings_get_int (browser->priv->browser_settings, PREF_BROWSER_WINDOW_HEIGHT);
4315 
4316 	if ((window_width == 0) || (window_height == 0)) {
4317 		int max_width;
4318 		int max_height;
4319 		int sidebar_width;
4320 		int thumb_size;
4321 		int thumb_spacing;
4322 		int default_columns_of_thumbnails;
4323 		int n_cols;
4324 
4325 		gtk_widget_realize (GTK_WIDGET (browser));
4326 		_gtk_widget_get_screen_size (GTK_WIDGET (browser), &max_width, &max_height);
4327 		max_width = max_width * 5 / 6;
4328 		max_height = max_height * 3 / 4;
4329 
4330 		sidebar_width = g_settings_get_int (browser->priv->browser_settings, PREF_BROWSER_BROWSER_SIDEBAR_WIDTH) + 10;
4331 		thumb_size = g_settings_get_int (browser->priv->browser_settings, PREF_BROWSER_THUMBNAIL_SIZE);
4332 		thumb_spacing = 40;
4333 		default_columns_of_thumbnails = 6;
4334 
4335 		for (n_cols = default_columns_of_thumbnails; n_cols >= 1; n_cols--) {
4336 			window_width = sidebar_width + (thumb_spacing + 20) + (n_cols * (thumb_size + thumb_spacing));
4337 			if (window_width < max_width)
4338 				break;
4339 		}
4340 		if (n_cols == 0)
4341 			window_width = max_width;
4342 		window_height = max_height;
4343 	}
4344 	gtk_window_set_default_size (GTK_WINDOW (browser), window_width, window_height);
4345 	if (g_settings_get_boolean (browser->priv->browser_settings, PREF_BROWSER_WINDOW_MAXIMIZED))
4346 		gtk_window_maximize(GTK_WINDOW (browser));
4347 
4348 	/* realize the widget before adding the ui to get the icons from the icon theme */
4349 
4350 	g_signal_connect (browser, "realize", G_CALLBACK (_gth_browser_realize), NULL);
4351 	g_signal_connect (browser, "unrealize", G_CALLBACK (_gth_browser_unrealize), NULL);
4352 	gtk_widget_realize (GTK_WIDGET (browser));
4353 
4354 	g_signal_connect (browser,
4355 			  "key-press-event",
4356 			  G_CALLBACK (browser_key_press_cb),
4357 			  browser);
4358 
4359 	/* ui actions */
4360 
4361 	g_action_map_add_action_entries (G_ACTION_MAP (browser),
4362 					 gth_browser_actions,
4363 					 G_N_ELEMENTS (gth_browser_actions),
4364 					 browser);
4365 	gth_window_add_accelerators (GTH_WINDOW (browser),
4366 				     gth_browser_accelerators,
4367 				     G_N_ELEMENTS (gth_browser_accelerators));
4368 
4369 	gth_window_add_shortcuts (GTH_WINDOW (browser),
4370 				  gth_browser_shortcuts,
4371 				  G_N_ELEMENTS (gth_browser_shortcuts));
4372 
4373 	/* -- image page -- */
4374 
4375 	/* content */
4376 
4377 	browser->priv->viewer_thumbnails_orientation = g_settings_get_enum (browser->priv->browser_settings, PREF_BROWSER_VIEWER_THUMBNAILS_ORIENT);
4378 	if (browser->priv->viewer_thumbnails_orientation == GTK_ORIENTATION_HORIZONTAL)
4379 		browser->priv->viewer_thumbnails_pane = gth_paned_new (GTK_ORIENTATION_VERTICAL);
4380 	else
4381 		browser->priv->viewer_thumbnails_pane = gth_paned_new (GTK_ORIENTATION_HORIZONTAL);
4382 	gtk_widget_show (browser->priv->viewer_thumbnails_pane);
4383 	gth_window_attach_content (GTH_WINDOW (browser), GTH_BROWSER_PAGE_VIEWER, browser->priv->viewer_thumbnails_pane);
4384 
4385 	browser->priv->viewer_sidebar_pane = gth_paned_new (GTK_ORIENTATION_HORIZONTAL);
4386 	gtk_style_context_add_class (gtk_widget_get_style_context (browser->priv->viewer_sidebar_pane), GTK_STYLE_CLASS_SIDEBAR);
4387 	gtk_widget_set_size_request (browser->priv->viewer_sidebar_pane, -1, MIN_VIEWER_SIZE);
4388 	gtk_widget_show (browser->priv->viewer_sidebar_pane);
4389 	if (browser->priv->viewer_thumbnails_orientation == GTK_ORIENTATION_HORIZONTAL)
4390 		gtk_paned_pack1 (GTK_PANED (browser->priv->viewer_thumbnails_pane), browser->priv->viewer_sidebar_pane, TRUE, FALSE);
4391 	else
4392 		gtk_paned_pack2 (GTK_PANED (browser->priv->viewer_thumbnails_pane), browser->priv->viewer_sidebar_pane, TRUE, FALSE);
4393 
4394 	browser->priv->viewer_container = gtk_overlay_new ();
4395 	gtk_widget_set_size_request (browser->priv->viewer_container, MIN_VIEWER_SIZE, -1);
4396 	gtk_widget_show (browser->priv->viewer_container);
4397 
4398 	g_signal_connect (browser->priv->viewer_container,
4399 			  "get-child-position",
4400 			  G_CALLBACK (viewer_container_get_child_position_cb),
4401 			  browser);
4402 
4403 	gtk_paned_pack1 (GTK_PANED (browser->priv->viewer_sidebar_pane), browser->priv->viewer_container, TRUE, FALSE);
4404 	browser->priv->viewer_sidebar_container = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
4405 	gtk_widget_set_vexpand (browser->priv->viewer_sidebar_container, TRUE);
4406 	gtk_paned_pack2 (GTK_PANED (browser->priv->viewer_sidebar_pane), browser->priv->viewer_sidebar_container, FALSE, FALSE);
4407 
4408 	browser->priv->thumbnail_list = gth_file_list_new (gth_grid_view_new (), (browser->priv->viewer_thumbnails_orientation == GTK_ORIENTATION_HORIZONTAL) ? GTH_FILE_LIST_MODE_H_SIDEBAR : GTH_FILE_LIST_MODE_V_SIDEBAR, TRUE);
4409 	gth_file_list_set_caption (GTH_FILE_LIST (browser->priv->thumbnail_list), "none");
4410 	gth_grid_view_set_cell_spacing (GTH_GRID_VIEW (gth_file_list_get_view (GTH_FILE_LIST (browser->priv->thumbnail_list))), 0);
4411 	gth_file_list_set_thumb_size (GTH_FILE_LIST (browser->priv->thumbnail_list), 95);
4412 
4413 	if (browser->priv->viewer_thumbnails_orientation == GTK_ORIENTATION_HORIZONTAL)
4414 		gtk_paned_pack2 (GTK_PANED (browser->priv->viewer_thumbnails_pane), browser->priv->thumbnail_list, FALSE, FALSE);
4415 	else
4416 		gtk_paned_pack1 (GTK_PANED (browser->priv->viewer_thumbnails_pane), browser->priv->thumbnail_list, FALSE, FALSE);
4417 	_gth_browser_set_thumbnail_list_visibility (browser, g_settings_get_boolean (browser->priv->browser_settings, PREF_BROWSER_THUMBNAIL_LIST_VISIBLE));
4418 
4419 	g_signal_connect (gth_file_list_get_view (GTH_FILE_LIST (browser->priv->thumbnail_list)),
4420 			  "file-selection-changed",
4421 			  G_CALLBACK (gth_thumbnail_view_selection_changed_cb),
4422 			  browser);
4423 
4424 	/* -- browser page -- */
4425 
4426 	/* dynamic header sections */
4427 
4428 	for (i = 0; i < GTH_BROWSER_N_HEADER_SECTIONS; i++) {
4429 		gboolean separated_buttons;
4430 
4431 		separated_buttons = (/*(i == GTH_BROWSER_HEADER_SECTION_BROWSER_TOOLS)*/
4432 				     /*|| (i == GTH_BROWSER_HEADER_SECTION_VIEWER_OTHER_COMMANDS)*/
4433 				     /*|| (i == GTH_BROWSER_HEADER_SECTION_VIEWER_SIDEBAR)*/
4434 				     (i == GTH_BROWSER_HEADER_SECTION_VIEWER_OTHER_VIEW)
4435 				     /*|| (i == GTH_BROWSER_HEADER_SECTION_VIEWER_EDIT)*/
4436 				     || (i == GTH_BROWSER_HEADER_SECTION_EDITOR_COMMANDS));
4437 
4438 		browser->priv->header_sections[i] = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, separated_buttons ? 6 : 0);
4439 		gtk_widget_set_valign (browser->priv->header_sections[i], GTK_ALIGN_CENTER);
4440 		if (! separated_buttons)
4441 			gtk_style_context_add_class (gtk_widget_get_style_context (browser->priv->header_sections[i]), GTK_STYLE_CLASS_LINKED);
4442 	}
4443 
4444 	/* window header bar */
4445 
4446 	{
4447 		GtkWidget  *header_bar;
4448 		GtkBuilder *builder;
4449 		GMenuModel *menu;
4450 		GtkWidget  *button;
4451 
4452 		header_bar = gth_window_get_header_bar (GTH_WINDOW (browser));
4453 
4454 		gtk_widget_set_margin_start (browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_BROWSER_LOCATIONS], GTH_BROWSER_HEADER_BAR_BIG_MARGIN);
4455 		gtk_widget_set_margin_end (browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_BROWSER_COMMANDS], GTH_BROWSER_HEADER_BAR_BIG_MARGIN);
4456 		gtk_widget_set_margin_start (browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_BROWSER_COMMANDS], GTH_BROWSER_HEADER_BAR_BIG_MARGIN);
4457 		gtk_widget_set_margin_end (browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_BROWSER_VIEW], GTH_BROWSER_HEADER_BAR_BIG_MARGIN);
4458 		gtk_widget_set_margin_end (browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_BROWSER_TOOLS], GTH_BROWSER_HEADER_BAR_BIG_MARGIN);
4459 		gtk_widget_set_margin_end (browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_VIEWER_SIDEBAR], GTH_BROWSER_HEADER_BAR_BIG_MARGIN);
4460 		gtk_widget_set_margin_end (browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_VIEWER_EDIT], GTH_BROWSER_HEADER_BAR_BIG_MARGIN);
4461 		gtk_widget_set_margin_start (browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_VIEWER_OTHER_VIEW], GTH_BROWSER_HEADER_BAR_BIG_MARGIN);
4462 		gtk_widget_set_margin_end (browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_VIEWER_OTHER_VIEW], GTH_BROWSER_HEADER_BAR_BIG_MARGIN);
4463 		gtk_widget_set_margin_end (browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_VIEWER_ZOOM], GTH_BROWSER_HEADER_BAR_BIG_MARGIN);
4464 		gtk_widget_set_margin_start (browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_VIEWER_COMMANDS], GTH_BROWSER_HEADER_BAR_BIG_MARGIN);
4465 		gtk_widget_set_margin_start (browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_VIEWER_OTHER_COMMANDS], GTH_BROWSER_HEADER_BAR_BIG_MARGIN);
4466 		gtk_widget_set_margin_start (browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_EDITOR_VIEW], GTH_BROWSER_HEADER_BAR_BIG_MARGIN);
4467 		gtk_widget_set_margin_end (browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_EDITOR_VIEW], GTH_BROWSER_HEADER_BAR_BIG_MARGIN);
4468 		gtk_widget_set_margin_end (browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_EDITOR_COMMANDS], GTH_BROWSER_HEADER_BAR_BIG_MARGIN);
4469 
4470 		gtk_header_bar_pack_start (GTK_HEADER_BAR (header_bar), browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_BROWSER_NAVIGATION]);
4471 		gtk_header_bar_pack_start (GTK_HEADER_BAR (header_bar), browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_BROWSER_LOCATIONS]);
4472 		gtk_header_bar_pack_start (GTK_HEADER_BAR (header_bar), browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_BROWSER_COMMANDS]);
4473 
4474 		gtk_header_bar_pack_start (GTK_HEADER_BAR (header_bar), browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_VIEWER_NAVIGATION]);
4475 		gtk_header_bar_pack_start (GTK_HEADER_BAR (header_bar), browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_VIEWER_OTHER_VIEW]);
4476 
4477 		gtk_header_bar_pack_start (GTK_HEADER_BAR (header_bar), browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_EDITOR_NAVIGATION]);
4478 		gtk_header_bar_pack_start (GTK_HEADER_BAR (header_bar), browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_EDITOR_VIEW]);
4479 
4480 		/* GTH_BROWSER_HEADER_SECTION_VIEWER_ZOOM is shared by the viewer and the editor */
4481 		gtk_header_bar_pack_start (GTK_HEADER_BAR (header_bar), browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_VIEWER_ZOOM]);
4482 		gtk_header_bar_pack_start (GTK_HEADER_BAR (header_bar), browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_VIEWER_VIEW]);
4483 		gtk_header_bar_pack_start (GTK_HEADER_BAR (header_bar), browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_VIEWER_COMMANDS]);
4484 		gtk_header_bar_pack_start (GTK_HEADER_BAR (header_bar), browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_VIEWER_OTHER_COMMANDS]);
4485 
4486 		/* gears menu button */
4487 
4488 		builder = _gtk_builder_new_from_resource ("gears-menu.ui");
4489 		menu = G_MENU_MODEL (gtk_builder_get_object (builder, "menu"));
4490 		browser->priv->menu_button = _gtk_menu_button_new_for_header_bar ("open-menu-symbolic");
4491 		gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (browser->priv->menu_button), menu);
4492 		gtk_widget_set_halign (GTK_WIDGET (gtk_menu_button_get_popup (GTK_MENU_BUTTON (browser->priv->menu_button))), GTK_ALIGN_END);
4493 		gtk_widget_show_all (browser->priv->menu_button);
4494 		gtk_header_bar_pack_end (GTK_HEADER_BAR (header_bar), browser->priv->menu_button);
4495 
4496 		gth_browser_add_menu_manager_for_menu (browser, GTH_BROWSER_MENU_MANAGER_GEARS, G_MENU (menu));
4497 		gth_browser_add_menu_manager_for_menu (browser, GTH_BROWSER_MENU_MANAGER_GEARS_FOLDER_ACTIONS, G_MENU (gtk_builder_get_object (builder, "folder-actions")));
4498 		gth_browser_add_menu_manager_for_menu (browser, GTH_BROWSER_MENU_MANAGER_GEARS_OTHER_ACTIONS, G_MENU (gtk_builder_get_object (builder, "other-actions")));
4499 		gth_browser_add_menu_manager_for_menu (browser, GTH_BROWSER_MENU_MANAGER_GEARS_APP_ACTIONS, G_MENU (gtk_builder_get_object (builder, "app-actions")));
4500 		_gtk_window_add_accelerators_from_menu ((GTK_WINDOW (browser)), menu);
4501 		g_object_unref (builder);
4502 
4503 		gtk_header_bar_pack_end (GTK_HEADER_BAR (header_bar), browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_BROWSER_TOOLS]);
4504 		gtk_header_bar_pack_end (GTK_HEADER_BAR (header_bar), browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_BROWSER_METADATA_TOOLS]);
4505 		gtk_header_bar_pack_end (GTK_HEADER_BAR (header_bar), browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_BROWSER_VIEW]);
4506 
4507 		gtk_header_bar_pack_end (GTK_HEADER_BAR (header_bar), browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_VIEWER_EDIT]);
4508 		gtk_header_bar_pack_end (GTK_HEADER_BAR (header_bar), browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_VIEWER_EDIT_METADATA]);
4509 		gtk_header_bar_pack_end (GTK_HEADER_BAR (header_bar), browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_VIEWER_SIDEBAR]);
4510 
4511 		gtk_header_bar_pack_end (GTK_HEADER_BAR (header_bar), browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_EDITOR_APPLY]);
4512 		gtk_header_bar_pack_end (GTK_HEADER_BAR (header_bar), browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_EDITOR_COMMANDS]);
4513 
4514 		/* browser navigation */
4515 
4516 		gth_browser_add_header_bar_button (browser,
4517 						   GTH_BROWSER_HEADER_SECTION_BROWSER_NAVIGATION,
4518 						   "go-previous-symbolic",
4519 						   _("Go to the previous visited location"),
4520 						   "win.go-back",
4521 						   NULL);
4522 		gth_browser_add_header_bar_button (browser,
4523 						   GTH_BROWSER_HEADER_SECTION_BROWSER_NAVIGATION,
4524 						   "go-next-symbolic",
4525 						   _("Go to the next visited location"),
4526 						   "win.go-forward",
4527 						   NULL);
4528 
4529 		/* history menu button */
4530 
4531 		builder = _gtk_builder_new_from_resource ("history-menu.ui");
4532 		button = _gtk_menu_button_new_for_header_bar ("document-open-recent-symbolic");
4533 		gtk_widget_set_tooltip_text (button, _("History"));
4534 
4535 		browser->priv->history_menu = g_object_ref (G_MENU (gtk_builder_get_object (builder, "visited-locations")));
4536 		gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (button), G_MENU_MODEL (gtk_builder_get_object (builder, "menu")));
4537 		gtk_widget_show (button);
4538 		gtk_box_pack_start (GTK_BOX (gth_browser_get_headerbar_section (browser, GTH_BROWSER_HEADER_SECTION_BROWSER_NAVIGATION)), button, FALSE, FALSE, 0);
4539 
4540 		g_object_unref (builder);
4541 
4542 		/* viewer navigation */
4543 
4544 		gth_browser_add_header_bar_button (browser,
4545 						   GTH_BROWSER_HEADER_SECTION_VIEWER_NAVIGATION,
4546 						   "go-previous-symbolic",
4547 						   _("View the folders"),
4548 						   "win.browser-mode",
4549 						   NULL);
4550 
4551 		/* viewer edit */
4552 
4553 		gth_browser_add_header_bar_toggle_button (browser,
4554 							  GTH_BROWSER_HEADER_SECTION_VIEWER_SIDEBAR,
4555 							  "dialog-information-symbolic",
4556 							  _("Properties"),
4557 							  "win.viewer-properties",
4558 							  NULL);
4559 		gth_browser_add_header_bar_toggle_button (browser,
4560 							  GTH_BROWSER_HEADER_SECTION_VIEWER_SIDEBAR,
4561 							  "palette-symbolic",
4562 							  _("Edit file"),
4563 							  "win.viewer-edit-file",
4564 							  NULL);
4565 
4566 		/* viewer view */
4567 
4568 		gth_browser_add_header_bar_button (browser,
4569 						   GTH_BROWSER_HEADER_SECTION_VIEWER_OTHER_VIEW,
4570 						   "view-fullscreen-symbolic",
4571 						   _("Fullscreen"),
4572 						   "win.fullscreen",
4573 						   NULL);
4574 
4575 		/* editor navigation */
4576 
4577 		gth_browser_add_header_bar_button (browser,
4578 						   GTH_BROWSER_HEADER_SECTION_EDITOR_NAVIGATION,
4579 						   "go-previous-symbolic",
4580 						   NULL,
4581 						   "win.browser-mode",
4582 						   NULL);
4583 
4584 		/* editor view */
4585 
4586 		gth_browser_add_header_bar_button (browser,
4587 						   GTH_BROWSER_HEADER_SECTION_EDITOR_VIEW,
4588 						   "view-fullscreen-symbolic",
4589 						   _("Fullscreen"),
4590 						   "win.fullscreen",
4591 						   NULL);
4592 
4593 		/* editor commands */
4594 
4595 		button = gth_browser_add_header_bar_label_button (browser,
4596 								  GTH_BROWSER_HEADER_SECTION_EDITOR_APPLY,
4597 								  _("Accept"),
4598 								  NULL,
4599 								  "win.apply-editor-changes",
4600 								  NULL);
4601 #ifdef GTK_STYLE_CLASS_SUGGESTED_ACTION
4602 		gtk_style_context_add_class (gtk_widget_get_style_context (button), GTK_STYLE_CLASS_SUGGESTED_ACTION);
4603 #endif
4604 		browser->priv->apply_editor_changes_button = button;
4605 	}
4606 
4607 	/* fullscreen toolbar */
4608 
4609 	browser->priv->fullscreen_toolbar = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
4610 	gtk_style_context_add_class (gtk_widget_get_style_context (browser->priv->fullscreen_toolbar), GTK_STYLE_CLASS_BACKGROUND);
4611 	gth_window_add_overlay (GTH_WINDOW (browser), browser->priv->fullscreen_toolbar);
4612 
4613 	/* overlay commands */
4614 
4615 	{
4616 		/* show next image */
4617 
4618 		browser->priv->next_image_button = gtk_button_new_from_icon_name ("go-next-symbolic", GTK_ICON_SIZE_BUTTON);
4619 		gtk_actionable_set_action_name (GTK_ACTIONABLE (browser->priv->next_image_button), "win.show-next-image");
4620 		gtk_style_context_add_class (gtk_widget_get_style_context (browser->priv->next_image_button), GTK_STYLE_CLASS_OSD);
4621 		gtk_widget_set_can_focus (browser->priv->next_image_button, FALSE);
4622 		gtk_overlay_add_overlay (GTK_OVERLAY (browser->priv->viewer_container), browser->priv->next_image_button);
4623 		_gth_browser_register_fixed_viewer_control (browser, browser->priv->next_image_button);
4624 
4625 		/* show previous image */
4626 
4627 		browser->priv->previous_image_button = gtk_button_new_from_icon_name ("go-previous-symbolic", GTK_ICON_SIZE_BUTTON);
4628 		gtk_actionable_set_action_name (GTK_ACTIONABLE (browser->priv->previous_image_button), "win.show-previous-image");
4629 		gtk_style_context_add_class (gtk_widget_get_style_context (browser->priv->previous_image_button), GTK_STYLE_CLASS_OSD);
4630 		gtk_widget_set_can_focus (browser->priv->previous_image_button, FALSE);
4631 		gtk_overlay_add_overlay (GTK_OVERLAY (browser->priv->viewer_container), browser->priv->previous_image_button);
4632 		_gth_browser_register_fixed_viewer_control (browser, browser->priv->previous_image_button);
4633 	}
4634 
4635 	/* infobar */
4636 
4637 	browser->priv->infobar = gth_info_bar_new ();
4638 	gth_window_attach (GTH_WINDOW (browser), browser->priv->infobar, GTH_WINDOW_INFOBAR);
4639 
4640 	/* statusbar */
4641 
4642 	browser->priv->statusbar = gth_statusbar_new ();
4643 	_gth_browser_set_statusbar_visibility (browser, g_settings_get_boolean (browser->priv->browser_settings, PREF_BROWSER_STATUSBAR_VISIBLE));
4644 	gth_window_attach (GTH_WINDOW (browser), browser->priv->statusbar, GTH_WINDOW_STATUSBAR);
4645 
4646 	{
4647 		GtkWidget *button;
4648 
4649 		/* statusbar commands in browser mode */
4650 
4651 		browser->priv->browser_status_commands = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
4652 		gtk_widget_show (browser->priv->browser_status_commands);
4653 		gtk_style_context_add_class (gtk_widget_get_style_context (browser->priv->browser_status_commands), GTK_STYLE_CLASS_LINKED);
4654 		gtk_box_pack_start (GTK_BOX (gth_statubar_get_action_area (GTH_STATUSBAR (browser->priv->statusbar))), browser->priv->browser_status_commands, FALSE, FALSE, 0);
4655 
4656 		button = gtk_toggle_button_new ();
4657 		gtk_container_add (GTK_CONTAINER (button), gtk_image_new_from_icon_name ("dialog-information-symbolic", GTK_ICON_SIZE_MENU));
4658 		gtk_widget_set_tooltip_text (button, _("Properties"));
4659 		gtk_widget_show_all (button);
4660 		gtk_actionable_set_action_name (GTK_ACTIONABLE (button), "win.browser-properties");
4661 		gtk_box_pack_start (GTK_BOX (browser->priv->browser_status_commands), button, FALSE, FALSE, 0);
4662 
4663 		/* statusbar commands in viewer mode */
4664 
4665 		browser->priv->viewer_status_commands = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3);
4666 		gtk_widget_show (browser->priv->viewer_status_commands);
4667 		/*gtk_style_context_add_class (gtk_widget_get_style_context (browser->priv->viewer_status_commands), GTK_STYLE_CLASS_LINKED);*/
4668 		gtk_box_pack_start (GTK_BOX (gth_statubar_get_action_area (GTH_STATUSBAR (browser->priv->statusbar))), browser->priv->viewer_status_commands, FALSE, FALSE, 0);
4669 
4670 		button = gtk_toggle_button_new ();
4671 		gtk_container_add (GTK_CONTAINER (button), gtk_image_new_from_icon_name ("view-grid-symbolic", GTK_ICON_SIZE_MENU));
4672 		gtk_widget_show_all (button);
4673 		gtk_actionable_set_action_name (GTK_ACTIONABLE (button), "win.show-thumbnail-list");
4674 		gtk_box_pack_end (GTK_BOX (browser->priv->viewer_status_commands), button, FALSE, FALSE, 0);
4675 	}
4676 
4677 	/* main content */
4678 
4679 	browser->priv->browser_right_container = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
4680 	gtk_widget_show (browser->priv->browser_right_container);
4681 	gth_window_attach_content (GTH_WINDOW (browser), GTH_BROWSER_PAGE_BROWSER, browser->priv->browser_right_container);
4682 
4683 	browser->priv->browser_left_container = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
4684 	gtk_paned_set_position (GTK_PANED (browser->priv->browser_left_container), g_settings_get_int (browser->priv->browser_settings, PREF_BROWSER_BROWSER_SIDEBAR_WIDTH));
4685 	gtk_widget_show (browser->priv->browser_left_container);
4686 	gtk_paned_pack1 (GTK_PANED (browser->priv->browser_right_container), browser->priv->browser_left_container, TRUE, TRUE);
4687 
4688 	/* the browser sidebar */
4689 
4690 	browser->priv->browser_sidebar = gth_auto_paned_new (GTK_ORIENTATION_VERTICAL);
4691 	gtk_paned_pack1 (GTK_PANED (browser->priv->browser_left_container), browser->priv->browser_sidebar, FALSE, FALSE);
4692 
4693 	/* the box that contains the folder list.  */
4694 
4695 	vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
4696 	gtk_style_context_add_class (gtk_widget_get_style_context (vbox), GTK_STYLE_CLASS_SIDEBAR);
4697 	gtk_widget_set_size_request (vbox, -1, FILE_PROPERTIES_MINIMUM_HEIGHT);
4698 	gtk_widget_show (vbox);
4699 	gtk_paned_pack1 (GTK_PANED (browser->priv->browser_sidebar), vbox, TRUE, FALSE);
4700 
4701 	/* the folder list */
4702 
4703 	scrolled_window = gtk_scrolled_window_new (NULL, NULL);
4704 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
4705 					GTK_POLICY_AUTOMATIC,
4706 					GTK_POLICY_AUTOMATIC);
4707 	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
4708 					     GTK_SHADOW_NONE);
4709 	gtk_widget_show (scrolled_window);
4710 
4711 	browser->priv->folder_tree = gth_folder_tree_new ("gthumb-vfs:///");
4712 	gtk_widget_show (browser->priv->folder_tree);
4713 
4714 	gtk_container_add (GTK_CONTAINER (scrolled_window), browser->priv->folder_tree);
4715 	gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0);
4716 
4717 	{
4718 		GtkTargetList  *target_list;
4719 		GtkTargetEntry *targets;
4720 		int             n_targets;
4721 
4722 		target_list = gtk_target_list_new (NULL, 0);
4723 		gtk_target_list_add_uri_targets (target_list, 0);
4724 		gtk_target_list_add_text_targets (target_list, 0);
4725 		targets = gtk_target_table_new_from_list (target_list, &n_targets);
4726 
4727 		gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW (browser->priv->folder_tree),
4728 						      targets,
4729 						      n_targets,
4730 						      GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_ASK);
4731 		gth_folder_tree_enable_drag_source (GTH_FOLDER_TREE (browser->priv->folder_tree),
4732 						    GDK_BUTTON1_MASK,
4733 						    targets,
4734 						    n_targets,
4735 						    GDK_ACTION_MOVE | GDK_ACTION_COPY);
4736 		g_signal_connect (browser->priv->folder_tree,
4737 				  "drag_motion",
4738 				  G_CALLBACK (folder_tree_drag_motion_cb),
4739 				  browser);
4740 		g_signal_connect (browser->priv->folder_tree,
4741 	                          "drag-data-received",
4742 	                          G_CALLBACK (folder_tree_drag_data_received),
4743 	                          browser);
4744 		g_signal_connect (browser->priv->folder_tree,
4745 				  "drag-data-get",
4746 				  G_CALLBACK (folder_tree_drag_data_get_cb),
4747 				  browser);
4748 
4749 		gtk_target_list_unref (target_list);
4750 		gtk_target_table_free (targets, n_targets);
4751 	}
4752 
4753 	g_signal_connect (browser->priv->folder_tree,
4754 			  "open",
4755 			  G_CALLBACK (folder_tree_open_cb),
4756 			  browser);
4757 	g_signal_connect (browser->priv->folder_tree,
4758 			  "open_parent",
4759 			  G_CALLBACK (folder_tree_open_parent_cb),
4760 			  browser);
4761 	g_signal_connect (browser->priv->folder_tree,
4762 			  "list_children",
4763 			  G_CALLBACK (folder_tree_list_children_cb),
4764 			  browser);
4765 	g_signal_connect (browser->priv->folder_tree,
4766 			  "folder_popup",
4767 			  G_CALLBACK (folder_tree_folder_popup_cb),
4768 			  browser);
4769 	g_signal_connect (browser->priv->folder_tree,
4770 			  "rename",
4771 			  G_CALLBACK (folder_tree_rename_cb),
4772 			  browser);
4773 
4774 	/* the file property box */
4775 
4776 	sidebar_sections = g_settings_get_strv (browser->priv->browser_settings, PREF_BROWSER_SIDEBAR_SECTIONS);
4777 	browser->priv->file_properties = gth_sidebar_new (sidebar_sections);
4778 	gtk_widget_set_size_request (browser->priv->file_properties, -1, FILE_PROPERTIES_MINIMUM_HEIGHT);
4779 	gtk_widget_hide (browser->priv->file_properties);
4780 	gtk_paned_pack2 (GTK_PANED (_gth_browser_get_browser_file_properties_container (browser)),
4781 			 browser->priv->file_properties,
4782 			 ! browser->priv->file_properties_on_the_right,
4783 			 FALSE);
4784 	g_strfreev (sidebar_sections);
4785 
4786 	g_signal_connect (gth_sidebar_get_toolbox (GTH_SIDEBAR (browser->priv->file_properties)),
4787 			  "options-visibility",
4788 			  G_CALLBACK (toolbox_options_visibility_cb),
4789 			  browser);
4790 
4791 	/* the box that contains the file list and the filter bar.  */
4792 
4793 	vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
4794 	gtk_widget_show (vbox);
4795 	gtk_paned_pack2 (GTK_PANED (browser->priv->browser_left_container), vbox, TRUE, TRUE);
4796 
4797 	/* the list extra widget container */
4798 
4799 	browser->priv->list_extra_widget_container = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
4800 	gtk_widget_show (browser->priv->list_extra_widget_container);
4801 	gtk_box_pack_start (GTK_BOX (vbox), browser->priv->list_extra_widget_container, FALSE, FALSE, 0);
4802 
4803 	/* location bar */
4804 
4805 	browser->priv->location_bar = gth_location_bar_new ();
4806 	gtk_widget_show (browser->priv->location_bar);
4807 	gtk_box_pack_start (GTK_BOX (browser->priv->list_extra_widget_container), browser->priv->location_bar, TRUE, TRUE, 0);
4808 	g_signal_connect (gth_location_bar_get_chooser (GTH_LOCATION_BAR (browser->priv->location_bar)),
4809 			  "changed",
4810 			  G_CALLBACK (location_chooser_changed_cb),
4811 			  browser);
4812 
4813 	/* list info bar */
4814 
4815 	browser->priv->list_info_bar = gth_info_bar_new ();
4816 	gtk_box_pack_start (GTK_BOX (browser->priv->list_extra_widget_container), browser->priv->list_info_bar, TRUE, TRUE, 0);
4817 
4818 	/* the file list */
4819 
4820 	browser->priv->file_list = gth_file_list_new (gth_grid_view_new (), GTH_FILE_LIST_MODE_NORMAL, TRUE);
4821 	sort_type = g_settings_get_string (browser->priv->browser_settings, PREF_BROWSER_SORT_TYPE);
4822 	gth_browser_set_sort_order (browser,
4823 				    gth_main_get_sort_type (sort_type),
4824 				    g_settings_get_boolean (browser->priv->browser_settings, PREF_BROWSER_SORT_INVERSE));
4825 	gth_file_list_set_thumb_size (GTH_FILE_LIST (browser->priv->file_list),
4826 				      g_settings_get_int (browser->priv->browser_settings, PREF_BROWSER_THUMBNAIL_SIZE));
4827 	caption = g_settings_get_string (browser->priv->browser_settings, PREF_BROWSER_THUMBNAIL_CAPTION);
4828 	gth_file_list_set_caption (GTH_FILE_LIST (browser->priv->file_list), caption);
4829 	gth_file_view_set_activate_on_single_click (GTH_FILE_VIEW (gth_file_list_get_view (GTH_FILE_LIST (browser->priv->file_list))), g_settings_get_boolean (browser->priv->browser_settings, PREF_BROWSER_SINGLE_CLICK_ACTIVATION));
4830 
4831 	g_free (caption);
4832 	g_free (sort_type);
4833 
4834 	gtk_widget_show (browser->priv->file_list);
4835 	gtk_box_pack_start (GTK_BOX (vbox), browser->priv->file_list, TRUE, TRUE, 0);
4836 
4837 	g_signal_connect (gth_file_list_get_view (GTH_FILE_LIST (browser->priv->file_list)),
4838 			  "button-press-event",
4839 			  G_CALLBACK (gth_file_list_button_press_cb),
4840 			  browser);
4841 	g_signal_connect (gth_file_list_get_empty_view (GTH_FILE_LIST (browser->priv->file_list)),
4842 			  "button-press-event",
4843 			  G_CALLBACK (gth_file_list_button_press_cb),
4844 			  browser);
4845 	g_signal_connect (browser->priv->file_list,
4846 			  "popup-menu",
4847 			  G_CALLBACK (gth_file_list_popup_menu_cb),
4848 			  browser);
4849 	g_signal_connect (gth_file_list_get_view (GTH_FILE_LIST (browser->priv->file_list)),
4850 			  "file-selection-changed",
4851 			  G_CALLBACK (gth_file_view_selection_changed_cb),
4852 			  browser);
4853 	g_signal_connect (gth_file_list_get_view (GTH_FILE_LIST (browser->priv->file_list)),
4854 			  "file-activated",
4855 			  G_CALLBACK (gth_file_view_file_activated_cb),
4856 			  browser);
4857 
4858 	/* the filter bar */
4859 
4860 	general_filter = g_settings_get_string (browser->priv->browser_settings, PREF_BROWSER_GENERAL_FILTER);
4861 	browser->priv->filterbar = gth_filterbar_new (general_filter);
4862 	gtk_widget_show (browser->priv->filterbar);
4863 	gth_filterbar_load_filter (GTH_FILTERBAR (browser->priv->filterbar), "active_filter.xml");
4864 	g_free (general_filter);
4865 	gtk_box_pack_end (GTK_BOX (vbox), browser->priv->filterbar, FALSE, FALSE, 0);
4866 
4867 	g_signal_connect (browser->priv->filterbar,
4868 			  "changed",
4869 			  G_CALLBACK (filterbar_changed_cb),
4870 			  browser);
4871 	g_signal_connect (browser->priv->filterbar,
4872 			  "personalize",
4873 			  G_CALLBACK (filterbar_personalize_cb),
4874 			  browser);
4875 
4876 	/* monitor signals */
4877 
4878 	browser->priv->folder_changed_id =
4879 		g_signal_connect (gth_main_get_default_monitor (),
4880 				  "folder-changed",
4881 				  G_CALLBACK (folder_changed_cb),
4882 				  browser);
4883 	browser->priv->file_renamed_id =
4884 		g_signal_connect (gth_main_get_default_monitor (),
4885 				  "file-renamed",
4886 				  G_CALLBACK (file_renamed_cb),
4887 				  browser);
4888 	browser->priv->metadata_changed_id =
4889 		g_signal_connect (gth_main_get_default_monitor (),
4890 				  "metadata-changed",
4891 				  G_CALLBACK (metadata_changed_cb),
4892 				  browser);
4893 	browser->priv->emblems_changed_id =
4894 		g_signal_connect (gth_main_get_default_monitor (),
4895 				  "emblems-changed",
4896 				  G_CALLBACK (emblems_changed_cb),
4897 				  browser);
4898 	browser->priv->entry_points_changed_id =
4899 		g_signal_connect (gth_main_get_default_monitor (),
4900 				  "entry-points-changed",
4901 				  G_CALLBACK (entry_points_changed_cb),
4902 				  browser);
4903 	browser->priv->order_changed_id =
4904 		g_signal_connect (gth_main_get_default_monitor (),
4905 				  "order-changed",
4906 				  G_CALLBACK (order_changed_cb),
4907 				  browser);
4908 	browser->priv->shortcuts_changed_id =
4909 		g_signal_connect (gth_main_get_default_monitor (),
4910 				  "shortcuts-changed",
4911 				  G_CALLBACK (shortcuts_changed_cb),
4912 				  browser);
4913 
4914 	/* init browser data */
4915 
4916 	/* file popup menu */
4917 	{
4918 		GtkBuilder *builder;
4919 		GMenuModel *menu;
4920 
4921 		builder = _gtk_builder_new_from_resource ("file-menu.ui");
4922 		menu = G_MENU_MODEL (gtk_builder_get_object (builder, "menu"));
4923 		browser->priv->file_popup = gtk_menu_new_from_model (menu);
4924 		gtk_menu_attach_to_widget (GTK_MENU (browser->priv->file_popup), GTK_WIDGET (browser), NULL);
4925 
4926 		gth_browser_add_menu_manager_for_menu (browser, GTH_BROWSER_MENU_MANAGER_FILE, G_MENU (menu));
4927 		gth_browser_add_menu_manager_for_menu (browser, GTH_BROWSER_MENU_MANAGER_FILE_SCREEN_ACTIONS, G_MENU (gtk_builder_get_object (builder, "screen-actions")));
4928 		gth_browser_add_menu_manager_for_menu (browser, GTH_BROWSER_MENU_MANAGER_FILE_OPEN_ACTIONS, G_MENU (gtk_builder_get_object (builder, "open-actions")));
4929 		gth_browser_add_menu_manager_for_menu (browser, GTH_BROWSER_MENU_MANAGER_FILE_EDIT_ACTIONS, G_MENU (gtk_builder_get_object (builder, "edit-actions")));
4930 		gth_browser_add_menu_manager_for_menu (browser, GTH_BROWSER_MENU_MANAGER_FILE_FILE_ACTIONS, G_MENU (gtk_builder_get_object (builder, "file-actions")));
4931 		gth_browser_add_menu_manager_for_menu (browser, GTH_BROWSER_MENU_MANAGER_FILE_FOLDER_ACTIONS, G_MENU (gtk_builder_get_object (builder, "folder-actions")));
4932 		gth_browser_add_menu_manager_for_menu (browser, GTH_BROWSER_MENU_MANAGER_FILE_OTHER_ACTIONS, G_MENU (gtk_builder_get_object (builder, "other-actions")));
4933 
4934 		g_object_unref (builder);
4935 	}
4936 
4937 	/* file list popup menu */
4938 	{
4939 		GtkBuilder *builder;
4940 		GMenuModel *menu;
4941 
4942 		builder = _gtk_builder_new_from_resource ("file-list-menu.ui");
4943 		menu = G_MENU_MODEL (gtk_builder_get_object (builder, "menu"));
4944 		browser->priv->file_list_popup = gtk_menu_new_from_model (menu);
4945 		gtk_menu_attach_to_widget (GTK_MENU (browser->priv->file_list_popup), GTK_WIDGET (browser), NULL);
4946 
4947 		gth_browser_add_menu_manager_for_menu (browser, GTH_BROWSER_MENU_MANAGER_FILE_LIST, G_MENU (menu));
4948 		gth_browser_add_menu_manager_for_menu (browser, GTH_BROWSER_MENU_MANAGER_FILE_LIST_SCREEN_ACTIONS, G_MENU (gtk_builder_get_object (builder, "screen-actions")));
4949 		gth_browser_add_menu_manager_for_menu (browser, GTH_BROWSER_MENU_MANAGER_FILE_LIST_OPEN_ACTIONS, G_MENU (gtk_builder_get_object (builder, "open-actions")));
4950 		gth_browser_add_menu_manager_for_menu (browser, GTH_BROWSER_MENU_MANAGER_FILE_LIST_EDIT_ACTIONS, G_MENU (gtk_builder_get_object (builder, "edit-actions")));
4951 		gth_browser_add_menu_manager_for_menu (browser, GTH_BROWSER_MENU_MANAGER_FILE_LIST_FILE_ACTIONS, G_MENU (gtk_builder_get_object (builder, "file-actions")));
4952 		gth_browser_add_menu_manager_for_menu (browser, GTH_BROWSER_MENU_MANAGER_FILE_LIST_DELETE_ACTIONS, G_MENU (gtk_builder_get_object (builder, "delete-actions")));
4953 		gth_browser_add_menu_manager_for_menu (browser, GTH_BROWSER_MENU_MANAGER_FILE_LIST_FOLDER_ACTIONS, G_MENU (gtk_builder_get_object (builder, "folder-actions")));
4954 		gth_browser_add_menu_manager_for_menu (browser, GTH_BROWSER_MENU_MANAGER_FILE_LIST_OTHER_ACTIONS, G_MENU (gtk_builder_get_object (builder, "other-actions")));
4955 
4956 		g_object_unref (builder);
4957 	}
4958 
4959 	/* folder popup menu */
4960 	{
4961 		GtkBuilder *builder;
4962 		GMenuModel *menu;
4963 
4964 		builder = _gtk_builder_new_from_resource ("folder-menu.ui");
4965 		menu = G_MENU_MODEL (gtk_builder_get_object (builder, "menu"));
4966 		browser->priv->folder_popup = gtk_menu_new_from_model (menu);
4967 		gtk_menu_attach_to_widget (GTK_MENU (browser->priv->folder_popup), GTK_WIDGET (browser), NULL);
4968 		g_signal_connect (browser->priv->folder_popup,
4969 				  "hide",
4970 				  G_CALLBACK (folder_popup_hide_cb),
4971 				  browser);
4972 
4973 		gth_browser_add_menu_manager_for_menu (browser, GTH_BROWSER_MENU_MANAGER_FOLDER, G_MENU (menu));
4974 		gth_browser_add_menu_manager_for_menu (browser, GTH_BROWSER_MENU_MANAGER_FOLDER_OPEN_ACTIONS, G_MENU (gtk_builder_get_object (builder, "open-actions")));
4975 		gth_browser_add_menu_manager_for_menu (browser, GTH_BROWSER_MENU_MANAGER_FOLDER_CREATE_ACTIONS, G_MENU (gtk_builder_get_object (builder, "create-actions")));
4976 		gth_browser_add_menu_manager_for_menu (browser, GTH_BROWSER_MENU_MANAGER_FOLDER_EDIT_ACTIONS, G_MENU (gtk_builder_get_object (builder, "edit-actions")));
4977 		gth_browser_add_menu_manager_for_menu (browser, GTH_BROWSER_MENU_MANAGER_FOLDER_FOLDER_ACTIONS, G_MENU (gtk_builder_get_object (builder, "folder-actions")));
4978 		gth_browser_add_menu_manager_for_menu (browser, GTH_BROWSER_MENU_MANAGER_FOLDER_OTHER_ACTIONS, G_MENU (gtk_builder_get_object (builder, "other-actions")));
4979 
4980 		g_object_unref (builder);
4981 	}
4982 
4983 	_gth_browser_set_sidebar_visibility (browser, g_settings_get_boolean (browser->priv->browser_settings, PREF_BROWSER_SIDEBAR_VISIBLE));
4984 
4985 	browser->priv->show_hidden_files = g_settings_get_boolean (browser->priv->browser_settings, PREF_BROWSER_SHOW_HIDDEN_FILES);
4986 	gth_window_change_action_state (GTH_WINDOW (browser), "show-hidden-files", browser->priv->show_hidden_files);
4987 
4988 	if (g_settings_get_boolean (browser->priv->browser_settings, PREF_BROWSER_PROPERTIES_VISIBLE))
4989 		gth_browser_show_file_properties (browser);
4990 	else
4991 		gth_browser_hide_sidebar (browser);
4992 
4993 	browser->priv->viewer_sidebar = g_settings_get_enum (browser->priv->browser_settings, PREF_BROWSER_VIEWER_SIDEBAR);
4994 	browser->priv->fast_file_type = g_settings_get_boolean (browser->priv->browser_settings, PREF_BROWSER_FAST_FILE_TYPE);
4995 	browser->priv->ask_to_save_modified_images = g_settings_get_boolean (browser->priv->messages_settings, PREF_MSG_SAVE_MODIFIED_IMAGE);
4996 	browser->priv->scroll_action = g_settings_get_enum (browser->priv->browser_settings, PREF_VIEWER_SCROLL_ACTION);
4997 
4998 	/* load the history only for the first window */
4999 	{
5000 		GList * windows = gtk_application_get_windows (Main_Application);
5001 		if ((windows == NULL) || (windows->next == NULL))
5002 			_gth_browser_history_load (browser);
5003 	}
5004 
5005 	gtk_widget_realize (browser->priv->file_list);
5006 	gth_hook_invoke ("gth-browser-construct", browser);
5007 	gth_window_load_shortcuts (GTH_WINDOW (browser));
5008 
5009 	performance (DEBUG_INFO, "window initialized");
5010 
5011 	/* settings notifications */
5012 
5013 	g_signal_connect (browser->priv->browser_settings,
5014 			  "changed::" PREF_BROWSER_GENERAL_FILTER,
5015 			  G_CALLBACK (pref_general_filter_changed),
5016 			  browser);
5017 	g_signal_connect (browser->priv->browser_settings,
5018 			  "changed::" PREF_BROWSER_VIEWER_THUMBNAILS_ORIENT,
5019 			  G_CALLBACK (pref_ui_viewer_thumbnails_orient_changed),
5020 			  browser);
5021 	g_signal_connect (browser->priv->browser_settings,
5022 			  "changed::" PREF_BROWSER_PROPERTIES_ON_THE_RIGHT,
5023 			  G_CALLBACK (pref_browser_properties_on_the_right_changed),
5024 			  browser);
5025 	g_signal_connect (browser->priv->browser_settings,
5026 			  "changed::" PREF_BROWSER_STATUSBAR_VISIBLE,
5027 			  G_CALLBACK (pref_ui_statusbar_visible_changed),
5028 			  browser);
5029 	g_signal_connect (browser->priv->browser_settings,
5030 			  "changed::" PREF_BROWSER_SIDEBAR_VISIBLE,
5031 			  G_CALLBACK (pref_ui_sidebar_visible_changed),
5032 			  browser);
5033 	g_signal_connect (browser->priv->browser_settings,
5034 			  "changed::" PREF_BROWSER_THUMBNAIL_LIST_VISIBLE,
5035 			  G_CALLBACK (pref_ui_thumbnail_list_visible_changed),
5036 			  browser);
5037 	g_signal_connect (browser->priv->browser_settings,
5038 			  "changed::" PREF_BROWSER_SHOW_HIDDEN_FILES,
5039 			  G_CALLBACK (pref_show_hidden_files_changed),
5040 			  browser);
5041 	g_signal_connect (browser->priv->browser_settings,
5042 			  "changed::" PREF_BROWSER_FAST_FILE_TYPE,
5043 			  G_CALLBACK (pref_fast_file_type_changed),
5044 			  browser);
5045 	g_signal_connect (browser->priv->browser_settings,
5046 			  "changed::" PREF_BROWSER_THUMBNAIL_SIZE,
5047 			  G_CALLBACK (pref_thumbnail_size_changed),
5048 			  browser);
5049 	g_signal_connect (browser->priv->browser_settings,
5050 			  "changed::" PREF_BROWSER_THUMBNAIL_CAPTION,
5051 			  G_CALLBACK (pref_thumbnail_caption_changed),
5052 			  browser);
5053 	g_signal_connect (browser->priv->browser_settings,
5054 			  "changed::" PREF_BROWSER_SINGLE_CLICK_ACTIVATION,
5055 			  G_CALLBACK (pref_single_click_activation_changed),
5056 			  browser);
5057 	g_signal_connect (browser->priv->browser_settings,
5058 			  "changed::" PREF_BROWSER_OPEN_FILES_IN_FULLSCREEN,
5059 			  G_CALLBACK (pref_open_files_in_fullscreen_changed),
5060 			  browser);
5061 	g_signal_connect (browser->priv->messages_settings,
5062 			  "changed::" PREF_MSG_SAVE_MODIFIED_IMAGE,
5063 			  G_CALLBACK (pref_msg_save_modified_image_changed),
5064 			  browser);
5065 	g_signal_connect (browser->priv->browser_settings,
5066 			  "changed::" PREF_VIEWER_SCROLL_ACTION,
5067 			  G_CALLBACK (pref_scroll_action_changed),
5068 			  browser);
5069 
5070 	browser->priv->constructed = TRUE;
5071 }
5072 
5073 
5074 GtkWidget *
gth_browser_new(GFile * location,GFile * file_to_select)5075 gth_browser_new (GFile *location,
5076 		 GFile *file_to_select)
5077 {
5078 	GthBrowser    *browser;
5079 	NewWindowData *data;
5080 
5081 	browser = (GthBrowser*) g_object_new (GTH_TYPE_BROWSER, NULL);
5082 
5083 	data = g_new0 (NewWindowData, 1);
5084 	data->browser = browser;
5085 	data->location = _g_object_ref (location);
5086 	if (data->location == NULL)
5087 		data->location = g_file_new_for_uri (gth_pref_get_startup_location ());
5088 	data->file_to_select = _g_object_ref (file_to_select);
5089 
5090 	browser->priv->construct_step2_event = call_when_idle (_gth_browser_construct_step2, data);
5091 
5092 	return (GtkWidget*) browser;
5093 }
5094 
5095 
5096 GFile *
gth_browser_get_location(GthBrowser * browser)5097 gth_browser_get_location (GthBrowser *browser)
5098 {
5099 	return browser->priv->location->file;
5100 }
5101 
5102 
5103 GthFileData *
gth_browser_get_location_data(GthBrowser * browser)5104 gth_browser_get_location_data (GthBrowser *browser)
5105 {
5106 	return browser->priv->location;
5107 }
5108 
5109 
5110 GthFileData *
gth_browser_get_current_file(GthBrowser * browser)5111 gth_browser_get_current_file (GthBrowser *browser)
5112 {
5113 	return browser->priv->current_file;
5114 }
5115 
5116 
5117 gboolean
gth_browser_get_file_modified(GthBrowser * browser)5118 gth_browser_get_file_modified (GthBrowser *browser)
5119 {
5120 	if (browser->priv->current_file != NULL)
5121 		return g_file_info_get_attribute_boolean (browser->priv->current_file->info, "gth::file::is-modified");
5122 	else
5123 		return FALSE;
5124 }
5125 
5126 
5127 void
gth_browser_go_to(GthBrowser * browser,GFile * location,GFile * file_to_select)5128 gth_browser_go_to (GthBrowser *browser,
5129 		   GFile      *location,
5130 		   GFile      *file_to_select)
5131 {
5132 	gth_window_set_current_page (GTH_WINDOW (browser), GTH_BROWSER_PAGE_BROWSER);
5133 	_gth_browser_load (browser, location, file_to_select, NULL, 0, GTH_ACTION_GO_TO, FALSE);
5134 }
5135 
5136 
5137 static void
gth_browser_go_to_with_state(GthBrowser * browser,GFile * location,GList * selected,double vscroll)5138 gth_browser_go_to_with_state (GthBrowser  *browser,
5139 			      GFile       *location,
5140 			      GList       *selected,
5141 			      double       vscroll)
5142 {
5143 	gth_window_set_current_page (GTH_WINDOW (browser), GTH_BROWSER_PAGE_BROWSER);
5144 	_gth_browser_load (browser, location, NULL, selected, vscroll, GTH_ACTION_GO_TO, FALSE);
5145 }
5146 
5147 
5148 void
gth_browser_go_back(GthBrowser * browser,int steps)5149 gth_browser_go_back (GthBrowser *browser,
5150 		     int         steps)
5151 {
5152 	GList *new_current;
5153 
5154 	new_current = browser->priv->history_current;
5155 	while ((new_current != NULL) && (steps-- > 0))
5156 		new_current = new_current->next;
5157 
5158 	if (new_current == NULL)
5159 		return;
5160 
5161 	browser->priv->history_current = new_current;
5162 	_gth_browser_load (browser, (GFile*) browser->priv->history_current->data, NULL, NULL, 0, GTH_ACTION_GO_BACK, FALSE);
5163 }
5164 
5165 
5166 void
gth_browser_go_forward(GthBrowser * browser,int steps)5167 gth_browser_go_forward (GthBrowser *browser,
5168 			int         steps)
5169 {
5170 	GList *new_current;
5171 
5172 	new_current = browser->priv->history_current;
5173 	while ((new_current != NULL) && (steps-- > 0))
5174 		new_current = new_current->prev;
5175 
5176 	if (new_current == NULL)
5177 		return;
5178 
5179 	browser->priv->history_current = new_current;
5180 	_gth_browser_load (browser, (GFile *) browser->priv->history_current->data, NULL, NULL, 0, GTH_ACTION_GO_FORWARD, FALSE);
5181 }
5182 
5183 
5184 void
gth_browser_go_to_history_pos(GthBrowser * browser,int pos)5185 gth_browser_go_to_history_pos (GthBrowser *browser,
5186 			       int         pos)
5187 {
5188 	GList *new_current;
5189 
5190 	new_current = g_list_nth (browser->priv->history, pos);
5191 	if (new_current == NULL)
5192 		return;
5193 
5194 	if (new_current == browser->priv->history_current)
5195 		return;
5196 
5197 	browser->priv->history_current = new_current;
5198 	_gth_browser_load (browser, (GFile*) browser->priv->history_current->data, NULL, NULL, 0, GTH_ACTION_GO_BACK, FALSE);
5199 }
5200 
5201 
5202 void
gth_browser_go_up(GthBrowser * browser,int steps)5203 gth_browser_go_up (GthBrowser *browser,
5204 		   int         steps)
5205 {
5206 	GFile *parent;
5207 
5208 	if (browser->priv->location == NULL)
5209 		return;
5210 
5211 	parent = g_object_ref (browser->priv->location->file);
5212 	while ((steps-- > 0) && (parent != NULL)) {
5213 		GFile *parent_parent;
5214 
5215 		parent_parent = g_file_get_parent (parent);
5216 		g_object_unref (parent);
5217 		parent = parent_parent;
5218 	}
5219 
5220 	if (parent != NULL) {
5221 		gth_browser_go_to (browser, parent, NULL);
5222 		g_object_unref (parent);
5223 	}
5224 }
5225 
5226 
5227 void
gth_browser_go_home(GthBrowser * browser)5228 gth_browser_go_home (GthBrowser *browser)
5229 {
5230 	GFile *location;
5231 
5232 	if (g_settings_get_boolean (browser->priv->browser_settings, PREF_BROWSER_USE_STARTUP_LOCATION))
5233 		location = g_file_new_for_uri (gth_pref_get_startup_location ());
5234 	else
5235 		location = g_file_new_for_uri (_g_uri_get_home ());
5236 
5237 	gth_browser_go_to (browser, location, NULL);
5238 
5239 	g_object_unref (location);
5240 }
5241 
5242 
5243 void
gth_browser_clear_history(GthBrowser * browser)5244 gth_browser_clear_history (GthBrowser *browser)
5245 {
5246 	_g_object_list_unref (browser->priv->history);
5247 	browser->priv->history = NULL;
5248 	browser->priv->history_current = NULL;
5249 
5250 	if (browser->priv->location != NULL)
5251 		_gth_browser_history_add (browser, browser->priv->location->file);
5252 	_gth_browser_history_menu (browser);
5253 }
5254 
5255 
5256 void
gth_browser_set_dialog(GthBrowser * browser,const char * dialog_name,GtkWidget * dialog)5257 gth_browser_set_dialog (GthBrowser *browser,
5258 			const char *dialog_name,
5259 			GtkWidget  *dialog)
5260 {
5261 	if (dialog != NULL)
5262 		gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
5263 	g_hash_table_insert (browser->priv->named_dialogs, (gpointer) dialog_name, dialog);
5264 }
5265 
5266 
5267 GtkWidget *
gth_browser_get_dialog(GthBrowser * browser,const char * dialog_name)5268 gth_browser_get_dialog (GthBrowser *browser,
5269 			const char *dialog_name)
5270 {
5271 	return g_hash_table_lookup (browser->priv->named_dialogs, dialog_name);
5272 }
5273 
5274 
5275 GthIconCache *
gth_browser_get_menu_icon_cache(GthBrowser * browser)5276 gth_browser_get_menu_icon_cache (GthBrowser *browser)
5277 {
5278 	return browser->priv->menu_icon_cache;
5279 }
5280 
5281 
5282 GtkWidget *
gth_browser_get_infobar(GthBrowser * browser)5283 gth_browser_get_infobar (GthBrowser *browser)
5284 {
5285 	return browser->priv->infobar;
5286 }
5287 
5288 
5289 GtkWidget *
gth_browser_get_statusbar(GthBrowser * browser)5290 gth_browser_get_statusbar (GthBrowser *browser)
5291 {
5292 	return browser->priv->statusbar;
5293 }
5294 
5295 
5296 GtkWidget *
gth_browser_get_filterbar(GthBrowser * browser)5297 gth_browser_get_filterbar (GthBrowser *browser)
5298 {
5299 	return browser->priv->filterbar;
5300 }
5301 
5302 
5303 GtkWidget *
gth_browser_get_headerbar_section(GthBrowser * browser,GthBrowserHeaderSection section)5304 gth_browser_get_headerbar_section (GthBrowser			*browser,
5305 				   GthBrowserHeaderSection	 section)
5306 {
5307 	return browser->priv->header_sections[section];
5308 }
5309 
5310 
5311 static void
_gth_browser_setup_header_bar_button(GthBrowser * browser,GthBrowserHeaderSection section,const char * tooltip,const char * action_name,const char * accelerator,GtkWidget * button)5312 _gth_browser_setup_header_bar_button (GthBrowser			*browser,
5313 				      GthBrowserHeaderSection		 section,
5314 				      const char			*tooltip,
5315 				      const char 			*action_name,
5316 				      const char			*accelerator,
5317 				      GtkWidget 			*button)
5318 {
5319 	if (action_name != NULL)
5320 		gtk_actionable_set_action_name (GTK_ACTIONABLE (button), action_name);
5321 	if (tooltip != NULL)
5322 		gtk_widget_set_tooltip_text (button, tooltip);
5323 	if ((action_name != NULL) && (accelerator != NULL))
5324 		_gtk_window_add_accelerator_for_action (GTK_WINDOW (browser),
5325 							gth_window_get_accel_group (GTH_WINDOW (browser)),
5326 							action_name,
5327 							accelerator,
5328 							NULL);
5329 	gtk_box_pack_start (GTK_BOX (gth_browser_get_headerbar_section (browser, section)), button, FALSE, FALSE, 0);
5330 	gtk_widget_show (button);
5331 }
5332 
5333 
5334 GtkWidget *
gth_browser_add_header_bar_button(GthBrowser * browser,GthBrowserHeaderSection section,const char * icon_name,const char * tooltip,const char * action_name,const char * accelerator)5335 gth_browser_add_header_bar_button (GthBrowser			*browser,
5336 				   GthBrowserHeaderSection	 section,
5337 				   const char			*icon_name,
5338 				   const char			*tooltip,
5339 				   const char 			*action_name,
5340 				   const char			*accelerator)
5341 {
5342 	GtkWidget *button;
5343 
5344 	g_return_val_if_fail (icon_name != NULL, NULL);
5345 
5346 	button = _gtk_image_button_new_for_header_bar (icon_name);
5347 	_gth_browser_setup_header_bar_button (browser, section, tooltip, action_name, accelerator, button);
5348 
5349 	return button;
5350 }
5351 
5352 
5353 GtkWidget *
gth_browser_add_header_bar_toggle_button(GthBrowser * browser,GthBrowserHeaderSection section,const char * icon_name,const char * tooltip,const char * action_name,const char * accelerator)5354 gth_browser_add_header_bar_toggle_button (GthBrowser			*browser,
5355 					  GthBrowserHeaderSection	 section,
5356 					  const char			*icon_name,
5357 					  const char			*tooltip,
5358 					  const char 			*action_name,
5359 					  const char			*accelerator)
5360 {
5361 	GtkWidget *button;
5362 
5363 	g_return_val_if_fail (icon_name != NULL, NULL);
5364 
5365 	button = _gtk_toggle_image_button_new_for_header_bar (icon_name);
5366 	_gth_browser_setup_header_bar_button (browser, section, tooltip, action_name, accelerator, button);
5367 
5368 	return button;
5369 }
5370 
5371 
5372 GtkWidget *
gth_browser_add_header_bar_label_button(GthBrowser * browser,GthBrowserHeaderSection section,const char * label,const char * tooltip,const char * action_name,const char * accelerator)5373 gth_browser_add_header_bar_label_button (GthBrowser			*browser,
5374 					 GthBrowserHeaderSection	 section,
5375 					 const char			*label,
5376 					 const char			*tooltip,
5377 					 const char 			*action_name,
5378 					 const char			*accelerator)
5379 {
5380 	GtkWidget *button;
5381 
5382 	g_return_val_if_fail (label != NULL, NULL);
5383 
5384 	button = gtk_button_new_with_label (label);
5385 	gtk_button_set_use_underline (GTK_BUTTON (button), TRUE);
5386 	_gth_browser_setup_header_bar_button (browser, section, tooltip, action_name, accelerator, button);
5387 
5388 	return button;
5389 }
5390 
5391 
5392 GtkWidget *
gth_browser_add_header_bar_menu_button(GthBrowser * browser,GthBrowserHeaderSection section,const char * icon_name,const char * tooltip,GtkWidget * popover)5393 gth_browser_add_header_bar_menu_button (GthBrowser		*browser,
5394 					GthBrowserHeaderSection	 section,
5395 					const char              *icon_name,
5396 					const char              *tooltip,
5397 					GtkWidget               *popover)
5398 {
5399 	GtkWidget *button;
5400 
5401 	g_return_val_if_fail (icon_name != NULL, NULL);
5402 
5403 	button = _gtk_menu_button_new_for_header_bar (icon_name);
5404 	gtk_menu_button_set_popover (GTK_MENU_BUTTON (button), popover);
5405 	_gth_browser_setup_header_bar_button (browser, section, tooltip, NULL, NULL, button);
5406 
5407 	return button;
5408 }
5409 
5410 
5411 void
gth_browser_add_menu_manager_for_menu(GthBrowser * browser,const char * menu_id,GMenu * menu)5412 gth_browser_add_menu_manager_for_menu (GthBrowser *browser,
5413 				       const char *menu_id,
5414 				       GMenu	  *menu)
5415 {
5416 	g_hash_table_insert (browser->priv->menu_managers, g_strdup (menu_id), gth_menu_manager_new (menu));
5417 }
5418 
5419 
5420 GthMenuManager *
gth_browser_get_menu_manager(GthBrowser * browser,const char * menu_id)5421 gth_browser_get_menu_manager (GthBrowser *browser,
5422 			      const char *menu_id)
5423 {
5424 	return g_hash_table_lookup (browser->priv->menu_managers, menu_id);
5425 }
5426 
5427 
5428 GtkWidget *
gth_browser_get_file_list(GthBrowser * browser)5429 gth_browser_get_file_list (GthBrowser *browser)
5430 {
5431 	return browser->priv->file_list;
5432 }
5433 
5434 
5435 GtkWidget *
gth_browser_get_file_list_view(GthBrowser * browser)5436 gth_browser_get_file_list_view (GthBrowser *browser)
5437 {
5438 	return gth_file_list_get_view (GTH_FILE_LIST (browser->priv->file_list));
5439 }
5440 
5441 
5442 GtkWidget *
gth_browser_get_thumbnail_list(GthBrowser * browser)5443 gth_browser_get_thumbnail_list (GthBrowser *browser)
5444 {
5445 	return browser->priv->thumbnail_list;
5446 }
5447 
5448 
5449 GtkWidget *
gth_browser_get_thumbnail_list_view(GthBrowser * browser)5450 gth_browser_get_thumbnail_list_view (GthBrowser *browser)
5451 {
5452 	return gth_file_list_get_view (GTH_FILE_LIST (browser->priv->thumbnail_list));
5453 }
5454 
5455 
5456 GthFileSource *
gth_browser_get_location_source(GthBrowser * browser)5457 gth_browser_get_location_source (GthBrowser *browser)
5458 {
5459 	return browser->priv->location_source;
5460 }
5461 
5462 
5463 GthFileStore *
gth_browser_get_file_store(GthBrowser * browser)5464 gth_browser_get_file_store (GthBrowser *browser)
5465 {
5466 	return GTH_FILE_STORE (gth_file_view_get_model (GTH_FILE_VIEW (gth_browser_get_file_list_view (browser))));
5467 }
5468 
5469 
5470 GtkWidget *
gth_browser_get_folder_tree(GthBrowser * browser)5471 gth_browser_get_folder_tree (GthBrowser *browser)
5472 {
5473 	return browser->priv->folder_tree;
5474 }
5475 
5476 
5477 void
gth_browser_get_sort_order(GthBrowser * browser,GthFileDataSort ** sort_type,gboolean * inverse)5478 gth_browser_get_sort_order (GthBrowser        *browser,
5479 			    GthFileDataSort **sort_type,
5480 			    gboolean         *inverse)
5481 {
5482 	if (sort_type != NULL)
5483 		*sort_type = browser->priv->current_sort_type;
5484 	if (inverse != NULL)
5485 		*inverse = browser->priv->current_sort_inverse;
5486 }
5487 
5488 
5489 void
gth_browser_set_sort_order(GthBrowser * browser,GthFileDataSort * sort_type,gboolean sort_inverse)5490 gth_browser_set_sort_order (GthBrowser      *browser,
5491 			    GthFileDataSort *sort_type,
5492 			    gboolean         sort_inverse)
5493 {
5494 	g_return_if_fail (sort_type != NULL);
5495 
5496 	browser->priv->default_sort_type = sort_type;
5497 	browser->priv->default_sort_inverse = sort_inverse;
5498 	_gth_browser_set_sort_order (browser, sort_type, sort_inverse, TRUE, TRUE);
5499 }
5500 
5501 
5502 void
gth_browser_get_file_list_info(GthBrowser * browser,int * current_position,int * n_visibles)5503 gth_browser_get_file_list_info (GthBrowser *browser,
5504 				int        *current_position,
5505 				int        *n_visibles)
5506 {
5507 	if (current_position != NULL)
5508 		*current_position = browser->priv->current_file_position;
5509 	if (n_visibles != NULL)
5510 		*n_visibles = browser->priv->n_visibles;
5511 }
5512 
5513 
5514 void
gth_browser_stop(GthBrowser * browser)5515 gth_browser_stop (GthBrowser *browser)
5516 {
5517 	_gth_browser_cancel (browser, NULL, NULL);
5518 }
5519 
5520 
5521 void
gth_browser_reload(GthBrowser * browser)5522 gth_browser_reload (GthBrowser *browser)
5523 {
5524 	if (gth_window_get_current_page (GTH_WINDOW (browser)) != GTH_BROWSER_PAGE_BROWSER)
5525 		return;
5526 	gth_browser_go_to (browser, browser->priv->location->file, NULL);
5527 }
5528 
5529 
5530 typedef struct {
5531 	GthBrowser   *browser;
5532 	GthTask      *task;
5533 	GthTaskFlags  flags;
5534 	gulong        completed_event;
5535 } TaskData;
5536 
5537 
5538 static void
task_data_free(TaskData * task_data)5539 task_data_free (TaskData *task_data)
5540 {
5541 	g_object_unref (task_data->task);
5542 	g_object_unref (task_data->browser);
5543 	g_free (task_data);
5544 }
5545 
5546 
5547 static void
background_task_completed_cb(GthTask * task,GError * error,gpointer user_data)5548 background_task_completed_cb (GthTask  *task,
5549 			      GError   *error,
5550 			      gpointer  user_data)
5551 {
5552 	TaskData   *task_data = user_data;
5553 	GthBrowser *browser = task_data->browser;
5554 
5555 	_gth_browser_remove_activity (browser);
5556 
5557 	browser->priv->background_tasks = g_list_remove (browser->priv->background_tasks, task_data);
5558 	g_signal_handler_disconnect (task, task_data->completed_event);
5559 	task_data_free (task_data);
5560 
5561 	if (error == NULL)
5562 		return;
5563 
5564 	if ((error->domain == G_IO_ERROR)
5565 	    && ! g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)
5566 	    && ((task_data->flags & GTH_TASK_FLAGS_IGNORE_ERROR) == 0))
5567 	{
5568 		_gth_browser_show_error (browser, _("Could not perform the operation"), error);
5569 	}
5570 }
5571 
5572 
5573 static TaskData *
task_data_new(GthBrowser * browser,GthTask * task,GthTaskFlags flags)5574 task_data_new (GthBrowser   *browser,
5575 	       GthTask      *task,
5576 	       GthTaskFlags  flags)
5577 {
5578 	TaskData *task_data;
5579 
5580 	task_data = g_new0 (TaskData, 1);
5581 	task_data->browser = g_object_ref (browser);
5582 	task_data->task = g_object_ref (task);
5583 	task_data->flags = flags;
5584 	task_data->completed_event = g_signal_connect (task_data->task,
5585 						       "completed",
5586 						       G_CALLBACK (background_task_completed_cb),
5587 						       task_data);
5588 	return task_data;
5589 }
5590 
5591 
5592 static void
foreground_task_completed_cb(GthTask * task,GError * error,GthBrowser * browser)5593 foreground_task_completed_cb (GthTask    *task,
5594 			      GError     *error,
5595 			      GthBrowser *browser)
5596 {
5597 	_gth_browser_remove_activity (browser);
5598 
5599 	g_signal_handler_disconnect (browser->priv->task, browser->priv->task_completed);
5600 	g_signal_handler_disconnect (browser->priv->task, browser->priv->task_progress);
5601 
5602 	gth_browser_update_sensitivity (browser);
5603 	if ((error != NULL) && ! g_error_matches (error, GTH_TASK_ERROR, GTH_TASK_ERROR_CANCELLED))
5604 		_gth_browser_show_error (browser, _("Could not perform the operation"), error);
5605 
5606 	g_object_unref (browser->priv->task);
5607 	browser->priv->task = NULL;
5608 }
5609 
5610 
5611 static void
foreground_task_progress_cb(GthTask * task,const char * description,const char * details,gboolean pulse,double fraction,GthBrowser * browser)5612 foreground_task_progress_cb (GthTask    *task,
5613 			     const char *description,
5614 			     const char *details,
5615 			     gboolean    pulse,
5616 			     double      fraction,
5617 			     GthBrowser *browser)
5618 {
5619 	/* void */
5620 }
5621 
5622 
5623 void
gth_browser_exec_task(GthBrowser * browser,GthTask * task,GthTaskFlags flags)5624 gth_browser_exec_task (GthBrowser   *browser,
5625 		       GthTask      *task,
5626 		       GthTaskFlags  flags)
5627 {
5628 	g_return_if_fail (GTH_IS_BROWSER (browser));
5629 	g_return_if_fail (task != NULL);
5630 
5631 	if ((flags & GTH_TASK_FLAGS_FOREGROUND) == 0) {
5632 		TaskData *task_data;
5633 
5634 		_gth_browser_add_activity (browser);
5635 
5636 		task_data = task_data_new (browser, task, flags);
5637 		browser->priv->background_tasks = g_list_prepend (browser->priv->background_tasks, task_data);
5638 
5639 		if (browser->priv->progress_dialog == NULL) {
5640 			browser->priv->progress_dialog = gth_progress_dialog_new (GTK_WINDOW (browser));
5641 			g_object_add_weak_pointer (G_OBJECT (browser->priv->progress_dialog), (gpointer*) &(browser->priv->progress_dialog));
5642 		}
5643 		gth_progress_dialog_add_task (GTH_PROGRESS_DIALOG (browser->priv->progress_dialog), task, flags);
5644 
5645 		return;
5646 	}
5647 
5648 	/* foreground task */
5649 
5650 	if (browser->priv->task != NULL)
5651 		gth_task_cancel (task);
5652 
5653 	browser->priv->task = g_object_ref (task);
5654 	browser->priv->task_completed = g_signal_connect (task,
5655 							  "completed",
5656 							  G_CALLBACK (foreground_task_completed_cb),
5657 							  browser);
5658 	browser->priv->task_progress = g_signal_connect (task,
5659 							 "progress",
5660 							 G_CALLBACK (foreground_task_progress_cb),
5661 							 browser);
5662 	_gth_browser_add_activity (browser);
5663 	gth_browser_update_sensitivity (browser);
5664 	gth_task_exec (browser->priv->task, NULL);
5665 }
5666 
5667 
5668 void
gth_browser_set_close_with_task(GthBrowser * browser,gboolean value)5669 gth_browser_set_close_with_task (GthBrowser *browser,
5670 				 gboolean    value)
5671 {
5672 	browser->priv->close_with_task = value;
5673 }
5674 
5675 
5676 gboolean
gth_browser_get_close_with_task(GthBrowser * browser)5677 gth_browser_get_close_with_task (GthBrowser *browser)
5678 {
5679 	return browser->priv->close_with_task;
5680 }
5681 
5682 
5683 GtkWidget *
gth_browser_get_location_bar(GthBrowser * browser)5684 gth_browser_get_location_bar (GthBrowser *browser)
5685 {
5686 	return browser->priv->location_bar;
5687 }
5688 
5689 
5690 GtkWidget *
gth_browser_get_list_info_bar(GthBrowser * browser)5691 gth_browser_get_list_info_bar (GthBrowser *browser)
5692 {
5693 	return browser->priv->list_info_bar;
5694 }
5695 
5696 
5697 gboolean
gth_browser_viewer_button_press_cb(GthBrowser * browser,GdkEventButton * event)5698 gth_browser_viewer_button_press_cb (GthBrowser     *browser,
5699 				    GdkEventButton *event)
5700 {
5701 	g_return_val_if_fail (event != NULL, FALSE);
5702 
5703 	if (event->button == 3) {
5704 		gth_browser_file_menu_popup (browser, event);
5705 		return TRUE;
5706 	}
5707 
5708 	return FALSE;
5709 }
5710 
5711 
5712 gboolean
gth_browser_viewer_scroll_event_cb(GthBrowser * browser,GdkEventScroll * event)5713 gth_browser_viewer_scroll_event_cb (GthBrowser     *browser,
5714 				    GdkEventScroll *event)
5715 {
5716 	gboolean handled;
5717 
5718 	g_return_val_if_fail (event != NULL, FALSE);
5719 
5720 	if (! _gth_browser_can_change_image (browser))
5721 		return FALSE;
5722 
5723 	if (event->state & GDK_SHIFT_MASK)
5724 		return FALSE;
5725 
5726 	if (event->state & GDK_CONTROL_MASK)
5727 		return FALSE;
5728 
5729 	if ((event->direction != GDK_SCROLL_UP) && (event->direction != GDK_SCROLL_DOWN))
5730 		return FALSE;
5731 
5732 	handled = FALSE;
5733 	switch (browser->priv->scroll_action) {
5734 	case GTH_SCROLL_ACTION_CHANGE_FILE:
5735 		if (event->direction == GDK_SCROLL_UP)
5736 			gth_browser_show_prev_image (browser, FALSE, FALSE);
5737 		else
5738 			gth_browser_show_next_image (browser, FALSE, FALSE);
5739 		handled = TRUE;
5740 		break;
5741 
5742 	case GTH_SCROLL_ACTION_ZOOM:
5743 		handled = gth_viewer_page_zoom_from_scroll (browser->priv->viewer_page, event);
5744 		break;
5745 
5746 	default:
5747 		break;
5748 	}
5749 
5750 	return handled;
5751 }
5752 
5753 
5754 static void
gth_browser_toggle_properties_on_screen(GthBrowser * browser)5755 gth_browser_toggle_properties_on_screen (GthBrowser *browser)
5756 {
5757 	gboolean on_screen;
5758 
5759 	on_screen = browser->priv->fullscreen && (GTH_VIEWER_PAGE_GET_INTERFACE (browser->priv->viewer_page)->show_properties != NULL);
5760 	if (on_screen) {
5761 		browser->priv->properties_on_screen = ! browser->priv->properties_on_screen;
5762 		gth_viewer_page_show_properties (browser->priv->viewer_page, browser->priv->properties_on_screen);
5763 	}
5764 	else if (browser->priv->viewer_sidebar != GTH_SIDEBAR_STATE_PROPERTIES)
5765 		gth_browser_show_file_properties (browser);
5766 	else
5767 		gth_browser_hide_sidebar (browser);
5768 }
5769 
5770 
5771 gboolean
gth_browser_viewer_key_press_cb(GthBrowser * browser,GdkEventKey * event)5772 gth_browser_viewer_key_press_cb (GthBrowser  *browser,
5773 				 GdkEventKey *event)
5774 {
5775 	gboolean activated;
5776 
5777 	g_return_val_if_fail (event != NULL, FALSE);
5778 
5779 	activated = gth_window_activate_shortcut (GTH_WINDOW (browser),
5780 						  GTH_SHORTCUT_CONTEXT_VIEWER,
5781 						  event->keyval,
5782 						  event->state);
5783 
5784 	if (! activated && gtk_widget_get_realized (browser->priv->file_list))
5785 		activated = gth_hook_invoke_get ("gth-browser-file-list-key-press", browser, event) != NULL;
5786 
5787 	return activated;
5788 }
5789 
5790 
5791 void
gth_browser_set_viewer_widget(GthBrowser * browser,GtkWidget * widget)5792 gth_browser_set_viewer_widget (GthBrowser *browser,
5793 			       GtkWidget  *widget)
5794 {
5795 	GtkWidget *child;
5796 
5797 	child = gth_browser_get_viewer_widget (browser);
5798 	if (child != NULL)
5799 		gtk_widget_destroy (child);
5800 	if (widget != NULL)
5801 		gtk_container_add (GTK_CONTAINER (browser->priv->viewer_container), widget);
5802 }
5803 
5804 
5805 GtkWidget *
gth_browser_get_viewer_widget(GthBrowser * browser)5806 gth_browser_get_viewer_widget (GthBrowser *browser)
5807 {
5808 	return gtk_bin_get_child (GTK_BIN (browser->priv->viewer_container));
5809 }
5810 
5811 
5812 GthViewerPage *
gth_browser_get_viewer_page(GthBrowser * browser)5813 gth_browser_get_viewer_page (GthBrowser *browser)
5814 {
5815 	return browser->priv->viewer_page;
5816 }
5817 
5818 
5819 GtkWidget *
gth_browser_get_viewer_sidebar(GthBrowser * browser)5820 gth_browser_get_viewer_sidebar (GthBrowser *browser)
5821 {
5822 	return browser->priv->file_properties;
5823 }
5824 
5825 
5826 static gboolean
view_focused_image(GthBrowser * browser)5827 view_focused_image (GthBrowser *browser)
5828 {
5829 	GthFileView *view;
5830 	int          n;
5831 	GtkTreeIter  iter;
5832 	GthFileData *focused_file = NULL;
5833 
5834 	if (browser->priv->current_file == NULL)
5835 		return FALSE;
5836 
5837 	view = GTH_FILE_VIEW (gth_browser_get_file_list_view (browser));
5838 	n = gth_file_view_get_cursor (view);
5839 	if (n == -1)
5840 		return FALSE;
5841 
5842 	if (! gth_file_store_get_nth_visible (GTH_FILE_STORE (gth_file_view_get_model (view)), n, &iter))
5843 		return FALSE;
5844 
5845 	focused_file = gth_file_store_get_file (GTH_FILE_STORE (gth_file_view_get_model (view)), &iter);
5846 	if (focused_file == NULL)
5847 		return FALSE;
5848 
5849 	return ! g_file_equal (browser->priv->current_file->file, focused_file->file);
5850 }
5851 
5852 
5853 static void _gth_browser_load_file_keep_view (GthBrowser  *browser,
5854 					      GthFileData *file_data,
5855 					      gboolean     view,
5856 					      gboolean     no_delay);
5857 
5858 
5859 gboolean
gth_browser_show_next_image(GthBrowser * browser,gboolean skip_broken,gboolean only_selected)5860 gth_browser_show_next_image (GthBrowser *browser,
5861 			     gboolean    skip_broken,
5862 			     gboolean    only_selected)
5863 {
5864 	GthFileView *view;
5865 	int          pos;
5866 
5867 	if (! _gth_browser_can_change_image (browser))
5868 		return FALSE;
5869 
5870 	view = GTH_FILE_VIEW (gth_browser_get_file_list_view (browser));
5871 
5872 	if (browser->priv->current_file == NULL) {
5873 		pos = gth_file_list_next_file (GTH_FILE_LIST (browser->priv->file_list), -1, skip_broken, only_selected, TRUE);
5874 	}
5875 	else if (view_focused_image (browser)) {
5876 		pos = gth_file_view_get_cursor (view);
5877 		if (pos < 0)
5878 			pos = gth_file_list_next_file (GTH_FILE_LIST (browser->priv->file_list), -1, skip_broken, only_selected, TRUE);
5879 	}
5880 	else {
5881 		pos = gth_file_store_get_pos (gth_browser_get_file_store (browser), browser->priv->current_file->file);
5882 		pos = gth_file_list_next_file (GTH_FILE_LIST (browser->priv->file_list), pos, skip_broken, only_selected, FALSE);
5883 	}
5884 
5885 	if (pos >= 0) {
5886 		GtkTreeIter  iter;
5887 
5888 		if (gth_file_store_get_nth_visible (GTH_FILE_STORE (gth_file_view_get_model (view)), pos, &iter)) {
5889 			GthFileData *file_data;
5890 
5891 			file_data = gth_file_store_get_file (GTH_FILE_STORE (gth_file_view_get_model (view)), &iter);
5892 			_gth_browser_load_file_keep_view (browser, file_data, TRUE, TRUE);
5893 		}
5894 	}
5895 	else
5896 		gdk_window_beep (gtk_widget_get_window (GTK_WIDGET (browser)));
5897 
5898 	return (pos >= 0);
5899 }
5900 
5901 
5902 gboolean
gth_browser_show_prev_image(GthBrowser * browser,gboolean skip_broken,gboolean only_selected)5903 gth_browser_show_prev_image (GthBrowser *browser,
5904 			     gboolean    skip_broken,
5905 			     gboolean    only_selected)
5906 {
5907 	GthFileView *view;
5908 	int          pos;
5909 
5910 	if (! _gth_browser_can_change_image (browser))
5911 		return FALSE;
5912 
5913 	view = GTH_FILE_VIEW (gth_browser_get_file_list_view (browser));
5914 
5915 	if (browser->priv->current_file == NULL) {
5916 		pos = gth_file_list_prev_file (GTH_FILE_LIST (browser->priv->file_list), -1, skip_broken, only_selected, TRUE);
5917 	}
5918 	else if (view_focused_image (browser)) {
5919 		pos = gth_file_view_get_cursor (view);
5920 		if (pos < 0)
5921 			pos = gth_file_list_prev_file (GTH_FILE_LIST (browser->priv->file_list), -1, skip_broken, only_selected, TRUE);
5922 	}
5923 	else {
5924 		pos = gth_file_store_get_pos (gth_browser_get_file_store (browser), browser->priv->current_file->file);
5925 		pos = gth_file_list_prev_file (GTH_FILE_LIST (browser->priv->file_list), pos, skip_broken, only_selected, FALSE);
5926 	}
5927 
5928 	if (pos >= 0) {
5929 		GtkTreeIter iter;
5930 
5931 		if (gth_file_store_get_nth_visible (GTH_FILE_STORE (gth_file_view_get_model (view)), pos, &iter)) {
5932 			GthFileData *file_data;
5933 
5934 			file_data = gth_file_store_get_file (GTH_FILE_STORE (gth_file_view_get_model (view)), &iter);
5935 			_gth_browser_load_file_keep_view (browser, file_data, TRUE, TRUE);
5936 		}
5937 	}
5938 	else
5939 		gdk_window_beep (gtk_widget_get_window (GTK_WIDGET (browser)));
5940 
5941 	return (pos >= 0);
5942 }
5943 
5944 
5945 gboolean
gth_browser_show_first_image(GthBrowser * browser,gboolean skip_broken,gboolean only_selected)5946 gth_browser_show_first_image (GthBrowser *browser,
5947 			      gboolean    skip_broken,
5948 			      gboolean    only_selected)
5949 {
5950 	int          pos;
5951 	GthFileView *view;
5952 	GtkTreeIter  iter;
5953 	GthFileData *file_data;
5954 
5955 	if (! _gth_browser_can_change_image (browser))
5956 		return FALSE;
5957 
5958 	pos = gth_file_list_first_file (GTH_FILE_LIST (browser->priv->file_list), skip_broken, only_selected);
5959 	if (pos < 0)
5960 		return FALSE;
5961 
5962 	view = GTH_FILE_VIEW (gth_browser_get_file_list_view (browser));
5963 
5964 	if (! gth_file_store_get_nth_visible (GTH_FILE_STORE (gth_file_view_get_model (view)), pos, &iter))
5965 		return FALSE;
5966 
5967 	file_data = gth_file_store_get_file (GTH_FILE_STORE (gth_file_view_get_model (view)), &iter);
5968 	_gth_browser_load_file_keep_view (browser, file_data, TRUE, TRUE);
5969 
5970 	return TRUE;
5971 }
5972 
5973 
5974 gboolean
gth_browser_show_last_image(GthBrowser * browser,gboolean skip_broken,gboolean only_selected)5975 gth_browser_show_last_image (GthBrowser *browser,
5976 			     gboolean    skip_broken,
5977 			     gboolean    only_selected)
5978 {
5979 	int          pos;
5980 	GthFileView *view;
5981 	GtkTreeIter  iter;
5982 	GthFileData *file_data;
5983 
5984 	if (! _gth_browser_can_change_image (browser))
5985 		return FALSE;
5986 
5987 	pos = gth_file_list_last_file (GTH_FILE_LIST (browser->priv->file_list), skip_broken, only_selected);
5988 	if (pos < 0)
5989 		return FALSE;
5990 
5991 	view = GTH_FILE_VIEW (gth_browser_get_file_list_view (browser));
5992 
5993 	if (! gth_file_store_get_nth_visible (GTH_FILE_STORE (gth_file_view_get_model (view)), pos, &iter))
5994 		return FALSE;
5995 
5996 	file_data = gth_file_store_get_file (GTH_FILE_STORE (gth_file_view_get_model (view)), &iter);
5997 	_gth_browser_load_file_keep_view (browser, file_data, TRUE, TRUE);
5998 
5999 	return TRUE;
6000 }
6001 
6002 
6003 /* -- gth_browser_load_file -- */
6004 
6005 
6006 typedef struct {
6007 	int           ref;
6008 	GthBrowser   *browser;
6009 	GthFileData  *file_data;
6010 	gboolean      view;
6011 	gboolean      fullscreen;
6012 	GCancellable *cancellable;
6013 } LoadFileData;
6014 
6015 
6016 static void
cancel_all_metadata_operations(GthBrowser * browser)6017 cancel_all_metadata_operations (GthBrowser  *browser)
6018 {
6019 	GList *scan;
6020 
6021 	for (scan = browser->priv->load_file_data_queue; scan; scan = scan->next) {
6022 		LoadFileData *data = scan->data;
6023 		g_cancellable_cancel (data->cancellable);
6024 	}
6025 }
6026 
6027 
6028 static LoadFileData *
load_file_data_new(GthBrowser * browser,GthFileData * file_data,gboolean view,gboolean fullscreen)6029 load_file_data_new (GthBrowser  *browser,
6030 		    GthFileData *file_data,
6031 		    gboolean     view,
6032 		    gboolean     fullscreen)
6033 {
6034 	LoadFileData *data;
6035 
6036 	data = g_new0 (LoadFileData, 1);
6037 	data->ref = 1;
6038 	data->browser = g_object_ref (browser);
6039 	if (file_data != NULL)
6040 		data->file_data = gth_file_data_dup (file_data);
6041 	data->view = view;
6042 	data->fullscreen = fullscreen;
6043 	data->cancellable = g_cancellable_new ();
6044 
6045 	cancel_all_metadata_operations (browser);
6046 	browser->priv->load_file_data_queue = g_list_prepend (browser->priv->load_file_data_queue, data);
6047 
6048 	return data;
6049 }
6050 
6051 
6052 static void
load_file_data_ref(LoadFileData * data)6053 load_file_data_ref (LoadFileData *data)
6054 {
6055 	data->ref++;
6056 }
6057 
6058 
6059 static void
load_file_data_unref(LoadFileData * data)6060 load_file_data_unref (LoadFileData *data)
6061 {
6062 	if (--data->ref != 0)
6063 		return;
6064 
6065 	data->browser->priv->load_file_data_queue = g_list_remove (data->browser->priv->load_file_data_queue, data);
6066 	_g_object_unref (data->file_data);
6067 	_g_object_unref (data->browser);
6068 	_g_object_unref (data->cancellable);
6069 	g_free (data);
6070 }
6071 
6072 
6073 static void
6074 gth_viewer_page_file_loaded_cb (GthViewerPage *viewer_page,
6075 				GthFileData   *file_data,
6076 				GFileInfo     *updated_metadata,
6077 				gboolean       success,
6078 				gpointer       user_data);
6079 
6080 
6081 static void
_gth_browser_set_current_viewer_page(GthBrowser * browser,GthViewerPage * registered_viewer_page)6082 _gth_browser_set_current_viewer_page (GthBrowser    *browser,
6083 				      GthViewerPage *registered_viewer_page)
6084 {
6085 	if ((browser->priv->viewer_page != NULL) && (G_OBJECT_TYPE (registered_viewer_page) != G_OBJECT_TYPE (browser->priv->viewer_page)))
6086 		_gth_browser_deactivate_viewer_page (browser);
6087 
6088 	if (browser->priv->viewer_page == NULL) {
6089 		browser->priv->viewer_page = g_object_new (G_OBJECT_TYPE (registered_viewer_page), NULL);
6090 		gth_viewer_page_activate (browser->priv->viewer_page, browser);
6091 		gth_hook_invoke ("gth-browser-activate-viewer-page", browser);
6092 		_gth_browser_show_pointer_on_viewer (browser, FALSE);
6093 
6094 		g_signal_connect (browser->priv->viewer_page,
6095 				  "file-loaded",
6096 				  G_CALLBACK (gth_viewer_page_file_loaded_cb),
6097 				  browser);
6098 	}
6099 }
6100 
6101 
6102 static void
file_metadata_ready_cb(GList * files,GError * error,gpointer user_data)6103 file_metadata_ready_cb (GList    *files,
6104 			GError   *error,
6105 			gpointer  user_data)
6106 {
6107 	LoadFileData *data = user_data;
6108 	GthBrowser   *browser = data->browser;
6109 	GthFileData  *file_data;
6110 	gboolean      different_mime_type;
6111 
6112 	if ((error != NULL) || (files == NULL)) {
6113 		load_file_data_unref (data);
6114 		return;
6115 	}
6116 
6117 	file_data = files->data;
6118 	if ((browser->priv->current_file == NULL) || ! _g_file_equal (file_data->file, browser->priv->current_file->file)) {
6119 		load_file_data_unref (data);
6120 		return;
6121 	}
6122 
6123 	/* the mime type can be different for example when a jpeg image has a .png extension */
6124 	different_mime_type = ! g_str_equal (gth_file_data_get_mime_type (browser->priv->current_file), gth_file_data_get_mime_type (file_data));
6125 
6126 	_g_file_info_update (browser->priv->current_file->info, file_data->info);
6127 
6128 	gth_browser_update_title (browser);
6129 	gth_browser_update_statusbar_file_info (browser);
6130 	gth_sidebar_set_file (GTH_SIDEBAR (browser->priv->file_properties), browser->priv->current_file);
6131 	if (gth_window_get_current_page (GTH_WINDOW (browser)) == GTH_BROWSER_PAGE_VIEWER) {
6132 		_gth_browser_make_file_visible (browser, browser->priv->current_file);
6133 		_gth_browser_update_statusbar_list_info (browser);
6134 	}
6135 	gth_browser_update_sensitivity (browser);
6136 	if (browser->priv->viewer_page != NULL) {
6137 		GthViewerPage *basic_viewer_page;
6138 
6139 		/* The basic viewer is registered before any other viewer, so
6140 		 * it's the last one in the viewer_pages list. */
6141 
6142 		basic_viewer_page = g_list_last (browser->priv->viewer_pages)->data;
6143 
6144 		/* If after reading the metadata we got a different mime type
6145 		 * and the current viewer is the default file viewer it's likely
6146 		 * that we have an image with a wrong extension.  Try to
6147 		 * load the file again to see if the mime type can be viewed by
6148 		 * a different viewer_page. */
6149 
6150 		if (different_mime_type && (G_OBJECT_TYPE (browser->priv->viewer_page) == G_OBJECT_TYPE (basic_viewer_page)))
6151 			_gth_browser_load_file_more_options (browser, data->file_data, data->view, data->fullscreen, data->view);
6152 		else
6153 			gth_viewer_page_update_info (browser->priv->viewer_page, browser->priv->current_file);
6154 	}
6155 
6156 	/* location is NULL if the file has been loaded because requested
6157 	 * from the command line */
6158 	if (browser->priv->location == NULL) {
6159 		GFile *parent;
6160 
6161 		parent = g_file_get_parent (file_data->file);
6162 		_gth_browser_load (browser, parent, file_data->file, NULL, 0, GTH_ACTION_GO_TO, FALSE);
6163 		g_object_unref (parent);
6164 	}
6165 
6166 	load_file_data_unref (data);
6167 }
6168 
6169 
6170 static gboolean
load_metadata_cb(gpointer user_data)6171 load_metadata_cb (gpointer user_data)
6172 {
6173 	LoadFileData *data = user_data;
6174 	GthBrowser   *browser = data->browser;
6175 	GList        *files;
6176 
6177 	if (browser->priv->load_metadata_timeout != 0) {
6178 		g_source_remove (browser->priv->load_metadata_timeout);
6179 		browser->priv->load_metadata_timeout = 0;
6180 	}
6181 
6182 	if ((browser->priv->current_file == NULL) ||
6183 	    ! _g_file_equal (data->file_data->file, browser->priv->current_file->file))
6184 	{
6185 		return FALSE;
6186 	}
6187 
6188 	load_file_data_ref (data);
6189 	files = g_list_prepend (NULL, data->file_data->file);
6190 	_g_query_all_metadata_async (files,
6191 				     GTH_LIST_DEFAULT,
6192 				     "*",
6193 				     data->cancellable,
6194 				     file_metadata_ready_cb,
6195 				     data);
6196 
6197 	g_list_free (files);
6198 
6199 	return FALSE;
6200 }
6201 
6202 
6203 static void
gth_viewer_page_file_loaded_cb(GthViewerPage * viewer_page,GthFileData * file_data,GFileInfo * updated_metadata,gboolean success,gpointer user_data)6204 gth_viewer_page_file_loaded_cb (GthViewerPage *viewer_page,
6205 				GthFileData   *file_data,
6206 				GFileInfo     *updated_metadata,
6207 				gboolean       success,
6208 				gpointer       user_data)
6209 {
6210 	GthBrowser   *browser = user_data;
6211 	LoadFileData *data;
6212 
6213 	if ((browser->priv->current_file == NULL) || ! g_file_equal (file_data->file, browser->priv->current_file->file))
6214 		return;
6215 
6216 	if (! success) {
6217 		GthViewerPage *basic_viewer_page;
6218 
6219 		/* Use the basic viewer if the default viewer failed.  The
6220 		 * basic viewer is registered before any other viewer, so it's
6221 		 * the last one in the viewer_pages list. */
6222 
6223 		basic_viewer_page = g_list_last (browser->priv->viewer_pages)->data;
6224 		_gth_browser_set_current_viewer_page (browser, basic_viewer_page);
6225 		if (gth_window_get_current_page (GTH_WINDOW (browser)) == GTH_BROWSER_PAGE_VIEWER)
6226 			gth_viewer_page_show (browser->priv->viewer_page);
6227 		gth_viewer_page_view (browser->priv->viewer_page, browser->priv->current_file);
6228 
6229 		return;
6230 	}
6231 
6232 	_g_file_info_update (browser->priv->current_file->info, updated_metadata);
6233 	g_file_info_set_attribute_boolean (browser->priv->current_file->info, "gth::file::is-modified", FALSE);
6234 
6235 	if (browser->priv->load_metadata_timeout != 0)
6236 		g_source_remove (browser->priv->load_metadata_timeout);
6237 
6238 	data = load_file_data_new (browser, browser->priv->current_file, FALSE, FALSE);
6239 	browser->priv->load_metadata_timeout = g_timeout_add_full (G_PRIORITY_DEFAULT,
6240 								   LOAD_METADATA_DELAY,
6241 								   load_metadata_cb,
6242 								   data,
6243 								   (GDestroyNotify) load_file_data_unref);
6244 }
6245 
6246 
6247 static void
_gth_browser_load_file(GthBrowser * browser,GthFileData * file_data,gboolean view,gboolean fullcreen)6248 _gth_browser_load_file (GthBrowser  *browser,
6249 			GthFileData *file_data,
6250 			gboolean     view,
6251 			gboolean     fullcreen)
6252 {
6253 	GList *scan;
6254 
6255 	if (file_data == NULL) {
6256 		_gth_browser_deactivate_viewer_page (browser);
6257 		_g_object_unref (browser->priv->current_file);
6258 		browser->priv->current_file = NULL;
6259 
6260 		gth_sidebar_set_file (GTH_SIDEBAR (browser->priv->file_properties), NULL);
6261 
6262 		gth_browser_update_statusbar_file_info (browser);
6263 		gth_browser_update_title (browser);
6264 		gth_browser_update_sensitivity (browser);
6265 
6266 		return;
6267 	}
6268 
6269 	_g_object_unref (browser->priv->current_file);
6270 	browser->priv->current_file = gth_file_data_dup (file_data);
6271 
6272 	_gth_browser_update_current_file_position (browser);
6273 	gth_browser_update_statusbar_file_info (browser);
6274 
6275 	if (browser->priv->viewer_pages == NULL)
6276 		browser->priv->viewer_pages = g_list_reverse (gth_main_get_registered_objects (GTH_TYPE_VIEWER_PAGE));
6277 
6278 	for (scan = browser->priv->viewer_pages; scan; scan = scan->next) {
6279 		GthViewerPage *registered_viewer_page = scan->data;
6280 
6281 		if (gth_viewer_page_can_view (registered_viewer_page, browser->priv->current_file)) {
6282 			_gth_browser_set_current_viewer_page (browser, registered_viewer_page);
6283 			break;
6284 		}
6285 	}
6286 
6287 	if (view) {
6288 		if (fullcreen) {
6289 			if (! gth_browser_get_is_fullscreen (browser))
6290 				gth_browser_fullscreen (browser);
6291 		}
6292 		else
6293 			gth_window_set_current_page (GTH_WINDOW (browser), GTH_BROWSER_PAGE_VIEWER);
6294 	}
6295 
6296 	if (gth_window_get_current_page (GTH_WINDOW (browser)) == GTH_BROWSER_PAGE_VIEWER) {
6297 		gth_viewer_page_show (browser->priv->viewer_page);
6298 		if (browser->priv->fullscreen) {
6299 			gth_viewer_page_fullscreen (browser->priv->viewer_page, TRUE);
6300 			_gth_browser_show_pointer_on_viewer (browser, FALSE);
6301 		}
6302 		_gth_browser_make_file_visible (browser, browser->priv->current_file);
6303 	}
6304 
6305 	if (browser->priv->viewer_page != NULL)
6306 		gth_viewer_page_view (browser->priv->viewer_page, browser->priv->current_file);
6307 	else
6308 		gth_viewer_page_file_loaded_cb (NULL, browser->priv->current_file, NULL, FALSE, browser);
6309 }
6310 
6311 
6312 static void
load_file__previuos_file_saved_cb(GthBrowser * browser,gboolean cancelled,gpointer user_data)6313 load_file__previuos_file_saved_cb (GthBrowser *browser,
6314 				   gboolean    cancelled,
6315 				   gpointer    user_data)
6316 {
6317 	LoadFileData *data = user_data;
6318 
6319 	if (! cancelled)
6320 		_gth_browser_load_file (data->browser, data->file_data, data->view, data->fullscreen);
6321 
6322 	load_file_data_unref (data);
6323 }
6324 
6325 
6326 static gboolean
load_file_delayed_cb(gpointer user_data)6327 load_file_delayed_cb (gpointer user_data)
6328 {
6329 	LoadFileData *data = user_data;
6330 	GthBrowser   *browser = data->browser;
6331 
6332 	load_file_data_ref (data);
6333 
6334 	if (browser->priv->load_file_timeout != 0) {
6335 		g_source_remove (browser->priv->load_file_timeout);
6336 		browser->priv->load_file_timeout = 0;
6337 	}
6338 
6339 	if (browser->priv->ask_to_save_modified_images && gth_browser_get_file_modified (browser)) {
6340 		load_file_data_ref (data);
6341 		gth_browser_ask_whether_to_save (browser,
6342 						 load_file__previuos_file_saved_cb,
6343 						 data);
6344 	}
6345 	else
6346 		_gth_browser_load_file (data->browser, data->file_data, data->view, data->fullscreen);
6347 
6348 	load_file_data_unref (data);
6349 
6350 	return FALSE;
6351 }
6352 
6353 
6354 static void
_gth_browser_load_file_more_options(GthBrowser * browser,GthFileData * file_data,gboolean view,gboolean fullscreen,gboolean no_delay)6355 _gth_browser_load_file_more_options (GthBrowser  *browser,
6356 				     GthFileData *file_data,
6357 				     gboolean     view,
6358 				     gboolean     fullscreen,
6359 				     gboolean     no_delay)
6360 {
6361 	LoadFileData *data;
6362 
6363 	_gth_browser_hide_infobar (browser);
6364 
6365 	if (browser->priv->load_file_timeout != 0) {
6366 		g_source_remove (browser->priv->load_file_timeout);
6367 		browser->priv->load_file_timeout = 0;
6368 	}
6369 
6370 	if (browser->priv->load_metadata_timeout != 0) {
6371 		g_source_remove (browser->priv->load_metadata_timeout);
6372 		browser->priv->load_metadata_timeout = 0;
6373 	}
6374 
6375 	data = load_file_data_new (browser, file_data, view, fullscreen);
6376 	if (no_delay) {
6377 		load_file_delayed_cb (data);
6378 		load_file_data_unref (data);
6379 	}
6380 	else
6381 		browser->priv->load_file_timeout =
6382 				g_timeout_add_full (G_PRIORITY_DEFAULT,
6383 						    LOAD_FILE_DELAY,
6384 						    load_file_delayed_cb,
6385 						    data,
6386 						    (GDestroyNotify) load_file_data_unref);
6387 }
6388 
6389 
6390 static void
_gth_browser_load_file_keep_view(GthBrowser * browser,GthFileData * file_data,gboolean view,gboolean no_delay)6391 _gth_browser_load_file_keep_view (GthBrowser  *browser,
6392 				  GthFileData *file_data,
6393 				  gboolean     view,
6394 				  gboolean     no_delay)
6395 {
6396 	if (browser->priv->view_files_in_fullscreen && gth_browser_get_is_fullscreen (browser))
6397 		view = FALSE;
6398 	else if (gth_window_get_current_page (GTH_WINDOW (browser)) == GTH_BROWSER_PAGE_VIEWER)
6399 		view = FALSE;
6400 	_gth_browser_load_file_more_options (browser, file_data, view, browser->priv->view_files_in_fullscreen, no_delay);
6401 }
6402 
6403 
6404 void
gth_browser_load_file(GthBrowser * browser,GthFileData * file_data,gboolean view)6405 gth_browser_load_file (GthBrowser  *browser,
6406 		       GthFileData *file_data,
6407 		       gboolean     view)
6408 {
6409 	_gth_browser_load_file_keep_view (browser, file_data, view, view);
6410 }
6411 
6412 
6413 void
gth_browser_show_file_properties(GthBrowser * browser)6414 gth_browser_show_file_properties (GthBrowser *browser)
6415 {
6416 	switch (gth_window_get_current_page (GTH_WINDOW (browser))) {
6417 	case GTH_BROWSER_PAGE_BROWSER:
6418 	case GTH_WINDOW_PAGE_UNDEFINED: /* --> when called from gth_browser_init */
6419 		g_settings_set_boolean (browser->priv->browser_settings, PREF_BROWSER_PROPERTIES_VISIBLE, TRUE);
6420 		gth_window_change_action_state (GTH_WINDOW (browser), "browser-properties", TRUE);
6421 		if (gth_window_get_current_page (GTH_WINDOW (browser)) != GTH_WINDOW_PAGE_UNDEFINED)
6422 			gtk_widget_show (browser->priv->file_properties);
6423 		break;
6424 
6425 	case GTH_BROWSER_PAGE_VIEWER:
6426 		gth_window_change_action_state (GTH_WINDOW (browser), "viewer-edit-file", FALSE);
6427 		browser->priv->viewer_sidebar = GTH_SIDEBAR_STATE_PROPERTIES;
6428 		gth_window_change_action_state (GTH_WINDOW (browser), "viewer-properties", TRUE);
6429 		gtk_widget_show (browser->priv->viewer_sidebar_container);
6430 		gtk_widget_show (browser->priv->file_properties);
6431 		gth_sidebar_show_properties (GTH_SIDEBAR (browser->priv->file_properties));
6432 		break;
6433 	}
6434 }
6435 
6436 
6437 void
gth_browser_show_viewer_tools(GthBrowser * browser)6438 gth_browser_show_viewer_tools (GthBrowser *browser)
6439 {
6440 	gth_window_set_current_page (GTH_WINDOW (browser), GTH_BROWSER_PAGE_VIEWER);
6441 
6442 	gth_window_change_action_state (GTH_WINDOW (browser), "viewer-properties", FALSE);
6443 	browser->priv->viewer_sidebar = GTH_SIDEBAR_STATE_TOOLS;
6444 	gth_window_change_action_state (GTH_WINDOW (browser), "viewer-edit-file", TRUE);
6445 	gtk_widget_show (browser->priv->viewer_sidebar_container);
6446 	gtk_widget_show (browser->priv->file_properties);
6447 	gth_sidebar_show_tools (GTH_SIDEBAR (browser->priv->file_properties));
6448 }
6449 
6450 
6451 void
gth_browser_toggle_file_properties(GthBrowser * browser)6452 gth_browser_toggle_file_properties (GthBrowser  *browser)
6453 {
6454 	g_return_if_fail (GTH_IS_BROWSER (browser));
6455 
6456 	switch (gth_window_get_current_page (GTH_WINDOW (browser))) {
6457 	case GTH_BROWSER_PAGE_BROWSER:
6458 		if (gth_window_get_action_state (GTH_WINDOW (browser), "browser-properties"))
6459 			gth_browser_hide_sidebar (browser);
6460 		else
6461 			gth_browser_show_file_properties (browser);
6462 		break;
6463 
6464 	case GTH_BROWSER_PAGE_VIEWER:
6465 		gth_browser_toggle_properties_on_screen (browser);
6466 		break;
6467 
6468 	default:
6469 		break;
6470 	}
6471 }
6472 
6473 
6474 void
gth_browser_toggle_viewer_tools(GthBrowser * browser)6475 gth_browser_toggle_viewer_tools (GthBrowser  *browser)
6476 {
6477 	g_return_if_fail (GTH_IS_BROWSER (browser));
6478 
6479 	switch (gth_window_get_current_page (GTH_WINDOW (browser))) {
6480 	case GTH_BROWSER_PAGE_BROWSER:
6481 		if (browser->priv->viewer_page != NULL)
6482 			gth_browser_show_viewer_tools (GTH_BROWSER (browser));
6483 		break;
6484 
6485 	case GTH_BROWSER_PAGE_VIEWER:
6486 		if (browser->priv->viewer_sidebar != GTH_SIDEBAR_STATE_TOOLS)
6487 			gth_browser_show_viewer_tools (browser);
6488 		else
6489 			gth_browser_hide_sidebar (browser);
6490 		break;
6491 
6492 	default:
6493 		break;
6494 	}
6495 }
6496 
6497 
6498 void
gth_browser_hide_sidebar(GthBrowser * browser)6499 gth_browser_hide_sidebar (GthBrowser *browser)
6500 {
6501 	switch (gth_window_get_current_page (GTH_WINDOW (browser))) {
6502 	case GTH_BROWSER_PAGE_BROWSER:
6503 		g_settings_set_boolean (browser->priv->browser_settings, PREF_BROWSER_PROPERTIES_VISIBLE, FALSE);
6504 		gth_window_change_action_state (GTH_WINDOW (browser), "browser-properties", FALSE);
6505 		gtk_widget_hide (browser->priv->file_properties);
6506 		break;
6507 
6508 	case GTH_BROWSER_PAGE_VIEWER:
6509 		if (! gth_sidebar_tool_is_active (GTH_SIDEBAR (browser->priv->file_properties))) {
6510 			if (browser->priv->viewer_sidebar == GTH_SIDEBAR_STATE_PROPERTIES)
6511 				gth_window_change_action_state (GTH_WINDOW (browser), "viewer-properties", FALSE);
6512 			else if (browser->priv->viewer_sidebar == GTH_SIDEBAR_STATE_TOOLS)
6513 				gth_window_change_action_state (GTH_WINDOW (browser), "viewer-edit-file", FALSE);
6514 			browser->priv->viewer_sidebar = GTH_SIDEBAR_STATE_HIDDEN;
6515 			gtk_widget_hide (browser->priv->viewer_sidebar_container);
6516 		}
6517 		break;
6518 	}
6519 }
6520 
6521 
6522 /* -- gth_browser_load_location -- */
6523 
6524 
6525 typedef struct {
6526 	GthFileSource *file_source;
6527 	GthFileData   *location_data;
6528 	GthBrowser    *browser;
6529 } LoadLocationData;
6530 
6531 
6532 static void
load_location_data_free(LoadLocationData * data)6533 load_location_data_free (LoadLocationData *data)
6534 {
6535 	g_object_unref (data->location_data);
6536 	g_object_unref (data->file_source);
6537 	g_free (data);
6538 }
6539 
6540 
6541 static void
load_file_attributes_ready_cb(GObject * object,GError * error,gpointer user_data)6542 load_file_attributes_ready_cb (GObject  *object,
6543 			       GError   *error,
6544 			       gpointer  user_data)
6545 {
6546 	LoadLocationData *data = user_data;
6547 	GthBrowser       *browser = data->browser;
6548 
6549 	if (error == NULL) {
6550 		if (g_file_info_get_file_type (data->location_data->info) == G_FILE_TYPE_REGULAR) {
6551 			GFile *parent;
6552 
6553 			parent = g_file_get_parent (data->location_data->file);
6554 			if ((browser->priv->location != NULL) && ! g_file_equal (parent, browser->priv->location->file)) {
6555 				/* set location to NULL to force a folder reload */
6556 				_g_object_unref (browser->priv->location);
6557 				browser->priv->location = NULL;
6558 			}
6559 
6560 			gth_browser_load_file (browser, data->location_data, TRUE);
6561 
6562 			g_object_unref (parent);
6563 		}
6564 		else if (g_file_info_get_file_type (data->location_data->info) == G_FILE_TYPE_DIRECTORY) {
6565 			gth_window_set_current_page (GTH_WINDOW (browser), GTH_BROWSER_PAGE_BROWSER);
6566 			gth_browser_go_to (browser, data->location_data->file, NULL);
6567 		}
6568 		else {
6569 			char   *title;
6570 			GError *error;
6571 
6572 			title = _g_format_str_for_file (_("Could not load the position “%s”"), data->location_data->file);
6573 			error = g_error_new (GTH_ERROR, 0, _("File type not supported"));
6574 			_gth_browser_show_error (browser, title, error);
6575 			g_clear_error (&error);
6576 
6577 			g_free (title);
6578 		}
6579 	}
6580 	else if (browser->priv->location == NULL) {
6581 		GFile *home;
6582 
6583 		home = g_file_new_for_uri (_g_uri_get_home ());
6584 		gth_browser_load_location (browser, home);
6585 
6586 		g_object_unref (home);
6587 	}
6588 	else {
6589 		char *title;
6590 
6591 		title = _g_format_str_for_file (_("Could not load the position “%s”"), data->location_data->file);
6592 		_gth_browser_show_error (browser, title, error);
6593 
6594 		g_free (title);
6595 	}
6596 
6597 	load_location_data_free (data);
6598 }
6599 
6600 
6601 void
gth_browser_load_location(GthBrowser * browser,GFile * location)6602 gth_browser_load_location (GthBrowser *browser,
6603 		  	   GFile      *location)
6604 {
6605 	LoadLocationData *data;
6606 
6607 	data = g_new0 (LoadLocationData, 1);
6608 	data->browser = browser;
6609 	data->location_data = gth_file_data_new (location, NULL);
6610 	data->file_source = gth_main_get_file_source (data->location_data->file);
6611 	if (data->file_source == NULL) {
6612 		char   *title;
6613 		GError *error;
6614 
6615 		title = _g_format_str_for_file (_("Could not load the position “%s”"), data->location_data->file);
6616 		error = g_error_new (GTH_ERROR, 0, _("No suitable module found"));
6617 		_gth_browser_show_error (browser, title, error);
6618 		g_clear_error (&error);
6619 
6620 		g_free (title);
6621 	}
6622 
6623 	gth_file_source_read_metadata (data->file_source,
6624 				       data->location_data,
6625 				       GFILE_STANDARD_ATTRIBUTES_WITH_FAST_CONTENT_TYPE,
6626 				       load_file_attributes_ready_cb,
6627 				       data);
6628 }
6629 
6630 
6631 /* -- _gth_browser_cancel -- */
6632 
6633 
6634 #define CHECK_CANCELLABLE_INTERVAL 100
6635 
6636 
6637 typedef struct {
6638 	GthBrowser *browser;
6639 	DataFunc    done_func;
6640 	gpointer    user_data;
6641 	gulong      check_id;
6642 } CancelData;
6643 
6644 
6645 static void
cancel_data_unref(CancelData * cancel_data)6646 cancel_data_unref (CancelData *cancel_data)
6647 {
6648 	g_object_unref (cancel_data->browser);
6649 	g_free (cancel_data);
6650 }
6651 
6652 
6653 static gboolean
check_cancellable_cb(gpointer user_data)6654 check_cancellable_cb (gpointer user_data)
6655 {
6656 	CancelData *cancel_data = user_data;
6657 	GthBrowser *browser = cancel_data->browser;
6658 
6659 	if ((browser->priv->load_data_queue == NULL)
6660 	    && (browser->priv->load_file_data_queue == NULL)
6661 	    && (browser->priv->task == NULL)
6662 	    && (browser->priv->background_tasks == NULL))
6663 	{
6664 		g_source_remove (cancel_data->check_id);
6665 		cancel_data->check_id = 0;
6666 
6667 		if (cancel_data->done_func != NULL)
6668 			cancel_data->done_func (cancel_data->user_data);
6669 		cancel_data_unref (cancel_data);
6670 
6671 		return FALSE;
6672 	}
6673 
6674 	return TRUE;
6675 }
6676 
6677 
6678 static void
_gth_browser_cancel(GthBrowser * browser,DataFunc done_func,gpointer user_data)6679 _gth_browser_cancel (GthBrowser *browser,
6680 		     DataFunc    done_func,
6681 		     gpointer    user_data)
6682 {
6683 	CancelData *cancel_data;
6684 	GList      *scan;
6685 
6686 	cancel_data = g_new0 (CancelData, 1);
6687 	cancel_data->browser = g_object_ref (browser);
6688 	cancel_data->done_func = done_func;
6689 	cancel_data->user_data = user_data;
6690 
6691 	if (browser->priv->load_file_timeout != 0) {
6692 		g_source_remove (browser->priv->load_file_timeout);
6693 		browser->priv->load_file_timeout = 0;
6694 	}
6695 
6696 	if (browser->priv->load_metadata_timeout != 0) {
6697 		g_source_remove (browser->priv->load_metadata_timeout);
6698 		browser->priv->load_metadata_timeout = 0;
6699 	}
6700 
6701 	for (scan = browser->priv->load_data_queue; scan; scan = scan->next) {
6702 		LoadData *data = scan->data;
6703 
6704 		if (data->file_source != NULL)
6705 			gth_file_source_cancel (data->file_source);
6706 		g_cancellable_cancel (data->cancellable);
6707 	}
6708 
6709 	for (scan = browser->priv->load_file_data_queue; scan; scan = scan->next) {
6710 		LoadFileData *data = scan->data;
6711 		g_cancellable_cancel (data->cancellable);
6712 	}
6713 
6714 	for (scan = browser->priv->background_tasks; scan; scan = scan->next) {
6715 		TaskData *data = scan->data;
6716 		if (gth_task_is_running (data->task))
6717 			gth_task_cancel (data->task);
6718 	}
6719 
6720 	if ((browser->priv->task != NULL) && gth_task_is_running (browser->priv->task))
6721 		gth_task_cancel (browser->priv->task);
6722 
6723 	cancel_data->check_id = g_timeout_add (CHECK_CANCELLABLE_INTERVAL,
6724 					       check_cancellable_cb,
6725 					       cancel_data);
6726 }
6727 
6728 
6729 gpointer
gth_browser_get_image_preloader(GthBrowser * browser)6730 gth_browser_get_image_preloader (GthBrowser *browser)
6731 {
6732 	return g_object_ref (browser->priv->image_preloader);
6733 }
6734 
6735 
6736 void
gth_browser_register_viewer_control(GthBrowser * browser,GtkWidget * widget)6737 gth_browser_register_viewer_control (GthBrowser *browser,
6738 				     GtkWidget  *widget)
6739 {
6740 	browser->priv->viewer_controls = g_list_prepend (browser->priv->viewer_controls, widget);
6741 }
6742 
6743 
6744 void
gth_browser_unregister_viewer_control(GthBrowser * browser,GtkWidget * widget)6745 gth_browser_unregister_viewer_control (GthBrowser *browser,
6746 				       GtkWidget  *widget)
6747 {
6748 	browser->priv->viewer_controls = g_list_remove (browser->priv->viewer_controls, widget);
6749 }
6750 
6751 
6752 void
gth_browser_fullscreen(GthBrowser * browser)6753 gth_browser_fullscreen (GthBrowser *browser)
6754 {
6755 	if (browser->priv->fullscreen) {
6756 		gth_browser_unfullscreen (browser);
6757 		return;
6758 	}
6759 
6760 	if (browser->priv->current_file == NULL) {
6761 		if (! gth_browser_show_first_image (browser, FALSE, FALSE)) {
6762 			browser->priv->fullscreen = FALSE;
6763 			return;
6764 		}
6765 	}
6766 
6767 	browser->priv->was_fullscreen = FALSE;
6768 	browser->priv->fullscreen = TRUE;
6769 
6770 	browser->priv->before_fullscreen.page = gth_window_get_current_page (GTH_WINDOW (browser));
6771 	browser->priv->before_fullscreen.thumbnail_list = gth_window_get_action_state (GTH_WINDOW (browser), "show-thumbnail-list");
6772 	browser->priv->before_fullscreen.browser_properties = gth_window_get_action_state (GTH_WINDOW (browser), "browser-properties");
6773 	browser->priv->before_fullscreen.viewer_sidebar = browser->priv->viewer_sidebar;
6774 
6775 	if (browser->priv->fullscreen_headerbar == NULL) {
6776 		browser->priv->fullscreen_headerbar = gth_window_get_header_bar (GTH_WINDOW (browser));
6777 
6778 		gtk_widget_set_margin_top (browser->priv->viewer_sidebar_container,
6779 					   gtk_widget_get_allocated_height (browser->priv->fullscreen_headerbar));
6780 
6781 		g_object_ref (browser->priv->fullscreen_headerbar);
6782 		gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (browser->priv->fullscreen_headerbar)), browser->priv->fullscreen_headerbar);
6783 		gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (browser->priv->fullscreen_headerbar), FALSE);
6784 		gtk_box_pack_start (GTK_BOX (browser->priv->fullscreen_toolbar), browser->priv->fullscreen_headerbar, TRUE, TRUE, 0);
6785 		g_object_unref (browser->priv->fullscreen_headerbar);
6786 	}
6787 
6788 	g_list_free (browser->priv->viewer_controls);
6789 	browser->priv->viewer_controls = g_list_append (NULL, browser->priv->fullscreen_toolbar);
6790 
6791 	gtk_window_fullscreen (GTK_WINDOW (browser));
6792 
6793 	gth_window_set_current_page (GTH_WINDOW (browser), GTH_BROWSER_PAGE_VIEWER);
6794 	if (browser->priv->fullscreen_state.sidebar == GTH_SIDEBAR_STATE_PROPERTIES)
6795 		gth_browser_show_file_properties (browser);
6796 	else if (browser->priv->fullscreen_state.sidebar == GTH_SIDEBAR_STATE_TOOLS)
6797 		gth_browser_show_viewer_tools (browser);
6798 	else
6799 		gth_browser_hide_sidebar (browser);
6800 
6801 	_gth_browser_set_thumbnail_list_visibility (browser, browser->priv->fullscreen_state.thumbnail_list);
6802 
6803 	gth_window_show_only_content (GTH_WINDOW (browser), TRUE);
6804 
6805 	browser->priv->properties_on_screen = FALSE;
6806 
6807 	if (browser->priv->viewer_page != NULL) {
6808 		gth_viewer_page_show_properties (browser->priv->viewer_page, browser->priv->properties_on_screen);
6809 		gth_viewer_page_fullscreen (browser->priv->viewer_page, TRUE);
6810 		_gth_browser_show_pointer_on_viewer (browser, FALSE);
6811 	}
6812 
6813 	gth_browser_update_sensitivity (browser);
6814 	browser->priv->was_fullscreen = browser->priv->fullscreen;
6815 }
6816 
6817 
6818 void
gth_browser_unfullscreen(GthBrowser * browser)6819 gth_browser_unfullscreen (GthBrowser *browser)
6820 {
6821 	browser->priv->was_fullscreen = TRUE;
6822 	browser->priv->fullscreen = FALSE;
6823 
6824 	if (browser->priv->fullscreen_headerbar != NULL) {
6825 		g_object_ref (browser->priv->fullscreen_headerbar);
6826 		gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (browser->priv->fullscreen_headerbar)), browser->priv->fullscreen_headerbar);
6827 		gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (browser->priv->fullscreen_headerbar), TRUE);
6828 		gth_window_set_header_bar (GTH_WINDOW (browser), browser->priv->fullscreen_headerbar);
6829 		g_object_unref (browser->priv->fullscreen_headerbar);
6830 		browser->priv->fullscreen_headerbar = NULL;
6831 	}
6832 	gtk_widget_set_margin_top (browser->priv->viewer_sidebar_container, 0);
6833 	gtk_widget_hide (browser->priv->fullscreen_toolbar);
6834 
6835 	gth_window_show_only_content (GTH_WINDOW (browser), FALSE);
6836 
6837 	if (! gth_sidebar_tool_is_active (GTH_SIDEBAR (browser->priv->file_properties)))
6838 		browser->priv->fullscreen_state.sidebar = browser->priv->viewer_sidebar;
6839 	browser->priv->fullscreen_state.thumbnail_list = gth_window_get_action_state (GTH_WINDOW (browser), "show-thumbnail-list");
6840 
6841 	if (browser->priv->before_fullscreen.page < 0)
6842 		browser->priv->before_fullscreen.page = GTH_BROWSER_PAGE_BROWSER;
6843 	gth_window_set_current_page (GTH_WINDOW (browser), browser->priv->before_fullscreen.page);
6844 
6845 	_gth_browser_set_thumbnail_list_visibility (browser, browser->priv->before_fullscreen.thumbnail_list);
6846 
6847 	if (browser->priv->before_fullscreen.page == GTH_BROWSER_PAGE_BROWSER) {
6848 		browser->priv->viewer_sidebar = browser->priv->before_fullscreen.viewer_sidebar;
6849 		if (browser->priv->before_fullscreen.browser_properties)
6850 			gth_browser_show_file_properties (browser);
6851 		else
6852 			gth_browser_hide_sidebar (browser);
6853 	}
6854 	else if (browser->priv->before_fullscreen.page == GTH_BROWSER_PAGE_VIEWER) {
6855 		if (browser->priv->before_fullscreen.viewer_sidebar == GTH_SIDEBAR_STATE_PROPERTIES)
6856 			gth_browser_show_file_properties (browser);
6857 		else if (browser->priv->before_fullscreen.viewer_sidebar == GTH_SIDEBAR_STATE_TOOLS)
6858 			gth_browser_show_viewer_tools (browser);
6859 		else
6860 			gth_browser_hide_sidebar (browser);
6861 	}
6862 
6863 	gtk_window_unfullscreen (GTK_WINDOW (browser));
6864 
6865 	browser->priv->properties_on_screen = FALSE;
6866 	if (browser->priv->viewer_page != NULL) {
6867 		if (GTH_VIEWER_PAGE_GET_INTERFACE (browser->priv->viewer_page)->show_properties != NULL)
6868 			gth_viewer_page_show_properties (browser->priv->viewer_page, FALSE);
6869 		gth_viewer_page_fullscreen (browser->priv->viewer_page, FALSE);
6870 	}
6871 	_gth_browser_show_pointer_on_viewer (browser, TRUE);
6872 	g_list_free (browser->priv->viewer_controls);
6873 	browser->priv->viewer_controls = NULL;
6874 
6875 	gth_browser_update_sensitivity (browser);
6876 	browser->priv->was_fullscreen = browser->priv->fullscreen;
6877 }
6878 
6879 
6880 gboolean
gth_browser_get_is_fullscreen(GthBrowser * browser)6881 gth_browser_get_is_fullscreen (GthBrowser *browser)
6882 {
6883 	return browser->priv->fullscreen;
6884 }
6885 
6886 
6887 void
gth_browser_file_menu_popup(GthBrowser * browser,GdkEventButton * event)6888 gth_browser_file_menu_popup (GthBrowser     *browser,
6889 			     GdkEventButton *event)
6890 {
6891 	gth_hook_invoke ("gth-browser-file-popup-before", browser);
6892 	gtk_menu_popup_at_pointer (GTK_MENU (browser->priv->file_popup), (GdkEvent *) event);
6893 }
6894 
6895 
6896 void
gth_browser_save_state(GthBrowser * browser)6897 gth_browser_save_state (GthBrowser *browser)
6898 {
6899 	browser_state_free (&browser->priv->state);
6900 
6901 	browser->priv->state.saved = TRUE;
6902 	browser->priv->state.page = gth_window_get_current_page (GTH_WINDOW (browser));
6903 	if (browser->priv->location != NULL)
6904 		browser->priv->state.location = g_object_ref (browser->priv->location->file);
6905 	if (browser->priv->current_file != NULL)
6906 		browser->priv->state.current_file = g_object_ref (browser->priv->current_file->file);
6907 	browser->priv->state.selected = gth_file_selection_get_selected (GTH_FILE_SELECTION (gth_file_list_get_view (GTH_FILE_LIST (browser->priv->file_list))));
6908 	browser->priv->state.vscroll = gtk_adjustment_get_value (gth_file_list_get_vadjustment (GTH_FILE_LIST (browser->priv->file_list)));
6909 }
6910 
6911 
6912 gboolean
gth_browser_restore_state(GthBrowser * browser)6913 gth_browser_restore_state (GthBrowser *browser)
6914 {
6915 	if (! browser->priv->state.saved)
6916 		return FALSE;
6917 
6918 	switch (browser->priv->state.page) {
6919 	case GTH_BROWSER_PAGE_BROWSER:
6920 		if (browser->priv->state.current_file != NULL) {
6921 			gth_browser_go_to (browser,
6922 					   browser->priv->state.location,
6923 					   browser->priv->state.current_file);
6924 		}
6925 		else {
6926 			_gth_browser_load_file_more_options (browser, NULL, FALSE, FALSE, FALSE);
6927 			gth_browser_go_to_with_state (browser,
6928 						      browser->priv->state.location,
6929 						      browser->priv->state.selected,
6930 						      browser->priv->state.vscroll);
6931 		}
6932 		break;
6933 
6934 	case GTH_BROWSER_PAGE_VIEWER:
6935 		gth_browser_load_location (browser, browser->priv->state.current_file);
6936 		break;
6937 
6938 	default:
6939 		break;
6940 	}
6941 
6942 	return TRUE;
6943 }
6944 
6945 
6946 void
gth_browser_apply_editor_changes(GthBrowser * browser)6947 gth_browser_apply_editor_changes (GthBrowser *browser)
6948 {
6949 	GtkWidget *toolbox;
6950 	GtkWidget *file_tool;
6951 
6952 	toolbox = gth_sidebar_get_toolbox (GTH_SIDEBAR (browser->priv->file_properties));
6953 	file_tool = gth_toolbox_get_active_tool (GTH_TOOLBOX (toolbox));
6954 	if (file_tool != NULL)
6955 		gth_file_tool_apply_options (GTH_FILE_TOOL (file_tool));
6956 }
6957 
6958 
6959 GthICCProfile *
gth_browser_get_monitor_profile(GthBrowser * browser)6960 gth_browser_get_monitor_profile (GthBrowser *browser)
6961 {
6962 #if HAVE_LCMS2
6963 	if (browser->priv->screen_profile == NULL) {
6964 		int monitor_num;
6965 
6966 		if (_gtk_window_get_monitor_info (GTK_WINDOW (browser), NULL, &monitor_num, NULL)) {
6967 			char      *atom_name;
6968 			GdkAtom    type    = GDK_NONE;
6969 			int        format  = 0;
6970 			int        nitems  = 0;
6971 			guchar    *data    = NULL;
6972 
6973 			if (monitor_num > 0)
6974 				atom_name = g_strdup_printf ("_ICC_PROFILE_%d", monitor_num);
6975 			else
6976 				atom_name = g_strdup ("_ICC_PROFILE");
6977 
6978 			if (gdk_property_get (gdk_screen_get_root_window (gtk_widget_get_screen (GTK_WIDGET (browser))),
6979 			                      gdk_atom_intern (atom_name, FALSE),
6980 					      GDK_NONE,
6981 					      0, 64 * 1024 * 1024, FALSE,
6982 					      &type, &format, &nitems, &data) && nitems > 0)
6983 			{
6984 				GthCMSProfile cms_profile;
6985 
6986 				cms_profile = (GthCMSProfile) cmsOpenProfileFromMem (data, nitems);
6987 				if (cms_profile != NULL) {
6988 					char *id = g_strdup_printf ("%s%d", GTH_ICC_PROFILE_FROM_PROPERTY, monitor_num);
6989 					browser->priv->screen_profile = gth_icc_profile_new (id, cms_profile);
6990 					g_free (id);
6991 				}
6992 
6993 				g_free (data);
6994 			}
6995 
6996 			g_free (atom_name);
6997 		}
6998 	}
6999 #endif
7000 
7001 	if (browser->priv->screen_profile == NULL)
7002 		browser->priv->screen_profile = gth_icc_profile_new_srgb();
7003 
7004 	return browser->priv->screen_profile;
7005 }
7006 
7007 
7008 GtkWidget *
gth_browser_get_fullscreen_headerbar(GthBrowser * browser)7009 gth_browser_get_fullscreen_headerbar (GthBrowser *browser)
7010 {
7011 	return browser->priv->fullscreen_headerbar;
7012 }
7013 
7014 
7015 void
gth_browser_keep_mouse_visible(GthBrowser * browser,gboolean value)7016 gth_browser_keep_mouse_visible (GthBrowser *browser,
7017 			        gboolean    value)
7018 {
7019 	browser->priv->keep_mouse_visible = value;
7020 }
7021 
7022 
7023 void
gth_browser_show_menu(GthBrowser * browser)7024 gth_browser_show_menu (GthBrowser *browser)
7025 {
7026 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (browser->priv->menu_button), TRUE);
7027 }
7028