~ubuntu-branches/ubuntu/vivid/rawstudio/vivid

« back to all changes in this revision

Viewing changes to src/rs-tethered-shooting.c

  • Committer: Bazaar Package Importer
  • Author(s): Bernd Zeimetz
  • Date: 2011-07-28 17:36:32 UTC
  • mfrom: (2.1.11 upstream)
  • Revision ID: james.westby@ubuntu.com-20110728173632-5czluz9ye3c83zc5
Tags: 2.0-1
* [3750b2cf] Merge commit 'upstream/2.0'
* [63637468] Removing Patch, not necessary anymore.
* [2fb580dc] Add new build-dependencies.
* [c57d953b] Run dh_autoreconf due to patches in configure.in
* [13febe39] Add patch to remove the libssl requirement.
* [5ae773fe] Replace libjpeg62-dev by libjpeg8-dev :)
* [1969d755] Don't build static libraries.
* [7cfe0a2e] Add a patch to fix the plugin directory path.
  As plugins are shared libraries, they need to go into /usr/lib,
  not into /usr/share.
  Thanks to Andrew McMillan
* [c1d0d9dd] Don't install .la files for all plugins and libraries.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * * Copyright (C) 2006-2011 Anders Brander <anders@brander.dk>,
 
3
 * * Anders Kvist <akv@lnxbx.dk> and Klaus Post <klauspost@gmail.com>
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU General Public License
 
7
 * as published by the Free Software Foundation; either version 2
 
8
 * of the License, or (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
18
 */
 
19
 
 
20
 
 
21
#include <rawstudio.h>
 
22
#include <glib.h>
 
23
#include <gtk/gtk.h>
 
24
#include <string.h>
 
25
#include <config.h>
 
26
#include <gettext.h>
 
27
#include "rs-tethered-shooting.h"
 
28
#include <gphoto2/gphoto2-camera.h>
 
29
#include <stdlib.h>
 
30
#include <fcntl.h>
 
31
#include "filename.h"
 
32
#include <rs-store.h>
 
33
#include <rs-library.h>
 
34
#ifdef WITH_GCONF
 
35
#include <gconf/gconf-client.h>
 
36
#endif
 
37
#include "conf_interface.h"
 
38
#include "gtk-helper.h"
 
39
#include "rs-photo.h"
 
40
#include "rs-cache.h"
 
41
 
 
42
enum
 
43
{
 
44
  NAME_COLUMN,
 
45
  VALUE_COLUMN,
 
46
  N_COLUMNS
 
47
};
 
48
 
 
49
enum 
 
50
{
 
51
        ASYNC_THREAD_TYPE_NONE,
 
52
        ASYNC_THREAD_TYPE_MONITOR,
 
53
        ASYNC_THREAD_TYPE_INTERVAL
 
54
};
 
55
 
 
56
typedef struct {
 
57
        Camera *camera;
 
58
        GPContext *context;
 
59
        GtkWidget *window;
 
60
        GtkListStore *camera_store;
 
61
        GtkTextBuffer *status_buffer;
 
62
        GtkComboBox *camera_selector;
 
63
        GtkTextView *status_textview;
 
64
        RS_BLOB *rs;
 
65
        GThread *async_thread_id;
 
66
        gboolean keep_thread_running;
 
67
        gint thread_type;
 
68
        GtkWidget *interval_toggle_button;
 
69
        gint interval_toggle_button_signal;
 
70
} TetherInfo;
 
71
 
 
72
typedef struct {
 
73
        GtkWidget *example_label;
 
74
        GtkWidget *event;
 
75
        const gchar *output_type;
 
76
        const gchar *filename;
 
77
} CAMERA_FILENAME;
 
78
 
 
79
static void shutdown_async_thread(TetherInfo *t);
 
80
static void closeconnection(TetherInfo *t);
 
81
static void start_interval_shooting(GObject *entry, gpointer user_data);
 
82
 
 
83
 
 
84
static void
 
85
append_status_va_list(TetherInfo *t, const gchar *format, va_list args)
 
86
{
 
87
        gdk_threads_lock();
 
88
        gchar result_buffer[512];
 
89
        gint str_len = g_vsnprintf(result_buffer, 512, format, args);
 
90
        GtkTextIter iter;
 
91
        gtk_text_buffer_get_end_iter(t->status_buffer, &iter);
 
92
        gtk_text_buffer_insert(t->status_buffer, &iter, result_buffer, str_len);
 
93
        gtk_text_buffer_get_end_iter(t->status_buffer, &iter);
 
94
        if (t->status_textview)
 
95
        {
 
96
                /* get the current ( cursor )mark name */
 
97
                GtkTextMark* insert_mark = gtk_text_buffer_get_insert (t->status_buffer);
 
98
 
 
99
                /* move mark and selection bound to the end */
 
100
                gtk_text_buffer_place_cursor(t->status_buffer, &iter);
 
101
 
 
102
                /* scroll to the end view */
 
103
                gtk_text_view_scroll_to_mark( GTK_TEXT_VIEW (t->status_textview), insert_mark, 0.0, TRUE, 0.0, 1.0); 
 
104
        }
 
105
        gdk_threads_unlock();
 
106
}
 
107
 
 
108
static void
 
109
append_status(TetherInfo *t, const gchar *format, ...)
 
110
{
 
111
        va_list argptr;
 
112
        va_start(argptr,format);
 
113
        append_status_va_list(t, format, argptr);
 
114
        va_end(argptr);
 
115
}
 
116
 
 
117
static void
 
118
ctx_error_func (GPContext *context, const char *format, va_list args, void *data)
 
119
{
 
120
        gdk_threads_lock();
 
121
        TetherInfo *t = (TetherInfo*)data;
 
122
        append_status (t, _("Gphoto2 reported Context Error:\n"));
 
123
        append_status_va_list(t, format, args);
 
124
        append_status  (t, "\n");
 
125
        if (t->async_thread_id && t->async_thread_id != g_thread_self())
 
126
                shutdown_async_thread(t);
 
127
        t->keep_thread_running = FALSE;
 
128
        gdk_threads_unlock();
 
129
}
 
130
 
 
131
static void
 
132
ctx_status_func (GPContext *context, const char *format, va_list args, void *data)
 
133
{
 
134
        TetherInfo *t = (TetherInfo*)data;
 
135
        gdk_threads_lock();
 
136
        append_status_va_list(t, format, args);
 
137
        append_status  (t, "\n");
 
138
        gdk_threads_unlock();
 
139
}
 
140
 
 
141
int
 
142
enumerate_cameras(GtkListStore *camera_store, GPContext *context) {
 
143
        int ret, i, count;
 
144
        CameraList              *xlist = NULL;
 
145
        GPPortInfoList          *portinfolist = NULL;
 
146
        CameraAbilitiesList     *abilities = NULL;
 
147
        GtkTreeIter iter;
 
148
 
 
149
        count = 0;
 
150
        ret = gp_list_new (&xlist);
 
151
        if (ret < GP_OK) goto out;
 
152
        if (!portinfolist) {
 
153
                /* Load all the port drivers we have... */
 
154
                ret = gp_port_info_list_new (&portinfolist);
 
155
                if (ret < GP_OK) goto out;
 
156
                ret = gp_port_info_list_load (portinfolist);
 
157
                if (ret < 0) goto out;
 
158
                ret = gp_port_info_list_count (portinfolist);
 
159
                if (ret < 0) goto out;
 
160
        }
 
161
        /* Load all the camera drivers we have... */
 
162
        ret = gp_abilities_list_new (&abilities);
 
163
        if (ret < GP_OK) goto out;
 
164
        ret = gp_abilities_list_load (abilities, context);
 
165
        if (ret < GP_OK) goto out;
 
166
 
 
167
        /* ... and autodetect the currently attached cameras. */
 
168
        ret = gp_abilities_list_detect (abilities, portinfolist, xlist, context);
 
169
        if (ret < GP_OK) goto out;
 
170
 
 
171
        /* Filter out the "usb:" entry */
 
172
        ret = gp_list_count (xlist);
 
173
        if (ret < GP_OK) goto out;
 
174
        for (i=0;i<ret;i++) {
 
175
                const char *name, *value;
 
176
 
 
177
                gp_list_get_name (xlist, i, &name);
 
178
                gp_list_get_value (xlist, i, &value);
 
179
                if (!strcmp ("usb:",value)) continue;
 
180
                gtk_list_store_append(camera_store, &iter); 
 
181
                gtk_list_store_set (camera_store, &iter,
 
182
                        NAME_COLUMN, name,
 
183
                        VALUE_COLUMN, value,
 
184
                        -1);
 
185
                count++;
 
186
        }
 
187
out:
 
188
        gp_list_free (xlist);
 
189
        return count;
 
190
}
 
191
 
 
192
/*
 
193
 * This function looks up a label or key entry of
 
194
 * a configuration widget.
 
195
 * The functions descend recursively, so you can just
 
196
 * specify the last component.
 
197
 */
 
198
/* Should work, but currently not used */
 
199
#if 0
 
200
 
 
201
static int
 
202
_lookup_widget(CameraWidget*widget, const char *key, CameraWidget **child) {
 
203
        int ret;
 
204
        ret = gp_widget_get_child_by_name (widget, key, child);
 
205
        if (ret < GP_OK)
 
206
                ret = gp_widget_get_child_by_label (widget, key, child);
 
207
        return ret;
 
208
}
 
209
 
 
210
/* Gets a string configuration value.
 
211
 * This can be:
 
212
 *  - A Text widget
 
213
 *  - The current selection of a Radio Button choice
 
214
 *  - The current selection of a Menu choice
 
215
 *
 
216
 * Sample (for Canons eg):
 
217
 *   get_config_value_string (camera, "owner", &ownerstr, context);
 
218
 */
 
219
 
 
220
static int
 
221
get_config_value_string (Camera *camera, const char *key, char **str, GPContext *context) {
 
222
        CameraWidget            *widget = NULL, *child = NULL;
 
223
        CameraWidgetType        type;
 
224
        int                     ret;
 
225
        char                    *val;
 
226
 
 
227
        ret = gp_camera_get_config (camera, &widget, context);
 
228
        if (ret < GP_OK) {
 
229
                g_warning("camera_get_config failed: %d\n", ret);
 
230
                return ret;
 
231
        }
 
232
        ret = _lookup_widget (widget, key, &child);
 
233
        if (ret < GP_OK) {
 
234
                g_warning("lookup widget failed: %d\n", ret);
 
235
                goto out;
 
236
        }
 
237
 
 
238
        /* This type check is optional, if you know what type the label
 
239
         * has already. If you are not sure, better check. */
 
240
        ret = gp_widget_get_type (child, &type);
 
241
        if (ret < GP_OK) {
 
242
                g_warning("widget get type failed: %d\n", ret);
 
243
                goto out;
 
244
        }
 
245
        switch (type) {
 
246
        case GP_WIDGET_MENU:
 
247
        case GP_WIDGET_RADIO:
 
248
        case GP_WIDGET_TEXT:
 
249
                break;
 
250
        default:
 
251
                g_warning("widget has bad type %d\n", type);
 
252
                ret = GP_ERROR_BAD_PARAMETERS;
 
253
                goto out;
 
254
        }
 
255
 
 
256
        /* This is the actual query call. Note that we just
 
257
         * a pointer reference to the string, not a copy... */
 
258
        ret = gp_widget_get_value (child, &val);
 
259
        if (ret < GP_OK) {
 
260
                g_warning("could not query widget value: %d\n", ret);
 
261
                goto out;
 
262
        }
 
263
        /* Create a new copy for our caller. */
 
264
        *str = strdup (val);
 
265
out:
 
266
        gp_widget_free (widget);
 
267
        return ret;
 
268
}
 
269
#endif
 
270
 
 
271
#define CHECKRETVAL(A) if (A < GP_OK) {\
 
272
        append_status(t, _("ERROR: Gphoto2 returned error value %d\nError message is: %s\n"), A, gp_result_as_string(A));\
 
273
        gp_camera_free (t->camera);\
 
274
        t->camera = NULL;\
 
275
        return A;}
 
