126
117
gtk_main_iteration();
120
void img_remove_audio_files (GtkWidget *widget, img_window_struct *img)
122
GtkTreeSelection *sel;
125
GList *rr_list = NULL;
130
sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(img->music_file_treeview));
131
gtk_tree_selection_selected_foreach(sel, (GtkTreeSelectionForeachFunc) img_remove_foreach_func, &rr_list);
133
for (node = rr_list; node != NULL; node = node->next)
135
path = gtk_tree_row_reference_get_path((GtkTreeRowReference *) node->data);
138
if (gtk_tree_model_get_iter(GTK_TREE_MODEL(img->music_file_liststore), &iter, path))
140
gtk_tree_model_get(GTK_TREE_MODEL(img->music_file_liststore), &iter, 3, &secs, -1);
141
gtk_list_store_remove(img->music_file_liststore, &iter);
143
gtk_tree_path_free(path);
145
img->total_music_secs -= secs;
147
if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(img->music_file_liststore), &iter) == FALSE)
149
gtk_widget_set_sensitive (img->remove_audio_button, FALSE);
150
gtk_widget_set_sensitive (img->play_audio_button, FALSE);
151
gtk_label_set_text(GTK_LABEL(img->music_time_data), "");
155
time = img_convert_seconds_to_time(img->total_music_secs);
156
gtk_label_set_text(GTK_LABEL(img->music_time_data), time);
159
g_list_foreach(rr_list, (GFunc) gtk_tree_row_reference_free, NULL);
160
g_list_free(rr_list);
163
void img_remove_foreach_func (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GList **rowref_list)
165
GtkTreeRowReference *rowref;
167
rowref = gtk_tree_row_reference_new(model, path);
168
*rowref_list = g_list_append(*rowref_list, rowref);
171
void img_select_audio_files_to_add ( GtkMenuItem* button, img_window_struct *img)
173
GtkFileFilter *audio_filter, *all_files_filter;
175
GSList *files = NULL;
179
fs = gtk_file_chooser_dialog_new (_("Please choose the audio files to import"),
180
GTK_WINDOW (img->imagination_window),
181
GTK_FILE_CHOOSER_ACTION_OPEN,
188
/* only audio files filter */
189
audio_filter = gtk_file_filter_new ();
190
gtk_file_filter_set_name (audio_filter, _("All audio files") );
191
gtk_file_filter_add_pattern (audio_filter, "*.wav");
192
gtk_file_filter_add_pattern (audio_filter, "*.mp3");
193
gtk_file_filter_add_pattern (audio_filter, "*.ogg");
194
gtk_file_filter_add_pattern (audio_filter, "*.flac");
195
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (fs), audio_filter);
197
/* All files filter */
198
all_files_filter = gtk_file_filter_new ();
199
gtk_file_filter_set_name(all_files_filter, _("All files"));
200
gtk_file_filter_add_pattern(all_files_filter, "*");
201
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fs), all_files_filter);
203
gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (fs), TRUE);
205
response = gtk_dialog_run (GTK_DIALOG (fs));
206
if (response == GTK_RESPONSE_ACCEPT)
208
files = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (fs));
209
g_slist_foreach( files, (GFunc) img_add_audio_files, img);
212
g_slist_free (files);
214
time = img_convert_seconds_to_time(img->total_music_secs);
215
gtk_label_set_text(GTK_LABEL(img->music_time_data), time);
218
gtk_widget_destroy (fs);
221
void img_add_audio_files (gchar *filename, img_window_struct *img)
224
gchar *path, *file, *time;
227
path = g_path_get_dirname(filename);
228
file = g_path_get_basename(filename);
229
time = img_get_audio_length(img, filename, &secs);
233
gtk_list_store_append(img->music_file_liststore, &iter);
234
gtk_list_store_set (img->music_file_liststore, &iter, 0, path, 1, file, 2, time, 3, secs, -1);
236
img->total_music_secs += secs;
129
244
GSList *img_import_slides_file_chooser(img_window_struct *img)
131
246
GtkFileFilter *all_images_filter, *all_files_filter;
794
953
if (img->project_is_modified)
796
if (GTK_RESPONSE_OK != img_ask_user_confirmation(img))
955
if (GTK_RESPONSE_OK != img_ask_user_confirmation(img, _("You didn't save your slideshow yet. Are you sure you want to close it?")))
800
958
img_free_allocated_memory(img);
801
img_set_buttons_state(img, FALSE);
802
959
img_set_window_title(img,NULL);
803
960
img_set_statusbar_message(img,0);
804
961
gtk_image_set_from_pixbuf(GTK_IMAGE(img->image_area),NULL);
962
gtk_widget_set_sensitive(img->random_button, FALSE);
963
gtk_widget_set_sensitive(img->transition_type, FALSE);
964
gtk_widget_set_sensitive(img->duration, FALSE);
805
965
gtk_widget_hide(img->thumb_scrolledwindow);
808
void img_start_stop_export(GtkWidget *widget, img_window_struct *img)
814
/* If we are displaying preview, abort or bad things will happen. */
815
if(img->preview_is_running)
818
model = gtk_icon_view_get_model(GTK_ICON_VIEW(img->thumbnail_iconview));
819
if(!gtk_tree_model_get_iter_first(model, &iter))
822
if(img->export_is_running)
824
/* Remove idle function from main loop */
825
g_source_remove(img->source_id);
827
/* Clean resources used by export. */
828
img_clean_after_export(img);
833
GtkWidget *vbox, *hbox;
839
if(!img_run_encoder(img))
842
/* Create progress window with cancel and pause buttons, calculate
843
* the total number of frames to display. */
844
dialog = gtk_window_new( GTK_WINDOW_TOPLEVEL );
845
img->export_dialog = dialog;
846
gtk_window_set_title (GTK_WINDOW(img->export_dialog),_("Exporting the slideshow"));
847
gtk_container_set_border_width( GTK_CONTAINER( dialog ), 10 );
848
gtk_window_set_default_size( GTK_WINDOW( dialog ), 400, -1 );
849
gtk_window_set_type_hint( GTK_WINDOW( dialog ),
850
GDK_WINDOW_TYPE_HINT_DIALOG );
851
gtk_window_set_modal( GTK_WINDOW( dialog ), TRUE );
852
gtk_window_set_transient_for( GTK_WINDOW( dialog ),
853
GTK_WINDOW( img->imagination_window ) );
855
vbox = gtk_vbox_new( FALSE, 6 );
856
gtk_container_add( GTK_CONTAINER( dialog ), vbox );
858
label = gtk_label_new( _("Preparing for export ...") );
859
gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
860
img->export_label = label;
861
gtk_box_pack_start( GTK_BOX( vbox ), label, FALSE, FALSE, 0 );
863
progress = gtk_progress_bar_new();
864
img->export_pbar1 = progress;
865
string = g_strdup_printf( "%.2f", .0 );
866
gtk_progress_bar_set_text( GTK_PROGRESS_BAR( progress ), string );
867
gtk_box_pack_start( GTK_BOX( vbox ), progress, FALSE, FALSE, 0 );
869
label = gtk_label_new( _("Overall progress:") );
870
gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
871
gtk_box_pack_start( GTK_BOX( vbox ), label, FALSE, FALSE, 0 );
873
progress = gtk_progress_bar_new();
874
img->export_pbar2 = progress;
875
gtk_progress_bar_set_text( GTK_PROGRESS_BAR( progress ), string );
876
gtk_box_pack_start( GTK_BOX( vbox ), progress, FALSE, FALSE, 0 );
879
hbox = gtk_hbox_new( TRUE, 6 );
880
gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 );
882
button = gtk_button_new_from_stock( GTK_STOCK_CANCEL );
883
g_signal_connect( G_OBJECT( button ), "clicked",
884
G_CALLBACK( img_start_stop_export ), img );
885
gtk_box_pack_end( GTK_BOX( hbox ), button, FALSE, FALSE, 0 );
887
button = gtk_toggle_button_new_with_label( GTK_STOCK_MEDIA_PAUSE );
888
gtk_button_set_use_stock( GTK_BUTTON( button ), TRUE );
889
g_signal_connect( G_OBJECT( button ), "toggled",
890
G_CALLBACK( img_export_pause_unpause ), img );
891
gtk_box_pack_end( GTK_BOX( hbox ), button, FALSE, FALSE, 0 );
893
gtk_widget_show_all( dialog );
895
/* Display some visual feedback */
896
while( gtk_events_pending() )
897
gtk_main_iteration();
899
img->slide_pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(img->image_area));
900
if(img->slide_pixbuf)
901
g_object_ref(G_OBJECT(img->slide_pixbuf));
902
gtk_image_clear(GTK_IMAGE(img->image_area));
903
gtk_widget_set_app_paintable(img->image_area, TRUE);
904
g_signal_connect(G_OBJECT(img->image_area), "expose-event", G_CALLBACK(img_on_expose_event), img);
906
/* Create an empty pixbuf for starting image. */
907
img->pixbuf1 = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, img->image_area->allocation.width, img->image_area->allocation.height);
908
gdk_pixbuf_fill(img->pixbuf1, img->background_color);
910
/* Load first image from model */
911
gtk_tree_model_get(model, &iter, 1, &entry, -1);
912
img->pixbuf2 = img_scale_pixbuf(img, entry->filename);
914
/* Add export idle function and set initial values */
915
img->export_is_running = TRUE;
916
img->current_slide = entry;
918
img->export_frame_nr = img->total_secs * EXPORT_FPS;
919
img->export_frame_cur = 0;
920
/* Fix for the wrong progress bar indicators. */
921
img_export_calc_slide_frames( img );
923
img->export_slide = 1;
924
img->export_idle_func = (GSourceFunc)img_export_transition;
925
img->source_id = g_idle_add((GSourceFunc)img_export_transition, img);
927
string = g_strdup_printf( _("Slide %d export progress:"), 1 );
928
/* I did this for the translators. ^^ */
929
gtk_label_set_label( GTK_LABEL( img->export_label ), string );
934
static gboolean img_export_transition(img_window_struct *img)
937
gdouble export_progress;
939
/* If no transition effect is set, just connect still export
940
* idle function and remove itself from main loop. */
941
if(img->current_slide->render == NULL)
943
img->source_id = g_idle_add((GSourceFunc)img_export_still, img);
947
/* Switch to still export phase if progress reached 1. */
948
img->progress += (gdouble)1 / ( img->current_slide->speed * EXPORT_FPS );
949
if(img->progress > 1.00000005)
952
img->export_idle_func = (GSourceFunc)img_export_still;
953
img->source_id = g_idle_add((GSourceFunc)img_export_still, img);
958
/* Draw one frame of transition animation */
959
img->current_slide->render(img->image_area->window, img->pixbuf1, img->pixbuf2, img->progress, img->file_desc);
961
/* Increment global frame counters and update progress bars */
962
img->export_frame_cur++;
963
img->export_slide_cur++;
965
export_progress = (gdouble)img->export_slide_cur / img->export_slide_nr;
966
snprintf( string, 10, "%.2f%%", export_progress * 100 );
967
gtk_progress_bar_set_fraction( GTK_PROGRESS_BAR( img->export_pbar1 ),
969
gtk_progress_bar_set_text( GTK_PROGRESS_BAR( img->export_pbar1 ), string );
971
export_progress = (gdouble)img->export_frame_cur / img->export_frame_nr;
972
snprintf( string, 10, "%.2f%%", export_progress * 100 );
973
gtk_progress_bar_set_fraction( GTK_PROGRESS_BAR( img->export_pbar2 ),
975
gtk_progress_bar_set_text( GTK_PROGRESS_BAR( img->export_pbar2 ), string );
977
/* Draw every 10th frame of animation on screen */
978
if(img->export_frame_cur % 10 == 0)
979
gtk_widget_queue_draw(img->image_area);
984
static gboolean img_export_still(img_window_struct *img)
987
gdouble export_progress;
990
/* Initialize pixbuf data buffer */
991
if(img->pixbuf_data == NULL)
993
gtk_image_set_from_pixbuf(GTK_IMAGE(img->image_area), img->pixbuf2);
994
img_export_pixbuf_to_ppm(img->pixbuf2, &img->pixbuf_data, &lenght);
997
/* Draw frames until we have enough of them to fill slide duration gap. */
998
if( img->export_slide_cur > img->export_slide_nr )
1000
/* Exit still rendering and continue with next transition. */
1002
/* Clear image area for next renderer */
1003
gtk_image_clear(GTK_IMAGE(img->image_area));
1005
/* Load next image from store. */
1006
if(img_prepare_pixbufs(img))
1010
/* Update progress counters */
1011
img->export_slide++;
1012
string = g_strdup_printf( _("Slide %d export progress:"), img->export_slide );
1013
gtk_label_set_label( GTK_LABEL( img->export_label ), string );
1015
/* Progress bug fix */
1016
img_export_calc_slide_frames( img );
1018
g_free(img->pixbuf_data);
1019
img->pixbuf_data = NULL;
1020
img->export_idle_func = (GSourceFunc)img_export_transition;
1021
img->source_id = g_idle_add((GSourceFunc)img_export_transition, img);
1024
img_clean_after_export(img);
1028
write(img->file_desc, img->pixbuf_data, lenght);
1030
/* Increment global frame counter and update progress bar */
1031
img->export_frame_cur++;
1032
img->export_slide_cur++;
1034
/* CLAMPS are needed here because of the loosy conversion when switching
1035
* from floating point to integer arithmetics. */
1036
export_progress = CLAMP( (gdouble)img->export_slide_cur / img->export_slide_nr, 0, 1 );
1037
snprintf( string, 10, "%.2f%%", export_progress * 100 );
1038
gtk_progress_bar_set_fraction( GTK_PROGRESS_BAR( img->export_pbar1 ),
1040
gtk_progress_bar_set_text( GTK_PROGRESS_BAR( img->export_pbar1 ), string );
1042
export_progress = CLAMP( (gdouble)img->export_frame_cur / img->export_frame_nr, 0, 1 );
1043
snprintf( string, 10, "%.2f%%", export_progress * 100 );
1044
gtk_progress_bar_set_fraction( GTK_PROGRESS_BAR( img->export_pbar2 ),
1046
gtk_progress_bar_set_text( GTK_PROGRESS_BAR( img->export_pbar2 ), string );
1051
static void img_clean_after_export(img_window_struct *img)
1053
/* Disconnect expose event */
1054
g_signal_handlers_block_by_func(img->image_area, img_on_expose_event, img);
1055
gtk_widget_set_app_paintable(img->image_area, FALSE);
1057
/* Restore image that was used before export */
1058
gtk_image_set_from_pixbuf(GTK_IMAGE(img->image_area), img->slide_pixbuf);
1059
if(img->slide_pixbuf)
1060
g_object_unref(G_OBJECT(img->slide_pixbuf));
1062
/* Indicate that export is not running any more */
1063
img->export_is_running = FALSE;
1065
/* Clean other resources */
1066
g_slice_free(GtkTreeIter, img->cur_ss_iter);
1067
img->cur_ss_iter = NULL;
1068
g_free(img->pixbuf_data);
1069
img->pixbuf_data = NULL;
1070
gtk_widget_destroy( img->export_dialog );
1072
close(img->file_desc);
1075
/* Move one step forward in model and set img->pixbuf1 and img->pixbuf2
1076
* to appropriate values.
1077
* Return FALSE if we reached the end of the model, else TRUE. */
1078
static gboolean img_prepare_pixbufs(img_window_struct *img)
1080
GtkTreeModel *model;
1082
model = gtk_icon_view_get_model(GTK_ICON_VIEW(img->thumbnail_iconview));
1084
if(!img->cur_ss_iter)
1086
img->cur_ss_iter = g_slice_new(GtkTreeIter);
1087
gtk_tree_model_get_iter_first(model, img->cur_ss_iter);
1090
if(gtk_tree_model_iter_next(model, img->cur_ss_iter))
1092
g_object_unref(G_OBJECT(img->pixbuf1));
1093
img->pixbuf1 = img->pixbuf2;
1094
gtk_tree_model_get(model, img->cur_ss_iter, 1, &img->current_slide, -1);
1095
img->pixbuf2 = img_scale_pixbuf(img, img->current_slide->filename);
1103
if(gtk_tree_model_iter_next(model, img->cur_ss_iter))
1105
g_object_unref(G_OBJECT(img->pixbuf1));
1106
img->pixbuf1 = img->pixbuf2;
1107
gtk_tree_model_get(model, img->cur_ss_iter, 1, &img->current_slide, -1);
1108
img->pixbuf2 = img_scale_pixbuf(img, img->current_slide->filename);
1116
static void img_export_pixbuf_to_ppm(GdkPixbuf *pixbuf, guchar **data, guint *lenght)
1118
gint width, height, stride, channels;
1119
guchar *pixels, *tmp;
1124
width = gdk_pixbuf_get_width(pixbuf);
1125
height = gdk_pixbuf_get_height(pixbuf);
1126
stride = gdk_pixbuf_get_rowstride(pixbuf);
1127
channels = gdk_pixbuf_get_n_channels(pixbuf);
1128
pixels = gdk_pixbuf_get_pixels(pixbuf);
1130
header = g_strdup_printf("P6\n%d %d\n255\n", width, height);
1131
header_lenght = strlen(header) * sizeof(gchar);
1133
*lenght = sizeof(guchar) * width * height * channels + header_lenght;
1134
*data = g_slice_alloc(sizeof(guchar) * *lenght);
1136
memcpy(*data, header, header_lenght);
1137
tmp = *data + header_lenght;
1138
for(row = 0; row < height; row++)
1140
for(col = 0; col < width; col++)
967
/* Reset slideshow properties */
968
img->distort_images = TRUE;
969
img->background_color = 0;
970
img->final_transition.speed = NORMAL;
971
img->final_transition.render = NULL;
1184
/* Changed return value to gboolean. This way we can abort export in
1185
* img_start_stop_export function. */
1186
static gboolean img_run_encoder(img_window_struct *img)
1006
void img_move_audio_up( GtkButton *button, img_window_struct *img )
1189
GError *error = NULL;
1194
if (img->slideshow_format_index == 0)
1195
cmd_line = g_strdup_printf(
1196
"ffmpeg -f image2pipe -vcodec ppm -r %s -i pipe: "
1197
"-target %s-dvd -r %s -an -aspect %s -s %dx%d -y -bf 2 %s",
1199
img->image_area->allocation.height == 576 ? "pal" : "ntsc",
1201
img->aspect_ratio, img->image_area->allocation.width,
1202
img->image_area->allocation.height, img->slideshow_filename );
1204
cmd_line = g_strconcat(
1205
"ffmpeg -f image2pipe -vcodec ppm -r " EXPORT_FPS_STRING
1206
" -i pipe: -an -b 512k -s 320x240 -f flv -y ",
1207
img->slideshow_filename,NULL);
1208
argv = g_strsplit( cmd_line, " ", 0 );
1209
g_print( "%s\n", cmd_line );
1212
ret = g_spawn_async_with_pipes( NULL, argv, NULL,
1213
G_SPAWN_SEARCH_PATH/* |
1214
G_SPAWN_STDOUT_TO_DEV_NULL |
1215
G_SPAWN_STDERR_TO_DEV_NULL*/,
1216
NULL, NULL, NULL, &img->file_desc,
1217
NULL, NULL, &error );
1008
GtkTreeSelection *sel;
1009
GtkTreeModel *model;
1010
GtkTreeIter iter1, iter2;
1012
/* We need path, since there is no gtk_tree_model_iter_prev function!! */
1015
/* First we need to get selected iter. This function won't work if
1016
* selection's mode is set to GTK_SELECTION_MULTIPLE!! */
1017
sel = gtk_tree_view_get_selection( GTK_TREE_VIEW( img->music_file_treeview ) );
1018
if( ! gtk_tree_selection_get_selected( sel, &model, &iter1 ) )
1021
/* Now get previous iter and swap two items if previous iter exists. */
1022
path = gtk_tree_model_get_path( model, &iter1 );
1023
if( gtk_tree_path_prev( path ) )
1220
message = gtk_message_dialog_new (GTK_WINDOW (img->imagination_window),
1221
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1224
_("Failed to launch the encoder!"));
1225
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (message),"%s.",error->message);
1226
gtk_dialog_run (GTK_DIALOG (message));
1227
gtk_widget_destroy (message);
1228
g_error_free (error);
1025
gtk_tree_model_get_iter( model, &iter2, path );
1026
gtk_list_store_swap( GTK_LIST_STORE( model ), &iter1, &iter2 );
1235
void img_set_buttons_state(img_window_struct *img, gboolean state)
1237
gtk_widget_set_sensitive(img->import_button,state);
1238
gtk_widget_set_sensitive(img->import_menu, state);
1239
gtk_widget_set_sensitive(img->save_menu, state);
1240
gtk_widget_set_sensitive(img->save_as_menu, state);
1241
gtk_widget_set_sensitive(img->save_button, state);
1242
gtk_widget_set_sensitive(img->close_menu, state);
1243
gtk_widget_set_sensitive(img->properties_menu, state);
1244
gtk_widget_set_sensitive(img->preview_menu, state);
1245
gtk_widget_set_sensitive(img->preview_button,state);
1246
gtk_widget_set_sensitive(img->export_menu, state);
1247
gtk_widget_set_sensitive(img->export_button,state);
1250
static void img_export_calc_slide_frames(img_window_struct *img)
1253
/* This is fix for the progress bars. I forgot that slides with no
1254
* transition effect shouldn't have transition time added.
1255
* (I haven't caught that bug when testing because I created slideshow
1256
* where each slide had transition effect set.) */
1257
if( img->current_slide->render )
1258
/* Duration + transition time */
1259
img->export_slide_nr = ( img->current_slide->duration + img->current_slide->speed ) * EXPORT_FPS;
1262
img->export_slide_nr = img->current_slide->duration * EXPORT_FPS;
1264
img->export_slide_cur = 0;
1267
static void img_export_pause_unpause(GtkToggleButton *button, img_window_struct *img)
1269
if( gtk_toggle_button_get_active( button ) )
1271
g_source_remove( img->source_id );
1273
img->source_id = g_idle_add(img->export_idle_func, img);
1028
gtk_tree_path_free( path );
1031
void img_move_audio_down( GtkButton *button, img_window_struct *img )
1033
GtkTreeSelection *sel;
1034
GtkTreeModel *model;
1035
GtkTreeIter iter1, iter2;
1037
/* First we need to get selected iter. This function won't work if
1038
* selection's mode is set to GTK_SELECTION_MULTIPLE!! */
1039
sel = gtk_tree_view_get_selection( GTK_TREE_VIEW( img->music_file_treeview ) );
1040
if( ! gtk_tree_selection_get_selected( sel, &model, &iter1 ) )
1043
/* Get next iter and swap rows if iter exists. */
1045
if( gtk_tree_model_iter_next( model, &iter2 ) )
1046
gtk_list_store_swap( GTK_LIST_STORE( model ), &iter1, &iter2 );