~ubuntu-branches/ubuntu/jaunty/xvidcap/jaunty-proposed

« back to all changes in this revision

Viewing changes to src/gnome_ui.c

  • Committer: Bazaar Package Importer
  • Author(s): John Dong
  • Date: 2008-02-25 15:47:12 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20080225154712-qvr11ekcea4c9ry8
Tags: 1.1.6-0.1ubuntu1
* Merge from debian-multimedia (LP: #120003), Ubuntu Changes:
 - For ffmpeg-related build-deps, remove cvs from package names.
 - Standards-Version 3.7.3
 - Maintainer Spec

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * \file gnome_ui.c
 
3
 *
 
4
 * This file contains the main control UI for xvidcap
 
5
 * \todo rename the global variables pthread* to xvc_pthread*
 
6
 */
 
7
 
 
8
/* Copyright (C) 2003-07 Karl H. Beckers, Frankfurt
 
9
 * EMail: khb@jarre-de-the.net
 
10
 *
 
11
 * This program is free software; you can redistribute it and/or modify
 
12
 * it under the terms of the GNU General Public License as published by
 
13
 * the Free Software Foundation; either version 2 of the License, or
 
14
 * (at your option) any later version.
 
15
 *
 
16
 * This program is distributed in the hope that it will be useful,
 
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 
19
 * GNU General Public License for more details.
 
20
 *
 
21
 * You should have received a copy of the GNU General Public License
 
22
 * along with this program; if not, write to the Free Software
 
23
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
24
 *
 
25
 *
 
26
 */
 
27
#ifndef DOXYGEN_SHOULD_SKIP_THIS
 
28
#ifdef HAVE_CONFIG_H
 
29
# include <config.h>
 
30
#endif
 
31
 
 
32
#define DEBUGFILE "gnome_ui.c"
 
33
#endif     // DOXYGEN_SHOULD_SKIP_THIS
 
34
 
 
35
#include <sys/time.h>                  // for timeval struct and related
 
36
#include <sys/poll.h>
 
37
#include <stdlib.h>
 
38
#include <unistd.h>
 
39
 
 
40
#ifdef SOLARIS
 
41
#include <X11/X.h>
 
42
#include <X11/Xlib.h>
 
43
#endif     // SOLARIS
 
44
#include <X11/cursorfont.h>
 
45
#include <X11/Xmu/WinUtil.h>
 
46
 
 
47
#ifdef USE_XDAMAGE
 
48
#include <X11/extensions/Xfixes.h>
 
49
#include <X11/extensions/Xdamage.h>
 
50
#include <X11/Xproto.h>
 
51
#endif     // USE_XDAMAGE
 
52
 
 
53
#include <glib.h>
 
54
#include <gdk/gdkx.h>
 
55
#include <glade/glade.h>
 
56
#include <pthread.h>
 
57
#include <signal.h>
 
58
 
 
59
#include "led_meter.h"
 
60
#include "job.h"
 
61
#include "app_data.h"
 
62
#include "control.h"
 
63
#include "colors.h"
 
64
#include "codecs.h"
 
65
#include "frame.h"
 
66
#include "gnome_warning.h"
 
67
#include "gnome_options.h"
 
68
#include "gnome_ui.h"
 
69
#include "gnome_frame.h"
 
70
#include "xvidcap-intl.h"
 
71
#include "eggtrayicon.h"
 
72
 
 
73
/*
 
74
 * globals
 
75
 */
 
76
#ifndef DOXYGEN_SHOULD_SKIP_THIS
 
77
extern GtkWidget *xvc_pref_main_window;
 
78
extern GtkWidget *xvc_warn_main_window;
 
79
#endif     // DOXYGEN_SHOULD_SKIP_THIS
 
80
 
 
81
/** \brief make the main control panel globally available */
 
82
GtkWidget *xvc_ctrl_main_window = NULL;
 
83
 
 
84
/**
 
85
 * \brief make the main control panel's menu globally available
 
86
 *
 
87
 * @note this is needed because the warning dialog may need to change the
 
88
 *      status of capture type select buttons. If you change from e. g.
 
89
 *      single-frame capture to multi-frame capture, xvidcap checks your
 
90
 *      preferences for the new capture type and finding errors allows you
 
91
 *      to cancel back out of the change ... and needs to reset the menu.
 
92
 */
 
93
GtkWidget *xvc_ctrl_m1 = NULL;
 
94
 
 
95
/**
 
96
 * \brief the value here is picked up by the LED frame drop monitor widget.
 
97
 *      Set to 0 to clear the widget.
 
98
 */
 
99
int xvc_led_time = 0;
 
100
 
 
101
// those are for recording video in thread
 
102
/** \brief mutex for the recording, state changes and pausing/unpausing */
 
103
pthread_mutex_t recording_mutex = PTHREAD_MUTEX_INITIALIZER;
 
104
 
 
105
/** \brief condition for pausing/unpausing a recording effectively */
 
106
pthread_cond_t recording_condition_unpaused;
 
107
 
 
108
/** \brief the recording thread */
 
109
static pthread_t recording_thread;
 
110
 
 
111
/** \brief attributes of the recording thread */
 
112
static pthread_attr_t recording_thread_attr;
 
113
 
 
114
#ifdef USE_XDAMAGE
 
115
/** \brief mutex for the Xdamage support. It governs write access to the
 
116
 *      damaged region storage */
 
117
pthread_mutex_t damage_regions_mutex = PTHREAD_MUTEX_INITIALIZER;
 
118
#endif     // USE_XDAMAGE
 
119
 
 
120
/** \brief is the recording thread running?
 
121
 *
 
122
 * \todo find out if there's a way to tell that from the tread directly
 
123
 */
 
124
static Boolean recording_thread_running = FALSE;
 
125
 
 
126
/** \brief make the results dialog globally available to callbacks here */
 
127
static GtkWidget *xvc_result_dialog = NULL;
 
128
 
 
129
/** \brief remember the previous led_time set */
 
130
static int last_led_time = 0;
 
131
 
 
132
/** \brief remember the previously set picture number to allow for a quick
 
133
 *      check on the next call if we need to do anything */
 
134
static int last_pic_no = 0;
 
135
 
 
136
/** \brief store a timer that may be registered when setting a max recording
 
137
 *      time */
 
138
static guint stop_timer_id = 0;
 
139
 
 
140
/** calculate recording time */
 
141
static long start_time = 0, pause_time = 0, time_captured = 0;
 
142
 
 
143
/** \brief used to faciltate passing the filename selection from a file
 
144
 *      selector dialog back off the results dialog back to the results
 
145
 *      dialog and eventually the main dialog */
 
146
static char *target_file_name = NULL;
 
147
 
 
148
/**
 
149
 * \brief the errors found on submitting a set of preferences
 
150
 *
 
151
 * Used to pass this between the various components involved in deciding
 
152
 * what to do when OK is clicked
 
153
 * \todo the whole display of preferences and warning dialogs should be
 
154
 *      simplified through _run_dialog()
 
155
 */
 
156
static XVC_ErrorListItem *errors_after_cli = NULL;
 
157
 
 
158
/**
 
159
 * \brief remember the number of attempts to submit a set of preferences
 
160
 *
 
161
 * Hitting OK on a warning may make automatic changes to the preferences.
 
162
 * But it may not resolve all conflicts in one go and pop up the warning
 
163
 * dialog again, again offering automatic resultion actions. This should be
 
164
 * a rare case, however
 
165
 */
 
166
static int OK_attempts = 0;
 
167
 
 
168
/** \brief eggtrayicon for minimizing xvidcap to the system tray */
 
169
static GtkWidget *tray_icon = NULL;
 
170
 
 
171
/** \brief frame drop monitor for inclusion in the system tray */
 
172
static GtkWidget *tray_frame_mon = NULL;
 
173
 
 
174
/** \brief popup menu for the system tray icon */
 
175
static GtkWidget *tray_icon_menu = NULL;
 
176
 
 
177
/*
 
178
 * HELPER FUNCTIONS ...
 
179
 *
 
180
 *
 
181
 */
 
182
/**
 
183
 * \brief create the LED frame drop meter widget
 
184
 *
 
185
 * This function needs to conform to the custom widget creation functions
 
186
 * as libglade uses them
 
187
 * @param widget_name the name of the widget as set in glade
 
188
 * @param string1 not used
 
189
 * @param string2 not used
 
190
 * @param int1 not used
 
191
 * @param int2 not used
 
192
 * @return the created LED frame drop meter widget
 
193
 */
 
194
GtkWidget *
 
195
glade_create_led_meter (gchar * widget_name, gchar * string1,
 
196
                        gchar * string2, gint int1, gint int2)
 
197
{
 
198
#define DEBUGFUNCTION "glade_create_led_meter()"
 
199
    GtkWidget *frame_monitor = led_meter_new ();
 
200
 
 
201
    g_assert (frame_monitor);
 
202
 
 
203
    gtk_widget_set_name (GTK_WIDGET (frame_monitor), widget_name);
 
204
    gtk_widget_show (GTK_WIDGET (frame_monitor));
 
205
 
 
206
    return frame_monitor;
 
207
#undef DEBUGFUNCTION
 
208
}
 
209
 
 
210
/*
 
211
 * this isn't used atm
 
212
 *
 
213
 gint keySnooper (GtkWidget *grab_widget, GdkEventKey *event, gpointer func_data) {
 
214
 printf("keyval: %i - mods: %i\n", event->keyval, event->state);
 
215
 } */
 
216
 
 
217
/**
 
218
 * \brief change value of frame/filename display
 
219
 *
 
220
 * @param pic_no update the display according to this frame number
 
221
 */
 
222
void
 
223
GtkChangeLabel (int pic_no)
 
224
{
 
225
#define DEBUGFUNCTION "GtkChangeLabel()"
 
226
    static char file[PATH_MAX + 1], tmp_buf[PATH_MAX + 1];
 
227
    PangoLayout *layout = NULL;
 
228
    gint width = 0, height = 0;
 
229
    int filename_length = 0;
 
230
    GladeXML *xml = NULL;
 
231
    GtkWidget *w = NULL;
 
232
    Job *jobp = xvc_job_ptr ();
 
233
    XVC_AppData *app = xvc_appdata_ptr ();
 
234
 
 
235
    // generate the string to display in the filename button
 
236
    if (app->current_mode > 0) {
 
237
        sprintf (tmp_buf, jobp->file, jobp->movie_no);
 
238
        sprintf (file, "%s[%04d]", tmp_buf, pic_no);
 
239
    } else {
 
240
        sprintf (file, jobp->file, pic_no);
 
241
    }
 
242
    // cut the string to a sensible maximum length
 
243
    filename_length = strlen (file);
 
244
    if (filename_length > 60) {
 
245
        char tmp_file[PATH_MAX + 1];
 
246
        char *tmp_file2, *ptr;
 
247
        int n;
 
248
 
 
249
        strncpy (tmp_file, file, 20);
 
250
        tmp_file[20] = 0;
 
251
        n = filename_length - 20;
 
252
        ptr = (char *) &file + n;
 
253
        tmp_file2 = strncat (tmp_file, "...", 4);
 
254
        tmp_file2 = strncat (tmp_file, ptr, 45);
 
255
        strncpy (file, tmp_file2, 45);
 
256
    }
 
257
    // get the filename button widget
 
258
    xml = glade_get_widget_tree (xvc_ctrl_main_window);
 
259
    g_assert (xml);
 
260
    w = glade_xml_get_widget (xml, "xvc_ctrl_filename_button");
 
261
    g_assert (w);
 
262
 
 
263
    // set the text
 
264
    gtk_button_set_label (GTK_BUTTON (w), file);
 
265
 
 
266
    // adjust the size of the filname button
 
267
    layout = gtk_widget_create_pango_layout (w, file);
 
268
    g_assert (layout);
 
269
    pango_layout_get_pixel_size (layout, &width, &height);
 
270
    g_object_unref (layout);
 
271
 
 
272
    gtk_widget_set_size_request (GTK_WIDGET (w), (width + 30), -1);
 
273
#undef DEBUGFUNCTION
 
274
}
 
275
 
 
276
/**
 
277
 * \brief implements the actions required when successfully submitting the
 
278
 *      warning dialog, mainly resetting the control UI to the current
 
279
 *      state of the preferences.
 
280
 */
 
281
void
 
282
warning_submit ()
 
283
{
 
284
#define DEBUGFUNCTION "warning_submit()"
 
285
#ifdef DEBUG
 
286
    printf ("%s %s: Entering\n", DEBUGFILE, DEBUGFUNCTION);
 
287
#endif     // DEBUG
 
288
    XVC_AppData *app = xvc_appdata_ptr ();
 
289
 
 
290
    xvc_job_set_from_app_data (app);
 
291
 
 
292
    // set controls active/inactive/sensitive/insensitive according to
 
293
    // current options
 
294
    if (!(app->flags & FLG_NOGUI)) {
 
295
        xvc_reset_ctrl_main_window_according_to_current_prefs ();
 
296
    }
 
297
 
 
298
    if (xvc_errorlist_delete (errors_after_cli)) {
 
299
        fprintf (stderr,
 
300
                 "%s %s: Unrecoverable error while freeing error list, please contact the xvidcap project.\n",
 
301
                 DEBUGFILE, DEBUGFUNCTION);
 
302
        exit (1);
 
303
    }
 
304
    // reset attempts so warnings will be shown again next time ...
 
305
    OK_attempts = 0;
 
306
 
 
307
#ifdef DEBUG
 
308
    printf ("%s %s: Leaving\n", DEBUGFILE, DEBUGFUNCTION);
 
309
#endif     // DEBUG
 
310
#undef DEBUGFUNCTION
 
311
}
 
312
 
 
313
#ifdef USE_FFMPEG
 
314
/**
 
315
 * \brief this toggles the type of capture (sf vs. mf) currently active
 
316
 *
 
317
 * This is global because it can be necessary to call this from the warning
 
318
 * dialog.
 
319
 */
 
320
void
 
321
xvc_toggle_cap_type ()
 
322
{
 
323
#define DEBUGFUNCTION "xvc_toggle_cap_type()"
 
324
    int count_non_info_messages, rc;
 
325
    XVC_AppData *app = xvc_appdata_ptr ();
 
326
 
 
327
    count_non_info_messages = 0;
 
328
    rc = 0;
 
329
    errors_after_cli = xvc_appdata_validate (app, 1, &rc);
 
330
 
 
331
    if (rc == -1) {
 
332
        fprintf (stderr,
 
333
                 "%s %s: Unrecoverable error while validating options, please contact the xvidcap project.\n",
 
334
                 DEBUGFILE, DEBUGFUNCTION);
 
335
        exit (1);
 
336
    }
 
337
    // warning dialog
 
338
    if (errors_after_cli != NULL) {
 
339
        XVC_ErrorListItem *err;
 
340
 
 
341
        err = errors_after_cli;
 
342
        for (; err != NULL; err = err->next) {
 
343
            if (err->err->type != XVC_ERR_INFO)
 
344
                count_non_info_messages++;
 
345
        }
 
346
        if (count_non_info_messages > 0
 
347
            || (app->flags & FLG_RUN_VERBOSE && OK_attempts == 0)) {
 
348
            xvc_warn_main_window =
 
349
                xvc_create_warning_with_errors (errors_after_cli, 1);
 
350
            OK_attempts++;
 
351
        } else {
 
352
            warning_submit ();
 
353
        }
 
354
    } else {
 
355
        warning_submit ();
 
356
    }
 
357
#undef DEBUGFUNCTION
 
358
}
 
359
 
 
360
/**
 
361
 * \brief this undoes an attempt to toggle the type of capture (sf vs. mf)
 
362
 *      currently active
 
363
 *
 
364
 * This is global because it can be necessary to call this from the warning
 
365
 * dialog.
 
366
 */
 
367
void
 
368
xvc_undo_toggle_cap_type ()
 
369
{
 
370
#define DEBUGFUNCTION "xvc_undo_toggle_cap_type()"
 
371
    GladeXML *xml = NULL;
 
372
    GtkWidget *mitem = NULL;
 
373
    XVC_AppData *app = xvc_appdata_ptr ();
 
374
 
 
375
    xml = glade_get_widget_tree (xvc_ctrl_m1);
 
376
    g_assert (xml);
 
377
 
 
378
    OK_attempts = 0;
 
379
 
 
380
#ifdef DEBUG
 
381
    printf ("%s %s: pre current_mode %i\n", DEBUGFILE, DEBUGFUNCTION,
 
382
            app->current_mode);
 
383
#endif     // DEBUG
 
384
 
 
385
    app->current_mode = (app->current_mode == 0) ? 1 : 0;
 
386
 
 
387
#ifdef DEBUG
 
388
    printf ("%s %s: post current_mode %i\n", DEBUGFILE, DEBUGFUNCTION,
 
389
            app->current_mode);
 
390
#endif     // DEBUG
 
391
 
 
392
    if (app->current_mode == 0) {
 
393
        mitem = glade_xml_get_widget (xml, "xvc_ctrl_m1_mitem_sf_capture");
 
394
        g_assert (mitem);
 
395
        gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mitem), TRUE);
 
396
    } else {
 
397
        mitem = glade_xml_get_widget (xml, "xvc_ctrl_m1_mitem_mf_capture");
 
398
        g_assert (mitem);
 
399
        gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mitem), TRUE);
 
400
    }
 
401
 
 
402
#undef DEBUGFUNCTION
 
403
}
 
404
#endif     // USE_FFMPEG
 
405
 
 
406
#ifdef USE_XDAMAGE
 
407
/**
 
408
 * \brief event filter to register with gdk to retrieve X11 events
 
409
 *
 
410
 * @param xevent pointer to the wrapped X11 event
 
411
 * @param event pointer to the GdkEvent
 
412
 * @param user_data pointer to other data
 
413
 * @return flag to gdk whether to pass the event on or drop it
 
414
 */
 
415
GdkFilterReturn
 
416
xvc_xdamage_event_filter (GdkXEvent * xevent, GdkEvent * event, void *user_data)
 
