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