276
 
 
277
gpointer start_thread_monitor(gpointer _thread_info);
 
278
 
 
279
static int
 
280
enable_capture(TetherInfo *t) 
 
281
{
 
282
  int retval;
 
283
 
 
284
        if (!t->camera)
 
285
                return -1;
 
286
 
 
287
  g_debug("Get root config.");
 
288
  CameraWidget *rootconfig; // okay, not really
 
289
  CameraWidget *actualrootconfig;
 
290
        CameraWidget *child;
 
291
 
 
292
        retval = gp_camera_get_config(t->camera, &rootconfig, t->context);
 
293
        CHECKRETVAL(retval);
 
294
                actualrootconfig = rootconfig;
 
295
 
 
296
        /* Enable on Canon */
 
297
        if (retval >= 0)
 
298
        {
 
299
                retval = gp_widget_get_child_by_name(rootconfig, "main", &child);
 
300
        }
 
301
        if (retval >= 0)
 
302
        {
 
303
                rootconfig = child;
 
304
                retval = gp_widget_get_child_by_name(rootconfig, "settings", &child);
 
305
        }
 
306
        
 
307
        if (retval >= 0)
 
308
        {
 
309
                rootconfig = child;
 
310
                retval = gp_widget_get_child_by_name(rootconfig, "capture", &child);
 
311
        }
 
312
        if (retval >= 0)
 
313
        {
 
314
                CameraWidget *capture = child;
 
315
 
 
316
                const char *widgetinfo;
 
317
                gp_widget_get_name(capture, &widgetinfo);
 
318
                const char *widgetlabel;
 
319
                gp_widget_get_label(capture, &widgetlabel);
 
320
                int widgetid;
 
321
                gp_widget_get_id(capture, &widgetid);
 
322
                CameraWidgetType widgettype;
 
323
                gp_widget_get_type(capture, &widgettype);
 
324
                int one=1;
 
325
                retval = gp_widget_set_value(capture, &one);
 
326
                append_status(t, _("Enabling capture mode for Canon cameras.\n"));
 
327
        }
 
328
 
 
329
        /* Nikon may need this*/
 
330
        retval = gp_widget_get_child_by_name(actualrootconfig, "main", &child);
 
331
 
 
332
        if (retval >= 0)
 
333
        {
 
334
                rootconfig = child;
 
335
                retval = gp_widget_get_child_by_name(rootconfig, "settings", &child);
 
336
        }
 
337
        
 
338
        if (retval >= 0)
 
339
        {
 
340
                rootconfig = child;
 
341
                retval = gp_widget_get_child_by_name(rootconfig, "recordingmedia", &child);
 
342
        }
 
343
        if (retval >= 0)
 
344
        {
 
345
                CameraWidget *capture = child;
 
346
                CameraWidgetType widgettype;
 
347
                gp_widget_get_type(capture, &widgettype);
 
348
                const gchar* one = "SDRAM";
 
349
                retval = gp_widget_set_value(capture, one);
 
350
                append_status(t, _("Enabling capture mode for Nikon cameras.\n"));
 
351
        }
 
352
  g_debug("Enabling capture.");
 
353
  retval = gp_camera_set_config(t->camera, actualrootconfig, t->context);
 
354
        CHECKRETVAL(retval);
 
355
 
 
356
  g_debug("Capture Enabled.");
 
357
        append_status(t, _("Capture Enabled.\n"));
 
358
 
 
359
        return GP_OK;
 
360
}
 
