1 // python-gphoto2 - Python interface to libgphoto2
2 // http://github.com/jim-easterbrook/python-gphoto2
3 // Copyright (C) 2014-20 Jim Easterbrook jim@jim-easterbrook.me.uk
4 //
5 // This program is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (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, see <http://www.gnu.org/licenses/>.
17
18 %module(package="gphoto2") context
19
20 %include "common/preamble.i"
21
22 %rename(Context) _GPContext;
23
24 #ifndef SWIGIMPORTED
25
26 // Make docstring parameter types more Pythonic
27 %typemap(doc) GPContext * "$1_name: gphoto2.$*1_type";
28
29 // gp_camera_autodetect() returns a pointer in an output parameter
30 NEW_ARGOUT(CameraList *, gp_list_new, gp_list_unref)
31
32 // Ignore "backend" functions
33 %ignore gp_context_cancel;
34 %ignore gp_context_error;
35 %ignore gp_context_idle;
36 %ignore gp_context_message;
37 %ignore gp_context_progress_start;
38 %ignore gp_context_progress_stop;
39 %ignore gp_context_progress_update;
40 %ignore gp_context_question;
41 %ignore gp_context_ref;
42 %ignore gp_context_status;
43 %ignore gp_context_unref;
44
45 // Structs to store callback details
46 %ignore CallbackDetails::context;
47 %ignore CallbackDetails::func;
48 %ignore CallbackDetails::data;
49 %ignore CallbackDetails::remove;
50 %ignore del_CallbackDetails;
51
52 %inline %{
53 typedef void (*RemoveFunc) (GPContext *context, void *func, void *data);
54
55 typedef struct CallbackDetails {
56 GPContext *context;
57 PyObject *func_1;
58 PyObject *func_2;
59 PyObject *func_3;
60 PyObject *data;
61 RemoveFunc remove;
62 } CallbackDetails;
63
64 // Function to remove progress callbacks, compatible with RemoveFunc
unset_progress_funcs(GPContext * context,GPContextProgressStartFunc start_func,void * data)65 static void unset_progress_funcs(GPContext *context,
66 GPContextProgressStartFunc start_func,
67 void *data) {
68 gp_context_set_progress_funcs(context, NULL, NULL, NULL, NULL);
69 };
70
71 // Destructor
del_CallbackDetails(struct CallbackDetails * this)72 static int del_CallbackDetails(struct CallbackDetails *this) {
73 if (this->context)
74 this->remove(this->context, NULL, NULL);
75 Py_XDECREF(this->func_1);
76 Py_XDECREF(this->func_2);
77 Py_XDECREF(this->func_3);
78 Py_XDECREF(this->data);
79 free(this);
80 return GP_OK;
81 };
82 %}
83 DEFAULT_DTOR(CallbackDetails, del_CallbackDetails);
84
85 // Define wrapper functions to call Python callbacks from C callbacks
86 %define CB_WRAPPER(rtn_type, cb_name, cb_args, py3_arglist, py2_arglist, function)
87 %{
88 static rtn_type cb_name cb_args {
89 PyGILState_STATE gstate = PyGILState_Ensure();
90 CallbackDetails *this = data;
91 PyObject *result = NULL;
92 PyObject *arglist = NULL;
93 PyObject *self = NULL;
94 %}
95 #if #rtn_type == "int"
96 %{
97 rtn_type c_result = 0;
98 %}
99 #elif #rtn_type == "GPContextFeedback"
100 %{
101 rtn_type c_result = GP_CONTEXT_FEEDBACK_OK;
102 %}
103 #endif
104 %{
105 PyObject *py_context = SWIG_NewPointerObj(
106 SWIG_as_voidptr(context), SWIGTYPE_p__GPContext, 0);
107 #if PY_VERSION_HEX >= 0x03000000
108 arglist = Py_BuildValue py3_arglist;
109 #else
110 arglist = Py_BuildValue py2_arglist;
111 #endif
112 if (arglist == NULL) {
113 PyErr_Print();
114 goto fail;
115 }
116 result = PyObject_CallObject(function, arglist);
117 Py_DECREF(arglist);
118 if (result == NULL) {
119 PyErr_Print();
120 goto fail;
121 }
122 %}
123 #if #rtn_type != "void"
124 %{
125 c_result = PyInt_AsLong(result);
126 %}
127 #endif
128 %{
129 Py_DECREF(result);
130 fail:
131 PyGILState_Release(gstate);
132 %}
133 #if #rtn_type != "void"
134 %{
135 return c_result;
136 %}
137 #endif
138 %{
139 };
140 %}
141 %enddef // CB_WRAPPER
142
143 CB_WRAPPER(void, wrap_idle_func, (GPContext *context, void *data),
144 ("(OO)", py_context, this->data),
145 ("(OO)", py_context, this->data),
146 this->func_1)
147
148 CB_WRAPPER(void, wrap_error_func, (GPContext *context, const char *text, void *data),
149 ("(OyO)", py_context, text, this->data),
150 ("(OsO)", py_context, text, this->data),
151 this->func_1)
152
153 CB_WRAPPER(void, wrap_status_func, (GPContext *context, const char *text, void *data),
154 ("(OyO)", py_context, text, this->data),
155 ("(OsO)", py_context, text, this->data),
156 this->func_1)
157
158 CB_WRAPPER(void, wrap_message_func, (GPContext *context, const char *text, void *data),
159 ("(OyO)", py_context, text, this->data),
160 ("(OsO)", py_context, text, this->data),
161 this->func_1)
162
163 CB_WRAPPER(GPContextFeedback, wrap_question_func,
164 (GPContext *context, const char *text, void *data),
165 ("(OyO)", py_context, text, this->data),
166 ("(OsO)", py_context, text, this->data),
167 this->func_1)
168
169 CB_WRAPPER(GPContextFeedback, wrap_cancel_func, (GPContext *context, void *data),
170 ("(OO)", py_context, this->data),
171 ("(OO)", py_context, this->data),
172 this->func_1)
173
174 CB_WRAPPER(int, py_progress_start,
175 (GPContext *context, float target, const char *text, void *data),
176 ("(OfyO)", py_context, target, text, this->data),
177 ("(OfsO)", py_context, target, text, this->data),
178 this->func_1)
179
180 CB_WRAPPER(void, py_progress_update,
181 (GPContext *context, unsigned int id, float current, void *data),
182 ("(OifO)", py_context, id, current, this->data),
183 ("(OifO)", py_context, id, current, this->data),
184 this->func_2)
185
186 CB_WRAPPER(void, py_progress_stop, (GPContext *context, unsigned int id, void *data),
187 ("(OiO)", py_context, id, this->data),
188 ("(OiO)", py_context, id, this->data),
189 this->func_3)
190
191 // Typemaps for all callback setting functions
192 %typemap(in) void *data {
193 _global_callbacks->data = $input;
194 Py_INCREF(_global_callbacks->data);
195 $1 = _global_callbacks;
196 }
197 %typemap(doc) void *data "$1_name: object"
198
199 %typemap(check) GPContext *context {
200 _global_callbacks->context = $1;
201 }
202
203 // Macro to define typemaps for the six single callback function variants
204 %define SINGLE_CALLBACK_FUNCTION(cb_func_type, remove_func, cb_wrapper)
205
206 %typemap(arginit) cb_func_type (CallbackDetails *_global_callbacks) {
207 _global_callbacks = malloc(sizeof(CallbackDetails));
208 if (!_global_callbacks) {
209 PyErr_SetNone(PyExc_MemoryError);
210 SWIG_fail;
211 }
212 _global_callbacks->context = NULL;
213 _global_callbacks->func_1 = NULL;
214 _global_callbacks->func_2 = NULL;
215 _global_callbacks->func_3 = NULL;
216 _global_callbacks->data = NULL;
217 _global_callbacks->remove = (RemoveFunc) remove_func;
218 }
219 %typemap(freearg) cb_func_type {
220 if (_global_callbacks)
221 del_CallbackDetails(_global_callbacks);
222 }
223 %typemap(in) cb_func_type {
224 if (!PyCallable_Check($input)) {
225 SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname" "', argument " "$argnum" " is not callable");
226 }
227 _global_callbacks->func_1 = $input;
228 Py_INCREF(_global_callbacks->func_1);
229 $1 = (cb_func_type) cb_wrapper;
230 }
231 %typemap(doc) cb_func_type "$1_name: callable function"
232
233 %typemap(argout) cb_func_type {
234 $result = SWIG_Python_AppendOutput($result,
235 SWIG_NewPointerObj(_global_callbacks, SWIGTYPE_p_CallbackDetails, SWIG_POINTER_OWN));
236 _global_callbacks = NULL;
237 }
238
239 %enddef // SINGLE_CALLBACK_FUNCTION
240
241 SINGLE_CALLBACK_FUNCTION(GPContextIdleFunc,
242 gp_context_set_idle_func, wrap_idle_func)
243 SINGLE_CALLBACK_FUNCTION(GPContextErrorFunc,
244 gp_context_set_error_func, wrap_error_func)
245 SINGLE_CALLBACK_FUNCTION(GPContextStatusFunc,
246 gp_context_set_status_func, wrap_status_func)
247 SINGLE_CALLBACK_FUNCTION(GPContextMessageFunc,
248 gp_context_set_message_func, wrap_message_func)
249 SINGLE_CALLBACK_FUNCTION(GPContextQuestionFunc,
250 gp_context_set_question_func, wrap_question_func)
251 SINGLE_CALLBACK_FUNCTION(GPContextCancelFunc,
252 gp_context_set_cancel_func, wrap_cancel_func)
253
254 // Progress callbacks are more complicated
255 // Use macro for first function
256 SINGLE_CALLBACK_FUNCTION(GPContextProgressStartFunc,
257 unset_progress_funcs, py_progress_start)
258
259 // Use typemaps for other two functions
260 %typemap(in) GPContextProgressUpdateFunc {
261 if (!PyCallable_Check($input)) {
262 SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname" "', argument " "$argnum" " is not callable");
263 }
264 _global_callbacks->func_2 = $input;
265 Py_INCREF(_global_callbacks->func_2);
266 $1 = (GPContextProgressUpdateFunc) py_progress_update;
267 }
268 %typemap(doc) GPContextProgressUpdateFunc "$1_name: callable function"
269
270 %typemap(in) GPContextProgressStopFunc {
271 if (!PyCallable_Check($input)) {
272 SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname" "', argument " "$argnum" " is not callable");
273 }
274 _global_callbacks->func_3 = $input;
275 Py_INCREF(_global_callbacks->func_3);
276 $1 = (GPContextProgressStopFunc) py_progress_stop;
277 }
278 %typemap(doc) GPContextProgressStopFunc "$1_name: callable function"
279
280 // Add member methods to _GPContext
281 %exception _GPContext::camera_autodetect {
282 if (PyErr_WarnEx(PyExc_DeprecationWarning,
283 "Camera.autodetect replaces Context().camera_autodetect", 1) < 0) SWIG_fail;
284 $action
285 if (PyErr_Occurred() != NULL) SWIG_fail;
286 }
287 %extend _GPContext {
camera_autodetect(CameraList * list)288 void camera_autodetect(CameraList *list) {
289 int error = gp_camera_autodetect(list, $self);
290 if (error < GP_OK) GPHOTO2_ERROR(error)
291 }
292 };
293 VOID_MEMBER_FUNCTION(_GPContext,
294 set_idle_func, (GPContextIdleFunc func, void *data),
295 gp_context_set_idle_func, ($self, func, data))
296 VOID_MEMBER_FUNCTION(_GPContext,
297 set_error_func, (GPContextErrorFunc func, void *data),
298 gp_context_set_error_func, ($self, func, data))
299 VOID_MEMBER_FUNCTION(_GPContext,
300 set_message_func, (GPContextMessageFunc func, void *data),
301 gp_context_set_message_func, ($self, func, data))
302 VOID_MEMBER_FUNCTION(_GPContext,
303 set_question_func, (GPContextQuestionFunc func, void *data),
304 gp_context_set_question_func, ($self, func, data))
305 VOID_MEMBER_FUNCTION(_GPContext,
306 set_cancel_func, (GPContextCancelFunc func, void *data),
307 gp_context_set_cancel_func, ($self, func, data))
308 VOID_MEMBER_FUNCTION(_GPContext,
309 set_progress_funcs, (GPContextProgressStartFunc start_func,
310 GPContextProgressUpdateFunc update_func,
311 GPContextProgressStopFunc stop_func,
312 void *data),
313 gp_context_set_progress_funcs, ($self, start_func, update_func, stop_func, data))
314 VOID_MEMBER_FUNCTION(_GPContext,
315 set_status_func, (GPContextStatusFunc func, void *data),
316 gp_context_set_status_func, ($self, func, data))
317
318 #endif //ifndef SWIGIMPORTED
319
320 // Add default constructor and destructor
321 struct _GPContext {};
322 %extend _GPContext {
_GPContext()323 _GPContext() {
324 return gp_context_new();
325 }
~_GPContext()326 ~_GPContext() {
327 gp_context_unref($self);
328 }
329 };
330 %ignore _GPContext;
331 %newobject gp_context_new;
332 %delobject gp_context_unref;
333
334 %include "gphoto2/gphoto2-context.h"
335