/* * gnome_ui.c * * Copyright (C) 2003-06 Karl H. Beckers, Frankfurt * EMail: khb@jarre-de-the.net * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * */ #ifdef HAVE_CONFIG_H # include #endif #include // for timeval struct and related #include #include #ifdef SOLARIS #include #include #endif // SOLARIS #include #include #ifdef HAVE_SHMAT #include #endif // HAVE_SHMAT #include #include /* * include include */ #include #include #include #include "led_meter.h" #include "job.h" #include "app_data.h" #include "control.h" #include "colors.h" #include "codecs.h" #include "frame.h" #include "gnome_warning.h" #include "gnome_options.h" #include "gnome_ui.h" #include "gnome_frame.h" #include "xvidcap-intl.h" #define GLADE_FILE PACKAGE_DATA_DIR"/xvidcap/glade/gnome-xvidcap.glade" #define DEBUGFILE "gnome_ui.c" /* * globals * need to define this here, because we're calling it from * an event and/or the preferences (gtk2_options.c) */ GtkWidget *xvc_ctrl_main_window = NULL; GtkWidget *xvc_ctrl_m1 = NULL; GtkWidget *xvc_result_dialog = NULL; extern AppData *app; extern GtkWidget *xvc_pref_main_window; extern GtkWidget *xvc_warn_main_window; extern xvCodec tCodecs[NUMCODECS]; extern xvFFormat tFFormats[NUMCAPS]; extern xvAuCodec tAuCodecs[NUMAUCODECS]; static guint stop_timer_id = 0; static long start_time = 0, pause_time = 0, time_captured = 0; static char *target_file_name = NULL; static xvErrorListItem *errors_after_cli = NULL; static int OK_attempts = 0; // those are for recording video in thread pthread_mutex_t recording_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t update_filename_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t recording_condition_unpaused; static pthread_t recording_thread; static pthread_attr_t recording_thread_attr; static Boolean recording_thread_running = FALSE; // functions static gboolean stop_recording_gui_stuff(Job * jobp); static gboolean stop_recording_nongui_stuff(Job * jobp); static gboolean start_recording_gui_stuff(Job * jobp); static gboolean start_recording_nongui_stuff(Job * jobp); static gboolean timer_stop_recording(Job * job); void warning_submit(); void xvc_reset_ctrl_main_window_according_to_current_prefs(); void GtkChangeLabel(int pic_no); /* * XVIDCAP GUI API ( IF THAT WORD IS ALLOWED HERE ;) ) * * XVC_PREINIT IS FOR GUI PREINITIALIZATION LIKE SETTING FALLBACK OPTIONS * XVC_CREATEGUI IS FOR GUI CREATION * XVC_CREATEFRAME SHOULD CREATE THE SELECTION FRAME * XVC_INITGUI IS FOR MISCELLANEOUS INITIALIZATION STUFF * XVC_RUNGUI IS A WRAPPER AROUND THE UI'S MAIN LOOP * * XVC_ADDTIMEOUT IS A WRAPPER AROUND THE GUI'S FUNCTIONALITY FOR TRIGGERING ACTIONS AT A * GIVEN TIME * XVC_CHANGEGUILABEL IS A WRAPPER AROUND A FUNCTION TO CHANGE THE DISPLAY * OF THE CURRENT FRAME NUMBER (NOT NECESSARY IN A LABEL) * XVC_STOPCAPTURE IS A HOOK FOR RESETTING THE GUI TO A STOPPED STATE * XVC_STARTCAPTURE IS A HOOK FOR STARTING A CAPTURE SESSION */ Boolean xvc_init_pre(int argc, char **argv) { #define DEBUGFUNCTION "xvc_init_pre()" g_thread_init(NULL); // gnome program initialization // make gnome init ignore command line options (we want to handle them // ourselves // char *nothing[] = { "--disable-crash-dialog", "--help" }; // gnome_program_init(PACKAGE, VERSION, LIBGNOMEUI_MODULE, // 2, nothing, // GNOME_PARAM_APP_DATADIR, PACKAGE_DATA_DIR, NULL); gtk_init(&argc, &argv); return TRUE; #undef DEBUGFUNCTION } GtkWidget *glade_create_led_meter(gchar * widget_name, gchar * string1, gchar * string2, gint int1, gint int2) { #define DEBUGFUNCTION "glade_create_led_meter()" GtkWidget *frame_monitor = led_meter_new(); g_assert(frame_monitor); gtk_widget_set_name(GTK_WIDGET(frame_monitor), widget_name); gtk_widget_show(GTK_WIDGET(frame_monitor)); return frame_monitor; #undef DEBUGFUNCTION } Boolean xvc_ui_create() { #define DEBUGFUNCTION "xvc_ui_create()" Display *dpy; GladeXML *xml; #ifdef DEBUG printf("%s %s: Entering\n", DEBUGFILE, DEBUGFUNCTION); #endif // DEBUG // only show the ui if not in nogui if ((app->flags & FLG_NOGUI) == 0) { // main window // load the interface xml = glade_xml_new(GLADE_FILE, "xvc_ctrl_main_window", NULL); g_assert(xml); // connect the signals in the interface glade_xml_signal_autoconnect(xml); // store the toplevel widget for further reference xvc_ctrl_main_window = glade_xml_get_widget(xml, "xvc_ctrl_main_window"); xml = NULL; // popup window // load the interface xml = glade_xml_new(GLADE_FILE, "xvc_ctrl_m1", NULL); g_assert(xml); // connect the signals in the interface glade_xml_signal_autoconnect(xml); xvc_ctrl_m1 = glade_xml_get_widget(xml, "xvc_ctrl_m1"); dpy = GDK_DRAWABLE_XDISPLAY(GTK_WIDGET(xvc_ctrl_main_window)-> window); } else { dpy = XOpenDisplay(NULL); } // FIXME: This needs to go somewhere else more sensible #ifdef HasDGA if (!XF86DGAQueryExtension(dpy, &dga_evb, &dga_errb)) app->flags &= ~FLG_USE_DGA; else { int flag = 0; XF86DGAQueryDirectVideo(dpy, XDefaultScreen(dpy), &flag); if ((flag & XF86DGADirectPresent) == 0) { app->flags &= ~FLG_USE_DGA; if (app->verbose) { printf("%s %s: no xfdga direct present\n", DEBUGFILE, DEBUGFUNCTION); } } } #endif // HasDGA // FIXME: This needs to go somewhere else more sensible #ifdef HAVE_SHMAT if (!XShmQueryExtension(dpy)) app->flags &= ~FLG_USE_SHM; #endif // HAVE_SHMAT if (app->flags & FLG_NOGUI) { XCloseDisplay(dpy); } #ifdef DEBUG printf("%s %s: Leaving\n", DEBUGFILE, DEBUGFUNCTION); #endif // DEBUG return TRUE; #undef DEBUGFUNCTION } Boolean xvc_frame_create() { #define DEBUGFUNCTION "xvc_frame_create()" g_assert(app); if ((app->flags & FLG_NOGUI) == 0) { // there's one reason for not // having a main window g_assert(xvc_ctrl_main_window); } if (app->cap_width == 0) app->cap_width = 10; if (app->cap_height == 0) app->cap_height = 10; xvc_create_gtk_frame(xvc_ctrl_main_window, app->cap_width, app->cap_height, app->cap_pos_x, app->cap_pos_y); return TRUE; #undef DEBUGFUNCTION } void xvc_frame_destroy() { xvc_destroy_gtk_frame(); } void xvc_check_start_options() { #define DEBUGFUNCTION "xvc_check_start_options()" int count_non_info_messages = 0; int rc = 0; #ifdef DEBUG printf("%s %s: Entering with errors_after_cli = %p\n", DEBUGFILE, DEBUGFUNCTION, errors_after_cli); #endif // DEBUG if (OK_attempts > 0 && errors_after_cli != NULL) { errors_after_cli = xvc_app_data_validate(app, 1, &rc); #ifdef DEBUG printf("%s %s: new errors_after_cli = %p\n", DEBUGFILE, DEBUGFUNCTION, errors_after_cli); #endif // DEBUG if (rc == -1) { fprintf(stderr, "%s %s: Unrecoverable error while validating options, please contact the xvidcap project.\n", DEBUGFILE, DEBUGFUNCTION); exit(1); } } if ((app->flags & FLG_NOGUI) == 0) { // we're running with gui if (errors_after_cli != NULL) { xvErrorListItem *err; err = errors_after_cli; count_non_info_messages = 0; for (; err != NULL; err = err->next) { if (err->err->type != XV_ERR_INFO) count_non_info_messages++; } if (count_non_info_messages > 0 || (app->flags & FLG_RUN_VERBOSE && OK_attempts == 0)) { xvc_warn_main_window = xvc_create_warning_with_errors(errors_after_cli, 2); OK_attempts++; } else { warning_submit(); } } else { warning_submit(); } } else { // or without while (errors_after_cli != NULL && OK_attempts < 6) { xvErrorListItem *err; err = errors_after_cli; count_non_info_messages = rc = 0; for (; err != NULL; err = err->next) { if (err->err->type != XV_ERR_INFO) count_non_info_messages++; } if (count_non_info_messages > 0 || (app->flags & FLG_RUN_VERBOSE && OK_attempts == 0)) { err = errors_after_cli; for (; err != NULL; err = err->next) { if (err->err->type != XV_ERR_INFO || app->flags & FLG_RUN_VERBOSE) { xvc_errors_write_error_msg(err->err->code, ((app-> flags & FLG_RUN_VERBOSE) ? 1 : 0)); (*err->err->action) (err); } } } OK_attempts++; errors_after_cli = xvc_app_data_validate(app, 1, &rc); if (rc == -1) { fprintf(stderr, "%s %s: Unrecoverable error while validating options, please contact the xvidcap project.\n", DEBUGFILE, DEBUGFUNCTION); exit(1); } } if (errors_after_cli != NULL && count_non_info_messages > 0) { fprintf(stderr, "%s %s: You have specified some conflicting settings which could not be resolved automatically.\n", DEBUGFILE, DEBUGFUNCTION); exit(1); } warning_submit(); } #ifdef DEBUG printf("%s %s: Leaving\n", DEBUGFILE, DEBUGFUNCTION); #endif // DEBUG #undef DEBUGFUNCTION } Boolean xvc_ui_init(xvErrorListItem * errors) { #define DEBUGFUNCTION "xvc_ui_init()" #ifdef DEBUG printf("%s %s: Entering\n", DEBUGFILE, DEBUGFUNCTION); #endif // DEBUG // display warning dialog if required errors_after_cli = errors; // the gui warning dialog needs a realized window, therefore we // schedule it // do be displayed (potentially) when the main loop starts // this does not seem to work with nogui if (!(app->flags & FLG_NOGUI)) { gtk_init_add((GtkFunction) xvc_check_start_options, NULL); } else { xvc_check_start_options(); gtk_init_add((GtkFunction) xvc_capture_start, NULL); } #ifdef DEBUG printf("%s %s: Leaving\n", DEBUGFILE, DEBUGFUNCTION); #endif // DEBUG return TRUE; #undef DEBUGFUNCTION } int xvc_ui_run() { #define DEBUGFUNCTION "xvc_ui_run()"; gtk_main(); return 0; #undef DEBUGFUNCTION } void xvc_idle_add(void *func, void *data, Boolean queue_events) { if (queue_events || !gtk_events_pending()) g_idle_add(func, data); } Boolean xvc_change_filename_display(int pic_no) { #define DEBUGFUNCTION "xvc_change_filename_display()" GtkChangeLabel(pic_no); return FALSE; #undef DEBUGFUNCTION } void xvc_capture_stop_signal(Boolean wait) { #define DEBUGFUNCTION "xvc_capture_stop_signal()" int status = -1; #ifdef DEBUG printf("%s %s: Entering, should we wait? %i\n", DEBUGFILE, DEBUGFUNCTION, wait); #endif // DEBUG job_set_state(VC_STOP); if (recording_thread_running) { #ifdef DEBUG printf("%s %s: stop pressed while recording\n", DEBUGFILE, DEBUGFUNCTION); #endif // DEBUG // stop waiting for next frame to capture status = pthread_kill(recording_thread, SIGALRM); #ifdef DEBUG printf("%s %s: thread %i kill with rc %i\n", DEBUGFILE, DEBUGFUNCTION, (int) recording_thread, status); #endif // DEBUG } if (wait) { while (recording_thread_running) { usleep(100); } } #ifdef DEBUG printf("%s %s: Leaving\n", DEBUGFILE, DEBUGFUNCTION); #endif // DEBUG #undef DEBUGFUNCTION } Boolean xvc_capture_stop() { #define DEBUGFUNCTION "xvc_capture_stop()" Job *job = xvc_job_ptr(); gboolean rc; #ifdef DEBUG printf("%s %s: stopping\n", DEBUGFILE, DEBUGFUNCTION); #endif // DEBUG rc = stop_recording_nongui_stuff(job); #ifdef DEBUG printf("%s %s: done stopping non-gui stuff\n", DEBUGFILE, DEBUGFUNCTION); #endif // DEBUG if (!(job->flags & FLG_NOGUI)) rc = stop_recording_gui_stuff(job); return FALSE; #undef DEBUGFUNCTION } void xvc_capture_start() { #define DEBUGFUNCTION "xvc_capture_start()" Job *job = xvc_job_ptr(); gboolean rc; rc = start_recording_nongui_stuff(job); if (!(job->flags & FLG_NOGUI)) rc = start_recording_gui_stuff(job); #undef DEBUGFUNCTION } void xvc_frame_change(int x, int y, int width, int height, Boolean reposition_control) { #define DEBUGFUNCTION "xvc_frame_change()" xvc_change_gtk_frame(x, y, width, height, reposition_control); #undef DEBUGFUNCTION } Boolean xvc_frame_monitor(int measured_time) { #define DEBUGFUNCTION "xvc_frame_monitor()" Job *job = xvc_job_ptr(); int percent = 0, diff = 0; GladeXML *xml = NULL; GtkWidget *w = NULL; #ifdef DEBUG printf("%s %s: Entering with time = %i\n", DEBUGFILE, DEBUGFUNCTION, measured_time); #endif // DEBUG xml = glade_get_widget_tree(xvc_ctrl_main_window); g_return_val_if_fail(xml != NULL, FALSE); w = glade_xml_get_widget(xml, "xvc_ctrl_led_meter"); g_return_val_if_fail(w != NULL, FALSE); if (measured_time == 0) { percent = 0; } else if (measured_time <= job->time_per_frame) percent = 30; else if (measured_time >= (job->time_per_frame * 2)) percent = 100; else { diff = measured_time - job->time_per_frame; percent = diff * 70 / job->time_per_frame; percent += 30; } led_meter_set_percent(LED_METER(w), percent); if (percent == 0) LED_METER(w)->old_max_da = 0; #ifdef DEBUG printf("%s %s: Leaving with percent = %i\n", DEBUGFILE, DEBUGFUNCTION, percent); #endif // DEBUG return FALSE; #undef DEBUGFUNCTION } /* * HELPER FUNCTIONS ... * * */ /* * this isn't used atm * gint keySnooper (GtkWidget *grab_widget, GdkEventKey *event, gpointer func_data) { printf("keyval: %i - mods: %i\n", event->keyval, event->state); } */ /* * change value of frame/filename display */ void GtkChangeLabel(int pic_no) { #define DEBUGFUNCTION "GtkChangeLabel()" static char file[PATH_MAX + 1], tmp_buf[PATH_MAX + 1]; PangoLayout *layout = NULL; gint width = 0, height = 0; int filename_length = 0; GladeXML *xml = NULL; GtkWidget *w = NULL; Job *jobp = xvc_job_ptr(); // generate the string to display in the filename button if (jobp->flags & FLG_MULTI_IMAGE) { sprintf(tmp_buf, jobp->file, jobp->movie_no); sprintf(file, "%s[%04d]", tmp_buf, pic_no); } else { sprintf(file, jobp->file, pic_no); } // cut the string to a sensible maximum length filename_length = strlen(file); if (filename_length > 60) { char tmp_file[PATH_MAX + 1]; char *tmp_file2, *ptr; int n; strncpy(tmp_file, file, 20); tmp_file[20] = 0; n = filename_length - 20; ptr = (char *) &file + n; tmp_file2 = strncat(tmp_file, "...", 4); tmp_file2 = strncat(tmp_file, ptr, 45); strncpy(file, tmp_file2, 45); } // get the filename button widget xml = glade_get_widget_tree(xvc_ctrl_main_window); g_assert(xml); w = glade_xml_get_widget(xml, "xvc_ctrl_filename_button"); g_assert(w); // set the text gtk_button_set_label(GTK_BUTTON(w), file); // adjust the size of the filname button layout = gtk_widget_create_pango_layout(w, file); g_assert(layout); pango_layout_get_pixel_size(layout, &width, &height); g_object_unref(layout); gtk_widget_set_size_request(GTK_WIDGET(w), (width + 30), -1); #undef DEBUGFUNCTION } // first callbacks here .... // // gboolean on_xvc_ctrl_main_window_delete_event(GtkWidget * widget, GdkEvent * event, gpointer user_data) { #define DEBUGFUNCTION "on_xvc_ctrl_main_window_delete_event()" Job *jobp = xvc_job_ptr(); if (jobp && (jobp->state & VC_STOP) == 0) { xvc_capture_stop_signal(TRUE); } xvc_frame_destroy(); gtk_main_quit(); // FIXME: why does this seem to be // necessary with libglade where // it was not previously return FALSE; #undef DEBUGFUNCTION } gboolean on_xvc_ctrl_main_window_destroy_event(GtkWidget * widget, GdkEvent * event, gpointer user_data) { #define DEBUGFUNCTION "on_xvc_ctrl_main_window_destroy_event()" gtk_main_quit(); return FALSE; #undef DEBUGFUNCTION } void on_xvc_ctrl_m1_mitem_preferences_activate(GtkMenuItem * menuitem, gpointer user_data) { #define DEBUGFUNCTION "on_xvc_ctrl_m1_mitem_preferences_activate()" #ifdef DEBUG printf("%s %s: Entering with app %p\n", DEBUGFILE, DEBUGFUNCTION, app); #endif // DEBUG xvc_create_pref_dialog(app); #ifdef DEBUG printf("%s %s: Leaving\n", DEBUGFILE, DEBUGFUNCTION); #endif // DEBUG #undef DEBUGFUNCTION } void on_xvc_ctrl_m1_mitem_save_preferences_activate(GtkMenuItem * menuitem, gpointer user_data) { #define DEBUGFUNCTION "on_xvc_ctrl_m1_mitem_save_preferences_activate()" Job *jobp = xvc_job_ptr(); xvc_write_options_file(jobp); #undef DEBUGFUNCTION } void warning_submit() { #define DEBUGFUNCTION "warning_submit()" Display *mydisplay = NULL; Window root; XWindowAttributes win_attr; Job *jobp = xvc_job_ptr(); #ifdef DEBUG printf("%s %s: Entering\n", DEBUGFILE, DEBUGFUNCTION); #endif // DEBUG // Get X display and Window Attributes // notice, here we're still talking app->flags if (!(app->flags & FLG_NOGUI)) { mydisplay = GDK_DRAWABLE_XDISPLAY(GTK_WIDGET(xvc_ctrl_main_window)-> window); } else { mydisplay = XOpenDisplay(NULL); } g_assert(mydisplay); root = RootWindow(mydisplay, DefaultScreen(mydisplay)); if (!XGetWindowAttributes(mydisplay, root, &win_attr)) { char msg[256]; snprintf(msg, 256, "%s %s: Can't get window attributes!\n", DEBUGFILE, DEBUGFUNCTION); perror(msg); } if (jobp == NULL) jobp = xvc_job_new(); xvc_job_set_from_app_data(app, mydisplay, win_attr); // validate the job parameters xvc_job_validate(); // set controls active/inactive/sensitive/insensitive according to // current options if (!(app->flags & FLG_NOGUI)) { xvc_reset_ctrl_main_window_according_to_current_prefs(); // FIXME: any bad side-effects from removing this? // stop_recording_gui_stuff(jobp); } if (xvc_errors_delete_list(errors_after_cli)) { fprintf(stderr, "%s %s: Unrecoverable error while freeing error list, please contact the xvidcap project.\n", DEBUGFILE, DEBUGFUNCTION); exit(1); } // reset attempts so warnings will be shown again next time ... OK_attempts = 0; #ifdef DEBUG printf("%s %s: Leaving\n", DEBUGFILE, DEBUGFUNCTION); #endif // DEBUG #undef DEBUGFUNCTION } #ifdef USE_FFMPEG void xvc_toggle_cap_type() { #define DEBUGFUNCTION "xvc_toggle_cap_type()" int count_non_info_messages, rc; count_non_info_messages = 0; rc = 0; errors_after_cli = xvc_app_data_validate(app, 1, &rc); if (rc == -1) { fprintf(stderr, "%s %s: Unrecoverable error while validating options, please contact the xvidcap project.\n", DEBUGFILE, DEBUGFUNCTION); exit(1); } // warning dialog if (errors_after_cli != NULL) { xvErrorListItem *err; err = errors_after_cli; for (; err != NULL; err = err->next) { if (err->err->type != XV_ERR_INFO) count_non_info_messages++; } if (count_non_info_messages > 0 || (app->flags & FLG_RUN_VERBOSE && OK_attempts == 0)) { xvc_warn_main_window = xvc_create_warning_with_errors(errors_after_cli, 1); OK_attempts++; } else { warning_submit(); } } else { warning_submit(); } #undef DEBUGFUNCTION } void xvc_undo_toggle_cap_type() { #define DEBUGFUNCTION "xvc_undo_toggle_cap_type()" GladeXML *xml = NULL; GtkWidget *mitem = NULL; xml = glade_get_widget_tree(xvc_ctrl_m1); g_assert(xml); OK_attempts = 0; #ifdef DEBUG printf("%s %s: pre current_mode %i\n", DEBUGFILE, DEBUGFUNCTION, app->current_mode); #endif // DEBUG app->current_mode = (app->current_mode == 0) ? 1 : 0; #ifdef DEBUG printf("%s %s: post current_mode %i\n", DEBUGFILE, DEBUGFUNCTION, app->current_mode); #endif // DEBUG if (app->current_mode == 0) { mitem = glade_xml_get_widget(xml, "xvc_ctrl_m1_mitem_sf_capture"); g_assert(mitem); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mitem), TRUE); } else { mitem = glade_xml_get_widget(xml, "xvc_ctrl_m1_mitem_mf_capture"); g_assert(mitem); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mitem), TRUE); } #undef DEBUGFUNCTION } #endif // USE_FFMPEG void on_xvc_ctrl_m1_mitem_sf_capture_activate(GtkMenuItem * menuitem, gpointer user_data) { #ifdef USE_FFMPEG #define DEBUGFUNCTION "on_xvc_ctrl_m1_mitem_sf_capture_activate()" if (app->current_mode == 1 && gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem)) != 0) { app->current_mode = (app->current_mode == 0) ? 1 : 0; xvc_toggle_cap_type(); } #undef DEBUGFUNCTION #endif // USE_FFMPEG } void on_xvc_ctrl_m1_mitem_mf_capture_activate(GtkMenuItem * menuitem, gpointer user_data) { #ifdef USE_FFMPEG #define DEBUGFUNCTION "on_xvc_ctrl_m1_mitem_mf_capture_activate()" if (app->current_mode == 0 && gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem)) != 0) { app->current_mode = (app->current_mode == 0) ? 1 : 0; xvc_toggle_cap_type(); } #undef DEBUGFUNCTION #endif // USE_FFMPEG } void on_xvc_ctrl_m1_mitem_autocontinue_activate(GtkMenuItem * menuitem, gpointer user_data) { #define DEBUGFUNCTION "on_xvc_ctrl_m1_mitem_autocontinue_activate()" Job *jobp = xvc_job_ptr(); if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem))) { if ((!xvc_is_filename_mutable(jobp->file)) || (jobp->flags & FLG_MULTI_IMAGE) == 0) { printf ("Output not a video file or no counter in filename\nDisabling autocontinue!\n"); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM (menuitem), FALSE); } else { jobp->flags |= FLG_AUTO_CONTINUE; app->flags |= FLG_AUTO_CONTINUE; } } else { jobp->flags &= ~FLG_AUTO_CONTINUE; app->flags &= ~FLG_AUTO_CONTINUE; } #undef DEBUGFUNCTION } void on_xvc_ctrl_m1_mitem_make_activate(GtkMenuItem * menuitem, gpointer user_data) { #define DEBUGFUNCTION "on_xvc_ctrl_m1_mitem_make_activate()" Job *jobp = xvc_job_ptr(); if (!app->current_mode) { xvc_command_execute(app->single_frame.video_cmd, 0, 0, jobp->file, jobp->start_no, jobp->pic_no, jobp->area->width, jobp->area->height, jobp->fps); } else { xvc_command_execute(app->multi_frame.video_cmd, 2, jobp->movie_no, jobp->file, jobp->start_no, jobp->pic_no, jobp->area->width, jobp->area->height, jobp->fps); } #undef DEBUGFUNCTION } void on_xvc_ctrl_m1_mitem_help_activate(GtkMenuItem * menuitem, gpointer user_data) { #define DEBUGFUNCTION "on_xvc_ctrl_m1_mitem_help_activate()" system("yelp ghelp:xvidcap &"); #undef DEBUGFUNCTION } void on_xvc_ctrl_m1_mitem_quit_activate(GtkMenuItem * menuitem, gpointer user_data) { #define DEBUGFUNCTION "on_xvc_ctrl_m1_mitem_quit_activate()" gboolean ignore = TRUE; g_signal_emit_by_name((GtkObject *) xvc_ctrl_main_window, "destroy_event", 0, &ignore); #undef DEBUGFUNCTION } void do_record_thread(Job * job) { #define DEBUGFUNCTION "do_record_thread()" long pause = 1000; #ifdef DEBUG printf("%s %s: Entering with state = %i and tid = %i\n", DEBUGFILE, DEBUGFUNCTION, job->state, recording_thread); #endif // DEBUG recording_thread_running = TRUE; while ((job->state & VC_READY) == 0) { #ifdef DEBUG printf("%s %s: going for next frame with state %i\n", DEBUGFILE, DEBUGFUNCTION, job->state); #endif if ((job->state & VC_PAUSE) && !(job->state & VC_STEP)) { pthread_mutex_lock(&recording_mutex); pthread_cond_wait(&recording_condition_unpaused, &recording_mutex); pthread_mutex_unlock(&recording_mutex); #ifdef DEBUG printf("%s %s: unpaused\n", DEBUGFILE, DEBUGFUNCTION); #endif // DEBUG } pause = job->capture(job, NULL); if (pause > 0) usleep(pause * 1000); #ifdef DEBUG printf("%s %s: woke up\n", DEBUGFILE, DEBUGFUNCTION); #endif // DEBUG } #ifdef DEBUG printf("%s %s: Leaving\n", DEBUGFILE, DEBUGFUNCTION); #endif // DEBUG recording_thread_running = FALSE; pthread_exit(NULL); #undef DEBUGFUNCTION } gboolean stop_recording_nongui_stuff(Job * job) { #define DEBUGFUNCTION "stop_recording_nongui_stuff()" int state = 0; struct timeval curr_time; long stop_time = 0; #ifdef DEBUG printf("%s %s: Entering with thread running %i\n", DEBUGFILE, DEBUGFUNCTION, recording_thread_running); #endif // DEBUG state = VC_STOP; if (job->flags & FLG_AUTO_CONTINUE) { state |= VC_CONTINUE; } job_set_state(state); if (recording_thread_running) { pthread_join(recording_thread, NULL /* (void **) &status */ ); #ifdef DEBUG printf("%s %s: joined thread\n", DEBUGFILE, DEBUGFUNCTION); #endif // DEBUG } gettimeofday(&curr_time, NULL); stop_time = curr_time.tv_sec * 1000 + curr_time.tv_usec / 1000; time_captured += (stop_time - start_time); if (stop_timer_id) g_source_remove(stop_timer_id); #ifdef DEBUG printf("%s %s: Leaving\n", DEBUGFILE, DEBUGFUNCTION); #endif // DEBUG return FALSE; #undef DEBUGFUNCTION } // this handles the shortcut keybindings void do_results_help() { system((char *) "yelp ghelp:xvidcap?xvidcap-results &"); } gint on_xvc_result_dialog_key_press_event(GtkWidget * widget, GdkEvent * event) { #define DEBUGFUNCTION "on_xvc_result_dialog_key_press_event()" GdkEventKey *kevent = NULL; g_assert(widget); g_assert(event); kevent = (GdkEventKey *) event; #ifdef DEBUG printf("%s %s: Entering\n", DEBUGFILE, DEBUGFUNCTION); #endif // DEBUG if (kevent->keyval == 65470) { do_results_help(); } #ifdef DEBUG printf("%s %s: Leaving\n", DEBUGFILE, DEBUGFUNCTION); #endif // DEBUG // Tell calling code that we have not handled this event; pass it on. return FALSE; #undef DEBUGFUNCTION } void on_xvc_result_dialog_select_filename_button_clicked(GtkButton * button, gpointer user_data) { #define DEBUGFUNCTION "on_xvc_result_select_filename_button_clicked()" int result = 0; GladeXML *xml = NULL; GtkWidget *w = NULL, *dialog = NULL; #ifdef DEBUG printf("%s %s: Entering\n", DEBUGFILE, DEBUGFUNCTION); #endif // DEBUG // load the interface xml = glade_xml_new(GLADE_FILE, "xvc_save_filechooserdialog", NULL); g_assert(xml); // connect the signals in the interface glade_xml_signal_autoconnect(xml); dialog = glade_xml_get_widget(xml, "xvc_save_filechooserdialog"); g_assert(dialog); gtk_window_set_title(GTK_WINDOW(dialog), "Save Video As:"); result = gtk_dialog_run(GTK_DIALOG(dialog)); if (result == GTK_RESPONSE_OK) { target_file_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); if (xvc_result_dialog != NULL) { xml = NULL; xml = glade_get_widget_tree(GTK_WIDGET(xvc_result_dialog)); g_assert(xml); w = NULL; w = glade_xml_get_widget(xml, "xvc_result_dialog_filename_label"); g_assert(w); gtk_label_set_text(GTK_LABEL(w), target_file_name); w = NULL; w = glade_xml_get_widget(xml, "xvc_result_dialog_save_button"); g_assert(w); printf("setting save button sensitive\n"); gtk_widget_set_sensitive(GTK_WIDGET(w), TRUE); } } gtk_widget_destroy(dialog); #ifdef DEBUG printf("%s %s: Leaving with filename %s\n", DEBUGFILE, DEBUGFUNCTION, target_file_name); #endif // DEBUG #undef DEBUGFUNCTION } static gboolean stop_recording_gui_stuff(Job * job) { #define DEBUGFUNCTION "stop_recording_gui_stuff()" GladeXML *xml = NULL; GtkWidget *w = NULL; CapTypeOptions *target = NULL; Job *jobp = xvc_job_ptr(); #ifdef DEBUG printf("%s %s: Entering\n", DEBUGFILE, DEBUGFUNCTION); #endif // DEBUG // playing it safe xvc_change_filename_display(job->pic_no); // reset frame_drop_meter xvc_frame_monitor(0); xml = glade_get_widget_tree(GTK_WIDGET(xvc_ctrl_main_window)); g_assert(xml); // GUI stuff w = glade_xml_get_widget(xml, "xvc_ctrl_pause_toggle"); g_assert(w); gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(w), FALSE); // gtk_widget_set_sensitive(GTK_WIDGET(MI_file), TRUE); w = glade_xml_get_widget(xml, "xvc_ctrl_select_toggle"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), TRUE); w = glade_xml_get_widget(xml, "xvc_ctrl_record_toggle"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), TRUE); if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(w))) gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(w), FALSE); w = glade_xml_get_widget(xml, "xvc_ctrl_filename_button"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), TRUE); w = glade_xml_get_widget(xml, "xvc_ctrl_edit_button"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), TRUE); if (! ((jobp->flags & FLG_MULTI_IMAGE) != 0 && xvc_is_filename_mutable(jobp->file) != TRUE)) { w = glade_xml_get_widget(xml, "xvc_ctrl_step_button"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), FALSE); w = glade_xml_get_widget(xml, "xvc_ctrl_forward_button"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), TRUE); w = glade_xml_get_widget(xml, "xvc_ctrl_back_button"); g_assert(w); if ((jobp->flags & FLG_MULTI_IMAGE) == 0) { if (jobp->pic_no >= jobp->step) gtk_widget_set_sensitive(GTK_WIDGET(w), TRUE); } else { if (jobp->movie_no > 0) gtk_widget_set_sensitive(GTK_WIDGET(w), TRUE); } } w = glade_xml_get_widget(xml, "xvc_ctrl_pause_toggle"); g_assert(w); if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(w))) gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(w), FALSE); w = glade_xml_get_widget(xml, "xvc_ctrl_stop_toggle"); g_assert(w); if (!gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(w))) gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(w), TRUE); GtkChangeLabel(jobp->pic_no); #ifdef USE_FFMPEG if (job->target >= CAP_MF) target = &(app->multi_frame); else #endif // USE_FFMPEG target = &(app->single_frame); if ((strlen(target->file) < 1 || (app->flags & FLG_ALWAYS_SHOW_RESULTS) > 0) && (job->flags & FLG_AUTO_CONTINUE) == 0) { int result = 0; float fps_ratio = 0; char buf[100]; GladeXML *xml = NULL; GtkWidget *w = NULL; // load the interface xml = glade_xml_new(GLADE_FILE, "xvc_result_dialog", NULL); g_assert(xml); // connect the signals in the interface glade_xml_signal_autoconnect(xml); // get the widget xvc_result_dialog = glade_xml_get_widget(xml, "xvc_result_dialog"); g_assert(xvc_result_dialog); // width w = glade_xml_get_widget(xml, "xvc_result_dialog_width_label"); g_assert(w); snprintf(buf, 99, "%i", job->area->width); gtk_label_set_text(GTK_LABEL(w), buf); // height w = glade_xml_get_widget(xml, "xvc_result_dialog_height_label"); g_assert(w); snprintf(buf, 99, "%i", job->area->height); gtk_label_set_text(GTK_LABEL(w), buf); // video format w = glade_xml_get_widget(xml, "xvc_result_dialog_video_format_label"); g_assert(w); gtk_label_set_text(GTK_LABEL(w), _(tFFormats[jobp->target].longname)); // video codec w = glade_xml_get_widget(xml, "xvc_result_dialog_video_codec_label"); g_assert(w); gtk_label_set_text(GTK_LABEL(w), tCodecs[jobp->targetCodec].name); // audio codec w = glade_xml_get_widget(xml, "xvc_result_dialog_audio_codec_label"); g_assert(w); gtk_label_set_text(GTK_LABEL(w), tAuCodecs[jobp->au_targetCodec].name); // set fps w = glade_xml_get_widget(xml, "xvc_result_dialog_fps_label"); g_assert(w); snprintf(buf, 99, "%.2f", ((float) job->fps / 100)); gtk_label_set_text(GTK_LABEL(w), buf); // achieved fps w = glade_xml_get_widget(xml, "xvc_result_dialog_actual_fps_label"); g_assert(w); { char *str_template = NULL; float total_frames = ((float) jobp->pic_no / (float) job->step) + 1; float actual_fps = ((float) total_frames) / ((float) time_captured / 1000); if (actual_fps > ((float) jobp->fps / 100)) actual_fps = (float) jobp->fps / 100; fps_ratio = actual_fps / ((float) job->fps / 100); if (fps_ratio > (((float) LM_NUM_DAS - LM_LOW_THRESHOLD) / 10)) { str_template = "%.2f"; } else if (fps_ratio > (((float) LM_NUM_DAS - LM_MEDIUM_THRESHOLD) / 10)) { str_template = "%.2f"; } else { str_template = "%.2f"; } snprintf(buf, 99, str_template, actual_fps); gtk_label_set_markup(GTK_LABEL(w), buf); } // fps ratio w = glade_xml_get_widget(xml, "xvc_result_dialog_fps_ratio_progressbar"); g_assert(w); gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(w), fps_ratio); snprintf(buf, 99, "%.2f %%", fps_ratio * 100); gtk_progress_bar_set_text(GTK_PROGRESS_BAR(w), buf); // captured frames w = glade_xml_get_widget(xml, "xvc_result_dialog_total_frames_label"); g_assert(w); snprintf(buf, 99, "%i", (jobp->pic_no / job->step) + 1); gtk_label_set_text(GTK_LABEL(w), buf); // captured time w = glade_xml_get_widget(xml, "xvc_result_dialog_video_length_label"); g_assert(w); snprintf(buf, 99, "%.2f seconds", ((float) time_captured / 1000)); gtk_label_set_text(GTK_LABEL(w), buf); if (strlen(target->file) > 0) { w = glade_xml_get_widget(xml, "xvc_result_dialog_select_filename_button"); g_assert(w); gtk_widget_hide(GTK_WIDGET(w)); w = glade_xml_get_widget(xml, "xvc_result_dialog_filename_label"); g_assert(w); gtk_widget_hide(GTK_WIDGET(w)); w = glade_xml_get_widget(xml, "xvc_result_dialog_no_button"); g_assert(w); gtk_widget_hide(GTK_WIDGET(w)); w = glade_xml_get_widget(xml, "xvc_result_dialog_save_button"); g_assert(w); gtk_widget_hide(GTK_WIDGET(w)); w = glade_xml_get_widget(xml, "xvc_result_dialog_show_next_time_checkbutton"); g_assert(w); gtk_widget_show(GTK_WIDGET(w)); w = glade_xml_get_widget(xml, "xvc_result_dialog_close_button"); g_assert(w); gtk_widget_show(GTK_WIDGET(w)); } do { result = gtk_dialog_run(GTK_DIALOG(xvc_result_dialog)); switch (result) { case GTK_RESPONSE_OK: if (target_file_name != NULL) { char cmd_buf[PATH_MAX * 2 + 5]; int errnum = 0; snprintf(cmd_buf, (PATH_MAX * 2 + 5), "mv %s %s", jobp->file, target_file_name); errnum = system((char *) cmd_buf); if (errnum != 0) { GtkWidget *err_dialog = gtk_message_dialog_new(GTK_WINDOW (xvc_ctrl_main_window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "Error moving file from '%s' to '%s'\n%s", jobp->file, target_file_name, g_strerror(errnum)); gtk_dialog_run(GTK_DIALOG(err_dialog)); gtk_widget_destroy(err_dialog); } } case GTK_RESPONSE_CANCEL: case GTK_RESPONSE_CLOSE: w = glade_xml_get_widget(xml, "xvc_result_dialog_show_next_time_checkbutton"); g_assert(w); if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) app->flags &= ~FLG_ALWAYS_SHOW_RESULTS; break; case GTK_RESPONSE_HELP: do_results_help(); break; case GTK_RESPONSE_ACCEPT: if (!app->current_mode) { xvc_command_execute(app->single_frame.play_cmd, 1, 0, jobp->file, jobp->start_no, jobp->pic_no, jobp->area->width, jobp->area->height, jobp->fps); } else { xvc_command_execute(app->multi_frame.play_cmd, 2, jobp->movie_no, jobp->file, jobp->start_no, jobp->pic_no, jobp->area->width, jobp->area->height, jobp->fps); } break; default: break; } } while (result == GTK_RESPONSE_HELP || result == GTK_RESPONSE_ACCEPT); gtk_widget_destroy(xvc_result_dialog); xvc_result_dialog = NULL; // FIXME: realize move in a way that gives me real error codes } #ifdef DEBUG printf("%s %s: Leaving\n", DEBUGFILE, DEBUGFUNCTION); #endif // DEBUG return FALSE; #undef DEBUGFUNCTION } gboolean timer_stop_recording(Job * job) { #define DEBUGFUNCTION "timer_stop_recording()" xvc_capture_stop_signal(FALSE); return FALSE; #undef DEBUGFUNCTION } void on_xvc_ctrl_stop_toggle_toggled(GtkToggleToolButton * button, gpointer user_data) { #define DEBUGFUNCTION "on_xvc_ctrl_stop_toggle_toggled()" #ifdef DEBUG printf("%s %s: stopp button toggled\n", DEBUGFILE, DEBUGFUNCTION); #endif // DEBUG if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(button))) { if (recording_thread_running) xvc_capture_stop_signal(FALSE); else { GladeXML *xml = NULL; GtkWidget *w = NULL; xml = glade_get_widget_tree(GTK_WIDGET(xvc_ctrl_main_window)); g_assert(xml); w = glade_xml_get_widget(xml, "xvc_ctrl_pause_toggle"); g_assert(w); if (gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON(w))) gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON (w), FALSE); } } else { // empty } #undef DEBUGFUNCTION } gboolean start_recording_gui_stuff(Job * job) { #define DEBUGFUNCTION "start_recording_gui_stuff()" GladeXML *xml = NULL; GtkWidget *w = NULL; Job *jobp = xvc_job_ptr(); xml = glade_get_widget_tree(GTK_WIDGET(xvc_ctrl_main_window)); g_assert(xml); // GUI stuff w = glade_xml_get_widget(xml, "xvc_ctrl_record_toggle"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), FALSE); w = glade_xml_get_widget(xml, "xvc_ctrl_stop_toggle"); g_assert(w); if ((jobp->state & VC_PAUSE) == 0) { gtk_widget_set_sensitive(GTK_WIDGET(w), TRUE); } gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(w), FALSE); w = glade_xml_get_widget(xml, "xvc_ctrl_select_toggle"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), FALSE); w = glade_xml_get_widget(xml, "xvc_ctrl_pause_toggle"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), TRUE); w = glade_xml_get_widget(xml, "xvc_ctrl_filename_button"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), FALSE); w = glade_xml_get_widget(xml, "xvc_ctrl_edit_button"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), FALSE); if (jobp->state & VC_PAUSE) { w = glade_xml_get_widget(xml, "xvc_ctrl_step_button"); g_assert(w); if ((jobp->flags & FLG_MULTI_IMAGE) == 0) { gtk_widget_set_sensitive(GTK_WIDGET(w), TRUE); w = glade_xml_get_widget(xml, "xvc_ctrl_forward_button"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), TRUE); if (jobp->pic_no >= jobp->step) { w = glade_xml_get_widget(xml, "xvc_ctrl_back_button"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), TRUE); } } else { gtk_widget_set_sensitive(GTK_WIDGET(w), FALSE); if (!xvc_is_filename_mutable(jobp->file)) { w = glade_xml_get_widget(xml, "xvc_ctrl_forward_button"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), FALSE); w = glade_xml_get_widget(xml, "xvc_ctrl_back_button"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), FALSE); } } } else { w = glade_xml_get_widget(xml, "xvc_ctrl_forward_button"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), FALSE); w = glade_xml_get_widget(xml, "xvc_ctrl_back_button"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), FALSE); } if (job->flags & FLG_MULTI_IMAGE) { job->pic_no = job->start_no; GtkChangeLabel(job->pic_no); } return FALSE; #undef DEBUGFUNCTION } gboolean start_recording_nongui_stuff(Job * job) { #define DEBUGFUNCTION "start_recording_nongui_stuff()" struct timeval curr_time; if (!recording_thread_running) { // non-gui stuff // the following also unsets VC_READY job_keep_and_merge_state(VC_PAUSE, (VC_REC | VC_START)); if (job->flags & FLG_MULTI_IMAGE) { job->pic_no = job->start_no; } if ((job->state & VC_PAUSE) == 0) { // if (job->max_time != 0 && (job->state & VC_PAUSE) == 0) { gettimeofday(&curr_time, NULL); time_captured = 0; start_time = curr_time.tv_sec * 1000 + curr_time.tv_usec / 1000; if (job->max_time != 0) { // install a timer which stops recording // we need milli secs .. stop_timer_id = gtk_timeout_add((guint32) (job->max_time * 1000), (GtkFunction) timer_stop_recording, job); } } // initialize recording thread pthread_mutex_init(&recording_mutex, NULL); pthread_mutex_init(&update_filename_mutex, NULL); pthread_cond_init(&recording_condition_unpaused, NULL); pthread_attr_init(&recording_thread_attr); pthread_attr_setdetachstate(&recording_thread_attr, PTHREAD_CREATE_JOINABLE); pthread_create(&recording_thread, &recording_thread_attr, (void *) do_record_thread, (void *) job); } return FALSE; #undef DEBUGFUNCTION } void on_xvc_ctrl_record_toggle_toggled(GtkToggleToolButton * button, gpointer user_data) { #define DEBUGFUNCTION "on_xvc_ctrl_record_toggle_toggled()" if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(button))) { xvc_capture_start(); } else { // empty } #undef DEBUGFUNCTION } void on_xvc_ctrl_pause_toggle_toggled(GtkToggleToolButton * button, gpointer user_data) { #define DEBUGFUNCTION "on_xvc_ctrl_pause_toggle_toggled()" struct timeval curr_time; GladeXML *xml = NULL; GtkWidget *w = NULL; Job *jobp = xvc_job_ptr(); xml = glade_get_widget_tree(GTK_WIDGET(xvc_ctrl_main_window)); g_assert(xml); #ifdef DEBUG printf("%s %s: button active? (%d)\n", DEBUGFILE, DEBUGFUNCTION, (int) gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON (button))); #endif if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(button))) { gettimeofday(&curr_time, NULL); pause_time = curr_time.tv_sec * 1000 + curr_time.tv_usec / 1000; if ((jobp->state & VC_REC) != 0) { time_captured += (pause_time - start_time); } else { time_captured = 0; } // stop timer handling only if max_time is configured if (jobp->max_time != 0) { if (stop_timer_id) g_source_remove(stop_timer_id); } job_merge_and_remove_state(VC_PAUSE, VC_STOP); // GUI stuff w = glade_xml_get_widget(xml, "xvc_ctrl_stop_toggle"); g_assert(w); gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(w), FALSE); // make the led monitor stop xvc_frame_monitor(0); // gtk_widget_set_sensitive(GTK_WIDGET(stop), TRUE); if ((jobp->flags & FLG_MULTI_IMAGE) == 0 && jobp->state & VC_REC) { w = glade_xml_get_widget(xml, "xvc_ctrl_step_button"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), TRUE); w = glade_xml_get_widget(xml, "xvc_ctrl_forward_button"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), TRUE); if (jobp->pic_no >= jobp->step) { w = glade_xml_get_widget(xml, "xvc_ctrl_back_button"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), TRUE); } w = glade_xml_get_widget(xml, "xvc_ctrl_edit_button"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), TRUE); } } else { job_remove_state(VC_PAUSE | VC_STEP); // step is always only active if a running recording session is // paused // so releasing pause can always deactivate it w = glade_xml_get_widget(xml, "xvc_ctrl_step_button"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), FALSE); // the following only when recording is going on (not when just // pressing and // releasing pause if (jobp->state & VC_REC) { w = glade_xml_get_widget(xml, "xvc_ctrl_forward_button"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), FALSE); w = glade_xml_get_widget(xml, "xvc_ctrl_back_button"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), FALSE); w = glade_xml_get_widget(xml, "xvc_ctrl_edit_button"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), FALSE); } gettimeofday(&curr_time, NULL); start_time = curr_time.tv_sec * 1000 + curr_time.tv_usec / 1000; // restart timer handling only if max_time is configured if (jobp->max_time != 0) { // install a timer which stops recording // we need milli secs .. stop_timer_id = g_timeout_add((guint32) (jobp->max_time * 1000 - time_captured), (GtkFunction) timer_stop_recording, jobp); } } #undef DEBUGFUNCTION } void on_xvc_ctrl_step_button_clicked(GtkButton * button, gpointer user_data) { #define DEBUGFUNCTION "on_xvc_ctrl_step_button_clicked()" GladeXML *xml = NULL; GtkWidget *w = NULL; Job *jobp = xvc_job_ptr(); if ((jobp->flags & FLG_MULTI_IMAGE) == 0) { if (!(jobp->state & (VC_PAUSE | VC_REC))) return; job_merge_state(VC_STEP); // FIXME: what is the following condition meant to achieve? // if (jobp->pic_no == jobp->step ) { if (jobp->pic_no > (jobp->max_frames - jobp->step)) { xml = glade_get_widget_tree(GTK_WIDGET(xvc_ctrl_main_window)); g_assert(xml); w = glade_xml_get_widget(xml, "xvc_ctrl_step_button"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), FALSE); } // FIXME: find a clever way of making the led only flash for step // prolly needs a completely different handling of the led // updater, though } #undef DEBUGFUNCTION } void on_xvc_ctrl_filename_button_clicked(GtkButton * button, gpointer user_data) { #define DEBUGFUNCTION "on_xvc_ctrl_step_button_clicked()" Job *jobp = xvc_job_ptr(); if ((jobp->flags & FLG_MULTI_IMAGE) == 0) { if (jobp->pic_no != jobp->start_no && ((jobp->state & VC_STOP) > 0 || (jobp->state & VC_PAUSE) > 0)) { jobp->pic_no = jobp->start_no; GtkChangeLabel(jobp->pic_no); } } else { if (jobp->movie_no != 0 && (jobp->state & VC_STOP) > 0) { jobp->movie_no = 0; jobp->pic_no = jobp->start_no; GtkChangeLabel(jobp->pic_no); } } #undef DEBUGFUNCTION } void on_xvc_ctrl_back_button_clicked(GtkButton * button, gpointer user_data) { #define DEBUGFUNCTION "on_xvc_ctrl_back_button_clicked()" Job *jobp = xvc_job_ptr(); if ((jobp->flags & FLG_MULTI_IMAGE) == 0) { if (jobp->pic_no >= jobp->step) { jobp->pic_no -= jobp->step; GtkChangeLabel(jobp->pic_no); } else { fprintf(stderr, "%s %s: back button active although picture number < step. this should never happen\n", DEBUGFILE, DEBUGFUNCTION); } if (jobp->pic_no < jobp->step) gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE); } else { if (jobp->movie_no > 0) { jobp->movie_no -= 1; GtkChangeLabel(jobp->pic_no); } else { fprintf(stderr, "%s %s: back button active although movie number == 0. this should never happen\n", DEBUGFILE, DEBUGFUNCTION); } if (jobp->movie_no == 0) gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE); } #undef DEBUGFUNCTION } void on_xvc_ctrl_forward_button_clicked(GtkButton * button, gpointer user_data) { #define DEBUGFUNCTION "on_xvc_ctrl_forward_button_clicked()" GladeXML *xml = NULL; GtkWidget *w = NULL; Job *jobp = xvc_job_ptr(); if ((jobp->flags & FLG_MULTI_IMAGE) == 0) { jobp->pic_no += jobp->step; GtkChangeLabel(jobp->pic_no); if (jobp->pic_no == jobp->step) { xml = glade_get_widget_tree(GTK_WIDGET(xvc_ctrl_main_window)); g_assert(xml); w = glade_xml_get_widget(xml, "xvc_ctrl_back_button"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), TRUE); } } else { jobp->movie_no += 1; GtkChangeLabel(jobp->pic_no); if (jobp->movie_no == 1) { xml = glade_get_widget_tree(GTK_WIDGET(xvc_ctrl_main_window)); g_assert(xml); w = glade_xml_get_widget(xml, "xvc_ctrl_back_button"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), TRUE); } } #undef DEBUGFUNCTION } void on_xvc_ctrl_lock_toggle_toggled(GtkToggleToolButton * togglebutton, gpointer user_data) { #define DEBUGFUNCTION "on_xvc_ctrl_lock_toggle_toggled()" GtkTooltips *tooltips; XRectangle *frame_rectangle; int x, y, pheight, pwidth; tooltips = gtk_tooltips_new(); if (gtk_toggle_tool_button_get_active(togglebutton)) { xvc_frame_lock = 1; // button pressed = move frame with // control gtk_tool_item_set_tooltip(GTK_TOOL_ITEM(togglebutton), tooltips, _("Detach selection frame"), _("Detach selection frame")); gtk_window_set_gravity(GTK_WINDOW(xvc_ctrl_main_window), GDK_GRAVITY_NORTH_WEST); gtk_window_get_position(GTK_WINDOW(xvc_ctrl_main_window), &x, &y); gtk_window_get_size(GTK_WINDOW(xvc_ctrl_main_window), &pwidth, &pheight); gtk_window_set_gravity(GTK_WINDOW(xvc_ctrl_main_window), GDK_GRAVITY_STATIC); gtk_window_get_position(GTK_WINDOW(xvc_ctrl_main_window), &x, &y); gtk_window_get_size(GTK_WINDOW(xvc_ctrl_main_window), &pwidth, &pheight); if (x < 0) x = 0; y += pheight + FRAME_OFFSET; if (y < 0) y = 0; frame_rectangle = xvc_get_capture_area(); xvc_frame_change(x, y, frame_rectangle->width, frame_rectangle->height, FALSE); } else { xvc_frame_lock = 0; gtk_tool_item_set_tooltip(GTK_TOOL_ITEM(togglebutton), tooltips, _("Attach selection frame"), _("Attach selection frame")); } #undef DEBUGFUNCTION } void on_xvc_ctrl_select_toggle_toggled(GtkToggleToolButton * togglebutton, gpointer user_data) { #define DEBUGFUNCTION "on_xvc_ctrl_select_toggle_toggled()" Job *jobp = xvc_job_ptr(); if (gtk_toggle_tool_button_get_active(togglebutton)) { Display *display = GDK_DRAWABLE_XDISPLAY(GTK_WIDGET(xvc_ctrl_main_window)-> window); Cursor cursor; Window root, target = None, temp = None; XEvent event; int buttons = 0; int x_down, y_down, x_up, y_up, x, y, pheight = 0, pwidth = 0; int width, height; XGCValues gcv; GC gc; g_assert(display); root = RootWindow(display, DefaultScreen(display)); cursor = XCreateFontCursor(display, XC_crosshair); gcv.background = XBlackPixel(display, XDefaultScreen(display)); gcv.foreground = XWhitePixel(display, XDefaultScreen(display)); gcv.function = GXinvert; gcv.plane_mask = gcv.background ^ gcv.foreground; gcv.subwindow_mode = IncludeInferiors; gc = XCreateGC(display, root, GCBackground | GCForeground | GCFunction | GCPlaneMask | GCSubwindowMode, &gcv); // grab the mouse // if (XGrabPointer(display, root, False, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeSync, GrabModeAsync, root, cursor, CurrentTime) != GrabSuccess) { fprintf(stderr, "%s %s: Can't grab mouse!\n", DEBUGFILE, DEBUGFUNCTION); return; } x_down = y_down = x_up = y_up = width = height = 0; while (buttons < 2) { // allow pointer events XAllowEvents(display, SyncPointer, CurrentTime); // search in the queue for button events XWindowEvent(display, root, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, &event); switch (event.type) { case ButtonPress: x_down = event.xbutton.x; y_down = event.xbutton.y; target = event.xbutton.subwindow; // window selected // if (target == None) { target = root; } buttons++; break; case ButtonRelease: x_up = event.xbutton.x; y_up = event.xbutton.y; buttons++; break; default: // motion notify if (buttons == 1) { if (width) { // remove old frame XDrawRectangle(display, root, gc, x, y, width, height); } // button is pressed if (x_down > event.xbutton.x) { width = x_down - event.xbutton.x + 1; x = event.xbutton.x; } else { width = event.xbutton.x - x_down + 1; x = x_down; } if (y_down > event.xbutton.y) { height = y_down - event.xbutton.y + 1; y = event.xbutton.y; } else { height = event.xbutton.y - y_down + 1; y = y_down; } XDrawRectangle(display, root, gc, x, y, width, height); } break; } } if (width > 0) // remove old frame XDrawRectangle(display, root, gc, x, y, width, height); XUngrabPointer(display, CurrentTime); // Done with pointer XFreeCursor(display, cursor); XFreeGC(display, gc); if ((x_down != x_up) && (y_down != y_up)) { // an individual frame was selected if (x_up < x_down) { width = x_down - x_up + 2; x = x_up; } else { width = x_up - x_down + 2; x = x_down; } if (y_up < y_down) { height = y_down - y_up + 2; y = y_up; } else { height = y_up - y_down + 2; y = y_down; } if (target != root) target = XmuClientWindow(display, target); XGetWindowAttributes(display, target, &jobp->win_attr); jobp->win_attr.width = width; jobp->win_attr.height = height; } else { if (target != root) { // get the real window target = XmuClientWindow(display, target); } XGetWindowAttributes(display, target, &jobp->win_attr); XTranslateCoordinates(display, target, root, 0, 0, &x, &y, &temp); } jobp->win_attr.x = x; jobp->win_attr.y = y; // we must move the panel a little bit, so get the height of // the panel to adjust the y value gdk_window_get_size(GDK_WINDOW(xvc_ctrl_main_window->window), &pwidth, &pheight); pheight = pheight + FRAME_OFFSET; if (xvc_is_frame_locked()) { gtk_window_move(GTK_WINDOW(xvc_ctrl_main_window), x, y - pheight); } if (jobp->flags & FLG_RUN_VERBOSE) { printf("Original Selection geometry: %dx%d+%d+%d\n", jobp->win_attr.width, jobp->win_attr.height, x, y); } #ifdef USE_FFMPEG // // make sure we have even width and height for ffmpeg // if (jobp->target >= CAP_FFM) { Boolean changed = FALSE; if ((jobp->win_attr.width % 2) > 0) { jobp->win_attr.width--; changed = TRUE; } if ((jobp->win_attr.height % 2) > 0) { jobp->win_attr.height--; changed = TRUE; } if (jobp->win_attr.width < 20) { jobp->win_attr.width = 20; changed = TRUE; } if (jobp->win_attr.height < 20) { jobp->win_attr.height = 20; changed = TRUE; } if (changed) { if (jobp->flags & FLG_RUN_VERBOSE) { printf ("Modified Selection geometry: %dx%d+%d+%d\n", jobp->win_attr.width, jobp->win_attr.height, x, y); } } } #endif // USE_FFMPEG xvc_change_gtk_frame(x, y, jobp->win_attr.width, jobp->win_attr.height, FALSE); jobp->ncolors = xvc_get_colors(display, &jobp->win_attr, &jobp->colors); if (jobp->get_colors) { if (jobp->color_table) free(jobp->color_table); jobp->color_table = (*jobp->get_colors) (jobp->colors, jobp->ncolors); } if (jobp->flags & FLG_RUN_VERBOSE) { fprintf(stderr, "%s %s: color_table first entry: 0x%.8X\n", DEBUGFILE, DEBUGFUNCTION, *(u_int32_t *) jobp->color_table); } xvc_job_set_save_function(jobp->win_attr.visual, jobp->target); #ifdef DEBUG printf("%s%s: new visual: %d\n", DEBUGFILE, DEBUGFUNCTION, jobp->win_attr.visual->class); #endif } gtk_toggle_tool_button_set_active(togglebutton, FALSE); #undef DEBUGFUNCTION } void on_xvc_ctrl_m1_mitem_animate_activate(GtkButton * button, gpointer user_data) { #define DEBUGFUNCTION "on_xvc_ctrl_m1_mitem_animate_activate()" Job *jobp = xvc_job_ptr(); if (!app->current_mode) { xvc_command_execute(app->single_frame.play_cmd, 1, 0, jobp->file, jobp->start_no, jobp->pic_no, jobp->area->width, jobp->area->height, jobp->fps); } else { xvc_command_execute(app->multi_frame.play_cmd, 2, jobp->movie_no, jobp->file, jobp->start_no, jobp->pic_no, jobp->area->width, jobp->area->height, jobp->fps); } #undef DEBUGFUNCTION } void on_xvc_ctrl_edit_button_clicked(GtkToolButton * button, gpointer user_data) { #define DEBUGFUNCTION "on_xvc_ctrl_edit_button_clicked()" Job *jobp = xvc_job_ptr(); if (!app->current_mode) { xvc_command_execute(app->single_frame.edit_cmd, 2, jobp->pic_no, jobp->file, jobp->start_no, jobp->pic_no, jobp->area->width, jobp->area->height, jobp->fps); } else { xvc_command_execute(app->multi_frame.edit_cmd, 2, jobp->movie_no, jobp->file, jobp->start_no, jobp->pic_no, jobp->area->width, jobp->area->height, jobp->fps); } #undef DEBUGFUNCTION } void position_popup_menu(GtkMenu * menu, gint * x, gint * y, gboolean * push_in, gpointer user_data) { #define DEBUGFUNCTION "position_popup_menu()" int pheight = 0, px = 0, py = 0, tx = 0, ty = 0; GtkWidget *w = NULL; w = GTK_WIDGET(user_data); g_return_if_fail(w != NULL); pheight = w->allocation.height; px = w->allocation.x; py = w->allocation.y; tx += px; ty += py; w = gtk_widget_get_toplevel(GTK_WIDGET(w)); g_return_if_fail(w != NULL); gdk_window_get_origin(GDK_WINDOW(w->window), &px, &py); tx += px; ty += py; *x = tx; *y = ty + pheight; #undef DEBUGFUNCTION } // this pops up the menu on right click on filename button gint on_xvc_ctrl_filename_button_button_press_event(GtkWidget * widget, GdkEvent * event) { #define DEBUGFUNCTION "on_xvc_ctrl_filename_button_press_event()" gboolean is_sensitive = FALSE; GdkEventButton *bevent = NULL; g_assert(widget); g_assert(event); bevent = (GdkEventButton *) event; // FIXME: changing from menu sensitive or not to button sensitive or // not ... make sure that that's what I set elsewhere, too. g_object_get((gpointer) widget, (gchar *) "sensitive", &is_sensitive, NULL); if (bevent->button == (guint) 3 && is_sensitive == TRUE) { g_assert(xvc_ctrl_m1); gtk_menu_popup(GTK_MENU(xvc_ctrl_m1), NULL, NULL, position_popup_menu, widget, bevent->button, bevent->time); // Tell calling code that we have handled this event; the buck // stops here. return TRUE; } // Tell calling code that we have not handled this event; pass it on. return FALSE; #undef DEBUGFUNCTION } // this handles the shortcut keybindings for the menu gint on_xvc_ctrl_main_window_key_press_event(GtkWidget * widget, GdkEvent * event) { #define DEBUGFUNCTION "on_xvc_ctrl_main_window_key_press_event()" gboolean is_sensitive = FALSE; GtkWidget *button = NULL, *mitem = NULL; GdkEventKey *kevent = NULL; GladeXML *xml = NULL; g_assert(widget); g_assert(event); kevent = (GdkEventKey *) event; #ifdef DEBUG printf("%s %s: Entering\n", DEBUGFILE, DEBUGFUNCTION); #endif // DEBUG xml = glade_get_widget_tree(xvc_ctrl_main_window); g_assert(xml); button = glade_xml_get_widget(xml, "xvc_ctrl_filename_button"); g_assert(button); g_object_get((gpointer) button, (gchar *) "sensitive", &is_sensitive, NULL); if (kevent->keyval == 112 && kevent->state == 4) { xml = glade_get_widget_tree(xvc_ctrl_m1); g_assert(xml); mitem = glade_xml_get_widget(xml, "xvc_ctrl_m1_mitem_preferences"); g_assert(mitem); gtk_menu_item_activate(GTK_MENU_ITEM(mitem)); return TRUE; } else if (kevent->keyval == 113 && kevent->state == 4) { xml = glade_get_widget_tree(xvc_ctrl_m1); g_assert(xml); mitem = glade_xml_get_widget(xml, "xvc_ctrl_m1_mitem_quit"); g_assert(mitem); gtk_menu_item_activate(GTK_MENU_ITEM(mitem)); return TRUE; } else if (kevent->keyval == 65470 || (kevent->state == 4 && kevent->keyval == 104)) { xml = glade_get_widget_tree(xvc_ctrl_m1); g_assert(xml); mitem = glade_xml_get_widget(xml, "xvc_ctrl_m1_mitem_help"); g_assert(mitem); gtk_menu_item_activate(GTK_MENU_ITEM(mitem)); return TRUE; } #ifdef DEBUG printf("%s %s: Leaving\n", DEBUGFILE, DEBUGFUNCTION); #endif // DEBUG // Tell calling code that we have not handled this event; pass it on. return FALSE; #undef DEBUGFUNCTION } void on_xvc_ctrl_m1_mitem_about_activate(GtkMenuItem * menuitem, gpointer user_data) { GladeXML *xml = NULL; // load the interface xml = glade_xml_new(GLADE_FILE, "xvc_about_main_window", NULL); g_assert(xml); // connect the signals in the interface glade_xml_signal_autoconnect(xml); } void xvc_reset_ctrl_main_window_according_to_current_prefs() { #define DEBUGFUNCTION "xvc_reset_ctrl_main_window_according_to_current_prefs()" GladeXML *mwxml = NULL, *menuxml = NULL; GtkWidget *w = NULL; GtkTooltips *tooltips; Job *jobp = xvc_job_ptr(); #ifdef DEBUG printf("%s %s: Entering\n", DEBUGFILE, DEBUGFUNCTION); #endif // DEBUG mwxml = glade_get_widget_tree(xvc_ctrl_main_window); g_assert(mwxml); menuxml = glade_get_widget_tree(xvc_ctrl_m1); g_assert(menuxml); // various GUI initialization things // // first: the autocontinue menu item // // make autocontinue menuitem invisible if no ffmpeg #ifndef USE_FFMPEG w = NULL; w = glade_xml_get_widget(menuxml, "xvc_ctrl_m1_mitem_autocontinue"); g_return_if_fail(w != NULL); gtk_widget_hide(GTK_WIDGET(w)); w = NULL; w = glade_xml_get_widget(menuxml, "xvc_ctrl_m1_separator1"); g_return_if_fail(w != NULL); gtk_widget_hide(GTK_WIDGET(w)); #else // USE_FFMPEG // the rest in case we have ffmpeg if ((jobp->flags & FLG_MULTI_IMAGE) != 0) { w = glade_xml_get_widget(menuxml, "xvc_ctrl_m1_mitem_autocontinue"); g_assert(w); if ((jobp->flags & FLG_AUTO_CONTINUE) != 0) { gtk_widget_set_sensitive(GTK_WIDGET(w), TRUE); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), TRUE); } else { if (xvc_is_filename_mutable(jobp->file)) { gtk_widget_set_sensitive(GTK_WIDGET(w), TRUE); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), FALSE); } else { gtk_widget_set_sensitive(GTK_WIDGET(w), FALSE); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), FALSE); } } } else { w = glade_xml_get_widget(menuxml, "xvc_ctrl_m1_mitem_autocontinue"); g_assert(w); gtk_widget_set_sensitive(GTK_WIDGET(w), FALSE); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), FALSE); } #endif // USE_FFMPEG // // the filename button // GtkChangeLabel(jobp->pic_no); // // previous and next buttons have different meanings for on-the-fly // encoding // and individual frame capture ... this sets the tooltips accordingly // // // if ((jobp->flags & FLG_MULTI_IMAGE) == 0) { tooltips = gtk_tooltips_new(); g_assert(tooltips); w = NULL; w = glade_xml_get_widget(mwxml, "xvc_ctrl_back_button"); g_assert(w); gtk_tool_item_set_tooltip(GTK_TOOL_ITEM(w), tooltips, _("Move cursor back one frame"), _("Move cursor back one frame")); if (jobp->pic_no >= jobp->step) gtk_widget_set_sensitive(GTK_WIDGET(w), TRUE); else gtk_widget_set_sensitive(GTK_WIDGET(w), FALSE); w = glade_xml_get_widget(mwxml, "xvc_ctrl_forward_button"); g_assert(w); gtk_tool_item_set_tooltip(GTK_TOOL_ITEM(w), tooltips, _("Move cursor to next frame"), _("Move cursor to next frame")); gtk_widget_set_sensitive(GTK_WIDGET(w), TRUE); w = glade_xml_get_widget(mwxml, "xvc_ctrl_filename_button"); g_assert(w); gtk_tooltips_set_tip(GTK_TOOLTIPS(tooltips), GTK_WIDGET(w), _ ("Left Click: Reset frame counter and filename\nRight Click: Popup Menu"), _ ("Left Click: Reset frame counter and filename\nRight Click: Popup Menu")); w = glade_xml_get_widget(mwxml, "xvc_ctrl_edit_button"); g_assert(w); gtk_tool_item_set_tooltip(GTK_TOOL_ITEM(w), tooltips, _("Edit current individual frame"), _("Edit current individual frame")); w = glade_xml_get_widget(mwxml, "xvc_ctrl_step_button"); g_assert(w); gtk_tool_item_set_tooltip(GTK_TOOL_ITEM(w), tooltips, _("Capture single frame"), _("Capture single frame")); } else { GtkWidget *next = NULL, *previous = NULL, *filename = NULL, *w = NULL; next = glade_xml_get_widget(mwxml, "xvc_ctrl_forward_button"); g_assert(next); previous = glade_xml_get_widget(mwxml, "xvc_ctrl_back_button"); g_assert(previous); filename = glade_xml_get_widget(mwxml, "xvc_ctrl_filename_button"); g_assert(filename); tooltips = gtk_tooltips_new(); g_assert(tooltips); if (xvc_is_filename_mutable(jobp->file)) { gtk_widget_set_sensitive(GTK_WIDGET(next), TRUE); if (jobp->movie_no > 0) gtk_widget_set_sensitive(GTK_WIDGET(previous), TRUE); else gtk_widget_set_sensitive(GTK_WIDGET(previous), FALSE); } else { gtk_widget_set_sensitive(GTK_WIDGET(next), FALSE); gtk_widget_set_sensitive(GTK_WIDGET(previous), FALSE); } gtk_tool_item_set_tooltip(GTK_TOOL_ITEM(previous), tooltips, _("Move cursor to previous movie"), _("Move cursor to previous movie")); gtk_tool_item_set_tooltip(GTK_TOOL_ITEM(next), tooltips, _("Move cursor to next movie"), _("Move cursor to next movie")); gtk_tooltips_set_tip(GTK_TOOLTIPS(tooltips), GTK_WIDGET(filename), _ ("Left Click: Reset movie counter to zero\nRight Click: Popup Menu"), _ ("Left Click: Reset movie counter to zero\nRight Click: Popup Menu")); w = glade_xml_get_widget(mwxml, "xvc_ctrl_edit_button"); g_assert(w); gtk_tool_item_set_tooltip(GTK_TOOL_ITEM(w), tooltips, _("Edit current movie"), _("Edit current movie")); w = glade_xml_get_widget(mwxml, "xvc_ctrl_step_button"); g_assert(w); gtk_tool_item_set_tooltip(GTK_TOOL_ITEM(w), tooltips, NULL, NULL); } // // capture type radio buttons // // make capture type radio buttons invisible if no ffmpeg #ifndef USE_FFMPEG w = NULL; w = glade_xml_get_widget(menuxml, "xvc_ctrl_m1_mitem_sf_capture"); g_return_if_fail(w != NULL); gtk_widget_hide(GTK_WIDGET(w)); w = NULL; w = glade_xml_get_widget(menuxml, "xvc_ctrl_m1_mitem_mf_capture"); g_return_if_fail(w != NULL); gtk_widget_hide(GTK_WIDGET(w)); #else // USE_FFMPEG if (app->current_mode == 0) { w = NULL; w = glade_xml_get_widget(menuxml, "xvc_ctrl_m1_mitem_sf_capture"); g_return_if_fail(w != NULL); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), TRUE); } else { w = NULL; w = glade_xml_get_widget(menuxml, "xvc_ctrl_m1_mitem_mf_capture"); g_return_if_fail(w != NULL); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), TRUE); } #endif // USE_FFMPEG #undef DEBUGFUNCTION }