417
{
 
418
    XVC_AppData *app = xvc_appdata_ptr ();
 
419
    XEvent *xev = (XEvent *) xevent;
 
420
    XDamageNotifyEvent *e = (XDamageNotifyEvent *) (xevent);
 
421
    static XserverRegion region = None, clip_region = None;
 
422
    Job *job = xvc_job_ptr ();
 
423
 
 
424
    if (!recording_thread_running || job == NULL ||
 
425
        (job->flags & FLG_USE_XDAMAGE) == 0) {
 
426
        if (region != None) {
 
427
            XFixesDestroyRegion (app->dpy, region);
 
428
            region = None;
 
429
        }
 
430
        if (clip_region != None) {
 
431
            XFixesDestroyRegion (app->dpy, clip_region);
 
432
            clip_region = None;
 
433
        }
 
434
        return GDK_FILTER_CONTINUE;
 
435
    }
 
436
 
 
437
    if (region == None)
 
438
        region = XFixesCreateRegion (app->dpy, 0, 0);
 
439
    if (clip_region == None)
 
440
        clip_region = XFixesCreateRegion (app->dpy, 0, 0);
 
441
 
 
442
    if (xev->type == MapNotify) {
 
443
        // XSelectInput (app->dpy, xev->xcreatewindow.window, StructureNotifyMask);
 
444
//      if (!attribs.override_redirect /* && attribs.depth==pdata->specs.depth */) {
 
445
        XDamageCreate (app->dpy, xev->xcreatewindow.window,
 
446
                       XDamageReportRawRectangles);
 
447
//      }
 
448
    } else if (xev->type == app->dmg_event_base) {
 
449
        XRectangle rect = {
 
450
            XVC_MAX (e->area.x - 10, 0),
 
451
            XVC_MAX (e->area.y - 10, 0),
 
452
            e->area.width + 20,
 
453
            e->area.height + 20
 
454
        };
 
455
        XRectangle clip_rect = {
 
456
            app->area->x,
 
457
            app->area->y,
 
458
            app->area->width,
 
459
            app->area->height
 
460
        };
 
461
        XFixesSetRegion (app->dpy, region, &rect, 1);
 
462
        XFixesSetRegion (app->dpy, clip_region, &clip_rect, 1);
 
463
 
 
464
        // Offset the region with the windows' position
 
465
        XFixesTranslateRegion (app->dpy, region, e->geometry.x, e->geometry.y);
 
466
        XFixesIntersectRegion (app->dpy, clip_region, region, clip_region);
 
467
 
 
468
        pthread_mutex_lock (&damage_regions_mutex);
 
469
        XFixesUnionRegion (app->dpy, job->dmg_region, job->dmg_region,
 
470
                           clip_region);
 
471
        XDamageSubtract (app->dpy, e->damage, region, None);
 
472
        pthread_mutex_unlock (&damage_regions_mutex);
 
473
    }
 
474
 
 
475
    return GDK_FILTER_CONTINUE;
 
476
}
 
477
#endif     // USE_XDAMAGE
 
478
 
 
479
/**
 
480
 * \brief this is what the thread spawned on record actually does. It is
 
481
 *      normally stopped by setting the state machine to VC_STOP
 
482
 */
 
483
void
 
484
do_record_thread ()
 
485
{
 
486
#define DEBUGFUNCTION "do_record_thread()"
 
487
    Job *job = xvc_job_ptr ();
 
488
    long pause = 1000;
 
489
 
 
490
#ifdef DEBUG
 
491
    printf ("%s %s: Entering with state = %i and tid = %i\n", DEBUGFILE,
 
492
            DEBUGFUNCTION, job->state, recording_thread);
 
493
#endif     // DEBUG
 
494
 
 
495
    recording_thread_running = TRUE;
 
496
 
 
497
    if (!(job->flags & FLG_NOGUI)) {
 
498
        xvc_idle_add (xvc_change_filename_display, (void *) NULL);
 
499
        xvc_idle_add (xvc_frame_monitor, (void *) NULL);
 
500
    }
 
501
 
 
502
    while ((job->state & VC_READY) == 0) {
 
503
#ifdef DEBUG
 
504
        printf ("%s %s: going for next frame with state %i\n", DEBUGFILE,
 
505
                DEBUGFUNCTION, job->state);
 
506
#endif
 
507
        if ((job->state & VC_PAUSE) && !(job->state & VC_STEP)) {
 
508
            // make the led monitor stop for pausing
 
509
            xvc_led_time = 0;
 
510
 
 
511
            pthread_mutex_lock (&recording_mutex);
 
512
            pthread_cond_wait (&recording_condition_unpaused, &recording_mutex);
 
513
            pthread_mutex_unlock (&recording_mutex);
 
514
#ifdef DEBUG
 
515
            printf ("%s %s: unpaused\n", DEBUGFILE, DEBUGFUNCTION);
 
516
#endif     // DEBUG
 
517
        }
 
518
        pause = job->capture ();
 
519
 
 
520
        if (pause > 0)
 
521
            usleep (pause * 1000);
 
522
#ifdef DEBUG
 
523
        printf ("%s %s: woke up\n", DEBUGFILE, DEBUGFUNCTION);
 
524
#endif     // DEBUG
 
525
    }
 
526
 
 
527
#ifdef DEBUG
 
528
    printf ("%s %s: Leaving\n", DEBUGFILE, DEBUGFUNCTION);
 
529
#endif     // DEBUG
 
530
 
 
531
    recording_thread_running = FALSE;
 
532
    pthread_exit (NULL);
 
533
#undef DEBUGFUNCTION
 
534
}
 
535
 
 
536
/**
 
537
 * \brief implements those actions required for stopping a capture session
 
538
 *      that are not GUI related
 
539
 */
 
540
static void
 
541
stop_recording_nongui_stuff ()
 
542
{
 
543
#define DEBUGFUNCTION "stop_recording_nongui_stuff()"
 
544
    int state = 0;
 
545
    struct timeval curr_time;
 
546
    long stop_time = 0;
 
547
    XVC_AppData *app = xvc_appdata_ptr ();
 
548
 
 
549
#ifdef DEBUG
 
550
    printf ("%s %s: Entering with thread running %i\n",
 
551
            DEBUGFILE, DEBUGFUNCTION, recording_thread_running);
 
552
#endif     // DEBUG
 
553
 
 
554
    if (pause_time) {
 
555
        stop_time = pause_time;
 
556
    } else {
 
557
        gettimeofday (&curr_time, NULL);
 
558
        stop_time = curr_time.tv_sec * 1000 + curr_time.tv_usec / 1000;
 
559
        time_captured += (stop_time - start_time);
 
560
    }
 
561
 
 
562
    if (stop_timer_id)
 
563
        g_source_remove (stop_timer_id);
 
564
 
 
565
    state = VC_STOP;
 
566
    if (app->flags & FLG_AUTO_CONTINUE) {
 
567
        state |= VC_CONTINUE;
 
568
    }
 
569
    xvc_job_set_state (state);
 
570
 
 
571
    if (recording_thread_running) {
 
572
        pthread_join (recording_thread, NULL);
 
573
#ifdef DEBUG
 
574
        printf ("%s %s: joined thread\n", DEBUGFILE, DEBUGFUNCTION);
 
575
#endif     // DEBUG
 
576
    }
 
577
#ifdef USE_XDAMAGE
 
578
    if (app->flags & FLG_USE_XDAMAGE)
 
579
        gdk_window_remove_filter (NULL,
 
580
                                  (GdkFilterFunc) xvc_xdamage_event_filter,
 
581
                                  NULL);
 
582
#endif     // USE_XDAMAGE
 
583
 
 
584
#ifdef DEBUG
 
585
    printf ("%s %s: Leaving\n", DEBUGFILE, DEBUGFUNCTION);
 
586
#endif     // DEBUG
 
587
 
 
588
#undef DEBUGFUNCTION
 
589
}
 
590
 
 
591
/**
 
592
 * \brief displays the xvidcap user manual.
 
593
 */
 
594
void
 
595
do_results_help ()
 
596
{
 
597
    system ((char *) "yelp ghelp:xvidcap?xvidcap-results &");
 
598
}
 
599
 
 
600
/**
 
601
 * \brief implements the GUI related actions involved when stopping a
 
602
 *      capture session.
 
603
 */
 
604
static void
 
605
stop_recording_gui_stuff ()
 
606
{
 
607
#define DEBUGFUNCTION "stop_recording_gui_stuff()"
 
608
    GladeXML *xml = NULL;
 
609
    GtkWidget *w = NULL;
 
610
    XVC_CapTypeOptions *target = NULL;
 
611
    Job *jobp = xvc_job_ptr ();
 
612
    XVC_AppData *app = xvc_appdata_ptr ();
 
613
 
 
614
#ifdef DEBUG
 
615
    printf ("%s %s: Entering\n", DEBUGFILE, DEBUGFUNCTION);
 
616
#endif     // DEBUG
 
617
 
 
618
#ifdef USE_FFMPEG
 
619
    if (app->current_mode > 0)
 
620
        target = &(app->multi_frame);
 
621
    else
 
622
#endif     // USE_FFMPEG
 
623
        target = &(app->single_frame);
 
624
 
 
625
    xml = glade_get_widget_tree (GTK_WIDGET (xvc_ctrl_main_window));
 
626
    g_assert (xml);
 
627
 
 
628
    // GUI stuff
 
629
    w = glade_xml_get_widget (xml, "xvc_ctrl_pause_toggle");
 
630
    g_assert (w);
 
631
    gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (w), FALSE);
 
632
 
 
633
    w = glade_xml_get_widget (xml, "xvc_ctrl_select_toggle");
 
634
    g_assert (w);
 
635
    gtk_widget_set_sensitive (GTK_WIDGET (w), TRUE);
 
636
 
 
637
    w = glade_xml_get_widget (xml, "xvc_ctrl_record_toggle");
 
638
    g_assert (w);
 
639
    gtk_widget_set_sensitive (GTK_WIDGET (w), TRUE);
 
640
    if (gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON (w)))
 
641
        gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (w), FALSE);
 
642
 
 
643
    w = glade_xml_get_widget (xml, "xvc_ctrl_filename_button");
 
644
    g_assert (w);
 
645
    gtk_widget_set_sensitive (GTK_WIDGET (w), TRUE);
 
646
 
 
647
    w = glade_xml_get_widget (xml, "xvc_ctrl_edit_button");
 
648
    g_assert (w);
 
649
    gtk_widget_set_sensitive (GTK_WIDGET (w), TRUE);
 
650
 
 
651
    w = glade_xml_get_widget (xml, "xvc_ctrl_step_button");
 
652
    g_assert (w);
 
653
    gtk_widget_set_sensitive (GTK_WIDGET (w), FALSE);
 
654
 
 
655
    if (app->current_mode > 0) {
 
656
 
 
657
        if (xvc_is_filename_mutable (jobp->file) == TRUE) {
 
658
            if (jobp->movie_no > 0) {
 
659
                w = glade_xml_get_widget (xml, "xvc_ctrl_back_button");
 
660
                g_assert (w);
 
661
                gtk_widget_set_sensitive (GTK_WIDGET (w), TRUE);
 
662
            }
 
663
 
 
664
            w = glade_xml_get_widget (xml, "xvc_ctrl_forward_button");
 
665
            g_assert (w);
 
666
            gtk_widget_set_sensitive (GTK_WIDGET (w), TRUE);
 
667
        }
 
668
    } else {
 
669
        if (xvc_is_filename_mutable (jobp->file) == TRUE) {
 
670
            if (jobp->pic_no >= target->step) {
 
671
                w = glade_xml_get_widget (xml, "xvc_ctrl_back_button");
 
672
                g_assert (w);
 
673
                gtk_widget_set_sensitive (GTK_WIDGET (w), TRUE);
 
674
            }
 
675
 
 
676
            if (target->frames == 0
 
677
                || jobp->pic_no < (target->frames - target->step)) {
 
678
                w = glade_xml_get_widget (xml, "xvc_ctrl_forward_button");
 
679
                g_assert (w);
 
680
                gtk_widget_set_sensitive (GTK_WIDGET (w), TRUE);
 
681
            }
 
682
        }
 
683
    }
 
684
 
 
685
    w = glade_xml_get_widget (xml, "xvc_ctrl_pause_toggle");
 
686
    g_assert (w);
 
687
    if (gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON (w)))
 
688
        gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (w), FALSE);
 
689
    w = glade_xml_get_widget (xml, "xvc_ctrl_stop_toggle");
 
690
    g_assert (w);
 
691
    if (!gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON (w)))
 
692
        gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (w), TRUE);
 
693
 
 
694
    GtkChangeLabel (jobp->pic_no);
 
695
 
 
696
    if (app->flags & FLG_TO_TRAY) {
 
697
        gtk_widget_destroy (GTK_WIDGET (tray_frame_mon));
 
698
        tray_frame_mon = NULL;
 
699
        gtk_widget_destroy (GTK_WIDGET (tray_icon));
 
700
        tray_icon = NULL;
 
701
        gtk_widget_destroy (GTK_WIDGET (tray_icon_menu));
 
702
        tray_icon_menu = NULL;
 
703
        gtk_window_set_skip_taskbar_hint (GTK_WINDOW (xvc_ctrl_main_window),
 
704
                                          FALSE);
 
705
        gtk_window_deiconify (GTK_WINDOW (xvc_ctrl_main_window));
 
706
    }
 
707
 
 
708
    if ((strlen (target->file) < 1 ||
 
709
         (app->flags & FLG_ALWAYS_SHOW_RESULTS) > 0) &&
 
710
        (app->flags & FLG_AUTO_CONTINUE) == 0) {
 
711
        int result = 0;
 
712
        float fps_ratio = 0;
 
713
        char buf[100];
 
714
 
 
715
        GladeXML *xml = NULL;
 
716
        GtkWidget *w = NULL;
 
717
 
 
718
        // load the interface
 
719
        xml = glade_xml_new (XVC_GLADE_FILE, "xvc_result_dialog", NULL);
 
720
        g_assert (xml);
 
721
        // connect the signals in the interface
 
722
        glade_xml_signal_autoconnect (xml);
 
723
        // get the widget
 
724
        xvc_result_dialog = glade_xml_get_widget (xml, "xvc_result_dialog");
 
725
        g_assert (xvc_result_dialog);
 
726
 
 
727
        // width
 
728
        w = glade_xml_get_widget (xml, "xvc_result_dialog_width_label");
 
729
        g_assert (w);
 
730
        snprintf (buf, 99, "%i", app->area->width);
 
731
        gtk_label_set_text (GTK_LABEL (w), buf);
 
732
 
 
733
        // height
 
734
        w = glade_xml_get_widget (xml, "xvc_result_dialog_height_label");
 
735
        g_assert (w);
 
736
        snprintf (buf, 99, "%i", app->area->height);
 
737
        gtk_label_set_text (GTK_LABEL (w), buf);
 
738
 
 
739
        // video format
 
740
        w = glade_xml_get_widget (xml, "xvc_result_dialog_video_format_label");
 
741
        g_assert (w);
 
742
        gtk_label_set_text (GTK_LABEL (w),
 
743
                            _(xvc_formats[jobp->target].longname));
 
744
 
 
745
        // video codec
 
746
        w = glade_xml_get_widget (xml, "xvc_result_dialog_video_codec_label");
 
747
        g_assert (w);
 
748
        gtk_label_set_text (GTK_LABEL (w), xvc_codecs[jobp->targetCodec].name);
 
749
 
 
750
        // audio codec
 
751
        w = glade_xml_get_widget (xml, "xvc_result_dialog_audio_codec_label");
 
752
        g_assert (w);
 
753
        gtk_label_set_text (GTK_LABEL (w),
 
754
                            ((jobp->flags & FLG_REC_SOUND) ?
 
755
                             xvc_audio_codecs[jobp->au_targetCodec].name :
 
756
                             _("NONE")));
 
757
 
 
758
        // set fps
 
759
        w = glade_xml_get_widget (xml, "xvc_result_dialog_fps_label");
 
760
        g_assert (w);
 
761
        snprintf (buf, 99, "%.2f",
 
762
                  ((float) target->fps.num / (float) target->fps.den));
 
763
        gtk_label_set_text (GTK_LABEL (w), buf);
 
764
 
 
765
        // achieved fps
 
766
        w = glade_xml_get_widget (xml, "xvc_result_dialog_actual_fps_label");
 
767
        g_assert (w);
 
768
        {
 
769
            char *str_template = NULL;
 
770
            float total_frames =
 
771
                ((float) jobp->pic_no / (float) target->step) + 1;
 
772
            float actual_fps =
 
773
                ((float) total_frames) / ((float) time_captured / 1000);
 
774
 
 
775
            if (actual_fps >
 
776
                ((float) target->fps.num / (float) target->fps.den))
 
777
                actual_fps = (float) target->fps.num / (float) target->fps.den;
 
778
            fps_ratio =
 
779
                actual_fps / ((float) target->fps.num /
 
780
                              (float) target->fps.den);
 
781
 
 
782
            if (fps_ratio > (((float) LM_NUM_DAS - LM_LOW_THRESHOLD) / 10)) {
 
783
                str_template = "%.2f";
 
784
            } else if (fps_ratio >
 
785
                       (((float) LM_NUM_DAS - LM_MEDIUM_THRESHOLD) / 10)) {
 
786
                str_template = "<span background=\"#EEEE00\">%.2f</span>";
 
787
            } else {
 
788
                str_template = "<span background=\"#EE0000\">%.2f</span>";
 
789
            }
 
790
 
 
791
            snprintf (buf, 99, str_template, actual_fps);
 
792
            gtk_label_set_markup (GTK_LABEL (w), buf);
 
793
        }
 
794
 
 
795
        // fps ratio
 
796
        w = glade_xml_get_widget (xml,
 
797
                                  "xvc_result_dialog_fps_ratio_progressbar");
 
798
        g_assert (w);
 
799
        gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (w), fps_ratio);
 
800
        snprintf (buf, 99, "%.2f %%", fps_ratio * 100);
 
801
        gtk_progress_bar_set_text (GTK_PROGRESS_BAR (w), buf);
 
802
 
 
803
        // captured frames
 
804
        w = glade_xml_get_widget (xml, "xvc_result_dialog_total_frames_label");
 
805
        g_assert (w);
 
