1 /* -*- Mode: C; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 3 -*- */
2 
3 /*
4  * GImageView
5  * Copyright (C) 2001-2003 Takuro Ashie
6  * Copyright (C) 2003 Frank Fischer <frank_fischer@gmx.de>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21  *
22  * $Id: gimv_image_view.c,v 1.17 2004/09/29 06:13:50 makeinu Exp $
23  */
24 
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "gimageview.h"
29 
30 #include "cursors.h"
31 #include "dnd.h"
32 #include "fileutil.h"
33 #include "gimv_image.h"
34 #include "gimv_anim.h"
35 #include "gimv_icon_stock.h"
36 #include "gimv_thumb.h"
37 #include "gimv_image_view.h"
38 #include "gimv_image_win.h"
39 #include "gimv_nav_win.h"
40 #include "gtk2-compat.h"
41 #include "gtkutils.h"
42 #include "menu.h"
43 #include "prefs.h"
44 
45 #ifdef ENABLE_EXIF
46 
47 #include <libexif/exif-data.h>
48 #include <libexif/exif-utils.h>
49 #include <libexif/jpeg-data.h>
50 
51 #endif
52 
53 
54 #define MIN_IMAGE_WIDTH  8
55 #define MIN_IMAGE_HEIGHT 8
56 #define IMAGE_VIEW_ENABLE_SCALABLE_LOAD 1
57 
58 
59 typedef enum {
60    IMAGE_CHANGED_SIGNAL,
61    LOAD_START_SIGNAL,
62    LOAD_END_SIGNAL,
63    SET_LIST_SIGNAL,
64    UNSET_LIST_SIGNAL,
65    RENDERED_SIGNAL,
66    TOGGLE_ASPECT_SIGNAL,
67    TOGGLE_BUFFER_SIGNAL,
68    THUMBNAIL_CREATED_SIGNAL,
69 
70    IMAGE_PRESSED_SIGNAL,
71    IMAGE_RELEASED_SIGNAL,
72    IMAGE_CLICKED_SIGNAL,
73 
74    LAST_SIGNAL
75 } GimvImageViewSignalType;
76 
77 
78 typedef enum {
79    MOVIE_STOP,
80    MOVIE_PLAY,
81    MOVIE_PAUSE,
82    MOVIE_FORWARD,
83    MOVIE_REVERSE,
84    MOVIE_EJECT
85 } GimvImageViewMovieMenu;
86 
87 
88 typedef enum
89 {
90    GimvImageViewSeekBarDraggingFlag   = 1 << 0
91 } GimvImageViewPlayerFlags;
92 
93 
94 typedef struct GimvImageViewImageList_Tag
95 {
96    GList                    *list;
97    GList                    *current;
98    gpointer                  owner;
99    GimvImageViewNextFn       next_fn;
100    GimvImageViewPrevFn       prev_fn;
101    GimvImageViewNthFn        nth_fn;
102    GimvImageViewRemoveListFn remove_list_fn;
103    gpointer                  list_fn_user_data;
104 } GimvImageViewImageList;
105 
106 
107 struct GimvImageViewPrivate_Tag
108 {
109    GtkWidget       *navwin;
110 
111    /* image */
112    GdkPixmap       *pixmap;
113    GdkBitmap       *mask;
114 
115    /* image status */
116    gint             x_pos;
117    gint             y_pos;
118    gint             width;
119    gint             height;
120 
121    gfloat           x_scale;
122    gfloat           y_scale;
123    GimvImageViewOrientation rotate;
124 
125    gint             default_zoom;      /* should be defined as enum */
126    gint             default_rotation;  /* should be defined as enum */
127    GimvImageViewZoomType fit_to_frame;
128    gboolean         keep_aspect;
129    gboolean         ignore_alpha;
130    gboolean         buffer;
131 
132    /* imageview status */
133    gboolean         show_scrollbar;
134    gboolean         continuance_play;
135 
136    /* player status */
137    GimvImageViewPlayerFlags       player_flags;
138    GimvImageViewPlayerVisibleType player_visible;
139 
140    /* image list and related functions */
141    GimvImageViewImageList *image_list;
142 
143    /* information about image dragging */
144    guint            button;
145    gboolean         pressed;
146    gboolean         dragging;
147    gint             drag_startx;
148    gint             drag_starty;
149    gint             x_pos_drag_start;
150    gint             y_pos_drag_start;
151 
152    /* */
153    guint   load_end_signal_id;
154    guint   loader_progress_update_signal_id;
155    guint   loader_load_end_signal_id;
156 
157    GtkWindow *fullscreen;
158 };
159 
160 
161 /* object class methods */
162 static void gimv_image_view_class_init    (GimvImageViewClass *klass);
163 static void gimv_image_view_init          (GimvImageView *iv);
164 static void gimv_image_view_destroy       (GtkObject *object);
165 
166 /* image view class methods */
167 static void gimv_image_view_image_changed (GimvImageView *iv);
168 
169 /* call back functions for reference popup menu */
170 static void cb_ignore_alpha                (GimvImageView   *iv,
171                                             guint            action,
172                                             GtkWidget       *widget);
173 static void cb_keep_aspect                 (GimvImageView   *iv,
174                                             guint            action,
175                                             GtkWidget       *widget);
176 static void cb_zoom                        (GimvImageView   *iv,
177                                             GimvImageViewZoomType zoom,
178                                             GtkWidget       *widget);
179 static void cb_rotate                      (GimvImageView   *iv,
180                                             guint            action,
181                                             GtkWidget       *widget);
182 static void cb_toggle_scrollbar            (GimvImageView   *iv,
183                                             guint            action,
184                                             GtkWidget       *widget);
185 static void cb_create_thumbnail            (GimvImageView   *iv,
186                                             guint            action,
187                                             GtkWidget       *widget);
188 static void cb_toggle_buffer               (GimvImageView   *iv,
189                                             guint            action,
190                                             GtkWidget       *widget);
191 
192 /* call back functions for player toolbar */
193 static void     cb_gimv_image_view_play   (GtkButton     *button,
194                                            GimvImageView *iv);
195 static void     cb_gimv_image_view_stop   (GtkButton     *button,
196                                            GimvImageView *iv);
197 static void     cb_gimv_image_view_fw     (GtkButton     *button,
198                                            GimvImageView *iv);
199 static void     cb_gimv_image_view_rw     (GtkButton     *button,
200                                            GimvImageView *iv);
201 static void     cb_gimv_image_view_eject  (GtkButton     *button,
202                                            GimvImageView *iv);
203 static gboolean cb_seekbar_pressed  (GtkWidget      *widget,
204                                      GdkEventButton *event,
205                                      GimvImageView  *iv);
206 static gboolean cb_seekbar_released (GtkWidget      *widget,
207                                      GdkEventButton *event,
208                                      GimvImageView  *iv);
209 
210 /* other call back functions */
211 static void     cb_destroy_loader          (GimvImageLoader   *loader,
212                                             gpointer           data);
213 static void     cb_image_map               (GtkWidget         *widget,
214                                             GimvImageView     *iv);
215 static gboolean cb_image_key_press         (GtkWidget         *widget,
216                                             GdkEventKey       *event,
217                                             GimvImageView     *iv);
218 static gboolean cb_image_button_press      (GtkWidget         *widget,
219                                             GdkEventButton    *event,
220                                             GimvImageView     *iv);
221 static gboolean cb_image_button_release    (GtkWidget         *widget,
222                                             GdkEventButton    *event,
223                                             GimvImageView     *iv);
224 static gboolean cb_image_motion_notify     (GtkWidget         *widget,
225                                             GdkEventMotion    *event,
226                                             GimvImageView     *iv);
227 static void     cb_scrollbar_value_changed (GtkAdjustment     *adj,
228                                             GimvImageView     *iv);
229 static gboolean cb_nav_button              (GtkWidget         *widget,
230                                             GdkEventButton    *event,
231                                             GimvImageView     *iv);
232 
233 /* callback functions for movie menu */
234 static void cb_movie_menu                  (GimvImageView   *iv,
235                                             GimvImageViewMovieMenu operation,
236                                             GtkWidget       *widget);
237 static void cb_movie_menu_destroy          (GtkWidget       *widget,
238                                             GimvImageView   *iv);
239 static void cb_view_modes_menu_destroy     (GtkWidget       *widget,
240                                             GimvImageView   *iv);
241 static void cb_continuance                 (GimvImageView   *iv,
242                                             guint            active,
243                                             GtkWidget       *widget);
244 static void cb_change_view_mode            (GtkWidget       *widget,
245                                             GimvImageView   *iv);
246 
247 /* other private functions */
248 static void allocate_draw_buffer             (GimvImageView   *iv);
249 static void gimv_image_view_calc_image_size  (GimvImageView   *iv);
250 static void gimv_image_view_rotate_render    (GimvImageView   *iv,
251                                               guint            action);
252 
253 static void gimv_image_view_change_draw_widget     (GimvImageView     *iv,
254                                                     const gchar       *label);
255 static void gimv_image_view_adjust_pos_in_frame    (GimvImageView     *iv,
256                                                     gboolean           center);
257 static gint idle_gimv_image_view_change_image_info (gpointer           data);
258 static void gimv_image_view_get_request_size       (GimvImageView     *iv,
259                                                     gint              *width_ret,
260                                                     gint              *height_ret);
261 
262 static GtkWidget *gimv_image_view_create_player_toolbar (GimvImageView *iv);
263 
264 
265 static GtkVBoxClass *parent_class = NULL;
266 static gint gimv_image_view_signals[LAST_SIGNAL] = {0};
267 
268 
269 extern GimvImageViewPlugin imageview_draw_vfunc_table;
270 
271 GList *draw_area_list = NULL;
272 
273 
274 /* reference menu items */
275 GtkItemFactoryEntry gimv_image_view_popup_items [] =
276 {
277    {N_("/tear"),                  NULL,         NULL,                0, "<Tearoff>"},
278    {N_("/_Zoom"),                 NULL,         NULL,                0, "<Branch>"},
279    {N_("/_Rotate"),               NULL,         NULL,                0, "<Branch>"},
280    {N_("/Ignore _Alpha Channel"), NULL,         cb_ignore_alpha,     0, "<ToggleItem>"},
281    {N_("/---"),                   NULL,         NULL,                0, "<Separator>"},
282    {N_("/M_ovie"),                NULL,         NULL,                0, "<Branch>"},
283    {N_("/---"),                   NULL,         NULL,                0, "<Separator>"},
284    {N_("/_View modes"),           NULL,         NULL,                0, "<Branch>"},
285    {N_("/Show _Scrollbar"),       "<shift>S",   cb_toggle_scrollbar, 0, "<ToggleItem>"},
286    {N_("/---"),                   NULL,         NULL,                0, "<Separator>"},
287    {N_("/Create _Thumbnail"),     "<shift>T",   cb_create_thumbnail, 0, NULL},
288    {N_("/Memory _Buffer"),        "<control>B", cb_toggle_buffer,    0, "<ToggleItem>"},
289    {NULL, NULL, NULL, 0, NULL},
290 };
291 
292 
293 /* for "Zoom" sub menu */
294 GtkItemFactoryEntry gimv_image_view_zoom_items [] =
295 {
296    {N_("/tear"),                NULL,        NULL,            0,           "<Tearoff>"},
297    {N_("/Zoom _In"),            "S",         cb_zoom,         GIMV_IMAGE_VIEW_ZOOM_IN,     NULL},
298    {N_("/Zoom _Out"),           "A",         cb_zoom,         GIMV_IMAGE_VIEW_ZOOM_OUT,    NULL},
299    {N_("/_Fit to Window"),      "W",         cb_zoom,         GIMV_IMAGE_VIEW_ZOOM_FIT,    NULL},
300    {N_("/_Fit _Width"),         "<shift>W",  cb_zoom,         GIMV_IMAGE_VIEW_ZOOM_FIT_WIDTH, NULL},
301    {N_("/_Fit _Height"),        "<shift>H",  cb_zoom,         GIMV_IMAGE_VIEW_ZOOM_FIT_HEIGHT,NULL},
302    {N_("/Keep _aspect ratio"),  "<shift>A",  cb_keep_aspect,  0,           "<ToggleItem>"},
303    {N_("/---"),                 NULL,        NULL,            0,           "<Separator>"},
304    {N_("/10%(_1)"),             "1",         cb_zoom,         GIMV_IMAGE_VIEW_ZOOM_10,     NULL},
305    {N_("/25%(_2)"),             "2",         cb_zoom,         GIMV_IMAGE_VIEW_ZOOM_25,     NULL},
306    {N_("/50%(_3)"),             "3",         cb_zoom,         GIMV_IMAGE_VIEW_ZOOM_50,     NULL},
307    {N_("/75%(_4)"),             "4",         cb_zoom,         GIMV_IMAGE_VIEW_ZOOM_75,     NULL},
308    {N_("/100%(_5)"),            "5",         cb_zoom,         GIMV_IMAGE_VIEW_ZOOM_100,    NULL},
309    {N_("/125%(_6)"),            "6",         cb_zoom,         GIMV_IMAGE_VIEW_ZOOM_125,    NULL},
310    {N_("/150%(_7)"),            "7",         cb_zoom,         GIMV_IMAGE_VIEW_ZOOM_150,    NULL},
311    {N_("/175%(_8)"),            "8",         cb_zoom,         GIMV_IMAGE_VIEW_ZOOM_175,    NULL},
312    {N_("/200%(_9)"),            "9",         cb_zoom,         GIMV_IMAGE_VIEW_ZOOM_200,    NULL},
313    {NULL, NULL, NULL, 0, NULL},
314 };
315 
316 
317 /* for "Rotate" sub menu */
318 GtkItemFactoryEntry gimv_image_view_rotate_items [] =
319 {
320    {N_("/tear"),            NULL,  NULL,       0,           "<Tearoff>"},
321    {N_("/Rotate 90 degrees CW"),  "R",   cb_rotate,  GIMV_IMAGE_VIEW_ROTATE_270,  NULL},
322    {N_("/Rotate 90 degrees CCW"), "E",   cb_rotate,  GIMV_IMAGE_VIEW_ROTATE_90,   NULL},
323    {N_("/Rotate 180 degrees"),    "D",   cb_rotate,  GIMV_IMAGE_VIEW_ROTATE_180,  NULL},
324    {NULL, NULL, NULL, 0, NULL},
325 };
326 
327 
328 /* for "Movie" sub menu */
329 GtkItemFactoryEntry gimv_image_view_playable_items [] =
330 {
331    {N_("/tear"),             NULL,  NULL,           0,             "<Tearoff>"},
332    {N_("/_Play"),            NULL,  cb_movie_menu,  MOVIE_PLAY,    NULL},
333    {N_("/_Stop"),            NULL,  cb_movie_menu,  MOVIE_STOP,    NULL},
334    {N_("/P_ause"),           NULL,  cb_movie_menu,  MOVIE_PAUSE,   NULL},
335    {N_("/_Forward"),         NULL,  cb_movie_menu,  MOVIE_FORWARD, NULL},
336    {N_("/_Reverse"),         NULL,  cb_movie_menu,  MOVIE_REVERSE, NULL},
337    {N_("/---"),              NULL,  NULL,           0,             "<Separator>"},
338    {N_("/_Continuance"),     NULL,  cb_continuance, 0,             "<ToggleItem>"},
339    {N_("/---"),              NULL,  NULL,           0,             "<Separator>"},
340    {N_("/_Eject"),           NULL,  cb_movie_menu,  MOVIE_EJECT, NULL},
341    {NULL, NULL, NULL, 0, NULL},
342 };
343 
344 
345 static GList *GimvImageViewList = NULL;
346 static GdkPixmap *buffer = NULL;
347 static gboolean move_scrollbar_by_user = TRUE;
348 
349 
350 /****************************************************************************
351  *
352  *  Plugin Management
353  *
354  ****************************************************************************/
355 static gint
comp_func_priority(GimvImageViewPlugin * plugin1,GimvImageViewPlugin * plugin2)356 comp_func_priority (GimvImageViewPlugin *plugin1,
357                     GimvImageViewPlugin *plugin2)
358 {
359    g_return_val_if_fail (plugin1, 1);
360    g_return_val_if_fail (plugin2, -1);
361 
362    return plugin1->priority_hint - plugin2->priority_hint;
363 }
364 
365 gboolean
gimv_image_view_plugin_regist(const gchar * plugin_name,const gchar * module_name,gpointer impl,gint size)366 gimv_image_view_plugin_regist (const gchar *plugin_name,
367                                const gchar *module_name,
368                                gpointer impl,
369                                gint     size)
370 {
371    GimvImageViewPlugin *plugin = impl;
372 
373    g_return_val_if_fail (module_name, FALSE);
374    g_return_val_if_fail (plugin, FALSE);
375    g_return_val_if_fail (size > 0, FALSE);
376    g_return_val_if_fail (plugin->if_version == GIMV_IMAGE_VIEW_IF_VERSION, FALSE);
377    g_return_val_if_fail (plugin->label, FALSE);
378 
379    if (!draw_area_list)
380       draw_area_list = g_list_append (draw_area_list,
381                                       &imageview_draw_vfunc_table);
382 
383    draw_area_list = g_list_append (draw_area_list, plugin);
384    draw_area_list = g_list_sort (draw_area_list,
385                                  (GCompareFunc) comp_func_priority);
386 
387    return TRUE;
388 }
389 
390 
391 GList *
gimv_image_view_plugin_get_list(void)392 gimv_image_view_plugin_get_list (void)
393 {
394    if (!draw_area_list)
395       draw_area_list = g_list_append (draw_area_list,
396                                       &imageview_draw_vfunc_table);
397    return draw_area_list;
398 }
399 
400 
401 /****************************************************************************
402  *
403  *
404  *
405  ****************************************************************************/
406 GtkType
gimv_image_view_get_type(void)407 gimv_image_view_get_type (void)
408 {
409    static GtkType gimv_image_view_type = 0;
410 
411    if (!gimv_image_view_type) {
412       static const GtkTypeInfo gimv_image_view_info = {
413          "GimvImageView",
414          sizeof (GimvImageView),
415          sizeof (GimvImageViewClass),
416          (GtkClassInitFunc) gimv_image_view_class_init,
417          (GtkObjectInitFunc) gimv_image_view_init,
418          NULL,
419          NULL,
420          (GtkClassInitFunc) NULL,
421       };
422 
423       gimv_image_view_type = gtk_type_unique (gtk_vbox_get_type (),
424                                               &gimv_image_view_info);
425    }
426 
427    return gimv_image_view_type;
428 }
429 
430 
431 enum {
432   ARG_0,
433   ARG_X_SCALE,
434   ARG_Y_SCALE,
435   ARG_ORIENTATION,
436   ARG_DEFAULT_ZOOM,
437   ARG_DEFAULT_ROTATION,
438   ARG_KEEP_ASPECT,
439   ARG_KEEP_BUFFER,
440   ARG_IGNORE_ALPHA,
441   ARG_SHOW_SCROLLBAR,
442   ARG_CONTINUANCE_PLAY,
443 };
444 
445 
446 /* FIXME!! */
447 static void
gimv_image_view_set_arg(GtkObject * object,GtkArg * arg,guint arg_id)448 gimv_image_view_set_arg (GtkObject *object,
449                          GtkArg    *arg,
450                          guint      arg_id)
451 {
452    GimvImageView *iv = GIMV_IMAGE_VIEW(object);
453 
454    switch (arg_id) {
455    case ARG_X_SCALE:
456       iv->priv->x_scale = GTK_VALUE_FLOAT (*arg);
457       break;
458    case ARG_Y_SCALE:
459       iv->priv->y_scale = GTK_VALUE_FLOAT (*arg);
460       break;
461    case ARG_ORIENTATION:
462       iv->priv->rotate = GTK_VALUE_INT (*arg);
463       break;
464    case ARG_DEFAULT_ZOOM:
465       iv->priv->default_zoom = GTK_VALUE_INT (*arg);
466       break;
467    case ARG_DEFAULT_ROTATION:
468       iv->priv->default_rotation = GTK_VALUE_INT (*arg);
469       break;
470    case ARG_KEEP_ASPECT:
471       iv->priv->keep_aspect = GTK_VALUE_BOOL (*arg);
472       break;
473    case ARG_KEEP_BUFFER:
474       iv->priv->buffer = GTK_VALUE_BOOL (*arg);
475       break;
476    case ARG_IGNORE_ALPHA:
477       iv->priv->ignore_alpha = GTK_VALUE_BOOL (*arg);
478       break;
479    case ARG_SHOW_SCROLLBAR:
480       iv->priv->show_scrollbar = GTK_VALUE_BOOL (*arg);
481       break;
482    case ARG_CONTINUANCE_PLAY:
483       iv->priv->continuance_play = GTK_VALUE_BOOL (*arg);
484       break;
485    default:
486       break;
487    }
488 }
489 
490 static void
gimv_image_view_get_arg(GtkObject * object,GtkArg * arg,guint arg_id)491 gimv_image_view_get_arg (GtkObject *object,
492                          GtkArg    *arg,
493                          guint      arg_id)
494 {
495    GimvImageView *iv = GIMV_IMAGE_VIEW(object);
496 
497    switch (arg_id) {
498    case ARG_X_SCALE:
499       GTK_VALUE_FLOAT (*arg) = iv->priv->x_scale;
500       break;
501    case ARG_Y_SCALE:
502       GTK_VALUE_FLOAT (*arg) = iv->priv->y_scale;
503       break;
504    case ARG_ORIENTATION:
505       GTK_VALUE_INT (*arg) = iv->priv->rotate;
506       break;
507    case ARG_DEFAULT_ZOOM:
508       GTK_VALUE_INT (*arg) = iv->priv->default_zoom;
509       break;
510    case ARG_DEFAULT_ROTATION:
511       GTK_VALUE_INT (*arg) = iv->priv->default_rotation;
512       break;
513    case ARG_KEEP_ASPECT:
514       GTK_VALUE_BOOL (*arg) = iv->priv->keep_aspect;
515       break;
516    case ARG_KEEP_BUFFER:
517       GTK_VALUE_BOOL (*arg) = iv->priv->buffer;
518       break;
519    case ARG_IGNORE_ALPHA:
520       GTK_VALUE_BOOL (*arg) = iv->priv->ignore_alpha;
521       break;
522    case ARG_SHOW_SCROLLBAR:
523       GTK_VALUE_BOOL (*arg) = iv->priv->show_scrollbar;
524       break;
525    case ARG_CONTINUANCE_PLAY:
526       GTK_VALUE_BOOL (*arg) = iv->priv->continuance_play;
527       break;
528    default:
529       arg->type = GTK_TYPE_INVALID;
530       break;
531    }
532 }
533 
534 
535 static void
gimv_image_view_class_init(GimvImageViewClass * klass)536 gimv_image_view_class_init (GimvImageViewClass *klass)
537 {
538    GtkObjectClass *object_class;
539 
540    object_class = (GtkObjectClass *) klass;
541    parent_class = gtk_type_class (gtk_vbox_get_type ());
542 
543    gtk_object_add_arg_type ("GimvImageView::x_scale",
544                             GTK_TYPE_FLOAT,
545                             GTK_ARG_READWRITE,
546                             ARG_X_SCALE);
547    gtk_object_add_arg_type ("GimvImageView::y_scale",
548                             GTK_TYPE_FLOAT,
549                             GTK_ARG_READWRITE,
550                             ARG_Y_SCALE);
551    gtk_object_add_arg_type ("GimvImageView::orientation",
552                             GTK_TYPE_INT,
553                             GTK_ARG_READWRITE,
554                             ARG_ORIENTATION);
555    gtk_object_add_arg_type ("GimvImageView::default_zoom",
556                             GTK_TYPE_INT,
557                             GTK_ARG_READWRITE,
558                             ARG_DEFAULT_ZOOM);
559    gtk_object_add_arg_type ("GimvImageView::default_rotation",
560                             GTK_TYPE_INT,
561                             GTK_ARG_READWRITE,
562                             ARG_DEFAULT_ROTATION);
563    gtk_object_add_arg_type ("GimvImageView::keep_aspect",
564                             GTK_TYPE_BOOL,
565                             GTK_ARG_READWRITE,
566                             ARG_KEEP_ASPECT);
567    gtk_object_add_arg_type ("GimvImageView::keep_buffer",
568                             GTK_TYPE_BOOL,
569                             GTK_ARG_READWRITE,
570                             ARG_KEEP_BUFFER);
571    gtk_object_add_arg_type ("GimvImageView::ignore_alpha",
572                             GTK_TYPE_BOOL,
573                             GTK_ARG_READWRITE,
574                             ARG_IGNORE_ALPHA);
575    gtk_object_add_arg_type ("GimvImageView::show_scrollbar",
576                             GTK_TYPE_BOOL,
577                             GTK_ARG_READWRITE,
578                             ARG_SHOW_SCROLLBAR);
579    gtk_object_add_arg_type ("GimvImageView::continuance_play",
580                             GTK_TYPE_BOOL,
581                             GTK_ARG_READWRITE,
582                             ARG_CONTINUANCE_PLAY);
583 
584    gimv_image_view_signals[IMAGE_CHANGED_SIGNAL]
585       = gtk_signal_new ("image_changed",
586                         GTK_RUN_FIRST,
587                         GTK_CLASS_TYPE(object_class),
588                         GTK_SIGNAL_OFFSET (GimvImageViewClass, image_changed),
589                         gtk_signal_default_marshaller,
590                         GTK_TYPE_NONE, 0);
591 
592    gimv_image_view_signals[LOAD_START_SIGNAL]
593       = gtk_signal_new ("load_start",
594                         GTK_RUN_FIRST,
595                         GTK_CLASS_TYPE(object_class),
596                         GTK_SIGNAL_OFFSET (GimvImageViewClass, load_start),
597                         gtk_marshal_NONE__POINTER,
598                         GTK_TYPE_NONE, 1, GTK_TYPE_POINTER);
599 
600    gimv_image_view_signals[LOAD_END_SIGNAL]
601       = gtk_signal_new ("load_end",
602                         GTK_RUN_FIRST,
603                         GTK_CLASS_TYPE(object_class),
604                         GTK_SIGNAL_OFFSET (GimvImageViewClass, load_end),
605                         gtk_marshal_NONE__POINTER_INT,
606                         GTK_TYPE_NONE, 2, GTK_TYPE_POINTER, GTK_TYPE_INT);
607 
608    gimv_image_view_signals[SET_LIST_SIGNAL]
609       = gtk_signal_new ("set_list",
610                         GTK_RUN_FIRST,
611                         GTK_CLASS_TYPE(object_class),
612                         GTK_SIGNAL_OFFSET (GimvImageViewClass, set_list),
613                         gtk_signal_default_marshaller,
614                         GTK_TYPE_NONE, 0);
615 
616    gimv_image_view_signals[UNSET_LIST_SIGNAL]
617       = gtk_signal_new ("unset_list",
618                         GTK_RUN_FIRST,
619                         GTK_CLASS_TYPE(object_class),
620                         GTK_SIGNAL_OFFSET (GimvImageViewClass, unset_list),
621                         gtk_signal_default_marshaller,
622                         GTK_TYPE_NONE, 0);
623 
624    gimv_image_view_signals[RENDERED_SIGNAL]
625       = gtk_signal_new ("rendered",
626                         GTK_RUN_FIRST,
627                         GTK_CLASS_TYPE(object_class),
628                         GTK_SIGNAL_OFFSET (GimvImageViewClass, rendered),
629                         gtk_signal_default_marshaller,
630                         GTK_TYPE_NONE, 0);
631 
632    gimv_image_view_signals[TOGGLE_ASPECT_SIGNAL]
633       = gtk_signal_new ("toggle_aspect",
634                         GTK_RUN_FIRST,
635                         GTK_CLASS_TYPE(object_class),
636                         GTK_SIGNAL_OFFSET (GimvImageViewClass, toggle_aspect),
637                         gtk_marshal_NONE__INT,
638                         GTK_TYPE_NONE, 1, GTK_TYPE_INT);
639 
640    gimv_image_view_signals[TOGGLE_BUFFER_SIGNAL]
641       = gtk_signal_new ("toggle_buffer",
642                         GTK_RUN_FIRST,
643                         GTK_CLASS_TYPE(object_class),
644                         GTK_SIGNAL_OFFSET (GimvImageViewClass, toggle_buffer),
645                         gtk_marshal_NONE__INT,
646                         GTK_TYPE_NONE, 1, GTK_TYPE_INT);
647 
648    gimv_image_view_signals[THUMBNAIL_CREATED_SIGNAL]
649       = gtk_signal_new ("thumbnail_created",
650                         GTK_RUN_FIRST,
651                         GTK_CLASS_TYPE(object_class),
652                         GTK_SIGNAL_OFFSET (GimvImageViewClass, thumbnail_created),
653                         gtk_marshal_NONE__POINTER,
654                         GTK_TYPE_NONE, 1, GTK_TYPE_POINTER);
655 
656    gimv_image_view_signals[IMAGE_PRESSED_SIGNAL]
657       = gtk_signal_new ("image_pressed",
658                         GTK_RUN_LAST,
659                         GTK_CLASS_TYPE(object_class),
660                         GTK_SIGNAL_OFFSET (GimvImageViewClass, image_pressed),
661                         gtk_marshal_BOOL__POINTER,
662                         GTK_TYPE_BOOL, 1, GTK_TYPE_POINTER);
663 
664    gimv_image_view_signals[IMAGE_RELEASED_SIGNAL]
665       = gtk_signal_new ("image_released",
666                         GTK_RUN_LAST,
667                         GTK_CLASS_TYPE(object_class),
668                         GTK_SIGNAL_OFFSET (GimvImageViewClass, image_released),
669                         gtk_marshal_BOOL__POINTER,
670                         GTK_TYPE_BOOL, 1, GTK_TYPE_POINTER);
671 
672    gimv_image_view_signals[IMAGE_CLICKED_SIGNAL]
673       = gtk_signal_new ("image_clicked",
674                         GTK_RUN_LAST,
675                         GTK_CLASS_TYPE(object_class),
676                         GTK_SIGNAL_OFFSET (GimvImageViewClass, image_clicked),
677                         gtk_marshal_BOOL__POINTER,
678                         GTK_TYPE_BOOL, 1, GTK_TYPE_POINTER);
679 
680    gtk_object_class_add_signals (object_class, gimv_image_view_signals, LAST_SIGNAL);
681 
682    object_class->set_arg = gimv_image_view_set_arg;
683    object_class->get_arg = gimv_image_view_get_arg;
684    object_class->destroy = gimv_image_view_destroy;
685 
686    klass->image_changed     = gimv_image_view_image_changed;
687    klass->load_start        = NULL;
688    klass->load_end          = NULL;
689    klass->set_list          = NULL;
690    klass->unset_list        = NULL;
691    klass->rendered          = NULL;
692    klass->toggle_aspect     = NULL;
693    klass->toggle_buffer     = NULL;
694    klass->thumbnail_created = NULL;
695 }
696 
697 
698 static void
gimv_image_view_init(GimvImageView * iv)699 gimv_image_view_init (GimvImageView *iv)
700 {
701    GtkWidget *player, *event_box;
702 
703    /* initialize struct data based on config */
704    iv->loader     = NULL;
705    iv->image      = NULL;
706 
707    iv->hadj = iv->vadj  = NULL;
708 
709    iv->draw_area        = NULL;
710    iv->draw_area_funcs  = NULL;
711 
712    iv->progressbar      = NULL;
713 
714    iv->bg_color         = NULL;
715 
716    iv->cursor           = NULL;
717    iv->imageview_popup  = NULL;
718    iv->zoom_menu        = NULL;
719    iv->rotate_menu      = NULL;
720    iv->movie_menu       = NULL;
721    iv->view_modes_menu  = NULL;
722 
723    /* init private data */
724    iv->priv = g_new0(GimvImageViewPrivate, 1);
725 
726    iv->priv->navwin     = NULL;
727 
728    iv->priv->pixmap     = NULL;
729    iv->priv->mask       = NULL;
730 
731    iv->priv->x_pos      = 0;
732    iv->priv->y_pos      = 0;
733    iv->priv->width      = 0;
734    iv->priv->height     = 0;
735 
736    iv->priv->show_scrollbar   = FALSE;
737    iv->priv->default_zoom     = conf.imgview_default_zoom;
738    iv->priv->default_rotation = conf.imgview_default_rotation;
739    iv->priv->fit_to_frame     = 0;
740 
741    iv->priv->x_scale          = conf.imgview_scale;
742    iv->priv->y_scale          = conf.imgview_scale;
743    iv->priv->rotate     = 0;
744    iv->priv->keep_aspect      = conf.imgview_keep_aspect;
745    iv->priv->ignore_alpha     = FALSE;
746 
747    iv->priv->buffer           = conf.imgview_buffer;
748 
749    iv->priv->show_scrollbar   = conf.imgview_scrollbar;
750    iv->priv->continuance_play = conf.imgview_movie_continuance;
751 
752    iv->priv->player_flags     = 0;
753    iv->priv->player_visible   = GimvImageViewPlayerVisibleAuto;
754 
755    /* list */
756    iv->priv->image_list = NULL;
757 
758    iv->priv->load_end_signal_id               = 0;
759    iv->priv->loader_progress_update_signal_id = 0;
760    iv->priv->loader_load_end_signal_id        = 0;
761 
762    iv->priv->fullscreen = NULL;
763 
764    /* create widgets */
765    iv->loader = gimv_image_loader_new ();
766 
767    iv->table = gtk_table_new (2, 2, FALSE);
768    gtk_widget_show (iv->table);
769    gtk_box_pack_start (GTK_BOX (iv), iv->table, TRUE, TRUE, 0);
770 
771    player = gimv_image_view_create_player_toolbar (iv);
772    gtk_box_pack_start (GTK_BOX (iv), player, FALSE, FALSE, 2);
773 
774    gimv_image_view_change_draw_widget (iv, 0);
775 
776    iv->hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 10.0, 10.0, 0.0));
777    iv->hscrollbar = gtk_hscrollbar_new (iv->hadj);
778    gtk_widget_show (iv->hscrollbar);
779 
780    iv->vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 10.0, 10.0, 0.0));
781    iv->vscrollbar = gtk_vscrollbar_new (iv->vadj);
782    gtk_widget_show (iv->vscrollbar);
783 
784    event_box = gtk_event_box_new ();
785    gtk_widget_set_name (event_box, "NavWinButton");
786    gtk_widget_show (event_box);
787 
788    iv->nav_button = gimv_icon_stock_get_widget ("nav-button");
789    gtk_container_add (GTK_CONTAINER (event_box), iv->nav_button);
790    gtk_widget_show (iv->nav_button);
791 
792    gtk_table_attach (GTK_TABLE (iv->table), iv->vscrollbar,
793                      1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
794    gtk_table_attach (GTK_TABLE (iv->table), iv->hscrollbar,
795                      0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
796    gtk_table_attach (GTK_TABLE (iv->table), event_box,
797                      1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
798 
799    /* set signals */
800    gtk_signal_connect (GTK_OBJECT (iv->hadj), "value_changed",
801                        GTK_SIGNAL_FUNC (cb_scrollbar_value_changed), iv);
802 
803    gtk_signal_connect (GTK_OBJECT (iv->vadj), "value_changed",
804                        GTK_SIGNAL_FUNC (cb_scrollbar_value_changed), iv);
805 
806    gtk_signal_connect (GTK_OBJECT (event_box), "button_press_event",
807                        GTK_SIGNAL_FUNC (cb_nav_button), iv);
808 
809    /* add to list */
810    GimvImageViewList = g_list_append (GimvImageViewList, iv);
811 
812    if (!iv->priv->show_scrollbar) {
813       gimv_image_view_hide_scrollbar (iv);
814    }
815 }
816 
817 
818 GtkWidget*
gimv_image_view_new(GimvImageInfo * info)819 gimv_image_view_new (GimvImageInfo *info)
820 {
821    GimvImageView *iv = gtk_type_new (gimv_image_view_get_type ());
822 
823    if (info) {
824       iv->info = gimv_image_info_ref (info);
825    } else {
826       iv->info = NULL;
827    }
828 
829    /* load image */
830    if (iv->info)
831       gtk_idle_add (idle_gimv_image_view_change_image_info, iv);
832 
833    return GTK_WIDGET (iv);
834 }
835 
836 
837 static void
gimv_image_view_destroy(GtkObject * object)838 gimv_image_view_destroy (GtkObject *object)
839 {
840    GimvImageView *iv = GIMV_IMAGE_VIEW (object);
841 
842    if (GTK_IS_WIDGET (iv->draw_area)) {
843       gtk_widget_destroy (iv->draw_area);
844    }
845    iv->draw_area = NULL;
846 
847    if (iv->loader) {
848       if (gimv_image_loader_is_loading (iv->loader)) {
849          gimv_image_view_cancel_loading (iv);
850          gtk_signal_connect (GTK_OBJECT (iv->loader), "load_end",
851                              GTK_SIGNAL_FUNC (cb_destroy_loader),
852                              iv);
853       } else {
854          gimv_image_loader_unref (iv->loader);
855       }
856    }
857    iv->loader = NULL;
858 
859    if (iv->image)
860       gimv_image_unref (iv->image);
861    iv->image = NULL;
862 
863    if (iv->bg_color)
864       g_free (iv->bg_color);
865    iv->bg_color = NULL;
866 
867    if (iv->cursor)
868       gdk_cursor_destroy (iv->cursor);
869    iv->cursor = NULL;
870 
871    if (iv->info)
872       gimv_image_info_unref (iv->info);
873    iv->info = NULL;
874 
875    if (iv->priv) {
876       if (iv->priv->navwin) {
877          gtk_widget_destroy (iv->priv->navwin);
878          iv->priv->navwin = NULL;
879       }
880 
881       if (iv->priv->pixmap) {
882          gimv_image_free_pixmap_and_mask (iv->priv->pixmap, iv->priv->mask);
883          iv->priv->pixmap = NULL;
884          iv->priv->mask = NULL;
885       }
886 
887       if (iv->priv->image_list)
888          gimv_image_view_remove_list (iv, iv->priv->image_list->owner);
889       iv->priv->image_list = NULL;
890 
891       g_free(iv->priv);
892       iv->priv = NULL;
893    }
894 
895    if (GTK_OBJECT_CLASS (parent_class)->destroy)
896       GTK_OBJECT_CLASS (parent_class)->destroy (object);
897 }
898 
899 
900 static void
gimv_image_view_image_changed(GimvImageView * iv)901 gimv_image_view_image_changed (GimvImageView *iv)
902 {
903    GimvImageViewPlayableIF *playable;
904 
905    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
906 
907    if (!iv->draw_area_funcs) return;
908 
909    playable = iv->draw_area_funcs->playable;
910    if (!playable) return;
911    if (!playable->is_playable_fn) return;
912 
913    if (gimv_image_view_is_playable (iv)) {
914       GimvImageViewPlayableStatus status;
915 
916       if (iv->priv->player_visible == GimvImageViewPlayerVisibleAuto)
917          gtk_widget_show (iv->player_container);
918       status = gimv_image_view_playable_get_status (iv);
919       gimv_image_view_playable_set_status (iv, status);
920 
921    } else {
922       if (iv->priv->player_visible == GimvImageViewPlayerVisibleAuto)
923          gtk_widget_hide (iv->player_container);
924       gimv_image_view_playable_set_status (iv, GimvImageViewPlayableDisable);
925    }
926 }
927 
928 
929 
930 /*****************************************************************************
931  *
932  *   Callback functions for reference popup menu.
933  *
934  *****************************************************************************/
935 static void
cb_ignore_alpha(GimvImageView * iv,guint action,GtkWidget * widget)936 cb_ignore_alpha (GimvImageView *iv, guint action, GtkWidget *widget)
937 {
938    iv->priv->ignore_alpha = GTK_CHECK_MENU_ITEM(widget)->active;
939    gimv_image_view_show_image (iv);
940 }
941 
942 
943 static void
cb_keep_aspect(GimvImageView * iv,guint action,GtkWidget * widget)944 cb_keep_aspect (GimvImageView *iv, guint action, GtkWidget *widget)
945 {
946    iv->priv->keep_aspect = GTK_CHECK_MENU_ITEM(widget)->active;
947 
948    gtk_signal_emit (GTK_OBJECT(iv),
949                     gimv_image_view_signals[TOGGLE_ASPECT_SIGNAL],
950                     iv->priv->keep_aspect);
951 }
952 
953 
954 static void
cb_zoom(GimvImageView * iv,GimvImageViewZoomType zoom,GtkWidget * widget)955 cb_zoom (GimvImageView *iv, GimvImageViewZoomType zoom, GtkWidget *widget)
956 {
957    gimv_image_view_zoom_image (iv, zoom, 0, 0);
958 }
959 
960 
961 static void
cb_rotate(GimvImageView * iv,GimvImageViewOrientation rotate,GtkWidget * widget)962 cb_rotate (GimvImageView *iv, GimvImageViewOrientation rotate, GtkWidget *widget)
963 {
964    guint angle;
965 
966    /* convert to absolute angle */
967    angle = (iv->priv->rotate + rotate) % 4;
968 
969    gimv_image_view_rotate_image (iv, angle);
970 }
971 
972 
973 static void
cb_toggle_scrollbar(GimvImageView * iv,guint action,GtkWidget * widget)974 cb_toggle_scrollbar (GimvImageView *iv, guint action, GtkWidget *widget)
975 {
976    if (GTK_CHECK_MENU_ITEM(widget)->active) {
977       gimv_image_view_show_scrollbar (iv);
978    } else {
979       gimv_image_view_hide_scrollbar (iv);
980    }
981 }
982 
983 
984 static void
cb_create_thumbnail(GimvImageView * iv,guint action,GtkWidget * widget)985 cb_create_thumbnail (GimvImageView *iv, guint action, GtkWidget *widget)
986 {
987    g_return_if_fail (iv);
988 
989    gimv_image_view_create_thumbnail (iv);
990 }
991 
992 
993 static void
cb_toggle_buffer(GimvImageView * iv,guint action,GtkWidget * widget)994 cb_toggle_buffer (GimvImageView *iv, guint action, GtkWidget *widget)
995 {
996    if (GTK_CHECK_MENU_ITEM(widget)->active) {
997       gimv_image_view_load_image_buf (iv);
998       iv->priv->buffer = TRUE;
999    }
1000    else {
1001       iv->priv->buffer = FALSE;
1002       gimv_image_view_free_image_buf (iv);
1003    }
1004 
1005    gtk_signal_emit (GTK_OBJECT(iv),
1006                     gimv_image_view_signals[TOGGLE_BUFFER_SIGNAL],
1007                     iv->priv->buffer);
1008 }
1009 
1010 
1011 
1012 /*****************************************************************************
1013  *
1014  *   callback functions for movie menu.
1015  *
1016  *****************************************************************************/
1017 static void
cb_movie_menu(GimvImageView * iv,GimvImageViewMovieMenu operation,GtkWidget * widget)1018 cb_movie_menu (GimvImageView *iv,
1019                GimvImageViewMovieMenu operation,
1020                GtkWidget *widget)
1021 {
1022    g_return_if_fail (iv);
1023 
1024    switch (operation) {
1025    case MOVIE_PLAY:
1026       gimv_image_view_playable_play (iv);
1027       break;
1028    case MOVIE_STOP:
1029       gimv_image_view_playable_stop (iv);
1030       break;
1031    case MOVIE_PAUSE:
1032       gimv_image_view_playable_pause (iv);
1033       break;
1034    case MOVIE_FORWARD:
1035       gimv_image_view_playable_forward (iv);
1036       break;
1037    case MOVIE_REVERSE:
1038       gimv_image_view_playable_reverse (iv);
1039       break;
1040    case MOVIE_EJECT:
1041       gimv_image_view_playable_eject (iv);
1042       break;
1043    default:
1044       break;
1045    }
1046 }
1047 
1048 
1049 static void
cb_movie_menu_destroy(GtkWidget * widget,GimvImageView * iv)1050 cb_movie_menu_destroy (GtkWidget *widget, GimvImageView *iv)
1051 {
1052    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
1053    iv->movie_menu = NULL;
1054 }
1055 
1056 
1057 static void
cb_view_modes_menu_destroy(GtkWidget * widget,GimvImageView * iv)1058 cb_view_modes_menu_destroy (GtkWidget *widget, GimvImageView *iv)
1059 {
1060    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
1061    iv->view_modes_menu = NULL;
1062 }
1063 
1064 
1065 static void
cb_continuance(GimvImageView * iv,guint action,GtkWidget * widget)1066 cb_continuance (GimvImageView *iv, guint action, GtkWidget *widget)
1067 {
1068    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
1069    g_return_if_fail (GTK_IS_CHECK_MENU_ITEM (widget));
1070 
1071    iv->priv->continuance_play = GTK_CHECK_MENU_ITEM (widget)->active;
1072 }
1073 
1074 
1075 static void
cb_change_view_mode(GtkWidget * widget,GimvImageView * iv)1076 cb_change_view_mode (GtkWidget *widget, GimvImageView *iv)
1077 {
1078    const gchar *label;
1079 
1080    label = gtk_object_get_data (GTK_OBJECT (widget), "GimvImageView::ViewMode");
1081    gimv_image_view_change_view_mode (iv, label);
1082 }
1083 
1084 
1085 
1086 /*****************************************************************************
1087  *
1088  *   callback functions for player toolbar.
1089  *
1090  *****************************************************************************/
1091 static void
cb_gimv_image_view_play(GtkButton * button,GimvImageView * iv)1092 cb_gimv_image_view_play (GtkButton *button, GimvImageView *iv)
1093 {
1094    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
1095 
1096    gimv_image_view_playable_play (iv);
1097 }
1098 
1099 
1100 static void
cb_gimv_image_view_stop(GtkButton * button,GimvImageView * iv)1101 cb_gimv_image_view_stop (GtkButton *button, GimvImageView *iv)
1102 {
1103    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
1104 
1105    gimv_image_view_playable_stop (iv);
1106 }
1107 
1108 
1109 static void
cb_gimv_image_view_fw(GtkButton * button,GimvImageView * iv)1110 cb_gimv_image_view_fw (GtkButton *button, GimvImageView *iv)
1111 {
1112    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
1113 
1114    gimv_image_view_playable_forward (iv);
1115 }
1116 
1117 
1118 static void
cb_gimv_image_view_eject(GtkButton * button,GimvImageView * iv)1119 cb_gimv_image_view_eject (GtkButton *button, GimvImageView *iv)
1120 {
1121    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
1122 
1123    gimv_image_view_playable_eject (iv);
1124 }
1125 
1126 
1127 static void
cb_gimv_image_view_rw(GtkButton * button,GimvImageView * iv)1128 cb_gimv_image_view_rw (GtkButton *button, GimvImageView *iv)
1129 {
1130    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
1131 
1132    gimv_image_view_playable_reverse (iv);
1133 }
1134 
1135 
1136 static gboolean
cb_seekbar_pressed(GtkWidget * widget,GdkEventButton * event,GimvImageView * iv)1137 cb_seekbar_pressed (GtkWidget *widget,
1138                     GdkEventButton *event,
1139                     GimvImageView *iv)
1140 {
1141    g_return_val_if_fail (GIMV_IS_IMAGE_VIEW (iv), FALSE);
1142 
1143    iv->priv->player_flags |= GimvImageViewSeekBarDraggingFlag;
1144 
1145    return FALSE;
1146 }
1147 
1148 
1149 static gboolean
cb_seekbar_released(GtkWidget * widget,GdkEventButton * event,GimvImageView * iv)1150 cb_seekbar_released (GtkWidget *widget,
1151                      GdkEventButton *event,
1152                      GimvImageView *iv)
1153 {
1154    GtkAdjustment *adj;
1155    g_return_val_if_fail (GIMV_IS_IMAGE_VIEW (iv), FALSE);
1156 
1157    adj = gtk_range_get_adjustment (GTK_RANGE (iv->player.seekbar));
1158    gimv_image_view_playable_seek (iv, adj->value);
1159 
1160    iv->priv->player_flags &= ~GimvImageViewSeekBarDraggingFlag;
1161 
1162    return FALSE;
1163 }
1164 
1165 
1166 
1167 /*****************************************************************************
1168  *
1169  *   other callback functions.
1170  *
1171  *****************************************************************************/
1172 static void
cb_destroy_loader(GimvImageLoader * loader,gpointer data)1173 cb_destroy_loader (GimvImageLoader *loader, gpointer data)
1174 {
1175    gtk_signal_disconnect_by_func (GTK_OBJECT (loader),
1176                                   GTK_SIGNAL_FUNC (cb_destroy_loader),
1177                                   data);
1178    gimv_image_loader_unref (loader);
1179 }
1180 
1181 
1182 static void
cb_image_map(GtkWidget * widget,GimvImageView * iv)1183 cb_image_map (GtkWidget *widget, GimvImageView *iv)
1184 {
1185    gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
1186                                   GTK_SIGNAL_FUNC (cb_image_map), iv);
1187    gimv_image_view_show_image (iv);
1188    gimv_image_view_playable_play (iv);
1189    gtk_signal_emit (GTK_OBJECT(iv),
1190                     gimv_image_view_signals[IMAGE_CHANGED_SIGNAL]);
1191 }
1192 
1193 
1194 static gboolean
cb_image_key_press(GtkWidget * widget,GdkEventKey * event,GimvImageView * iv)1195 cb_image_key_press (GtkWidget *widget, GdkEventKey *event, GimvImageView *iv)
1196 {
1197    guint keyval, popup_key;
1198    GdkModifierType modval, popup_mod;
1199    gboolean move = FALSE;
1200    gint mx, my;
1201 
1202    g_return_val_if_fail (iv, FALSE);
1203 
1204    gimv_image_view_get_view_position (iv, &mx, &my);
1205 
1206    keyval = event->keyval;
1207    modval = event->state;
1208 
1209    if (akey.common_popup_menu || *akey.common_popup_menu)
1210       gtk_accelerator_parse (akey.common_popup_menu, &popup_key, &popup_mod);
1211    else
1212       return FALSE;
1213 
1214    if (keyval == popup_key && (!popup_mod || (modval & popup_mod))) {
1215       gimv_image_view_popup_menu (iv, NULL);
1216    } else {
1217       switch (keyval) {
1218       case GDK_Left:
1219       case GDK_KP_Left:
1220       case GDK_KP_4:
1221          mx -= 20;
1222          move = TRUE;
1223          break;
1224       case GDK_Right:
1225       case GDK_KP_Right:
1226       case GDK_KP_6:
1227          mx += 20;
1228          move = TRUE;
1229          break;
1230       case GDK_Up:
1231       case GDK_KP_Up:
1232       case GDK_KP_8:
1233          my -= 20;
1234          move = TRUE;
1235          break;
1236       case GDK_Down:
1237       case GDK_KP_Down:
1238       case GDK_KP_2:
1239          my += 20;
1240          move = TRUE;
1241          break;
1242       case GDK_KP_5:
1243          mx = 0;
1244          my = 0;
1245          move = TRUE;
1246          break;
1247       case GDK_Page_Up:
1248       case GDK_KP_Page_Up:
1249       case GDK_KP_9:
1250          gimv_image_view_prev (iv);
1251          return TRUE;
1252       case GDK_space:
1253       case GDK_Page_Down:
1254       case GDK_KP_Space:
1255       case GDK_KP_Page_Down:
1256       case GDK_KP_3:
1257       case GDK_KP_0:
1258          gimv_image_view_next (iv);
1259          return TRUE;
1260       case GDK_Home:
1261       case GDK_KP_Home:
1262       case GDK_KP_7:
1263         gimv_image_view_nth (iv, 0);
1264          return TRUE;
1265       case GDK_End:
1266       case GDK_KP_End:
1267       case GDK_KP_1:
1268       {
1269          gint last;
1270          if (iv->priv->image_list) {
1271             last = g_list_length (iv->priv->image_list->list) - 1;
1272             if (last > 0)
1273                gimv_image_view_nth (iv, last);
1274          }
1275          return TRUE;
1276       }
1277       case GDK_KP_Add:
1278       case GDK_plus:
1279          gimv_image_view_zoom_image (iv, GIMV_IMAGE_VIEW_ZOOM_IN, 0, 0);
1280          return FALSE;
1281          break;
1282       case GDK_KP_Subtract:
1283       case GDK_minus:
1284          gimv_image_view_zoom_image (iv, GIMV_IMAGE_VIEW_ZOOM_OUT, 0, 0);
1285          return FALSE;
1286          break;
1287       case GDK_equal:
1288       case GDK_KP_Equal:
1289       case GDK_KP_Enter:
1290          gimv_image_view_zoom_image (iv, GIMV_IMAGE_VIEW_ZOOM_100, 0, 0);
1291          return FALSE;
1292          break;
1293       case GDK_KP_Divide:
1294          gimv_image_view_zoom_image (iv, GIMV_IMAGE_VIEW_ZOOM_FIT, 0, 0);
1295          return FALSE;
1296          break;
1297       }
1298    }
1299 
1300    if (move) {
1301       gimv_image_view_moveto (iv, mx, my);
1302       return TRUE;
1303    }
1304 
1305    return FALSE;
1306 }
1307 
1308 
1309 static gboolean
cb_image_button_press(GtkWidget * widget,GdkEventButton * event,GimvImageView * iv)1310 cb_image_button_press (GtkWidget *widget, GdkEventButton *event,
1311                        GimvImageView *iv)
1312 {
1313    GdkCursor *cursor;
1314    gint retval = FALSE;
1315 
1316    g_return_val_if_fail (iv, FALSE);
1317 
1318    iv->priv->pressed = TRUE;
1319    iv->priv->button  = event->button;
1320 
1321    gtk_widget_grab_focus (widget);
1322 
1323    gtk_signal_emit (GTK_OBJECT (iv),
1324                     gimv_image_view_signals[IMAGE_PRESSED_SIGNAL],
1325                     event, &retval);
1326 
1327    if (iv->priv->dragging)
1328       return FALSE;
1329 
1330    if (event->button == 1) {   /* scroll image */
1331       if (!iv->priv->pixmap)
1332          return FALSE;
1333 
1334       cursor = cursor_get (widget->window, CURSOR_HAND_CLOSED);
1335       retval = gdk_pointer_grab (widget->window, FALSE,
1336                                  (GDK_POINTER_MOTION_MASK
1337                                   | GDK_POINTER_MOTION_HINT_MASK
1338                                   | GDK_BUTTON_RELEASE_MASK),
1339                                  NULL, cursor, event->time);
1340       gdk_cursor_destroy (cursor);
1341 
1342       if (retval != 0)
1343          return FALSE;
1344 
1345       iv->priv->drag_startx = event->x - iv->priv->x_pos;
1346       iv->priv->drag_starty = event->y - iv->priv->y_pos;
1347       iv->priv->x_pos_drag_start = iv->priv->x_pos;
1348       iv->priv->y_pos_drag_start = iv->priv->y_pos;
1349 
1350       allocate_draw_buffer (iv);
1351 
1352       return TRUE;
1353 
1354    }
1355 
1356    return FALSE;
1357 }
1358 
1359 
1360 static gboolean
cb_image_button_release(GtkWidget * widget,GdkEventButton * event,GimvImageView * iv)1361 cb_image_button_release  (GtkWidget *widget, GdkEventButton *event,
1362                           GimvImageView *iv)
1363 {
1364    gint retval = FALSE;
1365 
1366    /*
1367    if (event->button != 1)
1368       return FALSE;
1369    */
1370 
1371    gtk_signal_emit (GTK_OBJECT (iv),
1372                     gimv_image_view_signals[IMAGE_RELEASED_SIGNAL],
1373                     event, &retval);
1374 
1375    if(iv->priv->pressed && !iv->priv->dragging)
1376       gtk_signal_emit (GTK_OBJECT (iv),
1377                        gimv_image_view_signals[IMAGE_CLICKED_SIGNAL],
1378                        event, &retval);
1379 
1380    if (buffer) {
1381       gdk_pixmap_unref (buffer);
1382       buffer = NULL;
1383    }
1384 
1385    iv->priv->button   = 0;
1386    iv->priv->pressed  = FALSE;
1387    iv->priv->dragging = FALSE;
1388 
1389    gdk_pointer_ungrab (event->time);
1390 
1391    return retval;
1392 }
1393 
1394 
1395 static gboolean
cb_image_motion_notify(GtkWidget * widget,GdkEventMotion * event,GimvImageView * iv)1396 cb_image_motion_notify (GtkWidget *widget, GdkEventMotion *event,
1397                         GimvImageView *iv)
1398 {
1399    GdkModifierType mods;
1400    gint x, y, x_pos, y_pos, dx, dy;
1401 
1402    if (!iv->priv->pressed)
1403       return FALSE;
1404 
1405    gdk_window_get_pointer (widget->window, &x, &y, &mods);
1406 
1407    x_pos = x - iv->priv->drag_startx;
1408    y_pos = y - iv->priv->drag_starty;
1409    dx = x_pos - iv->priv->x_pos_drag_start;
1410    dy = y_pos - iv->priv->y_pos_drag_start;
1411 
1412    if (!iv->priv->dragging && (abs(dx) > 2 || abs (dy) > 2))
1413       iv->priv->dragging = TRUE;
1414 
1415    /* scroll image */
1416    if (iv->priv->button == 1) {
1417       if (event->is_hint)
1418          gdk_window_get_pointer (widget->window, &x, &y, &mods);
1419 
1420       iv->priv->x_pos = x_pos;
1421       iv->priv->y_pos = y_pos;
1422 
1423       gimv_image_view_adjust_pos_in_frame (iv, FALSE);
1424    }
1425 
1426    gimv_image_view_draw_image (iv);
1427 
1428    return TRUE;
1429 }
1430 
1431 
1432 static void
cb_drag_data_received(GtkWidget * widget,GdkDragContext * context,gint x,gint y,GtkSelectionData * seldata,guint info,guint32 time,gpointer data)1433 cb_drag_data_received (GtkWidget *widget,
1434                        GdkDragContext *context,
1435                        gint x, gint y,
1436                        GtkSelectionData *seldata,
1437                        guint info,
1438                        guint32 time,
1439                        gpointer data)
1440 {
1441    GimvImageView *iv = data;
1442    FilesLoader *files;
1443    GList *filelist;
1444    gchar *tmpstr;
1445 
1446    g_return_if_fail (iv || widget);
1447 
1448    filelist = dnd_get_file_list (seldata->data, seldata->length);
1449 
1450    if (filelist) {
1451       GimvImageInfo *info = gimv_image_info_get ((gchar *) filelist->data);
1452 
1453       if (!info) goto ERROR;
1454 
1455       gimv_image_view_change_image (iv, info);
1456       tmpstr = filelist->data;
1457       filelist = g_list_remove (filelist, tmpstr);
1458       g_free (tmpstr);
1459 
1460       if (filelist) {
1461          files = files_loader_new ();
1462          files->filelist = filelist;
1463          open_image_files_in_image_view (files);
1464          files->filelist = NULL;
1465          files_loader_delete (files);
1466       }
1467    }
1468 
1469 ERROR:
1470    g_list_foreach (filelist, (GFunc) g_free, NULL);
1471    g_list_free (filelist);
1472 }
1473 
1474 
1475 static void
cb_scrollbar_value_changed(GtkAdjustment * adj,GimvImageView * iv)1476 cb_scrollbar_value_changed (GtkAdjustment *adj, GimvImageView *iv)
1477 {
1478    g_return_if_fail (iv);
1479 
1480    if (!move_scrollbar_by_user) return;
1481 
1482    if (iv->priv->width > iv->draw_area->allocation.width)
1483       iv->priv->x_pos = 0 - iv->hadj->value;
1484    if (iv->priv->height > iv->draw_area->allocation.height)
1485       iv->priv->y_pos = 0 - iv->vadj->value;
1486 
1487    gimv_image_view_draw_image (iv);
1488 }
1489 
1490 
1491 static gboolean
cb_nav_button(GtkWidget * widget,GdkEventButton * event,GimvImageView * iv)1492 cb_nav_button (GtkWidget *widget, GdkEventButton *event, GimvImageView *iv)
1493 {
1494    g_return_val_if_fail (iv, FALSE);
1495 
1496    gimv_image_view_open_navwin (iv, event->x_root, event->y_root);
1497 
1498    return FALSE;
1499 }
1500 
1501 
1502 /*****************************************************************************
1503  *
1504  *   Private functions.
1505  *
1506  *****************************************************************************/
1507 static void
allocate_draw_buffer(GimvImageView * iv)1508 allocate_draw_buffer (GimvImageView *iv)
1509 {
1510    gint fwidth, fheight;
1511 
1512    if (!iv) return;
1513 
1514    if (buffer) gdk_pixmap_unref (buffer);
1515    gimv_image_view_get_image_frame_size (iv, &fwidth, &fheight);
1516    buffer = gdk_pixmap_new (iv->draw_area->window, fwidth, fheight, -1);
1517 }
1518 
1519 
1520 
1521 static void
gimv_image_view_calc_image_size(GimvImageView * iv)1522 gimv_image_view_calc_image_size (GimvImageView *iv)
1523 {
1524    gint orig_width, orig_height;
1525    gint width, height;
1526    gint fwidth, fheight;
1527    gfloat x_scale, y_scale;
1528 
1529    /* image scale */
1530    if (iv->priv->rotate == 0 || iv->priv->rotate == 2) {
1531       x_scale = iv->priv->x_scale;
1532       y_scale = iv->priv->y_scale;
1533    } else {
1534       x_scale = iv->priv->y_scale;
1535       y_scale = iv->priv->x_scale;
1536    }
1537 
1538    if (iv->priv->rotate == 0 || iv->priv->rotate == 2) {
1539       orig_width  = iv->info->width;
1540       orig_height = iv->info->height;
1541    } else {
1542       orig_width  = iv->info->height;
1543       orig_height = iv->info->width;
1544    }
1545 
1546    gimv_image_view_get_image_frame_size (iv, &fwidth, &fheight);
1547    width  = orig_width;
1548    height = orig_height;
1549 
1550    /* calculate image size */
1551    switch (iv->priv->fit_to_frame) {
1552    case GIMV_IMAGE_VIEW_ZOOM_FIT:
1553    case GIMV_IMAGE_VIEW_ZOOM_FIT_ZOOM_OUT_ONLY:
1554    {
1555       if (width <= fwidth && height <= fheight
1556           && iv->priv->fit_to_frame == GIMV_IMAGE_VIEW_ZOOM_FIT_ZOOM_OUT_ONLY)
1557       {
1558          iv->priv->x_scale = 100.0;
1559          iv->priv->y_scale = 100.0;
1560       } else {
1561          iv->priv->x_scale = (gfloat) fwidth  / (gfloat) width  * 100.0;
1562          iv->priv->y_scale = (gfloat) fheight / (gfloat) height * 100.0;
1563 
1564          if (iv->priv->keep_aspect) {
1565             if (iv->priv->x_scale > iv->priv->y_scale) {
1566                iv->priv->x_scale = iv->priv->y_scale;
1567                width  = orig_width * iv->priv->x_scale / 100.0;
1568                height = fheight;
1569             } else {
1570                iv->priv->y_scale = iv->priv->x_scale;
1571                width  = fwidth;
1572                height = orig_height * iv->priv->y_scale / 100.0;
1573             }
1574          } else {
1575             width  = fwidth;
1576             height = fheight;
1577          }
1578       }
1579 
1580       break;
1581    }
1582 
1583    case GIMV_IMAGE_VIEW_ZOOM_FIT_WIDTH:
1584       iv->priv->x_scale = (gfloat) fwidth / (gfloat) width * 100.0;
1585       iv->priv->y_scale = iv->priv->x_scale;
1586       width  = orig_width  * iv->priv->x_scale/ 100.0;
1587       height = orig_height * iv->priv->x_scale / 100.0;
1588       break;
1589 
1590    case GIMV_IMAGE_VIEW_ZOOM_FIT_HEIGHT:
1591       iv->priv->y_scale = (gfloat) fheight / (gfloat) height * 100.0;
1592       iv->priv->x_scale = iv->priv->y_scale;
1593       width  = orig_width  * iv->priv->y_scale / 100.0;
1594       height = orig_height * iv->priv->y_scale / 100.0;
1595       break;
1596 
1597    default:
1598       width  = orig_width  * x_scale / 100.0;
1599       height = orig_height * y_scale / 100.0;
1600       break;
1601    }
1602 
1603    iv->priv->fit_to_frame = 0;
1604 
1605    /*
1606     * zoom out if image is too big & window is not scrollable on
1607     * fullscreen mode
1608     */
1609    /*
1610    win_width  = hadj->page_size;
1611    win_height = vadj->page_size;
1612 
1613    if (im->fullscreen && (width > win_width || height > win_height)) {
1614          gfloat width_ratio, height_ratio;
1615 
1616          width_ratio = (gdouble) width / hadj->page_size;
1617          height_ratio = (gdouble) height / vadj->page_size;
1618          if (width_ratio > height_ratio) {
1619          width = win_width;
1620          height = (gdouble) height / (gdouble) width_ratio;
1621       } else {
1622          width = (gdouble) width / (gdouble) height_ratio;
1623          height = win_height;
1624       }
1625    }
1626    */
1627 
1628    if (width > MIN_IMAGE_WIDTH)
1629       iv->priv->width = width;
1630    else
1631       iv->priv->width = MIN_IMAGE_WIDTH;
1632    if (height > MIN_IMAGE_HEIGHT)
1633       iv->priv->height = height;
1634    else
1635       iv->priv->height = MIN_IMAGE_HEIGHT;
1636 }
1637 
1638 
1639 static void
gimv_image_view_change_draw_widget(GimvImageView * iv,const gchar * label)1640 gimv_image_view_change_draw_widget (GimvImageView *iv, const gchar *label)
1641 {
1642    GList *node;
1643    GimvImageViewPlugin *vftable = NULL;
1644    const gchar *view_mode;
1645 
1646    g_return_if_fail (iv);
1647 
1648    if (iv->draw_area_funcs
1649        && iv->draw_area_funcs->is_supported_fn
1650        && iv->draw_area_funcs->is_supported_fn (iv, iv->info))
1651    {
1652       return;
1653    }
1654 
1655    /* if default movie view mode is specified */
1656    /* FIXME!! this code is ad-hoc */
1657    view_mode = conf.movie_default_view_mode;
1658    if (iv->info
1659        && (gimv_image_info_is_movie (iv->info) || gimv_image_info_is_audio (iv->info))
1660        && view_mode && *view_mode)
1661    {
1662       for (node = gimv_image_view_plugin_get_list();
1663            node;
1664            node = g_list_next (node))
1665       {
1666          GimvImageViewPlugin *table = node->data;
1667 
1668          if (!table) continue;
1669 
1670          if (!strcmp (view_mode, table->label)
1671              && table->is_supported_fn
1672              && table->is_supported_fn (iv, iv->info))
1673          {
1674             vftable = table;
1675             break;
1676          }
1677       }
1678    }
1679 
1680    /* fall down... */
1681    for (node = gimv_image_view_plugin_get_list();
1682         node && !vftable;
1683         node = g_list_next (node))
1684    {
1685       GimvImageViewPlugin *table = node->data;
1686 
1687       if (!table) continue;
1688 
1689       if (label && *label) {
1690          if (!strcmp (label, table->label)
1691              || !strcmp (GIMV_IMAGE_VIEW_DEFAULT_VIEW_MODE, table->label))
1692          {
1693             vftable = table;
1694             break;
1695          }
1696       } else {
1697          if (!table->is_supported_fn
1698              || table->is_supported_fn (iv, iv->info))
1699          {
1700             vftable = table;
1701             break;
1702          }
1703       }
1704    }
1705 
1706    if (!vftable)
1707       vftable = &imageview_draw_vfunc_table;
1708    g_return_if_fail (vftable->create_fn);
1709    if (iv->draw_area_funcs && !strcmp (iv->draw_area_funcs->label, vftable->label))
1710       return;
1711    if (iv->draw_area)
1712       gtk_widget_destroy (iv->draw_area);
1713 
1714    iv->draw_area = vftable->create_fn (iv);
1715    iv->draw_area_funcs = vftable;
1716 
1717    gtk_widget_show (iv->draw_area);
1718 
1719    gtk_signal_connect_after (GTK_OBJECT (iv->draw_area), "key-press-event",
1720                              GTK_SIGNAL_FUNC(cb_image_key_press), iv);
1721    gtk_signal_connect (GTK_OBJECT (iv->draw_area), "button_press_event",
1722                        GTK_SIGNAL_FUNC (cb_image_button_press), iv);
1723    gtk_signal_connect (GTK_OBJECT (iv->draw_area), "button_release_event",
1724                        GTK_SIGNAL_FUNC (cb_image_button_release), iv);
1725    gtk_signal_connect (GTK_OBJECT (iv->draw_area), "motion_notify_event",
1726                        GTK_SIGNAL_FUNC (cb_image_motion_notify), iv);
1727    SIGNAL_CONNECT_TRANSRATE_SCROLL(iv->draw_area);
1728 
1729    if (iv->priv->fullscreen) {
1730       gtk_container_add (GTK_CONTAINER (iv->priv->fullscreen), iv->draw_area);
1731    } else {
1732       gtk_table_attach (GTK_TABLE (iv->table), iv->draw_area,
1733                         0, 1, 0, 1,
1734                         GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0);
1735    }
1736 
1737    /* for droping file list */
1738    gtk_signal_connect(GTK_OBJECT (iv->draw_area), "drag_data_received",
1739                       GTK_SIGNAL_FUNC (cb_drag_data_received), iv);
1740 
1741    dnd_dest_set (iv->draw_area, dnd_types_archive, dnd_types_archive_num);
1742 
1743    /* set flags */
1744    GTK_WIDGET_SET_FLAGS (iv->draw_area, GTK_CAN_FOCUS);
1745 }
1746 
1747 
1748 static void
gimv_image_view_adjust_pos_in_frame(GimvImageView * iv,gboolean center)1749 gimv_image_view_adjust_pos_in_frame (GimvImageView *iv, gboolean center)
1750 {
1751    gint fwidth, fheight;
1752 
1753    if (center) {
1754       gimv_image_view_get_image_frame_size (iv, &fwidth, &fheight);
1755 
1756       if (fwidth < iv->priv->width) {
1757          if (conf.imgview_scroll_nolimit) {
1758             if (iv->priv->x_pos > fwidth)
1759                iv->priv->x_pos = 0;
1760             else if (iv->priv->x_pos < 0 - iv->priv->width)
1761                iv->priv->x_pos = 0 - iv->priv->width + fwidth;
1762          } else {
1763             if (iv->priv->x_pos > 0)
1764                iv->priv->x_pos = 0;
1765             else if (iv->priv->x_pos < 0 - iv->priv->width + fwidth)
1766                iv->priv->x_pos = 0 - iv->priv->width + fwidth;
1767          }
1768       } else {
1769          iv->priv->x_pos = (fwidth - iv->priv->width) / 2;
1770       }
1771 
1772       if (fheight < iv->priv->height) {
1773          if (conf.imgview_scroll_nolimit) {
1774             if (iv->priv->y_pos > fheight)
1775                iv->priv->y_pos = 0;
1776             else if (iv->priv->y_pos < 0 - iv->priv->height)
1777                iv->priv->y_pos = 0 - iv->priv->height + fheight;
1778          } else {
1779             if (iv->priv->y_pos > 0)
1780                iv->priv->y_pos = 0;
1781             else if (iv->priv->y_pos < 0 - iv->priv->height + fheight)
1782                iv->priv->y_pos = 0 - iv->priv->height + fheight;
1783          }
1784       } else {
1785          iv->priv->y_pos = (fheight - iv->priv->height) / 2;
1786       }
1787    } else {
1788       if (!conf.imgview_scroll_nolimit) {
1789          gimv_image_view_get_image_frame_size (iv, &fwidth, &fheight);
1790 
1791          if (iv->priv->width <= fwidth) {
1792             if (iv->priv->x_pos < 0)
1793                iv->priv->x_pos = 0;
1794             if (iv->priv->x_pos > fwidth - iv->priv->width)
1795                iv->priv->x_pos = fwidth - iv->priv->width;
1796          } else if (iv->priv->x_pos < fwidth - iv->priv->width) {
1797             iv->priv->x_pos = fwidth - iv->priv->width;
1798          } else if (iv->priv->x_pos > 0) {
1799             iv->priv->x_pos = 0;
1800          }
1801 
1802          if (iv->priv->height <= fheight) {
1803             if (iv->priv->y_pos < 0)
1804                iv->priv->y_pos = 0;
1805             if (iv->priv->y_pos > fheight - iv->priv->height)
1806                iv->priv->y_pos = fheight - iv->priv->height;
1807          } else if (iv->priv->y_pos < fheight - iv->priv->height) {
1808             iv->priv->y_pos = fheight - iv->priv->height;
1809          } else if (iv->priv->y_pos > 0) {
1810             iv->priv->y_pos = 0;
1811          }
1812       }
1813    }
1814 }
1815 
1816 #ifdef ENABLE_EXIF
1817 static int
get_exif_rotation(GimvImageInfo * info)1818 get_exif_rotation (GimvImageInfo *info)
1819 {
1820    ExifData *edata;
1821    JPEGData *jdata;
1822    unsigned int i=0;
1823    int rotate=0;
1824    ExifByteOrder byte_order;
1825    ExifShort v_short;
1826 
1827    g_return_val_if_fail (info->filename && *(info->filename), 0);
1828 
1829    jdata = jpeg_data_new_from_file (info->filename);
1830    if (!jdata) {
1831       return 0;
1832    }
1833 
1834    edata = jpeg_data_get_exif_data (jdata);
1835    if (!edata) {
1836       goto ERROR;
1837    }
1838 
1839    byte_order = exif_data_get_byte_order (edata);
1840 
1841    for (i = 0; i < edata->ifd[0]->count; i++) {
1842       if (edata->ifd[0]->entries[i]->tag == EXIF_TAG_ORIENTATION) {
1843          v_short = exif_get_short (edata->ifd[0]->entries[i]->data , byte_order);
1844          switch (v_short) {
1845          case 1:            /* no rotation */
1846             rotate = 0;
1847             break;
1848          case 2:            /*flip vertical */
1849             rotate = 0;
1850             break;
1851          case 3:            /* rotate 180 degrees */
1852             rotate = 2;
1853             break;
1854          case 4:            /* flip vertial and rotate 180 degrees */
1855             rotate = 0;
1856             break;
1857          case 5:            /* rotate 90 degrees clockwise and flip vertical */
1858             rotate = 0;
1859             break;
1860          case 6:            /* rotate 90 degrees clockwise */
1861             rotate = 3;
1862             break;
1863          case 7:            /* rotate 90 degrees counterclockwise and flip vertical */
1864             rotate = 0;
1865             break;
1866          case 8:           /* rotate 90 degrees counterclockwise */
1867             rotate = 1;
1868             break;
1869          }
1870       }
1871    }
1872 
1873    exif_data_unref (edata);
1874    jpeg_data_unref (jdata);
1875 
1876    return rotate;
1877 
1878 ERROR:
1879    jpeg_data_unref (jdata);
1880    return 0;
1881 }
1882 
1883 #endif
1884 
1885 
1886 /*****************************************************************************
1887  *
1888  *   Public functions.
1889  *
1890  *****************************************************************************/
1891 GList *
gimv_image_view_get_list(void)1892 gimv_image_view_get_list (void)
1893 {
1894    return GimvImageViewList;
1895 }
1896 
1897 
1898 void
gimv_image_view_change_image(GimvImageView * iv,GimvImageInfo * info)1899 gimv_image_view_change_image (GimvImageView *iv, GimvImageInfo *info)
1900 {
1901    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
1902 
1903    gimv_image_view_playable_stop (iv);
1904 
1905    gimv_image_view_change_image_info (iv, info);
1906 
1907    gimv_image_view_change_draw_widget (iv, NULL);
1908    if (!g_list_find (GimvImageViewList, iv)) return;
1909 
1910    if (GTK_WIDGET_MAPPED (iv->draw_area)) {
1911       gimv_image_view_show_image (iv);
1912       gimv_image_view_playable_play (iv);
1913       gtk_signal_emit (GTK_OBJECT(iv),
1914                        gimv_image_view_signals[IMAGE_CHANGED_SIGNAL]);
1915    } else {
1916       gtk_signal_connect_after (GTK_OBJECT (iv->draw_area), "map",
1917                                 GTK_SIGNAL_FUNC (cb_image_map), iv);
1918    }
1919 }
1920 
1921 
1922 void
gimv_image_view_change_image_info(GimvImageView * iv,GimvImageInfo * info)1923 gimv_image_view_change_image_info (GimvImageView *iv, GimvImageInfo *info)
1924 {
1925    g_return_if_fail (iv);
1926 
1927    if (!g_list_find (GimvImageViewList, iv)) return;
1928 
1929    /* free old image */
1930    if (iv->priv->pixmap)
1931       gimv_image_free_pixmap_and_mask (iv->priv->pixmap, iv->priv->mask);
1932    iv->priv->pixmap = NULL;
1933    iv->priv->mask = NULL;
1934 
1935    if (iv->image)
1936       gimv_image_unref (iv->image);
1937    iv->image = NULL;
1938 
1939    /* free old image info */
1940    if (iv->info)
1941       gimv_image_info_unref (iv->info);
1942 
1943    /* Reset fit_to_frame (zoom control) to its default value for a new image.
1944     * The numbers correspond to the order of options in the pulldown menu
1945     * in prefs_ui_imagewin.c
1946     */
1947 
1948    /*
1949     * 2004-09-29 Takuro Ashie <ashie@homa.ne.jp>
1950     *   We should define enum.
1951     */
1952 
1953    switch (iv->priv->default_zoom) {
1954    case 2:
1955       iv->priv->fit_to_frame = GIMV_IMAGE_VIEW_ZOOM_FIT;
1956       break;
1957    case 3:
1958       iv->priv->fit_to_frame = GIMV_IMAGE_VIEW_ZOOM_FIT_ZOOM_OUT_ONLY;
1959       break;
1960    case 4:
1961       iv->priv->fit_to_frame = GIMV_IMAGE_VIEW_ZOOM_FIT_WIDTH;
1962       break;
1963    case 5:
1964       iv->priv->fit_to_frame = GIMV_IMAGE_VIEW_ZOOM_FIT_HEIGHT;
1965       break;
1966    case 0:
1967       iv->priv->x_scale = conf.imgview_scale;
1968       iv->priv->y_scale = conf.imgview_scale;
1969    case 1:
1970    default:
1971       iv->priv->fit_to_frame = 0;
1972       break;
1973    }
1974 
1975    /* ditto for rotation */
1976 
1977    switch (iv->priv->default_rotation) {
1978    case 4:
1979       break;
1980    case 5:
1981 #ifdef ENABLE_EXIF
1982       iv->priv->rotate = get_exif_rotation (info);
1983 #else
1984       iv->priv->rotate = 0;
1985 #endif
1986       break;
1987     default:
1988       iv->priv->rotate = iv->priv->default_rotation;
1989       break;
1990    }
1991 
1992    /* suggestion from sheepman <sheepman@tcn.zaq.ne.jp> */
1993    iv->priv->x_pos = iv->priv->y_pos = 0;
1994 
1995    /* allocate memory for new image info*/
1996    if (info)
1997       iv->info = gimv_image_info_ref (info);
1998    else
1999       iv->info = NULL;
2000 }
2001 
2002 
2003 static gint
idle_gimv_image_view_change_image_info(gpointer data)2004 idle_gimv_image_view_change_image_info (gpointer data)
2005 {
2006    GimvImageView *iv = data;
2007    GList *node;
2008 
2009    g_return_val_if_fail (data, FALSE);
2010 
2011    node = g_list_find (GimvImageViewList, iv);
2012    if (!node) return FALSE;
2013 
2014    gimv_image_info_ref (iv->info);
2015    gimv_image_view_change_image (iv, iv->info);
2016 
2017    return FALSE;
2018 }
2019 
2020 
2021 void
gimv_image_view_draw_image(GimvImageView * iv)2022 gimv_image_view_draw_image (GimvImageView *iv)
2023 {
2024    GdkGC *bg_gc;
2025    gboolean free = FALSE;
2026 
2027    if (!GTK_WIDGET_MAPPED (iv)) return;
2028 
2029    /* allocate buffer */
2030    if (!buffer) {
2031       allocate_draw_buffer (iv);
2032       free = TRUE;
2033    }
2034 
2035    /* fill background by default bg color */
2036    bg_gc = iv->draw_area->style->bg_gc[GTK_WIDGET_STATE (iv->draw_area)];
2037    gdk_draw_rectangle (buffer, bg_gc, TRUE, 0, 0, -1, -1);
2038 
2039    /* draw image to buffer */
2040    if (iv->priv->pixmap) {
2041       if (iv->priv->mask) {
2042          gdk_gc_set_clip_mask (iv->draw_area->style->black_gc, iv->priv->mask);
2043          gdk_gc_set_clip_origin (iv->draw_area->style->black_gc,
2044                                  iv->priv->x_pos, iv->priv->y_pos);
2045       }
2046 
2047       gdk_draw_pixmap (buffer,
2048                        iv->draw_area->style->black_gc,
2049                        iv->priv->pixmap,
2050                        0, 0,
2051                        iv->priv->x_pos, iv->priv->y_pos,
2052                        -1, -1);
2053 
2054       if (iv->priv->mask) {
2055          gdk_gc_set_clip_mask (iv->draw_area->style->black_gc, NULL);
2056          gdk_gc_set_clip_origin (iv->draw_area->style->black_gc, 0, 0);
2057       }
2058    }
2059 
2060    /* draw from buffer to foreground */
2061    gdk_draw_pixmap (iv->draw_area->window,
2062                     iv->draw_area->style->fg_gc[GTK_WIDGET_STATE (iv->draw_area)],
2063                     buffer, 0, 0, 0, 0, -1, -1);
2064 
2065    /* free buffer */
2066    if (free) {
2067       gdk_pixmap_unref (buffer);
2068       buffer = NULL;
2069    }
2070 
2071    gimv_image_view_reset_scrollbar (iv);
2072 }
2073 
2074 
2075 void
gimv_image_view_show_image(GimvImageView * iv)2076 gimv_image_view_show_image (GimvImageView *iv)
2077 {
2078    gimv_image_view_rotate_image (iv, iv->priv->rotate);
2079 }
2080 
2081 
2082 static gboolean
check_can_draw_image(GimvImageView * iv)2083 check_can_draw_image (GimvImageView *iv)
2084 {
2085    gboolean is_movie = FALSE;
2086    const gchar *newfile = NULL;
2087 
2088    g_return_val_if_fail (GIMV_IS_IMAGE_VIEW (iv), FALSE);
2089    g_return_val_if_fail (iv->draw_area, FALSE);
2090    g_return_val_if_fail (GTK_IS_DRAWING_AREA (iv->draw_area), FALSE);
2091 
2092    /* if (!GTK_WIDGET_MAPPED (iv->draw_area)) return FALSE; */
2093 
2094 #warning FIXME!!
2095    if (iv->info && gimv_image_info_is_movie (iv->info))
2096       is_movie = TRUE;
2097 
2098    if (is_movie) return TRUE;
2099    if (iv->image) return TRUE;
2100 
2101    if (iv->info)
2102       newfile = gimv_image_info_get_path (iv->info);
2103 
2104    if (newfile && *newfile) {
2105       if (!file_exists (newfile))
2106          g_print (_("File not exist: %s\n"), newfile);
2107       else
2108          g_print(_("Not an image (or unsupported) file: %s\n"), newfile);
2109    }
2110 
2111    /* clear draw area */
2112    gimv_image_view_draw_image (iv);
2113 
2114    return FALSE;
2115 }
2116 
2117 
2118 
2119 
2120 void
gimv_image_view_create_thumbnail(GimvImageView * iv)2121 gimv_image_view_create_thumbnail (GimvImageView *iv)
2122 {
2123    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
2124 
2125    if (!iv->info) return;
2126    if (iv->info->flags & GIMV_IMAGE_INFO_MRL_FLAG) return;   /* Dose it need? */
2127 
2128    if (!iv->draw_area_funcs) return;
2129    if (!iv->draw_area_funcs->create_thumbnail_fn) return;
2130 
2131    iv->draw_area_funcs->create_thumbnail_fn (iv, conf.cache_write_type);
2132 }
2133 
2134 
2135 /*****************************************************************************
2136  *
2137  *   functions for creating/show/hide/setting status child widgets
2138  *
2139  *****************************************************************************/
2140 void
gimv_image_view_change_view_mode(GimvImageView * iv,const gchar * label)2141 gimv_image_view_change_view_mode (GimvImageView *iv,
2142                                   const gchar *label)
2143 {
2144    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
2145 
2146    gimv_image_view_change_image (iv, NULL);
2147    gimv_image_view_change_draw_widget (iv, label);
2148 }
2149 
2150 
2151 static GtkWidget *
gimv_image_view_create_player_toolbar(GimvImageView * iv)2152 gimv_image_view_create_player_toolbar (GimvImageView *iv)
2153 {
2154    GtkWidget *hbox, *toolbar;
2155    GtkWidget *button, *seekbar;
2156    GtkWidget *iconw;
2157    GtkObject *adj;
2158 
2159    hbox = gtk_hbox_new (FALSE, 0);
2160    toolbar = gtkutil_create_toolbar ();
2161    gtk_toolbar_set_style (GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
2162    gtk_box_pack_start (GTK_BOX (hbox), toolbar, FALSE, FALSE, 0);
2163    gtk_widget_show (toolbar);
2164 
2165    iv->player_container = hbox;
2166    iv->player_toolbar = toolbar;
2167 
2168    /* Reverse button */
2169    iconw = gimv_icon_stock_get_widget ("rw");
2170    button = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar),
2171                                      _("RW"),
2172                                      _("Reverse"), _("Reverse"),
2173                                      iconw,
2174                                      GTK_SIGNAL_FUNC (cb_gimv_image_view_rw), iv);
2175    gtk_widget_set_sensitive (button, FALSE);
2176    iv->player.rw = button;
2177 
2178    /* play button */
2179    iconw = gimv_icon_stock_get_widget ("play");
2180    button = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar),
2181                                      _("Play"),
2182                                      _("Play"), _("Play"),
2183                                      iconw,
2184                                      GTK_SIGNAL_FUNC (cb_gimv_image_view_play), iv);
2185    gtk_widget_set_sensitive (button, FALSE);
2186    iv->player.play = button;
2187    iv->player.play_icon = iconw;
2188 
2189    /* stop button */
2190    iconw = gimv_icon_stock_get_widget ("stop2");
2191    button = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar),
2192                                      _("Stop"),
2193                                      _("Stop"), _("Stop"),
2194                                      iconw,
2195                                      GTK_SIGNAL_FUNC (cb_gimv_image_view_stop), iv);
2196    gtk_widget_set_sensitive (button, FALSE);
2197    iv->player.stop = button;
2198 
2199    /* Forward button */
2200    iconw = gimv_icon_stock_get_widget ("ff");
2201    button = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar),
2202                                      _("FF"),
2203                                      _("Forward"), _("Forward"),
2204                                      iconw,
2205                                      GTK_SIGNAL_FUNC (cb_gimv_image_view_fw), iv);
2206    gtk_widget_set_sensitive (button, FALSE);
2207    iv->player.fw = button;
2208 
2209    /* Eject button */
2210    iconw = gimv_icon_stock_get_widget ("eject");
2211    button = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar),
2212                                      _("Eject"),
2213                                      _("Eject"), _("Eject"),
2214                                      iconw,
2215                                      GTK_SIGNAL_FUNC (cb_gimv_image_view_eject), iv);
2216    iv->player.eject = button;
2217    gtk_widget_set_sensitive (button, FALSE);
2218 
2219    adj = gtk_adjustment_new (0.0, 0.0, 100.0, 0.1, 1.0, 1.0);
2220    seekbar = gtk_hscale_new (GTK_ADJUSTMENT (adj));
2221    gtk_scale_set_draw_value (GTK_SCALE (seekbar), FALSE);
2222    gtk_box_pack_start (GTK_BOX (hbox), seekbar, TRUE, TRUE, 0);
2223    gtk_widget_show (seekbar);
2224    iv->player.seekbar = seekbar;
2225 
2226    gtk_signal_connect (GTK_OBJECT (iv->player.seekbar), "button_press_event",
2227                        GTK_SIGNAL_FUNC (cb_seekbar_pressed), iv);
2228    gtk_signal_connect (GTK_OBJECT (iv->player.seekbar), "button_release_event",
2229                        GTK_SIGNAL_FUNC (cb_seekbar_released), iv);
2230 
2231    return hbox;
2232 }
2233 
2234 
2235 GtkWidget *
gimv_image_view_create_zoom_menu(GtkWidget * window,GimvImageView * iv,const gchar * path)2236 gimv_image_view_create_zoom_menu (GtkWidget *window,
2237                                   GimvImageView *iv,
2238                                   const gchar *path)
2239 {
2240    GtkWidget *menu;
2241    guint n_menu_items;
2242 
2243    g_return_val_if_fail (window, NULL);
2244    g_return_val_if_fail (iv, NULL);
2245    g_return_val_if_fail (path && *path, NULL);
2246 
2247    n_menu_items = sizeof(gimv_image_view_zoom_items)
2248       / sizeof(gimv_image_view_zoom_items[0]) - 1;
2249    menu = menu_create_items(window, gimv_image_view_zoom_items,
2250                             n_menu_items, path, iv);
2251    iv->zoom_menu = menu;
2252    menu_check_item_set_active (menu, "/Keep aspect ratio", iv->priv->keep_aspect);
2253 
2254    return menu;
2255 }
2256 
2257 
2258 GtkWidget *
gimv_image_view_create_rotate_menu(GtkWidget * window,GimvImageView * iv,const gchar * path)2259 gimv_image_view_create_rotate_menu (GtkWidget *window,
2260                                     GimvImageView *iv,
2261                                     const gchar *path)
2262 {
2263    GtkWidget *menu;
2264    guint n_menu_items;
2265 
2266    g_return_val_if_fail (window, NULL);
2267    g_return_val_if_fail (iv, NULL);
2268    g_return_val_if_fail (path && *path, NULL);
2269 
2270    n_menu_items = sizeof(gimv_image_view_rotate_items)
2271       / sizeof(gimv_image_view_rotate_items[0]) - 1;
2272    menu = menu_create_items(window, gimv_image_view_rotate_items,
2273                             n_menu_items, path, iv);
2274    iv->rotate_menu = menu;
2275 
2276    return menu;
2277 }
2278 
2279 
2280 GtkWidget *
gimv_image_view_create_movie_menu(GtkWidget * window,GimvImageView * iv,const gchar * path)2281 gimv_image_view_create_movie_menu (GtkWidget *window,
2282                                    GimvImageView *iv,
2283                                    const gchar *path)
2284 {
2285    GtkWidget *menu;
2286    guint n_menu_items;
2287    GimvImageViewPlayableStatus status;
2288 
2289    n_menu_items = sizeof(gimv_image_view_playable_items)
2290       / sizeof(gimv_image_view_playable_items[0]) - 1;
2291    menu = menu_create_items(window, gimv_image_view_playable_items,
2292                             n_menu_items, path, iv);
2293    iv->movie_menu = menu;
2294 
2295    menu_check_item_set_active (iv->movie_menu, "/Continuance",
2296                                iv->priv->continuance_play);
2297    status = gimv_image_view_playable_get_status (iv);
2298    gimv_image_view_playable_set_status (iv, status);
2299 
2300    gtk_signal_connect (GTK_OBJECT (menu), "destroy",
2301                        GTK_SIGNAL_FUNC (cb_movie_menu_destroy), iv);
2302 
2303    return menu;
2304 }
2305 
2306 
2307 GtkWidget *
gimv_image_view_create_view_modes_menu(GtkWidget * window,GimvImageView * iv,const gchar * path)2308 gimv_image_view_create_view_modes_menu (GtkWidget *window,
2309                                         GimvImageView *iv,
2310                                         const gchar *path)
2311 {
2312    GtkWidget *menu;
2313    GList *node;
2314 
2315    menu = gtk_menu_new();
2316    iv->view_modes_menu = menu;
2317 
2318    for (node = gimv_image_view_plugin_get_list(); node; node = g_list_next (node)) {
2319       GtkWidget *menu_item;
2320       GimvImageViewPlugin *vftable = node->data;
2321 
2322       if (!vftable) continue;
2323 
2324       menu_item = gtk_menu_item_new_with_label (_(vftable->label));
2325       gtk_object_set_data (GTK_OBJECT (menu_item),
2326                            "GimvImageView::ViewMode",
2327                            (gpointer) vftable->label);
2328       gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
2329                           GTK_SIGNAL_FUNC (cb_change_view_mode), iv);
2330       gtk_menu_append (GTK_MENU (menu), menu_item);
2331       gtk_widget_show (menu_item);
2332    }
2333 
2334    gtk_signal_connect (GTK_OBJECT (menu), "destroy",
2335                        GTK_SIGNAL_FUNC (cb_view_modes_menu_destroy), iv);
2336 
2337    return menu;
2338 }
2339 
2340 
2341 GtkWidget *
gimv_image_view_create_popup_menu(GtkWidget * window,GimvImageView * iv,const gchar * path)2342 gimv_image_view_create_popup_menu (GtkWidget *window,
2343                                    GimvImageView *iv,
2344                                    const gchar *path)
2345 {
2346    guint n_menu_items;
2347 
2348    g_return_val_if_fail (window, NULL);
2349    g_return_val_if_fail (iv, NULL);
2350    g_return_val_if_fail (path && *path, NULL);
2351 
2352    n_menu_items = sizeof(gimv_image_view_popup_items)
2353       / sizeof(gimv_image_view_popup_items[0]) - 1;
2354    iv->imageview_popup = menu_create_items(window, gimv_image_view_popup_items,
2355                                            n_menu_items, path, iv);
2356 
2357    gimv_image_view_create_zoom_menu (window, iv, path);
2358    gimv_image_view_create_rotate_menu (window, iv, path);
2359 
2360    menu_set_submenu (iv->imageview_popup, "/Zoom",   iv->zoom_menu);
2361    menu_set_submenu (iv->imageview_popup, "/Rotate", iv->rotate_menu);
2362 
2363    menu_check_item_set_active (iv->imageview_popup, "/Show Scrollbar",
2364                                iv->priv->show_scrollbar);
2365    menu_check_item_set_active (iv->imageview_popup, "/Memory Buffer",
2366                                iv->priv->buffer);
2367 
2368    gimv_image_view_create_movie_menu (window, iv, path);
2369    menu_set_submenu (iv->imageview_popup, "/Movie",  iv->movie_menu);
2370 
2371    gimv_image_view_create_view_modes_menu (window, iv, path);
2372    menu_set_submenu (iv->imageview_popup, "/View modes",  iv->view_modes_menu);
2373 
2374    return iv->imageview_popup;
2375 }
2376 
2377 
2378 void
gimv_image_view_popup_menu(GimvImageView * iv,GdkEventButton * event)2379 gimv_image_view_popup_menu (GimvImageView *iv, GdkEventButton *event)
2380 {
2381    guint button;
2382    guint32 time;
2383    GtkMenuPositionFunc pos_fn = NULL;
2384 
2385    g_return_if_fail (iv);
2386    /* g_return_if_fail (event); */
2387 
2388    if (event) {
2389       button = event->button;
2390       time = gdk_event_get_time ((GdkEvent *) event);
2391    } else {
2392       button = 0;
2393       time = GDK_CURRENT_TIME;
2394       pos_fn = menu_calc_popup_position;
2395    }
2396 
2397    if (iv->imageview_popup)
2398       gtk_menu_popup (GTK_MENU (iv->imageview_popup),
2399                       NULL, NULL,
2400                       pos_fn, iv->draw_area->window,
2401                       button, time);
2402 }
2403 
2404 
2405 void
gimv_image_view_set_bg_color(GimvImageView * iv,gint red,gint green,gint brue)2406 gimv_image_view_set_bg_color (GimvImageView *iv, gint red, gint green, gint brue)
2407 {
2408    g_return_if_fail (iv);
2409    g_return_if_fail (iv->draw_area);
2410 
2411    if (!iv->bg_color) {
2412       iv->bg_color = g_new0 (GdkColor, 1);
2413       iv->bg_color->pixel = 0;
2414    }
2415    iv->bg_color->red   = red;
2416    iv->bg_color->green = green;
2417    iv->bg_color->blue  = brue;
2418 
2419    if (GTK_WIDGET_MAPPED (iv->draw_area)) {
2420       GdkColormap *colormap;
2421       GtkStyle *style;
2422       colormap = gdk_window_get_colormap(iv->draw_area->window);
2423       gdk_colormap_alloc_color (colormap, iv->bg_color, FALSE, TRUE);
2424       style = gtk_style_copy (gtk_widget_get_style (iv->draw_area));
2425       style->bg[GTK_STATE_NORMAL] = *iv->bg_color;
2426       gtk_widget_set_style (iv->draw_area, style);
2427       gtk_style_unref (style);
2428    }
2429 }
2430 
2431 
2432 void
gimv_image_view_show_scrollbar(GimvImageView * iv)2433 gimv_image_view_show_scrollbar (GimvImageView *iv)
2434 {
2435    g_return_if_fail (iv);
2436    g_return_if_fail (iv->hscrollbar);
2437    g_return_if_fail (iv->vscrollbar);
2438 
2439    gtk_widget_show (iv->hscrollbar);
2440    gtk_widget_show (iv->vscrollbar);
2441    gtk_widget_show (iv->nav_button);
2442 
2443    iv->priv->show_scrollbar = TRUE;
2444 }
2445 
2446 
2447 void
gimv_image_view_hide_scrollbar(GimvImageView * iv)2448 gimv_image_view_hide_scrollbar (GimvImageView *iv)
2449 {
2450    g_return_if_fail (iv);
2451    g_return_if_fail (iv->hscrollbar);
2452    g_return_if_fail (iv->vscrollbar);
2453 
2454    gtk_widget_hide (iv->hscrollbar);
2455    gtk_widget_hide (iv->vscrollbar);
2456    gtk_widget_hide (iv->nav_button);
2457 
2458    iv->priv->show_scrollbar = FALSE;
2459 }
2460 
2461 
2462 void
gimv_image_view_set_progressbar(GimvImageView * iv,GtkWidget * progressbar)2463 gimv_image_view_set_progressbar (GimvImageView *iv, GtkWidget *progressbar)
2464 {
2465    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
2466 
2467    iv->progressbar = progressbar;
2468 }
2469 
2470 
2471 void
gimv_image_view_set_player_visible(GimvImageView * iv,GimvImageViewPlayerVisibleType type)2472 gimv_image_view_set_player_visible (GimvImageView *iv,
2473                                     GimvImageViewPlayerVisibleType type)
2474 {
2475    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
2476 
2477    switch (type) {
2478    case GimvImageViewPlayerVisibleHide:
2479       gtk_widget_hide (iv->player_container);
2480       iv->priv->player_visible = GimvImageViewPlayerVisibleHide;
2481       break;
2482    case GimvImageViewPlayerVisibleShow:
2483       gtk_widget_show (iv->player_container);
2484       iv->priv->player_visible = GimvImageViewPlayerVisibleShow;
2485       break;
2486    case GimvImageViewPlayerVisibleAuto:
2487    default:
2488       if (gimv_image_view_is_playable (iv)) {
2489          gtk_widget_show (iv->player_container);
2490       } else {
2491          gtk_widget_hide (iv->player_container);
2492       }
2493       iv->priv->player_visible = GimvImageViewPlayerVisibleAuto;
2494       break;
2495    }
2496 }
2497 
2498 
2499 GimvImageViewPlayerVisibleType
gimv_image_view_get_player_visible(GimvImageView * iv)2500 gimv_image_view_get_player_visible (GimvImageView *iv)
2501 {
2502    g_return_val_if_fail (GIMV_IS_IMAGE_VIEW (iv), 0);
2503    return iv->priv->player_visible;
2504 }
2505 
2506 
2507 static gboolean
cb_navwin_button_release(GtkWidget * widget,GdkEventButton * event,GimvImageView * iv)2508 cb_navwin_button_release  (GtkWidget *widget,
2509                            GdkEventButton *event,
2510                            GimvImageView *iv)
2511 {
2512    GimvNavWin *navwin;
2513    GimvImageViewZoomType zoom_type = -1;
2514 
2515    g_return_val_if_fail (GIMV_IS_NAV_WIN (widget), FALSE);
2516    g_return_val_if_fail (GIMV_IS_IMAGE_VIEW (iv), FALSE);
2517 
2518    navwin = GIMV_NAV_WIN (widget);
2519 
2520    switch (event->button) {
2521    case 4:
2522       zoom_type = GIMV_IMAGE_VIEW_ZOOM_OUT;
2523       break;
2524    case 5:
2525       zoom_type = GIMV_IMAGE_VIEW_ZOOM_IN;
2526       break;
2527    default:
2528       break;
2529    }
2530 
2531    if (zoom_type >= 0) {
2532       gint vx, vy;
2533 
2534       gtk_signal_handler_block_by_func (GTK_OBJECT(widget),
2535                                         GTK_SIGNAL_FUNC (cb_navwin_button_release),
2536                                         iv);
2537       gimv_image_view_zoom_image (iv, zoom_type, 0, 0);
2538       gtk_signal_handler_unblock_by_func (GTK_OBJECT(widget),
2539                                           GTK_SIGNAL_FUNC (cb_navwin_button_release),
2540                                           iv);
2541 
2542       gimv_nav_win_set_orig_image_size (navwin,
2543                                         iv->priv->width,
2544                                         iv->priv->height);
2545       gimv_image_view_get_view_position (iv, &vx, &vy);
2546       gimv_nav_win_set_view_position (navwin, vx, vy);
2547    }
2548 
2549    return FALSE;
2550 }
2551 
2552 
2553 #define ZOOM_KEY_NUM 12
2554 
2555 static void
zoom_key_parse(guint keys[ZOOM_KEY_NUM],GdkModifierType mods[ZOOM_KEY_NUM])2556 zoom_key_parse (guint keys[ZOOM_KEY_NUM], GdkModifierType mods[ZOOM_KEY_NUM])
2557 {
2558    gchar **keyconfs[ZOOM_KEY_NUM] = {
2559       &akey.imgwin_zoomin,
2560       &akey.imgwin_zoomout,
2561       &akey.imgwin_fit_img,
2562       &akey.imgwin_zoom10,
2563       &akey.imgwin_zoom25,
2564       &akey.imgwin_zoom50,
2565       &akey.imgwin_zoom75,
2566       &akey.imgwin_zoom100,
2567       &akey.imgwin_zoom125,
2568       &akey.imgwin_zoom150,
2569       &akey.imgwin_zoom175,
2570       &akey.imgwin_zoom200,
2571    };
2572    gint i;
2573 
2574    if (!keys) return;
2575    if (!mods) return;
2576 
2577    for (i = 0; i < ZOOM_KEY_NUM; i++) {
2578       gchar *keyconf;
2579 
2580       keys[i] = mods[i] = 0;
2581       if (!keyconfs[i] || !*keyconfs[i] || !**keyconfs[i]) continue;
2582       keyconf = *keyconfs[i];
2583 
2584       gtk_accelerator_parse (keyconf, &keys[i], &mods[i]);
2585    }
2586 }
2587 
2588 
2589 static gboolean
cb_navwin_key_press(GtkWidget * widget,GdkEventKey * event,GimvImageView * iv)2590 cb_navwin_key_press (GtkWidget *widget,
2591                      GdkEventKey *event,
2592                      GimvImageView *iv)
2593 {
2594    GimvNavWin *navwin;
2595    GimvImageViewZoomType zoom_type = -1;
2596    guint zoom_key[ZOOM_KEY_NUM], keyval;
2597    GdkModifierType zoom_mod[ZOOM_KEY_NUM], modval;
2598 
2599    g_return_val_if_fail (GIMV_IS_NAV_WIN (widget), FALSE);
2600    g_return_val_if_fail (GIMV_IS_IMAGE_VIEW (iv), FALSE);
2601 
2602    navwin = GIMV_NAV_WIN (widget);
2603 
2604    keyval = event->keyval;
2605    modval = event->state;
2606 
2607    zoom_key_parse (zoom_key, zoom_mod);
2608 
2609    if (keyval == GDK_equal
2610               || (keyval == zoom_key[0] && (!zoom_mod[0] || (modval & zoom_mod[0]))))
2611    {
2612       zoom_type = GIMV_IMAGE_VIEW_ZOOM_IN;
2613    } else if (event->keyval == GDK_minus
2614               || (keyval == zoom_key[1] && (!zoom_mod[1] || (modval & zoom_mod[1]))))
2615    {
2616       zoom_type = GIMV_IMAGE_VIEW_ZOOM_OUT;
2617    } else if (keyval == zoom_key[3] && (!zoom_mod[3] || (modval & zoom_mod[3]))) {
2618       zoom_type = GIMV_IMAGE_VIEW_ZOOM_10;
2619    } else if (keyval == zoom_key[4] && (!zoom_mod[4] || (modval & zoom_mod[4]))) {
2620       zoom_type = GIMV_IMAGE_VIEW_ZOOM_25;
2621    } else if (keyval == zoom_key[5] && (!zoom_mod[5] || (modval & zoom_mod[5]))) {
2622       zoom_type = GIMV_IMAGE_VIEW_ZOOM_50;
2623    } else if (keyval == zoom_key[6] && (!zoom_mod[6] || (modval & zoom_mod[6]))) {
2624       zoom_type = GIMV_IMAGE_VIEW_ZOOM_75;
2625    } else if (keyval == zoom_key[7] && (!zoom_mod[7] || (modval & zoom_mod[7]))) {
2626       zoom_type = GIMV_IMAGE_VIEW_ZOOM_100;
2627    } else if (keyval == zoom_key[8] && (!zoom_mod[8] || (modval & zoom_mod[8]))) {
2628       zoom_type = GIMV_IMAGE_VIEW_ZOOM_125;
2629    } else if (keyval == zoom_key[9] && (!zoom_mod[9] || (modval & zoom_mod[9]))) {
2630       zoom_type = GIMV_IMAGE_VIEW_ZOOM_150;
2631    } else if (keyval == zoom_key[10] && (!zoom_mod[10] || (modval & zoom_mod[10]))) {
2632       zoom_type = GIMV_IMAGE_VIEW_ZOOM_175;
2633    } else if (keyval == zoom_key[11] && (!zoom_mod[11] || (modval & zoom_mod[11]))) {
2634       zoom_type = GIMV_IMAGE_VIEW_ZOOM_200;
2635    }
2636 
2637    if (zoom_type >= 0) {
2638       gint vx, vy;
2639 
2640       gtk_signal_handler_block_by_func (GTK_OBJECT(widget),
2641                                         GTK_SIGNAL_FUNC (cb_navwin_key_press),
2642                                         iv);
2643       gimv_image_view_zoom_image (iv, zoom_type, 0, 0);
2644       gtk_signal_handler_unblock_by_func (GTK_OBJECT(widget),
2645                                           GTK_SIGNAL_FUNC (cb_navwin_key_press),
2646                                           iv);
2647 
2648       gimv_nav_win_set_orig_image_size (navwin,
2649                                         iv->priv->width,
2650                                         iv->priv->height);
2651       gimv_image_view_get_view_position (iv, &vx, &vy);
2652       gimv_nav_win_set_view_position (navwin, vx, vy);
2653    }
2654 
2655    return FALSE;
2656 }
2657 
2658 
2659 static void
cb_navwin_move(GimvNavWin * navwin,gint x,gint y,GimvImageView * iv)2660 cb_navwin_move (GimvNavWin *navwin, gint x, gint y, GimvImageView *iv)
2661 {
2662    g_return_if_fail (GIMV_IS_NAV_WIN (navwin));
2663    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
2664 
2665    gimv_image_view_moveto (iv, x, y);
2666 }
2667 
2668 
2669 void
gimv_image_view_open_navwin(GimvImageView * iv,gint x_root,gint y_root)2670 gimv_image_view_open_navwin (GimvImageView *iv, gint x_root, gint y_root)
2671 {
2672    GtkWidget *navwin;
2673    GimvImage *image;
2674    GdkPixmap *pixmap;
2675    GdkBitmap *mask;
2676    gint src_width, src_height, dest_width, dest_height;
2677    gint fwidth, fheight;
2678    gint fpos_x, fpos_y;
2679 
2680    g_return_if_fail (iv);
2681    if (!iv->priv->pixmap) return;
2682 
2683    /* get pixmap for navigator */
2684    gdk_window_get_size (iv->priv->pixmap, &src_width, &src_height);
2685    image = gimv_image_create_from_drawable (iv->priv->pixmap, 0, 0,
2686                                             src_width, src_height);
2687    g_return_if_fail (image);
2688 
2689    if (src_width > src_height) {
2690       dest_width  = GIMV_NAV_WIN_SIZE;
2691       dest_height = src_height * GIMV_NAV_WIN_SIZE / src_width;
2692    } else {
2693       dest_height = GIMV_NAV_WIN_SIZE;
2694       dest_width  = src_width * GIMV_NAV_WIN_SIZE / src_height;
2695    }
2696 
2697    gimv_image_scale_get_pixmap (image, dest_width, dest_height,
2698                                 &pixmap, &mask);
2699    if (!pixmap) goto ERROR;
2700 
2701    gimv_image_view_get_image_frame_size (iv, &fwidth, &fheight);
2702    gimv_image_view_get_view_position (iv, &fpos_x, &fpos_y);
2703 
2704    /* open navigate window */
2705    if (iv->priv->navwin) {
2706       navwin = iv->priv->navwin;
2707       gimv_nav_win_set_pixmap (GIMV_NAV_WIN (navwin), pixmap, mask,
2708                                iv->priv->width, iv->priv->height);
2709       gimv_nav_win_set_view_size (GIMV_NAV_WIN (navwin), fwidth, fheight);
2710       gimv_nav_win_set_view_position (GIMV_NAV_WIN (navwin), fpos_x, fpos_y);
2711       gimv_nav_win_show (GIMV_NAV_WIN (navwin), x_root, y_root);
2712    } else {
2713       navwin = gimv_nav_win_new (pixmap, mask,
2714                                  iv->priv->width, iv->priv->height,
2715                                  fwidth, fheight,
2716                                  fpos_x, fpos_y);
2717       gtk_signal_connect (GTK_OBJECT (navwin), "button_release_event",
2718                           GTK_SIGNAL_FUNC (cb_navwin_button_release), iv);
2719       gtk_signal_connect (GTK_OBJECT (navwin), "key-press-event",
2720                           GTK_SIGNAL_FUNC(cb_navwin_key_press), iv);
2721       gtk_signal_connect (GTK_OBJECT (navwin), "move",
2722                           GTK_SIGNAL_FUNC (cb_navwin_move), iv);
2723       gimv_nav_win_show (GIMV_NAV_WIN (navwin), x_root, y_root);
2724       iv->priv->navwin = navwin;
2725    }
2726 
2727    /* free */
2728    gdk_pixmap_unref (pixmap);
2729 
2730 ERROR:
2731    gimv_image_unref (image);
2732 }
2733 
2734 
2735 void
gimv_image_view_set_fullscreen(GimvImageView * iv,GtkWindow * fullscreen)2736 gimv_image_view_set_fullscreen (GimvImageView *iv, GtkWindow *fullscreen)
2737 {
2738    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
2739    g_return_if_fail (GTK_IS_WINDOW (fullscreen));
2740 
2741    if (iv->priv->fullscreen) return;
2742    iv->priv->fullscreen = fullscreen;
2743    gtk_widget_reparent (iv->draw_area, GTK_WIDGET (iv->priv->fullscreen));
2744 }
2745 
2746 
2747 void
gimv_image_view_unset_fullscreen(GimvImageView * iv)2748 gimv_image_view_unset_fullscreen (GimvImageView *iv)
2749 {
2750    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
2751 
2752    if (!iv->priv->fullscreen) return;
2753 
2754    gtk_widget_reparent (iv->draw_area, iv->table);
2755    iv->priv->fullscreen = NULL;
2756 }
2757 
2758 
2759 
2760 /*****************************************************************************
2761  *
2762  *  loading functions
2763  *
2764  *****************************************************************************/
2765 void
gimv_image_view_free_image_buf(GimvImageView * iv)2766 gimv_image_view_free_image_buf (GimvImageView *iv)
2767 {
2768    if (!iv)
2769       return;
2770 
2771    if (!iv->image) return;
2772    if (iv->priv->buffer) return;
2773 
2774 #warning FIXME!!
2775    if (gimv_image_info_is_animation (iv->info)
2776        || gimv_image_info_is_movie (iv->info)
2777        || gimv_image_info_is_audio (iv->info))
2778    {
2779       return;
2780    }
2781 
2782    gimv_image_unref (iv->image);
2783    iv->image = NULL;
2784 }
2785 static gint
progress_timeout(gpointer data)2786 progress_timeout (gpointer data)
2787 {
2788    gfloat new_val;
2789    GtkAdjustment *adj;
2790 
2791    adj = GTK_PROGRESS (data)->adjustment;
2792 
2793    new_val = adj->value + 1;
2794    if (new_val > adj->upper)
2795       new_val = adj->lower;
2796 
2797    gtk_progress_set_value (GTK_PROGRESS (data), new_val);
2798 
2799    return (TRUE);
2800 }
2801 
2802 
2803 static void
cb_loader_progress_update(GimvImageLoader * loader,GimvImageView * iv)2804 cb_loader_progress_update (GimvImageLoader *loader, GimvImageView *iv)
2805 {
2806    while (gtk_events_pending()) gtk_main_iteration();
2807 }
2808 
2809 
2810 static void
cb_loader_load_end(GimvImageLoader * loader,GimvImageView * iv)2811 cb_loader_load_end (GimvImageLoader *loader, GimvImageView *iv)
2812 {
2813    GimvImage *image, *rgb_image;
2814 
2815    g_return_if_fail (GIMV_IS_IMAGE_LOADER (loader));
2816    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
2817 
2818    image = gimv_image_loader_get_image (loader);
2819    if (!image) goto ERROR;
2820    gimv_image_ref (image);
2821    gimv_image_loader_unref_image (loader);
2822 
2823    /* FIXME */
2824    if (gimv_image_has_alpha (image) && !GIMV_IS_ANIM (image)) {
2825       gint bg_r = 255, bg_g = 255, bg_b = 255;
2826       GtkStyle *style;
2827 
2828       style = gtk_widget_get_style (iv->draw_area);
2829       bg_r = style->bg[GTK_STATE_NORMAL].red   / 256;
2830       bg_g = style->bg[GTK_STATE_NORMAL].green / 256;
2831       bg_b = style->bg[GTK_STATE_NORMAL].blue  / 256;
2832 
2833       rgb_image = gimv_image_rgba2rgb (image,
2834                                        bg_r, bg_g, bg_b,
2835                                        iv->priv->ignore_alpha);
2836       if (rgb_image) {
2837          gimv_image_unref (image);
2838          image = rgb_image;
2839       }
2840    }
2841 
2842    if (!g_list_find (GimvImageViewList, iv)) {
2843       gimv_image_unref (image);
2844       goto ERROR;
2845    } else {
2846       if (iv->image)
2847          gimv_image_unref (iv->image);
2848       iv->image = image;
2849    }
2850 
2851    gimv_image_view_rotate_render (iv, iv->priv->rotate);
2852 
2853 ERROR:
2854    gtk_signal_disconnect_by_func (GTK_OBJECT (iv->loader),
2855                                   GTK_SIGNAL_FUNC (cb_loader_progress_update),
2856                                   iv);
2857    gtk_signal_disconnect_by_func (GTK_OBJECT (iv->loader),
2858                                   GTK_SIGNAL_FUNC (cb_loader_load_end),
2859                                   iv);
2860 
2861    iv->priv->loader_progress_update_signal_id = 0;
2862    iv->priv->loader_load_end_signal_id        = 0;
2863 
2864    gtk_signal_emit (GTK_OBJECT(iv),
2865                     gimv_image_view_signals[LOAD_END_SIGNAL],
2866                     iv->info, FALSE);
2867 }
2868 
2869 
2870 static gboolean
gimv_image_view_need_load(GimvImageView * iv)2871 gimv_image_view_need_load (GimvImageView *iv)
2872 {
2873    gint width, height;
2874 
2875    if (!iv->image) return TRUE;
2876 
2877 #if IMAGE_VIEW_ENABLE_SCALABLE_LOAD
2878 
2879    if (iv->priv->rotate == 0 || iv->priv->rotate == 2) {
2880       width  = gimv_image_width (iv->image);
2881       height = gimv_image_height (iv->image);
2882    } else {
2883       width  = gimv_image_height (iv->image);
2884       height = gimv_image_width  (iv->image);
2885    }
2886 
2887    if ( width == iv->info->width
2888        &&  height == iv->info->height)
2889    {
2890       /* full scale image was already loaded */
2891       return FALSE;
2892 
2893    } else {
2894       gint req_width, req_height;
2895 
2896       gimv_image_view_get_request_size (iv, &req_width, &req_height);
2897 
2898       if (req_width >= 0 && req_height >= 0
2899           && width  >= req_width
2900           && height >= req_height)
2901       {
2902          /* the image is bigger than request size */
2903          return FALSE;
2904       }
2905    }
2906 
2907    return TRUE;
2908 
2909 #endif /* IMAGE_VIEW_ENABLE_SCALABLE_LOAD */
2910 
2911    return FALSE;
2912 }
2913 
2914 
2915 static void
gimv_image_view_load_image_buf_start(GimvImageView * iv)2916 gimv_image_view_load_image_buf_start (GimvImageView *iv)
2917 {
2918    const gchar *filename;
2919    gint req_width, req_height;
2920 
2921    g_return_if_fail (iv);
2922 
2923    if (!iv->info) return;
2924    if (!g_list_find (GimvImageViewList, iv)) return;
2925 
2926    if (!gimv_image_view_need_load (iv)) return;
2927 
2928 #warning FIXME!!
2929    if (gimv_image_info_is_archive (iv->info)
2930        || gimv_image_info_is_movie (iv->info)
2931        || gimv_image_info_is_audio (iv->info))
2932    {
2933       return;
2934    }
2935 
2936    filename = gimv_image_info_get_path (iv->info);
2937    if (!filename || !*filename) return;
2938 
2939    gtk_signal_emit (GTK_OBJECT(iv),
2940                     gimv_image_view_signals[LOAD_START_SIGNAL],
2941                     iv->info);
2942 
2943    if (gimv_image_info_is_in_archive (iv->info)) {
2944       guint timer = 0;
2945 
2946       /* set progress bar */
2947       if (iv->progressbar) {
2948          gtk_progress_set_activity_mode (GTK_PROGRESS (iv->progressbar), TRUE);
2949          timer = gtk_timeout_add (50,
2950                                   (GtkFunction) progress_timeout,
2951                                   iv->progressbar);
2952          gtk_grab_add (iv->progressbar);
2953       }
2954 
2955       /* extract */
2956       gimv_image_info_extract_archive (iv->info);
2957 
2958       /* unset progress bar */
2959       if (iv->progressbar) {
2960          gtk_timeout_remove (timer);
2961          gtk_progress_set_activity_mode (GTK_PROGRESS (iv->progressbar), FALSE);
2962          gtk_progress_bar_update (GTK_PROGRESS_BAR(iv->progressbar), 0.0);
2963          gtk_grab_remove (iv->progressbar);
2964       }
2965    }
2966 
2967    /* load image buf */
2968    /* iv->loader->flags |= GIMV_IMAGE_LOADER_DEBUG_FLAG; */
2969    if (iv->priv->loader_progress_update_signal_id)
2970       gtk_signal_disconnect (GTK_OBJECT (iv->loader),
2971                              iv->priv->loader_progress_update_signal_id);
2972    iv->priv->loader_progress_update_signal_id =
2973       gtk_signal_connect (GTK_OBJECT (iv->loader), "progress_update",
2974                           GTK_SIGNAL_FUNC (cb_loader_progress_update),
2975                              iv);
2976    if (iv->priv->loader_load_end_signal_id)
2977       gtk_signal_disconnect (GTK_OBJECT (iv->loader),
2978                              iv->priv->loader_load_end_signal_id);
2979    iv->priv->loader_load_end_signal_id =
2980       gtk_signal_connect (GTK_OBJECT (iv->loader), "load_end",
2981                           GTK_SIGNAL_FUNC (cb_loader_load_end),
2982                           iv);
2983 
2984    gimv_image_loader_set_image_info (iv->loader, iv->info);
2985    gimv_image_loader_set_as_animation (iv->loader, TRUE);
2986 
2987 #if IMAGE_VIEW_ENABLE_SCALABLE_LOAD
2988    gimv_image_view_get_request_size (iv, &req_width, &req_height);
2989    gimv_image_loader_set_size_request (iv->loader, req_width, req_height, TRUE);
2990 #endif
2991 
2992    gimv_image_loader_load_start (iv->loader);
2993 }
2994 
2995 
2996 static void
cb_loader_load_restart(GimvImageLoader * loader,GimvImageView * iv)2997 cb_loader_load_restart (GimvImageLoader *loader, GimvImageView *iv)
2998 {
2999    if (iv->priv->loader_load_end_signal_id)
3000       gtk_signal_disconnect (GTK_OBJECT (iv->loader),
3001                              iv->priv->loader_load_end_signal_id);
3002    iv->priv->loader_load_end_signal_id = 0;
3003    gimv_image_view_load_image_buf_start (iv);
3004 }
3005 
3006 
3007 void
gimv_image_view_load_image_buf(GimvImageView * iv)3008 gimv_image_view_load_image_buf (GimvImageView *iv)
3009 {
3010    if (gimv_image_loader_is_loading (iv->loader)) {
3011       if (iv->info == iv->loader->info) return;
3012 
3013       gimv_image_view_cancel_loading (iv);
3014 
3015       iv->priv->loader_load_end_signal_id
3016          = gtk_signal_connect (GTK_OBJECT (iv->loader), "load_end",
3017                                GTK_SIGNAL_FUNC (cb_loader_load_restart),
3018                                iv);
3019    } else {
3020       gimv_image_view_load_image_buf_start (iv);
3021    }
3022 }
3023 
3024 
3025 gboolean
gimv_image_view_is_loading(GimvImageView * iv)3026 gimv_image_view_is_loading (GimvImageView *iv)
3027 {
3028    g_return_val_if_fail (GIMV_IS_IMAGE_VIEW (iv), FALSE);
3029    g_return_val_if_fail (iv->loader, FALSE);
3030 
3031    return gimv_image_loader_is_loading (iv->loader);
3032 }
3033 
3034 
3035 void
gimv_image_view_cancel_loading(GimvImageView * iv)3036 gimv_image_view_cancel_loading (GimvImageView *iv)
3037 {
3038    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
3039 
3040    if (!gimv_image_loader_is_loading (iv->loader)) return;
3041 
3042    gimv_image_loader_load_stop (iv->loader);
3043 
3044    if (iv->priv->loader_progress_update_signal_id)
3045       gtk_signal_disconnect (GTK_OBJECT (iv->loader),
3046                              iv->priv->loader_progress_update_signal_id);
3047    iv->priv->loader_progress_update_signal_id = 0;
3048 
3049    if (iv->priv->loader_load_end_signal_id)
3050       gtk_signal_disconnect (GTK_OBJECT (iv->loader),
3051                              iv->priv->loader_load_end_signal_id);
3052    iv->priv->loader_load_end_signal_id = 0;
3053 
3054    /*
3055    gtk_signal_emit (GTK_OBJECT(iv),
3056                     gimv_image_view_signals[LOAD_END_SIGNAL],
3057                     iv->info, TRUE);
3058    */
3059 }
3060 
3061 
3062 
3063 /*****************************************************************************
3064  *
3065  *   scalable interface functions
3066  *
3067  *****************************************************************************/
3068 void
gimv_image_view_zoom_image(GimvImageView * iv,GimvImageViewZoomType zoom,gfloat x_scale,gfloat y_scale)3069 gimv_image_view_zoom_image (GimvImageView *iv, GimvImageViewZoomType zoom,
3070                             gfloat x_scale, gfloat y_scale)
3071 {
3072    gint cx_pos, cy_pos, fwidth, fheight;
3073    gfloat src_x_scale, src_y_scale;
3074 
3075    g_return_if_fail (iv);
3076 
3077    src_x_scale = iv->priv->x_scale;
3078    src_y_scale = iv->priv->y_scale;
3079 
3080    iv->priv->fit_to_frame = 0;
3081 
3082    switch (zoom) {
3083    case GIMV_IMAGE_VIEW_ZOOM_IN:
3084       if (iv->priv->x_scale < GIMV_IMAGE_VIEW_MAX_SCALE
3085           && iv->priv->y_scale < GIMV_IMAGE_VIEW_MAX_SCALE)
3086       {
3087          iv->priv->x_scale = iv->priv->x_scale + GIMV_IMAGE_VIEW_MIN_SCALE;
3088          iv->priv->y_scale = iv->priv->y_scale + GIMV_IMAGE_VIEW_MIN_SCALE;
3089       }
3090       break;
3091    case GIMV_IMAGE_VIEW_ZOOM_OUT:
3092       if (iv->priv->x_scale > GIMV_IMAGE_VIEW_MIN_SCALE
3093           && iv->priv->y_scale > GIMV_IMAGE_VIEW_MIN_SCALE)
3094       {
3095          iv->priv->x_scale = iv->priv->x_scale - GIMV_IMAGE_VIEW_MIN_SCALE;
3096          iv->priv->y_scale = iv->priv->y_scale - GIMV_IMAGE_VIEW_MIN_SCALE;
3097       }
3098       break;
3099    case GIMV_IMAGE_VIEW_ZOOM_FIT:
3100    case GIMV_IMAGE_VIEW_ZOOM_FIT_ZOOM_OUT_ONLY:
3101    case GIMV_IMAGE_VIEW_ZOOM_FIT_WIDTH:
3102    case GIMV_IMAGE_VIEW_ZOOM_FIT_HEIGHT:
3103       iv->priv->fit_to_frame = zoom;
3104       break;
3105    case GIMV_IMAGE_VIEW_ZOOM_10:
3106       iv->priv->x_scale = iv->priv->y_scale =  10;
3107       break;
3108    case GIMV_IMAGE_VIEW_ZOOM_25:
3109       iv->priv->x_scale = iv->priv->y_scale =  25;
3110       break;
3111    case GIMV_IMAGE_VIEW_ZOOM_50:
3112       iv->priv->x_scale = iv->priv->y_scale =  50;
3113       break;
3114    case GIMV_IMAGE_VIEW_ZOOM_75:
3115       iv->priv->x_scale = iv->priv->y_scale =  75;
3116       break;
3117    case GIMV_IMAGE_VIEW_ZOOM_100:
3118       iv->priv->x_scale = iv->priv->y_scale = 100;
3119       break;
3120    case GIMV_IMAGE_VIEW_ZOOM_125:
3121       iv->priv->x_scale = iv->priv->y_scale = 125;
3122       break;
3123    case GIMV_IMAGE_VIEW_ZOOM_150:
3124       iv->priv->x_scale = iv->priv->y_scale = 150;
3125       break;
3126    case GIMV_IMAGE_VIEW_ZOOM_175:
3127       iv->priv->x_scale = iv->priv->y_scale = 175;
3128       break;
3129    case GIMV_IMAGE_VIEW_ZOOM_200:
3130       iv->priv->x_scale = iv->priv->y_scale = 200;
3131       break;
3132    case GIMV_IMAGE_VIEW_ZOOM_300:
3133       iv->priv->x_scale = iv->priv->y_scale = 300;
3134       break;
3135    case GIMV_IMAGE_VIEW_ZOOM_FREE:
3136       iv->priv->x_scale = x_scale;
3137       iv->priv->y_scale = y_scale;
3138       break;
3139    default:
3140       break;
3141    }
3142 
3143    gimv_image_view_get_image_frame_size (iv, &fwidth, &fheight);
3144 
3145    cx_pos = (iv->priv->x_pos - fwidth  / 2) * iv->priv->x_scale / src_x_scale;
3146    cy_pos = (iv->priv->y_pos - fheight / 2) * iv->priv->y_scale / src_y_scale;
3147 
3148    iv->priv->x_pos = cx_pos + fwidth  / 2;
3149    iv->priv->y_pos = cy_pos + fheight / 2;
3150 
3151    gimv_image_view_show_image (iv);
3152 }
3153 
3154 
3155 gboolean
gimv_image_view_get_image_size(GimvImageView * iv,gint * width,gint * height)3156 gimv_image_view_get_image_size (GimvImageView   *iv,
3157                                 gint        *width,
3158                                 gint        *height)
3159 {
3160    g_return_val_if_fail (GIMV_IS_IMAGE_VIEW (iv), FALSE);
3161 
3162    if (width)
3163       *width = iv->priv->width;
3164    if (height)
3165       *height = iv->priv->height;
3166 
3167    return TRUE;
3168 }
3169 
3170 
3171 static void
gimv_image_view_get_request_size(GimvImageView * iv,gint * width_ret,gint * height_ret)3172 gimv_image_view_get_request_size (GimvImageView *iv,
3173                                   gint *width_ret, gint *height_ret)
3174 {
3175    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
3176    g_return_if_fail (width_ret && height_ret);
3177 
3178    *width_ret  = -1;
3179    *height_ret = -1;
3180 
3181    if (iv->priv->fit_to_frame) {
3182       gint fwidth, fheight;
3183 
3184       gimv_image_view_get_image_frame_size (iv, &fwidth, &fheight);
3185 
3186       if (iv->priv->rotate == 0 || iv->priv->rotate == 2) {
3187          *width_ret  = fwidth;
3188          *height_ret = fheight;
3189       } else {
3190          *width_ret  = fheight;
3191          *height_ret = fwidth;
3192       }
3193 
3194       return;
3195 
3196    } else if (iv->priv->width > MIN_IMAGE_WIDTH && iv->priv->height > MIN_IMAGE_HEIGHT) {
3197       *width_ret  = iv->info->width  * iv->priv->x_scale / 100.0;
3198       *height_ret = iv->info->height * iv->priv->y_scale / 100.0;
3199       return;
3200    } else {
3201       /*
3202        * the image was changed, so the image size may be unknown yet.
3203        * (iv->info will know it, but (currently) we don't trust it yet. )
3204        */
3205    }
3206 }
3207 
3208 
3209 
3210 /*****************************************************************************
3211  *
3212  *   rotatable interface functions
3213  *
3214  *****************************************************************************/
3215 static void
gimv_image_view_rotate_render(GimvImageView * iv,GimvImageViewOrientation angle)3216 gimv_image_view_rotate_render (GimvImageView *iv,
3217                                GimvImageViewOrientation angle)
3218 {
3219    switch (angle) {
3220    case GIMV_IMAGE_VIEW_ROTATE_90:
3221       iv->image = gimv_image_rotate_90 (iv->image, TRUE);
3222       break;
3223    case GIMV_IMAGE_VIEW_ROTATE_180:
3224       iv->image = gimv_image_rotate_180 (iv->image);
3225       break;
3226    case GIMV_IMAGE_VIEW_ROTATE_270:
3227       iv->image = gimv_image_rotate_90 (iv->image, FALSE);
3228       break;
3229    default:
3230       break;
3231    }
3232 }
3233 
3234 
3235 typedef struct RotateData_Tag {
3236    GimvImageViewOrientation angle;
3237 } RotateData;
3238 
3239 
3240 static void
cb_gimv_image_view_rotate_load_end(GimvImageView * iv,GimvImageInfo * info,gboolean cancel,gpointer user_data)3241 cb_gimv_image_view_rotate_load_end (GimvImageView *iv, GimvImageInfo *info,
3242                                     gboolean cancel, gpointer user_data)
3243 {
3244    RotateData *data = user_data;
3245    GimvImageViewOrientation angle = data->angle, rotate_angle;
3246    gboolean can_draw;
3247    gchar *path, *cache;
3248 
3249    if (iv->priv->load_end_signal_id)
3250       gtk_signal_disconnect (GTK_OBJECT (iv), iv->priv->load_end_signal_id);
3251    iv->priv->load_end_signal_id = 0;
3252 
3253    if (cancel) return;
3254 
3255    can_draw = check_can_draw_image (iv);
3256    if (!can_draw) goto func_end;
3257 
3258    /* rotate image */
3259    rotate_angle = (angle - iv->priv->rotate) % 4;
3260    if (rotate_angle < 0)
3261       rotate_angle = rotate_angle + 4;
3262 
3263    iv->priv->rotate = angle;
3264    gimv_image_view_rotate_render (iv, rotate_angle);
3265 
3266    /* set image size */
3267    gimv_image_view_calc_image_size (iv);
3268 
3269    /* image rendering */
3270    gimv_image_free_pixmap_and_mask (iv->priv->pixmap, iv->priv->mask);
3271    gimv_image_scale_get_pixmap (iv->image,
3272                                 iv->priv->width, iv->priv->height,
3273                                 &iv->priv->pixmap, &iv->priv->mask);
3274 
3275    /* reset image geometory */
3276    gimv_image_view_adjust_pos_in_frame (iv, TRUE);
3277 
3278    /* draw image */
3279    gimv_image_view_draw_image (iv);
3280 
3281    /* create thumbnail if not exist */
3282    path  = gimv_image_info_get_path_with_archive (iv->info);
3283    cache = gimv_thumb_find_thumbcache(path, NULL);
3284    if (path && *path && !cache) {
3285       gimv_image_view_create_thumbnail (iv);
3286    }
3287    g_free (path);
3288    g_free (cache);
3289    path  = NULL;
3290    cache = NULL;
3291 
3292    gimv_image_view_free_image_buf (iv);
3293 
3294 func_end:
3295    if (iv->priv->load_end_signal_id)
3296       gtk_signal_disconnect (GTK_OBJECT (iv), iv->priv->load_end_signal_id);
3297    iv->priv->load_end_signal_id = 0;
3298 
3299    gtk_signal_emit (GTK_OBJECT(iv), gimv_image_view_signals[RENDERED_SIGNAL]);
3300 }
3301 
3302 
3303 void
gimv_image_view_rotate_image(GimvImageView * iv,GimvImageViewOrientation angle)3304 gimv_image_view_rotate_image (GimvImageView *iv, GimvImageViewOrientation angle)
3305 {
3306    RotateData *data;
3307 
3308    if (iv->priv->load_end_signal_id)
3309       gtk_signal_disconnect (GTK_OBJECT (iv), iv->priv->load_end_signal_id);
3310 
3311    data = g_new0 (RotateData, 1);
3312    data->angle = angle;
3313 
3314    if (gimv_image_view_need_load (iv)) {
3315       iv->priv->load_end_signal_id
3316          = gtk_signal_connect_full (GTK_OBJECT (iv), "load_end",
3317                                     GTK_SIGNAL_FUNC (cb_gimv_image_view_rotate_load_end),
3318                                     NULL,
3319                                     data, (GtkDestroyNotify) g_free,
3320                                     FALSE, FALSE);
3321 
3322       gimv_image_view_load_image_buf (iv);
3323    } else {
3324       cb_gimv_image_view_rotate_load_end (iv, iv->info, FALSE, data);
3325       g_free (data);
3326    }
3327 }
3328 
3329 
3330 void
gimv_image_view_rotate_ccw(GimvImageView * iv)3331 gimv_image_view_rotate_ccw (GimvImageView *iv)
3332 {
3333    guint angle;
3334 
3335    g_return_if_fail (iv);
3336 
3337    /* convert to absolute angle */
3338    angle = (iv->priv->rotate + 1) % 4;
3339 
3340    gimv_image_view_rotate_image (iv, angle);
3341 }
3342 
3343 
3344 void
gimv_image_view_rotate_cw(GimvImageView * iv)3345 gimv_image_view_rotate_cw (GimvImageView *iv)
3346 {
3347    guint angle;
3348 
3349    g_return_if_fail (iv);
3350 
3351    /* convert to absolute angle */
3352    angle = (iv->priv->rotate + 3) % 4;
3353 
3354    gimv_image_view_rotate_image (iv, angle);
3355 }
3356 
3357 
3358 GimvImageViewOrientation
gimv_image_view_get_orientation(GimvImageView * iv)3359 gimv_image_view_get_orientation (GimvImageView *iv)
3360 {
3361    g_return_val_if_fail (GIMV_IS_IMAGE_VIEW (iv), 0);
3362    return iv->priv->rotate;
3363 }
3364 
3365 
3366 
3367 /*****************************************************************************
3368  *
3369  *   scrollable interface functions
3370  *
3371  *****************************************************************************/
3372 void
gimv_image_view_get_image_frame_size(GimvImageView * iv,gint * width,gint * height)3373 gimv_image_view_get_image_frame_size (GimvImageView *iv, gint *width, gint *height)
3374 {
3375    g_return_if_fail (width && height);
3376 
3377    *width = *height = 0;
3378 
3379    g_return_if_fail (iv);
3380 
3381    if (iv->priv->fullscreen) {
3382       *width  = GTK_WIDGET(iv->priv->fullscreen)->allocation.width;
3383       *height = GTK_WIDGET(iv->priv->fullscreen)->allocation.height;
3384    } else {
3385       *width  = iv->draw_area->allocation.width;
3386       *height = iv->draw_area->allocation.height;
3387    }
3388 }
3389 
3390 
3391 gboolean
gimv_image_view_get_view_position(GimvImageView * iv,gint * x,gint * y)3392 gimv_image_view_get_view_position (GimvImageView *iv, gint *x, gint *y)
3393 {
3394    g_return_val_if_fail (iv, FALSE);
3395    g_return_val_if_fail (x && y, FALSE);
3396 
3397    *x = 0 - iv->priv->x_pos;
3398    *y = 0 - iv->priv->y_pos;
3399 
3400    return TRUE;
3401 }
3402 
3403 
3404 void
gimv_image_view_moveto(GimvImageView * iv,gint x,gint y)3405 gimv_image_view_moveto (GimvImageView *iv, gint x, gint y)
3406 {
3407    g_return_if_fail (iv);
3408 
3409    iv->priv->x_pos = 0 - x;
3410    iv->priv->y_pos = 0 - y;
3411 
3412    gimv_image_view_adjust_pos_in_frame (iv, TRUE);
3413 
3414    gimv_image_view_draw_image (iv);
3415 }
3416 
3417 
3418 void
gimv_image_view_reset_scrollbar(GimvImageView * iv)3419 gimv_image_view_reset_scrollbar (GimvImageView *iv)
3420 {
3421    g_return_if_fail (iv);
3422    g_return_if_fail (iv->draw_area);
3423    g_return_if_fail (iv->hadj);
3424    g_return_if_fail (iv->vadj);
3425 
3426    /* horizontal */
3427    if (iv->priv->x_pos < 0)
3428       iv->hadj->value = 0 - iv->priv->x_pos;
3429    else
3430       iv->hadj->value = 0;
3431 
3432    if (iv->priv->width > iv->draw_area->allocation.width)
3433       iv->hadj->upper = iv->priv->width;
3434    else
3435       iv->hadj->upper = iv->draw_area->allocation.width;
3436    iv->hadj->page_size = iv->draw_area->allocation.width;
3437 
3438    /* vertical */
3439    if (iv->priv->y_pos < 0)
3440       iv->vadj->value = 0 - iv->priv->y_pos;
3441    else
3442       iv->vadj->value = 0;
3443 
3444    if (iv->priv->height > iv->draw_area->allocation.height)
3445       iv->vadj->upper = iv->priv->height;
3446    else
3447       iv->vadj->upper = iv->draw_area->allocation.height;
3448    iv->vadj->page_size = iv->draw_area->allocation.height;
3449 
3450    move_scrollbar_by_user = FALSE;
3451 
3452    gtk_signal_emit_by_name (GTK_OBJECT(iv->hadj), "changed");
3453    gtk_signal_emit_by_name (GTK_OBJECT(iv->vadj), "changed");
3454 
3455    move_scrollbar_by_user = TRUE;
3456 }
3457 
3458 
3459 
3460 /*****************************************************************************
3461  *
3462  *   playable interface functions
3463  *
3464  *****************************************************************************/
3465 gboolean
gimv_image_view_is_playable(GimvImageView * iv)3466 gimv_image_view_is_playable (GimvImageView *iv)
3467 {
3468    GimvImageViewPlayableIF *playable;
3469 
3470    g_return_val_if_fail (GIMV_IS_IMAGE_VIEW (iv), FALSE);
3471 
3472    if (!iv->info) return FALSE;
3473    if (!iv->draw_area_funcs || !iv->draw_area_funcs->playable) return FALSE;
3474 
3475    playable = iv->draw_area_funcs->playable;
3476 
3477    if (!playable->is_playable_fn) return FALSE;
3478 
3479    return playable->is_playable_fn (iv, iv->info);
3480 }
3481 
3482 
3483 void
gimv_image_view_playable_play(GimvImageView * iv)3484 gimv_image_view_playable_play (GimvImageView *iv)
3485 {
3486    GimvImageViewPlayableIF *playable;
3487 
3488    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
3489 
3490    if (!iv->draw_area_funcs || !iv->draw_area_funcs->playable) return;
3491    playable = iv->draw_area_funcs->playable;
3492 
3493    if (gimv_image_view_is_playable (iv)) {
3494       g_return_if_fail (playable->play_fn);
3495       playable->play_fn (iv);
3496    }
3497 }
3498 
3499 
3500 void
gimv_image_view_playable_stop(GimvImageView * iv)3501 gimv_image_view_playable_stop (GimvImageView *iv)
3502 {
3503    GimvImageViewPlayableIF *playable;
3504 
3505    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
3506 
3507    if (!iv->draw_area_funcs || !iv->draw_area_funcs->playable) return;
3508 
3509    playable = iv->draw_area_funcs->playable;
3510 
3511    if (!playable->stop_fn) return;
3512    playable->stop_fn (iv);
3513 }
3514 
3515 
3516 void
gimv_image_view_playable_pause(GimvImageView * iv)3517 gimv_image_view_playable_pause (GimvImageView *iv)
3518 {
3519    GimvImageViewPlayableIF *playable;
3520 
3521    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
3522 
3523    if (!iv->draw_area_funcs || !iv->draw_area_funcs->playable) return;
3524 
3525    playable = iv->draw_area_funcs->playable;
3526 
3527    if (!playable->pause_fn) return;
3528    playable->pause_fn (iv);
3529 }
3530 
3531 
3532 void
gimv_image_view_playable_forward(GimvImageView * iv)3533 gimv_image_view_playable_forward (GimvImageView *iv)
3534 {
3535    GimvImageViewPlayableIF *playable;
3536 
3537    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
3538 
3539    if (!iv->draw_area_funcs || !iv->draw_area_funcs->playable) return;
3540 
3541    playable = iv->draw_area_funcs->playable;
3542 
3543    if (!playable->forward_fn) return;
3544    playable->forward_fn (iv);
3545 }
3546 
3547 
3548 void
gimv_image_view_playable_reverse(GimvImageView * iv)3549 gimv_image_view_playable_reverse (GimvImageView *iv)
3550 {
3551    GimvImageViewPlayableIF *playable;
3552 
3553    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
3554 
3555    if (!iv->draw_area_funcs || !iv->draw_area_funcs->playable) return;
3556 
3557    playable = iv->draw_area_funcs->playable;
3558 
3559    if (!playable->reverse_fn) return;
3560    playable->reverse_fn (iv);
3561 }
3562 
3563 
3564 void
gimv_image_view_playable_seek(GimvImageView * iv,guint pos)3565 gimv_image_view_playable_seek (GimvImageView *iv, guint pos)
3566 {
3567    GimvImageViewPlayableIF *playable;
3568 
3569    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
3570 
3571    if (!iv->draw_area_funcs || !iv->draw_area_funcs->playable) return;
3572 
3573    playable = iv->draw_area_funcs->playable;
3574 
3575    if (!playable->seek_fn) return;
3576    playable->seek_fn (iv, pos);
3577 }
3578 
3579 
3580 void
gimv_image_view_playable_eject(GimvImageView * iv)3581 gimv_image_view_playable_eject (GimvImageView *iv)
3582 {
3583    GimvImageViewPlayableIF *playable;
3584 
3585 
3586    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
3587 
3588    if (!iv->draw_area_funcs || !iv->draw_area_funcs->playable) return;
3589 
3590    playable = iv->draw_area_funcs->playable;
3591 
3592    if (!playable->eject_fn) return;
3593    playable->eject_fn (iv);
3594 }
3595 
3596 
3597 GimvImageViewPlayableStatus
gimv_image_view_playable_get_status(GimvImageView * iv)3598 gimv_image_view_playable_get_status (GimvImageView *iv)
3599 {
3600    GimvImageViewPlayableIF *playable;
3601 
3602    g_return_val_if_fail (GIMV_IS_IMAGE_VIEW (iv), GimvImageViewPlayableDisable);
3603 
3604    if (!iv->draw_area_funcs || !iv->draw_area_funcs->playable)
3605       return GimvImageViewPlayableDisable;
3606 
3607    playable = iv->draw_area_funcs->playable;
3608 
3609    if (!playable->get_status_fn) return GimvImageViewPlayableDisable;
3610    return playable->get_status_fn (iv);
3611 }
3612 
3613 
3614 guint
gimv_image_view_playable_get_length(GimvImageView * iv)3615 gimv_image_view_playable_get_length (GimvImageView *iv)
3616 {
3617    GimvImageViewPlayableIF *playable;
3618 
3619    g_return_val_if_fail (GIMV_IS_IMAGE_VIEW (iv), 0);
3620 
3621    if (!iv->draw_area_funcs || !iv->draw_area_funcs->playable) return 0;
3622 
3623    playable = iv->draw_area_funcs->playable;
3624 
3625    if (!playable->get_length_fn) return 0;
3626    return playable->get_length_fn (iv);
3627 }
3628 
3629 
3630 guint
gimv_image_view_playable_get_position(GimvImageView * iv)3631 gimv_image_view_playable_get_position (GimvImageView *iv)
3632 {
3633    GimvImageViewPlayableIF *playable;
3634 
3635    g_return_val_if_fail (GIMV_IS_IMAGE_VIEW (iv), 0);
3636 
3637    if (!iv->draw_area_funcs || !iv->draw_area_funcs->playable) return 0;
3638 
3639    playable = iv->draw_area_funcs->playable;
3640 
3641    if (!playable->get_position_fn) return 0;
3642    return playable->get_position_fn (iv);
3643 }
3644 
3645 
3646 
3647 /*****************************************************************************
3648  *
3649  *   list interface functions
3650  *
3651  *****************************************************************************/
3652 void
gimv_image_view_set_list(GimvImageView * iv,GList * list,GList * current,gpointer list_owner,GimvImageViewNextFn next_fn,GimvImageViewPrevFn prev_fn,GimvImageViewNthFn nth_fn,GimvImageViewRemoveListFn remove_list_fn,gpointer list_fn_user_data)3653 gimv_image_view_set_list (GimvImageView       *iv,
3654                           GList           *list,
3655                           GList           *current,
3656                           gpointer         list_owner,
3657                           GimvImageViewNextFn  next_fn,
3658                           GimvImageViewPrevFn  prev_fn,
3659                           GimvImageViewNthFn   nth_fn,
3660                           GimvImageViewRemoveListFn remove_list_fn,
3661                           gpointer         list_fn_user_data)
3662 {
3663    g_return_if_fail (iv);
3664    g_return_if_fail (list);
3665    g_return_if_fail (current);
3666 
3667    if (!g_list_find (GimvImageViewList, iv)) return;
3668 
3669    if (iv->priv->image_list)
3670       gimv_image_view_remove_list (iv, iv->priv->image_list->owner);
3671 
3672    iv->priv->image_list = g_new0 (GimvImageViewImageList, 1);
3673 
3674    iv->priv->image_list->list = list;
3675    if (!current)
3676       iv->priv->image_list->current = list;
3677    else
3678       iv->priv->image_list->current = current;
3679 
3680    iv->priv->image_list->owner             = list_owner;
3681    iv->priv->image_list->next_fn           = next_fn;
3682    iv->priv->image_list->prev_fn           = prev_fn;
3683    iv->priv->image_list->nth_fn            = nth_fn;
3684    iv->priv->image_list->remove_list_fn    = remove_list_fn;
3685    iv->priv->image_list->list_fn_user_data = list_fn_user_data;
3686 
3687    gtk_signal_emit (GTK_OBJECT(iv), gimv_image_view_signals[SET_LIST_SIGNAL]);
3688 }
3689 
3690 
3691 void
gimv_image_view_remove_list(GimvImageView * iv,gpointer list_owner)3692 gimv_image_view_remove_list (GimvImageView *iv, gpointer list_owner)
3693 {
3694    g_return_if_fail (iv);
3695 
3696    if (!iv->priv->image_list) return;
3697 
3698    if (iv->priv->image_list->remove_list_fn
3699        && iv->priv->image_list->owner == list_owner)
3700    {
3701       iv->priv->image_list->remove_list_fn
3702          (iv,
3703           iv->priv->image_list->owner,
3704           iv->priv->image_list->list_fn_user_data);
3705    }
3706 
3707    g_free (iv->priv->image_list);
3708    iv->priv->image_list = NULL;
3709 
3710    gtk_signal_emit (GTK_OBJECT(iv), gimv_image_view_signals[UNSET_LIST_SIGNAL]);
3711 }
3712 
3713 
3714 gint
gimv_image_view_image_list_length(GimvImageView * iv)3715 gimv_image_view_image_list_length (GimvImageView *iv)
3716 {
3717    g_return_val_if_fail (GIMV_IS_IMAGE_VIEW (iv), 0);
3718    if (!iv->priv->image_list) return 0;
3719 
3720    return g_list_length (iv->priv->image_list->list);
3721 }
3722 
3723 
3724 gint
gimv_image_view_image_list_position(GimvImageView * iv)3725 gimv_image_view_image_list_position (GimvImageView *iv)
3726 {
3727    g_return_val_if_fail (GIMV_IS_IMAGE_VIEW (iv), 0);
3728    if (!iv->priv->image_list) return 0;
3729 
3730    return g_list_position (iv->priv->image_list->list,
3731                            iv->priv->image_list->current);
3732 }
3733 
3734 
3735 GList *
gimv_image_view_image_list_current(GimvImageView * iv)3736 gimv_image_view_image_list_current (GimvImageView *iv)
3737 {
3738    g_return_val_if_fail (GIMV_IS_IMAGE_VIEW (iv), NULL);
3739    if (!iv->priv->image_list) return NULL;
3740 
3741    return iv->priv->image_list->current;
3742 }
3743 
3744 
3745 static gint
idle_gimv_image_view_next(gpointer data)3746 idle_gimv_image_view_next (gpointer data)
3747 {
3748    GimvImageView *iv = data;
3749 
3750    g_return_val_if_fail (iv, FALSE);
3751    if (!iv->priv->image_list) return FALSE;
3752    if (!iv->priv->image_list->next_fn) return FALSE;
3753 
3754    iv->priv->image_list->current
3755       = iv->priv->image_list->next_fn (iv,
3756                                        iv->priv->image_list->owner,
3757                                        iv->priv->image_list->current,
3758                                        iv->priv->image_list->list_fn_user_data);
3759 
3760    return FALSE;
3761 }
3762 
3763 
3764 void
gimv_image_view_next(GimvImageView * iv)3765 gimv_image_view_next (GimvImageView *iv)
3766 {
3767    g_return_if_fail (iv);
3768    gtk_idle_add (idle_gimv_image_view_next, iv);
3769 }
3770 
3771 
3772 static gint
idle_gimv_image_view_prev(gpointer data)3773 idle_gimv_image_view_prev (gpointer data)
3774 {
3775    GimvImageView *iv = data;
3776 
3777    g_return_val_if_fail (iv, FALSE);
3778    if (!iv->priv->image_list) return FALSE;
3779    if (!iv->priv->image_list->prev_fn) return FALSE;
3780 
3781    iv->priv->image_list->current
3782       = iv->priv->image_list->prev_fn (iv,
3783                                        iv->priv->image_list->owner,
3784                                        iv->priv->image_list->current,
3785                                        iv->priv->image_list->list_fn_user_data);
3786 
3787    return FALSE;
3788 }
3789 
3790 
3791 void
gimv_image_view_prev(GimvImageView * iv)3792 gimv_image_view_prev (GimvImageView *iv)
3793 {
3794    g_return_if_fail (iv);
3795 
3796    gtk_idle_add (idle_gimv_image_view_prev, iv);
3797 }
3798 
3799 
3800 typedef struct NthFnData_Tag {
3801    GimvImageView *iv;
3802    gint       nth;
3803 } NthFnData;
3804 
3805 
3806 static gint
idle_gimv_image_view_nth(gpointer data)3807 idle_gimv_image_view_nth (gpointer data)
3808 {
3809    NthFnData *nth_fn_data = data;
3810    GimvImageView *iv = data;
3811    gint nth;
3812 
3813    g_return_val_if_fail (nth_fn_data, FALSE);
3814 
3815    iv = nth_fn_data->iv;
3816    nth = nth_fn_data->nth;
3817 
3818    g_free (nth_fn_data);
3819    nth_fn_data = NULL;
3820    data = NULL;
3821 
3822    g_return_val_if_fail (iv, FALSE);
3823    if (!iv->priv->image_list) return FALSE;
3824    if (!iv->priv->image_list->nth_fn) return FALSE;
3825 
3826    iv->priv->image_list->current
3827       = iv->priv->image_list->nth_fn (iv,
3828                                       iv->priv->image_list->owner,
3829                                       iv->priv->image_list->list,
3830                                       nth,
3831                                       iv->priv->image_list->list_fn_user_data);
3832 
3833    return FALSE;
3834 }
3835 
3836 
3837 void
gimv_image_view_nth(GimvImageView * iv,guint nth)3838 gimv_image_view_nth (GimvImageView *iv, guint nth)
3839 {
3840    NthFnData *nth_fn_data;
3841 
3842    g_return_if_fail (iv);
3843 
3844    nth_fn_data = g_new (NthFnData, 1);
3845    nth_fn_data->iv  = iv;
3846    nth_fn_data->nth = nth;
3847 
3848    gtk_idle_add (idle_gimv_image_view_nth, nth_fn_data);
3849 }
3850 
3851 
3852 static GList *
next_image(GimvImageView * iv,gpointer list_owner,GList * current,gpointer data)3853 next_image (GimvImageView *iv,
3854             gpointer list_owner,
3855             GList *current,
3856             gpointer data)
3857 {
3858    GList *next, *node;
3859 
3860    g_return_val_if_fail (iv, NULL);
3861    g_return_val_if_fail (iv == list_owner, NULL);
3862    g_return_val_if_fail (current, NULL);
3863 
3864    if (!iv->priv->image_list) return NULL;
3865 
3866    node = g_list_find (iv->priv->image_list->list, current->data);
3867    g_return_val_if_fail (node, NULL);
3868 
3869    next = g_list_next (current);
3870    if (!next)
3871       next = current;
3872    g_return_val_if_fail (next, NULL);
3873 
3874    if (next != current) {
3875       gimv_image_view_change_image (iv, next->data);
3876    }
3877 
3878    return next;
3879 }
3880 
3881 
3882 static GList *
prev_image(GimvImageView * iv,gpointer list_owner,GList * current,gpointer data)3883 prev_image (GimvImageView *iv,
3884             gpointer list_owner,
3885             GList *current,
3886             gpointer data)
3887 {
3888    GList *prev, *node;
3889 
3890    g_return_val_if_fail (iv, NULL);
3891    g_return_val_if_fail (iv == list_owner, NULL);
3892    g_return_val_if_fail (current, NULL);
3893 
3894    if (!iv->priv->image_list) return NULL;
3895 
3896    node = g_list_find (iv->priv->image_list->list, current->data);
3897    g_return_val_if_fail (node, NULL);
3898 
3899    prev = g_list_previous (current);
3900    if (!prev)
3901       prev = current;
3902    g_return_val_if_fail (prev, NULL);
3903 
3904    if (prev != current) {
3905       gimv_image_view_change_image (iv, prev->data);
3906    }
3907 
3908    return prev;
3909 }
3910 
3911 
3912 static GList *
nth_image(GimvImageView * iv,gpointer list_owner,GList * list,guint nth,gpointer data)3913 nth_image (GimvImageView *iv,
3914            gpointer list_owner,
3915            GList *list,
3916            guint nth,
3917            gpointer data)
3918 {
3919    GList *node;
3920 
3921    g_return_val_if_fail (iv, NULL);
3922    g_return_val_if_fail (iv == list_owner, NULL);
3923 
3924    if (!iv->priv->image_list) return NULL;
3925 
3926    node = g_list_nth (iv->priv->image_list->list, nth);
3927    g_return_val_if_fail (node, NULL);
3928 
3929    gimv_image_view_change_image (iv, node->data);
3930 
3931    return node;
3932 }
3933 
3934 
3935 static void
remove_list(GimvImageView * iv,gpointer list_owner,gpointer data)3936 remove_list (GimvImageView *iv, gpointer list_owner, gpointer data)
3937 {
3938    g_return_if_fail (iv == list_owner);
3939 
3940    if (!iv->priv->image_list) return;
3941 
3942    g_list_foreach (iv->priv->image_list->list, (GFunc) gimv_image_info_unref, NULL);
3943    g_list_free (iv->priv->image_list->list);
3944    iv->priv->image_list->list = NULL;
3945    iv->priv->image_list->current = NULL;
3946 }
3947 
3948 
3949 void
gimv_image_view_set_list_self(GimvImageView * iv,GList * list,GList * current)3950 gimv_image_view_set_list_self (GimvImageView *iv, GList *list, GList *current)
3951 {
3952    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
3953    g_return_if_fail (list);
3954 
3955    if (!current || !g_list_find (list, current->data))
3956       current = list;
3957 
3958    gimv_image_view_set_list (iv, list, current, iv,
3959                        next_image,
3960                        prev_image,
3961                        nth_image,
3962                        remove_list,
3963                        iv);
3964 }
3965 
3966 
3967 gboolean
gimv_image_view_has_list(GimvImageView * iv)3968 gimv_image_view_has_list (GimvImageView *iv)
3969 {
3970    if (iv->priv->image_list) {
3971       return TRUE;
3972    } else {
3973       return FALSE;
3974    }
3975 }
3976 
3977 void
gimv_image_view_playable_set_status(GimvImageView * iv,GimvImageViewPlayableStatus status)3978 gimv_image_view_playable_set_status (GimvImageView *iv,
3979                                      GimvImageViewPlayableStatus status)
3980 {
3981    GimvImageViewPlayableIF *playable;
3982    GtkWidget *play, *stop, *pause, *forward, *reverse, *eject;
3983    GtkItemFactory *ifactory;
3984 
3985    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
3986    if (!iv->draw_area_funcs || !iv->draw_area_funcs->playable) return;
3987 
3988    playable = iv->draw_area_funcs->playable;
3989 
3990    if (iv->movie_menu && GTK_IS_WIDGET (iv->movie_menu)) {
3991       ifactory = gtk_item_factory_from_widget (iv->movie_menu);
3992       play     = gtk_item_factory_get_item (ifactory, "/Play");
3993       stop     = gtk_item_factory_get_item (ifactory, "/Stop");
3994       pause    = gtk_item_factory_get_item (ifactory, "/Pause");
3995       forward  = gtk_item_factory_get_item (ifactory, "/Forward");
3996       reverse  = gtk_item_factory_get_item (ifactory, "/Reverse");
3997       eject    = gtk_item_factory_get_item (ifactory, "/Eject");
3998    } else {
3999       play = stop = pause = forward = reverse = eject = NULL;
4000    }
4001 
4002    if (status == GimvImageViewPlayableDisable) {
4003       gimv_icon_stock_change_widget_icon  (iv->player.play_icon, "play");
4004       gtk_widget_set_sensitive (iv->player.play,    FALSE);
4005       gtk_widget_set_sensitive (iv->player.stop,    FALSE);
4006       gtk_widget_set_sensitive (iv->player.fw,      FALSE);
4007       gtk_widget_set_sensitive (iv->player.rw,      FALSE);
4008       gtk_widget_set_sensitive (iv->player.eject,   FALSE);
4009       gtk_widget_set_sensitive (iv->player.seekbar, FALSE);
4010       if (play)    gtk_widget_set_sensitive (play,    FALSE);
4011       if (stop)    gtk_widget_set_sensitive (stop,    FALSE);
4012       if (pause)   gtk_widget_set_sensitive (pause,   FALSE);
4013       if (forward) gtk_widget_set_sensitive (forward, FALSE);
4014       if (reverse) gtk_widget_set_sensitive (reverse, FALSE);
4015       if (eject)   gtk_widget_set_sensitive (eject, FALSE);
4016       gimv_image_view_playable_set_position (iv, 0.0);
4017       return;
4018 
4019    } else {
4020       gboolean enable;
4021 
4022       enable = playable->play_fn ? TRUE : FALSE;
4023       gtk_widget_set_sensitive (iv->player.play,  enable);
4024       if (play) gtk_widget_set_sensitive (play, enable);
4025 
4026       enable = playable->pause_fn ? TRUE : FALSE;
4027       if (pause) gtk_widget_set_sensitive (pause, enable);
4028 
4029       enable = playable->stop_fn ? TRUE : FALSE;
4030       gtk_widget_set_sensitive (iv->player.stop,  enable);
4031       if (stop) gtk_widget_set_sensitive (stop, enable);
4032 
4033       enable = playable->forward_fn ? TRUE : FALSE;
4034       gtk_widget_set_sensitive (iv->player.fw,    enable);
4035       if (forward) gtk_widget_set_sensitive (forward, enable);
4036 
4037       enable = playable->reverse_fn ? TRUE : FALSE;
4038       gtk_widget_set_sensitive (iv->player.rw,    enable);
4039       if (reverse) gtk_widget_set_sensitive (reverse, enable);
4040 
4041       enable = playable->eject_fn ? TRUE : FALSE;
4042       gtk_widget_set_sensitive (iv->player.eject, enable);
4043       if (eject) gtk_widget_set_sensitive (eject, enable);
4044 
4045       if (playable->is_seekable_fn
4046           && playable->is_seekable_fn (iv)
4047           && playable->seek_fn)
4048       {
4049          gtk_widget_set_sensitive (iv->player.seekbar, TRUE);
4050       }
4051    }
4052 
4053    switch (status) {
4054    case GimvImageViewPlayableStop:
4055       gimv_image_view_playable_set_position (iv, 0.0);
4056       gtk_widget_set_sensitive (iv->player.stop,    FALSE);
4057       gtk_widget_set_sensitive (iv->player.fw,      FALSE);
4058       gtk_widget_set_sensitive (iv->player.rw,      FALSE);
4059       if (stop)    gtk_widget_set_sensitive (stop,    FALSE);
4060       if (pause)   gtk_widget_set_sensitive (pause,   FALSE);
4061       if (forward) gtk_widget_set_sensitive (forward, FALSE);
4062       if (reverse) gtk_widget_set_sensitive (reverse, FALSE);
4063       break;
4064    case GimvImageViewPlayableForward:
4065    case GimvImageViewPlayableReverse:
4066       gtk_widget_set_sensitive (iv->player.fw,      FALSE);
4067       gtk_widget_set_sensitive (iv->player.rw,      FALSE);
4068       if (pause)   gtk_widget_set_sensitive (pause,   FALSE);
4069       if (forward) gtk_widget_set_sensitive (forward, FALSE);
4070       if (reverse) gtk_widget_set_sensitive (reverse, FALSE);
4071       break;
4072    case GimvImageViewPlayablePlay:
4073       if (!playable->pause_fn) {
4074          gtk_widget_set_sensitive (iv->player.play, FALSE);
4075          if (pause) gtk_widget_set_sensitive (pause, FALSE);
4076       }
4077       break;
4078    case GimvImageViewPlayablePause:
4079    default:
4080       break;
4081    }
4082 
4083    if (status == GimvImageViewPlayablePlay && playable->pause_fn) {
4084       gimv_icon_stock_change_widget_icon (iv->player.play_icon, "pause");
4085    } else {
4086       gimv_icon_stock_change_widget_icon (iv->player.play_icon, "play");
4087    }
4088 }
4089 
4090 
4091 void
gimv_image_view_playable_set_position(GimvImageView * iv,gfloat pos)4092 gimv_image_view_playable_set_position (GimvImageView *iv, gfloat pos)
4093 {
4094    GtkAdjustment *adj;
4095 
4096    g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
4097 
4098    adj = gtk_range_get_adjustment (GTK_RANGE (iv->player.seekbar));
4099 
4100    if (iv->priv && !(iv->priv->player_flags & GimvImageViewSeekBarDraggingFlag)) {
4101       adj->value = pos;
4102       gtk_signal_emit_by_name (GTK_OBJECT(adj), "value_changed");
4103    }
4104 
4105 }
4106