361
 
 
362
static int
 
363
open_camera (TetherInfo *t, const char *model, const char *port) 
 
364
{
 
365
        Camera **camera = &t->camera;
 
366
        int ret, m, p;
 
367
        CameraAbilities a;
 
368
        GPPortInfo      pi;
 
369
        GPPortInfoList          *portinfolist = NULL;
 
370
        CameraAbilitiesList     *abilities = NULL;
 
371
 
 
372
        ret = gp_camera_new (camera);
 
373
        CHECKRETVAL(ret);
 
374
 
 
375
        /* First lookup the model / driver */
 
376
        m = gp_abilities_list_lookup_model (abilities, model);
 
377
        if (m < GP_OK)
 
378
                return ret;
 
379
 
 
380
        ret = gp_abilities_list_get_abilities (abilities, m, &a);
 
381
        CHECKRETVAL(ret);
 
382
 
 
383
        ret = gp_camera_set_abilities (*camera, a);
 
384
        CHECKRETVAL(ret);
 
385
 
 
386
        /* Then associate the camera with the specified port */
 
387
        p = gp_port_info_list_lookup_path (portinfolist, port);
 
388
        switch (p) 
 
389
        {
 
390
                case GP_ERROR_UNKNOWN_PORT:
 
391
                        append_status (t, _("The port you specified ('%s') can not be found."), port);
 
392
                        break;
 
393
                default:
 
394
                        break;
 
395
        }
 
396
 
 
397
        CHECKRETVAL(ret);
 
398
        ret = gp_port_info_list_get_info (portinfolist, p, &pi);
 
399
        CHECKRETVAL(ret);
 
400
        ret = gp_camera_set_port_info (*camera, pi);
 
401
        CHECKRETVAL(ret);
 
402
 
 
403
        return GP_OK;
 
404
}
 
405
 
 
406
 
 
407
static void add_tags_to_photo(TetherInfo* t, RS_PHOTO *photo)
 
408
{
 
409
        const gchar* photo_tags = rs_conf_get_string("tether-tags-for-new-images");
 
410
 
 
411
        if (!photo_tags)
 
412
                return;
 
413
 
 
414
        g_assert(photo != NULL);
 
415
        g_assert(photo->metadata != NULL);
 
416
 
 
417
        RSLibrary *lib = rs_library_get_singleton();
 
418
 
 
419
        rs_library_add_photo_with_metadata(lib, photo->filename, photo->metadata);
 
420
 
 
421
        gchar** split_tags = g_strsplit_set(photo_tags, " .,/;:~^*|&",0);
 
422
        int i = 0;
 
423
        while (split_tags[i] != NULL)
 
424
        {
 
425
                gint tag_id = rs_library_add_tag(lib, split_tags[i]);
 
426
                rs_io_idle_add_tag(photo->filename, tag_id, FALSE, -1);
 
427
                i++;
 
428
        }
 
429
        rs_io_idle_add_tag(photo->filename, -2, FALSE, -1);
 
430
        g_strfreev(split_tags);
 
431
}
 
432
 
 
433
 
 
434
static gchar*
 
435
add_file_to_store(TetherInfo* t, const char* tmp_name) 
 
436
{
 
437
        RSMetadata *metadata;
 
438
        gchar *lwd;
 
439
        gchar* org_template = rs_conf_get_string("tether-export-filename");
 
440
        lwd = rs_conf_get_string(CONF_LWD);
 
441
        GString *filename_template = g_string_new(lwd);
 
442
        g_string_append(filename_template, G_DIR_SEPARATOR_S);
 
443
        g_string_append(filename_template, org_template);
 
444
        g_string_append(filename_template, g_strrstr(tmp_name, "."));
 
445
        
 
446
        gchar* filename = filename_parse(g_string_free(filename_template, FALSE),tmp_name, 0);
 
447
 
 
448
        GFile* src = g_file_new_for_path(tmp_name);
 
449
        GFile* dst = g_file_new_for_path(filename);
 
450
 
 
451
        gdk_threads_unlock();
 
452
        if (!g_file_move(src, dst, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, NULL))
 
453
        {
 
454
                gdk_threads_lock();
 
455
                append_status(t, _("Moving file to current directory failed!\n"));
 
456
                return NULL;
 
457
        }
 
458
        g_object_unref(src);
 
459
        g_object_unref(dst);
 
460
        gdk_threads_lock();
 
461
 
 
462
        rs_store_set_iconview_size(t->rs->store, rs_store_get_iconview_size(t->rs->store)+1);
 
463
        rs_store_load_file(t->rs->store, filename);
 
464
 
 
465
        /* Make sure we rotate this right */
 
466
        gdk_threads_unlock();
 
467
        metadata = rs_metadata_new_from_file(filename);
 
468
        g_object_unref(metadata);
 
469
        gdk_threads_lock();
 
470
        return filename;
 
471
}
 
472
 
 
473
#define RS_NUM_SETTINGS 3
 
474
 
 
475
static gint
 
476
transfer_file_captured(TetherInfo* t, CameraFilePath* camera_file_path) 
 