806
        snprintf (buf, 99, "%i", (jobp->pic_no / target->step) + 1);
 
807
        gtk_label_set_text (GTK_LABEL (w), buf);
 
808
 
 
809
        // captured time
 
810
        w = glade_xml_get_widget (xml, "xvc_result_dialog_video_length_label");
 
811
        g_assert (w);
 
812
        snprintf (buf, 99, "%.2f seconds", ((float) time_captured / 1000));
 
813
        gtk_label_set_text (GTK_LABEL (w), buf);
 
814
 
 
815
        if (strlen (target->file) > 0) {
 
816
            w = glade_xml_get_widget (xml,
 
817
                                      "xvc_result_dialog_select_filename_button");
 
818
            g_assert (w);
 
819
            gtk_widget_hide (GTK_WIDGET (w));
 
820
 
 
821
            w = glade_xml_get_widget (xml, "xvc_result_dialog_filename_label");
 
822
            g_assert (w);
 
823
            gtk_widget_hide (GTK_WIDGET (w));
 
824
 
 
825
            w = glade_xml_get_widget (xml, "xvc_result_dialog_no_button");
 
826
            g_assert (w);
 
827
            gtk_widget_hide (GTK_WIDGET (w));
 
828
 
 
829
            w = glade_xml_get_widget (xml, "xvc_result_dialog_save_button");
 
830
            g_assert (w);
 
831
            gtk_widget_hide (GTK_WIDGET (w));
 
832
 
 
833
            w = glade_xml_get_widget (xml,
 
834
                                      "xvc_result_dialog_show_next_time_checkbutton");
 
835
            g_assert (w);
 
836
            gtk_widget_show (GTK_WIDGET (w));
 
837
 
 
838
            w = glade_xml_get_widget (xml, "xvc_result_dialog_close_button");
 
839
            g_assert (w);
 
840
            gtk_widget_show (GTK_WIDGET (w));
 
841
        }
 
842
 
 
843
        do {
 
844
            result = gtk_dialog_run (GTK_DIALOG (xvc_result_dialog));
 
845
 
 
846
            switch (result) {
 
847
            case GTK_RESPONSE_OK:
 
848
                if (target_file_name != NULL) {
 
849
                    char cmd_buf[PATH_MAX * 2 + 5];
 
850
                    int errnum = 0;
 
851
 
 
852
                    snprintf (cmd_buf, (PATH_MAX * 2 + 5), "mv %s %s",
 
853
                              target->file, target_file_name);
 
854
                    errnum = system ((char *) cmd_buf);
 
855
                    if (errnum != 0) {
 
856
                        GtkWidget *err_dialog =
 
857
                            gtk_message_dialog_new (GTK_WINDOW
 
858
                                                    (xvc_ctrl_main_window),
 
859
                                                    GTK_DIALOG_DESTROY_WITH_PARENT,
 
860
                                                    GTK_MESSAGE_ERROR,
 
861
                                                    GTK_BUTTONS_CLOSE,
 
862
                                                    "Error moving file from '%s' to '%s'\n%s",
 
863
                                                    target->file,
 
864
                                                    target_file_name,
 
865
                                                    g_strerror (errnum));
 
866
 
 
867
                        gtk_dialog_run (GTK_DIALOG (err_dialog));
 
868
                        gtk_widget_destroy (err_dialog);
 
869
                    }
 
870
                }
 
871
            case GTK_RESPONSE_CANCEL:
 
872
            case GTK_RESPONSE_CLOSE:
 
873
                w = glade_xml_get_widget (xml,
 
874
                                          "xvc_result_dialog_show_next_time_checkbutton");
 
875
                g_assert (w);
 
876
                if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)))
 
877
                    app->flags &= ~FLG_ALWAYS_SHOW_RESULTS;
 
878
                break;
 
879
            case GTK_RESPONSE_HELP:
 
880
                do_results_help ();
 
881
                break;
 
882
            case GTK_RESPONSE_ACCEPT:
 
883
                if (!app->current_mode) {
 
884
                    xvc_command_execute (target->play_cmd, 1, 0,
 
885
                                         target->file, target->start_no,
 
886
                                         jobp->pic_no, app->area->width,
 
887
                                         app->area->height, target->fps);
 
888
                } else {
 
889
                    xvc_command_execute (target->play_cmd, 2,
 
890
                                         jobp->movie_no, target->file,
 
891
                                         target->start_no, jobp->pic_no,
 
892
                                         app->area->width,
 
893
                                         app->area->height, target->fps);
 
894
                }
 
895
                break;
 
896
            default:
 
897
                break;
 
898
            }
 
899
        } while (result == GTK_RESPONSE_HELP || result == GTK_RESPONSE_ACCEPT);
 
900
 
 
901
        gtk_widget_destroy (xvc_result_dialog);
 
902
        xvc_result_dialog = NULL;
 
903
 
 
904
        // FIXME: realize move in a way that gives me real error codes
 
905
    }
 
906
#ifdef DEBUG
 
907
    printf ("%s %s: Leaving\n", DEBUGFILE, DEBUGFUNCTION);
 
908
#endif     // DEBUG
 
909
 
 
910
#undef DEBUGFUNCTION
 
911
}
 
912
 
 
913
/**
 
914
 * \brief this function is hooked up as the action to execute when a
 
915
 *      capture session with max_time set times out.
 
916
 *
 
917
 * \todo might be able to trigger xvc_capture_stop_signal directly
 
918
 */
 
919
gboolean
 
920
timer_stop_recording ()
 
921
{
 
922
#define DEBUGFUNCTION "timer_stop_recording()"
 
923
    xvc_capture_stop_signal (FALSE);
 
924
    return FALSE;
 
925
#undef DEBUGFUNCTION
 
926
}
 
927
 
 
928
static gboolean
 
929
on_tray_icon_button_press_event (GtkWidget * widget,
 
930
                                 GdkEvent * event, gpointer user_data)
 
931
{
 
932
    GdkEventButton *bevent = NULL;
 
933
 
 
934
    g_assert (widget);
 
935
    g_assert (event);
 
936
    bevent = (GdkEventButton *) event;
 
937
 
 
938
    if (bevent->button == (guint) 3) {
 
939
        g_assert (tray_icon_menu);
 
940
 
 
941
        gtk_menu_popup (GTK_MENU (tray_icon_menu), NULL, NULL,
 
942
                        NULL, widget, bevent->button, bevent->time);
 
943
        // Tell calling code that we have handled this event; the buck
 
944
        // stops here.
 
945
        return TRUE;
 
946
    }
 
947
    return FALSE;
 
948
}
 
949
 
 
950
/**
 
951
 * \brief implements the GUI related actions involved in starting a
 
952
 *      capture session
 
953
 */
 
954
static void
 
955
start_recording_gui_stuff ()
 
956
{
 
957
#define DEBUGFUNCTION "start_recording_gui_stuff()"
 
958
    GladeXML *xml = NULL;
 
959
    GtkWidget *w = NULL;
 
960
    Job *jobp = xvc_job_ptr ();
 
961
    XVC_CapTypeOptions *target = NULL;
 
962
    XVC_AppData *app = xvc_appdata_ptr ();
 
963
 
 
964
#ifdef USE_FFMPEG
 
965
    if (app->current_mode > 0)
 
966
        target = &(app->multi_frame);
 
967
    else
 
968
#endif     // USE_FFMPEG
 
969
        target = &(app->single_frame);
 
970
 
 
971
    if (app->flags & FLG_TO_TRAY) {
 
972
        GtkWidget *ebox = NULL, *hbox = NULL, *pause_cb;
 
973
 
 
974
//        GtkWidget *image = NULL;
 
975
//        GdkBitmap *bm = NULL;
 
976
 
 
977
        gtk_window_set_skip_taskbar_hint (GTK_WINDOW (xvc_ctrl_main_window),
 
978
                                          TRUE);
 
979
 
 
980
        tray_icon = GTK_WIDGET (egg_tray_icon_new ("xvc_tray_icon"));
 
981
        g_assert (tray_icon);
 
982
        ebox = gtk_event_box_new ();
 
983
        g_assert (ebox);
 
984
        hbox = gtk_hbox_new (FALSE, 2);
 
985
        g_assert (hbox);
 
986
        tray_frame_mon = NULL;
 
987
        tray_frame_mon = glade_create_led_meter ("tray_frame_mon", NULL,
 
988
                                                 NULL, 0, 0);
 
989
        g_assert (tray_frame_mon);
 
990
        gtk_container_add (GTK_CONTAINER (hbox), tray_frame_mon);
 
991
 
 
992
//        image = gtk_image_new_from_stock (GTK_STOCK_MEDIA_RECORD,
 
993
//                                          GTK_ICON_SIZE_SMALL_TOOLBAR);
 
994
//        g_assert (image);
 
995
//        gtk_container_add (GTK_CONTAINER (hbox), image);
 
996
        gtk_container_add (GTK_CONTAINER (ebox), hbox);
 
997
        gtk_container_add (GTK_CONTAINER (tray_icon), ebox);
 
998
        gtk_widget_show_all (tray_icon);
 
999
 
 
1000
        g_signal_connect (G_OBJECT (ebox), "button_press_event",
 
1001
                          G_CALLBACK (on_tray_icon_button_press_event), NULL);
 
1002
 
 
1003
        // load the interface
 
1004
        xml = glade_xml_new (XVC_GLADE_FILE, "xvc_ti_menu", NULL);
 
1005
        g_assert (xml);
 
1006
 
 
1007
        // connect the signals in the interface
 
1008
        glade_xml_signal_autoconnect (xml);
 
1009
        // store the toplevel widget for further reference
 
1010
        tray_icon_menu = glade_xml_get_widget (xml, "xvc_ti_menu");
 
1011
        if (jobp->state & VC_PAUSE) {
 
1012
            pause_cb = glade_xml_get_widget (xml, "xvc_ti_pause");
 
1013
            gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (pause_cb),
 
1014
                                            TRUE);
 
1015
        }
 
1016
 
 
1017
        gtk_window_iconify (GTK_WINDOW (xvc_ctrl_main_window));
 
1018
    }
 
1019
    xml = glade_get_widget_tree (GTK_WIDGET (xvc_ctrl_main_window));
 
1020
    g_assert (xml);
 
1021
 
 
1022
    // GUI stuff
 
1023
    w = glade_xml_get_widget (xml, "xvc_ctrl_record_toggle");
 
1024
    g_assert (w);
 
1025
    gtk_widget_set_sensitive (GTK_WIDGET (w), FALSE);
 
1026
 
 
1027
    w = glade_xml_get_widget (xml, "xvc_ctrl_stop_toggle");
 
1028
    g_assert (w);
 
1029
    if ((jobp->state & VC_PAUSE) == 0) {
 
1030
        gtk_widget_set_sensitive (GTK_WIDGET (w), TRUE);
 
1031
    }
 
1032
    gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (w), FALSE);
 
1033
 
 
1034
    w = glade_xml_get_widget (xml, "xvc_ctrl_select_toggle");
 
1035
    g_assert (w);
 
1036
    gtk_widget_set_sensitive (GTK_WIDGET (w), FALSE);
 
1037
 
 
1038
    w = glade_xml_get_widget (xml, "xvc_ctrl_pause_toggle");
 
1039
    g_assert (w);
 
1040
    gtk_widget_set_sensitive (GTK_WIDGET (w), TRUE);
 
1041
 
 
1042
    w = glade_xml_get_widget (xml, "xvc_ctrl_filename_button");
 
1043
    g_assert (w);
 
1044
    gtk_widget_set_sensitive (GTK_WIDGET (w), FALSE);
 
1045
 
 
1046
    w = glade_xml_get_widget (xml, "xvc_ctrl_edit_button");
 
1047
    g_assert (w);
 
1048
    gtk_widget_set_sensitive (GTK_WIDGET (w), FALSE);
 
1049
 
 
1050
    if (jobp->state & VC_PAUSE) {
 
1051
        w = glade_xml_get_widget (xml, "xvc_ctrl_step_button");
 
1052
        g_assert (w);
 
1053
        if (app->current_mode == 0) {
 
1054
            gtk_widget_set_sensitive (GTK_WIDGET (w), TRUE);
 
1055
 
 
1056
            if (target->frames == 0
 
1057
                || jobp->pic_no <= (target->frames - target->step)) {
 
1058
                w = glade_xml_get_widget (xml, "xvc_ctrl_forward_button");
 
1059
                g_assert (w);
 
1060
                gtk_widget_set_sensitive (GTK_WIDGET (w), TRUE);
 
1061
            }
 
1062
            if (jobp->pic_no >= target->step) {
 
1063
                w = glade_xml_get_widget (xml, "xvc_ctrl_back_button");
 
1064
                g_assert (w);
 
1065
                gtk_widget_set_sensitive (GTK_WIDGET (w), TRUE);
 
1066
            }
 
1067
        } else {
 
1068
            gtk_widget_set_sensitive (GTK_WIDGET (w), FALSE);
 
1069
            if (!xvc_is_filename_mutable (target->file)) {
 
1070
                w = glade_xml_get_widget (xml, "xvc_ctrl_forward_button");
 
1071
                g_assert (w);
 
1072
                gtk_widget_set_sensitive (GTK_WIDGET (w), FALSE);
 
1073
 
 
1074
                w = glade_xml_get_widget (xml, "xvc_ctrl_back_button");
 
1075
                g_assert (w);
 
1076
                gtk_widget_set_sensitive (GTK_WIDGET (w), FALSE);
 
1077
            }
 
1078
        }
 
1079
    } else {
 
1080
        w = glade_xml_get_widget (xml, "xvc_ctrl_forward_button");
 
1081
        g_assert (w);
 
1082
        gtk_widget_set_sensitive (GTK_WIDGET (w), FALSE);
 
1083
 
 
1084
        w = glade_xml_get_widget (xml, "xvc_ctrl_back_button");
 
1085
        g_assert (w);
 
1086
        gtk_widget_set_sensitive (GTK_WIDGET (w), FALSE);
 
1087
    }
 
1088
#undef DEBUGFUNCTION
 
1089
}
 
1090
 
 
1091
/**
 
1092
 * \brief implements those actions involved in starting a capture session
 
1093
 *      that are not GUI related
 
1094
 */
 
1095
static void
 
1096
start_recording_nongui_stuff ()
 
1097
{
 
1098
#define DEBUGFUNCTION "start_recording_nongui_stuff()"
 
1099
    if (!recording_thread_running) {
 
1100
        struct timeval curr_time;
 
1101
        Job *job = xvc_job_ptr ();
 
1102
        XVC_CapTypeOptions *target = NULL;
 
1103
        XVC_AppData *app = xvc_appdata_ptr ();
 
1104
 
 
1105
#ifdef USE_FFMPEG
 
1106
        if (app->current_mode > 0)
 
1107
            target = &(app->multi_frame);
 
1108
        else
 
1109
#endif     // USE_FFMPEG
 
1110
            target = &(app->single_frame);
 
1111
 
 
1112
        // the following also unsets VC_READY
 
1113
        xvc_job_keep_and_merge_state (VC_PAUSE, (VC_REC | VC_START));
 
1114
 
 
1115
        if (app->current_mode > 0) {
 
1116
            job->pic_no = target->start_no;
 
1117
        }
 
1118
 
 
1119
        if ((job->state & VC_PAUSE) == 0) {
 
1120
            // if (job->max_time != 0 && (job->state & VC_PAUSE) == 0) {
 
1121
            gettimeofday (&curr_time, NULL);
 
1122
            time_captured = 0;
 
1123
            start_time = curr_time.tv_sec * 1000 + curr_time.tv_usec / 1000;
 
1124
            if (target->time != 0) {
 
1125
                // install a timer which stops recording
 
1126
                // we need milli secs ..
 
1127
                stop_timer_id =
 
1128
                    g_timeout_add ((guint32) (target->time * 1000),
 
1129
                                   (GtkFunction) timer_stop_recording, job);
 
1130
            }
 
1131
        }
 
1132
#ifdef USE_XDAMAGE
 
1133
        if (job->flags & FLG_USE_XDAMAGE) {
 
1134
            GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (app->dpy);
 
1135
            Window *children, root_return, parent_return, root;
 
1136
            XWindowAttributes root_attrs;
 
1137
            unsigned int nchildren, i;
 
1138
 
 
1139
            root = DefaultRootWindow (app->dpy);
 
1140
            XGetWindowAttributes (app->dpy, root, &root_attrs);
 
1141
            XSelectInput (app->dpy, root, StructureNotifyMask);
 
1142
            XDamageCreate (app->dpy, DefaultRootWindow (app->dpy),
 
1143
                           XDamageReportRawRectangles);
 
1144
            XQueryTree (app->dpy,
 
1145
                        DefaultRootWindow (app->dpy),
 
1146
                        &root_return, &parent_return, &children, &nchildren);
 
1147
 
 
1148
            for (i = 0; i < nchildren; i++) {
 
1149
                XWindowAttributes attribs;
 
1150
                Status ret;
 
1151
 
 
1152
                gdk_error_trap_push ();
 
1153
                ret = XGetWindowAttributes (app->dpy, children[i], &attribs);
 
1154
                gdk_error_trap_pop ();
 
1155
 
 
1156
                if (ret) {
 
1157
                    //XSelectInput (app->dpy, children[i], StructureNotifyMask);
 
1158
//                  if (!attribs.override_redirect /* && attribs.depth==root_attr.depth */ ) {
 
1159
                    XDamageCreate (app->dpy, children[i],
 
1160
                                   XDamageReportRawRectangles);
 
1161
//                  }
 
1162
                }
 
1163
            }
 
1164
            XSync (app->dpy, False);
 
1165
            XFree (children);
 
1166
 
 
1167
            gdk_window_add_filter (NULL,
 
1168
                                   (GdkFilterFunc) xvc_xdamage_event_filter,
 
1169
                                   NULL);
 
1170
 
 
1171
            g_assert (gdpy);
 
1172
            gdk_x11_register_standard_event_type (gdpy,
 
1173
                                                  app->dmg_event_base,
 
1174
                                                  XDamageNumberEvents);
 
1175
        }
 
1176
#endif     // USE_XDAMAGE
 
1177
        // initialize recording thread
 
1178
        pthread_mutex_init (&recording_mutex, NULL);
 
1179
        pthread_cond_init (&recording_condition_unpaused, NULL);
 
1180
 
 
1181
        pthread_attr_init (&recording_thread_attr);
 
1182
        pthread_attr_setdetachstate (&recording_thread_attr,
 
1183
                                     PTHREAD_CREATE_JOINABLE);
 
1184
        pthread_create (&recording_thread, &recording_thread_attr,
 
1185
                        (void *) do_record_thread, (void *) job);
 
1186
 
 
1187
    }
 
1188
#undef DEBUGFUNCTION
 
1189
}
 
