Skip to content
This repository has been archived by the owner on Jun 28, 2020. It is now read-only.

Commit

Permalink
Added the dispose method to allow multiple connects to a camera
Browse files Browse the repository at this point in the history
  • Loading branch information
Tallak Tveide committed Feb 28, 2010
1 parent 672f75c commit 156078b
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 83 deletions.
151 changes: 69 additions & 82 deletions ext/gphoto2camera.c
Expand Up @@ -144,14 +144,16 @@ void camera_mark(GPhoto2Camera *c) {
}

void camera_free(GPhoto2Camera *c) {
if (!c->disposed) {
gp_result_check(gp_camera_exit(c->camera, c->context));
gp_result_check(gp_widget_free(c->config));
gp_result_check(gp_camera_unref(c->camera));
gp_result_check(gp_camera_free(c->camera));
free(c->virtFolder);
free(c->lastName);
free(c->context);
free(c);
}
free(c);
}

VALUE camera_allocate(VALUE klass) {
Expand All @@ -162,6 +164,7 @@ VALUE camera_allocate(VALUE klass) {
strcpy(c->virtFolder, "/");
c->lastName[0] = '\0';
c->context = gp_context_new();
c->disposed = 0;
gp_result_check(gp_camera_new(&(c->camera)));
gp_result_check(gp_camera_get_config(c->camera, &(c->config), c->context));
gp_result_check(gp_camera_ref(c->camera));
Expand Down Expand Up @@ -224,6 +227,41 @@ VALUE camera_initialize(int argc, VALUE *argv, VALUE self) {
return self;
}


/*
* call-seq:
* dispose => nil
*
* Releases resources aquired by the Camera class so that is will be possible
* to connect to the camera again even before Ruby garbage collection has
* released the Camera from memory
*
* Examples:
*
* c = GPhoto2::Camera.new
* begin
* c.capture
* ensure
* c.dispose # if capture failed, this code may run again in the same process
* end
*
*/
VALUE camera_dispose(VALUE self) {
GPhoto2Camera *c;
Data_Get_Struct(self, GPhoto2Camera, c);
check_disposed(c);
if (!c->disposed) {
gp_result_check(gp_camera_exit(c->camera, c->context));
gp_result_check(gp_widget_free(c->config));
gp_result_check(gp_camera_unref(c->camera));
gp_result_check(gp_camera_free(c->camera));
free(c->virtFolder);
free(c->lastName);
free(c->context);
c->disposed = -1;
}
}

/*
* call-seq:
* GPhoto2::Camera.ports => array
Expand Down Expand Up @@ -309,6 +347,7 @@ VALUE camera_capture(int argc, VALUE *argv, VALUE self) {
CameraFilePath path;

Data_Get_Struct(self, GPhoto2Camera, c);
check_disposed(c);

if (argc == 1) {
camera_config_merge(self, argv[0]);
Expand Down Expand Up @@ -369,6 +408,7 @@ VALUE camera_save(int argc, VALUE *argv, VALUE self) {
VALUE arr, hVal;

Data_Get_Struct(self, GPhoto2Camera, c);
check_disposed(c);

gp_list_new(&list);

Expand Down Expand Up @@ -538,6 +578,7 @@ VALUE camera_delete(int argc, VALUE *argv, VALUE self) {
VALUE arr;

Data_Get_Struct(self, GPhoto2Camera, c);
check_disposed(c);

gp_list_new(&list);

Expand Down Expand Up @@ -645,6 +686,7 @@ VALUE camera_get_config(int argc, VALUE *argv, VALUE self) {
case 1:
Check_Type(argv[0], T_SYMBOL);
Data_Get_Struct(self, GPhoto2Camera, c);
check_disposed(c);

if (strcmp(rb_id2name(rb_to_id(argv[0])), "no_cache") == 0) {
gp_widget_free(c->config);
Expand Down Expand Up @@ -686,6 +728,7 @@ VALUE camera_config_merge(VALUE self, VALUE hash) {
VALUE arr, cfgs, cfg_changed;

Data_Get_Struct(self, GPhoto2Camera, c);
check_disposed(c);

arr = rb_funcall(hash, rb_intern("keys"), 0);
cfgs = rb_iv_get(self, "@configuration");
Expand Down Expand Up @@ -790,6 +833,7 @@ VALUE camera_get_value(int argc, VALUE *argv, VALUE self) {
dir = argv[1];
Check_Type(dir, T_SYMBOL);
Data_Get_Struct(self, GPhoto2Camera, c);
check_disposed(c);

if (strcmp(rb_id2name(rb_to_id(dir)), "no_cache") == 0) {
gp_widget_free(c->config);
Expand Down Expand Up @@ -916,6 +960,7 @@ VALUE camera_set_value(VALUE self, VALUE str, VALUE newVal) {
}

Data_Get_Struct(self, GPhoto2Camera, c);
check_disposed(c);

gp_result_check(gp_widget_get_child_by_name(c->config, name, &(c->childConfig)));
gp_result_check(gp_widget_get_type(c->childConfig, &widgettype));
Expand Down Expand Up @@ -961,9 +1006,10 @@ VALUE camera_set_value(VALUE self, VALUE str, VALUE newVal) {
*
*/
VALUE camera_model_name(VALUE self) {
GPhoto2Camera *c;
Data_Get_Struct(self, GPhoto2Camera, c);
return rb_str_new2((*c).abilities.model);
GPhoto2Camera *c;
Data_Get_Struct(self, GPhoto2Camera, c);
check_disposed(c);
return rb_str_new2((*c).abilities.model);
}

/*
Expand All @@ -974,9 +1020,10 @@ VALUE camera_model_name(VALUE self) {
*
*/
VALUE camera_has_image_capture(VALUE self) {
GPhoto2Camera *c;
Data_Get_Struct(self, GPhoto2Camera, c);
return ((*c).abilities.operations & GP_OPERATION_CAPTURE_IMAGE) ? Qtrue : Qfalse;
GPhoto2Camera *c;
Data_Get_Struct(self, GPhoto2Camera, c);
check_disposed(c);
return ((*c).abilities.operations & GP_OPERATION_CAPTURE_IMAGE) ? Qtrue : Qfalse;
}

/*
Expand All @@ -987,9 +1034,10 @@ VALUE camera_has_image_capture(VALUE self) {
*
*/
VALUE camera_has_preview(VALUE self) {
GPhoto2Camera *c;
Data_Get_Struct(self, GPhoto2Camera, c);
return ((*c).abilities.operations & GP_OPERATION_CAPTURE_PREVIEW) ? Qtrue : Qfalse;
GPhoto2Camera *c;
Data_Get_Struct(self, GPhoto2Camera, c);
check_disposed(c);
return ((*c).abilities.operations & GP_OPERATION_CAPTURE_PREVIEW) ? Qtrue : Qfalse;
}

/*
Expand All @@ -1000,82 +1048,13 @@ VALUE camera_has_preview(VALUE self) {
*
*/
VALUE camera_has_config(VALUE self) {
GPhoto2Camera *c;
Data_Get_Struct(self, GPhoto2Camera, c);
return ((*c).abilities.operations & GP_OPERATION_CONFIG) ? Qtrue : Qfalse;
}


/*
* call-seq:
* abilities => hash
*
* Contents of the returned hash:
* * <b>:model</b> - a string decribing the camera model
* * <b>:status</b> - one of :production, :testing, :experimental or :deprecated
* * <b>:operations</b> - an array containing a combination of :capture_image, :capture_video, :capture_audio, :capture_preview and :config
*
* Returns the camera abilities
*
* Examples:
*
* c = GPhoto2::Camera.new
* # with Canon EOS 40D
* c.abilities #=> {:status=>:production,
* :operations=>[:capture_image, :capture_preview, :config],
* :model=>"Canon EOS 40D (PTP mode)"}
*
*/
VALUE camera_get_abilities(VALUE self) {
GPhoto2Camera *c;
Data_Get_Struct(self, GPhoto2Camera, c);
CameraAbilities a;
if (gp_result_check(gp_camera_get_abilities (c->camera, &a)) >= GP_OK) {
VALUE abilities = rb_hash_new();
/* model */
rb_hash_aset(abilities, rb_new_sym("model"), rb_str_new2(a.model));

/* driver status */
switch (a.status) {
case GP_DRIVER_STATUS_PRODUCTION:
rb_hash_aset(abilities, rb_new_sym("status"), rb_new_sym("production"));
break;
case GP_DRIVER_STATUS_TESTING:
rb_hash_aset(abilities, rb_new_sym("status"), rb_new_sym("testing"));
break;
case GP_DRIVER_STATUS_EXPERIMENTAL:
rb_hash_aset(abilities, rb_new_sym("status"), rb_new_sym("experimental"));
break;
case GP_DRIVER_STATUS_DEPRECATED:
rb_hash_aset(abilities, rb_new_sym("status"), rb_new_sym("deprecated"));
break;
}

/* operations */
VALUE ops = rb_ary_new();
if (a.operations & GP_OPERATION_CAPTURE_IMAGE) {
rb_ary_push(ops, rb_new_sym("capture_image"));
}
if (a.operations & GP_OPERATION_CAPTURE_VIDEO) {
rb_ary_push(ops, rb_new_sym("capture_video"));
}
if (a.operations & GP_OPERATION_CAPTURE_AUDIO) {
rb_ary_push(ops, rb_new_sym("capture_audio"));
}
if (a.operations & GP_OPERATION_CAPTURE_PREVIEW) {
rb_ary_push(ops, rb_new_sym("capture_preview"));
}
if (a.operations & GP_OPERATION_CONFIG) {
rb_ary_push(ops, rb_new_sym("config"));
}
rb_hash_aset(abilities, rb_new_sym("operations"), ops);

return abilities;
} else {
return Qnil;
}
check_disposed(c);
return ((*c).abilities.operations & GP_OPERATION_CONFIG) ? Qtrue : Qfalse;
}


/*
* call-seq:
* folder => string
Expand All @@ -1096,6 +1075,7 @@ VALUE camera_folder(VALUE self) {
GPhoto2Camera *c;

Data_Get_Struct(self, GPhoto2Camera, c);
check_disposed(c);

return rb_str_new2(c->virtFolder);
}
Expand Down Expand Up @@ -1125,6 +1105,7 @@ VALUE camera_subfolders(VALUE self) {
VALUE arr;

Data_Get_Struct(self, GPhoto2Camera, c);
check_disposed(c);

gp_list_new(&list);

Expand Down Expand Up @@ -1178,6 +1159,7 @@ VALUE camera_files(int argc, VALUE *argv, VALUE self) {
}

Data_Get_Struct(self, GPhoto2Camera, c);
check_disposed(c);

gp_list_new(&list);

Expand Down Expand Up @@ -1223,6 +1205,7 @@ VALUE camera_files_count(VALUE self) {
CameraList *list;

Data_Get_Struct(self, GPhoto2Camera, c);
check_disposed(c);

gp_list_new(&list);

Expand Down Expand Up @@ -1258,6 +1241,7 @@ VALUE camera_folder_up(VALUE self) {
GPhoto2Camera *c;

Data_Get_Struct(self, GPhoto2Camera, c);
check_disposed(c);

pch = strrchr(c->virtFolder, '/');
if ((pch - c->virtFolder) == 0) {
Expand Down Expand Up @@ -1298,6 +1282,7 @@ VALUE camera_folder_down(VALUE self, VALUE folder) {
GPhoto2Camera *c;

Data_Get_Struct(self, GPhoto2Camera, c);
check_disposed(c);

gp_list_new(&list);

Expand Down Expand Up @@ -1332,6 +1317,7 @@ VALUE camera_create_folder(VALUE self, VALUE folder) {
GPhoto2Camera *c;

Data_Get_Struct(self, GPhoto2Camera, c);
check_disposed(c);

name = RSTRING_PTR(folder);
gp_result_check(gp_camera_folder_make_dir(c->camera, c->virtFolder, name, c->context));
Expand Down Expand Up @@ -1394,6 +1380,7 @@ VALUE camera_wait(int argc, VALUE *argv, VALUE self) {
}

Data_Get_Struct(self, GPhoto2Camera, c);
check_disposed(c);
ce = (GPhoto2CameraEvent*) ALLOC(GPhoto2CameraEvent);

// RESULT_CHECK_EVENT(gp_filesystem_reset(c->camera->fs), ce);
Expand Down
4 changes: 4 additions & 0 deletions ext/gphoto2camera.h
Expand Up @@ -42,7 +42,11 @@ void camera_mark(GPhoto2Camera *c);
void camera_free(GPhoto2Camera *c);
VALUE camera_allocate(VALUE klass);




VALUE camera_initialize(int argc, VALUE *argv, VALUE self);
VALUE camera_dispose(VALUE self);
VALUE camera_class_ports(VALUE klass);

VALUE camera_capture(int argc, VALUE *argv, VALUE self);
Expand Down
9 changes: 9 additions & 0 deletions ext/gphoto2camera_utilities.c
Expand Up @@ -35,6 +35,15 @@ int gp_result_check(int retval) {
return retval;
}

int check_disposed(GPhoto2Camera* c) {
if ((*c).disposed) {
rb_raise(rb_cGPhoto2Exception, "Camera has been disposed");
return -1;
}
return 0;
}


VALUE getRadio(CameraWidget *cc) {
const char *val;

Expand Down
2 changes: 2 additions & 0 deletions ext/gphoto2camera_utilities.h
Expand Up @@ -50,12 +50,14 @@ typedef struct {
char *lastName;

CameraAbilities abilities;
int disposed;
} GPhoto2Camera;

extern VALUE rb_cGPhoto2Exception;

void rb_raise_gp_result(int retval);
int gp_result_check(int retval);
int check_disposed(GPhoto2Camera* c);

VALUE getRadio(CameraWidget *cc);
VALUE listRadio(CameraWidget *cc);
Expand Down
1 change: 1 addition & 0 deletions ext/gphoto4ruby.c
Expand Up @@ -85,6 +85,7 @@ void Init_gphoto4ruby() {
rb_define_alloc_func(rb_cGPhoto2Camera, camera_allocate);
rb_define_module_function(rb_cGPhoto2Camera, "ports", camera_class_ports, 0); /* in gphoto2camera.c */
rb_define_method(rb_cGPhoto2Camera, "initialize", camera_initialize, -1); /* in gphoto2camera.c */
rb_define_method(rb_cGPhoto2Camera, "dispose", camera_dispose, 0); /* in gphoto2camera.c */
rb_define_method(rb_cGPhoto2Camera, "config", camera_get_config, -1); /* in gphoto2camera.c */
rb_define_method(rb_cGPhoto2Camera, "config_merge", camera_config_merge, 1); /* in gphoto2camera.c */
rb_define_method(rb_cGPhoto2Camera, "[]", camera_get_value, -1); /* in gphoto2camera.c */
Expand Down
2 changes: 1 addition & 1 deletion gphoto4ruby.gemspec
Expand Up @@ -9,7 +9,7 @@ Gem::Specification.new do |s|

s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["neq4 company", "Sergey Kruk"]
s.date = %q{2010-02-26}
s.date = %q{2010-02-28}
s.description = %q{GPhoto4Ruby is used to control PPTP cameras (the ones that can be controlled with gphoto2) using power of ruby.}
s.email = %q{sergey.kruk@gmail.com}
s.extensions = ["ext/extconf.rb"]
Expand Down

0 comments on commit 156078b

Please sign in to comment.