477
{
 
478
        CameraFile *canonfile;
 
479
        int fd, retval, i;
 
480
        append_status(t,_("Downloading and adding image.\n"));
 
481
        char *tmp_name_ptr;
 
482
        tmp_name_ptr = g_build_filename(g_get_tmp_dir(), g_strdup_printf("rs-tether-%d.tmp", g_random_int()), NULL);
 
483
 
 
484
        if (NULL == tmp_name_ptr)
 
485
                return GP_ERROR;
 
486
 
 
487
        char *extension = g_strrstr(camera_file_path->name, ".");
 
488
        tmp_name_ptr = g_strconcat(tmp_name_ptr, extension, NULL);
 
489
 
 
490
        fd = open(tmp_name_ptr, O_CREAT | O_WRONLY, 0644);
 
491
        if (fd == -1)
 
492
        {
 
493
                append_status(t,_("Could not open temporary file on disk for writing"));
 
494
                return GP_ERROR;
 
495
        }
 
496
 
 
497
        gdk_threads_unlock();
 
498
        retval = gp_file_new_from_fd(&canonfile, fd);
 
499
        CHECKRETVAL(retval);
 
500
        retval = gp_camera_file_get(t->camera, camera_file_path->folder, camera_file_path->name, GP_FILE_TYPE_NORMAL, canonfile, t->context);
 
501
        CHECKRETVAL(retval);
 
502
        retval = gp_camera_file_delete(t->camera, camera_file_path->folder, camera_file_path->name, t->context);
 
503
        CHECKRETVAL(retval);
 
504
        gdk_threads_lock();
 
505
 
 
506
        /* Copy settings */
 
507
        gboolean copy_settings = TRUE;
 
508
        rs_conf_get_boolean_with_default("tether-copy-current-settings", &copy_settings, FALSE);
 
509
        RSSettings *settings_buffer[RS_NUM_SETTINGS];
 
510
 
 
511
        if (copy_settings && t->rs->photo)
 
512
        {
 
513
                for (i = 0; i < RS_NUM_SETTINGS; i++)
 
514
                {
 
515
                        settings_buffer[i] = rs_settings_new();
 
516
                        rs_settings_copy(t->rs->photo->settings[i], MASK_ALL, settings_buffer[i]);
 
517
                }
 
518
        }
 
519
        else 
 
520
                copy_settings = FALSE;
 
521
 
 
522
        gp_file_free(canonfile);
 
523
        gchar *filename = add_file_to_store(t, tmp_name_ptr);
 
524
        if (!filename)
 
525
                return GP_ERROR;
 
526
 
 
527
        gdk_threads_unlock();
 
528
        RS_PHOTO *photo = rs_photo_new();
 
529
        photo->filename = g_strdup(filename);
 
530
 
 
531
        /* Paste settings */
 
532
        if (copy_settings)
 
533
        {
 
534
                for (i = 0; i < RS_NUM_SETTINGS; i++)
 
535
                {
 
536
                        rs_settings_copy(settings_buffer[i], MASK_ALL, photo->settings[i]);
 
537
                        g_object_unref(settings_buffer[i]);
 
538
                }
 
539
                rs_cache_save(photo, MASK_ALL);
 
540
        }
 
541
 
 
542
        /* Add Tags */
 
543
        add_tags_to_photo(t, photo);
 
544
        g_object_unref(photo);
 
545
        photo = NULL;
 
546
        gdk_threads_lock();
 
547
 
 
548
        gboolean minimize = TRUE;
 
549
        rs_conf_get_boolean_with_default("tether-minimize-window", &minimize, TRUE);
 
550
 
 
551
        /* Open image, if this has been selected */
 
552
        gboolean open_image = TRUE;
 
553
        rs_conf_get_boolean_with_default("tether-open-image", &open_image, TRUE);
 
554
        if (open_image)
 
555
        {
 
556
                if (!rs_store_set_selected_name(t->rs->store, filename, TRUE))
 
557
                {
 
558
                        append_status(t, _("Could not open image!\n"));
 
559
                        minimize = FALSE;
 
560
                }
 
561
        }
 
562
 
 
563
        /* Minimize window */
 
564
        if (minimize)
 
565
                gtk_window_iconify(GTK_WINDOW(t->window));
 
566
 
 
567
        g_free(tmp_name_ptr);
 
568
        return GP_OK;
 
569
}
 
570
 
 
571
#undef RS_NUM_SETTINGS
 
572
 
 
573
static gint
 
574
capture_to_file(TetherInfo* t) 
 
575
{
 
576
        int retval;
 
577
        CameraFilePath camera_file_path;
 
578
 
 
579
        append_status(t, _("Capturing.\n"));
 
580
        retval = gp_camera_capture(t->camera, GP_CAPTURE_IMAGE, &camera_file_path, t->context);
 
581
        CHECKRETVAL(retval);
 
582
        retval = transfer_file_captured(t, &camera_file_path);
 
583
        return retval;
 
584
}
 
585
 
 
586
/* 
 
587
 * Threads are purely synchronized by gdk_threads_lock/unlock
 
588
 * Whenever they are idle, or doing heavy non-gui processing or IO, 
 
589
 * the lock is released.
 
590
*/
 
591
 
 
592
gpointer
 
593
start_thread_monitor(gpointer _thread_info)
 
594
{
 
595
        TetherInfo *t = (TetherInfo*) _thread_info;
 
596
        gdk_threads_enter();
 
597
        int retval;
 
598
        while (t->keep_thread_running)
 
599
        {
 
600
                Camera *cam = t->camera;
 
601
                CameraEventType type;
 
602
                void * event_data = NULL;
 
603
                if (NULL == cam)
 
604
                {
 
605
                        t->keep_thread_running = FALSE;
 
606
                        continue;
 
607
                }
 
608
                gdk_threads_leave();
 
609
                retval = gp_camera_wait_for_event(cam, 100, &type, &event_data, t->context);
 
610
                gdk_threads_enter();
 
611
 
 
612
                if (retval < GP_OK)
 
613
                {
 
614
                        append_status(t, _("Monitor recieved error %d, while waiting for camera.\nError text is: %s\n"), retval, gp_result_as_string(retval));
 
615
                        t->keep_thread_running = FALSE;
 
616
                }
 
617
                else
 
618
                {
 
619
                        if (type == GP_EVENT_FILE_ADDED)
 
620
                        {
 
621
                                CameraFilePath* camera_file_path = (CameraFilePath*)event_data;
 
622
                                retval = transfer_file_captured(t, camera_file_path);
 
623
                                if (retval < GP_OK)
 
624
                                {
 
625
                                        append_status(t, _("Recieved error %d, while downloading image from camera.\nError text is: %s\n"), retval, gp_result_as_string(retval));
 
626
                                        t->keep_thread_running = FALSE;
 
627
                                }
 
628
                                else
 
629
                                        append_status(t, _("File Downloaded Succesfully.\n"));
 
630
                        }
 
631
                }
 
632
        }
 
633
        append_status(t, _("Camera monitor shutting down.\n"));
 
634
        gdk_threads_leave();
 
635
        t->thread_type = ASYNC_THREAD_TYPE_NONE;
 
636
        return NULL;
 
637
}
 
638
 
 
639
gpointer
 
640
start_thread_interval(gpointer _thread_info)
 