1190
 
 
1191
/**
 
1192
 * \brief this positions the main control's menu (which is actually a
 
1193
 *      popup menu a.k.a. context menu) in the same way it would if it
 
1194
 *      were a normal menu
 
1195
 *
 
1196
 * @param menu pointer to the menu widget
 
1197
 * @param x pointer to an int where the calculated x-position will be returned
 
1198
 * @param y pointer to an int where the calculated y-position will be returned
 
1199
 * @param push_in not actively used
 
1200
 * @param user_data not actively used
 
1201
 */
 
1202
void
 
1203
position_popup_menu (GtkMenu * menu, gint * x, gint * y,
 
1204
                     gboolean * push_in, gpointer user_data)
 
1205
{
 
1206
#define DEBUGFUNCTION "position_popup_menu()"
 
1207
    int pheight = 0, px = 0, py = 0, tx = 0, ty = 0;
 
1208
    GtkWidget *w = NULL;
 
1209
 
 
1210
    w = GTK_WIDGET (user_data);
 
1211
 
 
1212
    g_return_if_fail (w != NULL);
 
1213
 
 
1214
    pheight = w->allocation.height;
 
1215
    px = w->allocation.x;
 
1216
    py = w->allocation.y;
 
1217
    tx += px;
 
1218
    ty += py;
 
1219
 
 
1220
    w = gtk_widget_get_toplevel (GTK_WIDGET (w));
 
1221
 
 
1222
    g_return_if_fail (w != NULL);
 
1223
 
 
1224
    gdk_window_get_origin (GDK_WINDOW (w->window), &px, &py);
 
1225
    tx += px;
 
1226
    ty += py;
 
1227
 
 
1228
    *x = tx;
 
1229
    *y = ty + pheight;
 
1230
#undef DEBUGFUNCTION
 
1231
}
 
1232
 
 
1233
/**
 
1234
 * \brief resets the main control window according to the preferences
 
1235
 *      currently set
 
1236
 */
 
1237
void
 
1238
xvc_reset_ctrl_main_window_according_to_current_prefs ()
 
1239
{
 
1240
#define DEBUGFUNCTION "xvc_reset_ctrl_main_window_according_to_current_prefs()"
 
1241
    GladeXML *mwxml = NULL, *menuxml = NULL;
 
1242
    GtkWidget *w = NULL;
 
1243
    GtkTooltips *tooltips;
 
1244
    Job *jobp = xvc_job_ptr ();
 
1245
    XVC_CapTypeOptions *target = NULL;
 
1246
    XVC_AppData *app = xvc_appdata_ptr ();
 
1247
 
 
1248
#ifdef DEBUG
 
1249
    printf ("%s %s: Entering\n", DEBUGFILE, DEBUGFUNCTION);
 
1250
#endif     // DEBUG
 
1251
 
 
1252
#ifdef USE_FFMPEG
 
1253
    if (app->current_mode > 0)
 
1254
        target = &(app->multi_frame);
 
1255
    else
 
1256
#endif     // USE_FFMPEG
 
1257
        target = &(app->single_frame);
 
1258
 
 
1259
    mwxml = glade_get_widget_tree (xvc_ctrl_main_window);
 
1260
    g_assert (mwxml);
 
1261
    menuxml = glade_get_widget_tree (xvc_ctrl_m1);
 
1262
    g_assert (menuxml);
 
1263
 
 
1264
    // various GUI initialization things
 
1265
 
 
1266
    //
 
1267
    // first: the autocontinue menu item
 
1268
    //
 
1269
    // make autocontinue menuitem invisible if no ffmpeg
 
1270
#ifndef USE_FFMPEG
 
1271
    w = NULL;
 
1272
    w = glade_xml_get_widget (menuxml, "xvc_ctrl_m1_mitem_autocontinue");
 
1273
    g_return_if_fail (w != NULL);
 
1274
    gtk_widget_hide (GTK_WIDGET (w));
 
1275
 
 
1276
    w = NULL;
 
1277
    w = glade_xml_get_widget (menuxml, "xvc_ctrl_m1_separator1");
 
1278
    g_return_if_fail (w != NULL);
 
1279
    gtk_widget_hide (GTK_WIDGET (w));
 
1280
 
 
1281
#else      // USE_FFMPEG
 
1282
    // the rest in case we have ffmpeg
 
1283
    if (app->current_mode > 0) {
 
1284
        w = glade_xml_get_widget (menuxml, "xvc_ctrl_m1_mitem_autocontinue");
 
1285
        g_assert (w);
 
1286
 
 
1287
        if ((app->flags & FLG_AUTO_CONTINUE) != 0) {
 
1288
            gtk_widget_set_sensitive (GTK_WIDGET (w), TRUE);
 
1289
            gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), TRUE);
 
1290
        } else {
 
1291
            if (xvc_is_filename_mutable (jobp->file)) {
 
1292
                gtk_widget_set_sensitive (GTK_WIDGET (w), TRUE);
 
1293
                gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), FALSE);
 
1294
            } else {
 
1295
                gtk_widget_set_sensitive (GTK_WIDGET (w), FALSE);
 
1296
                gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), FALSE);
 
1297
            }
 
1298
        }
 
1299
    } else {
 
1300
        w = glade_xml_get_widget (menuxml, "xvc_ctrl_m1_mitem_autocontinue");
 
1301
        g_assert (w);
 
1302
 
 
1303
        gtk_widget_set_sensitive (GTK_WIDGET (w), FALSE);
 
1304
        gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), FALSE);
 
1305
    }
 
1306
#endif     // USE_FFMPEG
 
1307
 
 
1308
    //
 
1309
    // the filename button
 
1310
    //
 
1311
    GtkChangeLabel (jobp->pic_no);
 
1312
 
 
1313
    // previous and next buttons have different meanings for on-the-fly
 
1314
    // encoding and individual frame capture ...
 
1315
    // this sets the tooltips accordingly
 
1316
    if (app->current_mode == 0) {
 
1317
        tooltips = gtk_tooltips_new ();
 
1318
        g_assert (tooltips);
 
1319
 
 
1320
        w = NULL;
 
1321
        w = glade_xml_get_widget (mwxml, "xvc_ctrl_back_button");
 
1322
        g_assert (w);
 
1323
        gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (w), tooltips,
 
1324
                                   _("Move cursor back one frame"),
 
1325
                                   _("Move cursor back one frame"));
 
1326
        if (jobp->pic_no >= target->step)
 
1327
            gtk_widget_set_sensitive (GTK_WIDGET (w), TRUE);
 
1328
        else
 
1329
            gtk_widget_set_sensitive (GTK_WIDGET (w), FALSE);
 
1330
 
 
1331
        w = glade_xml_get_widget (mwxml, "xvc_ctrl_forward_button");
 
1332
        g_assert (w);
 
1333
        gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (w), tooltips,
 
1334
                                   _("Move cursor to next frame"),
 
1335
                                   _("Move cursor to next frame"));
 
1336
        gtk_widget_set_sensitive (GTK_WIDGET (w), TRUE);
 
1337
 
 
1338
        w = glade_xml_get_widget (mwxml, "xvc_ctrl_filename_button");
 
1339
        g_assert (w);
 
1340
        gtk_tooltips_set_tip (GTK_TOOLTIPS (tooltips), GTK_WIDGET (w),
 
1341
                              _
 
1342
                              ("Left Click: Reset frame counter and filename\nRight Click: Popup Menu"),
 
1343
                              _
 
1344
                              ("Left Click: Reset frame counter and filename\nRight Click: Popup Menu"));
 
1345
 
 
1346
        w = glade_xml_get_widget (mwxml, "xvc_ctrl_edit_button");
 
1347
        g_assert (w);
 
1348
        gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (w), tooltips,
 
1349
                                   _("Edit current individual frame"),
 
1350
                                   _("Edit current individual frame"));
 
1351
 
 
1352
        w = glade_xml_get_widget (mwxml, "xvc_ctrl_step_button");
 
1353
        g_assert (w);
 
1354
        gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (w), tooltips,
 
1355
                                   _("Capture single frame"),
 
1356
                                   _("Capture single frame"));
 
1357
    } else {
 
1358
        GtkWidget *next = NULL, *previous = NULL, *filename = NULL, *w = NULL;
 
1359
 
 
1360
        next = glade_xml_get_widget (mwxml, "xvc_ctrl_forward_button");
 
1361
        g_assert (next);
 
1362
        previous = glade_xml_get_widget (mwxml, "xvc_ctrl_back_button");
 
1363
        g_assert (previous);
 
1364
        filename = glade_xml_get_widget (mwxml, "xvc_ctrl_filename_button");
 
1365
        g_assert (filename);
 
1366
        tooltips = gtk_tooltips_new ();
 
1367
        g_assert (tooltips);
 
1368
 
 
1369
        if (xvc_is_filename_mutable (jobp->file)) {
 
1370
            gtk_widget_set_sensitive (GTK_WIDGET (next), TRUE);
 
1371
            if (jobp->movie_no > 0)
 
1372
                gtk_widget_set_sensitive (GTK_WIDGET (previous), TRUE);
 
1373
            else
 
1374
                gtk_widget_set_sensitive (GTK_WIDGET (previous), FALSE);
 
1375
        } else {
 
1376
            gtk_widget_set_sensitive (GTK_WIDGET (next), FALSE);
 
1377
            gtk_widget_set_sensitive (GTK_WIDGET (previous), FALSE);
 
1378
        }
 
1379
        gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (previous), tooltips,
 
1380
                                   _("Move cursor to previous movie"),
 
1381
                                   _("Move cursor to previous movie"));
 
1382
        gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (next), tooltips,
 
1383
                                   _("Move cursor to next movie"),
 
1384
                                   _("Move cursor to next movie"));
 
1385
        gtk_tooltips_set_tip (GTK_TOOLTIPS (tooltips),
 
1386
                              GTK_WIDGET (filename),
 
1387
                              _
 
1388
                              ("Left Click: Reset movie counter to zero\nRight Click: Popup Menu"),
 
1389
                              _
 
1390
                              ("Left Click: Reset movie counter to zero\nRight Click: Popup Menu"));
 
1391
 
 
1392
        w = glade_xml_get_widget (mwxml, "xvc_ctrl_edit_button");
 
1393
        g_assert (w);
 
1394
        gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (w), tooltips,
 
1395
                                   _("Edit current movie"),
 
1396
                                   _("Edit current movie"));
 
1397
 
 
1398
        w = glade_xml_get_widget (mwxml, "xvc_ctrl_step_button");
 
1399
        g_assert (w);
 
1400
        gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (w), tooltips, NULL, NULL);
 
1401
    }
 
1402
 
 
1403
    //
 
1404
    // capture type radio buttons
 
1405
    //
 
1406
    // make capture type radio buttons invisible if no ffmpeg
 
1407
#ifndef USE_FFMPEG
 
1408
    w = NULL;
 
1409
    w = glade_xml_get_widget (menuxml, "xvc_ctrl_m1_mitem_sf_capture");
 
1410
    g_return_if_fail (w != NULL);
 
1411
    gtk_widget_hide (GTK_WIDGET (w));
 
1412
 
 
1413
    w = NULL;
 
1414
    w = glade_xml_get_widget (menuxml, "xvc_ctrl_m1_mitem_mf_capture");
 
1415
    g_return_if_fail (w != NULL);
 
1416
    gtk_widget_hide (GTK_WIDGET (w));
 
1417
#else      // USE_FFMPEG
 
1418
    if (app->current_mode == 0) {
 
1419
        w = NULL;
 
1420
        w = glade_xml_get_widget (menuxml, "xvc_ctrl_m1_mitem_sf_capture");
 
1421
        g_return_if_fail (w != NULL);
 
1422
        gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), TRUE);
 
1423
 
 
1424
    } else {
 
1425
        w = NULL;
 
1426
        w = glade_xml_get_widget (menuxml, "xvc_ctrl_m1_mitem_mf_capture");
 
1427
        g_return_if_fail (w != NULL);
 
1428
        gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), TRUE);
 
1429
    }
 
1430
#endif     // USE_FFMPEG
 
1431
 
 
1432
#undef DEBUGFUNCTION
 
1433
}
 
1434
 
 
1435
/**
 
1436
 * XVIDCAP GUI API<br>
 
1437
 * ( IF THAT WORD IS ALLOWED HERE ;) )<br>
 
1438
 * <br><table>
 
1439
 * <tr><td>xvc_init_pre</td><td>do gui preintialization like setting fallback options, initializing thread libraries and the like</td></tr>
 
1440
 * <tr><td>xvc_ui_create</td><td>create the gui</td></tr>
 
1441
 * <tr><td>xvc_frame_create</td><td>create the frame for selecting the area to capture</td></tr>
 
1442
 * <tr><td>xvc_check_start_options</td><td>check the preferences on program start</td></tr>
 
1443
 * <tr><td>xvc_ui_init</td><td>gui initialization</td></tr>
 
1444
 * <tr><td>xvc_ui_run</td><td>start the ui's main loop</td></tr>
 
1445
 * <tr><td>xvc_idle_add</td><td>queue an idle action</td></tr>
 
1446
 * <tr><td>xvc_change_filename_display</td><td>update the display of the current frame/file</td></tr>
 
1447
 * <tr><td>xvc_capture_stop_signal</td><td>tell the ui you want it to stop recording</td></tr>
 
1448
 * <tr><td>xvc_capture_stop</td><td>implements the functions for actually stopping</td></tr>
 
1449
 * <tr><td>xvc_capture_start</td><td>implements the functions for starting a recording</td></tr>
 
1450
 * <tr><td>xvc_frame_change</td><td>change the area to capture</td></tr>
 
1451
 * <tr><td>xvc_frame_monitor</td><td>update a widget monitoring frame rate</td></tr>
 
1452
 * </table>
 
1453
 */
 
1454
 
 
1455
/**
 
1456
 * \brief does gui preintialization, mainly initializing thread libraries
 
1457
 *      and calling gtk_init with the command line arguments
 
1458
 *
 
1459
 * @param argc number of command line arguments
 
1460
 * @param argv pointer to the command line arguments
 
1461
 * @return Could be FALSE for failure, but de facto always TRUE
 
1462
 */
 
1463
Boolean
 
1464
xvc_init_pre (int argc, char **argv)
 
1465
{
 
1466
#define DEBUGFUNCTION "xvc_init_pre()"
 
1467
    g_thread_init (NULL);
 
1468
    gdk_threads_init ();
 
1469
 
 
1470
    gtk_init (&argc, &argv);
 
1471
    return TRUE;
 
1472
#undef DEBUGFUNCTION
 
1473
}
 
1474
 
 
1475
/**
 
1476
 * \brief creates the main control and menu from the glade definition,
 
1477
 *      connects the signals and stores the widget pointers for further
 
1478
 *      reference.
 
1479
 *
 
1480
 * @return Could be FALSE for failure, but de facto always TRUE
 
1481
 */
 
1482
Boolean
 
1483
xvc_ui_create ()
 
1484
{
 
1485
#define DEBUGFUNCTION "xvc_ui_create()"
 
1486
    GladeXML *xml = NULL;
 
1487
    XVC_AppData *app = xvc_appdata_ptr ();
 
1488
 
 
1489
#ifdef DEBUG
 
1490
    printf ("%s %s: Entering\n", DEBUGFILE, DEBUGFUNCTION);
 
1491
#endif     // DEBUG
 
1492
 
 
1493
    // only show the ui if not in nogui
 
1494
    if ((app->flags & FLG_NOGUI) == 0) {
 
1495
        // main window
 
1496
        // load the interface
 
1497
        xml = glade_xml_new (XVC_GLADE_FILE, "xvc_ctrl_main_window", NULL);
 
1498
 
 
1499
        g_assert (xml);
 
1500
 
 
1501
        // connect the signals in the interface
 
1502
        glade_xml_signal_autoconnect (xml);
 
1503
        // store the toplevel widget for further reference
 
1504
        xvc_ctrl_main_window =
 
1505
            glade_xml_get_widget (xml, "xvc_ctrl_main_window");
 
1506
 
 
1507
#if GTK_CHECK_VERSION(2, 5, 0)
 
1508
#else
 
1509
        {
 
1510
            GtkWidget *w = NULL;
 
1511
 
 
1512
/*
 
1513
 *            replace the following stock ids
 
1514
 *
 
1515
gtk-media-stop gtk-stop
 
1516
gtk-media-pause gtk-go-up (funky, but it works)
 
1517
gtk-media-record gtk-convert
 
1518
gtk-media-next gtk-goto-last
 
1519
gtk-media-rewind gtk-go-back
 
1520
gtk-media-forward gtk-go-forward
 
1521
gtk-edit gtk-paste (2nd choice would be gtk-open)
 
1522
*
 
1523
*/
 
1524
            w = glade_xml_get_widget (xml, "xvc_ctrl_stop_toggle");
 
1525
            if (w)
 
1526
                gtk_button_set_image (GTK_BUTTON (w),
 
1527
                                      gtk_image_new_from_stock ("gtk-stop",
 
1528
                                                                GTK_ICON_SIZE_BUTTON));
 
1529
 
 
1530
            w = glade_xml_get_widget (xml, "xvc_ctrl_pause_toggle");
 
1531
            if (w)
 
1532
                gtk_button_set_image (GTK_BUTTON (w),
 
1533
                                      gtk_image_new_from_stock ("gtk-go-up",
 
1534
                                                                GTK_ICON_SIZE_BUTTON));
 
1535
 
 
1536
            w = glade_xml_get_widget (xml, "xvc_ctrl_record_toggle");
 
1537
            if (w)
 
1538
                gtk_button_set_image (GTK_BUTTON (w),
 
1539
                                      gtk_image_new_from_stock ("gtk-convert",
 
1540
                                                                GTK_ICON_SIZE_BUTTON));
 
1541
 
 
1542
            w = glade_xml_get_widget (xml, "xvc_ctrl_step_button");
 
1543
            if (w)
 
1544
                gtk_button_set_image (GTK_BUTTON (w),
 
1545
                                      gtk_image_new_from_stock ("gtk-goto-last",
 
1546
                                                                GTK_ICON_SIZE_BUTTON));
 
1547
 
 
1548
            w = glade_xml_get_widget (xml, "xvc_ctrl_back_button");
 
1549
            if (w)
 
1550
                gtk_button_set_image (GTK_BUTTON (w),
 
1551
                                      gtk_image_new_from_stock ("gtk-go-back",
 
1552
                                                                GTK_ICON_SIZE_BUTTON));
 
1553
 
 
1554
            w = glade_xml_get_widget (xml, "xvc_ctrl_forward_button");
 
1555
            if (w)
 
1556
                gtk_button_set_image (GTK_BUTTON (w),
 
1557
                                      gtk_image_new_from_stock
 
1558
                                      ("gtk-go-forward", GTK_ICON_SIZE_BUTTON));
 
1559
 
 
1560
            w = glade_xml_get_widget (xml, "xvc_ctrl_edit_button");
 
1561
            if (w)
 
1562
                gtk_button_set_image (GTK_BUTTON (w),
 
1563
                                      gtk_image_new_from_stock ("gtk-paste",
 
1564
                                                                GTK_ICON_SIZE_BUTTON));
 
1565
            w = NULL;
 
1566
        }
 
1567
#endif     // GTK_CHECK_VERSION
 
1568
 
 
1569
        xml = NULL;
 
1570
        // popup window
 
1571
        // load the interface
 
1572
        xml = glade_xml_new (XVC_GLADE_FILE, "xvc_ctrl_m1", NULL);
 
1573
 
 
1574
        g_assert (xml);
 
1575
 
 
1576
        // connect the signals in the interface
 
1577
        glade_xml_signal_autoconnect (xml);
 
1578
        xvc_ctrl_m1 = glade_xml_get_widget (xml, "xvc_ctrl_m1");
 
1579
    }
 
1580
#ifdef DEBUG
 
1581
    printf ("%s %s: Leaving\n", DEBUGFILE, DEBUGFUNCTION);
 
1582
#endif     // DEBUG
 
1583
 
 
1584
    return TRUE;
 
1585
#undef DEBUGFUNCTION
 
1586
}
 
