Fix SUSE lint warnings
[lxde/gpicview.git] / src / main-win.c
CommitLineData
1d48a247 1/***************************************************************************
1c8a8ba7
HJYP
2 * Copyright (C) 2007, 2008 by PCMan (Hong Jen Yee) *
3 * pcman.tw@gmail.com *
1d48a247 4 * *
1c8a8ba7 5 * This program is free software; you can redistribute it and/or modify *
1d48a247
HJYP
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
1c8a8ba7 10 * This program is distributed in the hope that it will be useful, *
1d48a247
HJYP
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
1c8a8ba7 16 * along with this program; if not, write to the *
1d48a247
HJYP
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
21#ifdef HAVE_CONFIG_H
22# include <config.h>
23#endif
24
cf15ca10 25#include "main-win.h"
bb0f721e 26
1d48a247
HJYP
27#include <glib/gi18n.h>
28#include <glib/gstdio.h>
29#include <gdk/gdkkeysyms.h>
30
0ed1aa41 31#include <unistd.h>
1d48a247
HJYP
32#include <string.h>
33#include <errno.h>
d2d3c393 34#include <stdlib.h>
1c8a8ba7 35#include <stdio.h>
1d48a247 36
bb0f721e
HJYP
37#include "pref.h"
38
9c52ae58 39#include "image-view.h"
0c0c8179 40#include "image-list.h"
1d48a247 41#include "working-area.h"
cf15ca10 42#include "ptk-menu.h"
701822a6 43#include "file-dlgs.h"
7c3b160c 44#include "jpeg-tran.h"
1d48a247 45
d8d44976 46/* For drag & drop */
cf15ca10 47static GtkTargetEntry drop_targets[] =
1d48a247
HJYP
48{
49 {"text/uri-list", 0, 0},
cf15ca10 50 {"text/plain", 0, 1}
1d48a247
HJYP
51};
52
cf15ca10
HJYP
53static void main_win_init( MainWin*mw );
54static void main_win_finalize( GObject* obj );
55
56static void create_nav_bar( MainWin* mw, GtkWidget* box);
57GtkWidget* add_nav_btn( MainWin* mw, const char* icon, const char* tip, GCallback cb, gboolean toggle);
58// GtkWidget* add_menu_item( GtkMenuShell* menu, const char* label, const char* icon, GCallback cb, gboolean toggle=FALSE );
da046c6e 59static void rotate_image( MainWin* mw, int angle );
cf15ca10
HJYP
60static void show_popup_menu( MainWin* mw, GdkEventButton* evt );
61
62/* signal handlers */
63static gboolean on_delete_event( GtkWidget* widget, GdkEventAny* evt );
64static void on_size_allocate( GtkWidget* widget, GtkAllocation *allocation );
86ebaeb3 65static gboolean on_win_state_event( GtkWidget* widget, GdkEventWindowState* state );
cf15ca10
HJYP
66static void on_zoom_fit( GtkToggleButton* btn, MainWin* mw );
67static void on_zoom_fit_menu( GtkMenuItem* item, MainWin* mw );
68static void on_full_screen( GtkWidget* btn, MainWin* mw );
69static void on_next( GtkWidget* btn, MainWin* mw );
70static void on_orig_size( GtkToggleButton* btn, MainWin* mw );
71static void on_orig_size_menu( GtkToggleButton* btn, MainWin* mw );
72static void on_prev( GtkWidget* btn, MainWin* mw );
1c8a8ba7 73static void on_rotate_auto_save( GtkWidget* btn, MainWin* mw );
cf15ca10
HJYP
74static void on_rotate_clockwise( GtkWidget* btn, MainWin* mw );
75static void on_rotate_counterclockwise( GtkWidget* btn, MainWin* mw );
76static void on_save_as( GtkWidget* btn, MainWin* mw );
77static void on_save( GtkWidget* btn, MainWin* mw );
78static void on_open( GtkWidget* btn, MainWin* mw );
79static void on_zoom_in( GtkWidget* btn, MainWin* mw );
80static void on_zoom_out( GtkWidget* btn, MainWin* mw );
81static void on_preference( GtkWidget* btn, MainWin* mw );
82static void on_quit( GtkWidget* btn, MainWin* mw );
83static gboolean on_button_press( GtkWidget* widget, GdkEventButton* evt, MainWin* mw );
84static gboolean on_button_release( GtkWidget* widget, GdkEventButton* evt, MainWin* mw );
85static gboolean on_mouse_move( GtkWidget* widget, GdkEventMotion* evt, MainWin* mw );
86static gboolean on_scroll_event( GtkWidget* widget, GdkEventScroll* evt, MainWin* mw );
87static gboolean on_key_press_event(GtkWidget* widget, GdkEventKey * key);
1c8a8ba7 88static gboolean save_confirm( MainWin* mw, const char* file_path );
cf15ca10 89static void on_drag_data_received( GtkWidget* widget, GdkDragContext *drag_context,
1c8a8ba7 90 int x, int y, GtkSelectionData* data, guint info, guint time, MainWin* mw );
cf15ca10
HJYP
91static void on_delete( GtkWidget* btn, MainWin* mw );
92static void on_about( GtkWidget* menu, MainWin* mw );
1d48a247 93
d8d44976 94static void update_title(const char *filename, MainWin *mw );
da046c6e 95
96void on_flip_vertical( GtkWidget* btn, MainWin* mw );
97void on_flip_horizontal( GtkWidget* btn, MainWin* mw );
98static int trans_angle_to_id(int i);
99static int get_new_angle( int orig_angle, int rotate_angle );
1d48a247 100
cf15ca10 101// Begin of GObject-related stuff
1d48a247 102
cf15ca10 103G_DEFINE_TYPE( MainWin, main_win, GTK_TYPE_WINDOW )
1d48a247 104
cf15ca10
HJYP
105void main_win_class_init( MainWinClass* klass )
106{
1d48a247
HJYP
107 GObjectClass * obj_class;
108 GtkWidgetClass *widget_class;
109
110 obj_class = ( GObjectClass * ) klass;
111// obj_class->set_property = _set_property;
112// obj_class->get_property = _get_property;
cf15ca10 113 obj_class->finalize = main_win_finalize;
1d48a247
HJYP
114
115 widget_class = GTK_WIDGET_CLASS ( klass );
116 widget_class->delete_event = on_delete_event;
117 widget_class->size_allocate = on_size_allocate;
118 widget_class->key_press_event = on_key_press_event;
e216a767 119 widget_class->window_state_event = on_win_state_event;
1d48a247
HJYP
120}
121
cf15ca10
HJYP
122void main_win_finalize( GObject* obj )
123{
124 MainWin *mw = (MainWin*)obj;
125
126 main_win_close(mw);
127
128 if( G_LIKELY(mw->img_list) )
129 image_list_free( mw->img_list );
130 gdk_cursor_unref( mw->hand_cursor );
131
1c8a8ba7
HJYP
132 // FIXME: Put this here is weird
133 gtk_main_quit();
cf15ca10
HJYP
134}
135
136GtkWidget* main_win_new()
1d48a247 137{
cf15ca10 138 return (GtkWidget*)g_object_new ( MAIN_WIN_TYPE, NULL );
1d48a247
HJYP
139}
140
141// End of GObject-related stuff
142
cf15ca10 143void main_win_init( MainWin*mw )
1d48a247 144{
1c8a8ba7 145 gtk_window_set_title( (GtkWindow*)mw, _("Image Viewer"));
cf15ca10
HJYP
146 gtk_window_set_icon_from_file( (GtkWindow*)mw, PACKAGE_DATA_DIR"/pixmaps/gpicview.png", NULL );
147 gtk_window_set_default_size( (GtkWindow*)mw, 640, 480 );
1d48a247
HJYP
148
149 GtkWidget* box = gtk_vbox_new( FALSE, 0 );
cf15ca10 150 gtk_container_add( (GtkContainer*)mw, box);
1d48a247
HJYP
151
152 // image area
cf15ca10
HJYP
153 mw->evt_box = gtk_event_box_new();
154 GTK_WIDGET_SET_FLAGS( mw->evt_box, GTK_CAN_FOCUS );
155 gtk_widget_add_events( mw->evt_box,
1d48a247
HJYP
156 GDK_POINTER_MOTION_MASK|GDK_BUTTON_PRESS_MASK|
157 GDK_BUTTON_RELEASE_MASK|GDK_SCROLL_MASK );
cf15ca10
HJYP
158 g_signal_connect( mw->evt_box, "button-press-event", G_CALLBACK(on_button_press), mw );
159 g_signal_connect( mw->evt_box, "button-release-event", G_CALLBACK(on_button_release), mw );
160 g_signal_connect( mw->evt_box, "motion-notify-event", G_CALLBACK(on_mouse_move), mw );
161 g_signal_connect( mw->evt_box, "scroll-event", G_CALLBACK(on_scroll_event), mw );
1c8a8ba7 162 // Set bg color to white
794cac1a
HJYP
163
164 gtk_widget_modify_bg( mw->evt_box, GTK_STATE_NORMAL, &pref.bg );
1d48a247 165
cf15ca10
HJYP
166 mw->img_view = image_view_new();
167 gtk_container_add( (GtkContainer*)mw->evt_box, (GtkWidget*)mw->img_view);
1d48a247 168
2c34ffe0
HJYP
169 const char scroll_style[]=
170 "style \"gpicview-scroll\" {"
171 "GtkScrolledWindow::scrollbar-spacing=0"
172 "}"
173 "class \"GtkScrolledWindow\" style \"gpicview-scroll\"";
174 gtk_rc_parse_string( scroll_style );
cf15ca10
HJYP
175 mw->scroll = gtk_scrolled_window_new( NULL, NULL );
176 gtk_scrolled_window_set_shadow_type( (GtkScrolledWindow*)mw->scroll, GTK_SHADOW_NONE );
177 gtk_scrolled_window_set_policy((GtkScrolledWindow*)mw->scroll,
1d48a247
HJYP
178 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
179 GtkAdjustment *hadj, *vadj;
cf15ca10 180 hadj = gtk_scrolled_window_get_hadjustment((GtkScrolledWindow*)mw->scroll);
1d48a247
HJYP
181 hadj->page_increment = 10;
182 gtk_adjustment_changed(hadj);
cf15ca10 183 vadj = gtk_scrolled_window_get_vadjustment((GtkScrolledWindow*)mw->scroll);
1d48a247
HJYP
184 vadj->page_increment = 10;
185 gtk_adjustment_changed(vadj);
9c52ae58 186
d2d3c393 187 image_view_set_adjustments( IMAGE_VIEW(mw->img_view), hadj, vadj ); // dirty hack :-(
cf15ca10
HJYP
188 gtk_scrolled_window_add_with_viewport( (GtkScrolledWindow*)mw->scroll, mw->evt_box );
189 GtkWidget* viewport = gtk_bin_get_child( (GtkBin*)mw->scroll );
2c34ffe0
HJYP
190 gtk_viewport_set_shadow_type( (GtkViewport*)viewport, GTK_SHADOW_NONE );
191 gtk_container_set_border_width( (GtkContainer*)viewport, 0 );
1d48a247 192
cf15ca10 193 gtk_box_pack_start( (GtkBox*)box, mw->scroll, TRUE, TRUE, 0 );
1d48a247
HJYP
194
195 // build toolbar
cf15ca10 196 create_nav_bar( mw, box );
1d48a247
HJYP
197 gtk_widget_show_all( box );
198
cf15ca10 199 mw->hand_cursor = gdk_cursor_new_for_display( gtk_widget_get_display((GtkWidget*)mw), GDK_FLEUR );
1d48a247 200
5bfec971 201// zoom_mode = ZOOM_NONE;
cf15ca10 202 mw->zoom_mode = ZOOM_FIT;
1d48a247
HJYP
203
204 // Set up drag & drop
cf15ca10
HJYP
205 gtk_drag_dest_set( (GtkWidget*)mw, GTK_DEST_DEFAULT_ALL,
206 drop_targets,
207 G_N_ELEMENTS(drop_targets),
208 GDK_ACTION_COPY | GDK_ACTION_ASK );
209 g_signal_connect( mw, "drag-data-received", G_CALLBACK(on_drag_data_received), mw );
9c52ae58 210
cf15ca10 211 mw->img_list = image_list_new();
7c3b160c 212
7c3b160c
HJYP
213 // rotation angle is zero on startup
214 mw->rotation_angle = 0;
1d48a247
HJYP
215}
216
cf15ca10 217void create_nav_bar( MainWin* mw, GtkWidget* box )
1d48a247 218{
cf15ca10 219 mw->nav_bar = gtk_hbox_new( FALSE, 0 );
1d48a247 220
cf15ca10
HJYP
221 add_nav_btn( mw, GTK_STOCK_GO_BACK, _("Previous"), G_CALLBACK(on_prev), FALSE );
222 add_nav_btn( mw, GTK_STOCK_GO_FORWARD, _("Next"), G_CALLBACK(on_next), FALSE );
1d48a247 223
cf15ca10 224 gtk_box_pack_start( (GtkBox*)mw->nav_bar, gtk_vseparator_new(), FALSE, FALSE, 0 );
1c8a8ba7 225
cf15ca10
HJYP
226 add_nav_btn( mw, GTK_STOCK_ZOOM_OUT, _("Zoom Out"), G_CALLBACK(on_zoom_out), FALSE );
227 add_nav_btn( mw, GTK_STOCK_ZOOM_IN, _("Zoom In"), G_CALLBACK(on_zoom_in), FALSE );
5bfec971
HJYP
228
229// percent = gtk_entry_new(); // show scale (in percentage)
cf15ca10 230// g_signal_connect( percent, "activate", G_CALLBACK(on_percentage), mw );
5bfec971
HJYP
231// gtk_widget_set_size_request( percent, 45, -1 );
232// gtk_box_pack_start( (GtkBox*)nav_bar, percent, FALSE, FALSE, 2 );
233
cf15ca10
HJYP
234 mw->btn_fit = add_nav_btn( mw, GTK_STOCK_ZOOM_FIT, _("Fit Image To Window Size"),
235 G_CALLBACK(on_zoom_fit), TRUE );
236 mw->btn_orig = add_nav_btn( mw, GTK_STOCK_ZOOM_100, _("Original Size"),
237 G_CALLBACK(on_orig_size), TRUE );
238 gtk_toggle_button_set_active( (GtkToggleButton*)mw->btn_fit, TRUE );
5bfec971 239
1d48a247
HJYP
240#ifndef GTK_STOCK_FULLSCREEN
241#define GTK_STOCK_FULLSCREEN "gtk-fullscreen"
242#endif
1c8a8ba7 243 add_nav_btn( mw, GTK_STOCK_FULLSCREEN, _("Full Screen"), G_CALLBACK(on_full_screen), FALSE ); // gtk+ 2.8+
1d48a247 244
cf15ca10 245 gtk_box_pack_start( (GtkBox*)mw->nav_bar, gtk_vseparator_new(), FALSE, FALSE, 0 );
1d48a247 246
701822a6
HJYP
247 mw->btn_rotate_ccw = add_nav_btn( mw, "object-rotate-left", _("Rotate Counterclockwise"), G_CALLBACK(on_rotate_counterclockwise), FALSE );
248 mw->btn_rotate_cw = add_nav_btn( mw, "object-rotate-right", _("Rotate Clockwise"), G_CALLBACK(on_rotate_clockwise), FALSE );
1d48a247 249
701822a6
HJYP
250 mw->btn_flip_h = add_nav_btn( mw, "object-flip-horizontal", _("Flip Horizontal"), G_CALLBACK(on_flip_horizontal), FALSE );
251 mw->btn_flip_v = add_nav_btn( mw, "object-flip-vertical", _("Flip Vertical"), G_CALLBACK(on_flip_vertical), FALSE );
d8d44976 252
cf15ca10 253 gtk_box_pack_start( (GtkBox*)mw->nav_bar, gtk_vseparator_new(), FALSE, FALSE, 0 );
1d48a247 254
cf15ca10
HJYP
255 add_nav_btn( mw, GTK_STOCK_OPEN, _("Open File"), G_CALLBACK(on_open), FALSE );
256 add_nav_btn( mw, GTK_STOCK_SAVE, _("Save File"), G_CALLBACK(on_save), FALSE );
257 add_nav_btn( mw, GTK_STOCK_SAVE_AS, _("Save File As"), G_CALLBACK(on_save_as), FALSE );
258 add_nav_btn( mw, GTK_STOCK_DELETE, _("Delete File"), G_CALLBACK(on_delete), FALSE );
1d48a247 259
cf15ca10 260 gtk_box_pack_start( (GtkBox*)mw->nav_bar, gtk_vseparator_new(), FALSE, FALSE, 0 );
bb0f721e 261 add_nav_btn( mw, GTK_STOCK_PREFERENCES, _("Preferences"), G_CALLBACK(on_preference), FALSE );
1c8a8ba7 262 add_nav_btn( mw, GTK_STOCK_QUIT, _("Quit"), G_CALLBACK(on_quit), FALSE );
1d48a247
HJYP
263
264 GtkWidget* align = gtk_alignment_new( 0.5, 0, 0, 0 );
cf15ca10 265 gtk_container_add( (GtkContainer*)align, mw->nav_bar );
1d48a247
HJYP
266 gtk_box_pack_start( (GtkBox*)box, align, FALSE, TRUE, 2 );
267}
268
cf15ca10 269gboolean on_delete_event( GtkWidget* widget, GdkEventAny* evt )
1d48a247
HJYP
270{
271 gtk_widget_destroy( widget );
272 return TRUE;
273}
274
d8d44976 275static void update_title(const char *filename, MainWin *mw )
da046c6e 276{
277 static char fname[50];
278 static int wid, hei;
794cac1a 279
da046c6e 280 char buf[100];
794cac1a 281
da046c6e 282 if(filename != NULL)
283 {
284 strncpy(fname, filename, 49);
285 fname[49] = '\0';
794cac1a 286
da046c6e 287 wid = gdk_pixbuf_get_width( mw->pix );
288 hei = gdk_pixbuf_get_height( mw->pix );
289 }
794cac1a 290
da046c6e 291 snprintf(buf, 100, "%s (%dx%d) %d%%", fname, wid, hei, (int)(mw->scale * 100));
292 gtk_window_set_title( (GtkWindow*)mw, buf );
794cac1a
HJYP
293
294 return;
da046c6e 295}
296
d8d44976
HJYP
297gboolean on_animation_timeout( MainWin* mw )
298{
299 int delay;
300 if ( gdk_pixbuf_animation_iter_advance( mw->animation_iter, NULL ) )
301 {
302 mw->pix = gdk_pixbuf_animation_iter_get_pixbuf( mw->animation_iter );
303 image_view_set_pixbuf( (ImageView*)mw->img_view, mw->pix );
304 }
305 delay = gdk_pixbuf_animation_iter_get_delay_time( mw->animation_iter );
7e1dcec1 306 mw->animation_timeout = g_timeout_add(delay, (GSourceFunc) on_animation_timeout, mw );
d8d44976
HJYP
307 return FALSE;
308}
309
07db5c2f
HJYP
310static void update_btns(MainWin* mw)
311{
312 gboolean enable = (mw->animation == NULL);
313 gtk_widget_set_sensitive(mw->btn_rotate_cw, enable);
314 gtk_widget_set_sensitive(mw->btn_rotate_ccw, enable);
315 gtk_widget_set_sensitive(mw->btn_flip_v, enable);
316 gtk_widget_set_sensitive(mw->btn_flip_h, enable);
317}
318
cf15ca10 319gboolean main_win_open( MainWin* mw, const char* file_path, ZoomMode zoom )
1d48a247 320{
1d48a247 321 GError* err = NULL;
da046c6e 322 GdkPixbufFormat* info;
323 info = gdk_pixbuf_get_file_info( file_path, NULL, NULL );
fecf68e0 324 char* type = ((info != NULL) ? gdk_pixbuf_format_get_name(info) : "");
da046c6e 325
cf15ca10 326 main_win_close( mw );
c215db47 327
d8d44976
HJYP
328 /* grabs a file as if it were an animation */
329 mw->animation = gdk_pixbuf_animation_new_from_file( file_path, &err );
330 if( ! mw->animation )
1d48a247 331 {
cf15ca10 332 main_win_show_error( mw, err->message );
d8d44976 333 g_error_free(err);
07db5c2f 334 update_btns( mw );
cf15ca10 335 return FALSE;
1d48a247 336 }
d8d44976
HJYP
337
338 /* tests if the file is actually just a normal picture */
339 if ( gdk_pixbuf_animation_is_static_image( mw->animation ) )
340 {
341 mw->pix = gdk_pixbuf_animation_get_static_image( mw->animation );
342 g_object_ref(mw->pix);
343 g_object_unref(mw->animation);
344 mw->animation = NULL;
345 }
346 else
347 {
348 int delay;
349 /* we found an animation */
350 mw->animation_iter = gdk_pixbuf_animation_get_iter( mw->animation, NULL );
351 mw->pix = gdk_pixbuf_animation_iter_get_pixbuf( mw->animation_iter );
352 delay = gdk_pixbuf_animation_iter_get_delay_time( mw->animation_iter );
7e1dcec1 353 mw->animation_timeout = g_timeout_add( delay, (GSourceFunc) on_animation_timeout, mw );
d8d44976 354 }
07db5c2f 355 update_btns( mw );
d8d44976
HJYP
356
357 if(!strcmp(type,"jpeg"))
c215db47 358 {
701822a6 359 GdkPixbuf* tmp;
da046c6e 360 // Only jpeg should rotate by EXIF
701822a6
HJYP
361 tmp = gdk_pixbuf_apply_embedded_orientation(mw->pix);
362 g_object_unref(mw->pix);
363 mw->pix = tmp;
c215db47 364 }
794cac1a 365
cf15ca10 366 mw->zoom_mode = zoom;
da8bd946 367
5bfec971 368 // select most suitable viewing mode
d8ce3af1 369 if( zoom == ZOOM_NONE )
1d48a247 370 {
cf15ca10
HJYP
371 int w = gdk_pixbuf_get_width( mw->pix );
372 int h = gdk_pixbuf_get_height( mw->pix );
1d48a247 373
1d48a247 374 GdkRectangle area;
cf15ca10 375 get_working_area( gtk_widget_get_screen((GtkWidget*)mw), &area );
c325c989
HJYP
376 // g_debug("determine best zoom mode: orig size: w=%d, h=%d", w, h);
377 // FIXME: actually this is a little buggy :-(
da8bd946 378 if( w < area.width && h < area.height && (w >= 640 || h >= 480) )
1d48a247 379 {
cf15ca10
HJYP
380 gtk_scrolled_window_set_policy( (GtkScrolledWindow*)mw->scroll, GTK_POLICY_NEVER, GTK_POLICY_NEVER );
381 gtk_widget_set_size_request( (GtkWidget*)mw->img_view, w, h );
5bfec971 382 GtkRequisition req;
cf15ca10 383 gtk_widget_size_request ( (GtkWidget*)mw, &req );
9c52ae58
HJYP
384 if( req.width < 640 ) req.width = 640;
385 if( req.height < 480 ) req.height = 480;
cf15ca10
HJYP
386 gtk_window_resize( (GtkWindow*)mw, req.width, req.height );
387 gtk_widget_set_size_request( (GtkWidget*)mw->img_view, -1, -1 );
388 gtk_scrolled_window_set_policy( (GtkScrolledWindow*)mw->scroll, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
389 mw->zoom_mode = ZOOM_ORIG;
da046c6e 390 mw->scale = 1.0;
1d48a247
HJYP
391 }
392 else
cf15ca10 393 mw->zoom_mode = ZOOM_FIT;
5bfec971 394 }
5bfec971 395
cf15ca10 396 if( mw->zoom_mode == ZOOM_FIT )
d8ce3af1 397 {
cf15ca10 398 gtk_toggle_button_set_active( (GtkToggleButton*)mw->btn_fit, TRUE );
c325c989 399 main_win_fit_window_size( mw, FALSE, GDK_INTERP_BILINEAR );
d8ce3af1 400 }
cf15ca10 401 else if( mw->zoom_mode == ZOOM_SCALE ) // scale
d8ce3af1 402 {
cf15ca10
HJYP
403 gtk_toggle_button_set_active( (GtkToggleButton*)mw->btn_orig, FALSE );
404 gtk_toggle_button_set_active( (GtkToggleButton*)mw->btn_fit, FALSE );
405 main_win_scale_image( mw, mw->scale, GDK_INTERP_BILINEAR );
d8ce3af1 406 }
cf15ca10 407 else if( mw->zoom_mode == ZOOM_ORIG ) // original size
5bfec971 408 {
cf15ca10 409 gtk_toggle_button_set_active( (GtkToggleButton*)mw->btn_orig, TRUE );
da046c6e 410 image_view_set_scale( (ImageView*)mw->img_view, mw->scale, GDK_INTERP_BILINEAR );
cf15ca10 411 main_win_center_image( mw );
1d48a247
HJYP
412 }
413
cf15ca10 414 image_view_set_pixbuf( (ImageView*)mw->img_view, mw->pix );
9c52ae58 415
1d48a247
HJYP
416// while (gtk_events_pending ())
417// gtk_main_iteration ();
418
419 // build file list
420 char* dir_path = g_path_get_dirname( file_path );
cf15ca10 421 image_list_open_dir( mw->img_list, dir_path, NULL );
f214531d 422 image_list_sort_by_name( mw->img_list, GTK_SORT_DESCENDING );
1d48a247 423 g_free( dir_path );
76e88fcf 424
1d48a247 425 char* base_name = g_path_get_basename( file_path );
cf15ca10 426 image_list_set_current( mw->img_list, base_name );
76e88fcf
HJYP
427
428 char* disp_name = g_filename_display_name( base_name );
1d48a247
HJYP
429 g_free( base_name );
430
d8d44976 431 update_title( disp_name, mw );
76e88fcf 432 g_free( disp_name );
1d48a247 433
cf15ca10 434 return TRUE;
1d48a247
HJYP
435}
436
cf15ca10 437void main_win_close( MainWin* mw )
1d48a247 438{
d8d44976
HJYP
439 if( mw->animation )
440 {
441 g_object_unref( mw->animation );
442 mw->animation = NULL;
443 if( mw->animation_timeout );
444 {
445 g_source_remove( mw->animation_timeout );
446 mw->animation_timeout = 0;
447 }
448 }
449 else if( mw->pix )
9c52ae58 450 {
cf15ca10 451 g_object_unref( mw->pix );
1d48a247 452 }
d8d44976 453 mw->pix = NULL;
1d48a247
HJYP
454}
455
cf15ca10 456void main_win_show_error( MainWin* mw, const char* message )
1d48a247 457{
cf15ca10 458 GtkWidget* dlg = gtk_message_dialog_new( (GtkWindow*)mw,
1d48a247
HJYP
459 GTK_DIALOG_MODAL,
460 GTK_MESSAGE_ERROR,
461 GTK_BUTTONS_OK,
a574ce8f 462 "%s", message );
1d48a247
HJYP
463 gtk_dialog_run( (GtkDialog*)dlg );
464 gtk_widget_destroy( dlg );
465}
466
cf15ca10 467void on_size_allocate( GtkWidget* widget, GtkAllocation *allocation )
1d48a247 468{
cf15ca10 469 GTK_WIDGET_CLASS(main_win_parent_class)->size_allocate( widget, allocation );
52c867e9 470 if( GTK_WIDGET_REALIZED (widget) )
1d48a247 471 {
cf15ca10 472 MainWin* mw = (MainWin*)widget;
9c52ae58 473
cf15ca10 474 if( mw->zoom_mode == ZOOM_FIT )
52c867e9
HJYP
475 {
476 while(gtk_events_pending ())
477 gtk_main_iteration(); // makes it more fluid
1d48a247 478
c325c989 479 main_win_fit_window_size( mw, FALSE, GDK_INTERP_BILINEAR );
52c867e9 480 }
1d48a247
HJYP
481 }
482}
483
86ebaeb3 484gboolean on_win_state_event( GtkWidget* widget, GdkEventWindowState* state )
e216a767
HJYP
485{
486 MainWin* mw = (MainWin*)widget;
1c8a8ba7 487 if( state->new_window_state == GDK_WINDOW_STATE_FULLSCREEN )
e216a767 488 {
794cac1a 489 gtk_widget_modify_bg( mw->evt_box, GTK_STATE_NORMAL, &pref.bg_full );
1c8a8ba7
HJYP
490 gtk_widget_hide( gtk_widget_get_parent(mw->nav_bar) );
491 mw->full_screen = TRUE;
e216a767 492 }
1c8a8ba7 493 else
e216a767 494 {
794cac1a 495 gtk_widget_modify_bg( mw->evt_box, GTK_STATE_NORMAL, &pref.bg );
1c8a8ba7
HJYP
496 gtk_widget_show( gtk_widget_get_parent(mw->nav_bar) );
497 mw->full_screen = FALSE;
e216a767 498 }
b0fd70a0 499
500 int previous = pref.open_maximized;
501 pref.open_maximized = (state->new_window_state == GDK_WINDOW_STATE_MAXIMIZED);
502 if (previous != pref.open_maximized)
503 save_preferences();
86ebaeb3 504 return TRUE;
e216a767
HJYP
505}
506
cf15ca10 507void main_win_fit_size( MainWin* mw, int width, int height, gboolean can_strech, GdkInterpType type )
1d48a247 508{
cf15ca10 509 if( ! mw->pix )
1d48a247
HJYP
510 return;
511
cf15ca10
HJYP
512 int orig_w = gdk_pixbuf_get_width( mw->pix );
513 int orig_h = gdk_pixbuf_get_height( mw->pix );
1d48a247 514
da8bd946
HJYP
515 if( can_strech || (orig_w > width || orig_h > height) )
516 {
cf15ca10
HJYP
517 gdouble xscale = ((gdouble)width) / orig_w;
518 gdouble yscale = ((gdouble)height)/ orig_h;
519 gdouble final_scale = xscale < yscale ? xscale : yscale;
1d48a247 520
cf15ca10 521 main_win_scale_image( mw, final_scale, type );
da8bd946
HJYP
522 }
523 else // use original size if the image is smaller than the window
524 {
cf15ca10
HJYP
525 mw->scale = 1.0;
526 image_view_set_scale( (ImageView*)mw->img_view, 1.0, type );
794cac1a 527
d8d44976 528 update_title(NULL, mw);
da8bd946 529 }
1d48a247
HJYP
530}
531
cf15ca10 532void main_win_fit_window_size( MainWin* mw, gboolean can_strech, GdkInterpType type )
1d48a247 533{
cf15ca10 534 mw->zoom_mode = ZOOM_FIT;
94fcf707 535
cf15ca10 536 if( mw->pix == NULL )
da8bd946 537 return;
94fcf707 538
cf15ca10 539 main_win_fit_size( mw, mw->scroll->allocation.width, mw->scroll->allocation.height, can_strech, type );
1d48a247
HJYP
540}
541
cf15ca10 542GtkWidget* add_nav_btn( MainWin* mw, const char* icon, const char* tip, GCallback cb, gboolean toggle )
1d48a247 543{
701822a6
HJYP
544 GtkWidget* img;
545 if( g_str_has_prefix(icon, "gtk-") )
546 img = gtk_image_new_from_stock(icon, GTK_ICON_SIZE_SMALL_TOOLBAR);
547 else
548 img = gtk_image_new_from_icon_name(icon, GTK_ICON_SIZE_SMALL_TOOLBAR);
1d48a247
HJYP
549 GtkWidget* btn;
550 if( G_UNLIKELY(toggle) )
551 {
552 btn = gtk_toggle_button_new();
cf15ca10 553 g_signal_connect( btn, "toggled", cb, mw );
1d48a247
HJYP
554 }
555 else
556 {
557 btn = gtk_button_new();
cf15ca10 558 g_signal_connect( btn, "clicked", cb, mw );
1d48a247
HJYP
559 }
560 gtk_button_set_relief( (GtkButton*)btn, GTK_RELIEF_NONE );
561 gtk_button_set_focus_on_click( (GtkButton*)btn, FALSE );
562 gtk_container_add( (GtkContainer*)btn, img );
d8d44976 563 gtk_widget_set_tooltip_text( btn, tip );
cf15ca10 564 gtk_box_pack_start( (GtkBox*)mw->nav_bar, btn, FALSE, FALSE, 0 );
1d48a247
HJYP
565 return btn;
566}
567
cf15ca10 568void on_zoom_fit_menu( GtkMenuItem* item, MainWin* mw )
1d48a247 569{
cf15ca10 570 gtk_button_clicked( (GtkButton*)mw->btn_fit );
1d48a247
HJYP
571}
572
cf15ca10 573void on_zoom_fit( GtkToggleButton* btn, MainWin* mw )
1d48a247
HJYP
574{
575 if( ! btn->active )
576 {
cf15ca10 577 if( mw->zoom_mode == ZOOM_FIT )
1d48a247
HJYP
578 gtk_toggle_button_set_active( btn, TRUE );
579 return;
580 }
cf15ca10 581 gtk_toggle_button_set_active( (GtkToggleButton*)mw->btn_orig, FALSE );
1d48a247 582
c325c989 583 main_win_fit_window_size( mw, FALSE, GDK_INTERP_BILINEAR );
1d48a247
HJYP
584}
585
cf15ca10 586void on_full_screen( GtkWidget* btn, MainWin* mw )
1d48a247 587{
cf15ca10 588 if( ! mw->full_screen )
cf15ca10 589 gtk_window_fullscreen( (GtkWindow*)mw );
1d48a247 590 else
cf15ca10 591 gtk_window_unfullscreen( (GtkWindow*)mw );
1d48a247
HJYP
592}
593
cf15ca10 594void on_orig_size_menu( GtkToggleButton* btn, MainWin* mw )
1d48a247 595{
cf15ca10 596 gtk_button_clicked( (GtkButton*)mw->btn_orig );
1d48a247
HJYP
597}
598
cf15ca10 599void on_orig_size( GtkToggleButton* btn, MainWin* mw )
1d48a247 600{
cf15ca10 601 // this callback could be called from activate signal of menu item.
1d48a247
HJYP
602 if( GTK_IS_MENU_ITEM(btn) )
603 {
cf15ca10 604 gtk_button_clicked( (GtkButton*)mw->btn_orig );
1d48a247
HJYP
605 return;
606 }
607
608 if( ! btn->active )
609 {
cf15ca10 610 if( mw->zoom_mode == ZOOM_ORIG )
1d48a247
HJYP
611 gtk_toggle_button_set_active( btn, TRUE );
612 return;
613 }
cf15ca10
HJYP
614 mw->zoom_mode = ZOOM_ORIG;
615 mw->scale = 1.0;
616// gtk_scrolled_window_set_policy( (GtkScrolledWindow*)mw->scroll,
94fcf707 617// GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
1d48a247 618
cf15ca10 619 gtk_toggle_button_set_active( (GtkToggleButton*)mw->btn_fit, FALSE );
1d48a247 620
cf15ca10 621 if( ! mw->pix )
1d48a247
HJYP
622 return;
623
1c8a8ba7 624 // update scale
d8d44976 625 update_title(NULL, mw);
794cac1a 626
cf15ca10 627 image_view_set_scale( (ImageView*)mw->img_view, 1.0, GDK_INTERP_BILINEAR );
1d48a247 628
9c52ae58
HJYP
629 while (gtk_events_pending ())
630 gtk_main_iteration ();
631
cf15ca10 632 main_win_center_image( mw ); // FIXME: mw doesn't work well. Why?
1d48a247
HJYP
633}
634
f34b3b31 635void on_prev( GtkWidget* btn, MainWin* mw )
1d48a247 636{
cf15ca10
HJYP
637 const char* name;
638 if( image_list_is_empty( mw->img_list ) )
1d48a247
HJYP
639 return;
640
cf15ca10 641 name = image_list_get_prev( mw->img_list );
1d48a247 642
cf15ca10 643 if( ! name && image_list_has_multiple_files( mw->img_list ) )
1d48a247
HJYP
644 {
645 // FIXME: need to ask user first?
cf15ca10 646 name = image_list_get_last( mw->img_list );
1d48a247
HJYP
647 }
648
649 if( name )
650 {
cf15ca10
HJYP
651 char* file_path = image_list_get_current_file_path( mw->img_list );
652 main_win_open( mw, file_path, ZOOM_FIT );
1d48a247
HJYP
653 g_free( file_path );
654 }
655}
656
f34b3b31 657void on_next( GtkWidget* btn, MainWin* mw )
1d48a247 658{
cf15ca10 659 if( image_list_is_empty( mw->img_list ) )
1d48a247
HJYP
660 return;
661
cf15ca10 662 const char* name = image_list_get_next( mw->img_list );
1d48a247 663
cf15ca10 664 if( ! name && image_list_has_multiple_files( mw->img_list ) )
1d48a247
HJYP
665 {
666 // FIXME: need to ask user first?
cf15ca10 667 name = image_list_get_first( mw->img_list );
1d48a247
HJYP
668 }
669
670 if( name )
671 {
cf15ca10
HJYP
672 char* file_path = image_list_get_current_file_path( mw->img_list );
673 main_win_open( mw, file_path, ZOOM_FIT );
1d48a247
HJYP
674 g_free( file_path );
675 }
676}
677
da046c6e 678//////////////////// rotate & flip
679
680static int trans_angle_to_id(int i)
681{
682 if(i == 0) return 1;
683 else if(i == 90) return 6;
684 else if(i == 180) return 3;
685 else if(i == 270) return 8;
686 else if(i == -45) return 7;
687 else if(i == -90) return 2;
688 else if(i == -135) return 5;
ed14be05 689 else /* -180 */ return 4;
da046c6e 690}
691
692static int get_new_angle( int orig_angle, int rotate_angle )
693{
694 // defined in exif.c
695 extern int ExifRotateFlipMapping[9][9];
696 static int angle_trans_back[] = {0, 0, -90, 180, -180, -135, 90, -45, 270};
794cac1a 697
da046c6e 698 orig_angle = trans_angle_to_id(orig_angle);
699 rotate_angle = trans_angle_to_id(rotate_angle);
794cac1a 700
da046c6e 701 return angle_trans_back[ ExifRotateFlipMapping[orig_angle][rotate_angle] ];
702}
703
1c8a8ba7 704void on_rotate_auto_save( GtkWidget* btn, MainWin* mw )
aab0b120 705{
1c8a8ba7
HJYP
706 if(pref.auto_save_rotated){
707// gboolean ask_before_save = pref.ask_before_save;
708// pref.ask_before_save = FALSE;
709 on_save(btn,mw);
710// pref.ask_before_save = ask_before_save;
827117ce 711 }
aab0b120 712}
713
1c8a8ba7 714void on_rotate_clockwise( GtkWidget* btn, MainWin* mw )
1d48a247 715{
1c8a8ba7
HJYP
716 rotate_image( mw, GDK_PIXBUF_ROTATE_CLOCKWISE );
717 mw->rotation_angle = get_new_angle(mw->rotation_angle, 90);
718 on_rotate_auto_save(btn, mw);
719}
827117ce 720
1c8a8ba7
HJYP
721void on_rotate_counterclockwise( GtkWidget* btn, MainWin* mw )
722{
723 rotate_image( mw, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE );
724 mw->rotation_angle = get_new_angle(mw->rotation_angle, 270);
725 on_rotate_auto_save(btn, mw);
da046c6e 726}
727
728void on_flip_vertical( GtkWidget* btn, MainWin* mw )
729{
1c8a8ba7
HJYP
730 rotate_image( mw, -180 );
731 mw->rotation_angle = get_new_angle(mw->rotation_angle, -180);
732 on_rotate_auto_save(btn, mw);
da046c6e 733}
734
735void on_flip_horizontal( GtkWidget* btn, MainWin* mw )
736{
1c8a8ba7
HJYP
737 rotate_image( mw, -90 );
738 mw->rotation_angle = get_new_angle(mw->rotation_angle, -90);
739 on_rotate_auto_save(btn, mw);
1d48a247
HJYP
740}
741
d8d44976 742/* end of rotate & flip */
da046c6e 743
cf15ca10 744void on_save_as( GtkWidget* btn, MainWin* mw )
1d48a247 745{
701822a6
HJYP
746 char *file, *type;
747
cf15ca10 748 if( ! mw->pix )
1d48a247 749 return;
827117ce 750
7e1dcec1 751 file = get_save_filename( GTK_WINDOW(mw), image_list_get_dir( mw->img_list ), &type );
701822a6 752 if( file )
1d48a247 753 {
701822a6
HJYP
754 char* dir;
755 main_win_save( mw, file, type, TRUE );
756 dir = g_path_get_dirname(file);
757 const char* name = file + strlen(dir) + 1;
827117ce 758
701822a6 759 if( strcmp( image_list_get_dir(mw->img_list), dir ) == 0 )
1d48a247 760 {
701822a6
HJYP
761 /* if the saved file is located in the same dir */
762 /* simply add it to image list */
763 image_list_add_sorted( mw->img_list, name, TRUE );
1d48a247 764 }
701822a6 765 else /* otherwise reload the whole image list. */
1d48a247 766 {
701822a6
HJYP
767 /* switch to the dir containing the saved file. */
768 image_list_open_dir( mw->img_list, dir, NULL );
1d48a247 769 }
701822a6
HJYP
770 update_title( name, mw );
771 g_free( dir );
1c8a8ba7
HJYP
772 g_free( file );
773 g_free( type );
1d48a247 774 }
1d48a247
HJYP
775}
776
cf15ca10 777void on_save( GtkWidget* btn, MainWin* mw )
1d48a247 778{
cf15ca10 779 if( ! mw->pix )
1d48a247
HJYP
780 return;
781
cf15ca10
HJYP
782 char* file_name = g_build_filename( image_list_get_dir( mw->img_list ),
783 image_list_get_current( mw->img_list ), NULL );
1d48a247
HJYP
784 GdkPixbufFormat* info;
785 info = gdk_pixbuf_get_file_info( file_name, NULL, NULL );
786 char* type = gdk_pixbuf_format_get_name( info );
da046c6e 787
1c8a8ba7
HJYP
788 /* Confirm save if requested. */
789 if ((pref.ask_before_save) && ( ! save_confirm(mw, file_name)))
701822a6 790 return;
1c8a8ba7
HJYP
791
792 if(strcmp(type,"jpeg")==0)
da046c6e 793 {
1c8a8ba7 794 if(!pref.rotate_exif_only || ExifRotate(file_name, mw->rotation_angle) == FALSE)
da046c6e 795 {
796 // hialan notes:
794cac1a 797 // ExifRotate retrun FALSE when
da046c6e 798 // 1. Can not read file
799 // 2. Exif do not have TAG_ORIENTATION tag
800 // 3. Format unknown
794cac1a 801 // And then we apply rotate_and_save_jpeg_lossless() ,
da046c6e 802 // the result would not effected by EXIF Orientation...
7c3b160c 803#ifdef HAVE_LIBJPEG
1c8a8ba7
HJYP
804 int status = rotate_and_save_jpeg_lossless(file_name,mw->rotation_angle);
805 if(status != 0)
da046c6e 806 {
1c8a8ba7 807 main_win_show_error( mw, g_strerror(status) );
da046c6e 808 }
809#else
1c8a8ba7 810 main_win_save( mw, file_name, type, pref.ask_before_save );
7c3b160c 811#endif
da046c6e 812 }
1c8a8ba7
HJYP
813 } else
814 main_win_save( mw, file_name, type, pref.ask_before_save );
7c3b160c 815 mw->rotation_angle = 0;
1d48a247
HJYP
816 g_free( file_name );
817 g_free( type );
818}
819
cf15ca10 820void on_open( GtkWidget* btn, MainWin* mw )
1d48a247 821{
701822a6 822 char* file = get_open_filename( (GtkWindow*)mw, image_list_get_dir( mw->img_list ) );
1d48a247
HJYP
823 if( file )
824 {
cf15ca10 825 main_win_open( mw, file, ZOOM_NONE );
1d48a247
HJYP
826 g_free( file );
827 }
828}
829
cf15ca10 830void on_zoom_in( GtkWidget* btn, MainWin* mw )
1d48a247 831{
cf15ca10
HJYP
832 mw->zoom_mode = ZOOM_SCALE;
833 gtk_toggle_button_set_active( (GtkToggleButton*)mw->btn_fit, FALSE );
834 gtk_toggle_button_set_active( (GtkToggleButton*)mw->btn_orig, FALSE );
835// gtk_scrolled_window_set_policy( (GtkScrolledWindow*)mw->scroll,
94fcf707 836// GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
1d48a247 837
cf15ca10
HJYP
838 double scale = mw->scale;
839 if( mw->pix && scale < 20.0 )
1d48a247 840 {
cf15ca10 841// busy(TRUE);
9c52ae58
HJYP
842 scale *= 1.05;
843 if( scale > 20.0 )
844 scale = 20.0;
cf15ca10
HJYP
845 if( mw->scale != scale )
846 main_win_scale_image( mw, scale, GDK_INTERP_BILINEAR );
1d48a247 847// adjust_adjustment_on_zoom(oldscale);
cf15ca10 848// busy(FALSE);
1d48a247
HJYP
849 }
850}
851
cf15ca10 852void on_zoom_out( GtkWidget* btn, MainWin* mw )
1d48a247 853{
cf15ca10
HJYP
854 mw->zoom_mode = ZOOM_SCALE;
855 gtk_toggle_button_set_active( (GtkToggleButton*)mw->btn_fit, FALSE );
856 gtk_toggle_button_set_active( (GtkToggleButton*)mw->btn_orig, FALSE );
857// gtk_scrolled_window_set_policy( (GtkScrolledWindow*)mw->scroll,
94fcf707 858// GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
1d48a247 859
cf15ca10
HJYP
860 double scale = mw->scale;
861 if( mw->pix && scale > 0.02 )
1d48a247 862 {
cf15ca10 863// busy(TRUE);
da8bd946 864
9c52ae58
HJYP
865 scale /= 1.05;
866 if( scale < 0.02 )
867 scale = 0.02;
cf15ca10
HJYP
868 if( mw->scale != scale )
869 main_win_scale_image( mw, scale, GDK_INTERP_BILINEAR );
1d48a247 870// adjust_adjustment_on_zoom(oldscale);
cf15ca10 871// busy(FALSE);
1d48a247
HJYP
872 }
873}
874
cf15ca10 875void on_preference( GtkWidget* btn, MainWin* mw )
1d48a247 876{
1c8a8ba7 877 edit_preferences( (GtkWindow*)mw );
1d48a247
HJYP
878}
879
cf15ca10 880void on_quit( GtkWidget* btn, MainWin* mw )
1d48a247 881{
cf15ca10 882 gtk_widget_destroy( (GtkWidget*)mw );
1d48a247
HJYP
883}
884
cf15ca10 885gboolean on_button_press( GtkWidget* widget, GdkEventButton* evt, MainWin* mw )
1d48a247 886{
9c52ae58
HJYP
887 if( ! GTK_WIDGET_HAS_FOCUS( widget ) )
888 gtk_widget_grab_focus( widget );
5bfec971 889
1d48a247
HJYP
890 if( evt->type == GDK_BUTTON_PRESS)
891 {
892 if( evt->button == 1 ) // left button
893 {
cf15ca10 894 if( ! mw->pix )
1d48a247 895 return FALSE;
cf15ca10
HJYP
896 mw->dragging = TRUE;
897 gtk_widget_get_pointer( (GtkWidget*)mw, &mw->drag_old_x ,&mw->drag_old_y );
898 gdk_window_set_cursor( widget->window, mw->hand_cursor );
1d48a247
HJYP
899 }
900 else if( evt->button == 3 ) // right button
901 {
cf15ca10 902 show_popup_menu( mw, evt );
1d48a247
HJYP
903 }
904 }
905 else if( evt->type == GDK_2BUTTON_PRESS && evt->button == 1 ) // double clicked
906 {
1c8a8ba7 907 on_full_screen( NULL, mw );
1d48a247 908 }
1d48a247
HJYP
909 return FALSE;
910}
911
cf15ca10 912gboolean on_mouse_move( GtkWidget* widget, GdkEventMotion* evt, MainWin* mw )
1d48a247 913{
cf15ca10 914 if( ! mw->dragging )
1d48a247 915 return FALSE;
9c52ae58 916
1d48a247 917 int cur_x, cur_y;
cf15ca10 918 gtk_widget_get_pointer( (GtkWidget*)mw, &cur_x ,&cur_y );
1d48a247 919
cf15ca10
HJYP
920 int dx = (mw->drag_old_x - cur_x);
921 int dy = (mw->drag_old_y - cur_y);
1d48a247
HJYP
922
923 GtkAdjustment *hadj, *vadj;
cf15ca10
HJYP
924 hadj = gtk_scrolled_window_get_hadjustment((GtkScrolledWindow*)mw->scroll);
925 vadj = gtk_scrolled_window_get_vadjustment((GtkScrolledWindow*)mw->scroll);
1d48a247 926
9c52ae58 927 GtkRequisition req;
cf15ca10 928 gtk_widget_size_request( (GtkWidget*)mw->img_view, &req );
1d48a247
HJYP
929
930 if( ABS(dx) > 4 )
931 {
cf15ca10 932 mw->drag_old_x = cur_x;
9c52ae58 933 if( req.width > hadj->page_size )
1d48a247
HJYP
934 {
935 gdouble x = gtk_adjustment_get_value (hadj) + dx;
936 if( x < hadj->lower )
937 x = hadj->lower;
938 else if( (x + hadj->page_size) > hadj->upper )
939 x = hadj->upper - hadj->page_size;
940
941 if( x != hadj->value )
942 gtk_adjustment_set_value (hadj, x );
943 }
944 }
945
946 if( ABS(dy) > 4 )
947 {
9c52ae58 948 if( req.height > vadj->page_size )
1d48a247 949 {
cf15ca10 950 mw->drag_old_y = cur_y;
1d48a247
HJYP
951 gdouble y = gtk_adjustment_get_value (vadj) + dy;
952 if( y < vadj->lower )
953 y = vadj->lower;
954 else if( (y + vadj->page_size) > vadj->upper )
955 y = vadj->upper - vadj->page_size;
956
957 if( y != vadj->value )
958 gtk_adjustment_set_value (vadj, y );
959 }
960 }
961 return FALSE;
962}
963
cf15ca10 964gboolean on_button_release( GtkWidget* widget, GdkEventButton* evt, MainWin* mw )
1d48a247 965{
cf15ca10 966 mw->dragging = FALSE;
1d48a247
HJYP
967 gdk_window_set_cursor( widget->window, NULL );
968 return FALSE;
969}
970
cf15ca10 971gboolean on_scroll_event( GtkWidget* widget, GdkEventScroll* evt, MainWin* mw )
5bfec971 972{
58e1b106 973 guint modifiers = gtk_accelerator_get_default_mod_mask();
5bfec971
HJYP
974 switch( evt->direction )
975 {
976 case GDK_SCROLL_UP:
58e1b106
JH
977 if ((evt->state & modifiers) == GDK_CONTROL_MASK)
978 on_zoom_in( NULL, mw );
979 else
980 on_prev( NULL, mw );
5bfec971
HJYP
981 break;
982 case GDK_SCROLL_DOWN:
58e1b106
JH
983 if ((evt->state & modifiers) == GDK_CONTROL_MASK)
984 on_zoom_out( NULL, mw );
985 else
986 on_next( NULL, mw );
5bfec971
HJYP
987 break;
988 case GDK_SCROLL_LEFT:
1c8a8ba7
HJYP
989 if( gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL )
990 on_next( NULL, mw );
991 else
992 on_prev( NULL, mw );
5bfec971
HJYP
993 break;
994 case GDK_SCROLL_RIGHT:
1c8a8ba7
HJYP
995 if( gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL )
996 on_prev( NULL, mw );
997 else
998 on_next( NULL, mw );
5bfec971
HJYP
999 break;
1000 }
da8bd946 1001 return TRUE;
5bfec971
HJYP
1002}
1003
cf15ca10 1004gboolean on_key_press_event(GtkWidget* widget, GdkEventKey * key)
1d48a247 1005{
cf15ca10 1006 MainWin* mw = (MainWin*)widget;
1d48a247
HJYP
1007 switch( key->keyval )
1008 {
7c3b160c
HJYP
1009 case GDK_Right:
1010 case GDK_KP_Right:
1011 case GDK_rightarrow:
1c8a8ba7
HJYP
1012 if( gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL )
1013 on_prev( NULL, mw );
1014 else
1015 on_next( NULL, mw );
1016 break;
1d48a247
HJYP
1017 case GDK_Return:
1018 case GDK_space:
1019 case GDK_Next:
5bfec971
HJYP
1020 case GDK_KP_Down:
1021 case GDK_Down:
1022 case GDK_downarrow:
cf15ca10 1023 on_next( NULL, mw );
1d48a247 1024 break;
7c3b160c
HJYP
1025 case GDK_Left:
1026 case GDK_KP_Left:
1027 case GDK_leftarrow:
1c8a8ba7
HJYP
1028 if( gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL )
1029 on_next( NULL, mw );
1030 else
1031 on_prev( NULL, mw );
1032 break;
1d48a247
HJYP
1033 case GDK_Prior:
1034 case GDK_BackSpace:
5bfec971
HJYP
1035 case GDK_KP_Up:
1036 case GDK_Up:
1037 case GDK_uparrow:
cf15ca10 1038 on_prev( NULL, mw );
1d48a247
HJYP
1039 break;
1040 case GDK_KP_Add:
1041 case GDK_plus:
641adad3 1042 case GDK_equal:
cf15ca10 1043 on_zoom_in( NULL, mw );
1d48a247
HJYP
1044 break;
1045 case GDK_KP_Subtract:
1046 case GDK_minus:
cf15ca10 1047 on_zoom_out( NULL, mw );
1d48a247 1048 break;
1d48a247 1049 case GDK_s:
d8d44976 1050 case GDK_S:
cf15ca10 1051 on_save( NULL, mw );
1d48a247 1052 break;
c9c60499 1053 case GDK_a:
1054 case GDK_A:
1055 on_save_as( NULL, mw );
1056 break;
1d48a247 1057 case GDK_l:
d8d44976 1058 case GDK_L:
cf15ca10 1059 on_rotate_counterclockwise( NULL, mw );
1d48a247
HJYP
1060 break;
1061 case GDK_r:
d8d44976 1062 case GDK_R:
cf15ca10 1063 on_rotate_clockwise( NULL, mw );
1d48a247
HJYP
1064 break;
1065 case GDK_f:
d8d44976 1066 case GDK_F:
cf15ca10
HJYP
1067 if( mw->zoom_mode != ZOOM_FIT )
1068 gtk_button_clicked((GtkButton*)mw->btn_fit );
1d48a247
HJYP
1069 break;
1070 case GDK_g:
d8d44976 1071 case GDK_G:
cf15ca10
HJYP
1072 if( mw->zoom_mode != ZOOM_ORIG )
1073 gtk_button_clicked((GtkButton*)mw->btn_orig );
1d48a247 1074 break;
d8d44976
HJYP
1075 case GDK_h:
1076 case GDK_H:
1077 on_flip_horizontal( NULL, mw );
1078 break;
1079 case GDK_v:
1080 case GDK_V:
1081 on_flip_vertical( NULL, mw );
1082 break;
1d48a247 1083 case GDK_o:
d8d44976 1084 case GDK_O:
cf15ca10 1085 on_open( NULL, mw );
5bfec971
HJYP
1086 break;
1087 case GDK_Delete:
1088 case GDK_d:
d8d44976 1089 case GDK_D:
cf15ca10 1090 on_delete( NULL, mw );
1d48a247 1091 break;
d8d44976
HJYP
1092 case GDK_p:
1093 case GDK_P:
1094 on_preference( NULL, mw );
1c8a8ba7 1095 break;
1d48a247 1096 case GDK_Escape:
cf15ca10
HJYP
1097 if( mw->full_screen )
1098 on_full_screen( NULL, mw );
1d48a247 1099 else
cf15ca10 1100 on_quit( NULL, mw );
1d48a247 1101 break;
1c8a8ba7 1102 case GDK_q:
f7401dea 1103 case GDK_Q:
1c8a8ba7
HJYP
1104 on_quit( NULL, mw );
1105 break;
1d48a247 1106 case GDK_F11:
cf15ca10 1107 on_full_screen( NULL, mw );
1d48a247
HJYP
1108 break;
1109
1110 default:
cf15ca10 1111 GTK_WIDGET_CLASS(main_win_parent_class)->key_press_event( widget, key );
1d48a247
HJYP
1112 }
1113 return FALSE;
1114}
1115
cf15ca10 1116void main_win_center_image( MainWin* mw )
1d48a247
HJYP
1117{
1118 GtkAdjustment *hadj, *vadj;
cf15ca10
HJYP
1119 hadj = gtk_scrolled_window_get_hadjustment((GtkScrolledWindow*)mw->scroll);
1120 vadj = gtk_scrolled_window_get_vadjustment((GtkScrolledWindow*)mw->scroll);
1d48a247 1121
9c52ae58 1122 GtkRequisition req;
cf15ca10 1123 gtk_widget_size_request( (GtkWidget*)mw->img_view, &req );
1d48a247 1124
9c52ae58
HJYP
1125 if( req.width > hadj->page_size )
1126 gtk_adjustment_set_value(hadj, ( hadj->upper - hadj->page_size ) / 2 );
1d48a247 1127
9c52ae58
HJYP
1128 if( req.height > vadj->page_size )
1129 gtk_adjustment_set_value(vadj, ( vadj->upper - vadj->page_size ) / 2 );
1d48a247
HJYP
1130}
1131
da046c6e 1132void rotate_image( MainWin* mw, int angle )
1d48a247 1133{
da046c6e 1134 GdkPixbuf* rpix = NULL;
1135
cf15ca10 1136 if( ! mw->pix )
1d48a247
HJYP
1137 return;
1138
da046c6e 1139 if(angle > 0)
1140 {
1141 rpix = gdk_pixbuf_rotate_simple( mw->pix, angle );
1142 }
1143 else
1144 {
1145 if(angle == -90)
1146 rpix = gdk_pixbuf_flip( mw->pix, TRUE );
1147 else if(angle == -180)
1148 rpix = gdk_pixbuf_flip( mw->pix, FALSE );
1149 }
1c8a8ba7
HJYP
1150
1151 if (!rpix) {
1152 return;
1153 }
1154
cf15ca10 1155 g_object_unref( mw->pix );
794cac1a 1156
cf15ca10 1157 mw->pix = rpix;
0c0c8179 1158 image_view_set_pixbuf( (ImageView*)mw->img_view, mw->pix );
1d48a247 1159
cf15ca10 1160 if( mw->zoom_mode == ZOOM_FIT )
c325c989 1161 main_win_fit_window_size( mw, FALSE, GDK_INTERP_BILINEAR );
1d48a247
HJYP
1162}
1163
cf15ca10 1164gboolean main_win_scale_image( MainWin* mw, double new_scale, GdkInterpType type )
1d48a247
HJYP
1165{
1166 if( G_UNLIKELY( new_scale == 1.0 ) )
1167 {
cf15ca10 1168 gtk_toggle_button_set_active( (GtkToggleButton*)mw->btn_orig, TRUE );
da046c6e 1169 mw->scale = 1.0;
cf15ca10 1170 return TRUE;
1d48a247 1171 }
cf15ca10 1172 mw->scale = new_scale;
0c0c8179 1173 image_view_set_scale( (ImageView*)mw->img_view, new_scale, type );
794cac1a 1174
d8d44976 1175 update_title( NULL, mw );
794cac1a 1176
cf15ca10 1177 return TRUE;
1d48a247
HJYP
1178}
1179
1c8a8ba7 1180gboolean save_confirm( MainWin* mw, const char* file_path )
aab0b120 1181{
1c8a8ba7
HJYP
1182 if( g_file_test( file_path, G_FILE_TEST_EXISTS ) )
1183 {
1184 GtkWidget* dlg = gtk_message_dialog_new( (GtkWindow*)mw,
1185 GTK_DIALOG_MODAL,
1186 GTK_MESSAGE_QUESTION,
1187 GTK_BUTTONS_YES_NO,
1188 _("The file name you selected already exists.\nDo you want to overwrite existing file?\n(Warning: The quality of original image might be lost)") );
1189 if( gtk_dialog_run( (GtkDialog*)dlg ) != GTK_RESPONSE_YES )
827117ce 1190 {
827117ce 1191 gtk_widget_destroy( dlg );
1c8a8ba7 1192 return FALSE;
827117ce 1193 }
1c8a8ba7 1194 gtk_widget_destroy( dlg );
827117ce 1195 }
1c8a8ba7
HJYP
1196 return TRUE;
1197}
1198
1199gboolean main_win_save( MainWin* mw, const char* file_path, const char* type, gboolean confirm )
1200{
1201 gboolean result1,gdk_save_supported;
1202 GSList *gdk_formats;
1203 GSList *gdk_formats_i;
1204 if( ! mw->pix )
1205 return FALSE;
827117ce 1206
1c8a8ba7 1207 /* detect if the current type can be save by gdk_pixbuf_save() */
3d62c4bb
YCLP
1208 gdk_save_supported = FALSE;
1209 gdk_formats = gdk_pixbuf_get_formats();
1210 for (gdk_formats_i = gdk_formats; gdk_formats_i;
1211 gdk_formats_i = g_slist_next(gdk_formats_i))
1212 {
1213 GdkPixbufFormat *data;
1214 data = gdk_formats_i->data;
1215 if (gdk_pixbuf_format_is_writable(data))
1216 {
1217 if ( strcmp(type, gdk_pixbuf_format_get_name(data))==0)
1218 {
1219 gdk_save_supported = TRUE;
1220 break;
1221 }
1222 }
1223 }
1224 g_slist_free (gdk_formats);
1225
1d48a247 1226 GError* err = NULL;
3d62c4bb
YCLP
1227 if (!gdk_save_supported)
1228 {
701822a6 1229 main_win_show_error( mw, _("Writing this image format is not supported.") );
3d62c4bb
YCLP
1230 return FALSE;
1231 }
701822a6
HJYP
1232 if( strcmp( type, "jpeg" ) == 0 )
1233 {
1234 char tmp[32];
1235 g_sprintf(tmp, "%d", pref.jpg_quality);
1236 result1 = gdk_pixbuf_save( mw->pix, file_path, type, &err, "quality", tmp, NULL );
1237 }
1238 else if( strcmp( type, "png" ) == 0 )
1239 {
1240 char tmp[32];
1241 g_sprintf(tmp, "%d", pref.png_compression);
1242 result1 = gdk_pixbuf_save( mw->pix, file_path, type, &err, "compression", tmp, NULL );
1243 }
1244 else
1245 result1 = gdk_pixbuf_save( mw->pix, file_path, type, &err, NULL );
3d62c4bb 1246 if( ! result1 )
1d48a247 1247 {
cf15ca10
HJYP
1248 main_win_show_error( mw, err->message );
1249 return FALSE;
1d48a247 1250 }
cf15ca10 1251 return TRUE;
1d48a247
HJYP
1252}
1253
cf15ca10 1254void on_delete( GtkWidget* btn, MainWin* mw )
1d48a247 1255{
cf15ca10 1256 char* file_path = image_list_get_current_file_path( mw->img_list );
1d48a247
HJYP
1257 if( file_path )
1258 {
f7401dea 1259 int resp = GTK_RESPONSE_YES;
1260 if ( pref.ask_before_delete )
1261 {
1262 GtkWidget* dlg = gtk_message_dialog_new( (GtkWindow*)mw,
1263 GTK_DIALOG_MODAL,
1264 GTK_MESSAGE_QUESTION,
1265 GTK_BUTTONS_YES_NO,
1266 _("Are you sure you want to delete current file?\n\nWarning: Once deleted, the file cannot be recovered.") );
1267 resp = gtk_dialog_run( (GtkDialog*)dlg );
1268 gtk_widget_destroy( dlg );
1269 }
1d48a247 1270
f7401dea 1271 if( resp == GTK_RESPONSE_YES )
1d48a247 1272 {
fa27691a 1273 const char* name = image_list_get_current( mw->img_list );
794cac1a 1274
fa27691a
HJYP
1275 if( g_unlink( file_path ) != 0 )
1276 main_win_show_error( mw, g_strerror(errno) );
1277 else
1278 {
1279 const char* next_name = image_list_get_next( mw->img_list );
1280 if( ! next_name )
1281 next_name = image_list_get_prev( mw->img_list );
794cac1a 1282
fa27691a
HJYP
1283 if( next_name )
1284 {
1285 char* next_file_path = image_list_get_current_file_path( mw->img_list );
1286 main_win_open( mw, next_file_path, ZOOM_FIT );
1287 g_free( next_file_path );
1288 }
1289
1290 image_list_remove ( mw->img_list, name );
1291
1292 if ( ! next_name )
1c8a8ba7
HJYP
1293 {
1294 main_win_close( mw );
f7401dea 1295 image_list_close( mw->img_list );
1c8a8ba7
HJYP
1296 image_view_set_pixbuf( (ImageView*)mw->img_view, NULL );
1297 gtk_window_set_title( (GtkWindow*) mw, _("Image Viewer"));
1298 }
fa27691a 1299 }
1d48a247 1300 }
fa27691a 1301 g_free( file_path );
1d48a247
HJYP
1302 }
1303}
1304
cf15ca10 1305void show_popup_menu( MainWin* mw, GdkEventButton* evt )
1d48a247 1306{
5bfec971
HJYP
1307 static PtkMenuItemEntry menu_def[] =
1308 {
1309 PTK_IMG_MENU_ITEM( N_( "Previous" ), GTK_STOCK_GO_BACK, on_prev, GDK_leftarrow, 0 ),
1310 PTK_IMG_MENU_ITEM( N_( "Next" ), GTK_STOCK_GO_FORWARD, on_next, GDK_rightarrow, 0 ),
1311 PTK_SEPARATOR_MENU_ITEM,
1312 PTK_IMG_MENU_ITEM( N_( "Zoom Out" ), GTK_STOCK_ZOOM_OUT, on_zoom_out, GDK_minus, 0 ),
1313 PTK_IMG_MENU_ITEM( N_( "Zoom In" ), GTK_STOCK_ZOOM_IN, on_zoom_in, GDK_plus, 0 ),
1314 PTK_IMG_MENU_ITEM( N_( "Fit Image To Window Size" ), GTK_STOCK_ZOOM_FIT, on_zoom_fit_menu, GDK_F, 0 ),
1315 PTK_IMG_MENU_ITEM( N_( "Original Size" ), GTK_STOCK_ZOOM_100, on_orig_size_menu, GDK_G, 0 ),
1316 PTK_SEPARATOR_MENU_ITEM,
0c8ac162 1317 PTK_IMG_MENU_ITEM( N_( "Full Screen" ), GTK_STOCK_FULLSCREEN, on_full_screen, GDK_F11, 0 ),
5bfec971 1318 PTK_SEPARATOR_MENU_ITEM,
701822a6
HJYP
1319 PTK_IMG_MENU_ITEM( N_( "Rotate Counterclockwise" ), "object-rotate-left", on_rotate_counterclockwise, GDK_L, 0 ),
1320 PTK_IMG_MENU_ITEM( N_( "Rotate Clockwise" ), "object-rotate-right", on_rotate_clockwise, GDK_R, 0 ),
1321 PTK_IMG_MENU_ITEM( N_( "Flip Horizontal" ), "object-flip-horizontal", on_flip_horizontal, GDK_H, 0 ),
1322 PTK_IMG_MENU_ITEM( N_( "Flip Vertical" ), "object-flip-vertical", on_flip_vertical, GDK_V, 0 ),
5bfec971
HJYP
1323 PTK_SEPARATOR_MENU_ITEM,
1324 PTK_IMG_MENU_ITEM( N_("Open File"), GTK_STOCK_OPEN, G_CALLBACK(on_open), GDK_O, 0 ),
1325 PTK_IMG_MENU_ITEM( N_("Save File"), GTK_STOCK_SAVE, G_CALLBACK(on_save), GDK_S, 0 ),
1326 PTK_IMG_MENU_ITEM( N_("Save As"), GTK_STOCK_SAVE_AS, G_CALLBACK(on_save_as), GDK_A, 0 ),
da046c6e 1327// PTK_IMG_MENU_ITEM( N_("Save As Other Size"), GTK_STOCK_SAVE_AS, G_CALLBACK(on_save_as), GDK_A, 0 ),
5bfec971
HJYP
1328 PTK_IMG_MENU_ITEM( N_("Delete File"), GTK_STOCK_DELETE, G_CALLBACK(on_delete), GDK_Delete, 0 ),
1329 PTK_SEPARATOR_MENU_ITEM,
1c8a8ba7 1330 PTK_IMG_MENU_ITEM( N_("Preferences"), GTK_STOCK_PREFERENCES, G_CALLBACK(on_preference), GDK_P, 0 ),
1c8a8ba7 1331 PTK_STOCK_MENU_ITEM( GTK_STOCK_ABOUT, on_about ),
701822a6
HJYP
1332 PTK_SEPARATOR_MENU_ITEM,
1333 PTK_IMG_MENU_ITEM( N_("Quit"), GTK_STOCK_QUIT, G_CALLBACK(on_quit), GDK_Q, 0 ),
5bfec971
HJYP
1334 PTK_MENU_END
1335 };
07db5c2f
HJYP
1336 GtkWidget* rotate_cw;
1337 GtkWidget* rotate_ccw;
1338 GtkWidget* flip_v;
1339 GtkWidget* flip_h;
1340
1341 menu_def[10].ret = &rotate_ccw;
1342 menu_def[11].ret = &rotate_cw;
1343 menu_def[12].ret = &flip_h;
1344 menu_def[13].ret = &flip_v;
5bfec971 1345
cf15ca10 1346 // mw accel group is useless. It's only used to display accels in popup menu
5bfec971 1347 GtkAccelGroup* accel_group = gtk_accel_group_new();
cf15ca10 1348 GtkMenuShell* popup = (GtkMenuShell*)ptk_menu_new_from_data( menu_def, mw, accel_group );
1d48a247 1349
07db5c2f
HJYP
1350 if( mw->animation )
1351 {
1352 gtk_widget_set_sensitive( rotate_ccw, FALSE );
1353 gtk_widget_set_sensitive( rotate_cw, FALSE );
1354 gtk_widget_set_sensitive( flip_h, FALSE );
1355 gtk_widget_set_sensitive( flip_v, FALSE );
1356 }
1357
1d48a247
HJYP
1358 gtk_widget_show_all( (GtkWidget*)popup );
1359 g_signal_connect( popup, "selection-done", G_CALLBACK(gtk_widget_destroy), NULL );
1360 gtk_menu_popup( (GtkMenu*)popup, NULL, NULL, NULL, NULL, evt->button, evt->time );
1361}
1362
1c8a8ba7 1363/* callback used to open default browser when URLs got clicked */
7c3b160c 1364static void open_url( GtkAboutDialog *dlg, const gchar *url, gpointer data)
1d48a247 1365{
1c8a8ba7 1366 /* FIXME: is there any better way to do this? */
7e1dcec1 1367 char* programs[] = { "xdg-open", "gnome-open", "exo-open" };
7c3b160c
HJYP
1368 int i;
1369 for( i = 0; i < G_N_ELEMENTS(programs); ++i)
1d48a247 1370 {
d8d44976 1371 gchar* open_cmd = NULL;
7c3b160c 1372 if( (open_cmd = g_find_program_in_path( programs[i] )) )
1d48a247 1373 {
d8d44976 1374 char* argv [3];
ff032ffe 1375 argv [0] = programs[i];
1c8a8ba7
HJYP
1376 argv [1] = (gchar *) url;
1377 argv [2] = NULL;
794cac1a 1378 g_spawn_async (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL);
7c3b160c
HJYP
1379 g_free( open_cmd );
1380 break;
1d48a247 1381 }
1c8a8ba7 1382 }
1d48a247
HJYP
1383}
1384
cf15ca10 1385void on_about( GtkWidget* menu, MainWin* mw )
1d48a247
HJYP
1386{
1387 GtkWidget * about_dlg;
1388 const gchar *authors[] =
1389 {
1390 "洪任諭 Hong Jen Yee <pcman.tw@gmail.com>",
7c3b160c 1391 "Martin Siggel <martinsiggel@googlemail.com>",
da046c6e 1392 "Hialan Liu <hialan.liu@gmail.com>",
d8d44976
HJYP
1393 "Marty Jack <martyj19@comcast.net>",
1394 "Louis Casillas <oxaric@gmail.com>",
7c3b160c 1395 _(" * Refer to source code of EOG image viewer and GThumb"),
1d48a247
HJYP
1396 NULL
1397 };
1c8a8ba7 1398 /* TRANSLATORS: Replace this string with your names, one name per line. */
1d48a247
HJYP
1399 gchar *translators = _( "translator-credits" );
1400
7c3b160c
HJYP
1401 gtk_about_dialog_set_url_hook( open_url, mw, NULL);
1402
1d48a247 1403 about_dlg = gtk_about_dialog_new ();
7c3b160c
HJYP
1404
1405 gtk_container_set_border_width ( ( GtkContainer*)about_dlg , 2 );
1406 gtk_about_dialog_set_version ( (GtkAboutDialog*)about_dlg, VERSION );
1407 gtk_about_dialog_set_name ( (GtkAboutDialog*)about_dlg, _( "GPicView" ) );
1408 gtk_about_dialog_set_logo( (GtkAboutDialog*)about_dlg, gdk_pixbuf_new_from_file( PACKAGE_DATA_DIR"/pixmaps/gpicview.png", NULL ) );
701822a6 1409 gtk_about_dialog_set_copyright ( (GtkAboutDialog*)about_dlg, _( "Copyright (C) 2007 - 2009" ) );
7c3b160c 1410 gtk_about_dialog_set_comments ( (GtkAboutDialog*)about_dlg, _( "Lightweight image viewer from LXDE project" ) );
1c8a8ba7 1411 gtk_about_dialog_set_license ( (GtkAboutDialog*)about_dlg, "GPicView\n\nCopyright (C) 2007 Hong Jen Yee (PCMan)\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA." );
d8d44976 1412 gtk_about_dialog_set_website ( (GtkAboutDialog*)about_dlg, "http://wiki.lxde.org/en/GPicView" );
7c3b160c
HJYP
1413 gtk_about_dialog_set_authors ( (GtkAboutDialog*)about_dlg, authors );
1414 gtk_about_dialog_set_translator_credits ( (GtkAboutDialog*)about_dlg, translators );
1415 gtk_window_set_transient_for( (GtkWindow*) about_dlg, GTK_WINDOW( mw ) );
1416
1417 gtk_dialog_run( ( GtkDialog*)about_dlg );
1d48a247
HJYP
1418 gtk_widget_destroy( about_dlg );
1419}
1420
cf15ca10
HJYP
1421void on_drag_data_received( GtkWidget* widget, GdkDragContext *drag_context,
1422 int x, int y, GtkSelectionData* data, guint info, guint time, MainWin* mw )
1d48a247
HJYP
1423{
1424 if( ! data || data->length <= 0)
1425 return;
1426
1d48a247
HJYP
1427 char* file = NULL;
1428 if( info == 0 ) // text/uri-list
1429 {
1430 char** uris = gtk_selection_data_get_uris( data );
1431 if( uris )
1432 {
1433 file = g_filename_from_uri(*uris, NULL, NULL);
1434 g_strfreev( uris );
1435 }
1436 }
1437 else if( info == 1 ) // text/plain
1438 {
1439 file = (char*)gtk_selection_data_get_text( data );
1440 }
1441 if( file )
1442 {
cf15ca10 1443 main_win_open( mw, file, ZOOM_FIT );
1d48a247
HJYP
1444 g_free( file );
1445 }
1446}