641
{
 
642
        TetherInfo *t = (TetherInfo*) _thread_info;
 
643
        gdk_threads_enter();
 
644
        int retval;
 
645
        GTimer* capture_timer = g_timer_new();
 
646
        while (t->keep_thread_running)
 
647
        {
 
648
                retval = capture_to_file(t);
 
649
                if (retval < GP_OK)
 
650
                {
 
651
                        append_status(t, _("Recieved error %d, while capturing image.\nError text is: %s\n"), retval, gp_result_as_string(retval));
 
652
                        t->keep_thread_running = FALSE;
 
653
                }
 
654
                if (t->keep_thread_running)
 
655
                {
 
656
                        gdouble interval = 10.0;
 
657
                        rs_conf_get_double("tether-interval-interval", &interval);
 
658
 
 
659
                        gboolean take_next = g_timer_elapsed(capture_timer, NULL) > interval;
 
660
 
 
661
                        if (take_next)
 
662
                                append_status(t, _("Warning: It took longer time to capture the image than the set interval\nIt took %.1f seconds to download the image.\nConsider increasing the interval.\n"), g_timer_elapsed(capture_timer, NULL) + 0.1);
 
663
 
 
664
                        append_status(t, _("Waiting for next image.\n"));
 
665
 
 
666
                        while (t->keep_thread_running && !take_next)
 
667
                        {
 
668
                                if (g_timer_elapsed(capture_timer, NULL) > interval)
 
669
                                        take_next = TRUE;
 
670
                                else
 
671
                                {
 
672
                                        gdk_threads_leave();
 
673
                                        /* Sleep 100ms */
 
674
                                        g_usleep(100*1000);
 
675
                                        gdk_threads_enter();
 
676
                                }
 
677
                        }
 
678
                        g_timer_reset(capture_timer);
 
679
                        
 
680
                        if (t->keep_thread_running)
 
681
                        {
 
682
                                GTK_CATCHUP();
 
683
                                gdk_threads_leave();
 
684
                                /* Sleep 10ms, just to let GUI become responsive */
 
685
                                g_usleep(10*1000);
 
686
                                gdk_threads_enter();
 
687
                        }
 
688
                }
 
689
        }
 
690
        g_signal_handler_disconnect(G_OBJECT(t->interval_toggle_button), t->interval_toggle_button_signal);
 
691
        t->interval_toggle_button_signal =  g_signal_connect(G_OBJECT(t->interval_toggle_button), "clicked", G_CALLBACK(start_interval_shooting), t);
 
692
        gtk_button_set_label(GTK_BUTTON(t->interval_toggle_button), _("Start Shooting"));
 
693
        append_status(t, _("Interval shooting shutting down.\n"));
 
694
        gdk_threads_leave();
 
695
        g_timer_destroy(capture_timer);
 
696
        t->thread_type = ASYNC_THREAD_TYPE_NONE;
 
697
        return NULL;
 
698
}
 
699
 
 
700
static void closeconnection(TetherInfo *t)
 
701
{
 
702
        if (!t->camera)
 
703
                return;
 
704
        append_status(t, _("Disconnecting current camera\n"));
 
705
        gp_camera_exit (t->camera, t->context);
 
706
        gp_camera_free (t->camera);
 
707
        t->camera = NULL;
 
708
}
 
709
 
 
710
static void initcamera(TetherInfo *t, GtkTreeIter *iter)
 
711
{
 
712
        gint ret;
 
713
 
 
714
        /* This call will autodetect cameras, take the
 
715
         * first one from the list and use it. It will ignore
 
716
         * any others... See the *multi* examples on how to
 
717
         * detect and use more than the first one.
 
718
         */
 
719
        const char      *name, *value;
 
720
 
 
721
        gtk_tree_model_get(GTK_TREE_MODEL(t->camera_store), iter,
 
722
                NAME_COLUMN, &name,
 
723
                VALUE_COLUMN, &value, -1);
 
724
 
 
725
        ret = open_camera(t, name, value);
 
726
        if (ret < GP_OK) 
 
727
        {
 
728
                append_status(t,_("Camera %s on port %s failed to open\n"), name, value);
 
729
                return;
 
730
        }
 
731
        
 
732
        ret = gp_camera_init (t->camera, t->context);
 
733
        if (ret < GP_OK) {
 
734
                append_status(t,_("ERROR: Init camera returned %d.\nError text is:%s\n"), ret, gp_result_as_string(ret));
 
735
                gp_camera_free (t->camera);
 
736
                t->camera = NULL;
 
737
                return;
 
738
        }
 
739
 
 
740
        enable_capture(t);
 
741
}
 
742
 
 
743
 
 
744
static void
 
745
update_example(CAMERA_FILENAME *filename)
 
746
{
 
747
        gchar *parsed;
 
748
        gchar *final = "";
 
749
        GtkLabel *example = GTK_LABEL(filename->example_label);
 
750
 
 
751
        parsed = filename_parse(filename->filename, "filename", 0);
 
752
        final = g_strdup_printf("%s.ext", parsed);
 
753
 
 
754
        gtk_label_set_markup(example, final);
 
755
 
 
756
        g_free(parsed);
 
757
        g_free(final);
 
758
}
 
759
 
 
760
/* When entering this, we must have gdk locked */
 
761
static void
 
762
shutdown_async_thread(TetherInfo *t)
 
763
{
 
764
        if (t->async_thread_id && t->keep_thread_running)
 
765
        {
 
766
                t->keep_thread_running = FALSE;
 
767
                gdk_threads_leave();
 
768
                g_thread_join(t->async_thread_id);
 
769
                gdk_threads_enter();
 
770
                t->async_thread_id = NULL;
 
771
                append_status(t, _("Shutting down asynchronous thread\n"));
 
772
        }
 
773
}
 
774
 
 
775
 
 
776
static void
 
777
refresh_cameralist(GObject *entry, gpointer user_data)
 
778
{
 
779
        TetherInfo *t = (TetherInfo*)user_data;
 
780
        shutdown_async_thread(t);
 
781
        closeconnection(t);
 
782
        gtk_list_store_clear(t->camera_store);
 
783
        int i = enumerate_cameras(t->camera_store, t->context);
 
784
        append_status(t, _("Found %d cameras\n"), i);
 
785
        if (i > 0)
 
786
                gtk_combo_box_set_active(GTK_COMBO_BOX(t->camera_selector), 0);
 
787
        else
 
788
                gtk_combo_box_set_active(GTK_COMBO_BOX(t->camera_selector), -1);
 
789
 
 
790
}
 
791
 
 
792
static void
 
793
connect_camera(GObject *entry, gpointer user_data)
 
794
{
 
795
        TetherInfo *t = (TetherInfo*)user_data;
 
796
        shutdown_async_thread(t);
 
797
        closeconnection(t);
 
798
        GtkTreeIter iter;
 
799
        if (gtk_combo_box_get_active_iter(t->camera_selector, &iter))
 
800
                initcamera(t,&iter);
 
801
        else
 
802
                append_status(t, _("No camera selected - Cannot connect!\n"));
 
803
}
 
804
 
 
805
static void
 
806
take_photo(GObject *entry, gpointer user_data)
 
807
{
 
808
        TetherInfo *t = (TetherInfo*)user_data;
 
809
        gint ret_val;
 
810
        if (!t->camera)
 
811
                connect_camera(entry, user_data);
 
812
        if (!t->camera)
 
813
                return;
 
814
 
 
815
        if (t->keep_thread_running)
 
816
        {
 
817
                append_status(t, _("Shutting down running thread to enable remote capture.\n"));
 
818
                shutdown_async_thread(t);
 
819
        }
 
820
 
 
821
        ret_val = capture_to_file(t);
 
822
        if (ret_val < GP_OK)
 
823
        {
 
824
                append_status(t, _("Recieved error %d, while capturing image.\nError text is: %s\n"), ret_val, gp_result_as_string(ret_val));
 
825
                closeconnection(t);
 
826
        }
 
827
}
 
