2
* * Copyright (C) 2006-2011 Anders Brander <anders@brander.dk>,
3
* * Anders Kvist <akv@lnxbx.dk> and Klaus Post <klauspost@gmail.com>
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.
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.
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.
21
#include <rawstudio.h>
27
#include "rs-tethered-shooting.h"
28
#include <gphoto2/gphoto2-camera.h>
33
#include <rs-library.h>
35
#include <gconf/gconf-client.h>
37
#include "conf_interface.h"
38
#include "gtk-helper.h"
51
ASYNC_THREAD_TYPE_NONE,
52
ASYNC_THREAD_TYPE_MONITOR,
53
ASYNC_THREAD_TYPE_INTERVAL
60
GtkListStore *camera_store;
61
GtkTextBuffer *status_buffer;
62
GtkComboBox *camera_selector;
63
GtkTextView *status_textview;
65
GThread *async_thread_id;
66
gboolean keep_thread_running;
68
GtkWidget *interval_toggle_button;
69
gint interval_toggle_button_signal;
73
GtkWidget *example_label;
75
const gchar *output_type;
76
const gchar *filename;
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);
85
append_status_va_list(TetherInfo *t, const gchar *format, va_list args)
88
gchar result_buffer[512];
89
gint str_len = g_vsnprintf(result_buffer, 512, format, args);
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)
96
/* get the current ( cursor )mark name */
97
GtkTextMark* insert_mark = gtk_text_buffer_get_insert (t->status_buffer);
99
/* move mark and selection bound to the end */
100
gtk_text_buffer_place_cursor(t->status_buffer, &iter);
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);
105
gdk_threads_unlock();
109
append_status(TetherInfo *t, const gchar *format, ...)
112
va_start(argptr,format);
113
append_status_va_list(t, format, argptr);
118
ctx_error_func (GPContext *context, const char *format, va_list args, void *data)
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();
132
ctx_status_func (GPContext *context, const char *format, va_list args, void *data)
134
TetherInfo *t = (TetherInfo*)data;
136
append_status_va_list(t, format, args);
137
append_status (t, "\n");
138
gdk_threads_unlock();
142
enumerate_cameras(GtkListStore *camera_store, GPContext *context) {
144
CameraList *xlist = NULL;
145
GPPortInfoList *portinfolist = NULL;
146
CameraAbilitiesList *abilities = NULL;
150
ret = gp_list_new (&xlist);
151
if (ret < GP_OK) goto out;
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;
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;
167
/* ... and autodetect the currently attached cameras. */
168
ret = gp_abilities_list_detect (abilities, portinfolist, xlist, context);
169
if (ret < GP_OK) goto out;
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;
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,
188
gp_list_free (xlist);
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.
198
/* Should work, but currently not used */
202
_lookup_widget(CameraWidget*widget, const char *key, CameraWidget **child) {
204
ret = gp_widget_get_child_by_name (widget, key, child);
206
ret = gp_widget_get_child_by_label (widget, key, child);
210
/* Gets a string configuration value.
213
* - The current selection of a Radio Button choice
214
* - The current selection of a Menu choice
216
* Sample (for Canons eg):
217
* get_config_value_string (camera, "owner", &ownerstr, context);
221
get_config_value_string (Camera *camera, const char *key, char **str, GPContext *context) {
222
CameraWidget *widget = NULL, *child = NULL;
223
CameraWidgetType type;
227
ret = gp_camera_get_config (camera, &widget, context);
229
g_warning("camera_get_config failed: %d\n", ret);
232
ret = _lookup_widget (widget, key, &child);
234
g_warning("lookup widget failed: %d\n", ret);
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);
242
g_warning("widget get type failed: %d\n", ret);
247
case GP_WIDGET_RADIO:
251
g_warning("widget has bad type %d\n", type);
252
ret = GP_ERROR_BAD_PARAMETERS;
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);
260
g_warning("could not query widget value: %d\n", ret);
263
/* Create a new copy for our caller. */
266
gp_widget_free (widget);
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);\
277
gpointer start_thread_monitor(gpointer _thread_info);
280
enable_capture(TetherInfo *t)
287
g_debug("Get root config.");
288
CameraWidget *rootconfig; // okay, not really
289
CameraWidget *actualrootconfig;
292
retval = gp_camera_get_config(t->camera, &rootconfig, t->context);
294
actualrootconfig = rootconfig;
296
/* Enable on Canon */
299
retval = gp_widget_get_child_by_name(rootconfig, "main", &child);
304
retval = gp_widget_get_child_by_name(rootconfig, "settings", &child);
310
retval = gp_widget_get_child_by_name(rootconfig, "capture", &child);
314
CameraWidget *capture = child;
316
const char *widgetinfo;
317
gp_widget_get_name(capture, &widgetinfo);
318
const char *widgetlabel;
319
gp_widget_get_label(capture, &widgetlabel);
321
gp_widget_get_id(capture, &widgetid);
322
CameraWidgetType widgettype;
323
gp_widget_get_type(capture, &widgettype);
325
retval = gp_widget_set_value(capture, &one);
326
append_status(t, _("Enabling capture mode for Canon cameras.\n"));
329
/* Nikon may need this*/
330
retval = gp_widget_get_child_by_name(actualrootconfig, "main", &child);
335
retval = gp_widget_get_child_by_name(rootconfig, "settings", &child);
341
retval = gp_widget_get_child_by_name(rootconfig, "recordingmedia", &child);
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"));
352
g_debug("Enabling capture.");
353
retval = gp_camera_set_config(t->camera, actualrootconfig, t->context);
356
g_debug("Capture Enabled.");
357
append_status(t, _("Capture Enabled.\n"));
363
open_camera (TetherInfo *t, const char *model, const char *port)
365
Camera **camera = &t->camera;
369
GPPortInfoList *portinfolist = NULL;
370
CameraAbilitiesList *abilities = NULL;
372
ret = gp_camera_new (camera);
375
/* First lookup the model / driver */
376
m = gp_abilities_list_lookup_model (abilities, model);
380
ret = gp_abilities_list_get_abilities (abilities, m, &a);
383
ret = gp_camera_set_abilities (*camera, a);
386
/* Then associate the camera with the specified port */
387
p = gp_port_info_list_lookup_path (portinfolist, port);
390
case GP_ERROR_UNKNOWN_PORT:
391
append_status (t, _("The port you specified ('%s') can not be found."), port);
398
ret = gp_port_info_list_get_info (portinfolist, p, &pi);
400
ret = gp_camera_set_port_info (*camera, pi);
407
static void add_tags_to_photo(TetherInfo* t, RS_PHOTO *photo)
409
const gchar* photo_tags = rs_conf_get_string("tether-tags-for-new-images");
414
g_assert(photo != NULL);
415
g_assert(photo->metadata != NULL);
417
RSLibrary *lib = rs_library_get_singleton();
419
rs_library_add_photo_with_metadata(lib, photo->filename, photo->metadata);
421
gchar** split_tags = g_strsplit_set(photo_tags, " .,/;:~^*|&",0);
423
while (split_tags[i] != NULL)
425
gint tag_id = rs_library_add_tag(lib, split_tags[i]);
426
rs_io_idle_add_tag(photo->filename, tag_id, FALSE, -1);
429
rs_io_idle_add_tag(photo->filename, -2, FALSE, -1);
430
g_strfreev(split_tags);
435
add_file_to_store(TetherInfo* t, const char* tmp_name)
437
RSMetadata *metadata;
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, "."));
446
gchar* filename = filename_parse(g_string_free(filename_template, FALSE),tmp_name, 0);
448
GFile* src = g_file_new_for_path(tmp_name);
449
GFile* dst = g_file_new_for_path(filename);
451
gdk_threads_unlock();
452
if (!g_file_move(src, dst, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, NULL))
455
append_status(t, _("Moving file to current directory failed!\n"));
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);
465
/* Make sure we rotate this right */
466
gdk_threads_unlock();
467
metadata = rs_metadata_new_from_file(filename);
468
g_object_unref(metadata);
473
#define RS_NUM_SETTINGS 3
476
transfer_file_captured(TetherInfo* t, CameraFilePath* camera_file_path)
478
CameraFile *canonfile;
480
append_status(t,_("Downloading and adding image.\n"));
482
tmp_name_ptr = g_build_filename(g_get_tmp_dir(), g_strdup_printf("rs-tether-%d.tmp", g_random_int()), NULL);
484
if (NULL == tmp_name_ptr)
487
char *extension = g_strrstr(camera_file_path->name, ".");
488
tmp_name_ptr = g_strconcat(tmp_name_ptr, extension, NULL);
490
fd = open(tmp_name_ptr, O_CREAT | O_WRONLY, 0644);
493
append_status(t,_("Could not open temporary file on disk for writing"));
497
gdk_threads_unlock();
498
retval = gp_file_new_from_fd(&canonfile, fd);
500
retval = gp_camera_file_get(t->camera, camera_file_path->folder, camera_file_path->name, GP_FILE_TYPE_NORMAL, canonfile, t->context);
502
retval = gp_camera_file_delete(t->camera, camera_file_path->folder, camera_file_path->name, t->context);
507
gboolean copy_settings = TRUE;
508
rs_conf_get_boolean_with_default("tether-copy-current-settings", ©_settings, FALSE);
509
RSSettings *settings_buffer[RS_NUM_SETTINGS];
511
if (copy_settings && t->rs->photo)
513
for (i = 0; i < RS_NUM_SETTINGS; i++)
515
settings_buffer[i] = rs_settings_new();
516
rs_settings_copy(t->rs->photo->settings[i], MASK_ALL, settings_buffer[i]);
520
copy_settings = FALSE;
522
gp_file_free(canonfile);
523
gchar *filename = add_file_to_store(t, tmp_name_ptr);
527
gdk_threads_unlock();
528
RS_PHOTO *photo = rs_photo_new();
529
photo->filename = g_strdup(filename);
534
for (i = 0; i < RS_NUM_SETTINGS; i++)
536
rs_settings_copy(settings_buffer[i], MASK_ALL, photo->settings[i]);
537
g_object_unref(settings_buffer[i]);
539
rs_cache_save(photo, MASK_ALL);
543
add_tags_to_photo(t, photo);
544
g_object_unref(photo);
548
gboolean minimize = TRUE;
549
rs_conf_get_boolean_with_default("tether-minimize-window", &minimize, TRUE);
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);
556
if (!rs_store_set_selected_name(t->rs->store, filename, TRUE))
558
append_status(t, _("Could not open image!\n"));
563
/* Minimize window */
565
gtk_window_iconify(GTK_WINDOW(t->window));
567
g_free(tmp_name_ptr);
571
#undef RS_NUM_SETTINGS
574
capture_to_file(TetherInfo* t)
577
CameraFilePath camera_file_path;
579
append_status(t, _("Capturing.\n"));
580
retval = gp_camera_capture(t->camera, GP_CAPTURE_IMAGE, &camera_file_path, t->context);
582
retval = transfer_file_captured(t, &camera_file_path);
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.
593
start_thread_monitor(gpointer _thread_info)
595
TetherInfo *t = (TetherInfo*) _thread_info;
598
while (t->keep_thread_running)
600
Camera *cam = t->camera;
601
CameraEventType type;
602
void * event_data = NULL;
605
t->keep_thread_running = FALSE;
609
retval = gp_camera_wait_for_event(cam, 100, &type, &event_data, t->context);
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;
619
if (type == GP_EVENT_FILE_ADDED)
621
CameraFilePath* camera_file_path = (CameraFilePath*)event_data;
622
retval = transfer_file_captured(t, camera_file_path);
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;
629
append_status(t, _("File Downloaded Succesfully.\n"));
633
append_status(t, _("Camera monitor shutting down.\n"));
635
t->thread_type = ASYNC_THREAD_TYPE_NONE;
640
start_thread_interval(gpointer _thread_info)
642
TetherInfo *t = (TetherInfo*) _thread_info;
645
GTimer* capture_timer = g_timer_new();
646
while (t->keep_thread_running)
648
retval = capture_to_file(t);
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;
654
if (t->keep_thread_running)
656
gdouble interval = 10.0;
657
rs_conf_get_double("tether-interval-interval", &interval);
659
gboolean take_next = g_timer_elapsed(capture_timer, NULL) > interval;
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);
664
append_status(t, _("Waiting for next image.\n"));
666
while (t->keep_thread_running && !take_next)
668
if (g_timer_elapsed(capture_timer, NULL) > interval)
678
g_timer_reset(capture_timer);
680
if (t->keep_thread_running)
684
/* Sleep 10ms, just to let GUI become responsive */
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"));
695
g_timer_destroy(capture_timer);
696
t->thread_type = ASYNC_THREAD_TYPE_NONE;
700
static void closeconnection(TetherInfo *t)
704
append_status(t, _("Disconnecting current camera\n"));
705
gp_camera_exit (t->camera, t->context);
706
gp_camera_free (t->camera);
710
static void initcamera(TetherInfo *t, GtkTreeIter *iter)
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.
719
const char *name, *value;
721
gtk_tree_model_get(GTK_TREE_MODEL(t->camera_store), iter,
723
VALUE_COLUMN, &value, -1);
725
ret = open_camera(t, name, value);
728
append_status(t,_("Camera %s on port %s failed to open\n"), name, value);
732
ret = gp_camera_init (t->camera, t->context);
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);
745
update_example(CAMERA_FILENAME *filename)
749
GtkLabel *example = GTK_LABEL(filename->example_label);
751
parsed = filename_parse(filename->filename, "filename", 0);
752
final = g_strdup_printf("%s.ext", parsed);
754
gtk_label_set_markup(example, final);
760
/* When entering this, we must have gdk locked */
762
shutdown_async_thread(TetherInfo *t)
764
if (t->async_thread_id && t->keep_thread_running)
766
t->keep_thread_running = FALSE;
768
g_thread_join(t->async_thread_id);
770
t->async_thread_id = NULL;
771
append_status(t, _("Shutting down asynchronous thread\n"));
777
refresh_cameralist(GObject *entry, gpointer user_data)
779
TetherInfo *t = (TetherInfo*)user_data;
780
shutdown_async_thread(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);
786
gtk_combo_box_set_active(GTK_COMBO_BOX(t->camera_selector), 0);
788
gtk_combo_box_set_active(GTK_COMBO_BOX(t->camera_selector), -1);
793
connect_camera(GObject *entry, gpointer user_data)
795
TetherInfo *t = (TetherInfo*)user_data;
796
shutdown_async_thread(t);
799
if (gtk_combo_box_get_active_iter(t->camera_selector, &iter))
802
append_status(t, _("No camera selected - Cannot connect!\n"));
806
take_photo(GObject *entry, gpointer user_data)
808
TetherInfo *t = (TetherInfo*)user_data;
811
connect_camera(entry, user_data);
815
if (t->keep_thread_running)
817
append_status(t, _("Shutting down running thread to enable remote capture.\n"));
818
shutdown_async_thread(t);
821
ret_val = capture_to_file(t);
824
append_status(t, _("Recieved error %d, while capturing image.\nError text is: %s\n"), ret_val, gp_result_as_string(ret_val));
830
tags_entry_changed(GtkEntry *entry, gpointer user_data)
832
const gchar* tags = gtk_entry_get_text(GTK_ENTRY(entry));
833
rs_conf_set_string("tether-tags-for-new-images", tags);
837
spin_button_entry_changed(GtkEntry *entry, gpointer user_data)
839
gdouble value = gtk_spin_button_get_value(GTK_SPIN_BUTTON(entry));
840
rs_conf_set_double(user_data, value);
844
filename_entry_changed(GtkEntry *entry, gpointer user_data)
846
CAMERA_FILENAME *filename = (CAMERA_FILENAME *) user_data;
847
filename->filename = gtk_entry_get_text(entry);
848
update_example(filename);
852
start_monitor(GObject *entry, gpointer user_data)
854
TetherInfo *t = (TetherInfo*)user_data;
856
connect_camera(entry, user_data);
860
if ((t->async_thread_id || t->keep_thread_running) && t->thread_type != ASYNC_THREAD_TYPE_MONITOR)
862
append_status(t, _("Shutting down already running thread.\n"));
863
shutdown_async_thread(t);
865
if (!t->async_thread_id || !t->keep_thread_running)
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);
873
append_status(t, _("Monitor Thread already running.\n"));
878
close_button_pressed(GtkEntry *entry, gpointer user_data)
880
TetherInfo *t = (TetherInfo*)user_data;
881
shutdown_async_thread(t);
883
gp_context_unref(t->context);
884
gtk_widget_destroy(t->window);
888
close_main_window(GtkEntry *entry, GdkEvent *event, gpointer user_data)
890
TetherInfo *t = (TetherInfo*)user_data;
891
shutdown_async_thread(t);
894
gp_context_unref(t->context);
895
gtk_widget_destroy(GTK_WIDGET(entry));
899
stop_interval_shooting(GObject *entry, gpointer user_data)
901
TetherInfo *t = (TetherInfo*)user_data;
902
if (t->keep_thread_running && t->thread_type == ASYNC_THREAD_TYPE_INTERVAL)
904
append_status(t, _("Shutting down interval capture thread.\n"));
905
shutdown_async_thread(t);
910
disconnect_camera_action(GObject *entry, gpointer user_data)
912
TetherInfo *t = (TetherInfo*)user_data;
915
append_status(t, _("No camera connected.\n"));
918
shutdown_async_thread(t);
923
start_interval_shooting(GObject *entry, gpointer user_data)
925
TetherInfo *t = (TetherInfo*)user_data;
927
connect_camera(entry, user_data);
930
if (t->keep_thread_running)
931
shutdown_async_thread(t);
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"));
940
t->async_thread_id = g_thread_create(start_thread_interval, t, TRUE, NULL);
944
build_tether_gui(TetherInfo *t)
950
GtkWidget *filename_hbox;
951
GtkWidget *filename_label;
952
GtkWidget *filename_chooser;
953
GtkWidget *filename_entry;
954
GtkWidget *check_button;
956
GtkWidget *example_hbox;
957
GtkWidget *example_label1;
958
GtkWidget *example_label2;
959
CAMERA_FILENAME *filename;
961
GtkWidget *status_window;
962
GtkWidget *status_textview;
963
GtkWidget *tags_entry;
964
GtkWidget *number_spin;
966
/* A box to hold everything */
967
GtkBox *main_box = GTK_BOX(gtk_vbox_new (FALSE, 7));
969
/* A box for main constrols */
970
box = GTK_BOX(gtk_vbox_new (FALSE, 5));
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);
978
h_box = GTK_BOX(gtk_hbox_new (FALSE, 0));
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);
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);
995
gtk_box_pack_start(box, GTK_WIDGET(h_box), FALSE, FALSE, 5);
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);
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);
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);
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);
1019
gtk_box_pack_start(box, GTK_WIDGET(h_box), FALSE, FALSE, 5);
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);
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);
1037
gtk_box_pack_start(GTK_BOX(main_box), gui_box(_("Master Control"), GTK_WIDGET(box), "tether_controls", TRUE), FALSE, FALSE, 0);
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));
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);
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;
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);
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);
1072
tags_entry = gtk_entry_new();
1073
gchar* tags = rs_conf_get_string("tether-tags-for-new-images");
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);
1081
/* Add filename& tags box */
1082
gtk_box_pack_start(GTK_BOX(main_box), gui_box(_("Filename & Tags"), GTK_WIDGET(box), "tether_filename_tags", TRUE), FALSE, FALSE, 0);
1084
/* INTERVAL SHOOTING */
1085
box = GTK_BOX(gtk_vbox_new (FALSE, 2));
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);
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);
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);
1111
box = GTK_BOX(gtk_vbox_new (FALSE, 5));
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);
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);
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);
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);
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);
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));
1147
rs_tethered_shooting_open(RS_BLOB *rs)
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");
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");
1159
g_free(filename_template);
1161
TetherInfo *tether_info = NULL;
1163
if (tether_info == NULL)
1165
tether_info = g_malloc0(sizeof(TetherInfo));
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;
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);
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);
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);
1185
append_status(tether_info, _("Found %d cameras\n"), i);
1187
build_tether_gui(tether_info);
1188
gtk_window_resize(GTK_WINDOW(window), 500, 400);
1189
gtk_widget_show_all(GTK_WIDGET(window));