1 /*
2 * Copyright © 2009-2018 Siyan Panayotov <contact@siyanpanayotov.com>
3 *
4 * This file is part of Viewnior.
5 *
6 * Viewnior is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Viewnior is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Viewnior. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <stdlib.h>
21 #include <libintl.h>
22 #include <glib/gi18n.h>
23 #define _(String) gettext (String)
24
25 #include "config.h"
26 #include <glib/gstdio.h>
27 #include <gtk/gtk.h>
28 #include <gdk/gdkkeysyms.h>
29 #include <errno.h>
30 #include <sys/wait.h>
31 #include "vnr-window.h"
32 #include "uni-scroll-win.h"
33 #include "uni-anim-view.h"
34 #include "vnr-tools.h"
35 #include "vnr-file.h"
36 #include "vnr-message-area.h"
37 #include "vnr-properties-dialog.h"
38 #include "vnr-crop.h"
39 #include "uni-exiv2.hpp"
40 #include "uni-utils.h"
41
42 /* Timeout to hide the toolbar in fullscreen mode */
43 #define FULLSCREEN_TIMEOUT 1000
44
45 G_DEFINE_TYPE (VnrWindow, vnr_window, GTK_TYPE_WINDOW);
46
47 static void vnr_window_unfullscreen (VnrWindow *window);
48 static void stop_slideshow(VnrWindow *window);
49 static void start_slideshow(VnrWindow *window);
50 static void restart_slideshow(VnrWindow *window);
51 static void allow_slideshow(VnrWindow *window);
52
53 static void leave_fs_cb (GtkButton *button, VnrWindow *window);
54 static void toggle_show_next_cb (GtkToggleButton *togglebutton, VnrWindow *window);
55 static void spin_value_change_cb (GtkSpinButton *spinbutton, VnrWindow *window);
56 static void save_image_cb (GtkWidget *widget, VnrWindow *window);
57 static void zoom_changed_cb (UniImageView *view, VnrWindow *window);
58 static gboolean fullscreen_timeout_cb (VnrWindow *window);
59 static gboolean leave_image_area_cb(GtkWidget * widget, GdkEventCrossing * ev, VnrWindow *window);
60 static gboolean fullscreen_motion_cb(GtkWidget * widget, GdkEventMotion * ev, VnrWindow *window);
61 static void open_with_launch_application_cb (GtkAction *action, VnrWindow *window);
62
63 const gchar *ui_definition = "<ui>"
64 "<menubar name=\"MainMenu\">"
65 "<menu action=\"File\">"
66 "<menuitem action=\"FileOpen\"/>"
67 "<menuitem action=\"FileOpenDir\"/>"
68 "<menu action=\"FileOpenWith\">"
69 "<placeholder name=\"AppEntries\"/>"
70 "</menu>"
71 "<separator/>"
72 "<menuitem action=\"FileSave\"/>"
73 "<menuitem action=\"FileReload\"/>"
74 "<separator/>"
75 "<menuitem action=\"FileProperties\"/>"
76 "<separator/>"
77 "<menuitem action=\"FileClose\"/>"
78 "</menu>"
79 "<menu action=\"Edit\">"
80 "<menuitem action=\"FileDelete\"/>"
81 "<separator/>"
82 "<menuitem action=\"EditPreferences\"/>"
83 "</menu>"
84 "<menu action=\"View\">"
85 "<menuitem action=\"ViewMenuBar\"/>"
86 "<menuitem action=\"ViewToolbar\"/>"
87 "<menuitem action=\"ViewScrollbar\"/>"
88 "<separator/>"
89 "<menuitem action=\"ViewZoomIn\"/>"
90 "<menuitem action=\"ViewZoomOut\"/>"
91 "<menuitem action=\"ViewZoomNormal\"/>"
92 "<menuitem action=\"ViewZoomFit\"/>"
93 "<separator/>"
94 "<menuitem name=\"Fullscreen\" action=\"ViewFullscreen\"/>"
95 "<menuitem name=\"Slideshow\" action=\"ViewSlideshow\"/>"
96 "<separator/>"
97 "<menuitem name=\"ResizeWindow\" action=\"ViewResizeWindow\"/>"
98 "</menu>"
99 "<menu action=\"Image\">"
100 "<menuitem action=\"ImageFlipVertical\"/>"
101 "<menuitem action=\"ImageFlipHorizontal\"/>"
102 "<separator/>"
103 "<menuitem action=\"ImageRotateCW\"/>"
104 "<menuitem action=\"ImageRotateCCW\"/>"
105 "<separator/>"
106 "<menuitem action=\"ImageCrop\"/>"
107 "<placeholder name=\"WallpaperEntry\"/>"
108 "</menu>"
109 "<menu action=\"Go\">"
110 "<menuitem name=\"GoPrevious\" action=\"GoPrevious\"/>"
111 "<menuitem name=\"GoNext\" action=\"GoNext\"/>"
112 "<separator/>"
113 "<menuitem name=\"GoFirst\" action=\"GoFirst\"/>"
114 "<menuitem name=\"GoLast\" action=\"GoLast\"/>"
115 "</menu>"
116 "<menu action=\"Help\">"
117 "<menuitem action=\"HelpAbout\"/>"
118 "</menu>"
119 "</menubar>"
120 "<popup name=\"ButtonMenu\">"
121 "<menuitem action=\"FileOpen\"/>"
122 "<menuitem action=\"FileOpenDir\"/>"
123 "<menu action=\"FileOpenWith\">"
124 "<placeholder name=\"AppEntries\"/>"
125 "</menu>"
126 "<separator/>"
127 "<menuitem action=\"FileSave\"/>"
128 "<menuitem action=\"FileReload\"/>"
129 "<menuitem action=\"FileProperties\"/>"
130 "<separator/>"
131 "<menu action=\"Edit\">"
132 "<menuitem action=\"FileDelete\"/>"
133 "<separator/>"
134 "</menu>"
135 "<menu action=\"View\">"
136 "<menuitem action=\"ViewZoomIn\"/>"
137 "<menuitem action=\"ViewZoomOut\"/>"
138 "<menuitem action=\"ViewZoomNormal\"/>"
139 "<menuitem action=\"ViewZoomFit\"/>"
140 "<separator/>"
141 "<menuitem action=\"ViewMenuBar\"/>"
142 "<menuitem action=\"ViewToolbar\"/>"
143 "<menuitem action=\"ViewScrollbar\"/>"
144 "<menuitem name=\"Fullscreen\" action=\"ViewFullscreen\"/>"
145 "<menuitem name=\"Slideshow\" action=\"ViewSlideshow\"/>"
146 "<separator/>"
147 "<menuitem name=\"ResizeWindow\" action=\"ViewResizeWindow\"/>"
148 "</menu>"
149 "<menu action=\"Image\">"
150 "<menuitem action=\"ImageFlipVertical\"/>"
151 "<menuitem action=\"ImageFlipHorizontal\"/>"
152 "<separator/>"
153 "<menuitem action=\"ImageRotateCW\"/>"
154 "<menuitem action=\"ImageRotateCCW\"/>"
155 "<separator/>"
156 "<menuitem action=\"ImageCrop\"/>"
157 "<placeholder name=\"WallpaperEntry\"/>"
158 "</menu>"
159 "<separator/>"
160 "<menuitem action=\"EditPreferences\"/>"
161 "<separator/>"
162 "<menuitem action=\"HelpAbout\"/>"
163 "<menuitem action=\"FileClose\"/>"
164 "</popup>"
165 "<toolbar name=\"Toolbar\">"
166 "<toolitem action=\"GoPrevious\"/>"
167 "<toolitem action=\"GoNext\"/>"
168 "<separator/>"
169 "<toolitem action=\"ViewZoomIn\"/>"
170 "<toolitem action=\"ViewZoomOut\"/>"
171 "<toolitem action=\"ViewZoomNormal\"/>"
172 "<toolitem action=\"ViewZoomFit\"/>"
173 "<separator/>"
174 "<toolitem action=\"ImageRotateCCW\"/>"
175 "<toolitem action=\"ImageRotateCW\"/>"
176 "<separator expand=\"true\"/>"
177 "<toolitem action=\"Properties\"/>"
178 "</toolbar>"
179 "<popup name=\"PopupMenu\">"
180 "<menuitem name=\"GoPrevious\" action=\"GoPrevious\"/>"
181 "<menuitem name=\"GoNext\" action=\"GoNext\"/>"
182 "<separator/>"
183 "<menu action=\"FileOpenWith\">"
184 "<placeholder name=\"AppEntries\"/>"
185 "</menu>"
186 "<separator/>"
187 "<menuitem action=\"ViewZoomIn\"/>"
188 "<menuitem action=\"ViewZoomOut\"/>"
189 "<menuitem action=\"ViewZoomNormal\"/>"
190 "<placeholder name=\"WallpaperEntry\"/>"
191 "<separator/>"
192 "<menuitem name=\"MenuBar\" action=\"ViewMenuBar\"/>"
193 "<menuitem name=\"Toolbar\" action=\"ViewToolbar\"/>"
194 "<menuitem name=\"Scrollbar\" action=\"ViewScrollbar\"/>"
195 "<menuitem name=\"Fullscreen\" action=\"ViewFullscreen\"/>"
196 "<separator/>"
197 "<menuitem action=\"FileProperties\"/>"
198 "</popup>"
199 "<accelerator name=\"ControlEqualAccel\" action=\"ControlEqual\"/>"
200 "<accelerator name=\"ControlKPAddAccel\" action=\"ControlKpAdd\"/>"
201 "<accelerator name=\"ControlKPSubAccel\" action=\"ControlKpSub\"/>"
202 "<accelerator name=\"DeleteAccel\" action=\"Delete\"/>"
203 "</ui>";
204
205
206 const gchar *ui_definition_wallpaper = "<ui>"
207 "<menubar name=\"MainMenu\">"
208 "<menu action=\"Image\">"
209 "<placeholder name=\"WallpaperEntry\">"
210 "<separator/>"
211 "<menuitem name=\"Wallpaper\" action=\"SetAsWallpaper\"/>"
212 "</placeholder>"
213 "</menu>"
214 "</menubar>"
215 "<popup name=\"ButtonMenu\">"
216 "<menu action=\"Image\">"
217 "<placeholder name=\"WallpaperEntry\">"
218 "<separator/>"
219 "<menuitem name=\"Wallpaper\" action=\"SetAsWallpaper\"/>"
220 "</placeholder>"
221 "</menu>"
222 "</popup>"
223 "<popup name=\"PopupMenu\">"
224 "<placeholder name=\"WallpaperEntry\">"
225 "<separator/>"
226 "<menuitem action=\"SetAsWallpaper\"/>"
227 "</placeholder>"
228 "</popup>"
229 "</ui>";
230
231 /*************************************************************/
232 /***** Private actions ***************************************/
233 /*************************************************************/
234 /* Modified version of eog's eog_window_update_openwith_menu */
235 static void
vnr_window_update_openwith_menu(VnrWindow * window)236 vnr_window_update_openwith_menu (VnrWindow *window)
237 {
238 GFile *file;
239 GFileInfo *file_info;
240 GList *iter;
241 gchar *label, *tip;
242 const gchar *mime_type;
243 GtkAction *action;
244 GList *apps;
245 guint action_id = 0;
246
247 file = g_file_new_for_path ((gchar*)VNR_FILE(window->file_list->data)->path);
248 file_info = g_file_query_info (file,
249 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
250 0, NULL, NULL);
251
252 if (file_info == NULL)
253 return;
254 else
255 mime_type = g_file_info_get_content_type (file_info);
256
257 if (window->open_with_menu_id != 0)
258 {
259 gtk_ui_manager_remove_ui (window->ui_mngr, window->open_with_menu_id);
260 window->open_with_menu_id = 0;
261 }
262
263 if (window->actions_open_with != NULL)
264 {
265 gtk_ui_manager_remove_action_group (window->ui_mngr, window->actions_open_with);
266 window->actions_open_with = NULL;
267 }
268
269 if (mime_type == NULL)
270 {
271 g_object_unref (file_info);
272 return;
273 }
274
275 apps = g_app_info_get_all_for_type (mime_type);
276
277 g_object_unref (file_info);
278
279 if (!apps)
280 return;
281
282 window->actions_open_with = gtk_action_group_new ("OpenWithActions");
283 gtk_ui_manager_insert_action_group (window->ui_mngr, window->actions_open_with, -1);
284
285 window->open_with_menu_id = gtk_ui_manager_new_merge_id (window->ui_mngr);
286
287 for (iter = apps; iter; iter = iter->next) {
288 GAppInfo *app = iter->data;
289 gchar name[64];
290
291 /* Do not include viewnior itself */
292 if (g_ascii_strcasecmp (g_app_info_get_executable (app),
293 g_get_prgname ()) == 0)
294 {
295 g_object_unref (app);
296 continue;
297 }
298
299 g_snprintf (name, sizeof (name), "OpenWith%u", action_id++);
300
301 label = g_strdup (g_app_info_get_name (app));
302 tip = g_strdup_printf (_("Use \"%s\" to open the selected image"), g_app_info_get_name (app));
303 action = gtk_action_new (name, label, tip, NULL);
304
305 g_free (label);
306 g_free (tip);
307
308 g_object_set_data_full (G_OBJECT (action), "app", app,
309 (GDestroyNotify) g_object_unref);
310
311 g_signal_connect (action,
312 "activate",
313 G_CALLBACK (open_with_launch_application_cb),
314 window);
315
316 gtk_action_group_add_action (window->actions_open_with, action);
317 g_object_unref (action);
318
319 gtk_ui_manager_add_ui (window->ui_mngr,
320 window->open_with_menu_id,
321 "/MainMenu/File/FileOpenWith/AppEntries",
322 name,
323 name,
324 GTK_UI_MANAGER_MENUITEM,
325 FALSE);
326 gtk_ui_manager_add_ui (window->ui_mngr,
327 window->open_with_menu_id,
328 "/MainMenu/FileOpenWith/AppEntries",
329 name,
330 name,
331 GTK_UI_MANAGER_MENUITEM,
332 FALSE);
333 gtk_ui_manager_add_ui (window->ui_mngr,
334 window->open_with_menu_id,
335 "/PopupMenu/FileOpenWith/AppEntries",
336 name,
337 name,
338 GTK_UI_MANAGER_MENUITEM,
339 FALSE);
340 }
341
342 g_list_free (apps);
343 }
344
345 static void
vnr_window_save_accel_map()346 vnr_window_save_accel_map()
347 {
348 gchar *accelfile = g_build_filename (g_get_user_config_dir(), PACKAGE,
349 "accel_map", NULL);
350
351 gtk_accel_map_save (accelfile);
352 g_free (accelfile);
353 }
354
355 static void
vnr_window_load_accel_map()356 vnr_window_load_accel_map()
357 {
358 gchar *accelfile = g_build_filename (g_get_user_config_dir(), PACKAGE,
359 "accel_map", NULL);
360
361 gtk_accel_map_load (accelfile);
362 g_free (accelfile);
363 }
364
365 static void
vnr_window_hide_cursor(VnrWindow * window)366 vnr_window_hide_cursor(VnrWindow *window)
367 {
368 gdk_window_set_cursor (gtk_widget_get_window(GTK_WIDGET(window)), gdk_cursor_new(GDK_BLANK_CURSOR));
369 window->cursor_is_hidden = TRUE;
370 gdk_flush();
371 }
372
373 static void
vnr_window_show_cursor(VnrWindow * window)374 vnr_window_show_cursor(VnrWindow *window)
375 {
376 gdk_window_set_cursor (gtk_widget_get_window(GTK_WIDGET(window)), gdk_cursor_new(GDK_LEFT_PTR));
377 window->cursor_is_hidden = FALSE;
378 gdk_flush();
379 }
380
381 static void
update_fs_filename_label(VnrWindow * window)382 update_fs_filename_label(VnrWindow *window)
383 {
384 if(window->mode == VNR_WINDOW_MODE_NORMAL)
385 return;
386
387 gint position, total;
388 char *buf = NULL;
389
390 get_position_of_element_in_list(window->file_list, &position, &total);
391 buf = g_strdup_printf ("%s - %i/%i",
392 VNR_FILE(window->file_list->data)->display_name,
393 position, total);
394
395 gtk_label_set_text(GTK_LABEL(window->fs_filename_label), buf);
396
397 g_free(buf);
398 }
399
400 static gboolean
next_image_src(VnrWindow * window)401 next_image_src(VnrWindow *window)
402 {
403 if(g_list_length(g_list_first(window->file_list)) <= 1)
404 return FALSE;
405 else
406 vnr_window_next(window, FALSE);
407
408 window->ss_source_tag = g_timeout_add_seconds (window->ss_timeout,
409 (GSourceFunc)next_image_src,
410 window);
411
412 return FALSE;
413 }
414
415 static void
fullscreen_unset_timeout(VnrWindow * window)416 fullscreen_unset_timeout(VnrWindow *window)
417 {
418 if(window->fs_source != NULL)
419 {
420 g_source_unref (window->fs_source);
421 g_source_destroy (window->fs_source);
422 window->fs_source = NULL;
423 }
424 }
425
426 static void
fullscreen_set_timeout(VnrWindow * window)427 fullscreen_set_timeout(VnrWindow *window)
428 {
429 fullscreen_unset_timeout(window);
430
431 window->fs_source = g_timeout_source_new (FULLSCREEN_TIMEOUT);
432 g_source_set_callback (window->fs_source,
433 (GSourceFunc)fullscreen_timeout_cb,
434 window, NULL);
435
436 g_source_attach (window->fs_source, NULL);
437 }
438
439 static GtkWidget *
get_fs_controls(VnrWindow * window)440 get_fs_controls(VnrWindow *window)
441 {
442 if(window->fs_controls != NULL)
443 return window->fs_controls;
444
445 GtkWidget *box;
446 GtkToolItem *item;
447 GtkWidget *widget;
448 GtkAdjustment *spinner_adj;
449
450 /* Tool item, that contains the hbox */
451 item = gtk_tool_item_new();
452 gtk_tool_item_set_expand(item, TRUE);
453
454 box = gtk_hbox_new(FALSE, 0);
455 gtk_container_add (GTK_CONTAINER (item), box);
456
457 widget = gtk_button_new_from_stock(GTK_STOCK_LEAVE_FULLSCREEN);
458 g_signal_connect(widget, "clicked", G_CALLBACK(leave_fs_cb), window);
459 gtk_box_pack_end (GTK_BOX(box), widget, FALSE, FALSE, 0);
460
461 /* Create label for the current image's filename */
462 widget = gtk_label_new(NULL);
463 gtk_label_set_ellipsize (GTK_LABEL(widget), PANGO_ELLIPSIZE_END);
464 gtk_label_set_selectable (GTK_LABEL(widget), TRUE);
465 window->fs_filename_label = widget;
466 gtk_box_pack_end (GTK_BOX(box), widget, TRUE, TRUE, 10);
467
468
469 widget = gtk_vseparator_new();
470 gtk_box_pack_start (GTK_BOX(box), widget, FALSE, FALSE, 0);
471
472 widget = gtk_check_button_new_with_label(_("Show next image after: "));
473 g_signal_connect (widget, "toggled", G_CALLBACK(toggle_show_next_cb),
474 window);
475 gtk_box_pack_start (GTK_BOX(box), widget, FALSE, FALSE, 0);
476 window->toggle_btn = widget;
477
478 /* Create spin button to adjust slideshow's timeout */
479 //spinner_adj = (GtkAdjustment *) gtk_adjustment_new (5, 1.0, 30.0, 1.0, 1.0, 0);
480 spinner_adj = (GtkAdjustment *) gtk_adjustment_new (window->prefs->slideshow_timeout, 1.0, 30.0, 1.0, 1.0, 0);
481 widget = gtk_spin_button_new (spinner_adj, 1.0, 0);
482 gtk_spin_button_set_snap_to_ticks (GTK_SPIN_BUTTON(widget), TRUE);
483 gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON(widget),
484 GTK_UPDATE_ALWAYS);
485 g_signal_connect (widget, "value-changed",
486 G_CALLBACK(spin_value_change_cb), window);
487 gtk_box_pack_start (GTK_BOX(box), widget, FALSE, FALSE, 0);
488 window->ss_timeout_widget = widget;
489
490 window->fs_seconds_label = gtk_label_new(ngettext(" second", " seconds", 5));
491 gtk_box_pack_start (GTK_BOX(box), window->fs_seconds_label, FALSE, FALSE, 0);
492
493 window->fs_controls = GTK_WIDGET(item);
494
495 gtk_widget_show_all (window->fs_controls);
496 return window->fs_controls;
497 }
498
499 static void
vnr_window_set_drag(VnrWindow * window)500 vnr_window_set_drag(VnrWindow *window)
501 {
502 gtk_drag_dest_set (GTK_WIDGET (window),
503 GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
504 NULL, 0,
505 GDK_ACTION_COPY | GDK_ACTION_ASK);
506 gtk_drag_dest_add_uri_targets (GTK_WIDGET (window));
507 }
508
509 static void
vnr_window_fullscreen(VnrWindow * window)510 vnr_window_fullscreen(VnrWindow *window)
511 {
512 GdkColor color;
513 GtkAction *action;
514
515 gdk_color_parse ("black", &color);
516
517 gtk_widget_hide(window->menu_bar);
518 gtk_window_fullscreen(GTK_WINDOW(window));
519
520 window->mode = VNR_WINDOW_MODE_FULLSCREEN;
521 action = gtk_action_group_get_action (window->actions_image,
522 "ViewFullscreen");
523
524 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
525 gtk_widget_modify_bg(window->view, GTK_STATE_NORMAL, &color);
526
527 if (window->prefs->fit_on_fullscreen)
528 uni_image_view_set_zoom_mode (UNI_IMAGE_VIEW(window->view),
529 VNR_PREFS_ZOOM_FIT);
530
531 update_fs_filename_label(window);
532 gtk_widget_hide (window->toolbar);
533
534 if (window->prefs->show_menu_bar)
535 gtk_widget_show (window->properties_button);
536
537 gtk_widget_show (window->fs_controls);
538
539 stop_slideshow(window);
540
541 /* Reset timeouts for the toolbar autohide when the mouse
542 * moves over the UniImageviewer.
543 * "after" because it must be called after the uniImageView's
544 * callback (when the image is dragged).*/
545 g_signal_connect_after (window->view,
546 "motion-notify-event",
547 G_CALLBACK (fullscreen_motion_cb),
548 window);
549
550 /* Never hide the toolbar, while the mouse is over it */
551 g_signal_connect (window->toolbar,
552 "enter-notify-event",
553 G_CALLBACK (leave_image_area_cb),
554 window);
555
556 g_signal_connect (window->msg_area,
557 "enter-notify-event",
558 G_CALLBACK (leave_image_area_cb),
559 window);
560
561 fullscreen_set_timeout(window);
562 }
563
564 static void
vnr_window_unfullscreen(VnrWindow * window)565 vnr_window_unfullscreen(VnrWindow *window)
566 {
567 if(window->mode == VNR_WINDOW_MODE_NORMAL)
568 return;
569
570 GtkAction *action;
571
572 stop_slideshow(window);
573 window->mode = VNR_WINDOW_MODE_NORMAL;
574
575 gtk_widget_show(window->menu_bar);
576 gtk_window_unfullscreen(GTK_WINDOW(window));
577 action = gtk_action_group_get_action (window->actions_image,
578 "ViewFullscreen");
579
580 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE);
581 gtk_widget_modify_bg(window->view, GTK_STATE_NORMAL, NULL);
582
583 if (window->prefs->fit_on_fullscreen)
584 uni_image_view_set_zoom_mode (UNI_IMAGE_VIEW(window->view),
585 window->prefs->zoom);
586
587 if(window->prefs->show_menu_bar)
588 gtk_widget_hide (window->properties_button);
589 else
590 gtk_widget_hide (window->menu_bar);
591
592 gtk_widget_hide (window->fs_controls);
593
594 if(!window->prefs->show_toolbar)
595 gtk_widget_hide (window->toolbar);
596 else
597 gtk_widget_show (window->toolbar);
598
599 g_signal_handlers_disconnect_by_func(window->view,
600 G_CALLBACK(fullscreen_motion_cb),
601 window);
602
603 g_signal_handlers_disconnect_by_func(window->toolbar,
604 G_CALLBACK(leave_image_area_cb),
605 window);
606
607 g_signal_handlers_disconnect_by_func(window->msg_area,
608 G_CALLBACK(leave_image_area_cb),
609 window);
610
611 fullscreen_unset_timeout(window);
612 vnr_window_show_cursor(window);
613 }
614
615 static void
stop_slideshow(VnrWindow * window)616 stop_slideshow(VnrWindow *window)
617 {
618 if(!window->slideshow)
619 return;
620
621 if(window->mode != VNR_WINDOW_MODE_SLIDESHOW)
622 return;
623
624 GtkAction *action;
625
626 action = gtk_action_group_get_action (window->actions_collection,
627 "ViewSlideshow");
628
629 window->slideshow = FALSE;
630 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(window->toggle_btn), FALSE);
631 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE);
632 window->slideshow = TRUE;
633
634 window->mode = VNR_WINDOW_MODE_FULLSCREEN;
635
636 g_source_remove (window->ss_source_tag);
637 }
638
639 static void
start_slideshow(VnrWindow * window)640 start_slideshow(VnrWindow *window)
641 {
642 if(!window->slideshow)
643 return;
644
645 if(window->mode == VNR_WINDOW_MODE_SLIDESHOW)
646 return;
647
648 window->mode = VNR_WINDOW_MODE_SLIDESHOW;
649
650 window->ss_source_tag = g_timeout_add_seconds (window->ss_timeout,
651 (GSourceFunc)next_image_src,
652 window);
653
654 GtkAction *action;
655
656 action = gtk_action_group_get_action (window->actions_collection,
657 "ViewSlideshow");
658
659 window->slideshow = FALSE;
660 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(window->toggle_btn), TRUE);
661 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
662 window->slideshow = TRUE;
663 }
664
665 static void
restart_slideshow(VnrWindow * window)666 restart_slideshow(VnrWindow *window)
667 {
668 if(!window->slideshow)
669 return;
670
671 if(window->mode != VNR_WINDOW_MODE_SLIDESHOW)
672 return;
673
674 g_source_remove (window->ss_source_tag);
675 window->ss_source_tag = g_timeout_add_seconds (window->ss_timeout,
676 (GSourceFunc)next_image_src,
677 window);
678 }
679
680 static void
allow_slideshow(VnrWindow * window)681 allow_slideshow(VnrWindow *window)
682 {
683 if(window->slideshow)
684 return;
685
686 window->slideshow = TRUE;
687
688 gtk_widget_set_sensitive(window->toggle_btn, TRUE);
689 }
690
691 void
deny_slideshow(VnrWindow * window)692 deny_slideshow(VnrWindow *window)
693 {
694 if(!window->slideshow)
695 return;
696
697 window->slideshow = FALSE;
698
699 gtk_widget_set_sensitive(window->toggle_btn, FALSE);
700 }
701
702 static void
rotate_pixbuf(VnrWindow * window,GdkPixbufRotation angle)703 rotate_pixbuf(VnrWindow *window, GdkPixbufRotation angle)
704 {
705 GdkPixbuf *result;
706
707 if(!window->cursor_is_hidden)
708 gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window)),
709 gdk_cursor_new(GDK_WATCH));
710 /* This makes the cursor show NOW */
711 gdk_flush();
712
713 /* Stop slideshow while editing the image */
714 stop_slideshow(window);
715
716 result = gdk_pixbuf_rotate_simple(UNI_IMAGE_VIEW(window->view)->pixbuf,
717 angle);
718
719 if(result == NULL)
720 {
721 vnr_message_area_show(VNR_MESSAGE_AREA(window->msg_area),
722 TRUE, _("Not enough virtual memory."),
723 FALSE);
724 return;
725 }
726
727 uni_anim_view_set_static(UNI_ANIM_VIEW(window->view), result);
728
729 if(!window->cursor_is_hidden)
730 gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window)),
731 gdk_cursor_new(GDK_LEFT_PTR));
732 g_object_unref(result);
733
734 window->current_image_width = gdk_pixbuf_get_width (result);
735 window->current_image_height = gdk_pixbuf_get_height (result);
736
737 if(gtk_widget_get_visible(window->props_dlg))
738 vnr_properties_dialog_update_image(VNR_PROPERTIES_DIALOG(window->props_dlg));
739
740 /* Extra conditions. Rotating 180 degrees is also flipping horizontal and vertical */
741 if((window->modifications & (4))^((angle==GDK_PIXBUF_ROTATE_CLOCKWISE)<<2))
742 window->modifications ^= 3;
743
744 window->modifications ^= 4;
745 gtk_action_group_set_sensitive(window->action_save, window->modifications);
746
747 if(window->modifications == 0 && window->prefs->behavior_modify != VNR_PREFS_MODIFY_IGNORE)
748 {
749 vnr_message_area_hide(VNR_MESSAGE_AREA(window->msg_area));
750 return;
751 }
752
753 if(window->writable_format_name == NULL)
754 vnr_message_area_show(VNR_MESSAGE_AREA(window->msg_area),
755 TRUE,
756 _("Image modifications cannot be saved.\nWriting in this format is not supported."),
757 FALSE);
758 else if(window->prefs->behavior_modify == VNR_PREFS_MODIFY_SAVE)
759 save_image_cb(NULL, window);
760 else if(window->prefs->behavior_modify == VNR_PREFS_MODIFY_ASK)
761 vnr_message_area_show_with_button(VNR_MESSAGE_AREA(window->msg_area),
762 FALSE,
763 _("Save modifications?\nThis will overwrite the image and may reduce its quality!"),
764 FALSE, GTK_STOCK_SAVE,
765 G_CALLBACK(save_image_cb));
766 }
767
768 static void
flip_pixbuf(VnrWindow * window,gboolean horizontal)769 flip_pixbuf(VnrWindow *window, gboolean horizontal)
770 {
771 GdkPixbuf *result;
772
773 if(!window->cursor_is_hidden)
774 gdk_window_set_cursor (gtk_widget_get_window(GTK_WIDGET(window)),
775 gdk_cursor_new(GDK_WATCH));
776 /* This makes the cursor show NOW */
777 gdk_flush();
778
779 result = gdk_pixbuf_flip(UNI_IMAGE_VIEW(window->view)->pixbuf,
780 horizontal);
781
782 if(result == NULL)
783 {
784 vnr_message_area_show(VNR_MESSAGE_AREA(window->msg_area),
785 TRUE, _("Not enough virtual memory."),
786 FALSE);
787 return;
788 }
789
790 uni_anim_view_set_static(UNI_ANIM_VIEW(window->view), result);
791
792 if(gtk_widget_get_visible(window->props_dlg))
793 vnr_properties_dialog_update_image(VNR_PROPERTIES_DIALOG(window->props_dlg));
794
795 if(!window->cursor_is_hidden)
796 gdk_window_set_cursor (gtk_widget_get_window(GTK_WIDGET(window)),
797 gdk_cursor_new(GDK_LEFT_PTR));
798 g_object_unref(result);
799
800 /* Extra conditions. Rotating 180 degrees is also flipping horizontal and vertical */
801 window->modifications ^= (window->modifications&4)?1+horizontal:2-horizontal;
802
803 gtk_action_group_set_sensitive(window->action_save, window->modifications);
804
805 if(window->modifications == 0)
806 {
807 vnr_message_area_hide(VNR_MESSAGE_AREA(window->msg_area));
808 return;
809 }
810
811 if(window->writable_format_name == NULL)
812 vnr_message_area_show(VNR_MESSAGE_AREA(window->msg_area),
813 TRUE,
814 _("Image modifications cannot be saved.\nWriting in this format is not supported."),
815 FALSE);
816 else if(window->prefs->behavior_modify == VNR_PREFS_MODIFY_SAVE)
817 save_image_cb(NULL, window);
818 else if(window->prefs->behavior_modify == VNR_PREFS_MODIFY_ASK)
819 vnr_message_area_show_with_button(VNR_MESSAGE_AREA(window->msg_area),
820 FALSE,
821 _("Save modifications?\nThis will overwrite the image and may reduce its quality!"),
822 FALSE, GTK_STOCK_SAVE,
823 G_CALLBACK(save_image_cb));
824 }
825
826 /*************************************************************/
827 /***** Private signal handlers *******************************/
828 /*************************************************************/
829 /* Modified version of eog's open_with_launch_application_cb */
830 static void
open_with_launch_application_cb(GtkAction * action,VnrWindow * window)831 open_with_launch_application_cb (GtkAction *action, VnrWindow *window)
832 {
833 GAppInfo *app;
834 GFile *file;
835 GList *files = NULL;
836
837 file = g_file_new_for_path ((gchar*)VNR_FILE(window->file_list->data)->path);
838
839 app = g_object_get_data (G_OBJECT (action), "app");
840 files = g_list_append (files, file);
841 g_app_info_launch (app,
842 files,
843 NULL, NULL);
844
845 g_object_unref (file);
846 g_list_free (files);
847 }
848
849 static gboolean
leave_image_area_cb(GtkWidget * widget,GdkEventCrossing * ev,VnrWindow * window)850 leave_image_area_cb(GtkWidget * widget, GdkEventCrossing * ev, VnrWindow *window)
851 {
852 fullscreen_unset_timeout (window);
853 return FALSE;
854 }
855
856 static gboolean
fullscreen_motion_cb(GtkWidget * widget,GdkEventMotion * ev,VnrWindow * window)857 fullscreen_motion_cb(GtkWidget * widget, GdkEventMotion * ev, VnrWindow *window)
858 {
859 if(window->disable_autohide)
860 return FALSE;
861
862 /* Show the toolbar only when the moves moves to the top
863 * of the UniImageView */
864 if (ev->y < 20 && !gtk_widget_get_visible (window->toolbar))
865 gtk_widget_show (GTK_WIDGET (window->toolbar));
866
867 if(window->cursor_is_hidden)
868 vnr_window_show_cursor(window);
869
870 fullscreen_set_timeout(window);
871 return FALSE;
872 }
873
874 /* Hides the toolbar */
875 static gboolean
fullscreen_timeout_cb(VnrWindow * window)876 fullscreen_timeout_cb (VnrWindow *window)
877 {
878 fullscreen_unset_timeout (window);
879
880 if(window->disable_autohide)
881 return FALSE;
882
883 gtk_widget_hide (window->toolbar);
884 vnr_window_hide_cursor(window);
885 return FALSE;
886 }
887
888 static void
spin_value_change_cb(GtkSpinButton * spinbutton,VnrWindow * window)889 spin_value_change_cb (GtkSpinButton *spinbutton, VnrWindow *window)
890 {
891 int new_value = gtk_spin_button_get_value_as_int (spinbutton);
892
893 if(new_value != window->prefs->slideshow_timeout)
894 vnr_prefs_set_slideshow_timeout(window->prefs, new_value);
895
896 gtk_label_set_text (GTK_LABEL(window->fs_seconds_label),
897 ngettext(" second", " seconds", new_value));
898 window->ss_timeout = new_value;
899 restart_slideshow(window);
900 }
901
902 static void
toggle_show_next_cb(GtkToggleButton * togglebutton,VnrWindow * window)903 toggle_show_next_cb (GtkToggleButton *togglebutton, VnrWindow *window)
904 {
905 if(!window->slideshow)
906 return;
907
908 if(window->mode == VNR_WINDOW_MODE_FULLSCREEN)
909 start_slideshow(window);
910 else if(window->mode == VNR_WINDOW_MODE_SLIDESHOW)
911 stop_slideshow(window);
912 }
913
914 static void
save_image_cb(GtkWidget * widget,VnrWindow * window)915 save_image_cb (GtkWidget *widget, VnrWindow *window)
916 {
917 GError *error = NULL;
918 if(!window->cursor_is_hidden)
919 gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window)), gdk_cursor_new(GDK_WATCH));
920 /* This makes the cursor show NOW */
921 gdk_flush();
922
923 if(window->prefs->behavior_modify == VNR_PREFS_MODIFY_ASK)
924 vnr_message_area_hide(VNR_MESSAGE_AREA(window->msg_area));
925
926 /* Store exiv2 metadata to cache, so we can restore it afterwards */
927 uni_read_exiv2_to_cache(VNR_FILE(window->file_list->data)->path);
928
929 if(g_strcmp0(window->writable_format_name, "jpeg" ) == 0)
930 {
931 gchar *quality;
932 quality = g_strdup_printf ("%i", window->prefs->jpeg_quality);
933
934 gdk_pixbuf_save (uni_image_view_get_pixbuf(UNI_IMAGE_VIEW(window->view)),
935 VNR_FILE(window->file_list->data)->path, "jpeg",
936 &error, "quality", quality, NULL);
937 g_free(quality);
938 }
939 else if(g_strcmp0(window->writable_format_name, "png" ) == 0)
940 {
941 gchar *compression;
942 compression = g_strdup_printf ("%i", window->prefs->png_compression);
943
944 gdk_pixbuf_save (uni_image_view_get_pixbuf(UNI_IMAGE_VIEW(window->view)),
945 VNR_FILE(window->file_list->data)->path, "png",
946 &error, "compression", compression, NULL);
947 g_free(compression);
948 }
949 else
950 {
951 gdk_pixbuf_save (uni_image_view_get_pixbuf(UNI_IMAGE_VIEW(window->view)),
952 VNR_FILE(window->file_list->data)->path,
953 window->writable_format_name, &error, NULL);
954 }
955 uni_write_exiv2_from_cache(VNR_FILE(window->file_list->data)->path);
956
957 if(!window->cursor_is_hidden)
958 gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window)), gdk_cursor_new(GDK_LEFT_PTR));
959
960 if(error != NULL)
961 {
962 vnr_message_area_show(VNR_MESSAGE_AREA(window->msg_area), TRUE,
963 error->message, FALSE);
964 return;
965 }
966
967 if(window->prefs->reload_on_save)
968 {
969 vnr_window_open(window, FALSE);
970 return;
971 }
972
973 window->modifications = 0;
974
975 gtk_action_group_set_sensitive(window->action_save, FALSE);
976
977 if(window->prefs->behavior_modify != VNR_PREFS_MODIFY_ASK)
978 zoom_changed_cb(UNI_IMAGE_VIEW(window->view), window);
979
980 if(gtk_widget_get_visible(window->props_dlg))
981 vnr_properties_dialog_update(VNR_PROPERTIES_DIALOG(window->props_dlg));
982 }
983
984 static void
vnr_window_main_menu_position(GtkMenu * menu,gint * x,gint * y,gboolean * push_in,gpointer user_data)985 vnr_window_main_menu_position (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data)
986 {
987 VnrWindow *window = VNR_WINDOW(user_data);
988 GtkWidget *button = window->properties_button;
989 GdkWindow *gdk_window = gtk_widget_get_window(button);
990 GtkRequisition req = {0, 0};
991 GtkAllocation toolbar_allocation;
992 GtkAllocation button_allocation;
993
994 gdk_window_get_position(gdk_window, x, y);
995
996 // in maximuzed and fullscreen states gdk_window_get_position returns 0
997 if ( *x == 0 && gtk_widget_get_visible ( get_fs_controls(window)) ) {
998 GtkAllocation allocation;
999
1000 gtk_widget_get_allocation(get_fs_controls(window), &allocation);
1001 *x -= allocation.width;
1002 }
1003
1004 gtk_widget_size_request(GTK_WIDGET(menu), &req);
1005 gtk_widget_get_allocation(window->toolbar, &toolbar_allocation);
1006 gtk_widget_get_allocation(button, &button_allocation);
1007
1008 *x += toolbar_allocation.width - req.width;
1009 *y += button_allocation.height;
1010 }
1011
1012 static void
vnr_window_cmd_open_menu(GtkToggleAction * action,VnrWindow * window)1013 vnr_window_cmd_open_menu (GtkToggleAction *action, VnrWindow *window)
1014 {
1015 if( !gtk_toggle_action_get_active (action)) {
1016 return;
1017 }
1018 gtk_menu_popup(GTK_MENU(window->button_menu), NULL, NULL, vnr_window_main_menu_position, window, 0, gtk_get_current_event_time());
1019 return;
1020 }
1021
1022 static void
vnr_window_cmd_main_menu_hidden(GtkWidget * widget,gpointer user_data)1023 vnr_window_cmd_main_menu_hidden (GtkWidget *widget, gpointer user_data)
1024 {
1025 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(VNR_WINDOW(user_data)->properties_button), FALSE);
1026 }
1027
1028 static void
leave_fs_cb(GtkButton * button,VnrWindow * window)1029 leave_fs_cb (GtkButton *button, VnrWindow *window)
1030 {
1031 vnr_window_unfullscreen (window);
1032 }
1033
1034 static void
window_realize_cb(GtkWidget * widget,gpointer user_data)1035 window_realize_cb(GtkWidget *widget, gpointer user_data)
1036 {
1037 g_signal_handlers_disconnect_by_func(widget, window_realize_cb, user_data);
1038
1039 if(!vnr_message_area_is_critical(VNR_MESSAGE_AREA(VNR_WINDOW(widget)->msg_area)))
1040 {
1041 if ( VNR_WINDOW(widget)->prefs->start_maximized ) {
1042 vnr_window_open(VNR_WINDOW(widget), FALSE);
1043 }
1044 else
1045 {
1046 GdkScreen *screen;
1047 GdkRectangle monitor;
1048 screen = gtk_window_get_screen (GTK_WINDOW (widget));
1049 gdk_screen_get_monitor_geometry (screen,
1050 gdk_screen_get_monitor_at_window (screen,
1051 gtk_widget_get_window (widget)),
1052 &monitor);
1053
1054 VNR_WINDOW(widget)->max_width = monitor.width * 0.9 - 100;
1055 VNR_WINDOW(widget)->max_height = monitor.height * 0.9 - 100;
1056
1057 vnr_window_open(VNR_WINDOW(widget), TRUE);
1058 }
1059 if ( VNR_WINDOW(widget)->prefs->start_slideshow && VNR_WINDOW(widget)->file_list != NULL ) {
1060 vnr_window_fullscreen(VNR_WINDOW(widget));
1061 VNR_WINDOW(widget)->mode = VNR_WINDOW_MODE_NORMAL;
1062 allow_slideshow(VNR_WINDOW(widget));
1063 start_slideshow(VNR_WINDOW(widget));
1064 } else if ( VNR_WINDOW(widget)->prefs->start_fullscreen && VNR_WINDOW(widget)->file_list != NULL ) {
1065 vnr_window_fullscreen(VNR_WINDOW(widget));
1066 }
1067 }
1068 }
1069
1070 static gboolean
window_change_state_cb(GtkWidget * widget,GdkEventWindowState * event,gpointer user_data)1071 window_change_state_cb (GtkWidget * widget, GdkEventWindowState * event, gpointer user_data)
1072 {
1073 if ( event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED ) {
1074 /* Detect maximized state only */
1075 if ( event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED ) {
1076 VNR_WINDOW(widget)->prefs->start_maximized = TRUE;
1077 } else {
1078 VNR_WINDOW(widget)->prefs->start_maximized = FALSE;
1079 }
1080 vnr_prefs_save(VNR_WINDOW(widget)->prefs);
1081 }
1082 return TRUE;
1083 }
1084
1085
1086 static void
window_destroy_cb(GtkObject * object,gpointer user_data)1087 window_destroy_cb (GtkObject *object, gpointer user_data)
1088 {
1089 vnr_window_save_accel_map();
1090 vnr_prefs_save(VNR_WINDOW(object)->prefs);
1091 gtk_main_quit();
1092 }
1093
1094 static void
zoom_changed_cb(UniImageView * view,VnrWindow * window)1095 zoom_changed_cb (UniImageView *view, VnrWindow *window)
1096 {
1097 gint position, total;
1098 char *buf = NULL;
1099
1100 /* Change the info, only if there is an image
1101 * (vnr_window_close isn't called on the current image) */
1102 if(gtk_action_group_get_sensitive (window->actions_image))
1103 {
1104 get_position_of_element_in_list(window->file_list, &position, &total);
1105 buf = g_strdup_printf ("%s%s - %i/%i - %ix%i - %i%%", (window->modifications)?"*":"",
1106 VNR_FILE(window->file_list->data)->display_name,
1107 position, total,
1108 window->current_image_width, window->current_image_height,
1109 (int)(view->zoom*100.));
1110
1111 gtk_window_set_title (GTK_WINDOW(window), buf);
1112 g_free(buf);
1113 }
1114 }
1115
1116
1117 static void
window_drag_begin_cb(GtkWidget * widget,GdkDragContext * drag_context,GtkSelectionData * data,guint info,guint time,gpointer user_data)1118 window_drag_begin_cb (GtkWidget *widget,
1119 GdkDragContext *drag_context,
1120 GtkSelectionData *data,
1121 guint info,
1122 guint time,
1123 gpointer user_data)
1124 {
1125 gchar *uris[2];
1126
1127 uris[0] = g_filename_to_uri((gchar*)VNR_FILE(VNR_WINDOW(user_data)->file_list->data)->path, NULL, NULL);
1128 uris[1] = NULL;
1129
1130 gtk_selection_data_set_uris (data, uris);
1131
1132 g_free(uris[0]);
1133 }
1134
1135 static void
file_open_dialog_response_cb(GtkWidget * dialog,gint response_id,VnrWindow * window)1136 file_open_dialog_response_cb (GtkWidget *dialog,
1137 gint response_id,
1138 VnrWindow *window)
1139 {
1140 if (response_id == GTK_RESPONSE_ACCEPT)
1141 {
1142 GSList *uri_list = NULL;
1143 uri_list = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (dialog));
1144 g_return_if_fail(uri_list != NULL);
1145 vnr_window_open_from_list(window, uri_list);
1146 }
1147
1148 gtk_widget_destroy (dialog);
1149 }
1150
1151 static void
vnr_window_cmd_preferences(GtkAction * action,gpointer user_data)1152 vnr_window_cmd_preferences(GtkAction *action, gpointer user_data)
1153 {
1154 vnr_prefs_show_dialog(VNR_WINDOW(user_data)->prefs);
1155 }
1156
1157 static void
vnr_window_cmd_flip_horizontal(GtkAction * action,VnrWindow * window)1158 vnr_window_cmd_flip_horizontal(GtkAction *action, VnrWindow *window)
1159 {
1160 if ( !gtk_action_group_get_sensitive(window->actions_static_image) )
1161 return;
1162
1163 flip_pixbuf(window, TRUE);
1164 }
1165
1166 static void
vnr_window_cmd_flip_vertical(GtkAction * action,VnrWindow * window)1167 vnr_window_cmd_flip_vertical(GtkAction *action, VnrWindow *window)
1168 {
1169 if ( !gtk_action_group_get_sensitive(window->actions_static_image) )
1170 return;
1171
1172 flip_pixbuf(window, FALSE);
1173 }
1174
1175 static void
vnr_window_cmd_rotate_cw(GtkAction * action,gpointer user_data)1176 vnr_window_cmd_rotate_cw(GtkAction *action, gpointer user_data)
1177 {
1178 rotate_pixbuf(VNR_WINDOW(user_data), GDK_PIXBUF_ROTATE_CLOCKWISE);
1179 }
1180
1181 static void
vnr_window_cmd_rotate_ccw(GtkAction * action,gpointer user_data)1182 vnr_window_cmd_rotate_ccw(GtkAction *action, gpointer user_data)
1183 {
1184 rotate_pixbuf(VNR_WINDOW(user_data), GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE);
1185 }
1186
1187 static void
vnr_window_cmd_zoom_in(GtkAction * action,gpointer user_data)1188 vnr_window_cmd_zoom_in (GtkAction *action, gpointer user_data)
1189 {
1190 uni_image_view_zoom_in(UNI_IMAGE_VIEW(VNR_WINDOW(user_data)->view));
1191 }
1192
1193 static void
vnr_window_cmd_zoom_out(GtkAction * action,gpointer user_data)1194 vnr_window_cmd_zoom_out (GtkAction *action, gpointer user_data)
1195 {
1196 uni_image_view_zoom_out(UNI_IMAGE_VIEW(VNR_WINDOW(user_data)->view));
1197 }
1198
1199 static void
vnr_window_cmd_normal_size(GtkAction * action,gpointer user_data)1200 vnr_window_cmd_normal_size (GtkAction *action, gpointer user_data)
1201 {
1202 uni_image_view_set_zoom(UNI_IMAGE_VIEW(VNR_WINDOW(user_data)->view), 1);
1203 uni_image_view_set_fitting(UNI_IMAGE_VIEW(VNR_WINDOW(user_data)->view), UNI_FITTING_NONE);
1204 }
1205
1206 static void
vnr_window_cmd_fit(GtkAction * action,gpointer user_data)1207 vnr_window_cmd_fit (GtkAction *action, gpointer user_data)
1208 {
1209 uni_image_view_set_fitting(UNI_IMAGE_VIEW(VNR_WINDOW(user_data)->view), UNI_FITTING_FULL);
1210 }
1211
1212 static void
vnr_window_cmd_next(GtkAction * action,gpointer user_data)1213 vnr_window_cmd_next (GtkAction *action, gpointer user_data)
1214 {
1215 vnr_window_next(VNR_WINDOW(user_data), TRUE);
1216 }
1217
1218 static void
vnr_window_cmd_first(GtkAction * action,gpointer user_data)1219 vnr_window_cmd_first (GtkAction *action, gpointer user_data)
1220 {
1221 vnr_window_first(VNR_WINDOW(user_data));
1222 }
1223
1224 static void
vnr_window_cmd_last(GtkAction * action,gpointer user_data)1225 vnr_window_cmd_last (GtkAction *action, gpointer user_data)
1226 {
1227 vnr_window_last(VNR_WINDOW(user_data));
1228 }
1229
1230 static void
vnr_window_cmd_prev(GtkAction * action,gpointer user_data)1231 vnr_window_cmd_prev (GtkAction *action, gpointer user_data)
1232 {
1233 vnr_window_prev(VNR_WINDOW(user_data));
1234 }
1235
1236 static void
vnr_window_cmd_resize(GtkToggleAction * action,VnrWindow * window)1237 vnr_window_cmd_resize (GtkToggleAction *action, VnrWindow *window)
1238 {
1239 GtkAllocation allocation;
1240
1241 if ( action != NULL && !gtk_toggle_action_get_active(action) ) {
1242 window->prefs->auto_resize = FALSE;
1243 return;
1244 }
1245
1246 gint img_h, img_w; /* Width and Height of the pixbuf */
1247
1248 img_w = window->current_image_width;
1249 img_h = window->current_image_height;
1250
1251 if ( img_w == 0 || img_h == 0 )
1252 return;
1253
1254 window->prefs->auto_resize = TRUE;
1255
1256 vnr_tools_fit_to_size (&img_w, &img_h, window->max_width, window->max_height);
1257 gtk_widget_get_allocation (window->menus, &allocation);
1258 gtk_window_resize (GTK_WINDOW (window), img_w, img_h + allocation.height);
1259 }
1260
1261 static void
vnr_window_cmd_properties(GtkAction * action,VnrWindow * window)1262 vnr_window_cmd_properties (GtkAction *action, VnrWindow *window)
1263 {
1264 vnr_properties_dialog_show(VNR_PROPERTIES_DIALOG (window->props_dlg));
1265 }
1266
1267 static void
vnr_window_cmd_reload(GtkAction * action,VnrWindow * window)1268 vnr_window_cmd_reload (GtkAction *action, VnrWindow *window)
1269 {
1270 vnr_window_open(window, FALSE);
1271 }
1272
1273 static void
vnr_window_cmd_open(GtkAction * action,VnrWindow * window)1274 vnr_window_cmd_open(GtkAction *action, VnrWindow *window)
1275 {
1276 GtkWidget *dialog;
1277 GtkFileFilter *img_filter = NULL;
1278 GtkFileFilter *all_filter = NULL;
1279
1280 dialog = gtk_file_chooser_dialog_new (_("Open Image"),
1281 GTK_WINDOW(window),
1282 GTK_FILE_CHOOSER_ACTION_OPEN,
1283 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1284 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1285 NULL);
1286
1287 img_filter = gtk_file_filter_new ();
1288 g_assert (img_filter != NULL);
1289 gtk_file_filter_add_pixbuf_formats (img_filter);
1290 gtk_file_filter_add_mime_type (img_filter, "image/vnd.microsoft.icon");
1291 gtk_file_filter_set_name (img_filter, _("All Images"));
1292 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), img_filter);
1293
1294 all_filter = gtk_file_filter_new ();
1295 g_assert(all_filter != NULL);
1296 gtk_file_filter_add_pattern (all_filter, "*");
1297 gtk_file_filter_set_name (all_filter, _("All Files"));
1298 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), all_filter);
1299
1300 gtk_window_set_modal (GTK_WINDOW(dialog), FALSE);
1301 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
1302
1303 gtk_file_chooser_set_filter (GTK_FILE_CHOOSER(dialog), img_filter);
1304
1305 gchar *dirname;
1306 if(window->file_list != NULL)
1307 {
1308 dirname = g_path_get_dirname (VNR_FILE(window->file_list->data)->path);
1309 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(dialog), dirname);
1310 g_free(dirname);
1311 }
1312
1313 g_signal_connect (dialog, "response",
1314 G_CALLBACK (file_open_dialog_response_cb),
1315 window);
1316
1317 gtk_widget_show_all (GTK_WIDGET(dialog));
1318
1319 /* This only works when here. */
1320 gtk_file_chooser_set_show_hidden (GTK_FILE_CHOOSER(dialog), window->prefs->show_hidden);
1321 }
1322
1323 static void
vnr_window_cmd_open_dir(GtkAction * action,VnrWindow * window)1324 vnr_window_cmd_open_dir(GtkAction *action, VnrWindow *window)
1325 {
1326 GtkWidget *dialog;
1327 dialog = gtk_file_chooser_dialog_new (_("Open Folder"),
1328 GTK_WINDOW(window),
1329 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
1330 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1331 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1332 NULL);
1333
1334 gtk_window_set_modal (GTK_WINDOW(dialog), FALSE);
1335 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
1336
1337 gchar *dirname;
1338 if(window->file_list != NULL)
1339 {
1340 dirname = g_path_get_dirname (VNR_FILE(window->file_list->data)->path);
1341 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(dialog), dirname);
1342 g_free(dirname);
1343 }
1344
1345 g_signal_connect (dialog, "response",
1346 G_CALLBACK (file_open_dialog_response_cb),
1347 window);
1348
1349 gtk_widget_show_all (GTK_WIDGET(dialog));
1350
1351 /* This only works when here. */
1352 gtk_file_chooser_set_show_hidden (GTK_FILE_CHOOSER(dialog), window->prefs->show_hidden);
1353 }
1354
1355 static void
vnr_window_cmd_about(GtkAction * action,VnrWindow * window)1356 vnr_window_cmd_about (GtkAction *action, VnrWindow *window)
1357 {
1358 static const char *authors[] = {
1359 "Programming & icon design",
1360 "\tSiyan Panayotov <contact@siyanpanayotov.com>",
1361 "\nRefer to source code from GtkImageView",
1362 NULL
1363 };
1364
1365 char *license =
1366 ("Viewnior is free software: you can redistribute it and/or modify "
1367 "it under the terms of the GNU General Public License as published by "
1368 "the Free Software Foundation, either version 3 of the License, or "
1369 "(at your option) any later version.\n\n"
1370 "Viewnior is distributed in the hope that it will be useful, "
1371 "but WITHOUT ANY WARRANTY; without even the implied warranty of "
1372 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
1373 "GNU General Public License for more details.\n\n"
1374 "You should have received a copy of the GNU General Public License "
1375 "along with Viewnior. If not, see <http://www.gnu.org/licenses/>.\n");
1376
1377 gtk_show_about_dialog (GTK_WINDOW (window),
1378 "program-name", "Viewnior",
1379 "version", VERSION,
1380 "copyright", "Copyright \xc2\xa9 2009-2018 Siyan Panayotov <contact@siyanpanayotov.com>",
1381 "comments",_("Elegant Image Viewer"),
1382 "authors", authors,
1383 "logo-icon-name", "viewnior",
1384 "wrap-license", TRUE,
1385 "license", license,
1386 "website", "http://siyanpanayotov.com/project/viewnior/",
1387 "translator-credits", _( "translator-credits" ),
1388 NULL);
1389 }
1390
1391 static void
vnr_set_wallpaper(GtkAction * action,VnrWindow * win)1392 vnr_set_wallpaper(GtkAction *action, VnrWindow *win)
1393 {
1394 pid_t pid;
1395
1396 pid = fork();
1397
1398 if ( pid == 0 ) {
1399 gchar * tmp;
1400
1401 VnrPrefsDesktop desktop_environment = win->prefs->desktop;
1402
1403 if (desktop_environment == VNR_PREFS_DESKTOP_AUTO)
1404 {
1405 desktop_environment = uni_detect_desktop_environment();
1406 }
1407
1408 switch(desktop_environment) {
1409 case VNR_PREFS_DESKTOP_GNOME2:
1410 execlp("gconftool-2", "gconftool-2",
1411 "--set", "/desktop/gnome/background/picture_filename",
1412 "--type", "string",
1413 VNR_FILE(win->file_list->data)->path,
1414 NULL);
1415 break;
1416 case VNR_PREFS_DESKTOP_MATE:
1417 execlp("gsettings", "gsettings",
1418 "set", "org.mate.background",
1419 "picture-filename", VNR_FILE(win->file_list->data)->path,
1420 NULL);
1421 break;
1422 case VNR_PREFS_DESKTOP_GNOME3:
1423 tmp = g_strdup_printf("file://%s", VNR_FILE(win->file_list->data)->path);
1424 execlp("gsettings", "gsettings",
1425 "set", "org.gnome.desktop.background",
1426 "picture-uri", tmp,
1427 NULL);
1428 break;
1429 case VNR_PREFS_DESKTOP_XFCE:
1430 tmp = g_strdup_printf("/backdrop/screen%d/monitor0/workspace0/last-image",
1431 gdk_screen_get_number(gtk_widget_get_screen(GTK_WIDGET(win))));
1432 execlp("xfconf-query", "xfconf-query",
1433 "-c", "xfce4-desktop",
1434 "-p", tmp,
1435 "--type", "string",
1436 "--set",
1437 VNR_FILE(win->file_list->data)->path,
1438 NULL);
1439 break;
1440 case VNR_PREFS_DESKTOP_LXDE:
1441 execlp("pcmanfm", "pcmanfm",
1442 "--set-wallpaper",
1443 VNR_FILE(win->file_list->data)->path,
1444 NULL);
1445 break;
1446 case VNR_PREFS_DESKTOP_PUPPY:
1447 execlp("set_bg", "set_bg",
1448 VNR_FILE(win->file_list->data)->path,
1449 NULL);
1450 break;
1451 case VNR_PREFS_DESKTOP_FLUXBOX:
1452 execlp("fbsetbg", "fbsetbg",
1453 "-f", VNR_FILE(win->file_list->data)->path,
1454 NULL);
1455 break;
1456 case VNR_PREFS_DESKTOP_NITROGEN:
1457 execlp("nitrogen", "nitrogen",
1458 "--set-zoom-fill", "--save",
1459 VNR_FILE(win->file_list->data)->path,
1460 NULL);
1461 break;
1462 case VNR_PREFS_DESKTOP_CINNAMON:
1463 tmp = g_strdup_printf("file://%s", VNR_FILE(win->file_list->data)->path);
1464 execlp("gsettings", "gsettings",
1465 "set", "org.cinnamon.desktop.background",
1466 "picture-uri", tmp,
1467 NULL);
1468 break;
1469 default:
1470 _exit(0);
1471 }
1472 } else {
1473 wait(NULL);
1474 }
1475 }
1476
1477 static void
vnr_window_cmd_fullscreen(GtkAction * action,VnrWindow * window)1478 vnr_window_cmd_fullscreen (GtkAction *action, VnrWindow *window)
1479 {
1480 gboolean fullscreen;
1481
1482 fullscreen = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1483
1484 if (fullscreen)
1485 vnr_window_fullscreen (window);
1486 else
1487 vnr_window_unfullscreen (window);
1488 }
1489
1490 static void
vnr_window_cmd_menu_bar(GtkAction * action,VnrWindow * window)1491 vnr_window_cmd_menu_bar (GtkAction *action, VnrWindow *window)
1492 {
1493 gboolean show;
1494
1495 show = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1496 vnr_prefs_set_show_menu_bar(window->prefs, show);
1497
1498 if(window->mode != VNR_WINDOW_MODE_NORMAL)
1499 return;
1500
1501
1502 if (show)
1503 {
1504 gtk_widget_show (window->menu_bar);
1505 gtk_widget_hide (window->properties_button);
1506 }
1507 else
1508 {
1509 gtk_widget_hide (window->menu_bar);
1510 gtk_widget_show (window->properties_button);
1511 }
1512 }
1513
1514 static void
vnr_window_cmd_toolbar(GtkAction * action,VnrWindow * window)1515 vnr_window_cmd_toolbar (GtkAction *action, VnrWindow *window)
1516 {
1517 gboolean show;
1518
1519 show = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1520 vnr_prefs_set_show_toolbar(window->prefs, show);
1521
1522 if (show)
1523 gtk_widget_show (window->toolbar);
1524 else
1525 gtk_widget_hide (window->toolbar);
1526 }
1527
1528 static void
vnr_window_cmd_scrollbar(GtkAction * action,VnrWindow * window)1529 vnr_window_cmd_scrollbar (GtkAction *action, VnrWindow *window)
1530 {
1531 gboolean show;
1532
1533 show = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1534 vnr_prefs_set_show_scrollbar (window->prefs, show);
1535 uni_scroll_win_set_show_scrollbar (UNI_SCROLL_WIN (window->scroll_view), show);
1536 }
1537
1538 static void
vnr_window_cmd_slideshow(GtkAction * action,VnrWindow * window)1539 vnr_window_cmd_slideshow (GtkAction *action, VnrWindow *window)
1540 {
1541 if(!window->slideshow)
1542 return;
1543
1544 g_assert(window != NULL && VNR_IS_WINDOW(window));
1545
1546 gboolean slideshow;
1547
1548 slideshow = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1549
1550 if (slideshow && window->mode != VNR_WINDOW_MODE_SLIDESHOW)
1551 {
1552 /* ! Uncomment to force Fullscreen along with Slideshow */
1553 if(window->mode == VNR_WINDOW_MODE_NORMAL)
1554 {
1555 vnr_window_fullscreen (window);
1556 }
1557 start_slideshow(window);
1558 }
1559 else if(window->mode == VNR_WINDOW_MODE_SLIDESHOW)
1560 {
1561 /* ! Uncomment to force Fullscreen along with Slideshow */
1562 vnr_window_unfullscreen (window);
1563 stop_slideshow(window);
1564 }
1565 }
1566
1567 static void
vnr_window_cmd_delete(GtkAction * action,VnrWindow * window)1568 vnr_window_cmd_delete(GtkAction *action, VnrWindow *window)
1569 {
1570 GtkWidget *dlg = NULL;
1571 const gchar *file_path;
1572 gchar *markup, *prompt, *warning;
1573 gboolean restart_slideshow = FALSE;
1574 gboolean restart_autohide_timeout = FALSE;
1575 gboolean cursor_was_hidden = FALSE;
1576
1577 /* Used to get rid of the "may be used uninitialised" warning */
1578 markup = prompt = warning = NULL;
1579
1580 if(window->mode == VNR_WINDOW_MODE_SLIDESHOW)
1581 {
1582 stop_slideshow(window);
1583 restart_slideshow = TRUE;
1584 }
1585
1586 if(window->cursor_is_hidden)
1587 {
1588 cursor_was_hidden = TRUE;
1589 vnr_window_show_cursor(window);
1590 }
1591 window->disable_autohide = TRUE;
1592
1593 if(window->fs_source != NULL)
1594 restart_autohide_timeout = TRUE;
1595
1596 g_return_if_fail (window->file_list != NULL);
1597
1598 file_path = VNR_FILE(window->file_list->data)->path;
1599
1600 if(window->prefs->confirm_delete)
1601 {
1602 warning = _("If you delete an item, it will be permanently lost.");
1603
1604 /* I18N: The '%s' is replaced with the name of the file to be deleted. */
1605 prompt = g_strdup_printf (_("Are you sure you want to\n"
1606 "permanently delete \"%s\"?"),
1607 VNR_FILE(window->file_list->data)->display_name);
1608 markup = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s",
1609 prompt, warning);
1610
1611
1612 dlg = gtk_message_dialog_new(GTK_WINDOW(window),
1613 GTK_DIALOG_MODAL,
1614 GTK_MESSAGE_WARNING,
1615 GTK_BUTTONS_NONE,
1616 NULL);
1617
1618 gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dlg),
1619 markup);
1620
1621 gtk_dialog_add_buttons (GTK_DIALOG (dlg),
1622 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1623 GTK_STOCK_DELETE, GTK_RESPONSE_YES,
1624 NULL);
1625 }
1626
1627 if(!window->prefs->confirm_delete || gtk_dialog_run(GTK_DIALOG(dlg)) == GTK_RESPONSE_YES )
1628 {
1629 GFile *file;
1630 GError *error = NULL;
1631
1632 file = g_file_new_for_path(file_path);
1633 g_file_delete(file, NULL, &error);
1634
1635 if( error != NULL )
1636 {
1637 vnr_message_area_show(VNR_MESSAGE_AREA (window->msg_area), TRUE,
1638 error->message, FALSE);
1639 restart_slideshow = FALSE;
1640 }
1641 else
1642 {
1643 GList *next;
1644
1645 next = g_list_next(window->file_list);
1646 if(next == NULL)
1647 next = g_list_first(window->file_list);
1648
1649 if(g_list_length(g_list_first(window->file_list)) != 1)
1650 window->file_list = g_list_delete_link (window->file_list, window->file_list);
1651 else
1652 {
1653 g_list_free(window->file_list);
1654 next = NULL;
1655 }
1656
1657 if(next == NULL)
1658 {
1659 vnr_window_close(window);
1660 gtk_action_group_set_sensitive(window->actions_collection, FALSE);
1661 deny_slideshow(window);
1662 vnr_window_set_list(window, NULL, FALSE);
1663 vnr_message_area_show(VNR_MESSAGE_AREA (window->msg_area), TRUE,
1664 _("The given locations contain no images."),
1665 TRUE);
1666 restart_slideshow = FALSE;
1667
1668
1669 if(gtk_widget_get_visible(window->props_dlg))
1670 vnr_properties_dialog_clear(VNR_PROPERTIES_DIALOG(window->props_dlg));
1671 }
1672 else
1673 {
1674 vnr_window_set_list(window, next, FALSE);
1675 if(window->prefs->confirm_delete && !window->cursor_is_hidden)
1676 gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(dlg)),
1677 gdk_cursor_new(GDK_WATCH));
1678
1679 gdk_flush();
1680
1681 vnr_window_close(window);
1682 vnr_window_open(window, FALSE);
1683 if(window->prefs->confirm_delete && !window->cursor_is_hidden)
1684 gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(dlg)),
1685 gdk_cursor_new(GDK_LEFT_PTR));
1686 }
1687 }
1688 }
1689
1690 window->disable_autohide = FALSE;
1691
1692 if(restart_slideshow)
1693 start_slideshow(window);
1694 if(cursor_was_hidden)
1695 vnr_window_hide_cursor(window);
1696 if(restart_autohide_timeout)
1697 fullscreen_set_timeout(window);
1698
1699 if(window->prefs->confirm_delete)
1700 {
1701 g_free(prompt);
1702 g_free(markup);
1703 gtk_widget_destroy( dlg );
1704 }
1705 }
1706
1707 static void
vnr_window_cmd_crop(GtkAction * action,VnrWindow * window)1708 vnr_window_cmd_crop(GtkAction *action, VnrWindow *window)
1709 {
1710 VnrCrop *crop;
1711
1712 if ( !gtk_action_group_get_sensitive(window->actions_static_image) )
1713 return;
1714
1715 crop = (VnrCrop*) vnr_crop_new (window);
1716
1717 if(! vnr_crop_run(crop))
1718 {
1719 g_object_unref(crop);
1720 return;
1721 }
1722
1723 GdkPixbuf *cropped;
1724 GdkPixbuf *original;
1725
1726 original = uni_image_view_get_pixbuf(UNI_IMAGE_VIEW(window->view));
1727
1728 cropped = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (original),
1729 gdk_pixbuf_get_has_alpha (original),
1730 gdk_pixbuf_get_bits_per_sample (original),
1731 crop->area.width, crop->area.height);
1732
1733 gdk_pixbuf_copy_area((const GdkPixbuf*)original, crop->area.x, crop->area.y,
1734 crop->area.width, crop->area.height, cropped, 0, 0);
1735
1736 uni_anim_view_set_static(UNI_ANIM_VIEW(window->view), cropped);
1737
1738 g_object_unref(cropped);
1739
1740 window->modifications |= 8;
1741
1742 window->current_image_width = crop->area.width;
1743 window->current_image_height = crop->area.height;
1744
1745 gtk_action_group_set_sensitive(window->action_save, TRUE);
1746
1747 if(window->writable_format_name == NULL)
1748 vnr_message_area_show(VNR_MESSAGE_AREA(window->msg_area),
1749 TRUE,
1750 _("Image modifications cannot be saved.\nWriting in this format is not supported."),
1751 FALSE);
1752 else if(window->prefs->behavior_modify == VNR_PREFS_MODIFY_SAVE)
1753 save_image_cb(NULL, window);
1754 else if(window->prefs->behavior_modify == VNR_PREFS_MODIFY_ASK)
1755 vnr_message_area_show_with_button(VNR_MESSAGE_AREA(window->msg_area),
1756 FALSE,
1757 _("Save modifications?\nThis will overwrite the image and may reduce its quality!"),
1758 FALSE, GTK_STOCK_SAVE,
1759 G_CALLBACK(save_image_cb));
1760
1761 g_object_unref(crop);
1762 }
1763
1764 static const GtkActionEntry action_entries_window[] = {
1765 { "File", NULL, N_("_File") },
1766 { "Edit", NULL, N_("_Edit") },
1767 { "View", NULL, N_("_View") },
1768 { "Image", NULL, N_("_Image") },
1769 { "Go", NULL, N_("_Go") },
1770 { "Help", NULL, N_("_Help") },
1771
1772 { "FileOpen", GTK_STOCK_FILE, N_("Open _Image..."), "<control>O",
1773 N_("Open an Image"),
1774 G_CALLBACK (vnr_window_cmd_open) },
1775 { "FileOpenDir", GTK_STOCK_DIRECTORY, N_("Open _Folder..."), "<control>F",
1776 N_("Open a Folder"),
1777 G_CALLBACK (vnr_window_cmd_open_dir) },
1778 { "FileClose", GTK_STOCK_CLOSE, N_("_Close"), "<control>W",
1779 N_("Close window"),
1780 G_CALLBACK (gtk_main_quit) },
1781 { "HelpAbout", GTK_STOCK_ABOUT, N_("_About"), NULL,
1782 N_("About this application"),
1783 G_CALLBACK (vnr_window_cmd_about) },
1784 { "EditPreferences", GTK_STOCK_PREFERENCES, N_("_Preferences..."), NULL,
1785 N_("User preferences for Viewnior"),
1786 G_CALLBACK (vnr_window_cmd_preferences) }
1787 };
1788
1789 static const GtkActionEntry action_entry_save[] = {
1790 { "FileSave", GTK_STOCK_SAVE, N_("_Save"), "<control>S",
1791 N_("Save changes"),
1792 G_CALLBACK (save_image_cb) },
1793 };
1794
1795 static const GtkToggleActionEntry toggle_entry_properties[] = {
1796 { "Properties", GTK_STOCK_PROPERTIES, N_("_Properties"), NULL,
1797 N_("Properties"),
1798 G_CALLBACK (vnr_window_cmd_open_menu) },
1799 };
1800
1801 static const GtkActionEntry action_entry_wallpaper[] = {
1802 { "SetAsWallpaper", NULL, N_("Set as _Wallpaper"), "<control>F8",
1803 N_("Set the selected image as the desktop background"),
1804 G_CALLBACK (vnr_set_wallpaper) },
1805 };
1806
1807 static const GtkActionEntry action_entries_image[] = {
1808 { "FileOpenWith", NULL, N_("Open _With"), NULL,
1809 N_("Open the selected image with a different application"),
1810 NULL},
1811 { "FileDelete", GTK_STOCK_DELETE, N_("_Delete"), NULL,
1812 N_("Delete the current file"),
1813 G_CALLBACK (vnr_window_cmd_delete) },
1814 { "FileProperties", GTK_STOCK_PROPERTIES, N_("_Properties..."), "<Alt>Return",
1815 N_("Show information about the current file"),
1816 G_CALLBACK (vnr_window_cmd_properties) },
1817 { "FileReload", GTK_STOCK_REFRESH, N_("_Reload"), NULL,
1818 N_("Reload the current file"),
1819 G_CALLBACK (vnr_window_cmd_reload) },
1820 { "Delete", NULL, N_("_Delete"), "Delete",
1821 N_("Delete the current file"),
1822 G_CALLBACK (vnr_window_cmd_delete) },
1823 { "ViewZoomIn", GTK_STOCK_ZOOM_IN, N_("_Zoom In"), "<control>plus",
1824 N_("Enlarge the image"),
1825 G_CALLBACK (vnr_window_cmd_zoom_in) },
1826 { "ViewZoomOut", GTK_STOCK_ZOOM_OUT, N_("Zoom _Out"), "<control>minus",
1827 N_("Shrink the image"),
1828 G_CALLBACK (vnr_window_cmd_zoom_out) },
1829 { "ViewZoomNormal", GTK_STOCK_ZOOM_100, N_("_Normal Size"), "<control>0",
1830 N_("Show the image at its normal size"),
1831 G_CALLBACK (vnr_window_cmd_normal_size) },
1832 { "ViewZoomFit", GTK_STOCK_ZOOM_FIT, N_("Best _Fit"), NULL,
1833 N_("Fit the image to the window"),
1834 G_CALLBACK (vnr_window_cmd_fit) },
1835 { "ControlEqual", GTK_STOCK_ZOOM_IN, N_("_Zoom In"), "<control>equal",
1836 N_("Shrink the image"),
1837 G_CALLBACK (vnr_window_cmd_zoom_in) },
1838 { "ControlKpAdd", GTK_STOCK_ZOOM_IN, N_("_Zoom In"), "<control>KP_Add",
1839 N_("Shrink the image"),
1840 G_CALLBACK (vnr_window_cmd_zoom_in) },
1841 { "ControlKpSub", GTK_STOCK_ZOOM_OUT, N_("Zoom _Out"), "<control>KP_Subtract",
1842 N_("Shrink the image"),
1843 G_CALLBACK (vnr_window_cmd_zoom_out) },
1844 };
1845
1846 static const GtkActionEntry action_entries_static_image[] = {
1847 { "ImageRotateCW", "object-rotate-right", N_("Rotate _Clockwise"), "<control>R",
1848 N_("Rotate image clockwise"),
1849 G_CALLBACK (vnr_window_cmd_rotate_cw) },
1850 { "ImageRotateCCW", "object-rotate-left", N_("Rotate _Anti-clockwise"), "<control><shift>R",
1851 N_("Rotate image anti-clockwise"),
1852 G_CALLBACK (vnr_window_cmd_rotate_ccw) },
1853 { "ImageFlipVertical", "object-flip-vertical", N_("Flip _Vertical"), NULL,
1854 N_("Flip image vertically"),
1855 G_CALLBACK (vnr_window_cmd_flip_vertical) },
1856 { "ImageFlipHorizontal", "object-flip-horizontal", N_("Flip _Horizontal"), NULL,
1857 N_("Flip image horizontally"),
1858 G_CALLBACK (vnr_window_cmd_flip_horizontal) },
1859 { "ImageCrop", NULL, N_("Crop..."), NULL,
1860 N_("Crop"),
1861 G_CALLBACK (vnr_window_cmd_crop) },
1862 };
1863
1864 static const GtkToggleActionEntry toggle_entries_image[] = {
1865 { "ViewFullscreen", GTK_STOCK_FULLSCREEN, N_("Full _Screen"), "F11",
1866 N_("Show in fullscreen mode"),
1867 G_CALLBACK (vnr_window_cmd_fullscreen) },
1868 { "ViewResizeWindow", NULL, N_("_Adjust window size"), NULL,
1869 N_("Adjust window size to fit the image"),
1870 G_CALLBACK (vnr_window_cmd_resize) },
1871 };
1872
1873 static const GtkToggleActionEntry toggle_entries_window[] = {
1874 { "ViewMenuBar", NULL, N_("Menu Bar"), NULL,
1875 N_("Show Menu Bar"),
1876 G_CALLBACK (vnr_window_cmd_menu_bar) },
1877 { "ViewToolbar", NULL, N_("Toolbar"), NULL,
1878 N_("Show Toolbar"),
1879 G_CALLBACK (vnr_window_cmd_toolbar) },
1880 { "ViewScrollbar", NULL, N_("Scrollbar"), NULL,
1881 N_("Show Scrollbar"),
1882 G_CALLBACK (vnr_window_cmd_scrollbar) },
1883 };
1884
1885 static const GtkToggleActionEntry toggle_entries_collection[] = {
1886 { "ViewSlideshow", GTK_STOCK_NETWORK, N_("Sli_deshow"), "F5",
1887 N_("Show in slideshow mode"),
1888 G_CALLBACK (vnr_window_cmd_slideshow) },
1889 };
1890
1891 static const GtkActionEntry action_entries_collection[] = {
1892 { "GoPrevious", GTK_STOCK_GO_BACK, N_("_Previous Image"), "<Alt>Left",
1893 N_("Go to the previous image of the collection"),
1894 G_CALLBACK (vnr_window_cmd_prev) },
1895 { "GoNext", GTK_STOCK_GO_FORWARD, N_("_Next Image"), "<Alt>Right",
1896 N_("Go to the next image of the collection"),
1897 G_CALLBACK (vnr_window_cmd_next) },
1898 { "GoFirst", GTK_STOCK_GOTO_FIRST, N_("_First Image"), "<Alt>Home",
1899 N_("Go to the first image of the collection"),
1900 G_CALLBACK (vnr_window_cmd_first) },
1901 { "GoLast", GTK_STOCK_GOTO_LAST, N_("_Last Image"), "<Alt>End",
1902 N_("Go to the last image of the collection"),
1903 G_CALLBACK (vnr_window_cmd_last) },
1904 };
1905
1906 /*************************************************************/
1907 /***** Stuff that deals with the type ************************/
1908 /*************************************************************/
1909 /* Modified version of eog's eog_window_key_press */
1910 static gint
vnr_window_key_press(GtkWidget * widget,GdkEventKey * event)1911 vnr_window_key_press (GtkWidget *widget, GdkEventKey *event)
1912 {
1913 gint result = FALSE;
1914 VnrWindow *window = VNR_WINDOW(widget);
1915 GtkWidget *toolbar_focus_child;
1916 GtkWidget *msg_area_focus_child;
1917
1918 toolbar_focus_child = gtk_container_get_focus_child(GTK_CONTAINER(window->toolbar));
1919 msg_area_focus_child = gtk_container_get_focus_child(GTK_CONTAINER(window->msg_area));
1920
1921 switch(event->keyval){
1922 case GDK_KEY_Left:
1923 if (event->state & GDK_MOD1_MASK)
1924 {
1925 vnr_window_cmd_prev (NULL, window);
1926 result = TRUE;
1927 break;
1928 } /* else fall-trough is intended */
1929 case GDK_KEY_Up:
1930 if (!uni_scroll_win_image_fits (UNI_SCROLL_WIN (window->scroll_view)))
1931 {
1932 /* break to let scrollview handle the key */
1933 break;
1934 }
1935 if (toolbar_focus_child != NULL || msg_area_focus_child != NULL)
1936 break;
1937
1938 vnr_window_cmd_prev (NULL, window);
1939 result = TRUE;
1940 break;
1941 case GDK_KEY_Right:
1942 if (event->state & GDK_MOD1_MASK)
1943 {
1944 vnr_window_cmd_next (NULL, window);
1945 result = TRUE;
1946 break;
1947 } /* else fall-trough is intended */
1948 case GDK_KEY_Down:
1949 if (!uni_scroll_win_image_fits (UNI_SCROLL_WIN (window->scroll_view)))
1950 {
1951 /* break to let scrollview handle the key */
1952 break;
1953 }
1954 if (toolbar_focus_child != NULL || msg_area_focus_child != NULL)
1955 break;
1956
1957 vnr_window_cmd_next (NULL, window);
1958 result = TRUE;
1959 break;
1960 case GDK_KEY_Page_Up:
1961 vnr_window_cmd_prev (NULL, window);
1962 result = TRUE;
1963 break;
1964 case GDK_KEY_Page_Down:
1965 vnr_window_cmd_next (NULL, window);
1966 result = TRUE;
1967 break;
1968 case GDK_KEY_Escape:
1969 case 'q':
1970 if(window->mode != VNR_WINDOW_MODE_NORMAL)
1971 vnr_window_unfullscreen(window);
1972 else
1973 gtk_main_quit();
1974 break;
1975 case GDK_KEY_space:
1976 if (toolbar_focus_child != NULL || msg_area_focus_child != NULL)
1977 break;
1978 vnr_window_next(window, TRUE);
1979 result = TRUE;
1980 break;
1981 case GDK_KEY_BackSpace:
1982 vnr_window_prev(window);
1983 result = TRUE;
1984 break;
1985 case GDK_KEY_Home:
1986 vnr_window_first(window);
1987 result = TRUE;
1988 break;
1989 case GDK_KEY_End:
1990 vnr_window_last(window);
1991 result = TRUE;
1992 break;
1993 case 'h':
1994 vnr_window_cmd_flip_horizontal(NULL, window);
1995 break;
1996 case 'v':
1997 vnr_window_cmd_flip_vertical(NULL, window);
1998 break;
1999 case 'c':
2000 vnr_window_cmd_crop(NULL, window);
2001 break;
2002 }
2003
2004 if (result == FALSE && GTK_WIDGET_CLASS (vnr_window_parent_class)->key_press_event)
2005 result = (* GTK_WIDGET_CLASS (vnr_window_parent_class)->key_press_event) (widget, event);
2006
2007 return result;
2008 }
2009
2010 static void
vnr_window_drag_data_received(GtkWidget * widget,GdkDragContext * context,gint x,gint y,GtkSelectionData * selection_data,guint info,guint time)2011 vnr_window_drag_data_received (GtkWidget *widget,
2012 GdkDragContext *context,
2013 gint x, gint y,
2014 GtkSelectionData *selection_data,
2015 guint info, guint time)
2016 {
2017 GSList *uri_list = NULL;
2018 GdkAtom target = gtk_selection_data_get_target (selection_data);
2019 GdkDragAction suggested_action;
2020
2021 if (!gtk_targets_include_uri (&target, 1))
2022 return;
2023
2024 suggested_action = gdk_drag_context_get_suggested_action (context);
2025 if (suggested_action == GDK_ACTION_COPY || suggested_action == GDK_ACTION_ASK)
2026 {
2027 const guchar *data = gtk_selection_data_get_data (selection_data);
2028
2029 uri_list = vnr_tools_parse_uri_string_list_to_file_list ((gchar *) data);
2030 if(uri_list == NULL)
2031 {
2032 vnr_window_close(VNR_WINDOW (widget));
2033 gtk_action_group_set_sensitive(VNR_WINDOW (widget)->actions_collection, FALSE);
2034 deny_slideshow(VNR_WINDOW (widget));
2035 vnr_message_area_show(VNR_MESSAGE_AREA (VNR_WINDOW (widget)->msg_area), TRUE,
2036 _("The given locations contain no images."),
2037 TRUE);
2038 return;
2039 }
2040
2041 vnr_window_open_from_list(VNR_WINDOW (widget), uri_list);
2042 }
2043 }
2044
2045 static void
vnr_window_class_init(VnrWindowClass * klass)2046 vnr_window_class_init (VnrWindowClass * klass)
2047 {
2048 GtkWidgetClass *widget_class = (GtkWidgetClass *) klass;
2049
2050 widget_class->key_press_event = vnr_window_key_press;
2051 widget_class->drag_data_received = vnr_window_drag_data_received;
2052 }
2053
2054 GtkWindow *
vnr_window_new()2055 vnr_window_new ()
2056 {
2057 return (GtkWindow *) g_object_new (VNR_TYPE_WINDOW, NULL);
2058 }
2059
2060 static void
vnr_window_init(VnrWindow * window)2061 vnr_window_init (VnrWindow * window)
2062 {
2063 GError *error = NULL;
2064 GtkAction *action;
2065
2066 window->writable_format_name = NULL;
2067 window->file_list = NULL;
2068 window->fs_controls = NULL;
2069 window->fs_source = NULL;
2070 window->ss_timeout = 5;
2071 window->slideshow = TRUE;
2072 window->cursor_is_hidden = FALSE;
2073 window->disable_autohide = FALSE;
2074 window->actions_open_with = NULL;
2075 window->open_with_menu_id = 0;
2076
2077 window->prefs = (VnrPrefs*)vnr_prefs_new (GTK_WIDGET(window));
2078
2079 window->mode = VNR_WINDOW_MODE_NORMAL;
2080
2081 gtk_window_set_title ((GtkWindow *) window, "Viewnior");
2082 gtk_window_set_default_icon_name ("viewnior");
2083
2084 /* Build MENUBAR and TOOLBAR */
2085 window->ui_mngr = gtk_ui_manager_new();
2086
2087 window->actions_window = gtk_action_group_new("MenuActionsWindow");
2088
2089
2090 gtk_action_group_set_translation_domain (window->actions_window,
2091 GETTEXT_PACKAGE);
2092
2093 gtk_action_group_add_actions (window->actions_window,
2094 action_entries_window,
2095 G_N_ELEMENTS (action_entries_window),
2096 window);
2097
2098 gtk_ui_manager_insert_action_group (window->ui_mngr,
2099 window->actions_window, 0);
2100
2101 window->action_save = gtk_action_group_new("MenuActionSave");
2102
2103
2104 gtk_action_group_set_translation_domain (window->action_save,
2105 GETTEXT_PACKAGE);
2106
2107 gtk_action_group_add_actions (window->action_save,
2108 action_entry_save,
2109 G_N_ELEMENTS (action_entry_save),
2110 window);
2111
2112 gtk_ui_manager_insert_action_group (window->ui_mngr,
2113 window->action_save, 0);
2114
2115 window->action_properties = gtk_action_group_new("MenuActionProperties");
2116
2117
2118 gtk_action_group_set_translation_domain (window->action_properties,
2119 GETTEXT_PACKAGE);
2120
2121 gtk_action_group_add_toggle_actions (window->action_properties,
2122 toggle_entry_properties,
2123 G_N_ELEMENTS (toggle_entry_properties),
2124 window);
2125
2126 gtk_ui_manager_insert_action_group (window->ui_mngr,
2127 window->action_properties, 0);
2128
2129 window->actions_static_image = gtk_action_group_new("MenuActionsStaticImage");
2130
2131
2132 gtk_action_group_set_translation_domain (window->actions_static_image,
2133 GETTEXT_PACKAGE);
2134
2135 gtk_action_group_add_actions (window->actions_static_image,
2136 action_entries_static_image,
2137 G_N_ELEMENTS (action_entries_static_image),
2138 window);
2139
2140 gtk_ui_manager_insert_action_group (window->ui_mngr,
2141 window->actions_static_image, 0);
2142
2143
2144 window->actions_image = gtk_action_group_new("MenuActionsImage");
2145
2146
2147 gtk_action_group_set_translation_domain (window->actions_image,
2148 GETTEXT_PACKAGE);
2149
2150 gtk_action_group_add_actions (window->actions_image,
2151 action_entries_image,
2152 G_N_ELEMENTS (action_entries_image),
2153 window);
2154 gtk_action_group_add_toggle_actions (window->actions_image,
2155 toggle_entries_image,
2156 G_N_ELEMENTS (toggle_entries_image),
2157 window);
2158
2159 gtk_ui_manager_insert_action_group (window->ui_mngr,
2160 window->actions_image, 0);
2161 /**********/
2162 window->actions_bars = gtk_action_group_new("MenuActionsBars");
2163
2164
2165 gtk_action_group_set_translation_domain (window->actions_bars,
2166 GETTEXT_PACKAGE);
2167
2168 gtk_action_group_add_toggle_actions (window->actions_bars,
2169 toggle_entries_window,
2170 G_N_ELEMENTS (toggle_entries_window),
2171 window);
2172
2173 gtk_ui_manager_insert_action_group (window->ui_mngr,
2174 window->actions_bars, 0);
2175
2176 /*****************/
2177 window->actions_collection = gtk_action_group_new("MenuActionsCollection");
2178
2179
2180 gtk_action_group_set_translation_domain (window->actions_collection,
2181 GETTEXT_PACKAGE);
2182
2183 gtk_action_group_add_actions (window->actions_collection,
2184 action_entries_collection,
2185 G_N_ELEMENTS (action_entries_collection),
2186 window);
2187 gtk_action_group_add_toggle_actions (window->actions_collection,
2188 toggle_entries_collection,
2189 G_N_ELEMENTS (toggle_entries_collection),
2190 window);
2191
2192 gtk_ui_manager_insert_action_group (window->ui_mngr,
2193 window->actions_collection, 0);
2194
2195 if (!gtk_ui_manager_add_ui_from_string (window->ui_mngr,
2196 ui_definition, -1,
2197 &error)) {
2198 g_error ("building menus failed: %s\n", error->message);
2199 g_error_free (error);
2200 }
2201
2202 window->action_wallpaper = gtk_action_group_new("ActionWallpaper");
2203
2204 gtk_action_group_set_translation_domain (window->action_wallpaper,
2205 GETTEXT_PACKAGE);
2206
2207 gtk_action_group_add_actions (window->action_wallpaper,
2208 action_entry_wallpaper,
2209 G_N_ELEMENTS (action_entry_wallpaper),
2210 window);
2211
2212 gtk_ui_manager_insert_action_group (window->ui_mngr,
2213 window->action_wallpaper, 0);
2214
2215 if (!gtk_ui_manager_add_ui_from_string (window->ui_mngr,
2216 ui_definition_wallpaper, -1,
2217 &error)) {
2218 g_error ("building menus failed: %s\n", error->message);
2219 g_error_free (error);
2220 }
2221 gtk_action_group_set_sensitive(window->action_wallpaper, FALSE);
2222
2223 gtk_action_group_set_sensitive(window->actions_collection, FALSE);
2224 gtk_action_group_set_sensitive(window->actions_image, FALSE);
2225 gtk_action_group_set_sensitive(window->actions_static_image, FALSE);
2226 gtk_action_group_set_sensitive(window->action_save, FALSE);
2227 gtk_action_group_set_sensitive(window->actions_bars, TRUE);
2228
2229 /* Continue with layout */
2230
2231 window->layout = gtk_vbox_new(FALSE,0);
2232 gtk_container_add (GTK_CONTAINER (window), window->layout);
2233 gtk_widget_show(window->layout);
2234
2235 window->menus = gtk_vbox_new(FALSE,0);
2236 gtk_box_pack_start (GTK_BOX (window->layout), window->menus, FALSE,FALSE,0);
2237
2238 window->menu_bar = gtk_ui_manager_get_widget (window->ui_mngr, "/MainMenu");
2239 g_assert(GTK_IS_WIDGET(window->menu_bar));
2240 gtk_box_pack_start (GTK_BOX (window->menus), window->menu_bar, FALSE,FALSE,0);
2241
2242 window->properties_button = gtk_ui_manager_get_widget (window->ui_mngr, "/Toolbar/Properties");
2243 g_assert(GTK_IS_WIDGET(window->properties_button));
2244
2245 window->button_menu = gtk_ui_manager_get_widget (window->ui_mngr, "/ButtonMenu");
2246 g_assert(GTK_IS_WIDGET(window->button_menu));
2247 gtk_menu_attach_to_widget (GTK_MENU(window->button_menu), GTK_WIDGET(window->properties_button), NULL);
2248
2249 window->toolbar = gtk_ui_manager_get_widget (window->ui_mngr, "/Toolbar");
2250 g_assert(GTK_IS_WIDGET(window->toolbar));
2251 gtk_toolbar_set_style(GTK_TOOLBAR(window->toolbar), GTK_TOOLBAR_ICONS);
2252 g_object_set(G_OBJECT(window->toolbar), "show-arrow", FALSE, NULL);
2253 gtk_toolbar_insert (GTK_TOOLBAR (window->toolbar),
2254 GTK_TOOL_ITEM(get_fs_controls(window)), -1);
2255 gtk_box_pack_start (GTK_BOX (window->menus), window->toolbar, FALSE,FALSE,0);
2256
2257 window->popup_menu = gtk_ui_manager_get_widget (window->ui_mngr, "/PopupMenu");
2258 g_assert(GTK_IS_WIDGET(window->popup_menu));
2259
2260 gtk_ui_manager_ensure_update (window->ui_mngr);
2261 gtk_widget_show_all(window->menus);
2262
2263 gtk_widget_hide(get_fs_controls(window));
2264
2265 // Apply menu bar preference
2266 action = gtk_action_group_get_action (window->actions_bars,
2267 "ViewMenuBar");
2268 if(!window->prefs->show_menu_bar)
2269 gtk_widget_hide (window->menu_bar);
2270 else
2271 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
2272
2273
2274 // Apply toolbar preference
2275 action = gtk_action_group_get_action (window->actions_bars,
2276 "ViewToolbar");
2277 if(!window->prefs->show_toolbar)
2278 gtk_widget_hide (window->toolbar);
2279 else
2280 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
2281
2282 // Apply auto-resize preference
2283 action = gtk_action_group_get_action (window->actions_image,
2284 "ViewResizeWindow");
2285
2286 if(window->prefs->auto_resize)
2287 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
2288
2289 window->msg_area = vnr_message_area_new();
2290 VNR_MESSAGE_AREA(window->msg_area)->vnr_win = window;
2291 gtk_box_pack_start (GTK_BOX (window->layout), window->msg_area, FALSE,FALSE,0);
2292 gtk_widget_show(GTK_WIDGET (window->msg_area));
2293
2294 window->view = uni_anim_view_new ();
2295 gtk_widget_set_can_focus(window->view, TRUE);
2296 window->scroll_view = uni_scroll_win_new (UNI_IMAGE_VIEW (window->view));
2297
2298 // Apply scrollbar preference
2299 action = gtk_action_group_get_action (window->actions_bars,
2300 "ViewScrollbar");
2301 uni_scroll_win_set_show_scrollbar (UNI_SCROLL_WIN (window->scroll_view), window->prefs->show_scrollbar);
2302 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), window->prefs->show_scrollbar);
2303
2304 gtk_box_pack_end (GTK_BOX (window->layout), window->scroll_view, TRUE,TRUE,0);
2305 gtk_widget_show_all(GTK_WIDGET (window->scroll_view));
2306
2307 gtk_widget_grab_focus(window->view);
2308
2309 /* Care for Properties dialog */
2310 window->props_dlg = vnr_properties_dialog_new(window,
2311 gtk_action_group_get_action (window->actions_collection,
2312 "GoNext"),
2313 gtk_action_group_get_action (window->actions_collection,
2314 "GoPrevious"));
2315
2316 vnr_window_apply_preferences(window);
2317
2318 vnr_window_set_drag(window);
2319
2320 g_signal_connect (G_OBJECT (window), "destroy",
2321 G_CALLBACK (window_destroy_cb), NULL);
2322
2323 g_signal_connect (G_OBJECT (window), "realize",
2324 G_CALLBACK (window_realize_cb), NULL);
2325
2326 g_signal_connect (G_OBJECT (window), "window-state-event",
2327 G_CALLBACK (window_change_state_cb), NULL);
2328
2329 g_signal_connect (G_OBJECT (window->view), "zoom_changed",
2330 G_CALLBACK (zoom_changed_cb), window);
2331
2332 g_signal_connect (G_OBJECT (window->view), "drag-data-get",
2333 G_CALLBACK (window_drag_begin_cb), window);
2334
2335 g_signal_connect (G_OBJECT (window->button_menu), "hide",
2336 G_CALLBACK(vnr_window_cmd_main_menu_hidden), window);
2337
2338 gtk_window_add_accel_group (GTK_WINDOW (window),
2339 gtk_ui_manager_get_accel_group (window->ui_mngr));
2340
2341 vnr_window_load_accel_map();
2342 }
2343
2344 /*************************************************************/
2345 /***** Actions ***********************************************/
2346 /*************************************************************/
2347 gboolean
vnr_window_open(VnrWindow * window,gboolean fit_to_screen)2348 vnr_window_open (VnrWindow * window, gboolean fit_to_screen)
2349 {
2350 VnrFile *file;
2351 GdkPixbufAnimation *pixbuf;
2352 GdkPixbufFormat *format;
2353 UniFittingMode last_fit_mode;
2354 GError *error = NULL;
2355
2356 if(window->file_list == NULL)
2357 return FALSE;
2358
2359 file = VNR_FILE(window->file_list->data);
2360
2361 update_fs_filename_label(window);
2362
2363 pixbuf = gdk_pixbuf_animation_new_from_file (file->path, &error);
2364
2365 if (error != NULL)
2366 {
2367 vnr_message_area_show(VNR_MESSAGE_AREA (window->msg_area),
2368 TRUE, error->message, TRUE);
2369
2370 if(gtk_widget_get_visible(window->props_dlg))
2371 vnr_properties_dialog_clear(VNR_PROPERTIES_DIALOG(window->props_dlg));
2372 return FALSE;
2373 }
2374
2375 if(vnr_message_area_is_visible(VNR_MESSAGE_AREA(window->msg_area)))
2376 {
2377 vnr_message_area_hide(VNR_MESSAGE_AREA(window->msg_area));
2378 }
2379
2380 gtk_action_group_set_sensitive(window->actions_image, TRUE);
2381 gtk_action_group_set_sensitive(window->action_wallpaper, TRUE);
2382
2383 format = gdk_pixbuf_get_file_info (file->path, NULL, NULL);
2384
2385 g_free(window->writable_format_name);
2386 if(gdk_pixbuf_format_is_writable (format))
2387 window->writable_format_name = gdk_pixbuf_format_get_name (format);
2388 else
2389 window->writable_format_name = NULL;
2390
2391 vnr_tools_apply_embedded_orientation (&pixbuf);
2392 window->current_image_width = gdk_pixbuf_animation_get_width (pixbuf);
2393 window->current_image_height = gdk_pixbuf_animation_get_height (pixbuf);
2394 window->modifications = 0;
2395
2396 if(fit_to_screen)
2397 {
2398 GtkAllocation allocation;
2399 gint img_h, img_w; /* Width and Height of the pixbuf */
2400
2401 img_w = window->current_image_width;
2402 img_h = window->current_image_height;
2403
2404 vnr_tools_fit_to_size (&img_w, &img_h, window->max_width, window->max_height);
2405
2406 gtk_widget_get_allocation (window->menus, &allocation);
2407 gtk_window_resize (GTK_WINDOW (window), img_w, img_h + allocation.height);
2408 }
2409
2410 last_fit_mode = UNI_IMAGE_VIEW(window->view)->fitting;
2411
2412 /* Return TRUE if the image is static */
2413 if ( uni_anim_view_set_anim (UNI_ANIM_VIEW (window->view), pixbuf) )
2414 gtk_action_group_set_sensitive(window->actions_static_image, TRUE);
2415 else
2416 gtk_action_group_set_sensitive(window->actions_static_image, FALSE);
2417
2418 if(window->mode != VNR_WINDOW_MODE_NORMAL && window->prefs->fit_on_fullscreen)
2419 {
2420 uni_image_view_set_zoom_mode (UNI_IMAGE_VIEW(window->view), VNR_PREFS_ZOOM_FIT);
2421 }
2422 else if(window->prefs->zoom == VNR_PREFS_ZOOM_LAST_USED )
2423 {
2424 uni_image_view_set_fitting (UNI_IMAGE_VIEW(window->view), last_fit_mode);
2425 zoom_changed_cb(UNI_IMAGE_VIEW(window->view), window);
2426 }
2427 else
2428 {
2429 uni_image_view_set_zoom_mode (UNI_IMAGE_VIEW(window->view), window->prefs->zoom);
2430 }
2431
2432 if ( window->prefs->auto_resize ) {
2433 vnr_window_cmd_resize(NULL, window);
2434 }
2435
2436 if(gtk_widget_get_visible(window->props_dlg))
2437 vnr_properties_dialog_update(VNR_PROPERTIES_DIALOG(window->props_dlg));
2438
2439 vnr_window_update_openwith_menu (window);
2440
2441 g_object_unref(pixbuf);
2442 return TRUE;
2443 }
2444
2445 void
vnr_window_open_from_list(VnrWindow * window,GSList * uri_list)2446 vnr_window_open_from_list(VnrWindow *window, GSList *uri_list)
2447 {
2448 GList *file_list = NULL;
2449 GError *error = NULL;
2450
2451 if (g_slist_length(uri_list) == 1)
2452 {
2453 vnr_file_load_single_uri (uri_list->data, &file_list, window->prefs->show_hidden, &error);
2454 }
2455 else
2456 {
2457 vnr_file_load_uri_list (uri_list, &file_list, window->prefs->show_hidden, &error);
2458 }
2459
2460 if(error != NULL && file_list != NULL)
2461 {
2462 vnr_window_close(window);
2463 gtk_action_group_set_sensitive(window->actions_collection, FALSE);
2464 deny_slideshow(window);
2465 vnr_message_area_show(VNR_MESSAGE_AREA (window->msg_area),
2466 TRUE, error->message, TRUE);
2467
2468 vnr_window_set_list(window, file_list, TRUE);
2469 }
2470 else if(error != NULL)
2471 {
2472 vnr_window_close(window);
2473 deny_slideshow(window);
2474 vnr_message_area_show(VNR_MESSAGE_AREA (window->msg_area),
2475 TRUE, error->message, TRUE);
2476 }
2477 else if(file_list == NULL)
2478 {
2479 vnr_window_close(window);
2480 gtk_action_group_set_sensitive(window->actions_collection, FALSE);
2481 deny_slideshow(window);
2482 vnr_message_area_show(VNR_MESSAGE_AREA (window->msg_area), TRUE,
2483 _("The given locations contain no images."),
2484 TRUE);
2485 }
2486 else
2487 {
2488 vnr_window_set_list(window, file_list, TRUE);
2489 if(!window->cursor_is_hidden)
2490 gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window)),
2491 gdk_cursor_new(GDK_WATCH));
2492 /* This makes the cursor show NOW */
2493 gdk_flush();
2494
2495 vnr_window_close(window);
2496 vnr_window_open(window, FALSE);
2497 if(!window->cursor_is_hidden)
2498 gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window)),
2499 gdk_cursor_new(GDK_LEFT_PTR));
2500 }
2501 }
2502
2503 void
vnr_window_close(VnrWindow * window)2504 vnr_window_close(VnrWindow *window)
2505 {
2506 gtk_window_set_title (GTK_WINDOW (window), "Viewnior");
2507 uni_anim_view_set_anim (UNI_ANIM_VIEW (window->view), NULL);
2508 gtk_action_group_set_sensitive(window->actions_image, FALSE);
2509 gtk_action_group_set_sensitive(window->action_wallpaper, FALSE);
2510 gtk_action_group_set_sensitive(window->actions_static_image, FALSE);
2511 }
2512
2513 void
vnr_window_set_list(VnrWindow * window,GList * list,gboolean free_current)2514 vnr_window_set_list (VnrWindow *window, GList *list, gboolean free_current)
2515 {
2516 if (free_current == TRUE && window->file_list != NULL)
2517 g_list_free (window->file_list);
2518 if (g_list_length(g_list_first(list)) > 1)
2519 {
2520 gtk_action_group_set_sensitive(window->actions_collection, TRUE);
2521 allow_slideshow(window);
2522 }
2523 else
2524 {
2525 gtk_action_group_set_sensitive(window->actions_collection, FALSE);
2526 deny_slideshow(window);
2527 }
2528 window->file_list = list;
2529 }
2530
2531 gboolean
vnr_window_next(VnrWindow * window,gboolean rem_timeout)2532 vnr_window_next (VnrWindow *window, gboolean rem_timeout){
2533 GList *next;
2534
2535 /* Don't reload current image
2536 * if the list contains only one (or no) image */
2537 if (g_list_length(g_list_first(window->file_list)) <2)
2538 return FALSE;
2539
2540 if(window->mode == VNR_WINDOW_MODE_SLIDESHOW && rem_timeout)
2541 g_source_remove (window->ss_source_tag);
2542
2543 next = g_list_next(window->file_list);
2544 if(next == NULL)
2545 {
2546 next = g_list_first(window->file_list);
2547 }
2548
2549 window->file_list = next;
2550
2551 if(!window->cursor_is_hidden)
2552 gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window)),
2553 gdk_cursor_new(GDK_WATCH));
2554 /* This makes the cursor show NOW */
2555 gdk_flush();
2556
2557 vnr_window_open(window, FALSE);
2558 if(!window->cursor_is_hidden)
2559 gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window)),
2560 gdk_cursor_new(GDK_LEFT_PTR));
2561
2562 if(window->mode == VNR_WINDOW_MODE_SLIDESHOW && rem_timeout)
2563 window->ss_source_tag = g_timeout_add_seconds (window->ss_timeout,
2564 (GSourceFunc)next_image_src,
2565 window);
2566
2567 return TRUE;
2568 }
2569
2570 gboolean
vnr_window_prev(VnrWindow * window)2571 vnr_window_prev (VnrWindow *window){
2572 GList *prev;
2573
2574 /* Don't reload current image
2575 * if the list contains only one (or no) image */
2576 if (g_list_length(g_list_first(window->file_list)) <2)
2577 return FALSE;
2578
2579 if(window->mode == VNR_WINDOW_MODE_SLIDESHOW)
2580 g_source_remove (window->ss_source_tag);
2581
2582 prev = g_list_previous(window->file_list);
2583 if(prev == NULL)
2584 {
2585 prev = g_list_last(window->file_list);
2586 }
2587
2588 window->file_list = prev;
2589
2590 if(!window->cursor_is_hidden)
2591 gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window)),
2592 gdk_cursor_new(GDK_WATCH));
2593 /* This makes the cursor show NOW */
2594 gdk_flush();
2595
2596 vnr_window_open(window, FALSE);
2597 if(!window->cursor_is_hidden)
2598 gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window)),
2599 gdk_cursor_new(GDK_LEFT_PTR));
2600
2601 if(window->mode == VNR_WINDOW_MODE_SLIDESHOW)
2602 window->ss_source_tag = g_timeout_add_seconds (window->ss_timeout,
2603 (GSourceFunc)next_image_src,
2604 window);
2605
2606 return TRUE;
2607 }
2608
2609 gboolean
vnr_window_first(VnrWindow * window)2610 vnr_window_first (VnrWindow *window){
2611 GList *prev;
2612
2613 prev = g_list_first(window->file_list);
2614
2615 if(vnr_message_area_is_critical(VNR_MESSAGE_AREA(window->msg_area)))
2616 {
2617 vnr_message_area_hide(VNR_MESSAGE_AREA(window->msg_area));
2618 }
2619
2620 window->file_list = prev;
2621
2622 if(!window->cursor_is_hidden)
2623 gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window)),
2624 gdk_cursor_new(GDK_WATCH));
2625 /* This makes the cursor show NOW */
2626 gdk_flush();
2627
2628 vnr_window_open(window, FALSE);
2629 if(!window->cursor_is_hidden)
2630 gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window)),
2631 gdk_cursor_new(GDK_LEFT_PTR));
2632 return TRUE;
2633 }
2634
2635 gboolean
vnr_window_last(VnrWindow * window)2636 vnr_window_last (VnrWindow *window){
2637 GList *prev;
2638
2639 prev = g_list_last(window->file_list);
2640
2641 if(vnr_message_area_is_critical(VNR_MESSAGE_AREA(window->msg_area)))
2642 {
2643 vnr_message_area_hide(VNR_MESSAGE_AREA(window->msg_area));
2644 }
2645
2646 window->file_list = prev;
2647
2648 if(!window->cursor_is_hidden)
2649 gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window)),
2650 gdk_cursor_new(GDK_WATCH));
2651 /* This makes the cursor show NOW */
2652 gdk_flush();
2653
2654 vnr_window_open(window, FALSE);
2655 if(!window->cursor_is_hidden)
2656 gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window)),
2657 gdk_cursor_new(GDK_LEFT_PTR));
2658 return TRUE;
2659 }
2660
2661 void
vnr_window_apply_preferences(VnrWindow * window)2662 vnr_window_apply_preferences (VnrWindow *window)
2663 {
2664 if(window->prefs->smooth_images && UNI_IMAGE_VIEW(window->view)->interp != GDK_INTERP_BILINEAR)
2665 {
2666 UNI_IMAGE_VIEW(window->view)->interp = GDK_INTERP_BILINEAR;
2667 gtk_widget_queue_draw(window->view);
2668 }
2669 else if(!window->prefs->smooth_images && UNI_IMAGE_VIEW(window->view)->interp != GDK_INTERP_NEAREST)
2670 {
2671 UNI_IMAGE_VIEW(window->view)->interp = GDK_INTERP_NEAREST;
2672 gtk_widget_queue_draw(window->view);
2673 }
2674
2675
2676 if(gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(window->ss_timeout_widget)) != window->prefs->slideshow_timeout)
2677 {
2678 gtk_spin_button_set_value(GTK_SPIN_BUTTON(window->ss_timeout_widget), (gdouble) window->prefs->slideshow_timeout);
2679 }
2680 }
2681
2682 void
vnr_window_toggle_fullscreen(VnrWindow * window)2683 vnr_window_toggle_fullscreen (VnrWindow *window)
2684 {
2685 gboolean fullscreen;
2686
2687 fullscreen = (window->mode == VNR_WINDOW_MODE_NORMAL)?TRUE:FALSE;
2688
2689 if (fullscreen)
2690 vnr_window_fullscreen (window);
2691 else
2692 vnr_window_unfullscreen (window);
2693 }
2694