828
 
 
829
static void
 
830
tags_entry_changed(GtkEntry *entry, gpointer user_data)
 
831
{
 
832
        const gchar* tags = gtk_entry_get_text(GTK_ENTRY(entry));
 
833
        rs_conf_set_string("tether-tags-for-new-images", tags);
 
834
}
 
835
 
 
836
static void
 
837
spin_button_entry_changed(GtkEntry *entry, gpointer user_data)
 
838
{
 
839
        gdouble value = gtk_spin_button_get_value(GTK_SPIN_BUTTON(entry));
 
840
        rs_conf_set_double(user_data, value);
 
841
}
 
842
 
 
843
static void
 
844
filename_entry_changed(GtkEntry *entry, gpointer user_data)
 
845
{
 
846
        CAMERA_FILENAME *filename = (CAMERA_FILENAME *) user_data;
 
847
        filename->filename = gtk_entry_get_text(entry);
 
848
        update_example(filename);
 
849
}
 
850
 
 
851
static void
 
852
start_monitor(GObject *entry, gpointer user_data)
 
853
{
 
854
        TetherInfo *t = (TetherInfo*)user_data;
 
855
        if (!t->camera)
 
856
                connect_camera(entry, user_data);
 
857
        if (!t->camera)
 
858
                return;
 
859
 
 
860
        if ((t->async_thread_id || t->keep_thread_running) && t->thread_type != ASYNC_THREAD_TYPE_MONITOR)
 
861
        {
 
862
                append_status(t, _("Shutting down already running thread.\n"));
 
863
                shutdown_async_thread(t);
 
864
        }
 
865
        if (!t->async_thread_id || !t->keep_thread_running)
 
866
        {
 
867
                t->keep_thread_running = TRUE;
 
868
                append_status(t, _("Staring Monitor Thread.\n"));
 
869
                t->thread_type = ASYNC_THREAD_TYPE_MONITOR;
 
870
                t->async_thread_id = g_thread_create(start_thread_monitor, t, TRUE, NULL);
 
871
        }
 
872
        else
 
873
                append_status(t, _("Monitor Thread already running.\n"));
 
874
 
 
875
}
 
876
 
 
877
static void
 
878
close_button_pressed(GtkEntry *entry, gpointer user_data)
 
879
{
 
880
        TetherInfo *t = (TetherInfo*)user_data;
 
881
        shutdown_async_thread(t);
 
882
        closeconnection(t);
 
883
        gp_context_unref(t->context);
 
884
        gtk_widget_destroy(t->window);
 
885
}
 
886
 
 
887
static void
 
888
close_main_window(GtkEntry *entry, GdkEvent *event, gpointer user_data)
 
889
{
 
890
        TetherInfo *t = (TetherInfo*)user_data;
 
891
        shutdown_async_thread(t);
 
892
        if (t->camera)
 
893
                closeconnection(t);
 
894
        gp_context_unref(t->context);
 
895
        gtk_widget_destroy(GTK_WIDGET(entry));
 
896
}
 
897
 
 
898
static void 
 
899
stop_interval_shooting(GObject *entry, gpointer user_data)
 
900
{
 
901
        TetherInfo *t = (TetherInfo*)user_data;
 
902
        if (t->keep_thread_running && t->thread_type == ASYNC_THREAD_TYPE_INTERVAL)
 
903
        {
 
904
                append_status(t, _("Shutting down interval capture thread.\n"));
 
905
                shutdown_async_thread(t);
 
906
        }
 
907
}
 
908
 
 
909
static void 
 
910
disconnect_camera_action(GObject *entry, gpointer user_data)
 
911
{
 
912
        TetherInfo *t = (TetherInfo*)user_data;
 
913
        if (!t->camera)
 
914
        {
 
915
                append_status(t, _("No camera connected.\n"));
 
916
                return;
 
917
        }
 
918
        shutdown_async_thread(t);
 
919
        closeconnection(t);
 
920
}
 
921
 
 
922
static void 
 
923
start_interval_shooting(GObject *entry, gpointer user_data)
 
924
{
 
925
        TetherInfo *t = (TetherInfo*)user_data;
 
926
        if (!t->camera)
 
927
                connect_camera(entry, user_data);
 
928
        if (!t->camera)
 
929
                return;
 
930
        if (t->keep_thread_running)
 
931
                shutdown_async_thread(t);
 
932
 
 
933
        t->thread_type = ASYNC_THREAD_TYPE_INTERVAL;
 
934
        t->keep_thread_running = TRUE;
 
935
        append_status(t, _("Staring Interval Shooting Thread.\n"));
 
936
        g_signal_handler_disconnect(G_OBJECT(t->interval_toggle_button), t->interval_toggle_button_signal);
 
937
        t->interval_toggle_button_signal = g_signal_connect(G_OBJECT(t->interval_toggle_button), "clicked", G_CALLBACK(stop_interval_shooting), t);
 
938
        gtk_button_set_label(GTK_BUTTON(t->interval_toggle_button), _("Stop Shooting"));
 
939
        GTK_CATCHUP();
 
940
        t->async_thread_id = g_thread_create(start_thread_interval, t, TRUE, NULL);
 
941
}
 
942
 
 
943
static void 
 
944
build_tether_gui(TetherInfo *t)
 
945
{
 
946
 
 
947
        GtkWidget *button;
 
948
        GtkWidget* label;
 
949
        GtkBox *box, *h_box;
 
950
        GtkWidget *filename_hbox;
 
951
        GtkWidget *filename_label;
 
952
        GtkWidget *filename_chooser;
 
953
        GtkWidget *filename_entry;
 
954
        GtkWidget *check_button;
 
955
 
 
956
        GtkWidget *example_hbox;
 
957
        GtkWidget *example_label1;
 
958
        GtkWidget *example_label2;
 
959
        CAMERA_FILENAME *filename;
 
960
 
 
961
        GtkWidget *status_window;
 
962
        GtkWidget *status_textview;
 
963
        GtkWidget *tags_entry;
 
964
        GtkWidget *number_spin;
 
965
 
 
966
        /* A box to hold everything */
 
967
        GtkBox *main_box = GTK_BOX(gtk_vbox_new (FALSE, 7));
 
968
 
 
969
        /* A box for main constrols */
 
970
        box = GTK_BOX(gtk_vbox_new (FALSE, 5));
 
971
 
 
972
        label = gtk_label_new(_("Select camera:"));
 
973
        gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
 
974
        gtk_misc_set_padding (GTK_MISC(label), 7,3);
 
975
        gtk_box_pack_start(box, label, FALSE, FALSE, 0);
 
976
 
 
977
        /* Camera */
 
978
        h_box = GTK_BOX(gtk_hbox_new (FALSE, 0));
 
979
 
 
980
        /* Camera selector box */
 
981
        GtkWidget *camera_selector = gtk_combo_box_new_with_model(GTK_TREE_MODEL(t->camera_store));
 
982
        GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
 
983
        gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (camera_selector), cell, TRUE);
 