1587
 
 
1588
/**
 
1589
 * \brief creates the frame around the area to capture by calling the
 
1590
 *      actual implementation in xvc_create_gtk_frame
 
1591
 *
 
1592
 * @see xvc_create_gtk_frame
 
1593
 * @param win a Window (ID) to allow passing a window id for selecting
 
1594
 *      the area to capture (i.e. capture that window ... but not if you
 
1595
 *      move the window afterwards)
 
1596
 * @return Could be FALSE for failure, but de facto always TRUE
 
1597
 */
 
1598
Boolean
 
1599
xvc_frame_create (Window win)
 
1600
{
 
1601
#define DEBUGFUNCTION "xvc_frame_create()"
 
1602
    XVC_AppData *app = xvc_appdata_ptr ();
 
1603
 
 
1604
    if ((app->flags & FLG_NOGUI) == 0) {    /* there's one good reason for not
 
1605
                                             * having a main window */
 
1606
        g_assert (xvc_ctrl_main_window);
 
1607
    }
 
1608
 
 
1609
    if (win == None) {
 
1610
        Window root = DefaultRootWindow (app->dpy);
 
1611
 
 
1612
        // display and window attributes seem to be set correctly only if
 
1613
        // retrieved after the UI was mapped
 
1614
        gtk_init_add ((GtkFunction) xvc_appdata_set_window_attributes,
 
1615
                      (void *) root);
 
1616
 
 
1617
        if (app->area->width == 0)
 
1618
            app->area->width = 10;
 
1619
        if (app->area->height == 0)
 
1620
            app->area->height = 10;
 
1621
 
 
1622
        xvc_create_gtk_frame (xvc_ctrl_main_window, app->area->width,
 
1623
                              app->area->height, app->area->x, app->area->y);
 
1624
    } else {
 
1625
        Display *display = app->dpy;
 
1626
        int x, y;
 
1627
        Window temp = None;
 
1628
        Window root = DefaultRootWindow (display);
 
1629
 
 
1630
        // display and window attributes seem to be set correctly only if
 
1631
        // retrieved after the UI was mapped
 
1632
        gtk_init_add ((GtkFunction) xvc_appdata_set_window_attributes,
 
1633
                      (void *) win);
 
1634
        XTranslateCoordinates (display, win, root, 0, 0, &x, &y, &temp);
 
1635
 
 
1636
        app->area->x = x;
 
1637
        app->area->y = y;
 
1638
        app->area->width = app->win_attr.width;
 
1639
        app->area->height = app->win_attr.height;
 
1640
 
 
1641
        xvc_create_gtk_frame (xvc_ctrl_main_window, app->area->width,
 
1642
                              app->area->height, app->area->x, app->area->y);
 
1643
    }
 
1644
    return TRUE;
 
1645
#undef DEBUGFUNCTION
 
1646
}
 
1647
 
 
1648
/**
 
1649
 * \brief checks the current preferences and should be used to check
 
1650
 *      preferences right before running the UI
 
1651
 *
 
1652
 * This does not return anything but must react on errors found on its own.
 
1653
 * It is global mainly for allowing it to be called from the warning dialog
 
1654
 * in case the startup check produced an error with a default action, you
 
1655
 * clicked OK and then the validation needs to run again.
 
1656
 */
 
1657
void
 
1658
xvc_check_start_options ()
 
1659
{
 
1660
#define DEBUGFUNCTION "xvc_check_start_options()"
 
1661
    int count_non_info_messages = 0;
 
1662
    int rc = 0;
 
1663
    XVC_AppData *app = xvc_appdata_ptr ();
 
1664
 
 
1665
#ifdef DEBUG
 
1666
    printf ("%s %s: Entering with errors_after_cli = %p\n", DEBUGFILE,
 
1667
            DEBUGFUNCTION, errors_after_cli);
 
1668
#endif     // DEBUG
 
1669
 
 
1670
    if (OK_attempts > 0 && errors_after_cli != NULL) {
 
1671
        errors_after_cli = xvc_appdata_validate (app, 1, &rc);
 
1672
 
 
1673
#ifdef DEBUG
 
1674
        printf ("%s %s: new errors_after_cli = %p\n", DEBUGFILE,
 
1675
                DEBUGFUNCTION, errors_after_cli);
 
1676
#endif     // DEBUG
 
1677
 
 
1678
        if (rc == -1) {
 
1679
            fprintf (stderr,
 
1680
                     "%s %s: Unrecoverable error while validating options, please contact the xvidcap project.\n",
 
1681
                     DEBUGFILE, DEBUGFUNCTION);
 
1682
            exit (1);
 
1683
        }
 
1684
    }
 
1685
 
 
1686
    if ((app->flags & FLG_NOGUI) == 0) {    // we're running with gui
 
1687
        if (errors_after_cli != NULL) {
 
1688
            XVC_ErrorListItem *err;
 
1689
 
 
1690
            err = errors_after_cli;
 
1691
            count_non_info_messages = 0;
 
1692
 
 
1693
            for (; err != NULL; err = err->next) {
 
1694
                if (err->err->type != XVC_ERR_INFO)
 
1695
                    count_non_info_messages++;
 
1696
            }
 
1697
            if (count_non_info_messages > 0
 
1698
                || (app->flags & FLG_RUN_VERBOSE && OK_attempts == 0)) {
 
1699
                xvc_warn_main_window =
 
1700
                    xvc_create_warning_with_errors (errors_after_cli, 2);
 
1701
                OK_attempts++;
 
1702
            } else {
 
1703
                warning_submit ();
 
1704
            }
 
1705
        } else {
 
1706
            warning_submit ();
 
1707
        }
 
1708
    } else {                           // or without
 
1709
        while (errors_after_cli != NULL && OK_attempts < 6) {
 
1710
            XVC_ErrorListItem *err;
 
1711
 
 
1712
            err = errors_after_cli;
 
1713
            count_non_info_messages = rc = 0;
 
1714
 
 
1715
            for (; err != NULL; err = err->next) {
 
1716
                if (err->err->type != XVC_ERR_INFO)
 
1717
                    count_non_info_messages++;
 
1718
            }
 
1719
            if (count_non_info_messages > 0
 
1720
                || (app->flags & FLG_RUN_VERBOSE && OK_attempts == 0)) {
 
1721
                err = errors_after_cli;
 
1722
                for (; err != NULL; err = err->next) {
 
1723
                    if (err->err->type != XVC_ERR_INFO ||
 
1724
                        app->flags & FLG_RUN_VERBOSE) {
 
1725
                        xvc_error_write_msg (err->err->code,
 
1726
                                             ((app->
 
1727
                                               flags &
 
1728
                                               FLG_RUN_VERBOSE) ? 1 : 0));
 
1729
                        (*err->err->action) (err);
 
1730
                    }
 
1731
                }
 
1732
            }
 
1733
 
 
1734
            OK_attempts++;
 
1735
 
 
1736
            errors_after_cli = xvc_appdata_validate (app, 1, &rc);
 
1737
            if (rc == -1) {
 
1738
                fprintf (stderr,
 
1739
                         "%s %s: Unrecoverable error while validating options, please contact the xvidcap project.\n",
 
1740
                         DEBUGFILE, DEBUGFUNCTION);
 
1741
                exit (1);
 
1742
            }
 
1743
        }
 
1744
 
 
1745
        if (errors_after_cli != NULL && count_non_info_messages > 0) {
 
1746
            fprintf (stderr,
 
1747
                     "%s %s: You have specified some conflicting settings which could not be resolved automatically.\n",
 
1748
                     DEBUGFILE, DEBUGFUNCTION);
 
1749
            exit (1);
 
1750
        }
 
1751
        warning_submit ();
 
1752
    }
 
1753
 
 
1754
#ifdef DEBUG
 
1755
    printf ("%s %s: Leaving\n", DEBUGFILE, DEBUGFUNCTION);
 
1756
#endif     // DEBUG
 
1757
 
 
1758
#undef DEBUGFUNCTION
 
1759
}
 
1760
 
 
1761
/**
 
1762
 * \brief initializes the UI by mainly ensuring xvc_check_start_options is
 
1763
 *      called with the errors found in main
 
1764
 *
 
1765
 * @see xvc_check_start_options
 
1766
 * @param errors the errors in the preferences found in the main function
 
1767
 * @return Could be FALSE for failure, but de facto always TRUE
 
1768
 */
 
1769
Boolean
 
1770
xvc_ui_init (XVC_ErrorListItem * errors)
 
1771
{
 
1772
#define DEBUGFUNCTION "xvc_ui_init()"
 
1773
    XVC_AppData *app = xvc_appdata_ptr ();
 
1774
 
 
1775
#ifdef DEBUG
 
1776
    printf ("%s %s: Entering\n", DEBUGFILE, DEBUGFUNCTION);
 
1777
#endif     // DEBUG
 
1778
 
 
1779
    // display warning dialog if required
 
1780
    errors_after_cli = errors;
 
1781
    // the gui warning dialog needs a realized window, therefore we
 
1782
    // schedule it do be displayed (potentially) when the main loop starts
 
1783
    // this does not seem to work with nogui
 
1784
    if (!(app->flags & FLG_NOGUI)) {
 
1785
        gtk_init_add ((GtkFunction) xvc_check_start_options, NULL);
 
1786
    } else {
 
1787
        xvc_check_start_options ();
 
1788
        gtk_init_add ((GtkFunction) xvc_capture_start, NULL);
 
1789
    }
 
1790
 
 
1791
#ifdef DEBUG
 
1792
    printf ("%s %s: Leaving\n", DEBUGFILE, DEBUGFUNCTION);
 
1793
#endif     // DEBUG
 
1794
 
 
1795
    return TRUE;
 
1796
#undef DEBUGFUNCTION
 
1797
}
 
1798
 
 
1799
/**
 
1800
 * \brief runs the UI by executing the main loop
 
1801
 *
 
1802
 * @return Could be any integer for failure, but de facto always 0
 
1803
 */
 
1804
int
 
1805
xvc_ui_run ()
 
1806
{
 
1807
#define DEBUGFUNCTION "xvc_ui_run()";
 
1808
 
 
1809
    gtk_main ();
 
1810
 
 
1811
    return 0;
 
1812
#undef DEBUGFUNCTION
 
1813
}
 
1814
 
 
1815
/**
 
1816
 * \brief adds an action to the event queue to be executed when there's time
 
1817
 *
 
1818
 * The functions added here are executed whenever there's time until they
 
1819
 * return FALSE.
 
1820
 *
 
1821
 * @param func a pointer to a function to queue
 
1822
 * @param data a pointer to an argument to that function
 
1823
 */
 
1824
void
 
1825
xvc_idle_add (void *func, void *data)
 
1826
{
 
1827
    g_idle_add (func, data);
 
1828
}
 
1829
 
 
1830
/**
 
1831
 * \brief updates the display of the current frame/filename according to
 
1832
 *      the current state of job.
 
1833
 *
 
1834
 * This is meant to be used through xvc_idle_add during recording
 
1835
 * @return TRUE for as long as the recording thread is running or FALSE
 
1836
 *      otherwise
 
1837
 */
 
1838
Boolean
 
1839
xvc_change_filename_display ()
 
1840
{
 
1841
#define DEBUGFUNCTION "xvc_change_filename_display()"
 
1842
#ifdef DEBUG
 
1843
    printf ("%s %s: Entering\n", DEBUGFILE, DEBUGFUNCTION);
 
1844
#endif     // DEBUG
 
1845
    Job *job = xvc_job_ptr ();
 
1846
    Boolean ret = recording_thread_running;
 
1847
 
 
1848
    if (!ret) {
 
1849
        last_pic_no = 0;
 
1850
        GtkChangeLabel (job->pic_no);
 
1851
    } else if (job->pic_no != last_pic_no) {
 
1852
        last_pic_no = job->pic_no;
 
1853
        GtkChangeLabel (last_pic_no);
 
1854
    }
 
1855
#ifdef DEBUG
 
1856
    printf ("%s %s: Leaving! ...continuing? %i\n", DEBUGFILE, DEBUGFUNCTION,
 
1857
            (int) ret);
 
1858
#endif     // DEBUG
 
1859
 
 
1860
    return ret;
 
1861
#undef DEBUGFUNCTION
 
1862
}
 
1863
 
 
1864
/**
 
1865
 * \brief tell the recording thread to stop
 
1866
 *
 
1867
 * The actual stopping is done through the capture's state machine. This
 
1868
 * just sets the state to VC_STOP and sends the recording thread an ALARM
 
1869
 * signal to terminate a potential usleep. It may then wait for the thread
 
1870
 * to finish.
 
1871
 * @param wait should this function actually wait for the thread to finish?
 
1872
 */
 
1873
void
 
1874
xvc_capture_stop_signal (Boolean wait)
 
1875
{
 
1876
#define DEBUGFUNCTION "xvc_capture_stop_signal()"
 
1877
    int status = -1;
 
1878
 
 
1879
#ifdef DEBUG
 
1880
    printf ("%s %s: Entering, should we wait? %i\n",
 
1881
            DEBUGFILE, DEBUGFUNCTION, wait);
 
1882
#endif     // DEBUG
 
1883
 
 
1884
    xvc_job_set_state (VC_STOP);
 
1885
 
 
1886
    if (recording_thread_running) {
 
1887
#ifdef DEBUG
 
1888
        printf ("%s %s: stop pressed while recording\n",
 
1889
                DEBUGFILE, DEBUGFUNCTION);
 
1890
#endif     // DEBUG
 
1891
        // stop waiting for next frame to capture
 
1892
        status = pthread_kill (recording_thread, SIGALRM);
 
1893
#ifdef DEBUG
 
1894
        printf ("%s %s: thread %i kill with rc %i\n",
 
1895
                DEBUGFILE, DEBUGFUNCTION, (int) recording_thread, status);
 
1896
#endif     // DEBUG
 
1897
    }
 
1898
 
 
1899
    if (wait) {
 
1900
        while (recording_thread_running) {
 
1901
            usleep (100);
 
1902
        }
 
1903
    }
 
1904
#ifdef DEBUG
 
1905
    printf ("%s %s: Leaving\n", DEBUGFILE, DEBUGFUNCTION);
 
1906
#endif     // DEBUG
 
1907
#undef DEBUGFUNCTION
 
1908
}
 
1909
 
 
1910
/**
 
1911
 * \brief implements the actual actions required when stopping a recording
 
1912
 *      session, both GUI related an not.
 
1913
 */
 
1914
Boolean
 
1915
xvc_capture_stop ()
 
1916
{
 
1917
#define DEBUGFUNCTION "xvc_capture_stop()"
 
1918
    Job *job = xvc_job_ptr ();
 
1919
 
 
1920
#ifdef DEBUG
 
1921
    printf ("%s %s: stopping\n", DEBUGFILE, DEBUGFUNCTION);
 
1922
#endif     // DEBUG
 
1923
    stop_recording_nongui_stuff (job);
 
1924
#ifdef DEBUG
 
1925
    printf ("%s %s: done stopping non-gui stuff\n", DEBUGFILE, DEBUGFUNCTION);
 
1926
#endif     // DEBUG
 
1927
    if (!(job->flags & FLG_NOGUI)) {
 
1928
        gdk_threads_enter ();
 
1929
        stop_recording_gui_stuff (job);
 
1930
        gdk_flush ();
 
1931
        gdk_threads_leave ();
 
1932
    } else {
 
1933
        gtk_main_quit ();
 
1934
    }
 
1935
 
 
1936
    return FALSE;
 
1937
#undef DEBUGFUNCTION
 
1938
}
 
