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