984
        gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (camera_selector), cell, "text", NAME_COLUMN); 
 
985
        gtk_box_pack_start(h_box, camera_selector, TRUE, TRUE, 2);
 
986
        gtk_combo_box_set_active(GTK_COMBO_BOX(camera_selector), 0);
 
987
        t->camera_selector = GTK_COMBO_BOX(camera_selector);
 
988
 
 
989
        /* Refresh / Connect buttons */
 
990
        button = gtk_button_new_from_stock(GTK_STOCK_REFRESH);
 
991
        g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(refresh_cameralist), t);
 
992
        gtk_box_pack_start(h_box, button, FALSE, FALSE, 1);
 
993
 
 
994
        /* Add this box */
 
995
        gtk_box_pack_start(box, GTK_WIDGET(h_box), FALSE, FALSE, 5);
 
996
 
 
997
        /* "Take photo" & Monitor button */
 
998
        h_box = GTK_BOX(gtk_hbox_new (FALSE, 0));
 
999
        button = gtk_button_new_from_stock(GTK_STOCK_CONNECT);
 
1000
        g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(connect_camera), t);
 
1001
        gtk_box_pack_start(h_box, button, FALSE, FALSE, 1);
 
1002
 
 
1003
        button = gtk_button_new_with_label(_("Take Photo"));
 
1004
        g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(take_photo), t);
 
1005
        gtk_button_set_alignment (GTK_BUTTON(button), 0.0, 0.5);
 
1006
        gtk_box_pack_start(h_box, button, FALSE, FALSE, 5);
 
1007
 
 
1008
        button = gtk_button_new_with_label(_("Monitor Camera"));
 
1009
        g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(start_monitor), t);
 
1010
        gtk_button_set_alignment (GTK_BUTTON(button), 0.0, 0.5);
 
1011
        gtk_box_pack_start(h_box, button, FALSE, FALSE, 5);
 
1012
 
 
1013
        button = gtk_button_new_with_label(_("Disconnect Camera"));
 
1014
        g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(disconnect_camera_action), t);
 
1015
        gtk_button_set_alignment (GTK_BUTTON(button), 0.0, 0.5);
 
1016
        gtk_box_pack_start(h_box, button, FALSE, FALSE, 5);
 
1017
 
 
1018
        /* Add this box */
 
1019
        gtk_box_pack_start(box, GTK_WIDGET(h_box), FALSE, FALSE, 5);
 
1020
 
 
1021
        /* Status window */
 
1022
        label = gtk_label_new(_("Status:"));
 
1023
        gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
 
1024
        gtk_box_pack_start(box, label, FALSE, FALSE, 5);
 
1025
        status_window = gtk_scrolled_window_new(NULL, NULL);
 
1026
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(status_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 
1027
 
 
1028
        /* Status text */
 
1029
        status_textview = gtk_text_view_new_with_buffer(t->status_buffer);
 
1030
        gtk_text_view_set_editable(GTK_TEXT_VIEW(status_textview), FALSE);
 
1031
        gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(status_textview), FALSE);
 
1032
        gtk_container_add ( GTK_CONTAINER(status_window), status_textview);
 
1033
        gtk_box_pack_start(GTK_BOX(box), status_window, TRUE, FALSE, 0);
 
1034
        t->status_textview = GTK_TEXT_VIEW(status_textview);
 
1035
 
 
1036
        /* Add main box */
 
1037
        gtk_box_pack_start(GTK_BOX(main_box), gui_box(_("Master Control"), GTK_WIDGET(box), "tether_controls", TRUE), FALSE, FALSE, 0);
 
1038
 
 
1039
        /* FILENAME & TAGS */
 
1040
        box = GTK_BOX(gtk_vbox_new (FALSE, 5));
 
1041
                /* Filename template*/
 
1042
        filename = g_new0(CAMERA_FILENAME, 1);
 
1043
        filename_hbox = gtk_hbox_new(FALSE, 0);
 
1044
        filename_label = gtk_label_new(_("Filename template:"));
 
1045
        filename_chooser = rs_filename_chooser_button_new(NULL, "tether-export-filename");
 
1046
        filename_entry = g_object_get_data(G_OBJECT(filename_chooser), "entry");
 
1047
        g_signal_connect(filename_entry, "changed", G_CALLBACK(filename_entry_changed), filename);
 
1048
        filename->filename = gtk_entry_get_text(GTK_ENTRY(filename_entry));
 
1049
 
 
1050
        gtk_misc_set_alignment(GTK_MISC(filename_label), 0.0, 0.5);
 
1051
        gtk_box_pack_start(GTK_BOX(filename_hbox), filename_label, FALSE, TRUE, 5);
 
1052
        gtk_box_pack_start(GTK_BOX(filename_hbox), filename_chooser, FALSE, TRUE, 5);
 
1053
        gtk_box_pack_start(GTK_BOX(box), filename_hbox, FALSE, TRUE, 0);
 
1054
 
 
1055
        /* Example filename */
 
1056
        example_hbox = gtk_hbox_new(FALSE, 0);
 
1057
        example_label1 = gtk_label_new(_("Filename example:"));
 
1058
        example_label2 = gtk_label_new(NULL);
 
1059
        filename->example_label = example_label2;
 
1060
 
 
1061
        gtk_misc_set_alignment(GTK_MISC(example_label1), 0.0, 0.5);
 
1062
        gtk_misc_set_alignment(GTK_MISC(example_label2), 0.0, 0.5);
 
1063
        gtk_box_pack_start(GTK_BOX(example_hbox), example_label1, FALSE, TRUE, 5);
 
1064
        gtk_box_pack_start(GTK_BOX(example_hbox), example_label2, FALSE, TRUE, 5);
 
1065
        gtk_box_pack_start(GTK_BOX(box), example_hbox, FALSE, TRUE, 0);
 
1066
        update_example(filename);
 
1067
 
 
1068
        h_box = GTK_BOX(gtk_hbox_new (FALSE, 0));
 
1069
        label = gtk_label_new(_("Tags for new images:"));
 
1070
        gtk_box_pack_start(GTK_BOX(h_box), label, FALSE, TRUE, 5);
 
1071
 
 
1072
        tags_entry = gtk_entry_new();
 
1073
        gchar* tags = rs_conf_get_string("tether-tags-for-new-images");
 
1074
        if (tags)
 
1075
                gtk_entry_set_text(GTK_ENTRY(tags_entry), tags);
 
1076
        g_signal_connect(tags_entry, "changed", G_CALLBACK(tags_entry_changed), NULL);
 
1077
        gtk_box_pack_start(GTK_BOX(h_box), tags_entry, TRUE, TRUE, 5);
 
1078
        gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(h_box), FALSE, TRUE, 0);
 
1079
 
 
1080
 
 
1081
        /* Add filename& tags box */
 
1082
        gtk_box_pack_start(GTK_BOX(main_box), gui_box(_("Filename &amp; Tags"), GTK_WIDGET(box), "tether_filename_tags", TRUE), FALSE, FALSE, 0);
 
