1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; coding: utf-8 -*- */
2 
3 #include <glib.h>
4 #include <gtk/gtk.h>
5 #include <assert.h>
6 #include <stdio.h>
7 
8 // Library under test.
9 #include <src/gtkanimview.h>
10 #include <src/gtkimagescrollwin.h>
11 #include <src/gtkimagetooldragger.h>
12 #include <src/gtkimagetoolpainter.h>
13 #include <src/gtkimagetoolselector.h>
14 
15 // Defines for backwards compatibility with GTK+ 2.6
16 #if !GTK_CHECK_VERSION(2,8,0)
17 #define GTK_STOCK_FULLSCREEN ""
18 #endif
19 
20 //////////////////////////////////////////////////////////////////////
21 ///// Global data ////////////////////////////////////////////////////
22 //////////////////////////////////////////////////////////////////////
23 static GtkFileChooserDialog *open_dialog = NULL;
24 static GtkAnimView *view = NULL;
25 static GtkWindow *main_window;
26 static GtkActionGroup *default_group = NULL;
27 static GtkActionGroup *image_group = NULL;
28 static GtkActionGroup *transform_group = NULL;
29 static gboolean is_fullscreen = FALSE;
30 static GtkWidget *statusbar = NULL;
31 
32 // Label that displays the active selection.
33 static GtkWidget *sel_info_label = NULL;
34 
35 // Tools
36 static GtkIImageTool *dragger = NULL;
37 static GtkIImageTool *selector = NULL;
38 static GtkIImageTool *painter = NULL;
39 
40 // Context ID:s for the Statusbar
41 int help_msg_cid = -1;
42 int image_info_cid = -1;
43 
44 //////////////////////////////////////////////////////////////////////
45 ///// Opener dialog //////////////////////////////////////////////////
46 //////////////////////////////////////////////////////////////////////
47 static void
init_open_dialog()48 init_open_dialog ()
49 {
50 	open_dialog = (GtkFileChooserDialog *)
51 		gtk_file_chooser_dialog_new ("Open Image",
52 									 main_window,
53 									 GTK_FILE_CHOOSER_ACTION_OPEN,
54 									 GTK_STOCK_CANCEL,
55 									 GTK_RESPONSE_CANCEL,
56 									 GTK_STOCK_OPEN,
57 									 GTK_RESPONSE_ACCEPT,
58 									 NULL);
59 }
60 
61 //////////////////////////////////////////////////////////////////////
62 ///// ImageViewerApp /////////////////////////////////////////////////
63 //////////////////////////////////////////////////////////////////////
64 static void
push_image_info(char * basename,GdkPixbufAnimation * anim)65 push_image_info (char               *basename,
66                  GdkPixbufAnimation *anim)
67 {
68 	int width = gdk_pixbuf_animation_get_width (anim);
69 	int height = gdk_pixbuf_animation_get_height (anim);
70 	char *msg = g_strdup_printf ("%s, %d x %d pixels",
71 								 basename, width, height);
72 	gtk_statusbar_push (GTK_STATUSBAR (statusbar), image_info_cid, msg);
73 	g_free (msg);
74 }
75 
76 
77 static void
load_filename(char * path)78 load_filename (char *path)
79 {
80     GdkPixbufAnimation *anim = gdk_pixbuf_animation_new_from_file (path,
81                                                                    NULL);
82     if (!anim)
83     {
84         printf ("No anim!\n");
85         return;
86     }
87     gtk_anim_view_set_anim (view, anim);
88     g_object_unref (anim);
89 
90     char *basename = g_path_get_basename (path);
91     gtk_window_set_title (main_window, basename);
92     push_image_info (basename, anim);
93     g_free (basename);
94 
95     gtk_action_group_set_sensitive (image_group, TRUE);
96 
97     /* Only active the transform_group if the loaded object is a single
98        image -- transformations cannot be applied to animations. */
99     gboolean is_image = gdk_pixbuf_animation_is_static_image (anim);
100     gtk_action_group_set_sensitive (transform_group, is_image);
101 }
102 
103 //////////////////////////////////////////////////////////////////////
104 ///// Callbacks //////////////////////////////////////////////////////
105 //////////////////////////////////////////////////////////////////////
106 static void
sel_changed_cb(GtkImageToolSelector * selector,GtkLabel * label)107 sel_changed_cb (GtkImageToolSelector *selector,
108                 GtkLabel             *label)
109 {
110     GdkRectangle sel;
111     gtk_image_tool_selector_get_selection (selector, &sel);
112     if (!sel.width || !sel.height)
113         gtk_label_set_text (label, "");
114     else
115     {
116         char *text = g_strdup_printf ("%s", gdk_rectangle_to_str (sel));
117         gtk_label_set_text (label, text);
118         g_free (text);
119     }
120 }
121 
122 static void
change_image_tool_cb(GtkAction * action,GtkRadioAction * current)123 change_image_tool_cb (GtkAction      *action,
124                       GtkRadioAction *current)
125 {
126     int value = gtk_radio_action_get_current_value (current);
127     GtkIImageTool *tool = selector;
128     if (value == 10)
129         tool = dragger;
130     else if (value == 30)
131         tool = painter;
132     gtk_image_view_set_tool (GTK_IMAGE_VIEW (view), tool);
133     if (value == 20)
134         sel_changed_cb (GTK_IMAGE_TOOL_SELECTOR (selector),
135                         GTK_LABEL (sel_info_label));
136     else
137         gtk_label_set_text (GTK_LABEL (sel_info_label), "");
138 }
139 
140 static void
zoom_in_cb()141 zoom_in_cb ()
142 {
143 	gtk_image_view_zoom_in (GTK_IMAGE_VIEW (view));
144 }
145 
146 static void
zoom_out_cb()147 zoom_out_cb ()
148 {
149 	gtk_image_view_zoom_out (GTK_IMAGE_VIEW (view));
150 }
151 
152 static void
zoom_100_cb()153 zoom_100_cb ()
154 {
155 	gtk_image_view_set_zoom (GTK_IMAGE_VIEW (view), 1.0);
156 }
157 
158 static void
zoom_to_fit_cb()159 zoom_to_fit_cb ()
160 {
161 	gtk_image_view_set_fitting (GTK_IMAGE_VIEW (view), TRUE);
162 }
163 
164 static void
open_image_cb(GtkAction * action)165 open_image_cb (GtkAction *action)
166 {
167 	if (!open_dialog)
168 		init_open_dialog ();
169 	if (gtk_dialog_run (GTK_DIALOG (open_dialog)) == GTK_RESPONSE_ACCEPT)
170 	{
171 		char *fname;
172 		fname = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (open_dialog));
173 		load_filename (fname);
174 		g_free (fname);
175 	}
176 	gtk_widget_hide (GTK_WIDGET (open_dialog));
177 }
178 
179 static void
fullscreen_cb()180 fullscreen_cb ()
181 {
182 	// I do not have the patience to implement all things you do to
183 	// fullscreen for real. This is a faked approximation.
184 	is_fullscreen = !is_fullscreen;
185 	if (is_fullscreen)
186 		gtk_window_fullscreen (main_window);
187 	else
188 		gtk_window_unfullscreen (main_window);
189 
190     gtk_image_view_set_show_cursor (GTK_IMAGE_VIEW (view), !is_fullscreen);
191 	gtk_image_view_set_show_frame (GTK_IMAGE_VIEW (view), !is_fullscreen);
192 	gtk_image_view_set_black_bg (GTK_IMAGE_VIEW (view), is_fullscreen);
193 }
194 
195 static void
transform_cb()196 transform_cb ()
197 {
198     GdkPixbuf *pixbuf = gtk_image_view_get_pixbuf (GTK_IMAGE_VIEW (view));
199     guchar *pixels = gdk_pixbuf_get_pixels (pixbuf);
200     int rowstride = gdk_pixbuf_get_rowstride (pixbuf);
201     int n_channels = gdk_pixbuf_get_n_channels (pixbuf);
202     for (int y = 0; y < gdk_pixbuf_get_height (pixbuf); y++)
203         for (int x = 0; x < gdk_pixbuf_get_width (pixbuf); x++)
204         {
205             guchar *p = pixels + y * rowstride + x * n_channels;
206             for (int n  = 0; n < 3; n++)
207                 p[n] ^= 0xff;
208         }
209     gtk_image_view_damage_pixels (GTK_IMAGE_VIEW (view), NULL);
210 }
211 
212 static void
change_zoom_quality_cb(GtkAction * action,GtkRadioAction * current)213 change_zoom_quality_cb (GtkAction      *action,
214 						GtkRadioAction *current)
215 {
216 	if (gtk_radio_action_get_current_value (current))
217 		gtk_image_view_set_interpolation (GTK_IMAGE_VIEW (view),
218                                           GDK_INTERP_BILINEAR);
219 	else
220 		gtk_image_view_set_interpolation (GTK_IMAGE_VIEW (view),
221                                           GDK_INTERP_NEAREST);
222 }
223 
224 static void
change_transp_type_cb(GtkAction * action,GtkRadioAction * current)225 change_transp_type_cb (GtkAction      *action,
226                        GtkRadioAction *current)
227 {
228     int color = 0;
229     GtkImageTransp transp = gtk_radio_action_get_current_value (current);
230     if (transp == GTK_IMAGE_TRANSP_COLOR)
231         color = 0x000000;
232     gtk_image_view_set_transp (GTK_IMAGE_VIEW (view), transp, color);
233 }
234 
235 static void
menu_item_select_cb(GtkMenuItem * proxy)236 menu_item_select_cb (GtkMenuItem *proxy)
237 {
238 	GtkAction *action = g_object_get_data (G_OBJECT (proxy), "gtk-action");
239 
240 	char *msg;
241 	g_object_get (G_OBJECT (action), "tooltip", &msg, NULL);
242 
243 	if (msg)
244 	{
245 		gtk_statusbar_push (GTK_STATUSBAR (statusbar), help_msg_cid, msg);
246 		g_free (msg);
247 	}
248 }
249 
250 static void
menu_item_deselect_cb(GtkMenuItem * item)251 menu_item_deselect_cb (GtkMenuItem *item)
252 {
253 	gtk_statusbar_pop (GTK_STATUSBAR (statusbar), help_msg_cid);
254 }
255 
256 static void
connect_proxy_cb(GtkUIManager * ui,GtkAction * action,GtkWidget * proxy)257 connect_proxy_cb (GtkUIManager *ui,
258 				  GtkAction    *action,
259 				  GtkWidget    *proxy)
260 {
261 	if (!GTK_IS_MENU_ITEM (proxy))
262         return;
263     g_signal_connect (proxy, "select", G_CALLBACK (menu_item_select_cb), NULL);
264     g_signal_connect (proxy, "deselect",
265                       G_CALLBACK (menu_item_deselect_cb), NULL);
266 }
267 
268 static void
disconnect_proxy_cb(GtkUIManager * ui,GtkAction * action,GtkWidget * proxy)269 disconnect_proxy_cb (GtkUIManager *ui,
270 					 GtkAction    *action,
271 					 GtkWidget    *proxy)
272 {
273 	if (!GTK_IS_MENU_ITEM (proxy))
274         return;
275     g_signal_handlers_disconnect_by_func (proxy,
276                                           G_CALLBACK (menu_item_select_cb),
277                                           NULL);
278     g_signal_handlers_disconnect_by_func (proxy,
279                                           G_CALLBACK (menu_item_deselect_cb),
280                                           NULL);
281 }
282 
283 static void
zoom_changed_cb(GtkImageView * view,GtkLabel * label)284 zoom_changed_cb (GtkImageView *view,
285 				 GtkLabel     *label)
286 {
287 	gdouble zoom = gtk_image_view_get_zoom (view);
288 	char *text = g_strdup_printf ("%d%%", (int)(zoom * 100.0));
289 	gtk_label_set_text (label, text);
290 	g_free (text);
291 }
292 
293 static void
kill_app_cb(void)294 kill_app_cb (void)
295 {
296 	/* Kill the widgets. */
297 	gtk_widget_destroy (GTK_WIDGET (main_window));
298 	if (open_dialog)
299 		gtk_widget_destroy (GTK_WIDGET (open_dialog));
300 	gtk_main_quit ();
301 }
302 
303 //////////////////////////////////////////////////////////////////////
304 ///// MainWindow /////////////////////////////////////////////////////
305 //////////////////////////////////////////////////////////////////////
306 static GtkWindow *
main_window_new(GtkWidget * widget,int width,int height)307 main_window_new (GtkWidget *widget,
308                  int        width,
309                  int        height)
310 {
311     GtkWindow *window = (GtkWindow *)gtk_window_new (GTK_WINDOW_TOPLEVEL);
312     gtk_window_set_default_size (window, width, height);
313     gtk_container_add (GTK_CONTAINER (window), widget);
314     g_signal_connect (G_OBJECT (window), "delete_event",
315                       G_CALLBACK (kill_app_cb), NULL);
316     return window;
317 }
318 
319 //////////////////////////////////////////////////////////////////////
320 ///// UI Setup ///////////////////////////////////////////////////////
321 //////////////////////////////////////////////////////////////////////
322 static const GtkActionEntry default_actions[] = {
323     {"FileMenu", NULL, "_File"},
324     {
325         "Open",
326         GTK_STOCK_OPEN,
327         "_Open image",
328         NULL,
329         "Open an image",
330         G_CALLBACK (open_image_cb)
331     },
332     {
333         "Quit",
334         GTK_STOCK_QUIT,
335         "_Quit me!",
336         NULL,
337         "Quit the program",
338         G_CALLBACK (kill_app_cb)
339     },
340     {"EditMenu", NULL, "_Edit"},
341     {"ViewMenu", NULL, "_View"},
342     {"TranspMenu", NULL, "_Transparency"}
343 };
344 
345 static const GtkRadioActionEntry quality_actions[] = {
346 	{
347 		"QualityHigh",
348 		NULL,
349 		"_High Quality",
350 		NULL,
351 		"Use high quality zoom",
352 		TRUE
353 	},
354 	{
355 		"QualityLow",
356 		NULL,
357 		"_Low Quality",
358 		NULL,
359 		"Use low quality zoom",
360 		FALSE
361 	}
362 };
363 
364 static const GtkRadioActionEntry transp_actions[] = {
365     {
366         "TranspGrid",
367         NULL,
368         "Square _Grid",
369         NULL,
370         "Draw a grid on transparent parts",
371         GTK_IMAGE_TRANSP_GRID
372     },
373     {
374         "TranspBackground",
375         NULL,
376         "_Background",
377         NULL,
378         "Draw background color on transparent parts",
379         GTK_IMAGE_TRANSP_BACKGROUND
380     },
381     {
382         "TranspBlack",
383         NULL,
384         "_Black",
385         NULL,
386         "Draw black color on transparent parts",
387         GTK_IMAGE_TRANSP_COLOR
388     }
389 };
390 
391 static const GtkActionEntry image_actions[] = {
392     {
393         "ZoomIn",
394         GTK_STOCK_ZOOM_IN,
395         "Zoom _In",
396 		"<control>plus",
397         "Zoom in one step",
398 		G_CALLBACK (zoom_in_cb)
399     },
400     {
401         "ZoomOut",
402         GTK_STOCK_ZOOM_OUT,
403         "Zoom _Out",
404 		"<control>minus",
405         "Zoom out one step",
406 		G_CALLBACK (zoom_out_cb)
407     },
408 	{
409 		"ZoomNormal",
410 		GTK_STOCK_ZOOM_100,
411 		"_Normal Size",
412 		"<control>0",
413 		"Set zoom to natural size of the image",
414 		G_CALLBACK (zoom_100_cb)
415 	},
416 	{
417 		"ZoomFit",
418 		GTK_STOCK_ZOOM_FIT,
419 		"Best _Fit",
420 		NULL,
421 		"Adapt zoom to fit image",
422 		G_CALLBACK (zoom_to_fit_cb)
423 	},
424 	{
425 		"Fullscreen",
426 		GTK_STOCK_FULLSCREEN,
427 		"_Fullscreen Mode",
428 		"F11",
429 		"View image in fullscreen",
430 		G_CALLBACK (fullscreen_cb)
431 	}
432 };
433 
434 static const GtkRadioActionEntry image_tools[] = {
435     {
436         "DraggerTool",
437         GTK_STOCK_REFRESH,
438         "_Drag",
439         NULL,
440         "Use the hand tool",
441         10
442     },
443     {
444         "SelectorTool",
445         GTK_STOCK_MEDIA_PAUSE,
446         "_Select",
447         NULL,
448         "Use the rectangular selection tool",
449         20
450     },
451     {
452         "PainterTool",
453         GTK_STOCK_MEDIA_PLAY,
454         "_Paint",
455         NULL,
456         "Use the painter tool",
457         30
458     }
459 };
460 
461 static const GtkActionEntry transform_actions[] = {
462     {
463         "Transform",
464         NULL,
465         "_Transform",
466         "<control>T",
467         "Apply an XOR transformation to the image",
468         G_CALLBACK (transform_cb)
469     }
470 };
471 
472 gchar *ui_info =
473     "<ui>"
474     "  <menubar name = 'MenuBar'>"
475     "    <menu action = 'FileMenu'>"
476     "      <menuitem action = 'Open'/>"
477     "      <menuitem action = 'Quit'/>"
478     "    </menu>"
479     "    <menu action = 'EditMenu'>"
480     "      <menuitem action = 'Transform'/>"
481     "      <separator/>"
482     "      <menuitem action = 'DraggerTool'/>"
483     "      <menuitem action = 'SelectorTool'/>"
484     "      <menuitem action = 'PainterTool'/>"
485     "    </menu>"
486     "    <menu action = 'ViewMenu'>"
487 	"      <menuitem action = 'Fullscreen'/>"
488 	"      <separator/>"
489     "      <menuitem action = 'ZoomIn'/>"
490     "      <menuitem action = 'ZoomOut'/>"
491 	"      <menuitem action = 'ZoomNormal'/>"
492 	"      <menuitem action = 'ZoomFit'/>"
493     "      <separator/>"
494     "      <menu action = 'TranspMenu'>"
495     "        <menuitem action = 'TranspGrid'/>"
496     "        <menuitem action = 'TranspBackground'/>"
497     "        <menuitem action = 'TranspBlack'/>"
498     "      </menu>"
499 	"      <separator/>"
500 	"      <menuitem action = 'QualityHigh'/>"
501 	"      <menuitem action = 'QualityLow'/>"
502     "    </menu>"
503     "  </menubar>"
504     "  <toolbar name = 'ToolBar'>"
505     "    <toolitem action='Quit'/>"
506     "    <toolitem action='Open'/>"
507     "    <separator/>"
508     "    <toolitem action='DraggerTool'/>"
509     "    <toolitem action='SelectorTool'/>"
510     "    <toolitem action='PainterTool'/>"
511     "    <separator/>"
512     "    <toolitem action='ZoomIn'/>"
513     "    <toolitem action='ZoomOut'/>"
514 	"    <toolitem action='ZoomNormal'/>"
515 	"    <toolitem action='ZoomFit'/>"
516     "  </toolbar>"
517     "</ui>";
518 
519 
520 static void
parse_ui(GtkUIManager * uimanager)521 parse_ui (GtkUIManager *uimanager)
522 {
523     GError *err;
524     if (!gtk_ui_manager_add_ui_from_string (uimanager, ui_info, -1, &err))
525     {
526         g_warning ("Unable to create menus: %s", err->message);
527         g_free (err);
528     }
529 }
530 
531 static void
add_action_groups(GtkUIManager * uimanager)532 add_action_groups (GtkUIManager *uimanager)
533 {
534     // Setup the default group.
535     default_group = gtk_action_group_new ("default");
536     gtk_action_group_add_actions (default_group,
537                                   default_actions,
538                                   G_N_ELEMENTS (default_actions),
539                                   NULL);
540     gtk_action_group_add_radio_actions (default_group,
541                                         image_tools,
542                                         G_N_ELEMENTS (image_tools),
543                                         10,
544                                         G_CALLBACK (change_image_tool_cb),
545                                         NULL);
546     gtk_ui_manager_insert_action_group (uimanager, default_group, 0);
547 
548     // Setup the image group.
549     image_group = gtk_action_group_new ("image");
550     gtk_action_group_add_actions (image_group,
551                                   image_actions,
552                                   G_N_ELEMENTS (image_actions),
553                                   NULL);
554 	gtk_action_group_add_radio_actions (image_group,
555 										quality_actions,
556 										G_N_ELEMENTS (quality_actions),
557 										TRUE,
558 										G_CALLBACK (change_zoom_quality_cb),
559 										NULL);
560     gtk_action_group_add_radio_actions (image_group,
561                                         transp_actions,
562                                         G_N_ELEMENTS (transp_actions),
563                                         GTK_IMAGE_TRANSP_GRID,
564                                         G_CALLBACK (change_transp_type_cb),
565                                         NULL);
566 	gtk_action_group_set_sensitive (image_group, FALSE);
567     gtk_ui_manager_insert_action_group (uimanager, image_group, 0);
568 
569     // Transform group
570     transform_group = gtk_action_group_new ("transform");
571     gtk_action_group_add_actions (transform_group,
572                                   transform_actions,
573                                   G_N_ELEMENTS (transform_actions),
574                                   NULL);
575     gtk_action_group_set_sensitive (transform_group, FALSE);
576     gtk_ui_manager_insert_action_group (uimanager, transform_group, 0);
577 }
578 
579 static GtkWidget *
setup_layout(GtkUIManager * uimanager)580 setup_layout (GtkUIManager *uimanager)
581 {
582     GtkWidget *box = gtk_vbox_new (FALSE, 0);
583 
584     GtkWidget *menu = gtk_ui_manager_get_widget (uimanager, "/MenuBar");
585     gtk_box_pack_start (GTK_BOX (box), menu, FALSE, FALSE, 0);
586 
587     GtkWidget *toolbar = gtk_ui_manager_get_widget (uimanager, "/ToolBar");
588     gtk_box_pack_start (GTK_BOX (box), toolbar, FALSE, FALSE, 0);
589 
590 	GtkWidget *scroll_win = gtk_image_scroll_win_new (GTK_IMAGE_VIEW (view));
591 
592 	gtk_box_pack_start (GTK_BOX (box), scroll_win, TRUE, TRUE, 0);
593 
594 	statusbar = gtk_statusbar_new ();
595 
596     // A label in the statusbar that displays the current selection if
597     // there is one.
598     GtkWidget *sel_info_frame = gtk_frame_new (NULL);
599     gtk_frame_set_shadow_type (GTK_FRAME (sel_info_frame), GTK_SHADOW_IN);
600 
601     sel_info_label = gtk_label_new ("");
602     gtk_container_add (GTK_CONTAINER (sel_info_frame), sel_info_label);
603 
604     g_signal_connect (G_OBJECT (selector), "selection_changed",
605                       G_CALLBACK (sel_changed_cb), sel_info_label);
606 
607     gtk_box_pack_start (GTK_BOX (statusbar), sel_info_frame, FALSE, FALSE, 0);
608 
609     // A label in the statusbar that displays the current zoom. It
610     // updates its text when the zoom-changed signal is fired from the
611     // view.
612 	GtkWidget *zoom_info_frame = gtk_frame_new (NULL);
613 	gtk_frame_set_shadow_type (GTK_FRAME (zoom_info_frame), GTK_SHADOW_IN);
614 
615 	GtkWidget *zoom_info_label = gtk_label_new ("100%");
616 	gtk_container_add (GTK_CONTAINER (zoom_info_frame), zoom_info_label);
617 
618 	g_signal_connect (G_OBJECT (view), "zoom_changed",
619 					  G_CALLBACK (zoom_changed_cb), zoom_info_label);
620 
621 	gtk_box_pack_start (GTK_BOX (statusbar), zoom_info_frame, FALSE, FALSE, 0);
622 
623 	gtk_box_pack_end (GTK_BOX (box), statusbar, FALSE, FALSE, 0);
624     return box;
625 }
626 
627 static void
setup_main_window()628 setup_main_window ()
629 {
630     GtkUIManager *uimanager = gtk_ui_manager_new ();
631 
632 	g_signal_connect (uimanager, "connect_proxy",
633 					  G_CALLBACK (connect_proxy_cb), NULL);
634 	g_signal_connect (uimanager, "disconnect_proxy",
635 					  G_CALLBACK (disconnect_proxy_cb), NULL);
636 
637 
638 
639     add_action_groups (uimanager);
640     parse_ui (uimanager);
641 
642     GtkAccelGroup *accels = gtk_ui_manager_get_accel_group (uimanager);
643     assert (accels);
644 
645     GtkWidget *vbox = setup_layout (uimanager);
646     main_window = main_window_new (vbox, 700, 500);
647     gtk_window_add_accel_group (main_window, accels);
648 
649 	gtk_widget_grab_focus (GTK_WIDGET (view));
650 
651 	// Setup context ID:s
652 	help_msg_cid = gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar),
653 												 "help_msg");
654 	image_info_cid = gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar),
655 												   "image_info");
656 	g_object_unref (uimanager);
657 }
658 
659 int
main(int argc,char * argv[])660 main (int   argc,
661       char *argv[])
662 {
663 	char **filenames = NULL;
664 	GOptionEntry options[] = {
665 		{
666 			G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_FILENAME_ARRAY,
667 			&filenames, NULL, "[FILE...]"
668 		},
669 		{NULL}
670 	};
671 	GOptionContext *ctx = g_option_context_new ("Sample image viewer");
672 	g_option_context_add_main_entries (ctx, options, "example1");
673 	g_option_context_parse (ctx, &argc, &argv, NULL);
674 	g_option_context_free (ctx);
675 
676 	gtk_init (&argc, &argv);
677 
678 	view = GTK_ANIM_VIEW (gtk_anim_view_new ());
679 
680     dragger = gtk_image_tool_dragger_new (GTK_IMAGE_VIEW (view));
681     selector = gtk_image_tool_selector_new (GTK_IMAGE_VIEW (view));
682     painter = gtk_image_tool_painter_new (GTK_IMAGE_VIEW (view));
683 
684 	setup_main_window ();
685 
686 	if (filenames)
687 		load_filename (filenames[0]);
688 
689 	gtk_widget_show_all (GTK_WIDGET (main_window));
690     gtk_main ();
691     return 0;
692 }
693 
694