1939
 
 
1940
/**
 
1941
 * \brief starts a recording session
 
1942
 */
 
1943
void
 
1944
xvc_capture_start ()
 
1945
{
 
1946
#define DEBUGFUNCTION "xvc_capture_start()"
 
1947
    Job *job = xvc_job_ptr ();
 
1948
 
 
1949
    start_recording_nongui_stuff (job);
 
1950
    if (!(job->flags & FLG_NOGUI))
 
1951
        start_recording_gui_stuff (job);
 
1952
 
 
1953
#undef DEBUGFUNCTION
 
1954
}
 
1955
 
 
1956
/*
 
1957
 * \brief changes the frame around the area to capture by calling the
 
1958
 *      implementing function xvc_change_gtk_frame
 
1959
 *
 
1960
 * @see xvc_change_gtk_frame
 
1961
 * \todo sice nobody outside this file is calling it, it needs to be neither
 
1962
 *      global nor in the "API" functions. Prolly don't need this wrapper at
 
1963
 *      all .... remove
 
1964
 *
 
1965
void
 
1966
xvc_frame_change (int x, int y, int width, int height,
 
1967
                  Boolean reposition_control, Boolean show_dimensions)
 
1968
{
 
1969
#define DEBUGFUNCTION "xvc_frame_change()"
 
1970
    xvc_change_gtk_frame (x, y, width, height, reposition_control,
 
1971
                          show_dimensions);
 
1972
#undef DEBUGFUNCTION
 
1973
}
 
1974
 */
 
1975
 
 
1976
/**
 
1977
 * \brief updates the widget monitoring the current frame rate based on
 
1978
 *      the current value of xvc_led_time and last_led_time
 
1979
 *
 
1980
 * This is meant to be used through xvc_idle_add during recording
 
1981
 * @return TRUE for as long as the recording thread is running or FALSE
 
1982
 *      otherwise
 
1983
 * @see xvc_led_time
 
1984
 * @see last_led_time
 
1985
 * @see xvc_idle_add
 
1986
 */
 
1987
Boolean
 
1988
xvc_frame_monitor ()
 
1989
{
 
1990
#define DEBUGFUNCTION "xvc_frame_monitor()"
 
1991
 
 
1992
    Job *job = xvc_job_ptr ();
 
1993
    XVC_AppData *app = xvc_appdata_ptr ();
 
1994
    int percent = 0, diff = 0;
 
1995
    GladeXML *xml = NULL;
 
1996
    GtkWidget *w = NULL;
 
1997
    int ret = recording_thread_running;
 
1998
 
 
1999
#ifdef DEBUG
 
2000
    printf ("%s %s: Entering with time = %i\n", DEBUGFILE, DEBUGFUNCTION,
 
2001
            xvc_led_time);
 
2002
#endif     // DEBUG
 
2003
 
 
2004
    // fastpath
 
2005
    if (xvc_led_time != 0 && last_led_time == xvc_led_time)
 
2006
        return TRUE;
 
2007
 
 
2008
    if (app->flags & FLG_TO_TRAY && tray_frame_mon) {
 
2009
        w = tray_frame_mon;
 
2010
        g_return_val_if_fail (w != NULL, FALSE);
 
2011
    } else {
 
2012
        xml = glade_get_widget_tree (xvc_ctrl_main_window);
 
2013
        g_return_val_if_fail (xml != NULL, FALSE);
 
2014
        w = glade_xml_get_widget (xml, "xvc_ctrl_led_meter");
 
2015
        g_return_val_if_fail (w != NULL, FALSE);
 
2016
    }
 
2017
 
 
2018
    if (!ret) {
 
2019
        xvc_led_time = last_led_time = 0;
 
2020
    }
 
2021
 
 
2022
    if (xvc_led_time == 0) {
 
2023
        percent = 0;
 
2024
    } else if (xvc_led_time <= job->time_per_frame)
 
2025
        percent = 30;
 
2026
    else if (xvc_led_time >= (job->time_per_frame * 2))
 
2027
        percent = 100;
 
2028
    else {
 
2029
        diff = xvc_led_time - job->time_per_frame;
 
2030
        percent = diff * 70 / job->time_per_frame;
 
2031
        percent += 30;
 
2032
    }
 
2033
 
 
2034
    led_meter_set_percent (LED_METER (w), percent);
 
2035
 
 
2036
    if (percent == 0)
 
2037
        LED_METER (w)->old_max_da = 0;
 
2038
 
 
2039
#ifdef DEBUG
 
2040
    printf ("%s %s: Leaving with percent = %i ... continuing? %i\n",
 
2041
            DEBUGFILE, DEBUGFUNCTION, percent, ret);
 
2042
#endif     // DEBUG
 
2043
 
 
2044
    return ret;
 
2045
#undef DEBUGFUNCTION
 
2046
}
 
2047
 
 
2048
/*
 
2049
 * callbacks here ....
 
2050
 *
 
2051
 */
 
2052
#ifndef DOXYGEN_SHOULD_SKIP_THIS
 
2053
gboolean
 
2054
on_xvc_ctrl_main_window_delete_event (GtkWidget * widget,
 
2055
                                      GdkEvent * event, gpointer user_data)
 
2056
{
 
2057
#define DEBUGFUNCTION "on_xvc_ctrl_main_window_delete_event()"
 
2058
    Job *jobp = xvc_job_ptr ();
 
2059
 
 
2060
    if (jobp && (jobp->state & VC_STOP) == 0) {
 
2061
        xvc_capture_stop_signal (TRUE);
 
2062
    }
 
2063
 
 
2064
    xvc_destroy_gtk_frame ();
 
2065
    gtk_main_quit ();                  /** \todo why does this seem to be
 
2066
necessary with libglade where it was not previously */
 
2067
    return FALSE;
 
2068
#undef DEBUGFUNCTION
 
2069
}
 
2070
 
 
2071
gboolean
 
2072
on_xvc_ctrl_main_window_destroy_event (GtkWidget * widget,
 
2073
                                       GdkEvent * event, gpointer user_data)
 
2074
{
 
2075
#define DEBUGFUNCTION "on_xvc_ctrl_main_window_destroy_event()"
 
2076
    gtk_main_quit ();
 
2077
    return FALSE;
 
2078
#undef DEBUGFUNCTION
 
2079
}
 
2080
 
 
2081
void
 
2082
on_xvc_ctrl_m1_mitem_preferences_activate (GtkMenuItem * menuitem,
 
2083
                                           gpointer user_data)
 
2084
{
 
2085
#define DEBUGFUNCTION "on_xvc_ctrl_m1_mitem_preferences_activate()"
 
2086
    XVC_AppData *app = xvc_appdata_ptr ();
 
2087
 
 
2088
#ifdef DEBUG
 
2089
    printf ("%s %s: Entering with app %p\n", DEBUGFILE, DEBUGFUNCTION, app);
 
2090
#endif     // DEBUG
 
2091
 
 
2092
    xvc_create_pref_dialog (app);
 
2093
 
 
2094
#ifdef DEBUG
 
2095
    printf ("%s %s: Leaving\n", DEBUGFILE, DEBUGFUNCTION);
 
2096
#endif     // DEBUG
 
2097
#undef DEBUGFUNCTION
 
2098
}
 
2099
 
 
2100
void
 
2101
on_xvc_ctrl_m1_mitem_save_preferences_activate (GtkMenuItem *
 
2102
                                                menuitem, gpointer user_data)
 
2103
{
 
2104
#define DEBUGFUNCTION "on_xvc_ctrl_m1_mitem_save_preferences_activate()"
 
2105
    Job *jobp = xvc_job_ptr ();
 
2106
 
 
2107
    xvc_write_options_file (jobp);
 
2108
#undef DEBUGFUNCTION
 
2109
}
 
2110
 
 
2111
void
 
2112
on_xvc_ctrl_m1_mitem_sf_capture_activate (GtkMenuItem * menuitem,
 
2113
                                          gpointer user_data)
 
2114
{
 
2115
#ifdef USE_FFMPEG
 
2116
#define DEBUGFUNCTION "on_xvc_ctrl_m1_mitem_sf_capture_activate()"
 
2117
    XVC_AppData *app = xvc_appdata_ptr ();
 
2118
 
 
2119
    if (app->current_mode == 1
 
2120
        && gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem)) !=
 
2121
        0) {
 
2122
        app->current_mode = (app->current_mode == 0) ? 1 : 0;
 
2123
        xvc_toggle_cap_type ();
 
2124
    }
 
2125
#undef DEBUGFUNCTION
 
2126
#endif     // USE_FFMPEG
 
2127
}
 
2128
 
 
2129
void
 
2130
on_xvc_ctrl_m1_mitem_mf_capture_activate (GtkMenuItem * menuitem,
 
2131
                                          gpointer user_data)
 
2132
{
 
2133
#ifdef USE_FFMPEG
 
2134
#define DEBUGFUNCTION "on_xvc_ctrl_m1_mitem_mf_capture_activate()"
 
2135
    XVC_AppData *app = xvc_appdata_ptr ();
 
2136
 
 
2137
    if (app->current_mode == 0
 
2138
        && gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem)) !=
 
2139
        0) {
 
2140
        app->current_mode = (app->current_mode == 0) ? 1 : 0;
 
2141
        xvc_toggle_cap_type ();
 
2142
    }
 
2143
#undef DEBUGFUNCTION
 
2144
#endif     // USE_FFMPEG
 
2145
}
 
2146
 
 
2147
void
 
2148
on_xvc_ctrl_m1_mitem_autocontinue_activate (GtkMenuItem * menuitem,
 
2149
                                            gpointer user_data)
 
2150
{
 
2151
#define DEBUGFUNCTION "on_xvc_ctrl_m1_mitem_autocontinue_activate()"
 
2152
    Job *jobp = xvc_job_ptr ();
 
2153
    XVC_AppData *app = xvc_appdata_ptr ();
 
2154
 
 
2155
    if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem))) {
 
2156
        if ((!xvc_is_filename_mutable (jobp->file))
 
2157
            || app->current_mode == 0) {
 
2158
            printf
 
2159
                ("Output not a video file or no counter in filename\nDisabling autocontinue!\n");
 
2160
            gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM
 
2161
                                            (menuitem), FALSE);
 
2162
        } else {
 
2163
            jobp->flags |= FLG_AUTO_CONTINUE;
 
2164
            app->flags |= FLG_AUTO_CONTINUE;
 
2165
        }
 
2166
    } else {
 
2167
        jobp->flags &= ~FLG_AUTO_CONTINUE;
 
2168
        app->flags &= ~FLG_AUTO_CONTINUE;
 
2169
    }
 
2170
#undef DEBUGFUNCTION
 
2171
}
 
2172
 
 
2173
void
 
2174
on_xvc_ctrl_m1_mitem_make_activate (GtkMenuItem * menuitem, gpointer user_data)
 
2175
{
 
2176
#define DEBUGFUNCTION "on_xvc_ctrl_m1_mitem_make_activate()"
 
2177
    Job *jobp = xvc_job_ptr ();
 
2178
    XVC_CapTypeOptions *target = NULL;
 
2179
    XVC_AppData *app = xvc_appdata_ptr ();
 
2180
 
 
2181
#ifdef USE_FFMPEG
 
2182
    if (app->current_mode > 0)
 
2183
        target = &(app->multi_frame);
 
2184
    else
 
2185
#endif     // USE_FFMPEG
 
2186
        target = &(app->single_frame);
 
2187
 
 
2188
    if (!app->current_mode) {
 
2189
        xvc_command_execute (target->video_cmd, 0, 0,
 
2190
                             jobp->file, target->start_no, jobp->pic_no,
 
2191
                             app->area->width, app->area->height, target->fps);
 
2192
    } else {
 
2193
        xvc_command_execute (target->video_cmd, 2,
 
2194
                             jobp->movie_no, jobp->file, target->start_no,
 
2195
                             jobp->pic_no, app->area->width,
 
2196
                             app->area->height, target->fps);
 
2197
    }
 
2198
#undef DEBUGFUNCTION
 
2199
}
 
2200
 
 
2201
void
 
2202
on_xvc_ctrl_m1_mitem_help_activate (GtkMenuItem * menuitem, gpointer user_data)
 
2203
{
 
2204
#define DEBUGFUNCTION "on_xvc_ctrl_m1_mitem_help_activate()"
 
2205
    system ("yelp ghelp:xvidcap &");
 
2206
#undef DEBUGFUNCTION
 
2207
}
 
2208
 
 
2209
void
 
2210
on_xvc_ctrl_m1_mitem_quit_activate (GtkMenuItem * menuitem, gpointer user_data)
 
2211
{
 
2212
#define DEBUGFUNCTION "on_xvc_ctrl_m1_mitem_quit_activate()"
 
2213
    gboolean ignore = TRUE;
 
2214
 
 
2215
    g_signal_emit_by_name ((GtkObject *) xvc_ctrl_main_window,
 
2216
                           "destroy_event", 0, &ignore);
 
2217
#undef DEBUGFUNCTION
 
2218
}
 
2219
 
 
2220
gint
 
2221
on_xvc_result_dialog_key_press_event (GtkWidget * widget, GdkEvent * event)
 
2222
{
 
2223
#define DEBUGFUNCTION "on_xvc_result_dialog_key_press_event()"
 
2224
    GdkEventKey *kevent = NULL;
 
2225
 
 
2226
    g_assert (widget);
 
2227
    g_assert (event);
 
2228
    kevent = (GdkEventKey *) event;
 
2229
 
 
2230
#ifdef DEBUG
 
2231
    printf ("%s %s: Entering\n", DEBUGFILE, DEBUGFUNCTION);
 
2232
#endif     // DEBUG
 
2233
 
 
2234
    if (kevent->keyval == 65470) {
 
2235
        do_results_help ();
 
2236
    }
 
2237
#ifdef DEBUG
 
2238
    printf ("%s %s: Leaving\n", DEBUGFILE, DEBUGFUNCTION);
 
2239
#endif     // DEBUG
 
2240
 
 
2241
    // Tell calling code that we have not handled this event; pass it on.
 
2242
    return FALSE;
 
2243
#undef DEBUGFUNCTION
 
2244
}
 
2245
 
 
2246
void
 
2247
on_xvc_result_dialog_select_filename_button_clicked (GtkButton * button,
 
2248
                                                     gpointer user_data)
 
2249
{
 
2250
#define DEBUGFUNCTION "on_xvc_result_select_filename_button_clicked()"
 
2251
    int result = 0;
 
2252
 
 
2253
    GladeXML *xml = NULL;
 
2254
    GtkWidget *w = NULL, *dialog = NULL;
 
2255
 
 
2256
#ifdef DEBUG
 
2257
    printf ("%s %s: Entering\n", DEBUGFILE, DEBUGFUNCTION);
 
2258
#endif     // DEBUG
 
2259
 
 
2260
    // load the interface
 
2261
    xml = glade_xml_new (XVC_GLADE_FILE, "xvc_save_filechooserdialog", NULL);
 
2262
    g_assert (xml);
 
2263
    // connect the signals in the interface
 
2264
    glade_xml_signal_autoconnect (xml);
 
2265
 
 
2266
    dialog = glade_xml_get_widget (xml, "xvc_save_filechooserdialog");
 
2267
    g_assert (dialog);
 
2268
    gtk_window_set_title (GTK_WINDOW (dialog), "Save Video As:");
 
2269
 
 
2270
    result = gtk_dialog_run (GTK_DIALOG (dialog));
 
2271
 
 
2272
    if (result == GTK_RESPONSE_OK) {
 
2273
        target_file_name =
 
2274
            gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
 
2275
 
 
2276
        if (xvc_result_dialog != NULL) {
 
2277
            xml = NULL;
 
2278
            xml = glade_get_widget_tree (GTK_WIDGET (xvc_result_dialog));
 
2279
            g_assert (xml);
 
2280
 
 
2281
            w = NULL;
 
2282
            w = glade_xml_get_widget (xml, "xvc_result_dialog_filename_label");
 
2283
            g_assert (w);
 
2284
 
 
2285
            gtk_label_set_text (GTK_LABEL (w), target_file_name);
 
2286
 
 
2287
            w = NULL;
 
2288
            w = glade_xml_get_widget (xml, "xvc_result_dialog_save_button");
 
2289
            g_assert (w);
 
2290
            printf ("setting save button sensitive\n");
 
2291
            gtk_widget_set_sensitive (GTK_WIDGET (w), TRUE);
 
2292
        }
 
2293
    }
 
2294
 
 
2295
    gtk_widget_destroy (dialog);
 
2296
 
 
2297
#ifdef DEBUG
 
2298
    printf ("%s %s: Leaving with filename %s\n", DEBUGFILE, DEBUGFUNCTION,
 
2299
            target_file_name);
 
2300
#endif     // DEBUG
 
2301
#undef DEBUGFUNCTION
 
2302
}
 
2303
 
 
2304
void
 
2305
on_xvc_ctrl_stop_toggle_toggled (GtkToggleToolButton * button,
 
2306
                                 gpointer user_data)
 
2307
{
 
2308
#define DEBUGFUNCTION "on_xvc_ctrl_stop_toggle_toggled()"
 
2309
 
 
2310
#ifdef DEBUG
 
2311
    printf ("%s %s: stopp button toggled (%i)\n", DEBUGFILE, DEBUGFUNCTION,
 
2312
            gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON
 
2313
                                               (button)));
 
2314
#endif     // DEBUG
 
2315
 
 
2316
    if (gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON (button))) {
 
2317
        if (recording_thread_running)
 
2318
            xvc_capture_stop_signal (FALSE);
 
2319
        else {
 
2320
            GladeXML *xml = NULL;
 
2321
            GtkWidget *w = NULL;
 
2322
 
 
2323
            xml = glade_get_widget_tree (GTK_WIDGET (xvc_ctrl_main_window));
 
2324
            g_assert (xml);
 
2325
            w = glade_xml_get_widget (xml, "xvc_ctrl_pause_toggle");
 
2326
            g_assert (w);
 
2327
            if (gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON (w)))
 
2328
                gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON
 
2329
                                                   (w), FALSE);
 
2330
        }
 
2331
    } else {
 
2332
        // empty
 
2333
    }
 
2334
#undef DEBUGFUNCTION
 