1083
 
 
1084
        /* INTERVAL SHOOTING */
 
1085
        box = GTK_BOX(gtk_vbox_new (FALSE, 2));
 
1086
 
 
1087
        h_box = GTK_BOX(gtk_hbox_new (FALSE, 0));
 
1088
        label = gtk_label_new(_("Seconds between each shot:"));
 
1089
        gtk_box_pack_start(h_box, label, FALSE, FALSE, 5);
 
1090
        number_spin = gtk_spin_button_new_with_range(1.0, 24.0*60*60, 0.2);
 
1091
        gdouble interval = 10.0;
 
1092
        rs_conf_get_double("tether-interval-interval", &interval);
 
1093
        gtk_spin_button_set_value (GTK_SPIN_BUTTON(number_spin), interval);
 
1094
        g_signal_connect(number_spin, "changed", G_CALLBACK(spin_button_entry_changed), "tether-interval-interval");
 
1095
        gtk_box_pack_start(h_box, number_spin, FALSE, FALSE, 7);
 
1096
        gtk_box_pack_start(box, GTK_WIDGET(h_box), FALSE, FALSE, 2);
 
1097
 
 
1098
        h_box = GTK_BOX(gtk_hbox_new (FALSE, 0));
 
1099
        button = gtk_button_new_with_label(_("Start Shooting"));
 
1100
        t->interval_toggle_button_signal = g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(start_interval_shooting), t);
 
1101
        gtk_button_set_alignment (GTK_BUTTON(button), 0.0, 0.5);
 
1102
        gtk_box_pack_start(h_box, button, FALSE, FALSE, 5);
 
1103
        t->interval_toggle_button = button;
 
1104
        gtk_box_pack_start(box, GTK_WIDGET(h_box), FALSE, FALSE, 2);
 
1105
 
 
1106
        /* Add interval shooting box */
 
1107
        gtk_box_pack_start(GTK_BOX(main_box), gui_box(_("Interval Shooting"), GTK_WIDGET(box), "tether_interval_shooting_box", TRUE), FALSE, FALSE, 0);
 
1108
 
 
1109
 
 
1110
        /* PREFERENCES */
 
1111
        box = GTK_BOX(gtk_vbox_new (FALSE, 5));
 
1112
 
 
1113
        h_box = GTK_BOX(gtk_hbox_new (FALSE, 0));
 
1114
        check_button = checkbox_from_conf("tether-minimize-window", _("Minimize this window after capture"), TRUE);
 
1115
        gtk_button_set_alignment (GTK_BUTTON(check_button), 0.0, 0.5);
 
1116
        gtk_box_pack_start(h_box, check_button, FALSE, FALSE, 5);
 
1117
 
 
1118
        check_button = checkbox_from_conf("tether-copy-current-settings", _("Copy settings from active to new image"), FALSE);
 
1119
        gtk_button_set_alignment (GTK_BUTTON(check_button), 0.0, 0.5);
 
1120
        gtk_box_pack_start(h_box, check_button, FALSE, FALSE, 5);
 
1121
        gtk_box_pack_start(box, GTK_WIDGET(h_box), FALSE, FALSE, 0);
 
1122
 
 
1123
        h_box = GTK_BOX(gtk_hbox_new (FALSE, 0));
 
1124
        check_button = checkbox_from_conf("tether-open-image", _("Open new images after capture"), TRUE);
 
1125
        gtk_button_set_alignment (GTK_BUTTON(check_button), 0.0, 0.5);
 
1126
        gtk_box_pack_start(h_box, check_button, FALSE, FALSE, 5);
 
1127
        gtk_box_pack_start(box, GTK_WIDGET(h_box), FALSE, FALSE, 0);
 
1128
 
 
1129
        /* Add preferences box */
 
1130
        gtk_box_pack_start(GTK_BOX(main_box), gui_box(_("Preferences"), GTK_WIDGET(box), "tether_preferences", TRUE), FALSE, FALSE, 0);
 
1131
 
 
1132
                /* Close button */
 
1133
        h_box = GTK_BOX(gtk_hbox_new (FALSE, 0));
 
1134
        button = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
 
1135
        g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(close_button_pressed), t);
 
1136
        gtk_box_pack_end(h_box, button, FALSE, FALSE, 5);
 
1137
        gtk_box_pack_end(GTK_BOX(main_box), GTK_WIDGET(h_box), FALSE, FALSE, 5);
 
1138
 
 
1139
        /* All all to window */
 
1140
        gtk_container_set_border_width (GTK_CONTAINER(t->window), 5);
 
1141
        gtk_container_add(GTK_CONTAINER(t->window), GTK_WIDGET(main_box));
 
1142
 
 
1143
}
 
1144
 
 
1145
 
 
1146
void
 
1147
rs_tethered_shooting_open(RS_BLOB *rs) 
 
1148
{
 
1149
        GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 
1150
        gtk_window_set_title(GTK_WINDOW(window), _("Rawstudio Tethered Shooting"));
 
1151
        gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(rs->window));
 
1152
        gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ON_PARENT);
 
1153
        gchar* filename_template = rs_conf_get_string("tether-export-filename");
 
1154
 
 
1155
        /* Initialize filename_template to default if nothing is saved in config */
 
1156
        if (!filename_template)
 
1157
                rs_conf_set_string("tether-export-filename","Rawstudio_%2c");
 
1158
        else
 
1159
                g_free(filename_template);
 
1160
 
 
1161
        TetherInfo *tether_info = NULL;
 
1162
 
 
1163
        if (tether_info == NULL)
 
1164
        {
 
1165
                tether_info = g_malloc0(sizeof(TetherInfo));
 
1166
        }
 
1167
        tether_info->window = window;
 
1168
        tether_info->rs = rs;
 
1169
        tether_info->status_buffer = gtk_text_buffer_new(NULL);
 
1170
        tether_info->keep_thread_running = FALSE;
 
1171
        tether_info->thread_type = ASYNC_THREAD_TYPE_NONE;
 
1172
 
 
1173
        gtk_text_buffer_set_text(tether_info->status_buffer,_("Welcome to Tethered shooting!\nMake sure your camera is NOT mounted in your operating system.\n"),-1);
 
1174
        g_signal_connect(window, "delete-event", G_CALLBACK(close_main_window), tether_info);
 
1175
 
 
1176
        /* Initialize context */
 
1177
        tether_info->context = gp_context_new();
 
1178
        gp_context_set_error_func (tether_info->context, ctx_error_func, tether_info);
 
1179
        gp_context_set_status_func (tether_info->context, ctx_status_func, tether_info);        
 
1180
 
 
1181
        /* Enumerate cameras */
 
1182
        tether_info->camera_store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING);
 
1183
        int i = enumerate_cameras(tether_info->camera_store, tether_info->context);
 
1184
 
 
1185
        append_status(tether_info, _("Found %d cameras\n"), i);
 
1186
 
 
1187
        build_tether_gui(tether_info);
 
1188
        gtk_window_resize(GTK_WINDOW(window), 500, 400);
 
1189
        gtk_widget_show_all(GTK_WIDGET(window));
 
1190
}