1 /* Eye Of Gnome - Main Window
2  *
3  * Copyright (C) 2000-2008 The Free Software Foundation
4  *
5  * Author: Lucas Rocha <lucasr@gnome.org>
6  *
7  * Based on code by:
8  * 	- Federico Mena-Quintero <federico@gnome.org>
9  *	- Jens Finke <jens@gnome.org>
10  * Based on evince code (shell/ev-window.c) by:
11  * 	- Martin Kretzschmar <martink@gnome.org>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License along
24  * with this program; if not, write to the Free Software Foundation, Inc.,
25  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31 
32 #include <math.h>
33 
34 #include "eog-window.h"
35 #include "eog-scroll-view.h"
36 #include "eog-debug.h"
37 #include "eog-file-chooser.h"
38 #include "eog-thumb-view.h"
39 #include "eog-list-store.h"
40 #include "eog-sidebar.h"
41 #include "eog-statusbar.h"
42 #include "eog-preferences-dialog.h"
43 #include "eog-properties-dialog.h"
44 #include "eog-print.h"
45 #include "eog-error-message-area.h"
46 #include "eog-application.h"
47 #include "eog-application-internal.h"
48 #include "eog-thumb-nav.h"
49 #include "eog-config-keys.h"
50 #include "eog-job-scheduler.h"
51 #include "eog-jobs.h"
52 #include "eog-util.h"
53 #include "eog-save-as-dialog-helper.h"
54 #include "eog-plugin-engine.h"
55 #include "eog-close-confirmation-dialog.h"
56 #include "eog-clipboard-handler.h"
57 #include "eog-window-activatable.h"
58 #include "eog-metadata-sidebar.h"
59 #include "eog-zoom-entry.h"
60 
61 #include "eog-enum-types.h"
62 
63 #include <glib.h>
64 #include <glib-object.h>
65 #include <glib/gi18n.h>
66 #include <gio/gio.h>
67 #include <gdk/gdkkeysyms.h>
68 #include <gio/gdesktopappinfo.h>
69 #include <gtk/gtk.h>
70 
71 #include <libpeas/peas-extension-set.h>
72 #include <libpeas/peas-activatable.h>
73 
74 #if defined(HAVE_LCMS) && defined(GDK_WINDOWING_X11)
75 #include <X11/Xlib.h>
76 #include <X11/Xatom.h>
77 #include <gdk/gdkx.h>
78 #include <lcms2.h>
79 #endif
80 
81 #define EOG_WINDOW_MIN_WIDTH  360
82 #define EOG_WINDOW_MIN_HEIGHT 350
83 
84 #define EOG_WINDOW_DEFAULT_WIDTH  540
85 #define EOG_WINDOW_DEFAULT_HEIGHT 450
86 
87 #define EOG_WINDOW_FULLSCREEN_TIMEOUT 2 * 1000
88 #define EOG_WINDOW_FULLSCREEN_POPUP_THRESHOLD 5
89 
90 #define EOG_RECENT_FILES_GROUP  "Graphics"
91 #define EOG_RECENT_FILES_APP_NAME "Image Viewer"
92 
93 #define EOG_WALLPAPER_FILENAME "eog-wallpaper"
94 
95 #define is_rtl (gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL)
96 
97 typedef enum {
98 	EOG_WINDOW_STATUS_UNKNOWN,
99 	EOG_WINDOW_STATUS_INIT,
100 	EOG_WINDOW_STATUS_NORMAL
101 } EogWindowStatus;
102 
103 enum {
104 	PROP_0,
105 	PROP_GALLERY_POS,
106 	PROP_GALLERY_RESIZABLE,
107 	PROP_STARTUP_FLAGS
108 };
109 
110 enum {
111 	SIGNAL_PREPARED,
112 	SIGNAL_LAST
113 };
114 
115 static gint signals[SIGNAL_LAST];
116 
117 struct _EogWindowPrivate {
118 	GSettings           *fullscreen_settings;
119 	GSettings           *ui_settings;
120 	GSettings           *view_settings;
121 	GSettings           *lockdown_settings;
122 
123         EogListStore        *store;
124         EogImage            *image;
125 	EogWindowMode        mode;
126 	EogWindowStatus      status;
127 
128         GtkWidget           *overlay;
129         GtkWidget           *box;
130         GtkWidget           *layout;
131         GtkWidget           *cbox;
132         GtkWidget           *view;
133         GtkWidget           *sidebar;
134         GtkWidget           *thumbview;
135         GtkWidget           *statusbar;
136         GtkWidget           *nav;
137 	GtkWidget           *message_area;
138 	GtkWidget           *properties_dlg;
139 
140 	GtkBuilder          *gear_menu_builder;
141 
142 	GtkWidget           *fullscreen_popup;
143 	GSource             *fullscreen_timeout_source;
144 
145 	gboolean             slideshow_loop;
146 	gint                 slideshow_switch_timeout;
147 	GSource             *slideshow_switch_source;
148 
149 	guint                fullscreen_idle_inhibit_cookie;
150 
151         EogJob              *load_job;
152         EogJob              *transform_job;
153 	EogJob              *save_job;
154 	GFile               *last_save_as_folder;
155 	EogJob              *copy_job;
156 
157         guint                image_info_message_cid;
158         guint                tip_message_cid;
159 	guint                copy_file_cid;
160 
161         EogStartupFlags      flags;
162 	GSList              *file_list;
163 
164 	EogWindowGalleryPos  gallery_position;
165 	gboolean             gallery_resizable;
166 
167 	gboolean	     save_disabled;
168 	gboolean             needs_reload_confirmation;
169 
170 	GtkPageSetup        *page_setup;
171 
172 	PeasExtensionSet    *extensions;
173 
174 #ifdef HAVE_LCMS
175         cmsHPROFILE         *display_profile;
176 #endif
177 };
178 
179 G_DEFINE_TYPE_WITH_PRIVATE (EogWindow, eog_window, GTK_TYPE_APPLICATION_WINDOW);
180 
181 static void eog_window_action_toggle_fullscreen (GSimpleAction *action, GVariant *state, gpointer user_data);
182 static void eog_window_run_fullscreen (EogWindow *window, gboolean slideshow);
183 static void eog_window_action_save (GSimpleAction *action, GVariant *variant, gpointer user_data);
184 static void eog_window_action_save_as (GSimpleAction *action, GVariant *variant, gpointer user_data);
185 static void eog_window_action_toggle_slideshow (GSimpleAction *action, GVariant *state, gpointer user_data);
186 static void eog_window_action_pause_slideshow (GSimpleAction *action, GVariant *variant, gpointer user_data);
187 static void eog_window_stop_fullscreen (EogWindow *window, gboolean slideshow);
188 static void eog_job_load_cb (EogJobLoad *job, gpointer data);
189 static void eog_job_save_progress_cb (EogJobSave *job, float progress, gpointer data);
190 static void eog_job_progress_cb (EogJobLoad *job, float progress, gpointer data);
191 static void eog_job_transform_cb (EogJobTransform *job, gpointer data);
192 static void fullscreen_set_timeout (EogWindow *window);
193 static void fullscreen_clear_timeout (EogWindow *window);
194 static void slideshow_set_timeout (EogWindow *window);
195 static void update_action_groups_state (EogWindow *window);
196 static void eog_window_list_store_image_added (GtkTreeModel *tree_model,
197 					       GtkTreePath  *path,
198 					       GtkTreeIter  *iter,
199 					       gpointer      user_data);
200 static void eog_window_list_store_image_removed (GtkTreeModel *tree_model,
201                  				 GtkTreePath  *path,
202 						 gpointer      user_data);
203 static void eog_window_set_wallpaper (EogWindow *window, const gchar *filename, const gchar *visible_filename);
204 static gboolean eog_window_save_images (EogWindow *window, GList *images);
205 static void eog_window_finish_saving (EogWindow *window);
206 static void eog_window_error_message_area_response (GtkInfoBar *message_area,
207 						    gint        response_id,
208 						    EogWindow  *window);
209 
210 static GQuark
eog_window_error_quark(void)211 eog_window_error_quark (void)
212 {
213 	static GQuark q = 0;
214 
215 	if (q == 0)
216 		q = g_quark_from_static_string ("eog-window-error-quark");
217 
218 	return q;
219 }
220 
221 static gboolean
_eog_zoom_shrink_to_boolean(GBinding * binding,const GValue * source,GValue * target,gpointer user_data)222 _eog_zoom_shrink_to_boolean (GBinding *binding, const GValue *source,
223 			     GValue *target, gpointer user_data)
224 {
225 	EogZoomMode mode = g_value_get_enum (source);
226 	gboolean is_fit;
227 
228 	is_fit = (mode == EOG_ZOOM_MODE_SHRINK_TO_FIT);
229 	g_value_set_variant (target, g_variant_new_boolean (is_fit));
230 
231 	return TRUE;
232 }
233 
234 static void
eog_window_set_gallery_mode(EogWindow * window,EogWindowGalleryPos position,gboolean resizable)235 eog_window_set_gallery_mode (EogWindow           *window,
236 			     EogWindowGalleryPos  position,
237 			     gboolean             resizable)
238 {
239 	EogWindowPrivate *priv;
240 	GtkWidget *hpaned;
241 	EogThumbNavMode mode = EOG_THUMB_NAV_MODE_ONE_ROW;
242 
243 	eog_debug (DEBUG_PREFERENCES);
244 
245 	g_return_if_fail (EOG_IS_WINDOW (window));
246 
247 	priv = window->priv;
248 
249 	/* If layout is not set, ignore similar parameters
250 	 * to make sure a layout is set eventually */
251 	if (priv->layout
252 	    && priv->gallery_position == position
253 	    && priv->gallery_resizable == resizable)
254 		return;
255 
256 	priv->gallery_position = position;
257 	priv->gallery_resizable = resizable;
258 
259 	hpaned = gtk_widget_get_parent (priv->sidebar);
260 
261 	g_object_ref (hpaned);
262 	g_object_ref (priv->nav);
263 
264 	if (priv->layout)
265 	{
266 		gtk_container_remove (GTK_CONTAINER (priv->layout), hpaned);
267 		gtk_container_remove (GTK_CONTAINER (priv->layout), priv->nav);
268 
269 		gtk_widget_destroy (priv->layout);
270 	}
271 
272 	switch (position) {
273 	case EOG_WINDOW_GALLERY_POS_BOTTOM:
274 	case EOG_WINDOW_GALLERY_POS_TOP:
275 		if (resizable) {
276 			mode = EOG_THUMB_NAV_MODE_MULTIPLE_ROWS;
277 
278 			priv->layout = gtk_paned_new (GTK_ORIENTATION_VERTICAL);
279 
280 			if (position == EOG_WINDOW_GALLERY_POS_BOTTOM) {
281 				gtk_paned_pack1 (GTK_PANED (priv->layout), hpaned, TRUE, FALSE);
282 				gtk_paned_pack2 (GTK_PANED (priv->layout), priv->nav, FALSE, TRUE);
283 			} else {
284 				gtk_paned_pack1 (GTK_PANED (priv->layout), priv->nav, FALSE, TRUE);
285 				gtk_paned_pack2 (GTK_PANED (priv->layout), hpaned, TRUE, FALSE);
286 			}
287 		} else {
288 			mode = EOG_THUMB_NAV_MODE_ONE_ROW;
289 
290 			priv->layout = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
291 
292 			if (position == EOG_WINDOW_GALLERY_POS_BOTTOM) {
293 				gtk_box_pack_start (GTK_BOX (priv->layout), hpaned, TRUE, TRUE, 0);
294 				gtk_box_pack_start (GTK_BOX (priv->layout), priv->nav, FALSE, FALSE, 0);
295 			} else {
296 				gtk_box_pack_start (GTK_BOX (priv->layout), priv->nav, FALSE, FALSE, 0);
297 				gtk_box_pack_start (GTK_BOX (priv->layout), hpaned, TRUE, TRUE, 0);
298 			}
299 		}
300 		break;
301 
302 	case EOG_WINDOW_GALLERY_POS_LEFT:
303 	case EOG_WINDOW_GALLERY_POS_RIGHT:
304 		if (resizable) {
305 			mode = EOG_THUMB_NAV_MODE_MULTIPLE_COLUMNS;
306 
307 			priv->layout = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
308 
309 			if (position == EOG_WINDOW_GALLERY_POS_LEFT) {
310 				gtk_paned_pack1 (GTK_PANED (priv->layout), priv->nav, FALSE, TRUE);
311 				gtk_paned_pack2 (GTK_PANED (priv->layout), hpaned, TRUE, FALSE);
312 			} else {
313 				gtk_paned_pack1 (GTK_PANED (priv->layout), hpaned, TRUE, FALSE);
314 				gtk_paned_pack2 (GTK_PANED (priv->layout), priv->nav, FALSE, TRUE);
315 			}
316 		} else {
317 			mode = EOG_THUMB_NAV_MODE_ONE_COLUMN;
318 
319 			priv->layout = gtk_box_new (GTK_ORIENTATION_HORIZONTAL,
320 						    2);
321 
322 			if (position == EOG_WINDOW_GALLERY_POS_LEFT) {
323 				gtk_box_pack_start (GTK_BOX (priv->layout), priv->nav, FALSE, FALSE, 0);
324 				gtk_box_pack_start (GTK_BOX (priv->layout), hpaned, TRUE, TRUE, 0);
325 			} else {
326 				gtk_box_pack_start (GTK_BOX (priv->layout), hpaned, TRUE, TRUE, 0);
327 				gtk_box_pack_start (GTK_BOX (priv->layout), priv->nav, FALSE, FALSE, 0);
328 			}
329 		}
330 
331 		break;
332 	}
333 
334 	gtk_box_pack_end (GTK_BOX (priv->cbox), priv->layout, TRUE, TRUE, 0);
335 	gtk_widget_show (priv->layout);
336 
337 	eog_thumb_nav_set_mode (EOG_THUMB_NAV (priv->nav), mode);
338 
339 	if (priv->mode != EOG_WINDOW_MODE_UNKNOWN) {
340 		update_action_groups_state (window);
341 	}
342 }
343 
344 static void
eog_window_can_save_changed_cb(GSettings * settings,const gchar * key,gpointer user_data)345 eog_window_can_save_changed_cb (GSettings   *settings,
346 				const gchar *key,
347 				gpointer     user_data)
348 {
349 	EogWindowPrivate *priv;
350 	EogWindow *window;
351 	gboolean save_disabled = FALSE;
352 	GAction *action_save, *action_save_as;
353 
354 	eog_debug (DEBUG_PREFERENCES);
355 
356 	g_return_if_fail (EOG_IS_WINDOW (user_data));
357 
358 	window = EOG_WINDOW (user_data);
359 	priv = EOG_WINDOW (user_data)->priv;
360 
361 	save_disabled = g_settings_get_boolean (settings, key);
362 
363 	priv->save_disabled = save_disabled;
364 
365 	action_save =
366 		g_action_map_lookup_action (G_ACTION_MAP (window),
367 									"save");
368 	action_save_as =
369 		g_action_map_lookup_action (G_ACTION_MAP (window),
370 									"save-as");
371 
372 	if (priv->save_disabled) {
373 		g_simple_action_set_enabled (G_SIMPLE_ACTION (action_save), FALSE);
374 		g_simple_action_set_enabled (G_SIMPLE_ACTION (action_save_as), FALSE);
375 	} else {
376 		EogImage *image = eog_window_get_image (window);
377 
378 		if (EOG_IS_IMAGE (image)) {
379 			g_simple_action_set_enabled (G_SIMPLE_ACTION (action_save),
380 						  eog_image_is_modified (image));
381 
382 			g_simple_action_set_enabled (G_SIMPLE_ACTION (action_save_as), TRUE);
383 		}
384 	}
385 }
386 
387 #if defined(HAVE_LCMS) && defined(GDK_WINDOWING_X11)
388 static cmsHPROFILE *
eog_window_get_display_profile(GtkWidget * window)389 eog_window_get_display_profile (GtkWidget *window)
390 {
391 	GdkScreen *screen;
392 	Display *dpy;
393 	Atom icc_atom, type;
394 	int format;
395 	gulong nitems;
396 	gulong bytes_after;
397 	gulong length;
398 	guchar *str;
399 	int result;
400 	cmsHPROFILE *profile = NULL;
401 	char *atom_name;
402 
403 	screen = gtk_widget_get_screen (window);
404 
405 	if (GDK_IS_X11_SCREEN (screen)) {
406 		dpy = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen));
407 
408 		if (gdk_x11_screen_get_screen_number (screen) > 0)
409 			atom_name = g_strdup_printf ("_ICC_PROFILE_%d",
410 			                             gdk_x11_screen_get_screen_number (screen));
411 		else
412 			atom_name = g_strdup ("_ICC_PROFILE");
413 
414 		icc_atom = gdk_x11_get_xatom_by_name_for_display (gdk_screen_get_display (screen), atom_name);
415 
416 		g_free (atom_name);
417 
418 		result = XGetWindowProperty (dpy,
419 					     GDK_WINDOW_XID (gdk_screen_get_root_window (screen)),
420 					     icc_atom,
421 					     0,
422 					     G_MAXLONG,
423 					     False,
424 					     XA_CARDINAL,
425 					     &type,
426 					     &format,
427 					     &nitems,
428 					     &bytes_after,
429 		                             (guchar **)&str);
430 
431 		/* TODO: handle bytes_after != 0 */
432 
433 		if ((result == Success) && (type == XA_CARDINAL) && (nitems > 0)) {
434 			switch (format)
435 			{
436 				case 8:
437 					length = nitems;
438 					break;
439 				case 16:
440 					length = sizeof(short) * nitems;
441 					break;
442 				case 32:
443 					length = sizeof(long) * nitems;
444 					break;
445 				default:
446 					eog_debug_message (DEBUG_LCMS,
447 					                   "Unable to read profile, not correcting");
448 
449 					XFree (str);
450 					return NULL;
451 			}
452 
453 			profile = cmsOpenProfileFromMem (str, length);
454 
455 			if (G_UNLIKELY (profile == NULL)) {
456 				eog_debug_message (DEBUG_LCMS,
457 						   "Invalid display profile set, "
458 						   "not using it");
459 			}
460 
461 			XFree (str);
462 		}
463 	} else {
464 		/* ICC profiles cannot be queried on Wayland yet */
465 		eog_debug_message (DEBUG_LCMS,
466 		                   "Not an X11 screen. "
467 		                   "Cannot fetch display profile.");
468 	}
469 
470 	if (profile == NULL) {
471 		profile = cmsCreate_sRGBProfile ();
472 		eog_debug_message (DEBUG_LCMS,
473 		                   "No valid display profile set, assuming sRGB");
474 	}
475 
476 	return profile;
477 }
478 #endif
479 
480 static void
update_image_pos(EogWindow * window)481 update_image_pos (EogWindow *window)
482 {
483 	EogWindowPrivate *priv;
484 	GAction* action;
485 	gint pos = -1, n_images = 0;
486 
487 	priv = window->priv;
488 
489 	n_images = eog_list_store_length (EOG_LIST_STORE (priv->store));
490 
491 	/* priv->image may be NULL even if n_images > 0 */
492 	if (n_images > 0 && priv->image) {
493 		pos = eog_list_store_get_pos_by_image (EOG_LIST_STORE (priv->store),
494 						       priv->image);
495 	}
496 	/* Images: (image pos) / (n_total_images) */
497 	eog_statusbar_set_image_number (EOG_STATUSBAR (priv->statusbar),
498 					pos + 1,
499 					n_images);
500 
501 	action = g_action_map_lookup_action (G_ACTION_MAP (window),
502 	                                     "current-image");
503 
504 	g_return_if_fail (action != NULL);
505 	g_simple_action_set_state (G_SIMPLE_ACTION (action),
506 	                           g_variant_new ("(ii)", pos + 1, n_images));
507 
508 }
509 
510 static void
update_status_bar(EogWindow * window)511 update_status_bar (EogWindow *window)
512 {
513 	EogWindowPrivate *priv;
514 	char *str = NULL;
515 
516 	g_return_if_fail (EOG_IS_WINDOW (window));
517 
518 	eog_debug (DEBUG_WINDOW);
519 
520 	priv = window->priv;
521 
522 	if (priv->image != NULL) {
523 		if (eog_image_has_data (priv->image, EOG_IMAGE_DATA_DIMENSION)) {
524 			int zoom, width, height;
525 			goffset bytes = 0;
526 
527 			zoom = floor (100 * eog_scroll_view_get_zoom (EOG_SCROLL_VIEW (priv->view)) + 0.5);
528 
529 			eog_image_get_size (priv->image, &width, &height);
530 
531 			bytes = eog_image_get_bytes (priv->image);
532 
533 			if ((width > 0) && (height > 0)) {
534 				gchar *size_string;
535 
536 				size_string = g_format_size (bytes);
537 
538 				/* Translators: This is the string displayed in the statusbar
539 				 * The tokens are from left to right:
540 				 * - image width
541 				 * - image height
542 				 * - image size in bytes
543 				 * - zoom in percent */
544 				str = g_strdup_printf (ngettext("%i × %i pixel  %s    %i%%",
545 								"%i × %i pixels  %s    %i%%", height),
546 							width,
547 							height,
548 							size_string,
549 							zoom);
550 
551 				g_free (size_string);
552 			}
553 		}
554 
555 		update_image_pos (window);
556 	}
557 
558 	gtk_statusbar_pop (GTK_STATUSBAR (priv->statusbar),
559 			   priv->image_info_message_cid);
560 
561 	gtk_statusbar_push (GTK_STATUSBAR (priv->statusbar),
562 			    priv->image_info_message_cid, str ? str : "");
563 
564 	g_free (str);
565 }
566 
567 static void
eog_window_set_message_area(EogWindow * window,GtkWidget * message_area)568 eog_window_set_message_area (EogWindow *window,
569 		             GtkWidget *message_area)
570 {
571 	if (window->priv->message_area == message_area)
572 		return;
573 
574 	if (window->priv->message_area != NULL)
575 		gtk_widget_destroy (window->priv->message_area);
576 
577 	window->priv->message_area = message_area;
578 
579 	if (message_area == NULL) return;
580 
581 	gtk_box_pack_start (GTK_BOX (window->priv->cbox),
582 			    window->priv->message_area,
583 			    FALSE,
584 			    FALSE,
585 			    0);
586 
587 	g_object_add_weak_pointer (G_OBJECT (window->priv->message_area),
588 				   (void *) &window->priv->message_area);
589 }
590 
591 static void
_eog_window_enable_action_group(GActionMap * map,const gchar ** group,gboolean enable)592 _eog_window_enable_action_group (GActionMap   *map,
593 				 const gchar **group,
594 				 gboolean      enable)
595 {
596 	GAction *action;
597 	const gchar **it = group;
598 
599 	for (it = group; *it != NULL; it++) {
600 		action = g_action_map_lookup_action (map, *it);
601 		if (G_LIKELY (action))
602 			g_simple_action_set_enabled (G_SIMPLE_ACTION (action), enable);
603 		else
604 			g_warning ("Action not found in action group: %s", *it);
605 	}
606 }
607 
608 static void
_eog_window_enable_window_actions(EogWindow * window,gboolean enable)609 _eog_window_enable_window_actions (EogWindow *window, gboolean enable)
610 {
611 	static const gchar *window_actions[] = {
612 		"open",
613 		"close",
614 		"close-all",
615 		"preferences",
616 		"manual",
617 		"about",
618 		"view-gallery",
619 		"view-sidebar",
620 		"view-statusbar",
621 		"view-fullscreen",
622 		NULL
623 	};
624 
625 	_eog_window_enable_action_group (G_ACTION_MAP (window),
626 					 window_actions,
627 					 enable);
628 }
629 
630 static void
_eog_window_enable_image_actions(EogWindow * window,gboolean enable)631 _eog_window_enable_image_actions (EogWindow *window, gboolean enable)
632 {
633 	static const gchar *image_actions[] = {
634 		"save",
635 		"open-with",
636 		"save-as",
637 		"open-folder",
638 		"print",
639 		"properties",
640 		"undo",
641 		"flip-horizontal",
642 		"flip-vertical",
643 		"rotate-90",
644 		"rotate-270",
645 		"set-wallpaper",
646 		"move-trash",
647 		"delete",
648 		"copy",
649 		"zoom-in",
650 		"zoom-out",
651 		"zoom-normal",
652 		NULL
653 	};
654 
655 	_eog_window_enable_action_group (G_ACTION_MAP (window),
656 					 image_actions,
657 					 enable);
658 }
659 
660 static void
_eog_window_enable_gallery_actions(EogWindow * window,gboolean enable)661 _eog_window_enable_gallery_actions (EogWindow *window, gboolean enable)
662 {
663 
664 	static const gchar *gallery_actions[] = {
665 		"go-previous",
666 		"go-next",
667 		"go-first",
668 		"go-last",
669 		"go-random",
670 		NULL
671 	};
672 
673 	_eog_window_enable_action_group (G_ACTION_MAP (window),
674 					 gallery_actions,
675 					 enable);
676 }
677 
678 static void
update_action_groups_state(EogWindow * window)679 update_action_groups_state (EogWindow *window)
680 {
681 	EogWindowPrivate *priv;
682 	GAction *action_gallery;
683 	GAction *action_sidebar;
684 	GAction *action_fscreen;
685 	GAction *action_sshow;
686 	GAction *action_print;
687 	gboolean print_disabled = FALSE;
688 	gboolean show_image_gallery = FALSE;
689 	gint n_images = 0;
690 
691 	g_return_if_fail (EOG_IS_WINDOW (window));
692 
693 	eog_debug (DEBUG_WINDOW);
694 
695 	priv = window->priv;
696 
697 	action_gallery =
698 		g_action_map_lookup_action (G_ACTION_MAP (window),
699 					     "view-gallery");
700 
701 	action_sidebar =
702 		g_action_map_lookup_action (G_ACTION_MAP (window),
703 					     "view-sidebar");
704 
705 	action_fscreen =
706 		g_action_map_lookup_action (G_ACTION_MAP (window),
707 					     "view-fullscreen");
708 
709 	action_sshow =
710 		g_action_map_lookup_action (G_ACTION_MAP (window),
711 					     "view-slideshow");
712 
713 	action_print =
714 		g_action_map_lookup_action (G_ACTION_MAP (window),
715 					     "print");
716 
717 	g_assert (action_gallery != NULL);
718 	g_assert (action_sidebar != NULL);
719 	g_assert (action_fscreen != NULL);
720 	g_assert (action_sshow != NULL);
721 	g_assert (action_print != NULL);
722 
723 	if (priv->store != NULL) {
724 		n_images = eog_list_store_length (EOG_LIST_STORE (priv->store));
725 	}
726 
727 	if (priv->flags & EOG_STARTUP_DISABLE_GALLERY) {
728 		g_settings_set_boolean (priv->ui_settings,
729 					EOG_CONF_UI_IMAGE_GALLERY,
730 					FALSE);
731 
732 		show_image_gallery = FALSE;
733 	} else {
734 		show_image_gallery =
735 			g_settings_get_boolean (priv->ui_settings,
736 					EOG_CONF_UI_IMAGE_GALLERY);
737 	}
738 
739 	show_image_gallery &= n_images > 1 &&
740 			      priv->mode != EOG_WINDOW_MODE_SLIDESHOW;
741 
742 	gtk_widget_set_visible (priv->nav, show_image_gallery);
743 
744 	g_simple_action_set_state (G_SIMPLE_ACTION (action_gallery),
745 				   g_variant_new_boolean (show_image_gallery));
746 
747 	if (show_image_gallery)
748 		gtk_widget_grab_focus (priv->thumbview);
749 	else
750 		gtk_widget_grab_focus (priv->view);
751 
752 	if (n_images == 0) {
753 		_eog_window_enable_window_actions (window, TRUE);
754 		_eog_window_enable_image_actions (window, FALSE);
755 		_eog_window_enable_gallery_actions (window, FALSE);
756 
757 		g_simple_action_set_enabled (G_SIMPLE_ACTION (action_fscreen), FALSE);
758 		g_simple_action_set_enabled (G_SIMPLE_ACTION (action_sshow), FALSE);
759 
760 		/* If there are no images on model, initialization
761  		   stops here. */
762 		if (priv->status == EOG_WINDOW_STATUS_INIT) {
763 			priv->status = EOG_WINDOW_STATUS_NORMAL;
764 		}
765 	} else {
766 		_eog_window_enable_window_actions (window, TRUE);
767 		_eog_window_enable_image_actions (window, TRUE);
768 
769 		g_simple_action_set_enabled (G_SIMPLE_ACTION (action_fscreen), TRUE);
770 
771 		if (n_images == 1) {
772 			_eog_window_enable_gallery_actions (window, FALSE);
773 			g_simple_action_set_enabled (G_SIMPLE_ACTION (action_gallery), FALSE);
774 			g_simple_action_set_enabled (G_SIMPLE_ACTION (action_sshow), FALSE);
775 		} else {
776 			_eog_window_enable_gallery_actions (window, TRUE);
777 			g_simple_action_set_enabled (G_SIMPLE_ACTION (action_sshow), TRUE);
778 		}
779 	}
780 
781 	print_disabled = g_settings_get_boolean (priv->lockdown_settings,
782 						EOG_CONF_DESKTOP_CAN_PRINT);
783 
784 	if (print_disabled) {
785 		g_simple_action_set_enabled (G_SIMPLE_ACTION (action_print), FALSE);
786 	}
787 
788 	if (eog_sidebar_is_empty (EOG_SIDEBAR (priv->sidebar))) {
789 		g_simple_action_set_enabled (G_SIMPLE_ACTION (action_sidebar), FALSE);
790 		gtk_widget_hide (priv->sidebar);
791 	}
792 }
793 
794 static void
update_selection_ui_visibility(EogWindow * window)795 update_selection_ui_visibility (EogWindow *window)
796 {
797 	EogWindowPrivate *priv;
798 	GAction *wallpaper_action;
799 	gint n_selected;
800 
801 	priv = window->priv;
802 
803 	n_selected = eog_thumb_view_get_n_selected (EOG_THUMB_VIEW (priv->thumbview));
804 
805 	wallpaper_action =
806 		g_action_map_lookup_action (G_ACTION_MAP (window),
807 					     "set-wallpaper");
808 
809 	if (n_selected == 1) {
810 		g_simple_action_set_enabled (G_SIMPLE_ACTION (wallpaper_action), TRUE);
811 	} else {
812 		g_simple_action_set_enabled (G_SIMPLE_ACTION (wallpaper_action), FALSE);
813 	}
814 }
815 
816 static gboolean
add_file_to_recent_files(GFile * file)817 add_file_to_recent_files (GFile *file)
818 {
819 	gchar *text_uri;
820 	GFileInfo *file_info;
821 	GtkRecentData *recent_data;
822 	static gchar *groups[2] = { EOG_RECENT_FILES_GROUP , NULL };
823 
824 	if (file == NULL) return FALSE;
825 
826 	/* The password gets stripped here because ~/.recently-used.xbel is
827 	 * readable by everyone (chmod 644). It also makes the workaround
828 	 * for the bug with gtk_recent_info_get_uri_display() easier
829 	 * (see the comment in eog_window_update_recent_files_menu()). */
830 	text_uri = g_file_get_uri (file);
831 
832 	if (text_uri == NULL)
833 		return FALSE;
834 
835 	file_info = g_file_query_info (file,
836 	                               G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
837 	                               0, NULL, NULL);
838 	if (file_info == NULL)
839 		return FALSE;
840 
841 	recent_data = g_slice_new (GtkRecentData);
842 	recent_data->display_name = NULL;
843 	recent_data->description = NULL;
844 	recent_data->mime_type = (gchar *) g_file_info_get_content_type (file_info);
845 	recent_data->app_name = EOG_RECENT_FILES_APP_NAME;
846 	recent_data->app_exec = g_strjoin(" ", g_get_prgname (), "%u", NULL);
847 	recent_data->groups = groups;
848 	recent_data->is_private = FALSE;
849 
850 	gtk_recent_manager_add_full (gtk_recent_manager_get_default (),
851 	                             text_uri,
852 	                             recent_data);
853 
854 	g_free (recent_data->app_exec);
855 	g_free (text_uri);
856 	g_object_unref (file_info);
857 
858 	g_slice_free (GtkRecentData, recent_data);
859 
860 	return FALSE;
861 }
862 
863 static void
image_thumb_changed_cb(EogImage * image,gpointer data)864 image_thumb_changed_cb (EogImage *image, gpointer data)
865 {
866 	EogWindow *window;
867 	EogWindowPrivate *priv;
868 	GdkPixbuf *thumb;
869 
870 	g_return_if_fail (EOG_IS_WINDOW (data));
871 
872 	window = EOG_WINDOW (data);
873 	priv = window->priv;
874 
875 	thumb = eog_image_get_thumbnail (image);
876 
877 	if (thumb != NULL) {
878 		gtk_window_set_icon (GTK_WINDOW (window), thumb);
879 
880 		if (window->priv->properties_dlg != NULL) {
881 			eog_properties_dialog_update (EOG_PROPERTIES_DIALOG (priv->properties_dlg),
882 						      image);
883 		}
884 
885 		g_object_unref (thumb);
886 	} else if (!gtk_widget_get_visible (window->priv->nav)) {
887 		gint img_pos = eog_list_store_get_pos_by_image (window->priv->store, image);
888 		GtkTreePath *path = gtk_tree_path_new_from_indices (img_pos,-1);
889 		GtkTreeIter iter;
890 
891 		gtk_tree_model_get_iter (GTK_TREE_MODEL (window->priv->store), &iter, path);
892 		eog_list_store_thumbnail_set (window->priv->store, &iter);
893 		gtk_tree_path_free (path);
894 	}
895 }
896 
897 static void
file_changed_info_bar_response(GtkInfoBar * info_bar,gint response,EogWindow * window)898 file_changed_info_bar_response (GtkInfoBar *info_bar,
899 				gint response,
900 				EogWindow *window)
901 {
902 	if (response == GTK_RESPONSE_YES) {
903 		eog_window_reload_image (window);
904 	}
905 
906 	window->priv->needs_reload_confirmation = TRUE;
907 
908 	eog_window_set_message_area (window, NULL);
909 }
910 static void
image_file_changed_cb(EogImage * img,EogWindow * window)911 image_file_changed_cb (EogImage *img, EogWindow *window)
912 {
913 	GtkWidget *info_bar;
914 	gchar *text, *markup;
915 	GtkWidget *image;
916 	GtkWidget *label;
917 	GtkWidget *hbox;
918 
919 	if (window->priv->needs_reload_confirmation == FALSE)
920 		return;
921 
922 	if (!eog_image_is_modified (img)) {
923 		/* Auto-reload when image is unmodified (bug #555370) */
924 		eog_window_reload_image (window);
925 		return;
926 	}
927 
928 	window->priv->needs_reload_confirmation = FALSE;
929 
930 	info_bar = gtk_info_bar_new_with_buttons (_("_Reload"),
931 						  GTK_RESPONSE_YES,
932 						  C_("MessageArea", "Hi_de"),
933 						  GTK_RESPONSE_NO, NULL);
934 	gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar),
935 				       GTK_MESSAGE_QUESTION);
936 	image = gtk_image_new_from_icon_name ("dialog-question",
937 					      GTK_ICON_SIZE_DIALOG);
938 	label = gtk_label_new (NULL);
939 
940 	text = g_strdup_printf (_("The image “%s” has been modified by an external application."
941 				  " Would you like to reload it?"), eog_image_get_caption (img));
942 	markup = g_markup_printf_escaped ("<b>%s</b>", text);
943 	gtk_label_set_markup (GTK_LABEL (label), markup);
944 	gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
945 	g_free (text);
946 	g_free (markup);
947 
948 	hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
949 	gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
950 	gtk_widget_set_valign (image, GTK_ALIGN_START);
951 	gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
952 	gtk_widget_set_halign (label, GTK_ALIGN_START);
953 	gtk_box_pack_start (GTK_BOX (gtk_info_bar_get_content_area (GTK_INFO_BAR (info_bar))), hbox, TRUE, TRUE, 0);
954 	gtk_widget_show_all (hbox);
955 	gtk_widget_show (info_bar);
956 
957 	eog_window_set_message_area (window, info_bar);
958 	g_signal_connect (info_bar, "response",
959 			  G_CALLBACK (file_changed_info_bar_response), window);
960 }
961 
962 static void
eog_window_display_image(EogWindow * window,EogImage * image)963 eog_window_display_image (EogWindow *window, EogImage *image)
964 {
965 	EogWindowPrivate *priv;
966 	GFile *file;
967 
968 	g_return_if_fail (EOG_IS_WINDOW (window));
969 	g_return_if_fail (EOG_IS_IMAGE (image));
970 
971 	eog_debug (DEBUG_WINDOW);
972 
973 	g_assert (eog_image_has_data (image, EOG_IMAGE_DATA_IMAGE));
974 
975 	priv = window->priv;
976 
977 	if (image != NULL) {
978 		g_signal_connect (image,
979 				  "thumbnail_changed",
980 				  G_CALLBACK (image_thumb_changed_cb),
981 				  window);
982 		g_signal_connect (image, "file-changed",
983 				  G_CALLBACK (image_file_changed_cb),
984 				  window);
985 
986 		image_thumb_changed_cb (image, window);
987 	}
988 
989 	priv->needs_reload_confirmation = TRUE;
990 
991 	eog_scroll_view_set_image (EOG_SCROLL_VIEW (priv->view), image);
992 
993 	gtk_window_set_title (GTK_WINDOW (window), eog_image_get_caption (image));
994 
995 	update_status_bar (window);
996 
997 	file = eog_image_get_file (image);
998 	g_idle_add_full (G_PRIORITY_LOW,
999 			 (GSourceFunc) add_file_to_recent_files,
1000 			 file,
1001 			 (GDestroyNotify) g_object_unref);
1002 
1003 	if (eog_image_is_multipaged (image)) {
1004 		GtkWidget *info_bar;
1005 
1006 		eog_debug_message (DEBUG_IMAGE_DATA, "Image is multipaged");
1007 
1008 		info_bar = eog_multipage_error_message_area_new ();
1009 		g_signal_connect (info_bar,
1010 				  "response",
1011 				  G_CALLBACK (eog_window_error_message_area_response),
1012 				  window);
1013 		gtk_widget_show (info_bar);
1014 		eog_window_set_message_area (window, info_bar);
1015 	}
1016 
1017 	if (window->priv->mode == EOG_WINDOW_MODE_SLIDESHOW) {
1018 		slideshow_set_timeout (window);
1019 	}
1020 }
1021 
1022 static void
_eog_window_launch_appinfo_with_files(EogWindow * window,GAppInfo * appinfo,GList * files)1023 _eog_window_launch_appinfo_with_files (EogWindow *window,
1024 				       GAppInfo *appinfo,
1025 				       GList *files)
1026 {
1027 	GdkAppLaunchContext *context;
1028 
1029 	context = gdk_display_get_app_launch_context (
1030 	  gtk_widget_get_display (GTK_WIDGET (window)));
1031 	gdk_app_launch_context_set_screen (context,
1032 	  gtk_widget_get_screen (GTK_WIDGET (window)));
1033 	gdk_app_launch_context_set_icon (context,
1034 	  g_app_info_get_icon (appinfo));
1035 	gdk_app_launch_context_set_timestamp (context,
1036 	  gtk_get_current_event_time ());
1037 
1038 	g_app_info_launch (appinfo, files, G_APP_LAUNCH_CONTEXT (context), NULL);
1039 
1040 	g_object_unref (context);
1041 }
1042 
1043 static void
app_chooser_dialog_response_cb(GtkDialog * dialog,gint response_id,gpointer data)1044 app_chooser_dialog_response_cb (GtkDialog *dialog,
1045                                 gint response_id,
1046                                 gpointer data)
1047 {
1048 	EogWindow *window;
1049 	GAppInfo *app;
1050 	GFile *file;
1051 	GList *files = NULL;
1052 
1053 	g_return_if_fail (EOG_IS_WINDOW (data));
1054 
1055 	window = EOG_WINDOW (data);
1056 
1057 	if (response_id != GTK_RESPONSE_OK) {
1058 		goto out;
1059 	}
1060 
1061 	app = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (dialog));
1062 	file = eog_image_get_file (window->priv->image);
1063 	files = g_list_append (files, file);
1064 
1065 	_eog_window_launch_appinfo_with_files (window, app, files);
1066 
1067 	g_list_free (files);
1068 	g_object_unref (file);
1069 out:
1070 	gtk_widget_destroy (GTK_WIDGET (dialog));
1071 }
1072 
1073 static void
eog_window_open_file_chooser_dialog(EogWindow * window)1074 eog_window_open_file_chooser_dialog (EogWindow *window)
1075 {
1076 	GtkWidget *dialog;
1077 	GFileInfo *file_info;
1078 	GFile *file;
1079 	const gchar *mime_type = NULL;
1080 
1081 	file = eog_image_get_file (window->priv->image);
1082 	file_info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, 0, NULL, NULL);
1083 	mime_type = g_content_type_get_mime_type (
1084 			g_file_info_get_content_type (file_info));
1085 	g_object_unref (file_info);
1086 
1087 	dialog = gtk_app_chooser_dialog_new_for_content_type (GTK_WINDOW (window),
1088 							      GTK_DIALOG_MODAL |
1089 							      GTK_DIALOG_DESTROY_WITH_PARENT |
1090 							      GTK_DIALOG_USE_HEADER_BAR,
1091 							      mime_type);
1092 	gtk_widget_show (dialog);
1093 
1094 	g_signal_connect_object (dialog, "response",
1095 				 G_CALLBACK (app_chooser_dialog_response_cb),
1096 				 window, 0);
1097 
1098 	g_object_unref (file);
1099 }
1100 
1101 static void
eog_window_action_open_with(GSimpleAction * action,GVariant * parameter,gpointer user_data)1102 eog_window_action_open_with (GSimpleAction *action,
1103                             GVariant       *parameter,
1104                             gpointer        user_data)
1105 {
1106 	EogWindow *window;
1107 
1108 	g_return_if_fail (EOG_IS_WINDOW (user_data));
1109 	window = EOG_WINDOW (user_data);
1110 
1111 #ifdef HAVE_LIBPORTAL
1112 	if (eog_util_is_running_inside_flatpak ()) {
1113 		GFile *file = eog_image_get_file (window->priv->image);
1114 
1115 		eog_util_open_file_with_flatpak_portal (file, GTK_WINDOW (window));
1116 		g_object_unref (file);
1117 
1118 		return;
1119 	}
1120 #endif
1121 	eog_window_open_file_chooser_dialog (window);
1122 }
1123 
1124 static void
eog_window_clear_load_job(EogWindow * window)1125 eog_window_clear_load_job (EogWindow *window)
1126 {
1127 	EogWindowPrivate *priv = window->priv;
1128 
1129 	if (priv->load_job != NULL) {
1130 		if (!priv->load_job->finished)
1131 			eog_job_cancel (priv->load_job);
1132 
1133 		g_signal_handlers_disconnect_by_func (priv->load_job,
1134 						      eog_job_progress_cb,
1135 						      window);
1136 
1137 		g_signal_handlers_disconnect_by_func (priv->load_job,
1138 						      eog_job_load_cb,
1139 						      window);
1140 
1141 		eog_image_cancel_load (EOG_JOB_LOAD (priv->load_job)->image);
1142 
1143 		g_object_unref (priv->load_job);
1144 		priv->load_job = NULL;
1145 
1146 		/* Hide statusbar */
1147 		eog_statusbar_set_progress (EOG_STATUSBAR (priv->statusbar), 0);
1148 	}
1149 }
1150 
1151 static void
eog_job_progress_cb(EogJobLoad * job,float progress,gpointer user_data)1152 eog_job_progress_cb (EogJobLoad *job, float progress, gpointer user_data)
1153 {
1154 	EogWindow *window;
1155 
1156 	g_return_if_fail (EOG_IS_WINDOW (user_data));
1157 
1158 	window = EOG_WINDOW (user_data);
1159 
1160 	eog_statusbar_set_progress (EOG_STATUSBAR (window->priv->statusbar),
1161 				    progress);
1162 }
1163 
1164 static void
eog_job_save_progress_cb(EogJobSave * job,float progress,gpointer user_data)1165 eog_job_save_progress_cb (EogJobSave *job, float progress, gpointer user_data)
1166 {
1167 	EogWindowPrivate *priv;
1168 	EogWindow *window;
1169 
1170 	static EogImage *image = NULL;
1171 
1172 	g_return_if_fail (EOG_IS_WINDOW (user_data));
1173 
1174 	window = EOG_WINDOW (user_data);
1175 	priv = window->priv;
1176 
1177 	eog_statusbar_set_progress (EOG_STATUSBAR (priv->statusbar),
1178 				    progress);
1179 
1180 	if (image != job->current_image) {
1181 		gchar *str_image, *status_message;
1182 		guint n_images;
1183 
1184 		image = job->current_image;
1185 
1186 		n_images = g_list_length (job->images);
1187 
1188 		str_image = eog_image_get_uri_for_display (image);
1189 
1190 		/* Translators: This string is displayed in the statusbar
1191 		 * while saving images. The tokens are from left to right:
1192 		 * - the original filename
1193 		 * - the current image's position in the queue
1194 		 * - the total number of images queued for saving */
1195 		status_message = g_strdup_printf (_("Saving image “%s” (%u/%u)"),
1196 					          str_image,
1197 						  job->current_position + 1,
1198 						  n_images);
1199 		g_free (str_image);
1200 
1201 		gtk_statusbar_pop (GTK_STATUSBAR (priv->statusbar),
1202 				   priv->image_info_message_cid);
1203 
1204 		gtk_statusbar_push (GTK_STATUSBAR (priv->statusbar),
1205 				    priv->image_info_message_cid,
1206 				    status_message);
1207 
1208 		g_free (status_message);
1209 	}
1210 
1211 	if (progress == 1.0)
1212 		image = NULL;
1213 }
1214 
1215 static void
eog_window_obtain_desired_size(EogImage * image,gint width,gint height,EogWindow * window)1216 eog_window_obtain_desired_size (EogImage  *image,
1217 				gint       width,
1218 				gint       height,
1219 				EogWindow *window)
1220 {
1221 	GdkMonitor *monitor;
1222 	GdkRectangle monitor_rect;
1223 	GtkAllocation allocation;
1224 	gint final_width, final_height;
1225 	gint screen_width, screen_height;
1226 	gint window_width, window_height;
1227 	gint img_width, img_height;
1228 	gint view_width, view_height;
1229 	gint deco_width, deco_height;
1230 
1231 	update_action_groups_state (window);
1232 
1233 	img_width = width;
1234 	img_height = height;
1235 
1236 	if (!gtk_widget_get_realized (window->priv->view)) {
1237 		gtk_widget_realize (window->priv->view);
1238 	}
1239 
1240 	eog_debug_message (DEBUG_WINDOW, "Initial Image Size: %d x %d", img_width, img_height);
1241 
1242 	gtk_widget_get_allocation (window->priv->view, &allocation);
1243 	view_width  = allocation.width;
1244 	view_height = allocation.height;
1245 
1246 	eog_debug_message (DEBUG_WINDOW, "Initial View Size: %d x %d", view_width, view_height);
1247 
1248 
1249 	if (!gtk_widget_get_realized (GTK_WIDGET (window))) {
1250 		gtk_widget_realize (GTK_WIDGET (window));
1251 	}
1252 
1253 	gtk_widget_get_allocation (GTK_WIDGET (window), &allocation);
1254 	window_width  = allocation.width;
1255 	window_height = allocation.height;
1256 
1257 	eog_debug_message (DEBUG_WINDOW, "Initial Window Size: %d x %d", window_width, window_height);
1258 
1259 
1260 	monitor = gdk_display_get_monitor_at_window (
1261 				gtk_widget_get_display (GTK_WIDGET (window)),
1262 				gtk_widget_get_window (GTK_WIDGET (window)));
1263 
1264 	gdk_monitor_get_geometry (monitor, &monitor_rect);
1265 
1266 	screen_width  = monitor_rect.width;
1267 	screen_height = monitor_rect.height;
1268 
1269 	eog_debug_message (DEBUG_WINDOW, "Screen Size: %d x %d", screen_width, screen_height);
1270 
1271 	deco_width = window_width - view_width;
1272 	deco_height = window_height - view_height;
1273 
1274 	eog_debug_message (DEBUG_WINDOW, "Decoration Size: %d x %d", deco_width, deco_height);
1275 
1276 	if (img_width > 0 && img_height > 0) {
1277 		if ((img_width + deco_width > screen_width) ||
1278 		    (img_height + deco_height > screen_height))
1279 		{
1280 			double width_factor, height_factor, factor;
1281 
1282 			width_factor = (screen_width * 0.85 - deco_width) / (double) img_width;
1283 			height_factor = (screen_height * 0.85 - deco_height) / (double) img_height;
1284 			factor = MIN (width_factor, height_factor);
1285 
1286 			eog_debug_message (DEBUG_WINDOW, "Scaling Factor: %.2lf", factor);
1287 
1288 
1289 			img_width = img_width * factor;
1290 			img_height = img_height * factor;
1291 		}
1292 	}
1293 
1294 	final_width = MAX (EOG_WINDOW_MIN_WIDTH, img_width + deco_width);
1295 	final_height = MAX (EOG_WINDOW_MIN_HEIGHT, img_height + deco_height);
1296 
1297 	eog_debug_message (DEBUG_WINDOW, "Setting window size: %d x %d", final_width, final_height);
1298 
1299 	gtk_window_set_default_size (GTK_WINDOW (window), final_width, final_height);
1300 
1301 	g_signal_emit (window, signals[SIGNAL_PREPARED], 0);
1302 }
1303 
1304 static void
eog_window_error_message_area_response(GtkInfoBar * message_area,gint response_id,EogWindow * window)1305 eog_window_error_message_area_response (GtkInfoBar       *message_area,
1306 					gint              response_id,
1307 					EogWindow        *window)
1308 {
1309 	GAction *action_save_as;
1310 
1311 	g_return_if_fail (GTK_IS_INFO_BAR (message_area));
1312 	g_return_if_fail (EOG_IS_WINDOW (window));
1313 
1314 	/* remove message area */
1315 	eog_window_set_message_area (window, NULL);
1316 
1317 	/* evaluate message area response */
1318 	switch (response_id) {
1319 	case EOG_ERROR_MESSAGE_AREA_RESPONSE_NONE:
1320 	case EOG_ERROR_MESSAGE_AREA_RESPONSE_CANCEL:
1321 	case GTK_RESPONSE_CLOSE:
1322 		/* nothing to do in this case */
1323 		break;
1324 	case EOG_ERROR_MESSAGE_AREA_RESPONSE_RELOAD:
1325 		/* TODO: trigger loading for current image again */
1326 		break;
1327 	case EOG_ERROR_MESSAGE_AREA_RESPONSE_SAVEAS:
1328 		/* trigger save as command for current image */
1329 		action_save_as =
1330 			g_action_map_lookup_action (G_ACTION_MAP (window),
1331 							      "save-as");
1332 		eog_window_action_save_as (G_SIMPLE_ACTION (action_save_as), NULL, window);
1333 		break;
1334 	case EOG_ERROR_MESSAGE_AREA_RESPONSE_OPEN_WITH_EVINCE:
1335 	{
1336 		GDesktopAppInfo *app_info;
1337 		GFile *img_file;
1338 		GList *img_files = NULL;
1339 
1340 		app_info = g_desktop_app_info_new ("evince.desktop");
1341 
1342 		if (app_info) {
1343 			img_file = eog_image_get_file (window->priv->image);
1344 			if (img_file) {
1345 				img_files = g_list_append (img_files, img_file);
1346 			}
1347 			_eog_window_launch_appinfo_with_files (window,
1348 							       G_APP_INFO (app_info),
1349 							       img_files);
1350 			g_list_free_full (img_files, g_object_unref);
1351 		}
1352 	}
1353 		break;
1354 	}
1355 }
1356 
1357 static void
eog_job_load_cb(EogJobLoad * job,gpointer data)1358 eog_job_load_cb (EogJobLoad *job, gpointer data)
1359 {
1360 	EogWindow *window;
1361 	EogWindowPrivate *priv;
1362 	GAction *action_undo, *action_save;
1363 
1364         g_return_if_fail (EOG_IS_WINDOW (data));
1365 
1366 	eog_debug (DEBUG_WINDOW);
1367 
1368 	window = EOG_WINDOW (data);
1369 	priv = window->priv;
1370 
1371 	eog_statusbar_set_progress (EOG_STATUSBAR (priv->statusbar), 0.0);
1372 
1373 	gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar),
1374 			   priv->image_info_message_cid);
1375 
1376 	if (priv->image != NULL) {
1377 		g_signal_handlers_disconnect_by_func (priv->image,
1378 						      image_thumb_changed_cb,
1379 						      window);
1380 		g_signal_handlers_disconnect_by_func (priv->image,
1381 						      image_file_changed_cb,
1382 						      window);
1383 
1384 		g_object_unref (priv->image);
1385 	}
1386 
1387 	priv->image = g_object_ref (job->image);
1388 
1389 	if (EOG_JOB (job)->error == NULL) {
1390 #ifdef HAVE_LCMS
1391 		eog_image_apply_display_profile (job->image,
1392 						 priv->display_profile);
1393 #endif
1394 
1395 		_eog_window_enable_image_actions (window, TRUE);
1396 
1397 		/* Make sure the window is really realized
1398 		 *  before displaying the image. The ScrollView needs that.  */
1399         	if (!gtk_widget_get_realized (GTK_WIDGET (window))) {
1400 			gint width = -1, height = -1;
1401 
1402 			eog_image_get_size (job->image, &width, &height);
1403 			eog_window_obtain_desired_size (job->image, width,
1404 			                                height, window);
1405 
1406 		}
1407 
1408 		eog_window_display_image (window, job->image);
1409 	} else {
1410 		GtkWidget *message_area;
1411 
1412 		message_area = eog_image_load_error_message_area_new (
1413 					eog_image_get_caption (job->image),
1414 					EOG_JOB (job)->error);
1415 
1416 		g_signal_connect (message_area,
1417 				  "response",
1418 				  G_CALLBACK (eog_window_error_message_area_response),
1419 				  window);
1420 
1421 		gtk_window_set_icon (GTK_WINDOW (window), NULL);
1422 		gtk_window_set_title (GTK_WINDOW (window),
1423 				      eog_image_get_caption (job->image));
1424 
1425 		eog_window_set_message_area (window, message_area);
1426 
1427 		gtk_info_bar_set_default_response (GTK_INFO_BAR (message_area),
1428 						   GTK_RESPONSE_CANCEL);
1429 
1430 		gtk_widget_show (message_area);
1431 
1432 		update_status_bar (window);
1433 
1434 		eog_scroll_view_set_image (EOG_SCROLL_VIEW (priv->view), NULL);
1435 
1436         	if (window->priv->status == EOG_WINDOW_STATUS_INIT) {
1437 			update_action_groups_state (window);
1438 
1439 			g_signal_emit (window, signals[SIGNAL_PREPARED], 0);
1440 		}
1441 
1442 		_eog_window_enable_image_actions (window, FALSE);
1443 	}
1444 
1445 	eog_window_clear_load_job (window);
1446 
1447         if (window->priv->status == EOG_WINDOW_STATUS_INIT) {
1448 		window->priv->status = EOG_WINDOW_STATUS_NORMAL;
1449 
1450 		g_signal_handlers_disconnect_by_func
1451 			(job->image,
1452 			 G_CALLBACK (eog_window_obtain_desired_size),
1453 			 window);
1454 	}
1455 
1456 	action_save = g_action_map_lookup_action (G_ACTION_MAP (window),
1457 											  "save");
1458 	action_undo = g_action_map_lookup_action (G_ACTION_MAP (window),
1459 											  "undo");
1460 
1461 	/* Set Save and Undo sensitive according to image state.
1462 	 * Respect lockdown in case of Save.*/
1463 	g_simple_action_set_enabled (G_SIMPLE_ACTION (action_save),
1464 			(!priv->save_disabled && eog_image_is_modified (job->image)));
1465 	g_simple_action_set_enabled (G_SIMPLE_ACTION (action_undo),
1466 			eog_image_is_modified (job->image));
1467 
1468 	g_object_unref (job->image);
1469 }
1470 
1471 static void
eog_window_clear_transform_job(EogWindow * window)1472 eog_window_clear_transform_job (EogWindow *window)
1473 {
1474 	EogWindowPrivate *priv = window->priv;
1475 
1476 	if (priv->transform_job != NULL) {
1477 		if (!priv->transform_job->finished)
1478 			eog_job_cancel (priv->transform_job);
1479 
1480 		g_signal_handlers_disconnect_by_func (priv->transform_job,
1481 						      eog_job_transform_cb,
1482 						      window);
1483 		g_object_unref (priv->transform_job);
1484 		priv->transform_job = NULL;
1485 	}
1486 }
1487 
1488 static void
eog_job_transform_cb(EogJobTransform * job,gpointer data)1489 eog_job_transform_cb (EogJobTransform *job, gpointer data)
1490 {
1491 	EogWindow *window;
1492 	GAction *action_undo, *action_save;
1493 	EogImage *image;
1494 
1495         g_return_if_fail (EOG_IS_WINDOW (data));
1496 
1497 	window = EOG_WINDOW (data);
1498 
1499 	eog_window_clear_transform_job (window);
1500 
1501 	action_undo =
1502 		g_action_map_lookup_action (G_ACTION_MAP (window),
1503 									"undo");
1504 	action_save =
1505 		g_action_map_lookup_action (G_ACTION_MAP (window),
1506 									"save");
1507 
1508 	image = eog_window_get_image (window);
1509 
1510 	g_simple_action_set_enabled (G_SIMPLE_ACTION (action_undo),
1511 								 eog_image_is_modified (image));
1512 
1513 	if (!window->priv->save_disabled)
1514 	{
1515 		g_simple_action_set_enabled (G_SIMPLE_ACTION (action_save),
1516 									 eog_image_is_modified (image));
1517 	}
1518 }
1519 
1520 static void
apply_transformation(EogWindow * window,EogTransform * trans)1521 apply_transformation (EogWindow *window, EogTransform *trans)
1522 {
1523 	EogWindowPrivate *priv;
1524 	GList *images;
1525 
1526 	g_return_if_fail (EOG_IS_WINDOW (window));
1527 
1528 	priv = window->priv;
1529 
1530 	images = eog_thumb_view_get_selected_images (EOG_THUMB_VIEW (priv->thumbview));
1531 
1532 	eog_window_clear_transform_job (window);
1533 
1534 	priv->transform_job = eog_job_transform_new (images, trans);
1535 
1536 	g_signal_connect (priv->transform_job,
1537 			  "finished",
1538 			  G_CALLBACK (eog_job_transform_cb),
1539 			  window);
1540 
1541 	g_signal_connect (priv->transform_job,
1542 			  "progress",
1543 			  G_CALLBACK (eog_job_progress_cb),
1544 			  window);
1545 
1546 	eog_job_scheduler_add_job (priv->transform_job);
1547 }
1548 
1549 static void
handle_image_selection_changed_cb(EogThumbView * thumbview,EogWindow * window)1550 handle_image_selection_changed_cb (EogThumbView *thumbview, EogWindow *window)
1551 {
1552 	EogWindowPrivate *priv;
1553 	EogImage *image;
1554 	gchar *status_message;
1555 	gchar *str_image;
1556 
1557 	priv = window->priv;
1558 
1559 	if (eog_list_store_length (EOG_LIST_STORE (priv->store)) == 0) {
1560 		gtk_window_set_title (GTK_WINDOW (window),
1561 				      g_get_application_name());
1562 		gtk_statusbar_remove_all (GTK_STATUSBAR (priv->statusbar),
1563 					  priv->image_info_message_cid);
1564 		eog_scroll_view_set_image (EOG_SCROLL_VIEW (priv->view),
1565 					   NULL);
1566 	}
1567 	if (eog_thumb_view_get_n_selected (EOG_THUMB_VIEW (priv->thumbview)) == 0)
1568 		return;
1569 
1570 	update_selection_ui_visibility (window);
1571 
1572 	image = eog_thumb_view_get_first_selected_image (EOG_THUMB_VIEW (priv->thumbview));
1573 
1574 	g_assert (EOG_IS_IMAGE (image));
1575 
1576 	eog_window_clear_load_job (window);
1577 
1578 	eog_window_set_message_area (window, NULL);
1579 
1580 	gtk_statusbar_pop (GTK_STATUSBAR (priv->statusbar),
1581 			   priv->image_info_message_cid);
1582 
1583 	if (image == priv->image) {
1584 		update_status_bar (window);
1585 		return;
1586 	}
1587 
1588 	if (eog_image_has_data (image, EOG_IMAGE_DATA_IMAGE)) {
1589 		if (priv->image != NULL)
1590 			g_object_unref (priv->image);
1591 		priv->image = image;
1592 		eog_window_display_image (window, image);
1593 		return;
1594 	}
1595 
1596 	if (priv->status == EOG_WINDOW_STATUS_INIT) {
1597 		g_signal_connect (image,
1598 				  "size-prepared",
1599 				  G_CALLBACK (eog_window_obtain_desired_size),
1600 				  window);
1601 	}
1602 
1603 	priv->load_job = eog_job_load_new (image, EOG_IMAGE_DATA_ALL);
1604 
1605 	g_signal_connect (priv->load_job,
1606 			  "finished",
1607 			  G_CALLBACK (eog_job_load_cb),
1608 			  window);
1609 
1610 	g_signal_connect (priv->load_job,
1611 			  "progress",
1612 			  G_CALLBACK (eog_job_progress_cb),
1613 			  window);
1614 
1615 	eog_job_scheduler_add_job (priv->load_job);
1616 
1617 	str_image = eog_image_get_uri_for_display (image);
1618 
1619 	status_message = g_strdup_printf (_("Opening image “%s”"),
1620 				          str_image);
1621 
1622 	g_free (str_image);
1623 
1624 	gtk_statusbar_push (GTK_STATUSBAR (priv->statusbar),
1625 			    priv->image_info_message_cid, status_message);
1626 
1627 	g_free (status_message);
1628 }
1629 
1630 static void
view_zoom_changed_cb(GtkWidget * widget,double zoom,gpointer user_data)1631 view_zoom_changed_cb (GtkWidget *widget, double zoom, gpointer user_data)
1632 {
1633 	EogWindow *window;
1634 	GAction *action_zoom_in;
1635 	GAction *action_zoom_out;
1636 
1637 	g_return_if_fail (EOG_IS_WINDOW (user_data));
1638 
1639 	window = EOG_WINDOW (user_data);
1640 
1641 	update_status_bar (window);
1642 
1643 	action_zoom_in =
1644 		g_action_map_lookup_action (G_ACTION_MAP (window),
1645 					     "zoom-in");
1646 
1647 	action_zoom_out =
1648 		g_action_map_lookup_action (G_ACTION_MAP (window),
1649 					     "zoom-out");
1650 
1651 	g_simple_action_set_enabled (G_SIMPLE_ACTION (action_zoom_in),
1652 			!eog_scroll_view_get_zoom_is_max (EOG_SCROLL_VIEW (window->priv->view)));
1653 	g_simple_action_set_enabled (G_SIMPLE_ACTION (action_zoom_out),
1654 			!eog_scroll_view_get_zoom_is_min (EOG_SCROLL_VIEW (window->priv->view)));
1655 }
1656 
1657 static void
file_open_dialog_response_cb(GtkWidget * chooser,gint response_id,EogWindow * ev_window)1658 file_open_dialog_response_cb (GtkWidget *chooser,
1659 			      gint       response_id,
1660 			      EogWindow  *ev_window)
1661 {
1662 	if (response_id == GTK_RESPONSE_OK) {
1663 		GSList *uris;
1664 
1665 		uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (chooser));
1666 
1667 		eog_application_open_uri_list (EOG_APP,
1668 					       uris,
1669 					       GDK_CURRENT_TIME,
1670 					       0,
1671 					       NULL);
1672 
1673 		g_slist_foreach (uris, (GFunc) g_free, NULL);
1674 		g_slist_free (uris);
1675 	}
1676 
1677 	gtk_widget_destroy (chooser);
1678 }
1679 
1680 static void
eog_window_update_fullscreen_action(EogWindow * window)1681 eog_window_update_fullscreen_action (EogWindow *window)
1682 {
1683 	GAction *action;
1684 
1685 	action = g_action_map_lookup_action (G_ACTION_MAP (window),
1686 					      "view-fullscreen");
1687 
1688 	g_simple_action_set_state (G_SIMPLE_ACTION (action),
1689 			g_variant_new_boolean (window->priv->mode == EOG_WINDOW_MODE_FULLSCREEN));
1690 }
1691 
1692 static void
eog_window_update_slideshow_action(EogWindow * window)1693 eog_window_update_slideshow_action (EogWindow *window)
1694 {
1695 	GAction *action;
1696 
1697 	action = g_action_map_lookup_action (G_ACTION_MAP (window),
1698 					      "view-slideshow");
1699 
1700 	g_simple_action_set_state (G_SIMPLE_ACTION (action),
1701 			g_variant_new_boolean (window->priv->mode == EOG_WINDOW_MODE_SLIDESHOW));
1702 }
1703 
1704 static void
eog_window_update_pause_slideshow_action(EogWindow * window)1705 eog_window_update_pause_slideshow_action (EogWindow *window)
1706 {
1707 	GAction *action;
1708 
1709 	action = g_action_map_lookup_action (G_ACTION_MAP (window),
1710 					      "pause-slideshow");
1711 
1712 	g_simple_action_set_state (G_SIMPLE_ACTION (action),
1713 			g_variant_new_boolean (window->priv->mode != EOG_WINDOW_MODE_SLIDESHOW));
1714 }
1715 
1716 static gboolean
fullscreen_timeout_cb(gpointer data)1717 fullscreen_timeout_cb (gpointer data)
1718 {
1719 	EogWindow *window = EOG_WINDOW (data);
1720 
1721 	eog_debug (DEBUG_WINDOW);
1722 
1723 	gtk_revealer_set_reveal_child (
1724 		    GTK_REVEALER (window->priv->fullscreen_popup), FALSE);
1725 	eog_scroll_view_hide_cursor (EOG_SCROLL_VIEW (window->priv->view));
1726 
1727 	fullscreen_clear_timeout (window);
1728 
1729 	return FALSE;
1730 }
1731 
1732 static gboolean
slideshow_is_loop_end(EogWindow * window)1733 slideshow_is_loop_end (EogWindow *window)
1734 {
1735 	EogWindowPrivate *priv = window->priv;
1736 	EogImage *image = NULL;
1737 	gint pos;
1738 
1739 	image = eog_thumb_view_get_first_selected_image (EOG_THUMB_VIEW (priv->thumbview));
1740 
1741 	pos = eog_list_store_get_pos_by_image (priv->store, image);
1742 
1743 	return (pos == (eog_list_store_length (priv->store) - 1));
1744 }
1745 
1746 static gboolean
slideshow_switch_cb(gpointer data)1747 slideshow_switch_cb (gpointer data)
1748 {
1749 	EogWindow *window = EOG_WINDOW (data);
1750 	EogWindowPrivate *priv = window->priv;
1751 
1752 	eog_debug (DEBUG_WINDOW);
1753 
1754 	if (!priv->slideshow_loop && slideshow_is_loop_end (window)) {
1755 		eog_window_stop_fullscreen (window, TRUE);
1756 		return G_SOURCE_REMOVE;
1757 	}
1758 
1759 	eog_thumb_view_select_single (EOG_THUMB_VIEW (priv->thumbview),
1760 				      EOG_THUMB_VIEW_SELECT_RIGHT);
1761 
1762 	return G_SOURCE_REMOVE;
1763 }
1764 
1765 static void
fullscreen_clear_timeout(EogWindow * window)1766 fullscreen_clear_timeout (EogWindow *window)
1767 {
1768 	eog_debug (DEBUG_WINDOW);
1769 
1770 	if (window->priv->fullscreen_timeout_source != NULL) {
1771 		g_source_destroy (window->priv->fullscreen_timeout_source);
1772 		g_source_unref (window->priv->fullscreen_timeout_source);
1773 	}
1774 
1775 	window->priv->fullscreen_timeout_source = NULL;
1776 }
1777 
1778 static void
fullscreen_set_timeout(EogWindow * window)1779 fullscreen_set_timeout (EogWindow *window)
1780 {
1781 	GSource *source;
1782 
1783 	eog_debug (DEBUG_WINDOW);
1784 
1785 	fullscreen_clear_timeout (window);
1786 
1787 	source = g_timeout_source_new (EOG_WINDOW_FULLSCREEN_TIMEOUT);
1788 	g_source_set_callback (source, fullscreen_timeout_cb, window, NULL);
1789 
1790 	g_source_attach (source, NULL);
1791 
1792 	window->priv->fullscreen_timeout_source = source;
1793 
1794 	eog_scroll_view_show_cursor (EOG_SCROLL_VIEW (window->priv->view));
1795 }
1796 
1797 static void
slideshow_clear_timeout(EogWindow * window)1798 slideshow_clear_timeout (EogWindow *window)
1799 {
1800 	eog_debug (DEBUG_WINDOW);
1801 
1802 	if (window->priv->slideshow_switch_source != NULL) {
1803 		g_source_destroy (window->priv->slideshow_switch_source);
1804 		g_source_unref (window->priv->slideshow_switch_source);
1805 	}
1806 
1807 	window->priv->slideshow_switch_source = NULL;
1808 }
1809 
1810 static void
slideshow_set_timeout(EogWindow * window)1811 slideshow_set_timeout (EogWindow *window)
1812 {
1813 	GSource *source;
1814 
1815 	eog_debug (DEBUG_WINDOW);
1816 
1817 	slideshow_clear_timeout (window);
1818 
1819 	if (window->priv->mode != EOG_WINDOW_MODE_SLIDESHOW)
1820 		return;
1821 
1822 	if (window->priv->slideshow_switch_timeout <= 0)
1823 		return;
1824 
1825 	source = g_timeout_source_new (window->priv->slideshow_switch_timeout * 1000);
1826 	g_source_set_callback (source, slideshow_switch_cb, window, NULL);
1827 
1828 	g_source_attach (source, NULL);
1829 
1830 	window->priv->slideshow_switch_source = source;
1831 }
1832 
1833 static void
show_fullscreen_popup(EogWindow * window)1834 show_fullscreen_popup (EogWindow *window)
1835 {
1836 	eog_debug (DEBUG_WINDOW);
1837 
1838 	if (!gtk_widget_get_visible (window->priv->fullscreen_popup)) {
1839 		gtk_widget_show_all (GTK_WIDGET (window->priv->fullscreen_popup));
1840 	}
1841 
1842 	gtk_revealer_set_reveal_child (
1843 		    GTK_REVEALER (window->priv->fullscreen_popup), TRUE);
1844 
1845 	fullscreen_set_timeout (window);
1846 }
1847 
1848 static gboolean
fullscreen_motion_notify_cb(GtkWidget * widget,GdkEventMotion * event,gpointer user_data)1849 fullscreen_motion_notify_cb (GtkWidget      *widget,
1850 			     GdkEventMotion *event,
1851 			     gpointer       user_data)
1852 {
1853 	EogWindow *window = EOG_WINDOW (user_data);
1854 
1855 	eog_debug (DEBUG_WINDOW);
1856 
1857 	if (event->y < EOG_WINDOW_FULLSCREEN_POPUP_THRESHOLD) {
1858 		show_fullscreen_popup (window);
1859 	} else {
1860 		fullscreen_set_timeout (window);
1861 	}
1862 
1863 	return FALSE;
1864 }
1865 
1866 static gboolean
fullscreen_leave_notify_cb(GtkWidget * widget,GdkEventCrossing * event,gpointer user_data)1867 fullscreen_leave_notify_cb (GtkWidget *widget,
1868 			    GdkEventCrossing *event,
1869 			    gpointer user_data)
1870 {
1871 	EogWindow *window = EOG_WINDOW (user_data);
1872 
1873 	eog_debug (DEBUG_WINDOW);
1874 
1875 	fullscreen_clear_timeout (window);
1876 
1877 	return FALSE;
1878 }
1879 
1880 static void
exit_fullscreen_button_clicked_cb(GtkWidget * button,EogWindow * window)1881 exit_fullscreen_button_clicked_cb (GtkWidget *button, EogWindow *window)
1882 {
1883 	GAction *action;
1884 
1885 	eog_debug (DEBUG_WINDOW);
1886 
1887 	if (window->priv->mode == EOG_WINDOW_MODE_SLIDESHOW) {
1888 		action = g_action_map_lookup_action (G_ACTION_MAP (window),
1889 						      "view-slideshow");
1890 	} else {
1891 		action = g_action_map_lookup_action (G_ACTION_MAP (window),
1892 						      "view-fullscreen");
1893 	}
1894 	g_return_if_fail (action != NULL);
1895 
1896 	g_action_change_state (action, g_variant_new_boolean (FALSE));
1897 }
1898 
1899 static GtkWidget *
eog_window_create_fullscreen_popup(EogWindow * window)1900 eog_window_create_fullscreen_popup (EogWindow *window)
1901 {
1902 	GtkWidget *revealer;
1903 	GtkWidget *hbox;
1904 	GtkWidget *button;
1905 	GtkWidget *toolbar;
1906 	GtkBuilder *builder;
1907 
1908 	eog_debug (DEBUG_WINDOW);
1909 
1910 	revealer = gtk_revealer_new();
1911 	gtk_widget_add_events (revealer, GDK_ENTER_NOTIFY_MASK);
1912 
1913 	hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1914 	gtk_widget_set_valign (revealer, GTK_ALIGN_START);
1915 	gtk_widget_set_halign (revealer, GTK_ALIGN_FILL);
1916 	gtk_container_add (GTK_CONTAINER (revealer), hbox);
1917 
1918 	builder = gtk_builder_new_from_resource ("/org/gnome/eog/ui/fullscreen-toolbar.ui");
1919 	toolbar = GTK_WIDGET (gtk_builder_get_object (builder, "fullscreen_toolbar"));
1920 	g_assert (GTK_IS_TOOLBAR (toolbar));
1921 
1922 	gtk_box_pack_start (GTK_BOX (hbox), toolbar, TRUE, TRUE, 0);
1923 
1924 	button = GTK_WIDGET (gtk_builder_get_object (builder, "exit_fullscreen_button"));
1925 	g_signal_connect (button, "clicked",
1926 			  G_CALLBACK (exit_fullscreen_button_clicked_cb),
1927 			  window);
1928 
1929 	/* Disable timer when the pointer enters the toolbar window. */
1930 	g_signal_connect (revealer,
1931 			  "enter-notify-event",
1932 			  G_CALLBACK (fullscreen_leave_notify_cb),
1933 			  window);
1934 
1935 	g_object_unref (builder);
1936 	return revealer;
1937 }
1938 
1939 static void
update_ui_visibility(EogWindow * window)1940 update_ui_visibility (EogWindow *window)
1941 {
1942 	EogWindowPrivate *priv;
1943 
1944 	GAction *action;
1945 
1946 	gboolean fullscreen_mode, visible;
1947 
1948 	g_return_if_fail (EOG_IS_WINDOW (window));
1949 
1950 	eog_debug (DEBUG_WINDOW);
1951 
1952 	priv = window->priv;
1953 
1954 	fullscreen_mode = priv->mode == EOG_WINDOW_MODE_FULLSCREEN ||
1955 			  priv->mode == EOG_WINDOW_MODE_SLIDESHOW;
1956 
1957 	visible = g_settings_get_boolean (priv->ui_settings,
1958 					  EOG_CONF_UI_STATUSBAR);
1959 	visible = visible && !fullscreen_mode;
1960 	action = g_action_map_lookup_action (G_ACTION_MAP (window), "view-statusbar");
1961 	g_assert (action != NULL);
1962 	g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_boolean (visible));
1963 	gtk_widget_set_visible (priv->statusbar, visible);
1964 
1965 	if (priv->status != EOG_WINDOW_STATUS_INIT) {
1966 		visible = g_settings_get_boolean (priv->ui_settings,
1967 						  EOG_CONF_UI_IMAGE_GALLERY);
1968 		visible &= gtk_widget_get_visible (priv->nav);
1969 		visible &= (priv->mode != EOG_WINDOW_MODE_SLIDESHOW);
1970 		action = g_action_map_lookup_action (G_ACTION_MAP (window), "view-gallery");
1971 		g_assert (action != NULL);
1972 		g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_boolean (visible));
1973 		gtk_widget_set_visible (priv->nav, visible);
1974 	}
1975 
1976 	visible = g_settings_get_boolean (priv->ui_settings,
1977 					  EOG_CONF_UI_SIDEBAR);
1978 	visible = visible && !fullscreen_mode;
1979 	action = g_action_map_lookup_action (G_ACTION_MAP (window), "view-sidebar");
1980 	g_assert (action != NULL);
1981 	g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_boolean (visible));
1982 	gtk_widget_set_visible (priv->sidebar, visible);
1983 
1984 	if (priv->fullscreen_popup != NULL) {
1985 		gtk_widget_hide (priv->fullscreen_popup);
1986 	}
1987 }
1988 
1989 static void
eog_window_inhibit_screensaver(EogWindow * window)1990 eog_window_inhibit_screensaver (EogWindow *window)
1991 {
1992 	EogWindowPrivate *priv = window->priv;
1993 
1994 	/* Already inhibited */
1995 	if (G_UNLIKELY (priv->fullscreen_idle_inhibit_cookie != 0))
1996 		return;
1997 
1998 	eog_debug (DEBUG_WINDOW);
1999 
2000 	window->priv->fullscreen_idle_inhibit_cookie =
2001 		gtk_application_inhibit (GTK_APPLICATION (EOG_APP),
2002 		                         GTK_WINDOW (window),
2003 		                         GTK_APPLICATION_INHIBIT_IDLE,
2004 	/* L10N: This the reason why the screensaver is inhibited. */
2005 		                         _("Viewing a slideshow"));
2006 }
2007 
2008 static void
eog_window_uninhibit_screensaver(EogWindow * window)2009 eog_window_uninhibit_screensaver (EogWindow *window)
2010 {
2011 	EogWindowPrivate *priv = window->priv;
2012 
2013 	if (G_UNLIKELY (priv->fullscreen_idle_inhibit_cookie == 0))
2014 		return;
2015 
2016 	eog_debug (DEBUG_WINDOW);
2017 
2018 	gtk_application_uninhibit (GTK_APPLICATION (EOG_APP),
2019 	                           priv->fullscreen_idle_inhibit_cookie);
2020 	priv->fullscreen_idle_inhibit_cookie = 0;
2021 }
2022 
2023 static void
eog_window_run_fullscreen(EogWindow * window,gboolean slideshow)2024 eog_window_run_fullscreen (EogWindow *window, gboolean slideshow)
2025 {
2026 	static const GdkRGBA black = { 0., 0., 0., 1.};
2027 	EogWindowPrivate *priv;
2028 	gboolean upscale;
2029 
2030 	eog_debug (DEBUG_WINDOW);
2031 
2032 	priv = window->priv;
2033 
2034 	if (slideshow) {
2035 		priv->mode = EOG_WINDOW_MODE_SLIDESHOW;
2036 	} else {
2037 		/* Stop the timer if we come from slideshowing */
2038 		if (priv->mode == EOG_WINDOW_MODE_SLIDESHOW) {
2039 			slideshow_clear_timeout (window);
2040 			eog_window_uninhibit_screensaver (window);
2041 		}
2042 
2043 		priv->mode = EOG_WINDOW_MODE_FULLSCREEN;
2044 	}
2045 
2046 	if (window->priv->fullscreen_popup == NULL)
2047 	{
2048 		priv->fullscreen_popup
2049 			= eog_window_create_fullscreen_popup (window);
2050 		gtk_overlay_add_overlay (GTK_OVERLAY(priv->overlay),
2051 					 priv->fullscreen_popup);
2052 	}
2053 
2054 	update_ui_visibility (window);
2055 
2056 	g_signal_connect (priv->view,
2057 			  "motion-notify-event",
2058 			  G_CALLBACK (fullscreen_motion_notify_cb),
2059 			  window);
2060 
2061 	g_signal_connect (priv->view,
2062 			  "leave-notify-event",
2063 			  G_CALLBACK (fullscreen_leave_notify_cb),
2064 			  window);
2065 
2066 	g_signal_connect (priv->thumbview,
2067 			  "motion-notify-event",
2068 			  G_CALLBACK (fullscreen_motion_notify_cb),
2069 			  window);
2070 
2071 	g_signal_connect (priv->thumbview,
2072 			  "leave-notify-event",
2073 			  G_CALLBACK (fullscreen_leave_notify_cb),
2074 			  window);
2075 
2076 	fullscreen_set_timeout (window);
2077 
2078 	if (slideshow) {
2079 		priv->slideshow_loop =
2080 			g_settings_get_boolean (priv->fullscreen_settings,
2081 						EOG_CONF_FULLSCREEN_LOOP);
2082 
2083 		priv->slideshow_switch_timeout =
2084 			g_settings_get_int (priv->fullscreen_settings,
2085 					    EOG_CONF_FULLSCREEN_SECONDS);
2086 
2087 		slideshow_set_timeout (window);
2088 	}
2089 
2090 	upscale = g_settings_get_boolean (priv->fullscreen_settings,
2091 					  EOG_CONF_FULLSCREEN_UPSCALE);
2092 
2093 	eog_scroll_view_set_zoom_upscale (EOG_SCROLL_VIEW (priv->view),
2094 					  upscale);
2095 
2096 	gtk_widget_grab_focus (priv->view);
2097 
2098 	eog_scroll_view_override_bg_color (EOG_SCROLL_VIEW (window->priv->view),
2099 					   &black);
2100 
2101 	gtk_window_fullscreen (GTK_WINDOW (window));
2102 
2103 	if (slideshow)
2104 		eog_window_inhibit_screensaver (window);
2105 
2106 	/* Update both actions as we could've already been in one those modes */
2107 	eog_window_update_slideshow_action (window);
2108 	eog_window_update_fullscreen_action (window);
2109 	eog_window_update_pause_slideshow_action (window);
2110 }
2111 
2112 static void
eog_window_stop_fullscreen(EogWindow * window,gboolean slideshow)2113 eog_window_stop_fullscreen (EogWindow *window, gboolean slideshow)
2114 {
2115 	EogWindowPrivate *priv;
2116 
2117 	eog_debug (DEBUG_WINDOW);
2118 
2119 	priv = window->priv;
2120 
2121 	if (priv->mode != EOG_WINDOW_MODE_SLIDESHOW &&
2122 	    priv->mode != EOG_WINDOW_MODE_FULLSCREEN) return;
2123 
2124 	priv->mode = EOG_WINDOW_MODE_NORMAL;
2125 
2126 	fullscreen_clear_timeout (window);
2127 	gtk_revealer_set_reveal_child (GTK_REVEALER(window->priv->fullscreen_popup), FALSE);
2128 
2129 	if (slideshow) {
2130 		slideshow_clear_timeout (window);
2131 	}
2132 
2133 	g_signal_handlers_disconnect_by_func (priv->view,
2134 					      (gpointer) fullscreen_motion_notify_cb,
2135 					      window);
2136 
2137 	g_signal_handlers_disconnect_by_func (priv->view,
2138 					      (gpointer) fullscreen_leave_notify_cb,
2139 					      window);
2140 
2141 	g_signal_handlers_disconnect_by_func (priv->thumbview,
2142 					      (gpointer) fullscreen_motion_notify_cb,
2143 					      window);
2144 
2145 	g_signal_handlers_disconnect_by_func (priv->thumbview,
2146 					      (gpointer) fullscreen_leave_notify_cb,
2147 					      window);
2148 
2149 	update_ui_visibility (window);
2150 
2151 	eog_scroll_view_set_zoom_upscale (EOG_SCROLL_VIEW (priv->view), FALSE);
2152 
2153 	eog_scroll_view_override_bg_color (EOG_SCROLL_VIEW (window->priv->view),
2154 					   NULL);
2155 	gtk_window_unfullscreen (GTK_WINDOW (window));
2156 
2157 	if (slideshow) {
2158 		eog_window_update_slideshow_action (window);
2159 		eog_window_uninhibit_screensaver (window);
2160 	} else {
2161 		eog_window_update_fullscreen_action (window);
2162 	}
2163 
2164 	eog_scroll_view_show_cursor (EOG_SCROLL_VIEW (priv->view));
2165 }
2166 
2167 static void
set_basename_for_print_settings(GtkPrintSettings * print_settings,EogWindow * window)2168 set_basename_for_print_settings (GtkPrintSettings *print_settings, EogWindow *window)
2169 {
2170 	const char *basename = NULL;
2171 
2172 	if(G_LIKELY (window->priv->image != NULL))
2173 		basename = eog_image_get_caption (window->priv->image);
2174 
2175 	if (G_LIKELY(basename))
2176 		gtk_print_settings_set (print_settings,
2177 		                        GTK_PRINT_SETTINGS_OUTPUT_BASENAME,
2178 		                        basename);
2179 }
2180 
2181 static void
eog_window_print(EogWindow * window)2182 eog_window_print (EogWindow *window)
2183 {
2184 	GtkWidget *dialog;
2185 	GError *error = NULL;
2186 	GtkPrintOperation *print;
2187 	GtkPrintOperationResult res;
2188 	GtkPageSetup *page_setup;
2189 	GtkPrintSettings *print_settings;
2190 	gboolean page_setup_disabled = FALSE;
2191 
2192 	eog_debug (DEBUG_PRINTING);
2193 
2194 	print_settings = eog_print_get_print_settings ();
2195 	set_basename_for_print_settings (print_settings, window);
2196 
2197 	/* Make sure the window stays valid while printing */
2198 	g_object_ref (window);
2199 
2200 	if (window->priv->page_setup != NULL)
2201 		page_setup = g_object_ref (window->priv->page_setup);
2202 	else
2203 		page_setup = NULL;
2204 
2205 	print = eog_print_operation_new (window->priv->image,
2206 					 print_settings,
2207 					 page_setup);
2208 
2209 
2210 	// Disable page setup options if they are locked down
2211 	page_setup_disabled = g_settings_get_boolean (window->priv->lockdown_settings,
2212 						      EOG_CONF_DESKTOP_CAN_SETUP_PAGE);
2213 	if (page_setup_disabled)
2214 		gtk_print_operation_set_embed_page_setup (print, FALSE);
2215 
2216 
2217 	res = gtk_print_operation_run (print,
2218 				       GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
2219 				       GTK_WINDOW (window), &error);
2220 
2221 	if (res == GTK_PRINT_OPERATION_RESULT_ERROR) {
2222 		dialog = gtk_message_dialog_new (GTK_WINDOW (window),
2223 						 GTK_DIALOG_DESTROY_WITH_PARENT,
2224 						 GTK_MESSAGE_ERROR,
2225 						 GTK_BUTTONS_CLOSE,
2226 						 _("Error printing file:\n%s"),
2227 						 error->message);
2228 		g_signal_connect (dialog, "response",
2229 				  G_CALLBACK (gtk_widget_destroy), NULL);
2230 		gtk_widget_show (dialog);
2231 		g_error_free (error);
2232 	} else if (res == GTK_PRINT_OPERATION_RESULT_APPLY) {
2233 		GtkPageSetup *new_page_setup;
2234 		eog_print_set_print_settings (gtk_print_operation_get_print_settings (print));
2235 		new_page_setup = gtk_print_operation_get_default_page_setup (print);
2236 		if (window->priv->page_setup != NULL)
2237 			g_object_unref (window->priv->page_setup);
2238 		window->priv->page_setup = g_object_ref (new_page_setup);
2239 	}
2240 
2241 	if (page_setup != NULL)
2242 		g_object_unref (page_setup);
2243 	g_object_unref (print_settings);
2244 	g_object_unref (window);
2245 }
2246 
2247 static void
eog_window_action_file_open(GSimpleAction * action,GVariant * parameter,gpointer user_data)2248 eog_window_action_file_open (GSimpleAction *action,
2249 			     GVariant      *parameter,
2250 			     gpointer       user_data)
2251 {
2252 	EogWindow *window;
2253 	EogWindowPrivate *priv;
2254 	EogImage *current;
2255 	GtkWidget *dlg;
2256 
2257 	g_return_if_fail (EOG_IS_WINDOW (user_data));
2258 
2259 	window = EOG_WINDOW (user_data);
2260 
2261 	priv = window->priv;
2262 
2263 	dlg = eog_file_chooser_new (GTK_FILE_CHOOSER_ACTION_OPEN);
2264 	gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (window));
2265 
2266 	current = eog_thumb_view_get_first_selected_image (EOG_THUMB_VIEW (priv->thumbview));
2267 
2268 	if (current != NULL) {
2269 		gchar *dir_uri, *file_uri;
2270 
2271 		file_uri = eog_image_get_uri_for_display (current);
2272 		dir_uri = g_path_get_dirname (file_uri);
2273 
2274 		gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg),
2275 							 dir_uri);
2276 		g_free (file_uri);
2277 		g_free (dir_uri);
2278 		g_object_unref (current);
2279 	} else {
2280 		/* If desired by the user,
2281 		   fallback to the XDG_PICTURES_DIR (if available) */
2282 		const gchar *pics_dir;
2283 		gboolean use_fallback;
2284 
2285 		use_fallback = g_settings_get_boolean (priv->ui_settings,
2286 					EOG_CONF_UI_FILECHOOSER_XDG_FALLBACK);
2287 		pics_dir = g_get_user_special_dir (G_USER_DIRECTORY_PICTURES);
2288 		if (use_fallback && pics_dir) {
2289 			gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dlg),
2290 							     pics_dir);
2291 		}
2292 	}
2293 
2294 	g_signal_connect (dlg, "response",
2295 			  G_CALLBACK (file_open_dialog_response_cb),
2296 			  window);
2297 
2298 	gtk_widget_show_all (dlg);
2299 }
2300 
2301 static void
eog_job_close_save_cb(EogJobSave * job,gpointer user_data)2302 eog_job_close_save_cb (EogJobSave *job, gpointer user_data)
2303 {
2304 	EogWindow *window = EOG_WINDOW (user_data);
2305 	GAction *action_save;
2306 
2307 	g_signal_handlers_disconnect_by_func (job,
2308 					      eog_job_close_save_cb,
2309 					      window);
2310 
2311 	/* clean the last save job */
2312 	g_object_unref (window->priv->save_job);
2313 	window->priv->save_job = NULL;
2314 
2315 	/* recover save action from actions group */
2316 	action_save = g_action_map_lookup_action (G_ACTION_MAP (window),
2317 						   "save");
2318 
2319 	/* check if job contains any error */
2320 	if (EOG_JOB (job)->error == NULL) {
2321 		gtk_widget_destroy (GTK_WIDGET (window));
2322 	} else {
2323 		GtkWidget *message_area;
2324 
2325 		eog_thumb_view_set_current_image (EOG_THUMB_VIEW (window->priv->thumbview),
2326 						  job->current_image,
2327 						  TRUE);
2328 
2329 		message_area = eog_image_save_error_message_area_new (
2330 					eog_image_get_caption (job->current_image),
2331 					EOG_JOB (job)->error);
2332 
2333 		g_signal_connect (message_area,
2334 				  "response",
2335 				  G_CALLBACK (eog_window_error_message_area_response),
2336 				  window);
2337 
2338 		gtk_window_set_icon (GTK_WINDOW (window), NULL);
2339 		gtk_window_set_title (GTK_WINDOW (window),
2340 				      eog_image_get_caption (job->current_image));
2341 
2342 		eog_window_set_message_area (window, message_area);
2343 
2344 		gtk_info_bar_set_default_response (GTK_INFO_BAR (message_area),
2345 						   GTK_RESPONSE_CANCEL);
2346 
2347 		gtk_widget_show (message_area);
2348 
2349 		update_status_bar (window);
2350 
2351 		g_simple_action_set_enabled (G_SIMPLE_ACTION (action_save), TRUE);
2352 	}
2353 }
2354 
2355 static void
close_confirmation_dialog_response_handler(EogCloseConfirmationDialog * dlg,gint response_id,EogWindow * window)2356 close_confirmation_dialog_response_handler (EogCloseConfirmationDialog *dlg,
2357 					    gint                        response_id,
2358 					    EogWindow                  *window)
2359 {
2360 	GList            *selected_images;
2361 	EogWindowPrivate *priv;
2362 	GAction          *action_save_as;
2363 
2364 	priv = window->priv;
2365 
2366 	switch (response_id) {
2367 	case EOG_CLOSE_CONFIRMATION_DIALOG_RESPONSE_SAVE:
2368 		selected_images = eog_close_confirmation_dialog_get_selected_images (dlg);
2369 		gtk_widget_destroy (GTK_WIDGET (dlg));
2370 
2371 		if (eog_window_save_images (window, selected_images)) {
2372 			g_signal_connect (priv->save_job,
2373 					  "finished",
2374 					  G_CALLBACK (eog_job_close_save_cb),
2375 					  window);
2376 
2377 			eog_job_scheduler_add_job (priv->save_job);
2378 		}
2379 
2380 		break;
2381 
2382 	case EOG_CLOSE_CONFIRMATION_DIALOG_RESPONSE_SAVEAS:
2383 		selected_images = eog_close_confirmation_dialog_get_selected_images (dlg);
2384 		gtk_widget_destroy (GTK_WIDGET (dlg));
2385 
2386 		eog_thumb_view_set_current_image (EOG_THUMB_VIEW (priv->thumbview),
2387 						  g_list_first (selected_images)->data,
2388 						  TRUE);
2389 
2390 		action_save_as = g_action_map_lookup_action (G_ACTION_MAP (window),
2391 							      "save-as");
2392 		eog_window_action_save_as (G_SIMPLE_ACTION (action_save_as), NULL, window);
2393 		break;
2394 
2395 	case EOG_CLOSE_CONFIRMATION_DIALOG_RESPONSE_CLOSE:
2396 		gtk_widget_destroy (GTK_WIDGET (window));
2397 		break;
2398 
2399 	case EOG_CLOSE_CONFIRMATION_DIALOG_RESPONSE_CANCEL:
2400 		gtk_widget_destroy (GTK_WIDGET (dlg));
2401 		break;
2402 	}
2403 }
2404 
2405 static gboolean
eog_window_unsaved_images_confirm(EogWindow * window)2406 eog_window_unsaved_images_confirm (EogWindow *window)
2407 {
2408 	EogWindowPrivate *priv;
2409 	gboolean disabled;
2410 	GtkWidget *dialog;
2411 	GList *list;
2412 	EogImage *image;
2413 	GtkTreeIter iter;
2414 
2415 	priv = window->priv;
2416 
2417 	disabled = g_settings_get_boolean(priv->ui_settings,
2418 					EOG_CONF_UI_DISABLE_CLOSE_CONFIRMATION);
2419 	disabled |= window->priv->save_disabled;
2420 
2421 	if (disabled || !priv->store) {
2422 		return FALSE;
2423 	}
2424 
2425 	list = NULL;
2426 	if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->store), &iter)) {
2427 		do {
2428 			gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
2429 					    EOG_LIST_STORE_EOG_IMAGE, &image,
2430 					    -1);
2431 			if (!image)
2432 				continue;
2433 
2434 			if (eog_image_is_modified (image)) {
2435 				list = g_list_prepend (list, image);
2436 			} else {
2437 				g_object_unref (image);
2438 			}
2439 		} while (gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->store), &iter));
2440 	}
2441 
2442 	if (list) {
2443 		list = g_list_reverse (list);
2444 		dialog = eog_close_confirmation_dialog_new (GTK_WINDOW (window),
2445 							    list);
2446 		g_list_free (list);
2447 		g_signal_connect (dialog,
2448 				  "response",
2449 				  G_CALLBACK (close_confirmation_dialog_response_handler),
2450 				  window);
2451 		gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
2452 
2453 		gtk_widget_show (dialog);
2454 		return TRUE;
2455 
2456 	}
2457 	return FALSE;
2458 }
2459 
2460 static void
eog_window_action_close_window(GSimpleAction * action,GVariant * variant,gpointer user_data)2461 eog_window_action_close_window (GSimpleAction *action,
2462 				GVariant      *variant,
2463 				gpointer       user_data)
2464 {
2465 	g_return_if_fail (EOG_IS_WINDOW (user_data));
2466 
2467 	eog_window_close (EOG_WINDOW (user_data));
2468 }
2469 
2470 static void
eog_window_action_close_all_windows(GSimpleAction * action,GVariant * variant,gpointer user_data)2471 eog_window_action_close_all_windows (GSimpleAction *action,
2472 				     GVariant      *variant,
2473 				     gpointer       user_data)
2474 {
2475 	g_return_if_fail (EOG_IS_WINDOW (user_data));
2476 
2477 	eog_application_close_all_windows (EOG_APP);
2478 }
2479 
2480 static void
eog_window_action_preferences(GSimpleAction * action,GVariant * variant,gpointer user_data)2481 eog_window_action_preferences (GSimpleAction *action,
2482 			       GVariant      *variant,
2483 			       gpointer       user_data)
2484 {
2485 	g_return_if_fail (EOG_IS_WINDOW (user_data));
2486 
2487 	eog_window_show_preferences_dialog (EOG_WINDOW (user_data));
2488 }
2489 
2490 static void
eog_window_action_help(GSimpleAction * action,GVariant * variant,gpointer user_data)2491 eog_window_action_help (GSimpleAction *action,
2492 			GVariant      *variant,
2493 			gpointer       user_data)
2494 {
2495 	EogWindow *window;
2496 
2497 	g_return_if_fail (EOG_IS_WINDOW (user_data));
2498 
2499 	window = EOG_WINDOW (user_data);
2500 
2501 	eog_util_show_help (NULL, GTK_WINDOW (window));
2502 }
2503 
2504 static void
eog_window_action_about(GSimpleAction * action,GVariant * variant,gpointer user_data)2505 eog_window_action_about (GSimpleAction *action,
2506 			 GVariant      *variant,
2507 			 gpointer       user_data)
2508 {
2509 	g_return_if_fail (EOG_IS_WINDOW (user_data));
2510 
2511 	eog_window_show_about_dialog (EOG_WINDOW (user_data));
2512 }
2513 
2514 static void
eog_window_action_show_hide_bar(GSimpleAction * action,GVariant * state,gpointer user_data)2515 eog_window_action_show_hide_bar (GSimpleAction *action,
2516 				 GVariant      *state,
2517 				 gpointer       user_data)
2518 {
2519 	EogWindow *window;
2520 	EogWindowPrivate *priv;
2521 	gboolean visible;
2522 
2523 	g_return_if_fail (EOG_IS_WINDOW (user_data));
2524 
2525 	window = EOG_WINDOW (user_data);
2526 	priv = window->priv;
2527 
2528 	if (priv->mode != EOG_WINDOW_MODE_NORMAL &&
2529             priv->mode != EOG_WINDOW_MODE_FULLSCREEN) return;
2530 
2531 	visible = g_variant_get_boolean (state);
2532 
2533 	if (g_ascii_strcasecmp (g_action_get_name (G_ACTION (action)), "view-statusbar") == 0) {
2534 		gtk_widget_set_visible (priv->statusbar, visible);
2535 		g_simple_action_set_state (action, state);
2536 
2537 		if (priv->mode == EOG_WINDOW_MODE_NORMAL)
2538 			g_settings_set_boolean (priv->ui_settings,
2539 						EOG_CONF_UI_STATUSBAR, visible);
2540 
2541 	} else if (g_ascii_strcasecmp (g_action_get_name (G_ACTION (action)), "view-gallery") == 0) {
2542 		if (visible) {
2543 			/* Make sure the focus widget is realized to
2544 			 * avoid warnings on keypress events */
2545 			if (!gtk_widget_get_realized (window->priv->thumbview))
2546 				gtk_widget_realize (window->priv->thumbview);
2547 
2548 			gtk_widget_show (priv->nav);
2549 		} else {
2550 			/* Make sure the focus widget is realized to
2551 			 * avoid warnings on keypress events.
2552 			 * Don't do it during init phase or the view
2553 			 * will get a bogus allocation. */
2554 			if (!gtk_widget_get_realized (priv->view)
2555 			    && priv->status == EOG_WINDOW_STATUS_NORMAL)
2556 				gtk_widget_realize (priv->view);
2557 
2558 			gtk_widget_hide (priv->nav);
2559 		}
2560 		g_simple_action_set_state (action, state);
2561 		g_settings_set_boolean (priv->ui_settings,
2562 					EOG_CONF_UI_IMAGE_GALLERY, visible);
2563 
2564 	} else if (g_ascii_strcasecmp (g_action_get_name (G_ACTION (action)), "view-sidebar") == 0) {
2565 		gtk_widget_set_visible (priv->sidebar, visible);
2566 		g_simple_action_set_state (action, state);
2567 		g_settings_set_boolean (priv->ui_settings, EOG_CONF_UI_SIDEBAR,
2568 					visible);
2569 	}
2570 }
2571 
2572 static gboolean
in_desktop(const gchar * name)2573 in_desktop (const gchar *name)
2574 {
2575 	const gchar *desktop_name_list;
2576 	gchar **names;
2577 	gboolean in_list = FALSE;
2578 	gint i;
2579 
2580 	desktop_name_list = g_getenv ("XDG_CURRENT_DESKTOP");
2581 	if (!desktop_name_list)
2582 		return FALSE;
2583 
2584 	names = g_strsplit (desktop_name_list, ":", -1);
2585 	for (i = 0; names[i] && !in_list; i++)
2586 		if (strcmp (names[i], name) == 0) {
2587 			in_list = TRUE;
2588 			break;
2589 		}
2590 	g_strfreev (names);
2591 
2592 	return in_list;
2593 }
2594 
2595 static void
wallpaper_info_bar_response(GtkInfoBar * bar,gint response,EogWindow * window)2596 wallpaper_info_bar_response (GtkInfoBar *bar, gint response, EogWindow *window)
2597 {
2598 	if (response == GTK_RESPONSE_YES) {
2599 		GAppInfo *app_info;
2600 		gchar *path;
2601 		GError *error = NULL;
2602 
2603 		path = g_find_program_in_path ("unity-control-center");
2604 		if (path && in_desktop ("Unity"))
2605 			app_info = g_app_info_create_from_commandline ("unity-control-center appearance",
2606 								       "System Settings",
2607 								       G_APP_INFO_CREATE_NONE,
2608 								       &error);
2609 		else
2610 			app_info = g_app_info_create_from_commandline ("gnome-control-center background",
2611 								       "System Settings",
2612 								       G_APP_INFO_CREATE_NONE,
2613 								       &error);
2614 		g_free (path);
2615 
2616 		if (error != NULL) {
2617 			g_warning ("%s%s", _("Error launching System Settings: "),
2618 				   error->message);
2619 			g_error_free (error);
2620 			error = NULL;
2621 		}
2622 
2623 		if (app_info != NULL) {
2624 			GdkAppLaunchContext *context;
2625 			GdkDisplay *display;
2626 
2627 			display = gtk_widget_get_display (GTK_WIDGET (window));
2628 			context = gdk_display_get_app_launch_context (display);
2629 			g_app_info_launch (app_info, NULL, G_APP_LAUNCH_CONTEXT (context), &error);
2630 
2631 			if (error != NULL) {
2632 				g_warning ("%s%s", _("Error launching System Settings: "),
2633 					   error->message);
2634 				g_error_free (error);
2635 				error = NULL;
2636 			}
2637 
2638 			g_object_unref (context);
2639 			g_object_unref (app_info);
2640 		}
2641 	}
2642 
2643 	/* Close message area on every response */
2644 	eog_window_set_message_area (window, NULL);
2645 }
2646 
2647 static void
eog_window_set_wallpaper(EogWindow * window,const gchar * filename,const gchar * visible_filename)2648 eog_window_set_wallpaper (EogWindow *window, const gchar *filename, const gchar *visible_filename)
2649 {
2650 	GSettings *settings;
2651 	GtkWidget *info_bar;
2652 	GtkWidget *image;
2653 	GtkWidget *label;
2654 	GtkWidget *hbox;
2655 	gchar *markup;
2656 	gchar *text;
2657 	gchar *basename;
2658 	gchar *uri;
2659 
2660 	uri = g_filename_to_uri (filename, NULL, NULL);
2661 	settings = g_settings_new (EOG_CONF_DESKTOP_WALLPAPER_SCHEMA);
2662 	g_settings_set_string (settings, EOG_CONF_DESKTOP_WALLPAPER, uri);
2663 	g_object_unref (settings);
2664 	g_free (uri);
2665 
2666 	info_bar = gtk_info_bar_new_with_buttons (_("_Open Background Preferences"),
2667 						  GTK_RESPONSE_YES,
2668 						  C_("MessageArea","Hi_de"),
2669 						  GTK_RESPONSE_NO, NULL);
2670 	gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar),
2671 				       GTK_MESSAGE_QUESTION);
2672 
2673 	image = gtk_image_new_from_icon_name ("dialog-question",
2674 					      GTK_ICON_SIZE_DIALOG);
2675 	label = gtk_label_new (NULL);
2676 
2677 	if (!visible_filename)
2678 		basename = g_path_get_basename (filename);
2679 
2680 	text = g_strdup_printf (_("The image “%s” has been set as Desktop Background."
2681 				  " Would you like to modify its appearance?"),
2682 				visible_filename ? visible_filename : basename);
2683 	markup = g_markup_printf_escaped ("<b>%s</b>", text);
2684 	gtk_label_set_markup (GTK_LABEL (label), markup);
2685 	gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
2686 	g_free (markup);
2687 	g_free (text);
2688 	if (!visible_filename)
2689 		g_free (basename);
2690 
2691 	hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
2692 	gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
2693 	gtk_widget_set_valign (image, GTK_ALIGN_START);
2694 	gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
2695 	gtk_widget_set_halign (label, GTK_ALIGN_START);
2696 	gtk_box_pack_start (GTK_BOX (gtk_info_bar_get_content_area (GTK_INFO_BAR (info_bar))), hbox, TRUE, TRUE, 0);
2697 	gtk_widget_show_all (hbox);
2698 	gtk_widget_show (info_bar);
2699 
2700 
2701 	eog_window_set_message_area (window, info_bar);
2702 	gtk_info_bar_set_default_response (GTK_INFO_BAR (info_bar),
2703 					   GTK_RESPONSE_YES);
2704 	g_signal_connect (info_bar, "response",
2705 			  G_CALLBACK (wallpaper_info_bar_response), window);
2706 }
2707 
2708 static void
eog_job_save_cb(EogJobSave * job,gpointer user_data)2709 eog_job_save_cb (EogJobSave *job, gpointer user_data)
2710 {
2711 	EogWindow *window = EOG_WINDOW (user_data);
2712 	GAction *action_save;
2713 
2714 	g_signal_handlers_disconnect_by_func (job,
2715 					      eog_job_save_cb,
2716 					      window);
2717 
2718 	g_signal_handlers_disconnect_by_func (job,
2719 					      eog_job_save_progress_cb,
2720 					      window);
2721 
2722 	/* clean the last save job */
2723 	g_object_unref (window->priv->save_job);
2724 	window->priv->save_job = NULL;
2725 
2726 	/* recover save action from actions group */
2727 	action_save = g_action_map_lookup_action (G_ACTION_MAP (window),
2728 						   "save");
2729 
2730 	/* check if job contains any error */
2731 	if (EOG_JOB (job)->error == NULL) {
2732 		update_status_bar (window);
2733 		gtk_window_set_title (GTK_WINDOW (window),
2734 				      eog_image_get_caption (job->current_image));
2735 
2736 		g_simple_action_set_enabled (G_SIMPLE_ACTION (action_save), FALSE);
2737 	} else {
2738 		GtkWidget *message_area;
2739 
2740 		message_area = eog_image_save_error_message_area_new (
2741 					eog_image_get_caption (job->current_image),
2742 					EOG_JOB (job)->error);
2743 
2744 		g_signal_connect (message_area,
2745 				  "response",
2746 				  G_CALLBACK (eog_window_error_message_area_response),
2747 				  window);
2748 
2749 		gtk_window_set_icon (GTK_WINDOW (window), NULL);
2750 		gtk_window_set_title (GTK_WINDOW (window),
2751 				      eog_image_get_caption (job->current_image));
2752 
2753 		eog_window_set_message_area (window, message_area);
2754 
2755 		gtk_info_bar_set_default_response (GTK_INFO_BAR (message_area),
2756 						   GTK_RESPONSE_CANCEL);
2757 
2758 		gtk_widget_show (message_area);
2759 
2760 		update_status_bar (window);
2761 
2762 		g_simple_action_set_enabled (G_SIMPLE_ACTION (action_save), TRUE);
2763 	}
2764 }
2765 
2766 static void
eog_job_copy_cb(EogJobCopy * job,gpointer user_data)2767 eog_job_copy_cb (EogJobCopy *job, gpointer user_data)
2768 {
2769 	EogWindow *window = EOG_WINDOW (user_data);
2770 	gchar *filepath, *basename, *filename, *extension;
2771 	GAction *action;
2772 	GFile *source_file, *dest_file;
2773 	gint64 mtime;
2774 
2775 	/* Create source GFile */
2776 	basename = g_file_get_basename (job->images->data);
2777 	filepath = g_build_filename (job->destination, basename, NULL);
2778 	source_file = g_file_new_for_path (filepath);
2779 	g_free (filepath);
2780 
2781 	/* Create destination GFile */
2782 	extension = eog_util_filename_get_extension (basename);
2783 	filename = g_strdup_printf  ("%s.%s", EOG_WALLPAPER_FILENAME, extension);
2784 	filepath = g_build_filename (job->destination, filename, NULL);
2785 	dest_file = g_file_new_for_path (filepath);
2786 	g_free (filename);
2787 	g_free (extension);
2788 
2789 	/* Move the file */
2790 	g_file_move (source_file, dest_file, G_FILE_COPY_OVERWRITE,
2791 		     NULL, NULL, NULL, NULL);
2792 
2793 	/* Update mtime, see bug 664747 */
2794 	mtime = g_get_real_time ();
2795 	g_file_set_attribute_uint64 (dest_file, G_FILE_ATTRIBUTE_TIME_MODIFIED,
2796 				     (guint64)(mtime / G_USEC_PER_SEC),
2797 				     G_FILE_QUERY_INFO_NONE, NULL, NULL);
2798 	g_file_set_attribute_uint32 (dest_file,
2799 				     G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC,
2800 				     (guint32)(mtime % G_USEC_PER_SEC),
2801 				     G_FILE_QUERY_INFO_NONE, NULL, NULL);
2802 
2803 	/* Set the wallpaper */
2804 	eog_window_set_wallpaper (window, filepath, basename);
2805 	g_free (basename);
2806 	g_free (filepath);
2807 
2808 	gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar),
2809 			   window->priv->copy_file_cid);
2810 	action = g_action_map_lookup_action (G_ACTION_MAP (window),
2811 					      "set-wallpaper");
2812 	g_simple_action_set_enabled (G_SIMPLE_ACTION (action), TRUE);
2813 
2814 	window->priv->copy_job = NULL;
2815 
2816 	g_object_unref (source_file);
2817 	g_object_unref (dest_file);
2818 	g_object_unref (job);
2819 }
2820 
2821 static gboolean
eog_window_save_images(EogWindow * window,GList * images)2822 eog_window_save_images (EogWindow *window, GList *images)
2823 {
2824 	EogWindowPrivate *priv;
2825 
2826 	priv = window->priv;
2827 
2828 	if (window->priv->save_job != NULL)
2829 		return FALSE;
2830 
2831 	priv->save_job = eog_job_save_new (images);
2832 
2833 	g_signal_connect (priv->save_job,
2834 			  "finished",
2835 			  G_CALLBACK (eog_job_save_cb),
2836 			  window);
2837 
2838 	g_signal_connect (priv->save_job,
2839 			  "progress",
2840 			  G_CALLBACK (eog_job_save_progress_cb),
2841 			  window);
2842 
2843 	return TRUE;
2844 }
2845 
2846 static void
eog_window_action_save(GSimpleAction * action,GVariant * variant,gpointer user_data)2847 eog_window_action_save (GSimpleAction *action,
2848 			GVariant      *variant,
2849 			gpointer       user_data)
2850 {
2851 	EogWindowPrivate *priv;
2852 	EogWindow *window;
2853 	GList *images;
2854 
2855 	window = EOG_WINDOW (user_data);
2856 	priv = window->priv;
2857 
2858 	if (window->priv->save_job != NULL)
2859 		return;
2860 
2861 	images = eog_thumb_view_get_selected_images (EOG_THUMB_VIEW (priv->thumbview));
2862 
2863 	if (eog_window_save_images (window, images)) {
2864 		eog_job_scheduler_add_job (priv->save_job);
2865 	}
2866 }
2867 
2868 static GFile*
eog_window_retrieve_save_as_file(EogWindow * window,EogImage * image)2869 eog_window_retrieve_save_as_file (EogWindow *window, EogImage *image)
2870 {
2871 	GtkWidget *dialog;
2872 	GFile *save_file = NULL;
2873 	GFile *last_dest_folder;
2874 	gint response;
2875 
2876 	g_assert (image != NULL);
2877 
2878 	dialog = eog_file_chooser_new (GTK_FILE_CHOOSER_ACTION_SAVE);
2879 
2880 	last_dest_folder = window->priv->last_save_as_folder;
2881 
2882 	if (last_dest_folder && g_file_query_exists (last_dest_folder, NULL)) {
2883 		gtk_file_chooser_set_current_folder_file (GTK_FILE_CHOOSER (dialog), last_dest_folder, NULL);
2884 		gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog),
2885 						 eog_image_get_caption (image));
2886 	} else {
2887 		GFile *image_file;
2888 
2889 		image_file = eog_image_get_file (image);
2890 		/* Setting the file will also navigate to its parent folder */
2891 		gtk_file_chooser_set_file (GTK_FILE_CHOOSER (dialog),
2892 					   image_file, NULL);
2893 		g_object_unref (image_file);
2894 	}
2895 
2896 	gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(window));
2897 	response = gtk_dialog_run (GTK_DIALOG (dialog));
2898 	gtk_widget_hide (dialog);
2899 
2900 	if (response == GTK_RESPONSE_OK) {
2901 		save_file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
2902 		if (window->priv->last_save_as_folder)
2903 			g_object_unref (window->priv->last_save_as_folder);
2904 		window->priv->last_save_as_folder = g_file_get_parent (save_file);
2905 	}
2906 	gtk_widget_destroy (dialog);
2907 
2908 	return save_file;
2909 }
2910 
2911 static void
eog_window_action_save_as(GSimpleAction * action,GVariant * variant,gpointer user_data)2912 eog_window_action_save_as (GSimpleAction *action,
2913 			   GVariant      *variant,
2914 			   gpointer       user_data)
2915 {
2916         EogWindowPrivate *priv;
2917         EogWindow *window;
2918 	GList *images;
2919 	guint n_images;
2920 
2921         window = EOG_WINDOW (user_data);
2922 	priv = window->priv;
2923 
2924 	if (window->priv->save_job != NULL)
2925 		return;
2926 
2927 	images = eog_thumb_view_get_selected_images (EOG_THUMB_VIEW (priv->thumbview));
2928 	n_images = g_list_length (images);
2929 
2930 	if (n_images == 1) {
2931 		GFile *file;
2932 
2933 		file = eog_window_retrieve_save_as_file (window, images->data);
2934 
2935 		if (!file) {
2936 			g_list_free (images);
2937 			return;
2938 		}
2939 
2940 		priv->save_job = eog_job_save_as_new (images, NULL, file);
2941 
2942 		g_object_unref (file);
2943 	} else if (n_images > 1) {
2944 		GFile *base_file;
2945 		GtkWidget *dialog;
2946 		gchar *basedir;
2947 		EogURIConverter *converter;
2948 
2949 		basedir = g_get_current_dir ();
2950 		base_file = g_file_new_for_path (basedir);
2951 		g_free (basedir);
2952 
2953 		dialog = eog_save_as_dialog_new (GTK_WINDOW (window),
2954 						 images,
2955 						 base_file);
2956 
2957 		gtk_widget_show_all (dialog);
2958 
2959 		if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK) {
2960 			g_object_unref (base_file);
2961 			g_list_free (images);
2962 			gtk_widget_destroy (dialog);
2963 
2964 			return;
2965 		}
2966 
2967 		converter = eog_save_as_dialog_get_converter (dialog);
2968 
2969 		g_assert (converter != NULL);
2970 
2971 		priv->save_job = eog_job_save_as_new (images, converter, NULL);
2972 
2973 		gtk_widget_destroy (dialog);
2974 
2975 		g_object_unref (converter);
2976 		g_object_unref (base_file);
2977 	} else {
2978 		/* n_images = 0 -- No Image selected */
2979 		return;
2980 	}
2981 
2982 	g_signal_connect (priv->save_job,
2983 			  "finished",
2984 			  G_CALLBACK (eog_job_save_cb),
2985 			  window);
2986 
2987 	g_signal_connect (priv->save_job,
2988 			  "progress",
2989 			  G_CALLBACK (eog_job_save_progress_cb),
2990 			  window);
2991 
2992 	eog_job_scheduler_add_job (priv->save_job);
2993 }
2994 
2995 static void
eog_window_action_open_containing_folder(GSimpleAction * action,GVariant * variant,gpointer user_data)2996 eog_window_action_open_containing_folder (GSimpleAction *action,
2997 					  GVariant      *variant,
2998 					  gpointer       user_data)
2999 {
3000 	EogWindowPrivate *priv;
3001 	GFile *file;
3002 
3003 	g_return_if_fail (EOG_IS_WINDOW (user_data));
3004 
3005 	priv = EOG_WINDOW (user_data)->priv;
3006 
3007 	g_return_if_fail (priv->image != NULL);
3008 
3009 	file = eog_image_get_file (priv->image);
3010 
3011 	g_return_if_fail (file != NULL);
3012 
3013 	eog_util_show_file_in_filemanager (file,
3014 					   GTK_WINDOW (user_data));
3015 }
3016 
3017 static void
eog_window_action_print(GSimpleAction * action,GVariant * variant,gpointer user_data)3018 eog_window_action_print (GSimpleAction *action,
3019 			 GVariant      *variant,
3020 			 gpointer       user_data)
3021 {
3022 	EogWindow *window = EOG_WINDOW (user_data);
3023 
3024 	eog_window_print (window);
3025 }
3026 
3027 /**
3028  * eog_window_get_properties_dialog:
3029  * @window: a #EogWindow
3030  *
3031  * Gets the @window property dialog. The widget will be built on the first call to this function.
3032  *
3033  * Returns: (transfer none): a #GtkWidget.
3034  */
3035 
3036 GtkWidget*
eog_window_get_properties_dialog(EogWindow * window)3037 eog_window_get_properties_dialog (EogWindow *window)
3038 {
3039 	EogWindowPrivate *priv;
3040 
3041 	g_return_val_if_fail (EOG_IS_WINDOW (window), NULL);
3042 
3043 	priv = window->priv;
3044 
3045 	if (priv->properties_dlg == NULL) {
3046 		priv->properties_dlg =
3047 			eog_properties_dialog_new (GTK_WINDOW (window),
3048 						   EOG_THUMB_VIEW (priv->thumbview),
3049 						   "win.go-next",
3050 						   "win.go-previous");
3051 
3052 		eog_properties_dialog_update (EOG_PROPERTIES_DIALOG (priv->properties_dlg),
3053 					      priv->image);
3054 		g_settings_bind (priv->ui_settings,
3055 				 EOG_CONF_UI_PROPSDIALOG_NETBOOK_MODE,
3056 				 priv->properties_dlg, "netbook-mode",
3057 				 G_SETTINGS_BIND_GET);
3058 	}
3059 
3060 	return priv->properties_dlg;
3061 }
3062 
3063 static void
eog_window_action_properties(GSimpleAction * action,GVariant * variant,gpointer user_data)3064 eog_window_action_properties (GSimpleAction *action,
3065 			      GVariant      *variant,
3066 			      gpointer       user_data)
3067 {
3068 	EogWindow *window = EOG_WINDOW (user_data);
3069 	GtkWidget *dialog;
3070 
3071 	dialog = eog_window_get_properties_dialog (window);
3072 	gtk_widget_show (dialog);
3073 }
3074 
3075 static void
eog_window_action_undo(GSimpleAction * action,GVariant * variant,gpointer user_data)3076 eog_window_action_undo (GSimpleAction *action,
3077 			GVariant      *variant,
3078 			gpointer       user_data)
3079 {
3080 	g_return_if_fail (EOG_IS_WINDOW (user_data));
3081 
3082 	apply_transformation (EOG_WINDOW (user_data), NULL);
3083 }
3084 
3085 static void
eog_window_action_flip_horizontal(GSimpleAction * action,GVariant * variant,gpointer user_data)3086 eog_window_action_flip_horizontal (GSimpleAction *action,
3087 				   GVariant      *variant,
3088 				   gpointer       user_data)
3089 {
3090 	g_return_if_fail (EOG_IS_WINDOW (user_data));
3091 
3092 	apply_transformation (EOG_WINDOW (user_data),
3093 			      eog_transform_flip_new (EOG_TRANSFORM_FLIP_HORIZONTAL));
3094 }
3095 
3096 static void
eog_window_action_flip_vertical(GSimpleAction * action,GVariant * variant,gpointer user_data)3097 eog_window_action_flip_vertical (GSimpleAction *action,
3098 				 GVariant      *variant,
3099 				 gpointer      user_data)
3100 {
3101 	g_return_if_fail (EOG_IS_WINDOW (user_data));
3102 
3103 	apply_transformation (EOG_WINDOW (user_data),
3104 			      eog_transform_flip_new (EOG_TRANSFORM_FLIP_VERTICAL));
3105 }
3106 
3107 static void
eog_window_action_rotate_90(GSimpleAction * action,GVariant * parameter,gpointer user_data)3108 eog_window_action_rotate_90 (GSimpleAction *action,
3109                              GVariant      *parameter,
3110                              gpointer       user_data)
3111 {
3112 	g_return_if_fail (EOG_IS_WINDOW (user_data));
3113 
3114 	apply_transformation (EOG_WINDOW (user_data),
3115 			      eog_transform_rotate_new (90));
3116 }
3117 
3118 static void
eog_window_action_rotate_270(GSimpleAction * action,GVariant * parameter,gpointer user_data)3119 eog_window_action_rotate_270 (GSimpleAction *action,
3120                               GVariant      *parameter,
3121                               gpointer       user_data)
3122 {
3123 	g_return_if_fail (EOG_IS_WINDOW (user_data));
3124 
3125 	apply_transformation (EOG_WINDOW (user_data),
3126 			      eog_transform_rotate_new (270));
3127 }
3128 
3129 static void
eog_window_action_wallpaper(GSimpleAction * action,GVariant * variant,gpointer user_data)3130 eog_window_action_wallpaper (GSimpleAction *action,
3131 			     GVariant      *variant,
3132 			     gpointer       user_data)
3133 {
3134 	EogWindow *window;
3135 	EogWindowPrivate *priv;
3136 	EogImage *image;
3137 	g_autoptr(GFile) file = NULL;
3138 	g_autofree gchar *filename = NULL;
3139 
3140 	g_return_if_fail (EOG_IS_WINDOW (user_data));
3141 
3142 	window = EOG_WINDOW (user_data);
3143 	priv = window->priv;
3144 
3145 	/* If currently copying an image to set it as wallpaper, return. */
3146 	if (priv->copy_job != NULL)
3147 		return;
3148 
3149 	image = eog_thumb_view_get_first_selected_image (EOG_THUMB_VIEW (priv->thumbview));
3150 
3151 	g_return_if_fail (EOG_IS_IMAGE (image));
3152 
3153 	file = eog_image_get_file (image);
3154 
3155 	filename = g_file_get_path (file);
3156 
3157 	/* Currently only local files can be set as wallpaper */
3158 	if (filename == NULL || !eog_util_file_is_persistent (file))
3159 	{
3160 		GList *files = NULL;
3161 
3162 		g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
3163 
3164 		priv->copy_file_cid = gtk_statusbar_get_context_id (GTK_STATUSBAR (priv->statusbar),
3165 								    "copy_file_cid");
3166 		gtk_statusbar_push (GTK_STATUSBAR (priv->statusbar),
3167 				    priv->copy_file_cid,
3168 				    _("Saving image locally…"));
3169 
3170 		files = g_list_append (files, eog_image_get_file (image));
3171 		priv->copy_job = eog_job_copy_new (files, g_get_user_data_dir ());
3172 		g_signal_connect (priv->copy_job,
3173 				  "finished",
3174 				  G_CALLBACK (eog_job_copy_cb),
3175 				  window);
3176 		g_signal_connect (priv->copy_job,
3177 				  "progress",
3178 				  G_CALLBACK (eog_job_progress_cb),
3179 				  window);
3180 		eog_job_scheduler_add_job (priv->copy_job);
3181 
3182 		return;
3183 	}
3184 
3185 #ifdef HAVE_LIBPORTAL
3186 	if (eog_util_is_running_inside_flatpak ()) {
3187 		eog_util_set_wallpaper_with_portal (file, GTK_WINDOW (window));
3188 
3189 		return;
3190 	}
3191 #endif
3192 
3193 	eog_window_set_wallpaper (window, filename, NULL);
3194 
3195 }
3196 
3197 static gboolean
eog_window_all_images_trasheable(GList * images)3198 eog_window_all_images_trasheable (GList *images)
3199 {
3200 	GFile *file;
3201 	GFileInfo *file_info;
3202 	GList *iter;
3203 	EogImage *image;
3204 	gboolean can_trash = TRUE;
3205 
3206 	for (iter = images; iter != NULL; iter = g_list_next (iter)) {
3207 		image = (EogImage *) iter->data;
3208 		file = eog_image_get_file (image);
3209 		file_info = g_file_query_info (file,
3210 					       G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH,
3211 					       0, NULL, NULL);
3212 		can_trash = g_file_info_get_attribute_boolean (file_info,
3213 							       G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH);
3214 
3215 		g_object_unref (file_info);
3216 		g_object_unref (file);
3217 
3218 		if (can_trash == FALSE)
3219 			break;
3220 	}
3221 
3222 	return can_trash;
3223 }
3224 
3225 static gint
show_force_image_delete_confirm_dialog(EogWindow * window,GList * images)3226 show_force_image_delete_confirm_dialog (EogWindow *window,
3227 					GList     *images)
3228 {
3229 	static gboolean dont_ask_again_force_delete = FALSE;
3230 
3231 	GtkWidget *dialog;
3232 	GtkWidget *dont_ask_again_button;
3233 	EogImage  *image;
3234 	gchar     *prompt;
3235 	guint      n_images;
3236 	gint       response;
3237 
3238 	/* assume agreement, if the user doesn't want to be asked and deletion is available */
3239 	if (dont_ask_again_force_delete)
3240 		return GTK_RESPONSE_OK;
3241 
3242 	/* retrieve the selected images count */
3243 	n_images = g_list_length (images);
3244 
3245 	/* make the dialog prompt message */
3246 	if (n_images == 1) {
3247 		image = EOG_IMAGE (images->data);
3248 
3249 		prompt = g_strdup_printf (_("Are you sure you want to remove\n“%s” permanently?"),
3250 					  eog_image_get_caption (image));
3251 	} else {
3252 		prompt = g_strdup_printf (ngettext ("Are you sure you want to remove\n"
3253 						    "the selected image permanently?",
3254 						    "Are you sure you want to remove\n"
3255 						    "the %d selected images permanently?",
3256 						    n_images),
3257 					  n_images);
3258 	}
3259 
3260 	/* create the dialog */
3261 	dialog = gtk_message_dialog_new_with_markup (GTK_WINDOW (window),
3262 						     GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
3263 						     GTK_MESSAGE_WARNING,
3264 						     GTK_BUTTONS_NONE,
3265 						     "<span weight=\"bold\" size=\"larger\">%s</span>",
3266 						     prompt);
3267 
3268 	gtk_dialog_set_default_response (GTK_DIALOG (dialog),
3269 					 GTK_RESPONSE_OK);
3270 
3271 	/* add buttons to the dialog */
3272 	if (n_images == 1) {
3273 		gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Cancel"), GTK_RESPONSE_CANCEL);
3274 		gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Delete"), GTK_RESPONSE_OK);
3275 	} else {
3276 		gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Cancel"), GTK_RESPONSE_CANCEL);
3277 		gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Yes")   , GTK_RESPONSE_OK);
3278 	}
3279 
3280 	/* add 'dont ask again' button */
3281 	dont_ask_again_button = gtk_check_button_new_with_mnemonic (_("Do _not ask again during this session"));
3282 
3283 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dont_ask_again_button),
3284 				      FALSE);
3285 
3286 	gtk_box_pack_end (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
3287 			  dont_ask_again_button,
3288 			  TRUE,
3289 			  TRUE,
3290 			  0);
3291 
3292 	/* show dialog and get user response */
3293 	gtk_widget_show_all (dialog);
3294 	response = gtk_dialog_run (GTK_DIALOG (dialog));
3295 
3296 	/* only update the 'dont ask again' property if the user has accepted */
3297 	if (response == GTK_RESPONSE_OK)
3298 		dont_ask_again_force_delete = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dont_ask_again_button));
3299 
3300 	/* free resources */
3301 	g_free (prompt);
3302 	gtk_widget_destroy (dialog);
3303 
3304 	return response;
3305 }
3306 
3307 static gboolean
force_image_delete_real(EogImage * image,GError ** error)3308 force_image_delete_real (EogImage  *image,
3309 			 GError   **error)
3310 {
3311 	GFile     *file;
3312 	GFileInfo *file_info;
3313 	gboolean   can_delete;
3314 	gboolean   result;
3315 
3316 	g_return_val_if_fail (EOG_IS_IMAGE (image), FALSE);
3317 
3318 	/* retrieve image file */
3319 	file = eog_image_get_file (image);
3320 
3321 	if (file == NULL) {
3322 		g_set_error (error,
3323 			     EOG_WINDOW_ERROR,
3324 			     EOG_WINDOW_ERROR_IO,
3325 			     _("Couldn’t retrieve image file"));
3326 
3327 		return FALSE;
3328 	}
3329 
3330 	/* retrieve some image file information */
3331 	file_info = g_file_query_info (file,
3332 				       G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE,
3333 				       0,
3334 				       NULL,
3335 				       NULL);
3336 
3337 	if (file_info == NULL) {
3338 		g_set_error (error,
3339 			     EOG_WINDOW_ERROR,
3340 			     EOG_WINDOW_ERROR_IO,
3341 			     _("Couldn’t retrieve image file information"));
3342 
3343 		/* free resources */
3344 		g_object_unref (file);
3345 
3346 		return FALSE;
3347 	}
3348 
3349 	/* check that image file can be deleted */
3350 	can_delete = g_file_info_get_attribute_boolean (file_info,
3351 							G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE);
3352 
3353 	if (!can_delete) {
3354 		g_set_error (error,
3355 			     EOG_WINDOW_ERROR,
3356 			     EOG_WINDOW_ERROR_IO,
3357 			     _("Couldn’t delete file"));
3358 
3359 		/* free resources */
3360 		g_object_unref (file_info);
3361 		g_object_unref (file);
3362 
3363 		return FALSE;
3364 	}
3365 
3366 	/* delete image file */
3367 	result = g_file_delete (file,
3368 				NULL,
3369 				error);
3370 
3371 	/* free resources */
3372 	g_object_unref (file_info);
3373         g_object_unref (file);
3374 
3375 	return result;
3376 }
3377 
3378 static void
eog_window_force_image_delete(EogWindow * window,GList * images)3379 eog_window_force_image_delete (EogWindow *window,
3380 			       GList     *images)
3381 {
3382 	GList    *item;
3383 	gboolean  success;
3384 
3385 	g_return_if_fail (EOG_WINDOW (window));
3386 
3387 	/* force delete of each image of the list */
3388 	for (item = images; item != NULL; item = item->next) {
3389 		GError   *error;
3390 		EogImage *image;
3391 
3392 		error = NULL;
3393 		image = EOG_IMAGE (item->data);
3394 
3395 		success = force_image_delete_real (image, &error);
3396 
3397 		if (!success) {
3398 			GtkWidget *dialog;
3399 			gchar     *header;
3400 
3401 			/* set dialog error message */
3402 			header = g_strdup_printf (_("Error on deleting image %s"),
3403 						  eog_image_get_caption (image));
3404 
3405 			/* create dialog */
3406 			dialog = gtk_message_dialog_new (GTK_WINDOW (window),
3407 							 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
3408 							 GTK_MESSAGE_ERROR,
3409 							 GTK_BUTTONS_OK,
3410 							 "%s", header);
3411 
3412 			gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
3413 								  "%s",
3414 								  error->message);
3415 
3416 			/* show dialog */
3417 			gtk_dialog_run (GTK_DIALOG (dialog));
3418 
3419 			/* free resources */
3420 			gtk_widget_destroy (dialog);
3421 			g_free (header);
3422 
3423 			return;
3424 		}
3425 
3426 		/* remove image from store */
3427 		eog_list_store_remove_image (window->priv->store, image);
3428 	}
3429 
3430 	/* free list */
3431 	g_list_foreach (images, (GFunc) g_object_unref, NULL);
3432 	g_list_free    (images);
3433 }
3434 
3435 static void
eog_window_action_delete(GSimpleAction * action,GVariant * variant,gpointer user_data)3436 eog_window_action_delete (GSimpleAction *action,
3437 			  GVariant      *variant,
3438 			  gpointer       user_data)
3439 {
3440 	EogWindow *window;
3441 	GList     *images;
3442 	gint       result;
3443 
3444 	window = EOG_WINDOW (user_data);
3445 	images = eog_thumb_view_get_selected_images (EOG_THUMB_VIEW (window->priv->thumbview));
3446 	if (G_LIKELY (g_list_length (images) > 0))
3447 	{
3448 		result = show_force_image_delete_confirm_dialog (window, images);
3449 
3450 		if (result == GTK_RESPONSE_OK)
3451 			eog_window_force_image_delete (window, images);
3452 	}
3453 }
3454 
3455 static int
show_move_to_trash_confirm_dialog(EogWindow * window,GList * images,gboolean can_trash)3456 show_move_to_trash_confirm_dialog (EogWindow *window, GList *images, gboolean can_trash)
3457 {
3458 	GtkWidget *dlg;
3459 	char *prompt;
3460 	int response;
3461 	int n_images;
3462 	EogImage *image;
3463 	static gboolean dontaskagain = FALSE;
3464 	gboolean neverask = FALSE;
3465 	GtkWidget* dontask_cbutton = NULL;
3466 
3467 	/* Check if the user never wants to be bugged. */
3468 	neverask = g_settings_get_boolean (window->priv->ui_settings,
3469 					   EOG_CONF_UI_DISABLE_TRASH_CONFIRMATION);
3470 
3471 	/* Assume agreement, if the user doesn't want to be
3472 	 * asked and the trash is available */
3473 	if (can_trash && (dontaskagain || neverask))
3474 		return GTK_RESPONSE_OK;
3475 
3476 	n_images = g_list_length (images);
3477 
3478 	if (n_images == 1) {
3479 		image = EOG_IMAGE (images->data);
3480 		if (can_trash) {
3481 			prompt = g_strdup_printf (_("Are you sure you want to move\n“%s” to the trash?"),
3482 						  eog_image_get_caption (image));
3483 		} else {
3484 			prompt = g_strdup_printf (_("A trash for “%s” couldn’t be found. Do you want to remove "
3485 						    "this image permanently?"), eog_image_get_caption (image));
3486 		}
3487 	} else {
3488 		if (can_trash) {
3489 			prompt = g_strdup_printf (ngettext("Are you sure you want to move\n"
3490 							   "the selected image to the trash?",
3491 							   "Are you sure you want to move\n"
3492 							   "the %d selected images to the trash?", n_images), n_images);
3493 		} else {
3494 			prompt = g_strdup (_("Some of the selected images can’t be moved to the trash "
3495 					     "and will be removed permanently. Are you sure you want "
3496 					     "to proceed?"));
3497 		}
3498 	}
3499 
3500 	dlg = gtk_message_dialog_new_with_markup (GTK_WINDOW (window),
3501 						  GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
3502 						  GTK_MESSAGE_WARNING,
3503 						  GTK_BUTTONS_NONE,
3504 						  "<span weight=\"bold\" size=\"larger\">%s</span>",
3505 						  prompt);
3506 	g_free (prompt);
3507 
3508 	gtk_dialog_add_button (GTK_DIALOG (dlg), _("_Cancel"), GTK_RESPONSE_CANCEL);
3509 
3510 	if (can_trash) {
3511 		gtk_dialog_add_button (GTK_DIALOG (dlg), _("Move to _Trash"), GTK_RESPONSE_OK);
3512 
3513 		dontask_cbutton = gtk_check_button_new_with_mnemonic (_("Do _not ask again during this session"));
3514 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dontask_cbutton), FALSE);
3515 
3516 		gtk_box_pack_end (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), dontask_cbutton, TRUE, TRUE, 0);
3517 	} else {
3518 		if (n_images == 1) {
3519 			gtk_dialog_add_button (GTK_DIALOG (dlg), _("_Delete"), GTK_RESPONSE_OK);
3520 		} else {
3521 			gtk_dialog_add_button (GTK_DIALOG (dlg), _("_Yes"), GTK_RESPONSE_OK);
3522 		}
3523 	}
3524 
3525 	gtk_dialog_set_default_response (GTK_DIALOG (dlg), GTK_RESPONSE_OK);
3526 	gtk_window_set_title (GTK_WINDOW (dlg), "");
3527 	gtk_widget_show_all (dlg);
3528 
3529 	response = gtk_dialog_run (GTK_DIALOG (dlg));
3530 
3531 	/* Only update the property if the user has accepted */
3532 	if (can_trash && response == GTK_RESPONSE_OK)
3533 		dontaskagain = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dontask_cbutton));
3534 
3535 	/* The checkbutton is destroyed together with the dialog */
3536 	gtk_widget_destroy (dlg);
3537 
3538 	return response;
3539 }
3540 
3541 static gboolean
move_to_trash_real(EogImage * image,GError ** error)3542 move_to_trash_real (EogImage *image, GError **error)
3543 {
3544 	GFile *file;
3545 	GFileInfo *file_info;
3546 	gboolean can_trash, result;
3547 
3548 	g_return_val_if_fail (EOG_IS_IMAGE (image), FALSE);
3549 
3550 	file = eog_image_get_file (image);
3551 	file_info = g_file_query_info (file,
3552 				       G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH,
3553 				       0, NULL, NULL);
3554 	if (file_info == NULL) {
3555 		g_set_error (error,
3556 			     EOG_WINDOW_ERROR,
3557 			     EOG_WINDOW_ERROR_TRASH_NOT_FOUND,
3558 			     _("Couldn’t access trash."));
3559 		return FALSE;
3560 	}
3561 
3562 	can_trash = g_file_info_get_attribute_boolean (file_info,
3563 						       G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH);
3564 	g_object_unref (file_info);
3565 	if (can_trash)
3566 	{
3567 		result = g_file_trash (file, NULL, NULL);
3568 		if (result == FALSE) {
3569 			g_set_error (error,
3570 				     EOG_WINDOW_ERROR,
3571 				     EOG_WINDOW_ERROR_TRASH_NOT_FOUND,
3572 				     _("Couldn’t access trash."));
3573 		}
3574 	} else {
3575 		result = g_file_delete (file, NULL, NULL);
3576 		if (result == FALSE) {
3577 			g_set_error (error,
3578 				     EOG_WINDOW_ERROR,
3579 				     EOG_WINDOW_ERROR_IO,
3580 				     _("Couldn’t delete file"));
3581 		}
3582 	}
3583 
3584         g_object_unref (file);
3585 
3586 	return result;
3587 }
3588 
3589 static void
eog_window_action_copy_image(GSimpleAction * action,GVariant * variant,gpointer user_data)3590 eog_window_action_copy_image (GSimpleAction *action,
3591 			      GVariant      *variant,
3592 			      gpointer       user_data)
3593 {
3594 	GtkClipboard *clipboard;
3595 	EogWindow *window;
3596 	EogWindowPrivate *priv;
3597 	EogImage *image;
3598 	EogClipboardHandler *cbhandler;
3599 
3600 	g_return_if_fail (EOG_IS_WINDOW (user_data));
3601 
3602 	window = EOG_WINDOW (user_data);
3603 	priv = window->priv;
3604 
3605 	image = eog_thumb_view_get_first_selected_image (EOG_THUMB_VIEW (priv->thumbview));
3606 
3607 	g_return_if_fail (EOG_IS_IMAGE (image));
3608 
3609 	clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3610 
3611 	cbhandler = eog_clipboard_handler_new (image);
3612 	// cbhandler will self-destruct when it's not needed anymore
3613 	eog_clipboard_handler_copy_to_clipboard (cbhandler, clipboard);
3614 }
3615 
3616 static void
eog_window_action_move_to_trash(GSimpleAction * action,GVariant * variant,gpointer user_data)3617 eog_window_action_move_to_trash (GSimpleAction *action,
3618 				 GVariant      *variant,
3619 				 gpointer       user_data)
3620 {
3621 	GList *images;
3622 	GList *it;
3623 	EogWindowPrivate *priv;
3624 	EogListStore *list;
3625 	EogWindow *window;
3626 	int response;
3627 	int n_images;
3628 	gboolean success;
3629 	gboolean can_trash;
3630 
3631 	g_return_if_fail (EOG_IS_WINDOW (user_data));
3632 
3633 	window = EOG_WINDOW (user_data);
3634 	priv = window->priv;
3635 	list = priv->store;
3636 
3637 	n_images = eog_thumb_view_get_n_selected (EOG_THUMB_VIEW (priv->thumbview));
3638 
3639 	if (n_images < 1) return;
3640 
3641 	/* save position of selected image after the deletion */
3642 	images = eog_thumb_view_get_selected_images (EOG_THUMB_VIEW (priv->thumbview));
3643 
3644 	g_assert (images != NULL);
3645 
3646 	/* HACK: eog_list_store_get_n_selected return list in reverse order */
3647 	images = g_list_reverse (images);
3648 
3649 	can_trash = eog_window_all_images_trasheable (images);
3650 
3651 	if (g_ascii_strcasecmp (g_action_get_name (G_ACTION (action)), "Delete") == 0 ||
3652 	    can_trash == FALSE) {
3653 		response = show_move_to_trash_confirm_dialog (window, images, can_trash);
3654 
3655 		if (response != GTK_RESPONSE_OK) return;
3656 	}
3657 
3658 	/* FIXME: make a nice progress dialog */
3659 	/* Do the work actually. First try to delete the image from the disk. If this
3660 	 * is successful, remove it from the screen. Otherwise show error dialog.
3661 	 */
3662 	for (it = images; it != NULL; it = it->next) {
3663 		GError *error = NULL;
3664 		EogImage *image;
3665 
3666 		image = EOG_IMAGE (it->data);
3667 
3668 		success = move_to_trash_real (image, &error);
3669 
3670 		if (success) {
3671 			eog_list_store_remove_image (list, image);
3672 		} else {
3673 			char *header;
3674 			GtkWidget *dlg;
3675 
3676 			header = g_strdup_printf (_("Error on deleting image %s"),
3677 						  eog_image_get_caption (image));
3678 
3679 			dlg = gtk_message_dialog_new (GTK_WINDOW (window),
3680 						      GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
3681 						      GTK_MESSAGE_ERROR,
3682 						      GTK_BUTTONS_OK,
3683 						      "%s", header);
3684 
3685 			gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dlg),
3686 								  "%s", error->message);
3687 
3688 			gtk_dialog_run (GTK_DIALOG (dlg));
3689 
3690 			gtk_widget_destroy (dlg);
3691 
3692 			g_free (header);
3693 		}
3694 	}
3695 
3696 	/* free list */
3697 	g_list_foreach (images, (GFunc) g_object_unref, NULL);
3698 	g_list_free (images);
3699 }
3700 
3701 static void
eog_window_action_toggle_fullscreen(GSimpleAction * action,GVariant * state,gpointer user_data)3702 eog_window_action_toggle_fullscreen (GSimpleAction *action,
3703 				     GVariant      *state,
3704 				     gpointer       user_data)
3705 {
3706 	EogWindow *window;
3707 	gboolean fullscreen;
3708 
3709 	g_return_if_fail (EOG_IS_WINDOW (user_data));
3710 
3711 	eog_debug (DEBUG_WINDOW);
3712 
3713 	window = EOG_WINDOW (user_data);
3714 
3715 	fullscreen = g_variant_get_boolean (state);
3716 
3717 	if (fullscreen) {
3718 		eog_window_run_fullscreen (window, FALSE);
3719 	} else {
3720 		eog_window_stop_fullscreen (window, FALSE);
3721 	}
3722 }
3723 
3724 static void
eog_window_action_toggle_slideshow(GSimpleAction * action,GVariant * state,gpointer user_data)3725 eog_window_action_toggle_slideshow (GSimpleAction *action,
3726 				    GVariant      *state,
3727 				    gpointer       user_data)
3728 {
3729 	EogWindow *window;
3730 	gboolean slideshow;
3731 
3732 	g_return_if_fail (EOG_IS_WINDOW (user_data));
3733 
3734 	eog_debug (DEBUG_WINDOW);
3735 
3736 	window = EOG_WINDOW (user_data);
3737 
3738 	slideshow = g_variant_get_boolean (state);
3739 
3740 	if (slideshow) {
3741 		eog_window_run_fullscreen (window, TRUE);
3742 	} else {
3743 		eog_window_stop_fullscreen (window, TRUE);
3744 	}
3745 }
3746 
3747 static void
eog_window_action_pause_slideshow(GSimpleAction * action,GVariant * variant,gpointer user_data)3748 eog_window_action_pause_slideshow (GSimpleAction *action,
3749 				   GVariant      *variant,
3750 				   gpointer       user_data)
3751 {
3752 	EogWindow *window;
3753 	gboolean slideshow;
3754 
3755 	g_return_if_fail (EOG_IS_WINDOW (user_data));
3756 
3757 	eog_debug (DEBUG_WINDOW);
3758 
3759 	window = EOG_WINDOW (user_data);
3760 
3761 	slideshow = window->priv->mode == EOG_WINDOW_MODE_SLIDESHOW;
3762 
3763 	if (!slideshow && window->priv->mode != EOG_WINDOW_MODE_FULLSCREEN)
3764 		return;
3765 
3766 	eog_window_run_fullscreen (window, !slideshow);
3767 }
3768 
3769 static void
eog_window_action_zoom_in(GSimpleAction * action,GVariant * parameter,gpointer user_data)3770 eog_window_action_zoom_in (GSimpleAction *action,
3771                            GVariant      *parameter,
3772                            gpointer       user_data)
3773 {
3774 	EogWindowPrivate *priv;
3775 
3776 	g_return_if_fail (EOG_IS_WINDOW (user_data));
3777 
3778 	eog_debug (DEBUG_WINDOW);
3779 
3780 	priv = EOG_WINDOW (user_data)->priv;
3781 
3782 	if (priv->view) {
3783 		eog_scroll_view_zoom_in (EOG_SCROLL_VIEW (priv->view), FALSE);
3784 	}
3785 }
3786 
3787 static void
eog_window_action_zoom_out(GSimpleAction * action,GVariant * parameter,gpointer user_data)3788 eog_window_action_zoom_out (GSimpleAction *action,
3789                            GVariant      *parameter,
3790                            gpointer       user_data)
3791 {
3792 	EogWindowPrivate *priv;
3793 
3794 	g_return_if_fail (EOG_IS_WINDOW (user_data));
3795 
3796 	eog_debug (DEBUG_WINDOW);
3797 
3798 	priv = EOG_WINDOW (user_data)->priv;
3799 
3800 	if (priv->view) {
3801 		eog_scroll_view_zoom_out (EOG_SCROLL_VIEW (priv->view), FALSE);
3802 	}
3803 }
3804 
3805 static void
eog_window_action_zoom_normal(GSimpleAction * action,GVariant * variant,gpointer user_data)3806 eog_window_action_zoom_normal (GSimpleAction *action,
3807 			       GVariant      *variant,
3808 			       gpointer       user_data)
3809 {
3810 	EogWindowPrivate *priv;
3811 
3812 	g_return_if_fail (EOG_IS_WINDOW (user_data));
3813 
3814 	eog_debug (DEBUG_WINDOW);
3815 
3816 	priv = EOG_WINDOW (user_data)->priv;
3817 
3818 	if (priv->view) {
3819 		eog_scroll_view_set_zoom (EOG_SCROLL_VIEW (priv->view), 1.0);
3820 	}
3821 }
3822 
3823 static void
eog_window_action_toggle_zoom_fit(GSimpleAction * action,GVariant * state,gpointer user_data)3824 eog_window_action_toggle_zoom_fit (GSimpleAction *action,
3825 				   GVariant      *state,
3826 				   gpointer       user_data)
3827 {
3828 	EogWindowPrivate *priv;
3829 	EogZoomMode mode;
3830 
3831 	g_return_if_fail (EOG_IS_WINDOW (user_data));
3832 
3833 	eog_debug (DEBUG_WINDOW);
3834 
3835 	priv = EOG_WINDOW (user_data)->priv;
3836 
3837 	mode = g_variant_get_boolean (state)
3838 	       ? EOG_ZOOM_MODE_SHRINK_TO_FIT : EOG_ZOOM_MODE_FREE;
3839 
3840 	if (priv->view) {
3841 		eog_scroll_view_set_zoom_mode (EOG_SCROLL_VIEW (priv->view),
3842 					       mode);
3843 	}
3844 }
3845 
3846 static void
eog_window_action_go_prev(GSimpleAction * action,GVariant * parameter,gpointer user_data)3847 eog_window_action_go_prev (GSimpleAction *action,
3848                            GVariant      *parameter,
3849                            gpointer       user_data)
3850 {
3851 	EogWindowPrivate *priv;
3852 
3853 	g_return_if_fail (EOG_IS_WINDOW (user_data));
3854 
3855 	eog_debug (DEBUG_WINDOW);
3856 
3857 	priv = EOG_WINDOW (user_data)->priv;
3858 
3859 	eog_thumb_view_select_single (EOG_THUMB_VIEW (priv->thumbview),
3860 				      EOG_THUMB_VIEW_SELECT_LEFT);
3861 }
3862 
3863 static void
eog_window_action_go_next(GSimpleAction * action,GVariant * parameter,gpointer user_data)3864 eog_window_action_go_next (GSimpleAction *action,
3865                            GVariant      *parameter,
3866                            gpointer       user_data)
3867 {
3868 	EogWindowPrivate *priv;
3869 
3870 	g_return_if_fail (EOG_IS_WINDOW (user_data));
3871 
3872 	eog_debug (DEBUG_WINDOW);
3873 
3874 	priv = EOG_WINDOW (user_data)->priv;
3875 
3876 	eog_thumb_view_select_single (EOG_THUMB_VIEW (priv->thumbview),
3877 				      EOG_THUMB_VIEW_SELECT_RIGHT);
3878 }
3879 
3880 static void
eog_window_action_go_first(GSimpleAction * action,GVariant * parameter,gpointer user_data)3881 eog_window_action_go_first (GSimpleAction *action,
3882                             GVariant      *parameter,
3883                             gpointer       user_data)
3884 {
3885 	EogWindowPrivate *priv;
3886 
3887 	g_return_if_fail (EOG_IS_WINDOW (user_data));
3888 
3889 	eog_debug (DEBUG_WINDOW);
3890 
3891 	priv = EOG_WINDOW (user_data)->priv;
3892 
3893 	eog_thumb_view_select_single (EOG_THUMB_VIEW (priv->thumbview),
3894 				      EOG_THUMB_VIEW_SELECT_FIRST);
3895 }
3896 
3897 static void
eog_window_action_go_last(GSimpleAction * action,GVariant * parameter,gpointer user_data)3898 eog_window_action_go_last (GSimpleAction *action,
3899                            GVariant      *parameter,
3900                            gpointer       user_data)
3901 {
3902 	EogWindowPrivate *priv;
3903 
3904 	g_return_if_fail (EOG_IS_WINDOW (user_data));
3905 
3906 	eog_debug (DEBUG_WINDOW);
3907 
3908 	priv = EOG_WINDOW (user_data)->priv;
3909 
3910 	eog_thumb_view_select_single (EOG_THUMB_VIEW (priv->thumbview),
3911 				      EOG_THUMB_VIEW_SELECT_LAST);
3912 }
3913 
3914 static void
eog_window_action_go_random(GSimpleAction * action,GVariant * parameter,gpointer user_data)3915 eog_window_action_go_random (GSimpleAction *action,
3916                              GVariant      *parameter,
3917                              gpointer       user_data)
3918 {
3919 	EogWindowPrivate *priv;
3920 
3921 	g_return_if_fail (EOG_IS_WINDOW (user_data));
3922 
3923 	eog_debug (DEBUG_WINDOW);
3924 
3925 	priv = EOG_WINDOW (user_data)->priv;
3926 
3927 	eog_thumb_view_select_single (EOG_THUMB_VIEW (priv->thumbview),
3928 				      EOG_THUMB_VIEW_SELECT_RANDOM);
3929 }
3930 
3931 static void
eog_window_action_set_zoom(GSimpleAction * action,GVariant * parameter,gpointer user_data)3932 eog_window_action_set_zoom (GSimpleAction *action,
3933                             GVariant      *parameter,
3934                             gpointer       user_data)
3935 {
3936 	EogWindow *window;
3937 	double zoom;
3938 
3939 	g_return_if_fail (EOG_IS_WINDOW (user_data));
3940 	g_return_if_fail (g_variant_is_of_type (parameter, G_VARIANT_TYPE_DOUBLE));
3941 
3942 	window = EOG_WINDOW (user_data);
3943 
3944 	zoom = g_variant_get_double (parameter);
3945 
3946 	eog_debug_message (DEBUG_WINDOW, "Set zoom factor to %.4lf", zoom);
3947 
3948 	if (window->priv->view) {
3949 		eog_scroll_view_set_zoom (EOG_SCROLL_VIEW (window->priv->view),
3950 		                          zoom);
3951 	}
3952 }
3953 
3954 static void
readonly_state_handler(GSimpleAction * action,GVariant * value,gpointer user_data)3955 readonly_state_handler (GSimpleAction *action,
3956                         GVariant      *value,
3957                         gpointer       user_data)
3958 {
3959 	g_warning ("The state of action \"%s\" is read-only! Ignoring request!",
3960 	           g_action_get_name (G_ACTION (action)));
3961 }
3962 
3963 static const GActionEntry window_actions[] = {
3964 	/* Stateless actions on the window. */
3965 	{ "open",          eog_window_action_file_open },
3966 	{ "open-with",     eog_window_action_open_with },
3967 	{ "open-folder",   eog_window_action_open_containing_folder },
3968 	{ "save",          eog_window_action_save },
3969 	{ "save-as",       eog_window_action_save_as },
3970 	{ "close",         eog_window_action_close_window },
3971 	{ "close-all",     eog_window_action_close_all_windows },
3972 	{ "print",         eog_window_action_print },
3973 	{ "properties",    eog_window_action_properties },
3974 	{ "set-wallpaper", eog_window_action_wallpaper },
3975 	{ "preferences",   eog_window_action_preferences },
3976 	{ "manual",        eog_window_action_help },
3977 	{ "about",         eog_window_action_about },
3978 
3979 	/* Stateless actions on the image. */
3980 	{ "go-previous",     eog_window_action_go_prev },
3981 	{ "go-next",         eog_window_action_go_next },
3982 	{ "go-first",        eog_window_action_go_first },
3983 	{ "go-last",         eog_window_action_go_last },
3984 	{ "go-random",       eog_window_action_go_random },
3985 	{ "rotate-90",       eog_window_action_rotate_90 },
3986 	{ "rotate-270",      eog_window_action_rotate_270 },
3987 	{ "flip-horizontal", eog_window_action_flip_horizontal },
3988 	{ "flip-vertical",   eog_window_action_flip_vertical },
3989 	{ "move-trash",      eog_window_action_move_to_trash },
3990 	{ "delete",          eog_window_action_delete },
3991 	{ "copy",            eog_window_action_copy_image },
3992 	{ "undo",            eog_window_action_undo },
3993 	{ "zoom-in",         eog_window_action_zoom_in },
3994 	{ "zoom-out",        eog_window_action_zoom_out },
3995 	{ "zoom-normal",     eog_window_action_zoom_normal },
3996 	{ "zoom-set",        eog_window_action_set_zoom, "d" },
3997 
3998 	/* Stateful actions. */
3999 	{ "current-image",   NULL, NULL, "@(ii) (0, 0)", readonly_state_handler },
4000 	{ "view-statusbar",  NULL, NULL, "true",  eog_window_action_show_hide_bar },
4001 	{ "view-gallery",    NULL, NULL, "true",  eog_window_action_show_hide_bar },
4002 	{ "view-sidebar",    NULL, NULL, "true",  eog_window_action_show_hide_bar },
4003 	{ "view-slideshow",  NULL, NULL, "false", eog_window_action_toggle_slideshow },
4004 	{ "view-fullscreen", NULL, NULL, "false", eog_window_action_toggle_fullscreen },
4005 	{ "pause-slideshow", NULL, NULL, "false", eog_window_action_pause_slideshow },
4006 	{ "toggle-zoom-fit", NULL, NULL, "true",  eog_window_action_toggle_zoom_fit },
4007 };
4008 
4009 static void
eog_window_ui_settings_changed_cb(GSettings * settings,gchar * key,gpointer user_data)4010 eog_window_ui_settings_changed_cb (GSettings *settings,
4011 				   gchar     *key,
4012 				   gpointer   user_data)
4013 {
4014 	GVariant *new_state = NULL;
4015 	GVariant *old_state;
4016 	GAction *action;
4017 
4018 	g_return_if_fail (G_IS_ACTION (user_data));
4019 
4020 	action = G_ACTION (user_data);
4021 
4022 	new_state = g_settings_get_value (settings, key);
4023 	g_assert (new_state != NULL);
4024 
4025 	old_state = g_action_get_state (action);
4026 
4027 	if (g_variant_get_boolean (new_state) != g_variant_get_boolean (old_state))
4028 		g_action_change_state (action, new_state);
4029 
4030 	g_variant_unref (new_state);
4031 }
4032 
4033 static void
eog_window_drag_data_received(GtkWidget * widget,GdkDragContext * context,gint x,gint y,GtkSelectionData * selection_data,guint info,guint time)4034 eog_window_drag_data_received (GtkWidget *widget,
4035                                GdkDragContext *context,
4036                                gint x, gint y,
4037                                GtkSelectionData *selection_data,
4038                                guint info, guint time)
4039 {
4040         GSList *file_list;
4041         EogWindow *window;
4042 	GdkAtom target;
4043 	GtkWidget *src;
4044 
4045 	target = gtk_selection_data_get_target (selection_data);
4046 
4047         if (!gtk_targets_include_uri (&target, 1))
4048                 return;
4049 
4050 	/* if the request is from another process this will return NULL */
4051 	src = gtk_drag_get_source_widget (context);
4052 
4053 	/* if the drag request originates from the current eog instance, ignore
4054 	   the request if the source window is the same as the dest window */
4055 	if (src &&
4056 	    gtk_widget_get_toplevel (src) == gtk_widget_get_toplevel (widget))
4057 	{
4058 		gdk_drag_status (context, 0, time);
4059 		return;
4060 	}
4061 
4062         if (gdk_drag_context_get_suggested_action (context) == GDK_ACTION_COPY)
4063         {
4064                 window = EOG_WINDOW (widget);
4065 
4066                 file_list = eog_util_parse_uri_string_list_to_file_list ((const gchar *) gtk_selection_data_get_data (selection_data));
4067 
4068 		eog_window_open_file_list (window, file_list);
4069         }
4070 }
4071 
4072 static void
eog_window_set_drag_dest(EogWindow * window)4073 eog_window_set_drag_dest (EogWindow *window)
4074 {
4075         gtk_drag_dest_set (GTK_WIDGET (window),
4076                            GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
4077                            NULL, 0,
4078                            GDK_ACTION_COPY | GDK_ACTION_ASK);
4079 	gtk_drag_dest_add_uri_targets (GTK_WIDGET (window));
4080 }
4081 
4082 static void
eog_window_sidebar_visibility_changed(GtkWidget * widget,EogWindow * window)4083 eog_window_sidebar_visibility_changed (GtkWidget *widget, EogWindow *window)
4084 {
4085 	GAction *action;
4086 	GVariant *state;
4087 	gboolean visible;
4088 	gboolean active;
4089 
4090 	visible = gtk_widget_get_visible (window->priv->sidebar);
4091 
4092 	action = g_action_map_lookup_action (G_ACTION_MAP (window),
4093 					      "view-sidebar");
4094 
4095 	state = g_action_get_state (action);
4096 	active = g_variant_get_boolean (state);
4097 	if (active != visible)
4098 		g_action_change_state (action,
4099 				       g_variant_new_boolean (visible));
4100 	g_variant_unref (state);
4101 
4102 	/* Focus the image */
4103 	if (!visible && window->priv->image != NULL)
4104 		gtk_widget_grab_focus (window->priv->view);
4105 }
4106 
4107 static void
eog_window_sidebar_page_added(EogSidebar * sidebar,GtkWidget * main_widget,EogWindow * window)4108 eog_window_sidebar_page_added (EogSidebar  *sidebar,
4109 			       GtkWidget   *main_widget,
4110 			       EogWindow   *window)
4111 {
4112 	if (eog_sidebar_get_n_pages (sidebar) == 1) {
4113 		GAction *action;
4114 		GVariant *state;
4115 		gboolean show;
4116 
4117 		action = g_action_map_lookup_action (G_ACTION_MAP (window),
4118 						      "view-sidebar");
4119 
4120 		g_simple_action_set_enabled (G_SIMPLE_ACTION (action), TRUE);
4121 
4122 		state = g_action_get_state (action);
4123 		show = g_variant_get_boolean (state);
4124 
4125 		if (show)
4126 			gtk_widget_show (GTK_WIDGET (sidebar));
4127 
4128 		g_variant_unref (state);
4129 	}
4130 }
4131 
4132 static void
eog_window_sidebar_page_removed(EogSidebar * sidebar,GtkWidget * main_widget,EogWindow * window)4133 eog_window_sidebar_page_removed (EogSidebar  *sidebar,
4134 			         GtkWidget   *main_widget,
4135 			         EogWindow   *window)
4136 {
4137 	if (eog_sidebar_is_empty (sidebar)) {
4138 		GAction *action;
4139 
4140 		gtk_widget_hide (GTK_WIDGET (sidebar));
4141 
4142 		action = g_action_map_lookup_action (G_ACTION_MAP (window),
4143 						      "view-sidebar");
4144 
4145 		g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
4146 	}
4147 }
4148 
4149 static void
eog_window_finish_saving(EogWindow * window)4150 eog_window_finish_saving (EogWindow *window)
4151 {
4152 	EogWindowPrivate *priv = window->priv;
4153 
4154 	gtk_widget_set_sensitive (GTK_WIDGET (window), FALSE);
4155 
4156 	do {
4157 		gtk_main_iteration ();
4158 	} while (priv->save_job != NULL);
4159 }
4160 
4161 static void
eog_window_view_rotation_changed_cb(EogScrollView * view,gdouble degrees,EogWindow * window)4162 eog_window_view_rotation_changed_cb (EogScrollView *view,
4163 				     gdouble        degrees,
4164 				     EogWindow     *window)
4165 {
4166 	apply_transformation (window, eog_transform_rotate_new (degrees));
4167 }
4168 
4169 static void
eog_window_view_next_image_cb(EogScrollView * view,EogWindow * window)4170 eog_window_view_next_image_cb (EogScrollView *view,
4171 			       EogWindow     *window)
4172 {
4173 	eog_window_action_go_next (NULL, NULL, window);
4174 }
4175 
4176 static void
eog_window_view_previous_image_cb(EogScrollView * view,EogWindow * window)4177 eog_window_view_previous_image_cb (EogScrollView *view,
4178 				   EogWindow     *window)
4179 {
4180 	eog_window_action_go_prev (NULL, NULL, window);
4181 }
4182 
4183 static void
eog_window_construct_ui(EogWindow * window)4184 eog_window_construct_ui (EogWindow *window)
4185 {
4186 	EogWindowPrivate *priv;
4187 
4188 	GtkBuilder *builder;
4189 	GAction *action = NULL;
4190 	GObject *builder_object;
4191 
4192 	GtkWidget *popup_menu;
4193 	GtkWidget *hpaned;
4194 	GtkWidget *headerbar;
4195 	GtkWidget *zoom_entry;
4196 	GtkWidget *menu_button;
4197 	GtkWidget *menu_image;
4198 	GtkWidget *fullscreen_button;
4199 
4200 	g_return_if_fail (EOG_IS_WINDOW (window));
4201 
4202 	priv = window->priv;
4203 
4204 	priv->box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
4205 	gtk_container_add (GTK_CONTAINER (window), priv->box);
4206 	gtk_widget_show (priv->box);
4207 
4208 	headerbar = gtk_header_bar_new ();
4209 	gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (headerbar), TRUE);
4210 	gtk_header_bar_set_title (GTK_HEADER_BAR (headerbar),
4211 				  g_get_application_name ());
4212 	gtk_window_set_titlebar (GTK_WINDOW (window), headerbar);
4213 	gtk_widget_show (headerbar);
4214 
4215 #if 0
4216 	zoom_button = gtk_toggle_button_new ();
4217 	zoom_image = gtk_image_new_from_icon_name ("zoom-in-symbolic",
4218 						   GTK_ICON_SIZE_BUTTON);
4219 	gtk_button_set_image (GTK_BUTTON (zoom_button), zoom_image);
4220 	gtk_widget_set_tooltip_text (zoom_button,
4221 				     _("Shrink or enlarge the current image"));
4222 	g_signal_connect (zoom_button, "toggled",
4223 			  G_CALLBACK (eog_window_zoom_button_toggled_cb),
4224 			  window);
4225 	gtk_header_bar_pack_start (GTK_HEADER_BAR (headerbar), zoom_button);
4226 	/* disable zoom button if no image is loaded */
4227 	g_object_bind_property (g_action_map_lookup_action (G_ACTION_MAP(window),
4228 							    "zoom-normal"),
4229 				"enabled", zoom_button, "sensitive",
4230 				G_BINDING_DEFAULT);
4231 	gtk_widget_show (zoom_button);
4232 
4233 	priv->zoom_revealer = gtk_revealer_new ();
4234 	gtk_revealer_set_transition_type (GTK_REVEALER (priv->zoom_revealer),
4235 					  GTK_REVEALER_TRANSITION_TYPE_SLIDE_RIGHT);
4236 	gtk_header_bar_pack_start (GTK_HEADER_BAR (headerbar),
4237 				   priv->zoom_revealer);
4238 	gtk_widget_show (priv->zoom_revealer);
4239 
4240 	priv->zoom_scale = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL,
4241 						     0.3, 3.0, 0.1);
4242 	gtk_scale_set_draw_value (GTK_SCALE (priv->zoom_scale), FALSE);
4243 	/* Add a stop mark at 100% */
4244 	gtk_scale_add_mark (GTK_SCALE (priv->zoom_scale),
4245 			    1.0, GTK_POS_BOTTOM, NULL);
4246 	/* TODO: the scale by itself does not take any width, so we manually
4247 	 * set it here. Decide on the optimal value. */
4248 	gtk_widget_set_size_request (priv->zoom_scale, 200, -1);
4249 	g_signal_connect (priv->zoom_scale, "value-changed",
4250 			  G_CALLBACK (eog_window_zoom_scale_value_changed_cb),
4251 			  window);
4252 	gtk_container_add (GTK_CONTAINER (priv->zoom_revealer),
4253 			   priv->zoom_scale);
4254 	gtk_widget_show (priv->zoom_scale);
4255 #endif
4256 
4257 	menu_button = gtk_menu_button_new ();
4258 	menu_image = gtk_image_new_from_icon_name ("open-menu-symbolic",
4259 						   GTK_ICON_SIZE_BUTTON);
4260 	gtk_button_set_image (GTK_BUTTON (menu_button), menu_image);
4261 
4262 	builder = gtk_builder_new_from_resource ("/org/gnome/eog/ui/eog-gear-menu.ui");
4263 	builder_object = gtk_builder_get_object (builder, "gear-menu");
4264 	gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (menu_button),
4265 					G_MENU_MODEL (builder_object));
4266 
4267 	gtk_header_bar_pack_end (GTK_HEADER_BAR (headerbar), menu_button);
4268 	gtk_widget_show (menu_button);
4269 
4270 	action = G_ACTION (g_property_action_new ("toggle-gear-menu",
4271 						  menu_button, "active"));
4272 	g_action_map_add_action (G_ACTION_MAP (window), action);
4273 	g_object_unref (action);
4274 
4275 	fullscreen_button = gtk_button_new_from_icon_name ("view-fullscreen-symbolic",
4276 							   GTK_ICON_SIZE_BUTTON);
4277 	gtk_actionable_set_action_name (GTK_ACTIONABLE (fullscreen_button),
4278 					"win.view-fullscreen");
4279 	gtk_widget_set_tooltip_text(fullscreen_button,
4280 				    _("Show the current image in fullscreen mode"));
4281 	gtk_header_bar_pack_end (GTK_HEADER_BAR (headerbar), fullscreen_button);
4282 	gtk_widget_show (fullscreen_button);
4283 
4284 	priv->gear_menu_builder = builder;
4285 	builder = NULL;
4286 
4287 	priv->cbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
4288 	gtk_box_pack_start (GTK_BOX (priv->box), priv->cbox, TRUE, TRUE, 0);
4289 	gtk_widget_show (priv->cbox);
4290 
4291 	priv->statusbar = eog_statusbar_new ();
4292 	gtk_box_pack_end (GTK_BOX (priv->box),
4293 			  GTK_WIDGET (priv->statusbar),
4294 			  FALSE, FALSE, 0);
4295 	gtk_widget_show (priv->statusbar);
4296 
4297 	priv->image_info_message_cid =
4298 		gtk_statusbar_get_context_id (GTK_STATUSBAR (priv->statusbar),
4299 					      "image_info_message");
4300 	priv->tip_message_cid =
4301 		gtk_statusbar_get_context_id (GTK_STATUSBAR (priv->statusbar),
4302 					      "tip_message");
4303 
4304 	hpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
4305 
4306 	priv->sidebar = eog_sidebar_new ();
4307 	/* The sidebar shouldn't be shown automatically on show_all(),
4308 	   but only when the user actually wants it. */
4309 	gtk_widget_set_no_show_all (priv->sidebar, TRUE);
4310 
4311 	gtk_widget_set_size_request (priv->sidebar, 210, -1);
4312 
4313 	g_signal_connect_after (priv->sidebar,
4314 				"show",
4315 				G_CALLBACK (eog_window_sidebar_visibility_changed),
4316 				window);
4317 
4318 	g_signal_connect_after (priv->sidebar,
4319 				"hide",
4320 				G_CALLBACK (eog_window_sidebar_visibility_changed),
4321 				window);
4322 
4323 	g_signal_connect_after (priv->sidebar,
4324 				"page-added",
4325 				G_CALLBACK (eog_window_sidebar_page_added),
4326 				window);
4327 
4328 	g_signal_connect_after (priv->sidebar,
4329 				"page-removed",
4330 				G_CALLBACK (eog_window_sidebar_page_removed),
4331 				window);
4332 	priv->overlay = gtk_overlay_new();
4333 
4334  	priv->view = eog_scroll_view_new ();
4335 	g_signal_connect (priv->view,
4336 			  "rotation-changed",
4337 			  G_CALLBACK (eog_window_view_rotation_changed_cb),
4338 			  window);
4339 	g_signal_connect (priv->view,
4340 			  "next-image",
4341 			  G_CALLBACK (eog_window_view_next_image_cb),
4342 			  window);
4343 	g_signal_connect (priv->view,
4344 			  "previous-image",
4345 			  G_CALLBACK (eog_window_view_previous_image_cb),
4346 			  window);
4347 
4348 	gtk_container_add (GTK_CONTAINER(priv->overlay), priv->view);
4349 
4350 	eog_sidebar_add_page (EOG_SIDEBAR (priv->sidebar),
4351 			      _("Properties"),
4352 			      GTK_WIDGET (eog_metadata_sidebar_new (window)));
4353 
4354 	gtk_widget_set_size_request (GTK_WIDGET (priv->view), 100, 100);
4355 	g_signal_connect (G_OBJECT (priv->view),
4356 			  "zoom_changed",
4357 			  G_CALLBACK (view_zoom_changed_cb),
4358 			  window);
4359 	action = g_action_map_lookup_action (G_ACTION_MAP (window),
4360 					     "toggle-zoom-fit");
4361 	if (action != NULL) {
4362 		/* Binding will be destroyed when the objects finalize */
4363 		g_object_bind_property_full (priv->view, "zoom-mode",
4364 					     action, "state",
4365 					     G_BINDING_SYNC_CREATE,
4366 					     _eog_zoom_shrink_to_boolean,
4367 					     NULL, NULL, NULL);
4368 	}
4369 	g_settings_bind (priv->view_settings, EOG_CONF_VIEW_SCROLL_WHEEL_ZOOM,
4370 			 priv->view, "scrollwheel-zoom", G_SETTINGS_BIND_GET);
4371 	g_settings_bind (priv->view_settings, EOG_CONF_VIEW_ZOOM_MULTIPLIER,
4372 			 priv->view, "zoom-multiplier", G_SETTINGS_BIND_GET);
4373 
4374 	builder = gtk_builder_new_from_resource ("/org/gnome/eog/ui/popup-menus.ui");
4375 	builder_object = gtk_builder_get_object (builder, "view-popup-menu");
4376 
4377 	popup_menu = gtk_menu_new_from_model (G_MENU_MODEL (builder_object));
4378 
4379 	eog_scroll_view_set_popup (EOG_SCROLL_VIEW (priv->view),
4380 				   GTK_MENU (popup_menu));
4381 
4382 	g_object_unref (popup_menu);
4383 
4384 	gtk_paned_pack1 (GTK_PANED (hpaned),
4385 			 priv->overlay,
4386 			 TRUE,
4387 			 FALSE);
4388 	gtk_paned_pack2 (GTK_PANED (hpaned),
4389 			 priv->sidebar,
4390 			 FALSE,
4391 			 FALSE);
4392 
4393 	gtk_widget_show_all (hpaned);
4394 
4395 	zoom_entry = eog_zoom_entry_new (EOG_SCROLL_VIEW (priv->view),
4396 	                                 G_MENU (gtk_builder_get_object (builder,
4397 	                                                                 "zoom-menu")));
4398 	gtk_header_bar_pack_start (GTK_HEADER_BAR (headerbar), zoom_entry);
4399 
4400 	priv->thumbview = g_object_ref (eog_thumb_view_new ());
4401 
4402 	/* giving shape to the view */
4403 	gtk_icon_view_set_margin (GTK_ICON_VIEW (priv->thumbview), 4);
4404 	gtk_icon_view_set_row_spacing (GTK_ICON_VIEW (priv->thumbview), 0);
4405 
4406 	g_signal_connect (G_OBJECT (priv->thumbview), "selection_changed",
4407 			  G_CALLBACK (handle_image_selection_changed_cb), window);
4408 
4409 	priv->nav = eog_thumb_nav_new (priv->thumbview,
4410 				       EOG_THUMB_NAV_MODE_ONE_ROW,
4411 				       g_settings_get_boolean (priv->ui_settings,
4412 							       EOG_CONF_UI_SCROLL_BUTTONS));
4413 
4414 	// Bind the scroll buttons to their GSettings key
4415 	g_settings_bind (priv->ui_settings, EOG_CONF_UI_SCROLL_BUTTONS,
4416 			 priv->nav, "show-buttons", G_SETTINGS_BIND_GET);
4417 
4418 	// Re-use the scroll view's popup menu model for the thumb view
4419 	popup_menu = gtk_menu_new_from_model (G_MENU_MODEL(builder_object));
4420 	eog_thumb_view_set_thumbnail_popup (EOG_THUMB_VIEW (priv->thumbview),
4421 					    GTK_MENU (popup_menu));
4422 
4423 	g_object_unref (popup_menu);
4424 	g_clear_object (&builder);
4425 
4426 	// Setup priv->layout
4427 	eog_window_set_gallery_mode (window, priv->gallery_position, priv->gallery_resizable);
4428 
4429 	g_settings_bind (priv->ui_settings, EOG_CONF_UI_IMAGE_GALLERY_POSITION,
4430 			 window, "gallery-position", G_SETTINGS_BIND_GET);
4431 	g_settings_bind (priv->ui_settings, EOG_CONF_UI_IMAGE_GALLERY_RESIZABLE,
4432 			 window, "gallery-resizable", G_SETTINGS_BIND_GET);
4433 
4434 	g_signal_connect (priv->lockdown_settings,
4435 			  "changed::" EOG_CONF_DESKTOP_CAN_SAVE,
4436 			  G_CALLBACK (eog_window_can_save_changed_cb), window);
4437 	// Call callback once to have the value set
4438 	eog_window_can_save_changed_cb (priv->lockdown_settings,
4439 					EOG_CONF_DESKTOP_CAN_SAVE, window);
4440 
4441 	update_action_groups_state (window);
4442 
4443 	if ((priv->flags & EOG_STARTUP_FULLSCREEN) ||
4444 	    (priv->flags & EOG_STARTUP_SLIDE_SHOW)) {
4445 		eog_window_run_fullscreen (window, (priv->flags & EOG_STARTUP_SLIDE_SHOW));
4446 	} else {
4447 		priv->mode = EOG_WINDOW_MODE_NORMAL;
4448 		update_ui_visibility (window);
4449 	}
4450 
4451 	eog_window_set_drag_dest (window);
4452 }
4453 
4454 static void
eog_window_init(EogWindow * window)4455 eog_window_init (EogWindow *window)
4456 {
4457 	GdkGeometry hints;
4458 	EogWindowPrivate *priv;
4459 	GAction* action;
4460 
4461 	eog_debug (DEBUG_WINDOW);
4462 
4463 	hints.min_width  = EOG_WINDOW_MIN_WIDTH;
4464 	hints.min_height = EOG_WINDOW_MIN_HEIGHT;
4465 
4466 	priv = window->priv = eog_window_get_instance_private (window);
4467 
4468 	priv->fullscreen_settings = g_settings_new (EOG_CONF_FULLSCREEN);
4469 	priv->ui_settings = g_settings_new (EOG_CONF_UI);
4470 	priv->view_settings = g_settings_new (EOG_CONF_VIEW);
4471 	priv->lockdown_settings = g_settings_new (EOG_CONF_DESKTOP_LOCKDOWN_SCHEMA);
4472 
4473 	window->priv->file_list = NULL;
4474 	window->priv->store = NULL;
4475 	window->priv->image = NULL;
4476 
4477 	window->priv->fullscreen_popup = NULL;
4478 	window->priv->fullscreen_timeout_source = NULL;
4479 	window->priv->slideshow_loop = FALSE;
4480 	window->priv->slideshow_switch_timeout = 0;
4481 	window->priv->slideshow_switch_source = NULL;
4482 	window->priv->fullscreen_idle_inhibit_cookie = 0;
4483 
4484 	gtk_window_set_geometry_hints (GTK_WINDOW (window),
4485 				       GTK_WIDGET (window),
4486 				       &hints,
4487 				       GDK_HINT_MIN_SIZE);
4488 
4489 	gtk_window_set_default_size (GTK_WINDOW (window),
4490 				     EOG_WINDOW_DEFAULT_WIDTH,
4491 				     EOG_WINDOW_DEFAULT_HEIGHT);
4492 
4493 	gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
4494 
4495 	window->priv->mode = EOG_WINDOW_MODE_UNKNOWN;
4496 	window->priv->status = EOG_WINDOW_STATUS_UNKNOWN;
4497 
4498 #if defined(HAVE_LCMS) && defined(GDK_WINDOWING_X11)
4499 	window->priv->display_profile =
4500 		eog_window_get_display_profile (GTK_WIDGET (window));
4501 #endif
4502 
4503 	window->priv->gallery_position = EOG_WINDOW_GALLERY_POS_BOTTOM;
4504 	window->priv->gallery_resizable = FALSE;
4505 
4506 	window->priv->save_disabled = FALSE;
4507 
4508 	window->priv->page_setup = NULL;
4509 
4510 	gtk_window_set_application (GTK_WINDOW (window), GTK_APPLICATION (EOG_APP));
4511 
4512 	g_action_map_add_action_entries (G_ACTION_MAP (window),
4513 	                                 window_actions, G_N_ELEMENTS (window_actions),
4514 	                                 window);
4515 
4516 	/* Creating a binding between the ui settings and the related GActions does
4517 	 * not trigger the state changed handler since the state is updated directly
4518 	 * via the "state" property. Requesting a state change via these callbacks,
4519 	 * however, works. */
4520 	g_signal_connect (priv->ui_settings, "changed::"EOG_CONF_UI_IMAGE_GALLERY,
4521 					  G_CALLBACK (eog_window_ui_settings_changed_cb),
4522 					  g_action_map_lookup_action (G_ACTION_MAP (window), "view-gallery"));
4523 
4524 	g_signal_connect (priv->ui_settings, "changed::"EOG_CONF_UI_SIDEBAR,
4525 					  G_CALLBACK (eog_window_ui_settings_changed_cb),
4526 					  g_action_map_lookup_action (G_ACTION_MAP (window), "view-sidebar"));
4527 
4528 	g_signal_connect (priv->ui_settings, "changed::"EOG_CONF_UI_STATUSBAR,
4529 					  G_CALLBACK (eog_window_ui_settings_changed_cb),
4530 					  g_action_map_lookup_action (G_ACTION_MAP (window), "view-statusbar"));
4531 
4532 	action = g_action_map_lookup_action (G_ACTION_MAP (window),
4533 	                                     "current-image");
4534 	if (G_LIKELY (action != NULL))
4535 		g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
4536 
4537 	if (g_strcmp0 (PROFILE, "") != 0) {
4538 		GtkStyleContext *style_context;
4539 
4540 		style_context = gtk_widget_get_style_context (GTK_WIDGET (window));
4541 		gtk_style_context_add_class (style_context, "devel");
4542 	}
4543 }
4544 
4545 static void
eog_window_dispose(GObject * object)4546 eog_window_dispose (GObject *object)
4547 {
4548 	EogWindow *window;
4549 	EogWindowPrivate *priv;
4550 
4551 	g_return_if_fail (object != NULL);
4552 	g_return_if_fail (EOG_IS_WINDOW (object));
4553 
4554 	eog_debug (DEBUG_WINDOW);
4555 
4556 	window = EOG_WINDOW (object);
4557 	priv = window->priv;
4558 
4559 	peas_engine_garbage_collect (PEAS_ENGINE (EOG_APP->priv->plugin_engine));
4560 
4561 	if (priv->extensions != NULL) {
4562 		g_object_unref (priv->extensions);
4563 		priv->extensions = NULL;
4564 		peas_engine_garbage_collect (PEAS_ENGINE (EOG_APP->priv->plugin_engine));
4565 	}
4566 
4567 	if (priv->store != NULL) {
4568 		g_signal_handlers_disconnect_by_func (priv->store,
4569 					      eog_window_list_store_image_added,
4570 					      window);
4571 		g_signal_handlers_disconnect_by_func (priv->store,
4572 					    eog_window_list_store_image_removed,
4573 					    window);
4574 		g_object_unref (priv->store);
4575 		priv->store = NULL;
4576 	}
4577 
4578 	if (priv->image != NULL) {
4579 	  	g_signal_handlers_disconnect_by_func (priv->image,
4580 						      image_thumb_changed_cb,
4581 						      window);
4582 		g_signal_handlers_disconnect_by_func (priv->image,
4583 						      image_file_changed_cb,
4584 						      window);
4585 		g_object_unref (priv->image);
4586 		priv->image = NULL;
4587 	}
4588 
4589 	fullscreen_clear_timeout (window);
4590 
4591 	if (window->priv->fullscreen_popup != NULL) {
4592 		gtk_widget_destroy (priv->fullscreen_popup);
4593 		priv->fullscreen_popup = NULL;
4594 	}
4595 
4596 	slideshow_clear_timeout (window);
4597 	eog_window_uninhibit_screensaver (window);
4598 
4599 	eog_window_clear_load_job (window);
4600 
4601 	eog_window_clear_transform_job (window);
4602 
4603 	if (priv->view_settings) {
4604 		g_object_unref (priv->view_settings);
4605 		priv->view_settings = NULL;
4606 	}
4607 
4608 	if (priv->ui_settings) {
4609 		g_object_unref (priv->ui_settings);
4610 		priv->ui_settings = NULL;
4611 	}
4612 
4613 	if (priv->fullscreen_settings) {
4614 		g_object_unref (priv->fullscreen_settings);
4615 		priv->fullscreen_settings = NULL;
4616 	}
4617 
4618 	if (priv->lockdown_settings) {
4619 		g_object_unref (priv->lockdown_settings);
4620 		priv->lockdown_settings = NULL;
4621 	}
4622 
4623 	if (priv->file_list != NULL) {
4624 		g_slist_foreach (priv->file_list, (GFunc) g_object_unref, NULL);
4625 		g_slist_free (priv->file_list);
4626 		priv->file_list = NULL;
4627 	}
4628 
4629 #ifdef HAVE_LCMS
4630 	if (priv->display_profile != NULL) {
4631 		cmsCloseProfile (priv->display_profile);
4632 		priv->display_profile = NULL;
4633 	}
4634 #endif
4635 
4636 	if (priv->last_save_as_folder != NULL) {
4637 		g_object_unref (priv->last_save_as_folder);
4638 		priv->last_save_as_folder = NULL;
4639 	}
4640 
4641 	if (priv->page_setup != NULL) {
4642 		g_object_unref (priv->page_setup);
4643 		priv->page_setup = NULL;
4644 	}
4645 
4646 	if (priv->thumbview)
4647 	{
4648 		/* Disconnect so we don't get any unwanted callbacks
4649 		 * when the thumb view is disposed. */
4650 		g_signal_handlers_disconnect_by_func (priv->thumbview,
4651 		                 G_CALLBACK (handle_image_selection_changed_cb),
4652 		                 window);
4653 		g_clear_object (&priv->thumbview);
4654 	}
4655 
4656 	g_clear_object (&priv->gear_menu_builder);
4657 
4658 	peas_engine_garbage_collect (PEAS_ENGINE (EOG_APP->priv->plugin_engine));
4659 
4660 	G_OBJECT_CLASS (eog_window_parent_class)->dispose (object);
4661 }
4662 
4663 static gint
eog_window_delete(GtkWidget * widget,GdkEventAny * event)4664 eog_window_delete (GtkWidget *widget, GdkEventAny *event)
4665 {
4666 	EogWindow *window;
4667 	EogWindowPrivate *priv;
4668 
4669 	g_return_val_if_fail (EOG_IS_WINDOW (widget), FALSE);
4670 
4671 	window = EOG_WINDOW (widget);
4672 	priv = window->priv;
4673 
4674 	if (priv->save_job != NULL) {
4675 		eog_window_finish_saving (window);
4676 	}
4677 
4678 	if (eog_window_unsaved_images_confirm (window)) {
4679 		return TRUE;
4680 	}
4681 
4682 	gtk_widget_destroy (widget);
4683 
4684 	return TRUE;
4685 }
4686 
4687 /*
4688  * Imported from gedit-window.c:
4689  * GtkWindow catches keybindings for the menu items _before_ passing them to
4690  * the focused widget. This is unfortunate and means that trying to use
4691  * Return to activate a menu entry will instead skip to the next image.
4692  * Here we override GtkWindow's handler to do the same things that it
4693  * does, but in the opposite order and then we chain up to the grand
4694  * parent handler, skipping gtk_window_key_press_event.
4695  */
4696 static gint
eog_window_key_press(GtkWidget * widget,GdkEventKey * event)4697 eog_window_key_press (GtkWidget *widget, GdkEventKey *event)
4698 {
4699 	static gpointer grand_parent_class = NULL;
4700 
4701 	gint result = FALSE;
4702 	gboolean handle_selection = FALSE;
4703 	GdkModifierType modifiers;
4704 
4705 	if (grand_parent_class == NULL)
4706 	{
4707 		grand_parent_class = g_type_class_peek_parent (eog_window_parent_class);
4708 	}
4709 
4710 	/* handle focus widget key events */
4711 	if (!handle_selection) {
4712 		handle_selection = gtk_window_propagate_key_event (GTK_WINDOW (widget), event);
4713 	}
4714 
4715 	/* handle mnemonics and accelerators */
4716 	if (!handle_selection) {
4717 		handle_selection = gtk_window_activate_key (GTK_WINDOW (widget), event);
4718 	}
4719 
4720 	/* This part is disabled for now as it overrides the arrow key handlers
4721 	 * below which are still needed in RTL scenarios */
4722 #if 0
4723 	/* Chain up, invokes binding set on window */
4724 	if (!handle_selection) {
4725 		handle_selection = GTK_WIDGET_CLASS (grand_parent_class)->key_press_event (widget, event);
4726 	}
4727 #endif
4728 
4729 	/* If the workaround already handled the key event return early */
4730 	if(handle_selection)
4731 		return TRUE;
4732 
4733 	modifiers = gtk_accelerator_get_default_mod_mask ();
4734 
4735 	switch (event->keyval) {
4736 #if 0
4737 	case GDK_KEY_space:
4738 		if ((event->state & modifiers) == GDK_CONTROL_MASK) {
4739 			handle_selection = TRUE;
4740 			break;
4741 		}
4742 	case GDK_KEY_Return:
4743 		/* Image properties dialog case */
4744 		if ((event->state & modifiers) == GDK_MOD1_MASK) {
4745 			result = FALSE;
4746 			break;
4747 		}
4748 
4749 		if ((event->state & modifiers) == GDK_SHIFT_MASK) {
4750 			eog_window_action_go_prev (NULL, NULL, EOG_WINDOW (widget));
4751 		} else {
4752 			eog_window_action_go_next (NULL, NULL, EOG_WINDOW (widget));
4753 		}
4754 		result = TRUE;
4755 		break;
4756 #endif
4757 	case GDK_KEY_Escape:
4758 		if (EOG_WINDOW (widget)->priv->mode == EOG_WINDOW_MODE_FULLSCREEN) {
4759 			eog_window_stop_fullscreen (EOG_WINDOW (widget), FALSE);
4760 		} else if (EOG_WINDOW (widget)->priv->mode == EOG_WINDOW_MODE_SLIDESHOW) {
4761 			eog_window_stop_fullscreen (EOG_WINDOW (widget), TRUE);
4762 		} else {
4763 			eog_window_action_close_window (NULL, NULL, EOG_WINDOW (widget));
4764 			return TRUE;
4765 		}
4766 		break;
4767 	case GDK_KEY_Left:
4768 	/* case GDK_KEY_Up: */
4769 		if ((event->state & modifiers) == 0) {
4770 			/* Left and Up move to previous image */
4771 			if (is_rtl) { /* move to next in RTL mode */
4772 				eog_window_action_go_next (NULL, NULL, EOG_WINDOW (widget));
4773 			} else {
4774 				eog_window_action_go_prev (NULL, NULL, EOG_WINDOW (widget));
4775 			}
4776 			result = TRUE;
4777 		}
4778 		break;
4779 	case GDK_KEY_Right:
4780 	/* case GDK_KEY_Down: */
4781 		if ((event->state & modifiers) == 0) {
4782 			/* Right and Down move to next image */
4783 			if (is_rtl) { /* move to previous in RTL mode */
4784 				eog_window_action_go_prev (NULL, NULL, EOG_WINDOW (widget));
4785 			} else {
4786 				eog_window_action_go_next (NULL, NULL, EOG_WINDOW (widget));
4787 			}
4788 			result = TRUE;
4789 		}
4790 		break;
4791 	case GDK_KEY_Page_Up:
4792 		if ((event->state & modifiers) == 0) {
4793 			if (!eog_scroll_view_scrollbars_visible (EOG_SCROLL_VIEW (EOG_WINDOW (widget)->priv->view))) {
4794 				if (!gtk_widget_get_visible (EOG_WINDOW (widget)->priv->nav)) {
4795 					/* If the iconview is not visible skip to the
4796 					 * previous image manually as it won't handle
4797 					 * the keypress then. */
4798 					eog_window_action_go_prev (NULL, NULL, EOG_WINDOW (widget));
4799 					result = TRUE;
4800 				} else
4801 					handle_selection = TRUE;
4802 			}
4803 		}
4804 		break;
4805 	case GDK_KEY_Page_Down:
4806 		if ((event->state & modifiers) == 0) {
4807 			if (!eog_scroll_view_scrollbars_visible (EOG_SCROLL_VIEW (EOG_WINDOW (widget)->priv->view))) {
4808 				if (!gtk_widget_get_visible (EOG_WINDOW (widget)->priv->nav)) {
4809 					/* If the iconview is not visible skip to the
4810 					 * next image manually as it won't handle
4811 					 * the keypress then. */
4812 					eog_window_action_go_next (NULL, NULL, EOG_WINDOW (widget));
4813 					result = TRUE;
4814 				} else
4815 					handle_selection = TRUE;
4816 			}
4817 		}
4818 		break;
4819 	}
4820 
4821 	/* Update slideshow timeout */
4822 	if (result && (EOG_WINDOW (widget)->priv->mode == EOG_WINDOW_MODE_SLIDESHOW)) {
4823 		slideshow_set_timeout (EOG_WINDOW (widget));
4824 	}
4825 
4826 	if (handle_selection == TRUE && result == FALSE) {
4827 		gtk_widget_grab_focus (GTK_WIDGET (EOG_WINDOW (widget)->priv->thumbview));
4828 
4829 		result = gtk_widget_event (GTK_WIDGET (EOG_WINDOW (widget)->priv->thumbview),
4830 					   (GdkEvent *) event);
4831 	}
4832 
4833 	/* If we still haven't handled the event, give the scrollview a chance to do it.  */
4834 	if (result == FALSE &&
4835 		gtk_widget_get_realized (GTK_WIDGET (EOG_WINDOW (widget)->priv->view))) {
4836 			result = gtk_widget_event (GTK_WIDGET (EOG_WINDOW (widget)->priv->view),
4837 						   (GdkEvent *) event);
4838 	}
4839 
4840 	if (result == FALSE && GTK_WIDGET_CLASS (eog_window_parent_class)->key_press_event) {
4841 		result = (* GTK_WIDGET_CLASS (eog_window_parent_class)->key_press_event) (widget, event);
4842 	}
4843 
4844 	return result;
4845 }
4846 
4847 static gint
eog_window_button_press(GtkWidget * widget,GdkEventButton * event)4848 eog_window_button_press (GtkWidget *widget, GdkEventButton *event)
4849 {
4850 	EogWindow *window = EOG_WINDOW (widget);
4851 	gint result = FALSE;
4852 
4853 	/* We currently can't tell whether the old button codes (6, 7) are
4854 	 * still in use. So we keep them in addition to the new ones (8, 9)
4855 	 */
4856 	if (event->type == GDK_BUTTON_PRESS) {
4857 		switch (event->button) {
4858 		case 6:
4859 		case 8:
4860 			eog_thumb_view_select_single (EOG_THUMB_VIEW (window->priv->thumbview),
4861 						      EOG_THUMB_VIEW_SELECT_LEFT);
4862 			result = TRUE;
4863 		       	break;
4864 		case 7:
4865 		case 9:
4866 			eog_thumb_view_select_single (EOG_THUMB_VIEW (window->priv->thumbview),
4867 						      EOG_THUMB_VIEW_SELECT_RIGHT);
4868 			result = TRUE;
4869 		       	break;
4870 		}
4871 	}
4872 
4873 	if (result == FALSE && GTK_WIDGET_CLASS (eog_window_parent_class)->button_press_event) {
4874 		result = (* GTK_WIDGET_CLASS (eog_window_parent_class)->button_press_event) (widget, event);
4875 	}
4876 
4877 	return result;
4878 }
4879 
4880 static gboolean
eog_window_focus_out_event(GtkWidget * widget,GdkEventFocus * event)4881 eog_window_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
4882 {
4883 	EogWindow *window = EOG_WINDOW (widget);
4884 	EogWindowPrivate *priv = window->priv;
4885 	gboolean fullscreen;
4886 
4887 	eog_debug (DEBUG_WINDOW);
4888 
4889 	fullscreen = priv->mode == EOG_WINDOW_MODE_FULLSCREEN ||
4890 		     priv->mode == EOG_WINDOW_MODE_SLIDESHOW;
4891 
4892 	if (fullscreen) {
4893 		gtk_widget_hide (priv->fullscreen_popup);
4894 	}
4895 
4896 	return GTK_WIDGET_CLASS (eog_window_parent_class)->focus_out_event (widget, event);
4897 }
4898 
4899 static void
eog_window_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)4900 eog_window_set_property (GObject      *object,
4901 			 guint         property_id,
4902 			 const GValue *value,
4903 			 GParamSpec   *pspec)
4904 {
4905 	EogWindow *window;
4906 	EogWindowPrivate *priv;
4907 
4908         g_return_if_fail (EOG_IS_WINDOW (object));
4909 
4910         window = EOG_WINDOW (object);
4911 	priv = window->priv;
4912 
4913         switch (property_id) {
4914 	case PROP_GALLERY_POS:
4915 		eog_window_set_gallery_mode (window, g_value_get_enum (value),
4916 					     priv->gallery_resizable);
4917 		break;
4918 	case PROP_GALLERY_RESIZABLE:
4919 		eog_window_set_gallery_mode (window, priv->gallery_position,
4920 					     g_value_get_boolean (value));
4921 		break;
4922 	case PROP_STARTUP_FLAGS:
4923 		priv->flags = g_value_get_flags (value);
4924 		break;
4925 
4926         default:
4927                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
4928         }
4929 }
4930 
4931 static void
eog_window_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)4932 eog_window_get_property (GObject    *object,
4933 			 guint       property_id,
4934 			 GValue     *value,
4935 			 GParamSpec *pspec)
4936 {
4937 	EogWindow *window;
4938 	EogWindowPrivate *priv;
4939 
4940         g_return_if_fail (EOG_IS_WINDOW (object));
4941 
4942         window = EOG_WINDOW (object);
4943 	priv = window->priv;
4944 
4945         switch (property_id) {
4946 	case PROP_GALLERY_POS:
4947 		g_value_set_enum (value, priv->gallery_position);
4948 		break;
4949 	case PROP_GALLERY_RESIZABLE:
4950 		g_value_set_boolean (value, priv->gallery_resizable);
4951 		break;
4952 	case PROP_STARTUP_FLAGS:
4953 		g_value_set_flags (value, priv->flags);
4954 		break;
4955 
4956         default:
4957                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
4958 	}
4959 }
4960 
4961 static void
on_extension_added(PeasExtensionSet * set,PeasPluginInfo * info,PeasExtension * exten,GtkWindow * window)4962 on_extension_added (PeasExtensionSet *set,
4963 		    PeasPluginInfo   *info,
4964 		    PeasExtension    *exten,
4965 		    GtkWindow        *window)
4966 {
4967 	peas_extension_call (exten, "activate", window);
4968 }
4969 
4970 static void
on_extension_removed(PeasExtensionSet * set,PeasPluginInfo * info,PeasExtension * exten,GtkWindow * window)4971 on_extension_removed (PeasExtensionSet *set,
4972 		      PeasPluginInfo   *info,
4973 		      PeasExtension    *exten,
4974 		      GtkWindow        *window)
4975 {
4976 	peas_extension_call (exten, "deactivate", window);
4977 }
4978 
4979 static GObject *
eog_window_constructor(GType type,guint n_construct_properties,GObjectConstructParam * construct_params)4980 eog_window_constructor (GType type,
4981 			guint n_construct_properties,
4982 			GObjectConstructParam *construct_params)
4983 {
4984 	GObject *object;
4985 	EogWindowPrivate *priv;
4986 
4987 	object = G_OBJECT_CLASS (eog_window_parent_class)->constructor
4988 			(type, n_construct_properties, construct_params);
4989 
4990 	priv = EOG_WINDOW (object)->priv;
4991 
4992 	eog_window_construct_ui (EOG_WINDOW (object));
4993 
4994 	priv->extensions = peas_extension_set_new (PEAS_ENGINE (EOG_APP->priv->plugin_engine),
4995 						   EOG_TYPE_WINDOW_ACTIVATABLE,
4996 						   "window",
4997 						   EOG_WINDOW (object), NULL);
4998 	peas_extension_set_call (priv->extensions, "activate");
4999 	g_signal_connect (priv->extensions, "extension-added",
5000 			  G_CALLBACK (on_extension_added), object);
5001 	g_signal_connect (priv->extensions, "extension-removed",
5002 			  G_CALLBACK (on_extension_removed), object);
5003 
5004 	return object;
5005 }
5006 
5007 static void
eog_window_class_init(EogWindowClass * class)5008 eog_window_class_init (EogWindowClass *class)
5009 {
5010 	GObjectClass *g_object_class = (GObjectClass *) class;
5011 	GtkWidgetClass *widget_class = (GtkWidgetClass *) class;
5012 
5013 	g_object_class->constructor = eog_window_constructor;
5014 	g_object_class->dispose = eog_window_dispose;
5015 	g_object_class->set_property = eog_window_set_property;
5016 	g_object_class->get_property = eog_window_get_property;
5017 
5018 	widget_class->delete_event = eog_window_delete;
5019 	widget_class->key_press_event = eog_window_key_press;
5020 	widget_class->button_press_event = eog_window_button_press;
5021 	widget_class->drag_data_received = eog_window_drag_data_received;
5022 	widget_class->focus_out_event = eog_window_focus_out_event;
5023 
5024 /**
5025  * EogWindow:gallery-position:
5026  *
5027  * Determines the position of the image gallery in the window
5028  * relative to the image.
5029  */
5030 	g_object_class_install_property (
5031 		g_object_class, PROP_GALLERY_POS,
5032 		g_param_spec_enum ("gallery-position", NULL, NULL,
5033 				   EOG_TYPE_WINDOW_GALLERY_POS,
5034 				   EOG_WINDOW_GALLERY_POS_BOTTOM,
5035 				   G_PARAM_READWRITE | G_PARAM_STATIC_NAME));
5036 
5037 /**
5038  * EogWindow:gallery-resizable:
5039  *
5040  * If %TRUE the gallery will be resizable by the user otherwise it will be
5041  * in single column/row mode.
5042  */
5043 	g_object_class_install_property (
5044 		g_object_class, PROP_GALLERY_RESIZABLE,
5045 		g_param_spec_boolean ("gallery-resizable", NULL, NULL, FALSE,
5046 				      G_PARAM_READWRITE | G_PARAM_STATIC_NAME));
5047 
5048 /**
5049  * EogWindow:startup-flags:
5050  *
5051  * A bitwise OR of #EogStartupFlags elements, indicating how the window
5052  * should behave upon creation.
5053  */
5054 	g_object_class_install_property (g_object_class,
5055 					 PROP_STARTUP_FLAGS,
5056 					 g_param_spec_flags ("startup-flags",
5057 							     NULL,
5058 							     NULL,
5059 							     EOG_TYPE_STARTUP_FLAGS,
5060 					 		     0,
5061 					 		     G_PARAM_READWRITE |
5062 							     G_PARAM_CONSTRUCT_ONLY));
5063 
5064 /**
5065  * EogWindow::prepared:
5066  * @window: the object which received the signal.
5067  *
5068  * The #EogWindow::prepared signal is emitted when the @window is ready
5069  * to be shown.
5070  */
5071 	signals [SIGNAL_PREPARED] =
5072 		g_signal_new ("prepared",
5073 			      EOG_TYPE_WINDOW,
5074 			      G_SIGNAL_RUN_LAST,
5075 			      G_STRUCT_OFFSET (EogWindowClass, prepared),
5076 			      NULL, NULL,
5077 			      g_cclosure_marshal_VOID__VOID,
5078 			      G_TYPE_NONE, 0);
5079 }
5080 
5081 /**
5082  * eog_window_new:
5083  * @flags: the initialization parameters for the new window.
5084  *
5085  *
5086  * Creates a new and empty #EogWindow. Use @flags to indicate
5087  * if the window should be initialized fullscreen, in slideshow mode,
5088  * and/or without the thumbnails gallery visible. See #EogStartupFlags.
5089  *
5090  * Returns: a newly created #EogWindow.
5091  **/
5092 GtkWidget*
eog_window_new(EogStartupFlags flags)5093 eog_window_new (EogStartupFlags flags)
5094 {
5095 	EogWindow *window;
5096 
5097 	eog_debug (DEBUG_WINDOW);
5098 
5099 	window = EOG_WINDOW (g_object_new (EOG_TYPE_WINDOW,
5100 					   "type", GTK_WINDOW_TOPLEVEL,
5101 	                                   "application", EOG_APP,
5102 					   "startup-flags", flags,
5103 					   NULL));
5104 
5105 	return GTK_WIDGET (window);
5106 }
5107 
5108 static void
eog_window_list_store_image_added(GtkTreeModel * tree_model,GtkTreePath * path,GtkTreeIter * iter,gpointer user_data)5109 eog_window_list_store_image_added (GtkTreeModel *tree_model,
5110                                    GtkTreePath  *path,
5111                                    GtkTreeIter  *iter,
5112                                    gpointer      user_data)
5113 {
5114 	EogWindow *window = EOG_WINDOW (user_data);
5115 
5116 	update_image_pos (window);
5117 	update_action_groups_state (window);
5118 }
5119 
5120 static void
eog_window_list_store_image_removed(GtkTreeModel * tree_model,GtkTreePath * path,gpointer user_data)5121 eog_window_list_store_image_removed (GtkTreeModel *tree_model,
5122                                      GtkTreePath  *path,
5123                                      gpointer      user_data)
5124 {
5125 	EogWindow *window = EOG_WINDOW (user_data);
5126 	EogWindowPrivate *priv = window->priv;
5127 	gint n_images = eog_list_store_length (priv->store);
5128 
5129 	if (eog_thumb_view_get_n_selected (EOG_THUMB_VIEW (priv->thumbview)) == 0
5130 	    && n_images > 0) {
5131 		gint pos = MIN (gtk_tree_path_get_indices (path)[0],
5132 				n_images - 1);
5133 		EogImage *image = eog_list_store_get_image_by_pos (priv->store, pos);
5134 
5135 		if (image != NULL) {
5136 			eog_thumb_view_set_current_image (EOG_THUMB_VIEW (priv->thumbview),
5137 							  image, TRUE);
5138 			g_object_unref (image);
5139 		}
5140 	} else if (!n_images) {
5141 		eog_window_clear_load_job (window);
5142 	}
5143 
5144 	update_image_pos (window);
5145 	update_action_groups_state (window);
5146 }
5147 
5148 static void
eog_job_model_cb(EogJobModel * job,gpointer data)5149 eog_job_model_cb (EogJobModel *job, gpointer data)
5150 {
5151 	EogWindow *window;
5152 	EogWindowPrivate *priv;
5153 	gint n_images;
5154 
5155 	eog_debug (DEBUG_WINDOW);
5156 
5157 #ifdef HAVE_EXIF
5158         int i;
5159 	EogImage *image;
5160 #endif
5161 
5162         g_return_if_fail (EOG_IS_WINDOW (data));
5163 
5164 	window = EOG_WINDOW (data);
5165 	priv = window->priv;
5166 
5167 	if (priv->store != NULL) {
5168 		g_object_unref (priv->store);
5169 		priv->store = NULL;
5170 	}
5171 
5172 	priv->store = g_object_ref (job->store);
5173 
5174 	n_images = eog_list_store_length (EOG_LIST_STORE (priv->store));
5175 
5176 #ifdef HAVE_EXIF
5177 	if (g_settings_get_boolean (priv->view_settings, EOG_CONF_VIEW_AUTOROTATE)) {
5178 		for (i = 0; i < n_images; i++) {
5179 			image = eog_list_store_get_image_by_pos (priv->store, i);
5180 			eog_image_autorotate (image);
5181 			g_object_unref (image);
5182 		}
5183 	}
5184 #endif
5185 
5186 	eog_thumb_view_set_model (EOG_THUMB_VIEW (priv->thumbview), priv->store);
5187 
5188 	g_signal_connect (G_OBJECT (priv->store),
5189 			  "row-inserted",
5190 			  G_CALLBACK (eog_window_list_store_image_added),
5191 			  window);
5192 
5193 	g_signal_connect (G_OBJECT (priv->store),
5194 			  "row-deleted",
5195 			  G_CALLBACK (eog_window_list_store_image_removed),
5196 			  window);
5197 
5198 	if (n_images == 0) {
5199 		gint n_files;
5200 
5201 		/* Avoid starting up fullscreen with an empty model as
5202 		 * fullscreen controls might end up disabled */
5203 		if (priv->status == EOG_WINDOW_STATUS_INIT &&
5204 		    (priv->mode == EOG_WINDOW_MODE_FULLSCREEN
5205 		     || priv->mode == EOG_WINDOW_MODE_SLIDESHOW)) {
5206 			eog_window_stop_fullscreen (window,
5207 				priv->mode == EOG_WINDOW_MODE_SLIDESHOW);
5208 		}
5209 		priv->status = EOG_WINDOW_STATUS_NORMAL;
5210 		update_action_groups_state (window);
5211 
5212 		n_files = g_slist_length (priv->file_list);
5213 
5214 		if (n_files > 0) {
5215 			GtkWidget *message_area;
5216 			GFile *file = NULL;
5217 
5218 			if (n_files == 1) {
5219 				file = (GFile *) priv->file_list->data;
5220 			}
5221 
5222 			message_area = eog_no_images_error_message_area_new (file);
5223 
5224 			eog_window_set_message_area (window, message_area);
5225 
5226 			gtk_widget_show (message_area);
5227 		}
5228 
5229 		g_signal_emit (window, signals[SIGNAL_PREPARED], 0);
5230 	}
5231 }
5232 
5233 /**
5234  * eog_window_open_file_list:
5235  * @window: An #EogWindow.
5236  * @file_list: (element-type GFile): A %NULL-terminated list of #GFile's.
5237  *
5238  * Opens a list of files, adding them to the gallery in @window.
5239  * Files will be checked to be readable and later filtered according
5240  * with eog_list_store_add_files().
5241  **/
5242 void
eog_window_open_file_list(EogWindow * window,GSList * file_list)5243 eog_window_open_file_list (EogWindow *window, GSList *file_list)
5244 {
5245 	EogJob *job;
5246 
5247 	eog_debug (DEBUG_WINDOW);
5248 
5249 	window->priv->status = EOG_WINDOW_STATUS_INIT;
5250 
5251 	/* Free the list to avoid memory leak
5252 	 * when using flag EOG_STARTUP_SINGLE_WINDOW
5253 	 */
5254 	if (window->priv->file_list != NULL) {
5255 		g_slist_foreach (window->priv->file_list, (GFunc) g_object_unref, NULL);
5256 		g_slist_free (window->priv->file_list);
5257 	}
5258 
5259 	g_slist_foreach (file_list, (GFunc) g_object_ref, NULL);
5260 	window->priv->file_list = file_list;
5261 
5262 	job = eog_job_model_new (file_list);
5263 
5264 	g_signal_connect (job,
5265 			  "finished",
5266 			  G_CALLBACK (eog_job_model_cb),
5267 			  window);
5268 
5269 	eog_job_scheduler_add_job (job);
5270 	g_object_unref (job);
5271 }
5272 
5273 /**
5274  * eog_window_get_gear_menu_section:
5275  * @window: an #EogWindow.
5276  * @id: the ID for the menu section to look up
5277  *
5278  * Return value: (transfer none): a #GMenu or %NULL on failure
5279  **/
5280 GMenu *
eog_window_get_gear_menu_section(EogWindow * window,const gchar * id)5281 eog_window_get_gear_menu_section (EogWindow *window, const gchar *id)
5282 {
5283 	GObject *object;
5284 	g_return_val_if_fail (EOG_IS_WINDOW (window), NULL);
5285 
5286 	object = gtk_builder_get_object (window->priv->gear_menu_builder, id);
5287 	if (object == NULL || !G_IS_MENU (object))
5288 		return NULL;
5289 
5290 	return G_MENU (object);
5291 }
5292 
5293 /**
5294  * eog_window_get_mode:
5295  * @window: An #EogWindow.
5296  *
5297  * Gets the mode of @window. See #EogWindowMode for details.
5298  *
5299  * Returns: An #EogWindowMode.
5300  **/
5301 EogWindowMode
eog_window_get_mode(EogWindow * window)5302 eog_window_get_mode (EogWindow *window)
5303 {
5304         g_return_val_if_fail (EOG_IS_WINDOW (window), EOG_WINDOW_MODE_UNKNOWN);
5305 
5306 	return window->priv->mode;
5307 }
5308 
5309 /**
5310  * eog_window_set_mode:
5311  * @window: an #EogWindow.
5312  * @mode: an #EogWindowMode value.
5313  *
5314  * Changes the mode of @window to normal, fullscreen, or slideshow.
5315  * See #EogWindowMode for details.
5316  **/
5317 void
eog_window_set_mode(EogWindow * window,EogWindowMode mode)5318 eog_window_set_mode (EogWindow *window, EogWindowMode mode)
5319 {
5320         g_return_if_fail (EOG_IS_WINDOW (window));
5321 
5322 	if (window->priv->mode == mode)
5323 		return;
5324 
5325 	switch (mode) {
5326 	case EOG_WINDOW_MODE_NORMAL:
5327 		eog_window_stop_fullscreen (window,
5328 					    window->priv->mode == EOG_WINDOW_MODE_SLIDESHOW);
5329 		break;
5330 	case EOG_WINDOW_MODE_FULLSCREEN:
5331 		eog_window_run_fullscreen (window, FALSE);
5332 		break;
5333 	case EOG_WINDOW_MODE_SLIDESHOW:
5334 		eog_window_run_fullscreen (window, TRUE);
5335 		break;
5336 	case EOG_WINDOW_MODE_UNKNOWN:
5337 		break;
5338 	}
5339 }
5340 
5341 /**
5342  * eog_window_get_store:
5343  * @window: An #EogWindow.
5344  *
5345  * Gets the #EogListStore that contains the images in the gallery
5346  * of @window.
5347  *
5348  * Returns: (transfer none): an #EogListStore.
5349  **/
5350 EogListStore *
eog_window_get_store(EogWindow * window)5351 eog_window_get_store (EogWindow *window)
5352 {
5353         g_return_val_if_fail (EOG_IS_WINDOW (window), NULL);
5354 
5355 	return EOG_LIST_STORE (window->priv->store);
5356 }
5357 
5358 /**
5359  * eog_window_get_view:
5360  * @window: An #EogWindow.
5361  *
5362  * Gets the #EogScrollView in the window.
5363  *
5364  * Returns: (transfer none): the #EogScrollView.
5365  **/
5366 GtkWidget *
eog_window_get_view(EogWindow * window)5367 eog_window_get_view (EogWindow *window)
5368 {
5369         g_return_val_if_fail (EOG_IS_WINDOW (window), NULL);
5370 
5371        return window->priv->view;
5372 }
5373 
5374 /**
5375  * eog_window_get_sidebar:
5376  * @window: An #EogWindow.
5377  *
5378  * Gets the sidebar widget of @window.
5379  *
5380  * Returns: (transfer none): the #EogSidebar.
5381  **/
5382 GtkWidget *
eog_window_get_sidebar(EogWindow * window)5383 eog_window_get_sidebar (EogWindow *window)
5384 {
5385         g_return_val_if_fail (EOG_IS_WINDOW (window), NULL);
5386 
5387 	return window->priv->sidebar;
5388 }
5389 
5390 /**
5391  * eog_window_get_thumb_view:
5392  * @window: an #EogWindow.
5393  *
5394  * Gets the thumbnails view in @window.
5395  *
5396  * Returns: (transfer none): an #EogThumbView.
5397  **/
5398 GtkWidget *
eog_window_get_thumb_view(EogWindow * window)5399 eog_window_get_thumb_view (EogWindow *window)
5400 {
5401         g_return_val_if_fail (EOG_IS_WINDOW (window), NULL);
5402 
5403 	return window->priv->thumbview;
5404 }
5405 
5406 /**
5407  * eog_window_get_thumb_nav:
5408  * @window: an #EogWindow.
5409  *
5410  * Gets the thumbnails navigation pane in @window.
5411  *
5412  * Returns: (transfer none): an #EogThumbNav.
5413  **/
5414 GtkWidget *
eog_window_get_thumb_nav(EogWindow * window)5415 eog_window_get_thumb_nav (EogWindow *window)
5416 {
5417         g_return_val_if_fail (EOG_IS_WINDOW (window), NULL);
5418 
5419 	return window->priv->nav;
5420 }
5421 
5422 /**
5423  * eog_window_get_statusbar:
5424  * @window: an #EogWindow.
5425  *
5426  * Gets the statusbar in @window.
5427  *
5428  * Returns: (transfer none): a #EogStatusbar.
5429  **/
5430 GtkWidget *
eog_window_get_statusbar(EogWindow * window)5431 eog_window_get_statusbar (EogWindow *window)
5432 {
5433         g_return_val_if_fail (EOG_IS_WINDOW (window), NULL);
5434 
5435 	return window->priv->statusbar;
5436 }
5437 
5438 /**
5439  * eog_window_get_image:
5440  * @window: an #EogWindow.
5441  *
5442  * Gets the image currently displayed in @window or %NULL if
5443  * no image is being displayed.
5444  *
5445  * Returns: (transfer none): an #EogImage.
5446  **/
5447 EogImage *
eog_window_get_image(EogWindow * window)5448 eog_window_get_image (EogWindow *window)
5449 {
5450         g_return_val_if_fail (EOG_IS_WINDOW (window), NULL);
5451 
5452 	return window->priv->image;
5453 }
5454 
5455 /**
5456  * eog_window_is_empty:
5457  * @window: an #EogWindow.
5458  *
5459  * Tells whether @window is currently empty or not.
5460  *
5461  * Returns: %TRUE if @window has no images, %FALSE otherwise.
5462  **/
5463 gboolean
eog_window_is_empty(EogWindow * window)5464 eog_window_is_empty (EogWindow *window)
5465 {
5466         EogWindowPrivate *priv;
5467         gboolean empty = TRUE;
5468 
5469 	eog_debug (DEBUG_WINDOW);
5470 
5471         g_return_val_if_fail (EOG_IS_WINDOW (window), FALSE);
5472 
5473         priv = window->priv;
5474 
5475         if (priv->store != NULL) {
5476                 empty = (eog_list_store_length (EOG_LIST_STORE (priv->store)) == 0);
5477         }
5478 
5479         return empty;
5480 }
5481 
5482 void
eog_window_reload_image(EogWindow * window)5483 eog_window_reload_image (EogWindow *window)
5484 {
5485 	GtkWidget *view;
5486 
5487 	g_return_if_fail (EOG_IS_WINDOW (window));
5488 
5489 	if (window->priv->image == NULL)
5490 		return;
5491 
5492 	g_object_unref (window->priv->image);
5493 	window->priv->image = NULL;
5494 
5495 	view = eog_window_get_view (window);
5496 	eog_scroll_view_set_image (EOG_SCROLL_VIEW (view), NULL);
5497 
5498 	eog_thumb_view_select_single (EOG_THUMB_VIEW (window->priv->thumbview),
5499 				      EOG_THUMB_VIEW_SELECT_CURRENT);
5500 }
5501 
5502 gboolean
eog_window_is_not_initializing(const EogWindow * window)5503 eog_window_is_not_initializing (const EogWindow *window)
5504 {
5505 	g_return_val_if_fail (EOG_IS_WINDOW (window), FALSE);
5506 
5507 	return window->priv->status != EOG_WINDOW_STATUS_INIT;
5508 }
5509 
5510 void
eog_window_show_about_dialog(EogWindow * window)5511 eog_window_show_about_dialog (EogWindow *window)
5512 {
5513 	g_return_if_fail (EOG_IS_WINDOW (window));
5514 
5515 	static const char *authors[] = {
5516 		"Felix Riemann <friemann@gnome.org> (maintainer)",
5517 		"",
5518 		"Claudio Saavedra <csaavedra@igalia.com>",
5519 		"Lucas Rocha <lucasr@gnome.org>",
5520 		"Tim Gerla <tim+gnomebugs@gerla.net>",
5521 		"Philip Van Hoof <pvanhoof@gnome.org>",
5522                 "Paolo Borelli <pborelli@katamail.com>",
5523 		"Jens Finke <jens@triq.net>",
5524 		"Martin Baulig <martin@home-of-linux.org>",
5525 		"Arik Devens <arik@gnome.org>",
5526 		"Michael Meeks <mmeeks@gnu.org>",
5527 		"Federico Mena-Quintero <federico@gnome.org>",
5528 		"Lutz M\xc3\xbcller <urc8@rz.uni-karlsruhe.de>",
5529 		NULL
5530 	};
5531 
5532 	static const char *documenters[] = {
5533 		"Eliot Landrum <eliot@landrum.cx>",
5534 		"Federico Mena-Quintero <federico@gnome.org>",
5535 		"Sun GNOME Documentation Team <gdocteam@sun.com>",
5536 		"Tiffany Antopolski <tiffany@antopolski.com>",
5537 		NULL
5538 	};
5539 
5540 	gtk_show_about_dialog (GTK_WINDOW (window),
5541 			       "program-name", _("Image Viewer"),
5542 			       "version", VERSION,
5543 			       "copyright", "Copyright \xc2\xa9 2000-2010 Free Software Foundation, Inc.",
5544 			       "comments",_("The GNOME image viewer."),
5545 			       "authors", authors,
5546 			       "documenters", documenters,
5547 			       "translator-credits", _("translator-credits"),
5548 			       "website", "https://wiki.gnome.org/Apps/EyeOfGnome",
5549 			       "logo-icon-name", APPLICATION_ID,
5550 			       "wrap-license", TRUE,
5551 			       "license-type", GTK_LICENSE_GPL_2_0,
5552 			       NULL);
5553 }
5554 
5555 void
eog_window_show_preferences_dialog(EogWindow * window)5556 eog_window_show_preferences_dialog (EogWindow *window)
5557 {
5558 	GtkWidget *pref_dlg;
5559 
5560 	g_return_if_fail (window != NULL);
5561 
5562 	pref_dlg = eog_preferences_dialog_get_instance (GTK_WINDOW (window));
5563 
5564 	gtk_widget_show (pref_dlg);
5565 }
5566 
5567 void
eog_window_close(EogWindow * window)5568 eog_window_close (EogWindow *window)
5569 {
5570 	EogWindowPrivate *priv;
5571 
5572 	g_return_if_fail (EOG_IS_WINDOW (window));
5573 
5574 	priv = window->priv;
5575 
5576 	if (priv->save_job != NULL) {
5577 		eog_window_finish_saving (window);
5578 	}
5579 
5580 	if (!eog_window_unsaved_images_confirm (window)) {
5581 		gtk_widget_destroy (GTK_WIDGET (window));
5582 	}
5583 }
5584