2335
}
 
2336
 
 
2337
void
 
2338
on_xvc_ctrl_record_toggle_toggled (GtkToggleToolButton * button,
 
2339
                                   gpointer user_data)
 
2340
{
 
2341
#define DEBUGFUNCTION "on_xvc_ctrl_record_toggle_toggled()"
 
2342
 
 
2343
    if (gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON (button))) {
 
2344
        xvc_capture_start ();
 
2345
    } else {
 
2346
        // empty
 
2347
    }
 
2348
#undef DEBUGFUNCTION
 
2349
}
 
2350
 
 
2351
void
 
2352
on_xvc_ctrl_pause_toggle_toggled (GtkToggleToolButton * button,
 
2353
                                  gpointer user_data)
 
2354
{
 
2355
#define DEBUGFUNCTION "on_xvc_ctrl_pause_toggle_toggled()"
 
2356
    struct timeval curr_time;
 
2357
    GladeXML *xml = NULL;
 
2358
    GtkWidget *w = NULL;
 
2359
    Job *jobp = xvc_job_ptr ();
 
2360
    XVC_CapTypeOptions *target = NULL;
 
2361
    XVC_AppData *app = xvc_appdata_ptr ();
 
2362
 
 
2363
#ifdef USE_FFMPEG
 
2364
    if (app->current_mode > 0)
 
2365
        target = &(app->multi_frame);
 
2366
    else
 
2367
#endif     // USE_FFMPEG
 
2368
        target = &(app->single_frame);
 
2369
 
 
2370
    xml = glade_get_widget_tree (GTK_WIDGET (xvc_ctrl_main_window));
 
2371
    g_assert (xml);
 
2372
 
 
2373
#ifdef DEBUG
 
2374
    printf ("%s %s: is paused? (%d)\n", DEBUGFILE, DEBUGFUNCTION,
 
2375
            gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON
 
2376
                                               (button)));
 
2377
#endif
 
2378
 
 
2379
    if (gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON (button))) {
 
2380
        gettimeofday (&curr_time, NULL);
 
2381
        pause_time = curr_time.tv_sec * 1000 + curr_time.tv_usec / 1000;
 
2382
        if ((jobp->state & VC_REC) != 0) {
 
2383
            time_captured += (pause_time - start_time);
 
2384
        } else {
 
2385
            time_captured = 0;
 
2386
        }
 
2387
        // stop timer handling only if max_time is configured
 
2388
        if (target->time != 0) {
 
2389
            if (stop_timer_id)
 
2390
                g_source_remove (stop_timer_id);
 
2391
        }
 
2392
        xvc_job_merge_and_remove_state (VC_PAUSE, VC_STOP);
 
2393
 
 
2394
        // GUI stuff
 
2395
        w = glade_xml_get_widget (xml, "xvc_ctrl_stop_toggle");
 
2396
        g_assert (w);
 
2397
        gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (w), FALSE);
 
2398
 
 
2399
        if (app->current_mode == 0 && jobp->state & VC_REC) {
 
2400
            if (target->frames == 0
 
2401
                || jobp->pic_no <= (target->frames - target->step)) {
 
2402
                w = glade_xml_get_widget (xml, "xvc_ctrl_step_button");
 
2403
                g_assert (w);
 
2404
                gtk_widget_set_sensitive (GTK_WIDGET (w), TRUE);
 
2405
 
 
2406
                w = glade_xml_get_widget (xml, "xvc_ctrl_forward_button");
 
2407
                g_assert (w);
 
2408
                gtk_widget_set_sensitive (GTK_WIDGET (w), TRUE);
 
2409
            }
 
2410
 
 
2411
            if (jobp->pic_no >= target->step) {
 
2412
                w = glade_xml_get_widget (xml, "xvc_ctrl_back_button");
 
2413
                g_assert (w);
 
2414
                gtk_widget_set_sensitive (GTK_WIDGET (w), TRUE);
 
2415
            }
 
2416
 
 
2417
            w = glade_xml_get_widget (xml, "xvc_ctrl_edit_button");
 
2418
            g_assert (w);
 
2419
            gtk_widget_set_sensitive (GTK_WIDGET (w), TRUE);
 
2420
        }
 
2421
    } else {
 
2422
        xvc_job_remove_state (VC_PAUSE | VC_STEP);
 
2423
        // step is always only active if a running recording session is
 
2424
        // paused
 
2425
        // so releasing pause can always deactivate it
 
2426
 
 
2427
        w = glade_xml_get_widget (xml, "xvc_ctrl_step_button");
 
2428
        g_assert (w);
 
2429
        gtk_widget_set_sensitive (GTK_WIDGET (w), FALSE);
 
2430
        // the following only when recording is going on (not when just
 
2431
        // pressing and
 
2432
        // releasing pause
 
2433
        if (jobp->state & VC_REC) {
 
2434
            w = glade_xml_get_widget (xml, "xvc_ctrl_forward_button");
 
2435
            g_assert (w);
 
2436
            gtk_widget_set_sensitive (GTK_WIDGET (w), FALSE);
 
2437
 
 
2438
            w = glade_xml_get_widget (xml, "xvc_ctrl_back_button");
 
2439
            g_assert (w);
 
2440
            gtk_widget_set_sensitive (GTK_WIDGET (w), FALSE);
 
2441
 
 
2442
            w = glade_xml_get_widget (xml, "xvc_ctrl_edit_button");
 
2443
            g_assert (w);
 
2444
            gtk_widget_set_sensitive (GTK_WIDGET (w), FALSE);
 
2445
        } else {
 
2446
            xvc_job_merge_state (VC_STOP);
 
2447
        }
 
2448
 
 
2449
        pause_time = 0;
 
2450
        gettimeofday (&curr_time, NULL);
 
2451
        start_time = curr_time.tv_sec * 1000 + curr_time.tv_usec / 1000;
 
2452
        // restart timer handling only if max_time is configured
 
2453
        if (target->time != 0) {
 
2454
            // install a timer which stops recording
 
2455
            // we need milli secs ..
 
2456
            stop_timer_id = g_timeout_add ((guint32)
 
2457
                                           (target->time * 1000 -
 
2458
                                            time_captured), (GtkFunction)
 
2459
                                           timer_stop_recording, jobp);
 
2460
        }
 
2461
    }
 
2462
 
 
2463
#undef DEBUGFUNCTION
 
2464
}
 
2465
 
 
2466
void
 
2467
on_xvc_ctrl_step_button_clicked (GtkButton * button, gpointer user_data)
 
2468
{
 
2469
#define DEBUGFUNCTION "on_xvc_ctrl_step_button_clicked()"
 
2470
    GladeXML *xml = NULL;
 
2471
    GtkWidget *w = NULL;
 
2472
    Job *jobp = xvc_job_ptr ();
 
2473
    int pic_no = jobp->pic_no;
 
2474
    XVC_CapTypeOptions *target = NULL;
 
2475
    XVC_AppData *app = xvc_appdata_ptr ();
 
2476
 
 
2477
#ifdef USE_FFMPEG
 
2478
    if (app->current_mode > 0)
 
2479
        target = &(app->multi_frame);
 
2480
    else
 
2481
#endif     // USE_FFMPEG
 
2482
        target = &(app->single_frame);
 
2483
 
 
2484
    if (app->current_mode == 0) {
 
2485
        if (!(jobp->state & (VC_PAUSE | VC_REC)))
 
2486
            return;
 
2487
 
 
2488
        xvc_job_merge_state (VC_STEP);
 
2489
 
 
2490
        xml = glade_get_widget_tree (GTK_WIDGET (xvc_ctrl_main_window));
 
2491
        g_assert (xml);
 
2492
 
 
2493
        if (pic_no == 0) {
 
2494
            w = glade_xml_get_widget (xml, "xvc_ctrl_back_button");
 
2495
            g_assert (w);
 
2496
            gtk_widget_set_sensitive (GTK_WIDGET (w), TRUE);
 
2497
        }
 
2498
 
 
2499
        if (target->frames > 0 && pic_no >= (target->frames - target->step)) {
 
2500
            if (pic_no > (target->frames - target->step)) {
 
2501
                w = glade_xml_get_widget (xml, "xvc_ctrl_step_button");
 
2502
                g_assert (w);
 
2503
                gtk_widget_set_sensitive (GTK_WIDGET (w), FALSE);
 
2504
            }
 
2505
 
 
2506
            w = glade_xml_get_widget (xml, "xvc_ctrl_forward_button");
 
2507
            g_assert (w);
 
2508
            gtk_widget_set_sensitive (GTK_WIDGET (w), FALSE);
 
2509
        }
 
2510
    }
 
2511
#undef DEBUGFUNCTION
 
2512
}
 
2513
 
 
2514
void
 
2515
on_xvc_ctrl_filename_button_clicked (GtkButton * button, gpointer user_data)
 
2516
{
 
2517
#define DEBUGFUNCTION "on_xvc_ctrl_filename_button_clicked()"
 
2518
    GladeXML *xml = NULL;
 
2519
    GtkWidget *w = NULL;
 
2520
    Job *jobp = xvc_job_ptr ();
 
2521
    XVC_CapTypeOptions *target = NULL;
 
2522
    XVC_AppData *app = xvc_appdata_ptr ();
 
2523
 
 
2524
#ifdef USE_FFMPEG
 
2525
    if (app->current_mode > 0)
 
2526
        target = &(app->multi_frame);
 
2527
    else
 
2528
#endif     // USE_FFMPEG
 
2529
        target = &(app->single_frame);
 
2530
 
 
2531
    if (app->current_mode == 0) {
 
2532
        if (jobp->pic_no != target->start_no
 
2533
            && ((jobp->state & VC_STOP) > 0 || (jobp->state & VC_PAUSE) > 0)) {
 
2534
            xml = glade_get_widget_tree (GTK_WIDGET (xvc_ctrl_main_window));
 
2535
            g_assert (xml);
 
2536
 
 
2537
            w = glade_xml_get_widget (xml, "xvc_ctrl_back_button");
 
2538
            g_assert (w);
 
2539
            gtk_widget_set_sensitive (GTK_WIDGET (w), FALSE);
 
2540
 
 
2541
            jobp->pic_no = target->start_no;
 
2542
            GtkChangeLabel (jobp->pic_no);
 
2543
        }
 
2544
    } else {
 
2545
        if (jobp->movie_no != 0 && (jobp->state & VC_STOP) > 0) {
 
2546
            jobp->movie_no = 0;
 
2547
            jobp->pic_no = target->start_no;
 
2548
            GtkChangeLabel (jobp->pic_no);
 
2549
        }
 
2550
    }
 
2551
#undef DEBUGFUNCTION
 
2552
}
 
2553
 
 
2554
void
 
2555
on_xvc_ctrl_back_button_clicked (GtkButton * button, gpointer user_data)
 
2556
{
 
2557
#define DEBUGFUNCTION "on_xvc_ctrl_back_button_clicked()"
 
2558
    GladeXML *xml = NULL;
 
2559
    GtkWidget *w = NULL;
 
2560
    Job *jobp = xvc_job_ptr ();
 
2561
    XVC_CapTypeOptions *target = NULL;
 
2562
    XVC_AppData *app = xvc_appdata_ptr ();
 
2563
 
 
2564
#ifdef USE_FFMPEG
 
2565
    if (app->current_mode > 0)
 
2566
        target = &(app->multi_frame);
 
2567
    else
 
2568
#endif     // USE_FFMPEG
 
2569
        target = &(app->single_frame);
 
2570
 
 
2571
    if (app->current_mode == 0) {
 
2572
        if (jobp->pic_no >= target->step) {
 
2573
            jobp->pic_no -= target->step;
 
2574
            GtkChangeLabel (jobp->pic_no);
 
2575
        } else {
 
2576
            fprintf (stderr,
 
2577
                     "%s %s: back button active although picture number < step. this should never happen\n",
 
2578
                     DEBUGFILE, DEBUGFUNCTION);
 
2579
        }
 
2580
        if (jobp->pic_no < target->step)
 
2581
            gtk_widget_set_sensitive (GTK_WIDGET (button), FALSE);
 
2582
 
 
2583
        if (target->frames == 0
 
2584
            || jobp->pic_no == (target->frames - target->step)) {
 
2585
            xml = glade_get_widget_tree (GTK_WIDGET (xvc_ctrl_main_window));
 
2586
            g_assert (xml);
 
2587
 
 
2588
            if (jobp->state & VC_PAUSE) {
 
2589
                w = glade_xml_get_widget (xml, "xvc_ctrl_step_button");
 
2590
                g_assert (w);
 
2591
                if (app->current_mode == 0)
 
2592
                    gtk_widget_set_sensitive (GTK_WIDGET (w), TRUE);
 
2593
            }
 
2594
 
 
2595
            w = glade_xml_get_widget (xml, "xvc_ctrl_forward_button");
 
2596
            g_assert (w);
 
2597
            gtk_widget_set_sensitive (GTK_WIDGET (w), TRUE);
 
2598
        }
 
2599
    } else {
 
2600
        if (jobp->movie_no > 0) {
 
2601
            jobp->movie_no -= 1;
 
2602
            GtkChangeLabel (jobp->pic_no);
 
2603
        } else {
 
2604
            fprintf (stderr,
 
2605
                     "%s %s: back button active although movie number == 0. this should never happen\n",
 
2606
                     DEBUGFILE, DEBUGFUNCTION);
 
2607
        }
 
2608
        if (jobp->movie_no == 0)
 
2609
            gtk_widget_set_sensitive (GTK_WIDGET (button), FALSE);
 
2610
    }
 
2611
#undef DEBUGFUNCTION
 
2612
}
 
2613
 
 
2614
void
 
2615
on_xvc_ctrl_forward_button_clicked (GtkButton * button, gpointer user_data)
 
2616
{
 
2617
#define DEBUGFUNCTION "on_xvc_ctrl_forward_button_clicked()"
 
2618
    GladeXML *xml = NULL;
 
2619
    GtkWidget *w = NULL;
 
2620
    Job *jobp = xvc_job_ptr ();
 
2621
    XVC_CapTypeOptions *target = NULL;
 
2622
    XVC_AppData *app = xvc_appdata_ptr ();
 
2623
 
 
2624
#ifdef USE_FFMPEG
 
2625
    if (app->current_mode > 0)
 
2626
        target = &(app->multi_frame);
 
2627
    else
 
2628
#endif     // USE_FFMPEG
 
2629
        target = &(app->single_frame);
 
2630
 
 
2631
    if (app->current_mode == 0) {
 
2632
        jobp->pic_no += target->step;
 
2633
        GtkChangeLabel (jobp->pic_no);
 
2634
 
 
2635
        xml = glade_get_widget_tree (GTK_WIDGET (xvc_ctrl_main_window));
 
2636
        g_assert (xml);
 
2637
 
 
2638
        if (jobp->pic_no == target->step) {
 
2639
            w = glade_xml_get_widget (xml, "xvc_ctrl_back_button");
 
2640
            g_assert (w);
 
2641
 
 
2642
            gtk_widget_set_sensitive (GTK_WIDGET (w), TRUE);
 
2643
        }
 
2644
        if (target->frames > 0
 
2645
            && jobp->pic_no > (target->frames - target->step)) {
 
2646
            if (jobp->pic_no >= (target->frames - target->step)) {
 
2647
                w = glade_xml_get_widget (xml, "xvc_ctrl_step_button");
 
2648
                g_assert (w);
 
2649
                gtk_widget_set_sensitive (GTK_WIDGET (w), FALSE);
 
2650
            }
 
2651
 
 
2652
            w = glade_xml_get_widget (xml, "xvc_ctrl_forward_button");
 
2653
            g_assert (w);
 
2654
            gtk_widget_set_sensitive (GTK_WIDGET (w), FALSE);
 
2655
        }
 
2656
 
 
2657
    } else {
 
2658
        jobp->movie_no += 1;
 
2659
        GtkChangeLabel (jobp->pic_no);
 
2660
        if (jobp->movie_no == 1) {
 
2661
            xml = glade_get_widget_tree (GTK_WIDGET (xvc_ctrl_main_window));
 
2662
            g_assert (xml);
 
2663
 
 
2664
            w = glade_xml_get_widget (xml, "xvc_ctrl_back_button");
 
2665
            g_assert (w);
 
2666
 
 
2667
            gtk_widget_set_sensitive (GTK_WIDGET (w), TRUE);
 
2668
        }
 
2669
    }
 
2670
#undef DEBUGFUNCTION
 
2671
}
 
2672
 
 
2673
void
 
2674
on_xvc_ctrl_lock_toggle_toggled (GtkToggleToolButton *
 
2675
                                 togglebutton, gpointer user_data)
 
2676
{
 
2677
#define DEBUGFUNCTION "on_xvc_ctrl_lock_toggle_toggled()"
 
2678
    GtkTooltips *tooltips;
 
2679
    XRectangle *frame_rectangle = NULL;
 
2680
    int x, y, pheight, pwidth;
 
2681
 
 
2682
    tooltips = gtk_tooltips_new ();
 
2683
 
 
2684
    if (gtk_toggle_tool_button_get_active (togglebutton)) {
 
2685
        xvc_set_frame_locked (1);      /* button pressed = move frame with
 
2686
                                        * control */
 
2687
        gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (togglebutton), tooltips,
 
2688
                                   _("Detach selection frame"),
 
2689
                                   _("Detach selection frame"));
 
2690
 
 
2691
        gtk_window_set_gravity (GTK_WINDOW (xvc_ctrl_main_window),
 
2692
                                GDK_GRAVITY_NORTH_WEST);
 
2693
        gtk_window_get_position (GTK_WINDOW (xvc_ctrl_main_window), &x, &y);
 
2694
        gtk_window_get_size (GTK_WINDOW (xvc_ctrl_main_window), &pwidth,
 
2695
                             &pheight);
 
2696
        gtk_window_set_gravity (GTK_WINDOW (xvc_ctrl_main_window),
 
2697
                                GDK_GRAVITY_STATIC);
 
2698
        gtk_window_get_position (GTK_WINDOW (xvc_ctrl_main_window), &x, &y);
 
2699
        gtk_window_get_size (GTK_WINDOW (xvc_ctrl_main_window), &pwidth,
 
2700
                             &pheight);
 
2701
        if (x < 0)
 
2702
            x = 0;
 
2703
        y += pheight + FRAME_OFFSET + FRAME_WIDTH;
 
2704
        if (y < 0)
 
2705
            y = 0;
 
2706
        frame_rectangle = xvc_get_capture_area ();
 
2707
        xvc_change_gtk_frame (x, y, frame_rectangle->width,
 
2708
                              frame_rectangle->height, FALSE, TRUE);
 
2709
    } else {
 
2710
        xvc_set_frame_locked (0);
 
2711
        gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (togglebutton), tooltips,
 
2712
                                   _("Attach selection frame"),
 
2713
                                   _("Attach selection frame"));
 
2714
    }
 
2715
#undef DEBUGFUNCTION
 
2716
}
 
2717
 
 
2718
void
 
2719
on_xvc_ctrl_select_toggle_toggled (GtkToggleToolButton *
 
2720
                                   togglebutton, gpointer user_data)
 
2721
{
 
2722
#define DEBUGFUNCTION "on_xvc_ctrl_select_toggle_toggled()"
 
2723
    Job *jobp = xvc_job_ptr ();
 
2724
    XVC_AppData *app = xvc_appdata_ptr ();
 
2725
 
 
2726
    if (gtk_toggle_tool_button_get_active (togglebutton)) {
 
2727
        Display *display = xvc_frame_get_capture_display ();
 
2728
        Cursor cursor;
 
2729
        Window root = None, target_win = None, temp = None;
 
2730
        XEvent event;
 
2731
        int buttons = 0;
 
2732
        int x_down, y_down, x_up, y_up, x, y;
 
2733
        int width, height;
 
2734
        XGCValues gcv;
 
2735
        GC gc;
 
2736
        XVC_CapTypeOptions *target = NULL;
 
2737
 
 
2738
#ifdef USE_FFMPEG
 
2739
        if (app->current_mode > 0)
 
2740
            target = &(app->multi_frame);
 
2741
        else
 
2742
#endif     // USE_FFMPEG
 
2743
            target = &(app->single_frame);
 
2744
 
 
2745
        g_assert (display);
 
2746
 
 
2747
        root = DefaultRootWindow (display);
 
2748
        cursor = XCreateFontCursor (display, XC_crosshair);
 
2749
 
 
2750
        gcv.background = XBlackPixel (display, XDefaultScreen (display));
 
2751
        gcv.foreground = XWhitePixel (display, XDefaultScreen (display));
 
2752
        gcv.function = GXinvert;
 
2753
        gcv.plane_mask = gcv.background ^ gcv.foreground;
 
2754
        gcv.subwindow_mode = IncludeInferiors;
 
2755
        gc = XCreateGC (display, root,
 
2756
                        GCBackground | GCForeground | GCFunction |
 
2757
                        GCPlaneMask | GCSubwindowMode, &gcv);
 
2758
 
 
2759
        // grab the mouse
 
2760
        //
 
2761
        if (XGrabPointer (display, root, False,
 
2762
                          PointerMotionMask | ButtonPressMask |
 
2763
                          ButtonReleaseMask, GrabModeSync,
 
2764
                          GrabModeAsync, root, cursor, CurrentTime)
 
2765
            != GrabSuccess) {
 
2766
            fprintf (stderr, "%s %s: Can't grab mouse!\n", DEBUGFILE,
 
2767
                     DEBUGFUNCTION);
 
2768
            return;
 
2769
        }
 
2770
        x_down = y_down = x_up = y_up = width = height = 0;
 
2771
 
 
2772
        while (buttons < 2) {
 
2773
            // allow pointer events
 
2774
            XAllowEvents (display, SyncPointer, CurrentTime);
 
2775
            // search in the queue for button events
 
2776
            XWindowEvent (display, root,
 
2777
                          PointerMotionMask | ButtonPressMask |
 
2778
                          ButtonReleaseMask, &event);
 
2779
            switch (event.type) {
 
2780
            case ButtonPress:
 
2781
                x_down = event.xbutton.x;
 
2782
                y_down = event.xbutton.y;
 
2783
                target_win = event.xbutton.subwindow;   // window selected
 
2784
                //
 
2785
                if (target_win == None) {
 
2786
                    target_win = root;
 
2787
                }
 
2788
                buttons++;
 
2789
                break;
 
2790
            case ButtonRelease:
 
2791
                x_up = event.xbutton.x;
 
2792
                y_up = event.xbutton.y;
 
2793
                buttons++;
 
2794
                break;
 
2795
            default:
 
2796
                // motion notify
 
2797
                if (buttons == 1) {
 
2798
                    // button is pressed
 
2799
                    if (x_down > event.xbutton.x) {
 
2800
                        width = x_down - event.xbutton.x + 1;
 
2801
                        x = event.xbutton.x;
 
2802
                    } else {
 
2803
                        width = event.xbutton.x - x_down + 1;
 
2804
                        x = x_down;
 
2805
                    }
 
2806
                    if (y_down > event.xbutton.y) {
 
2807
                        height = y_down - event.xbutton.y + 1;
 
2808
                        y = event.xbutton.y;
 
2809
                    } else {
 
2810
                        height = event.xbutton.y - y_down + 1;
 
2811
                        y = y_down;
 
2812
                    }
 
2813
                    xvc_change_gtk_frame (x, y, width, height, FALSE, TRUE);
 
2814
                    // the previous call changes the frame edges, which are
 
2815
                    // gtk windows. we need to call the gtk main loop for
 
2816
                    // them to be drawn properly within this callback
 
2817
                    while (gtk_events_pending ())
 
2818
                        gtk_main_iteration ();
 
2819
                }
 
2820
                break;
 
2821
            }
 
2822
        }
 
2823
//        if (width > 0)                 // remove old frame
 
2824
//            xvc_change_gtk_frame (x, y, width, height, FALSE, TRUE);
 
2825
 
 
2826
        XUngrabPointer (display, CurrentTime);  // Done with pointer
 
2827
 
 
2828
        XFreeCursor (display, cursor);
 
2829
        XFreeGC (display, gc);
 
2830
 
 
2831
        if ((x_down != x_up) && (y_down != y_up)) {
 
2832
            // an individual frame was selected
 
2833
            if (x_up < x_down) {
 
2834
                width = x_down - x_up + 2;
 
2835
                x = x_up;
 
2836
            } else {
 
2837
                width = x_up - x_down + 2;
 
2838
                x = x_down;
 
2839
            }
 
2840
            if (y_up < y_down) {
 
2841
                height = y_down - y_up + 2;
 
2842
                y = y_up;
 
2843
            } else {
 
2844
                height = y_up - y_down + 2;
 
2845
                y = y_down;
 
2846
            }
 
2847
            xvc_appdata_set_window_attributes (target_win);
 
2848
            app->area->width = width;
 
2849
            app->area->height = height;
 
2850
        } else {
 
2851
            if (target_win != root) {
 
2852
                // get the real window
 
2853
                target_win = XmuClientWindow (display, target_win);
 
2854
            }
 
2855
            xvc_appdata_set_window_attributes (target_win);
 
2856
            XTranslateCoordinates (display, target_win, root, 0, 0, &x, &y,
 
2857
                                   &temp);
 
2858
            app->area->width = app->win_attr.width;
 
2859
            app->area->height = app->win_attr.height;
 
2860
        }
 
2861
 
 
2862
        app->area->x = x;
 
2863
        app->area->y = y;
 
2864
 
 
2865
        xvc_change_gtk_frame (x, y, app->area->width,
 
2866
                              app->area->height, xvc_is_frame_locked (), FALSE);
 
2867
 
 
2868
        // update colors and colormap
 
2869
        xvc_job_set_colors ();
 
2870
 
 
2871
        if (app->flags & FLG_RUN_VERBOSE) {
 
2872
            fprintf (stderr, "%s %s: color_table first entry: 0x%.8X\n",
 
2873
                     DEBUGFILE, DEBUGFUNCTION,
 
2874
                     *(u_int32_t *) jobp->color_table);
 
2875
        }
 
2876
        xvc_job_set_save_function (jobp->target);
 
2877
 
 
2878
#ifdef DEBUG
 
2879
        printf ("%s%s: new visual: %d\n", DEBUGFILE, DEBUGFUNCTION,
 
2880
                app->win_attr.visual->class);
 
2881
#endif
 
2882
 
 
2883
    }
 
2884
    gtk_toggle_tool_button_set_active (togglebutton, FALSE);
 
2885
 
 
2886
#undef DEBUGFUNCTION
 
2887
}
 
2888
 
 
2889
void
 
2890
on_xvc_ctrl_m1_mitem_animate_activate (GtkButton * button, gpointer user_data)
 
2891
{
 
2892
#define DEBUGFUNCTION "on_xvc_ctrl_m1_mitem_animate_activate()"
 
2893
    Job *jobp = xvc_job_ptr ();
 
2894
    XVC_CapTypeOptions *target = NULL;
 
2895
    XVC_AppData *app = xvc_appdata_ptr ();
 
2896
 
 
2897
#ifdef USE_FFMPEG
 
2898
    if (app->current_mode > 0)
 
2899
        target = &(app->multi_frame);
 
2900
    else
 
2901
#endif     // USE_FFMPEG
 
2902
        target = &(app->single_frame);
 
2903
 
 
2904
    if (!app->current_mode) {
 
2905
        xvc_command_execute (target->play_cmd, 1, 0,
 
2906
                             jobp->file, target->start_no, jobp->pic_no,
 
2907
                             app->area->width, app->area->height, target->fps);
 
2908
    } else {
 
2909
        xvc_command_execute (target->play_cmd, 2,
 
2910
                             jobp->movie_no, jobp->file, target->start_no,
 
2911
                             jobp->pic_no, app->area->width,
 
2912
                             app->area->height, target->fps);
 
2913
    }
 
2914
#undef DEBUGFUNCTION
 
2915
}
 
2916
 
 
2917
void
 
2918
on_xvc_ctrl_edit_button_clicked (GtkToolButton * button, gpointer user_data)
 
2919
{
 
2920
#define DEBUGFUNCTION "on_xvc_ctrl_edit_button_clicked()"
 
2921
    Job *jobp = xvc_job_ptr ();
 
2922
    XVC_CapTypeOptions *target = NULL;
 
2923
    XVC_AppData *app = xvc_appdata_ptr ();
 
2924
 
 
2925
#ifdef USE_FFMPEG
 
2926
    if (app->current_mode > 0)
 
2927
        target = &(app->multi_frame);
 
2928
    else
 
2929
#endif     // USE_FFMPEG
 
2930
        target = &(app->single_frame);
 
2931
 
 
2932
    if (!app->current_mode) {
 
2933
        xvc_command_execute (target->edit_cmd, 2,
 
2934
                             jobp->pic_no, jobp->file, target->start_no,
 
2935
                             jobp->pic_no, app->area->width,
 
2936
                             app->area->height, target->fps);
 
2937
    } else {
 
2938
        xvc_command_execute (target->edit_cmd, 2,
 
2939
                             jobp->movie_no, jobp->file, target->start_no,
 
2940
                             jobp->pic_no, app->area->width,
 
2941
                             app->area->height, target->fps);
 
2942
    }
 
2943
#undef DEBUGFUNCTION
 
2944
}
 
2945
 
 
2946
gint
 
2947
on_xvc_ctrl_filename_button_button_press_event (GtkWidget * widget,
 
2948
                                                GdkEvent * event)
 
2949
{
 
2950
#define DEBUGFUNCTION "on_xvc_ctrl_filename_button_press_event()"
 
2951
    gboolean is_sensitive = FALSE;
 
2952
    GdkEventButton *bevent = NULL;
 
2953
 
 
2954
    g_assert (widget);
 
2955
    g_assert (event);
 
2956
    bevent = (GdkEventButton *) event;
 
2957
 
 
2958
    // FIXME: changing from menu sensitive or not to button sensitive or
 
2959
    // not ... make sure that that's what I set elsewhere, too.
 
2960
    g_object_get ((gpointer) widget, (gchar *) "sensitive", &is_sensitive,
 
2961
                  NULL);
 
2962
    if (bevent->button == (guint) 3 && is_sensitive == TRUE) {
 
2963
 
 
2964
        g_assert (xvc_ctrl_m1);
 
2965
 
 
2966
        gtk_menu_popup (GTK_MENU (xvc_ctrl_m1), NULL, NULL,
 
2967
                        position_popup_menu, widget, bevent->button,
 
2968
                        bevent->time);
 
2969
        // Tell calling code that we have handled this event; the buck
 
2970
        // stops here.
 
2971
        return TRUE;
 
2972
    }
 
2973
    // Tell calling code that we have not handled this event; pass it on.
 
2974
    return FALSE;
 
2975
#undef DEBUGFUNCTION
 
2976
}
 
2977
 
 
2978
// this handles the shortcut keybindings for the menu
 
2979
gint
 
2980
on_xvc_ctrl_main_window_key_press_event (GtkWidget * widget, GdkEvent * event)
 
2981
{
 
2982
#define DEBUGFUNCTION "on_xvc_ctrl_main_window_key_press_event()"
 
2983
    gboolean is_sensitive = FALSE;
 
2984
    GtkWidget *button = NULL, *mitem = NULL;
 
2985
    GdkEventKey *kevent = NULL;
 
2986
    GladeXML *xml = NULL;
 
2987
 
 
2988
    g_assert (widget);
 
2989
    g_assert (event);
 
2990
    kevent = (GdkEventKey *) event;
 
2991
 
 
2992
#ifdef DEBUG
 
2993
    printf ("%s %s: Entering\n", DEBUGFILE, DEBUGFUNCTION);
 
2994
#endif     // DEBUG
 
2995
 
 
2996
    xml = glade_get_widget_tree (xvc_ctrl_main_window);
 
2997
    g_assert (xml);
 
2998
    button = glade_xml_get_widget (xml, "xvc_ctrl_filename_button");
 
2999
    g_assert (button);
 
3000
 
 
3001
    g_object_get ((gpointer) button, (gchar *) "sensitive", &is_sensitive,
 
3002
                  NULL);
 
3003
 
 
3004
    if (kevent->keyval == 112 && kevent->state == 4) {
 
3005
        xml = glade_get_widget_tree (xvc_ctrl_m1);
 
3006
        g_assert (xml);
 
3007
        mitem = glade_xml_get_widget (xml, "xvc_ctrl_m1_mitem_preferences");
 
3008
        g_assert (mitem);
 
3009
        gtk_menu_item_activate (GTK_MENU_ITEM (mitem));
 
3010
        return TRUE;
 
3011
    } else if (kevent->keyval == 113 && kevent->state == 4) {
 
3012
        xml = glade_get_widget_tree (xvc_ctrl_m1);
 
3013
        g_assert (xml);
 
3014
        mitem = glade_xml_get_widget (xml, "xvc_ctrl_m1_mitem_quit");
 
3015
        g_assert (mitem);
 
3016
        gtk_menu_item_activate (GTK_MENU_ITEM (mitem));
 
3017
        return TRUE;
 
3018
    } else if (kevent->keyval == 65470
 
3019
               || (kevent->state == 4 && kevent->keyval == 104)) {
 
3020
        xml = glade_get_widget_tree (xvc_ctrl_m1);
 
3021
        g_assert (xml);
 
3022
        mitem = glade_xml_get_widget (xml, "xvc_ctrl_m1_mitem_help");
 
3023
        g_assert (mitem);
 
3024
        gtk_menu_item_activate (GTK_MENU_ITEM (mitem));
 
3025
        return TRUE;
 
3026
    }
 
3027
#ifdef DEBUG
 
3028
    printf ("%s %s: Leaving\n", DEBUGFILE, DEBUGFUNCTION);
 
3029
#endif     // DEBUG
 
3030
 
 
3031
    // Tell calling code that we have not handled this event; pass it on.
 
3032
    return FALSE;
 
3033
#undef DEBUGFUNCTION
 
3034
}
 
3035
 
 
3036
void
 
3037
on_xvc_about_main_window_close (GtkAboutDialog * window, gpointer user_data)
 
3038
{
 
3039
    gtk_widget_destroy (GTK_WIDGET (window));
 
3040
}
 
3041
 
 
3042
void
 
3043
on_xvc_ctrl_m1_mitem_about_activate (GtkMenuItem * menuitem, gpointer user_data)
 
3044
{
 
3045
    GladeXML *xml = NULL;
 
3046
 
 
3047
    // load the interface
 
3048
    xml = glade_xml_new (XVC_GLADE_FILE, "xvc_about_main_window", NULL);
 
3049
    g_assert (xml);
 
3050
    // connect the signals in the interface
 
3051
    glade_xml_signal_autoconnect (xml);
 
3052
}
 
3053
 
 
3054
void
 
3055
on_xvc_ti_stop_selected (GtkMenuItem * menuitem, gpointer user_data)
 
3056
{
 
3057
    GtkWidget *button = NULL;
 
3058
    GladeXML *xml = NULL;
 
3059
 
 
3060
    xml = glade_get_widget_tree (xvc_ctrl_main_window);
 
3061
    g_assert (xml);
 
3062
    button = glade_xml_get_widget (xml, "xvc_ctrl_stop_toggle");
 
3063
    g_assert (button);
 
3064
 
 
3065
    gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (button), TRUE);
 
3066
}
 
3067
 
 
3068
void
 
3069
on_xvc_ti_pause_selected (GtkMenuItem * menuitem, gpointer user_data)
 
3070
{
 
3071
    GtkWidget *button = NULL;
 
3072
    GladeXML *xml = NULL;
 
3073
 
 
3074
    xml = glade_get_widget_tree (xvc_ctrl_main_window);
 
3075
    g_assert (xml);
 
3076
    button = glade_xml_get_widget (xml, "xvc_ctrl_pause_toggle");
 
3077
    g_assert (button);
 
3078
 
 
3079
    gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (button),
 
3080
                                       gtk_check_menu_item_get_active
 
3081
                                       (GTK_CHECK_MENU_ITEM (menuitem)));
 
3082
}
 
3083
 
 
3084
#endif     // DOXYGEN_SHOULD_SKIP_THIS