1 /** \file gphoto2-context.c
2 *
3 * \author Copyright 2001 Lutz Mueller <lutz@users.sourceforge.net>
4 *
5 * \par License
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * \par
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * \par
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301 USA
22 */
23
24 #define _DEFAULT_SOURCE
25
26 #include "config.h"
27 #include <gphoto2/gphoto2-context.h>
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include <gphoto2/gphoto2-port-log.h>
34
35 /**
36 * \internal
37 **/
38 struct _GPContext
39 {
40 GPContextIdleFunc idle_func;
41 void *idle_func_data;
42
43 GPContextProgressStartFunc progress_start_func;
44 GPContextProgressUpdateFunc progress_update_func;
45 GPContextProgressStopFunc progress_stop_func;
46 void *progress_func_data;
47
48 GPContextErrorFunc error_func;
49 void *error_func_data;
50
51 GPContextQuestionFunc question_func;
52 void *question_func_data;
53
54 GPContextCancelFunc cancel_func;
55 void *cancel_func_data;
56
57 GPContextStatusFunc status_func;
58 void *status_func_data;
59
60 GPContextMessageFunc message_func;
61 void *message_func_data;
62
63 unsigned int ref_count;
64 };
65
66 /**
67 * \brief Creates a new context.
68 *
69 * To be used by the frontend.
70 *
71 * \return a GPContext.
72 **/
73 GPContext *
gp_context_new(void)74 gp_context_new (void)
75 {
76 GPContext *context;
77
78 context = calloc (1, sizeof (GPContext));
79 if (!context)
80 return (NULL);
81
82 context->ref_count = 1;
83
84 return (context);
85 }
86
87 /**
88 * Increments the reference count of the context.
89 *
90 * \param context The context to bump the reference
91 **/
92 void
gp_context_ref(GPContext * context)93 gp_context_ref (GPContext *context)
94 {
95 if (!context)
96 return;
97
98 context->ref_count++;
99 }
100
101 static void
gp_context_free(GPContext * context)102 gp_context_free (GPContext *context)
103 {
104 free (context);
105 }
106
107 /**
108 * \brief Decrements reference count of a context.
109 *
110 * Decrement the reference count of a context and free if it goes to 0.
111 *
112 * \param context The context to drop the reference count.
113 **/
114 void
gp_context_unref(GPContext * context)115 gp_context_unref (GPContext *context)
116 {
117 if (!context)
118 return;
119
120 context->ref_count--;
121 if (!context->ref_count)
122 gp_context_free (context);
123 }
124
125 /**
126 * \brief Notify frontend of a brief idle time.
127 *
128 * Tells the frontend that it can do other processing at this moment, like refresh
129 * the UI. Backends should call this function every time when an
130 * interruption of the transfer is possible.
131 *
132 * \param context a GPContext
133 **/
134 void
gp_context_idle(GPContext * context)135 gp_context_idle (GPContext *context)
136 {
137 if (!context)
138 return;
139
140 if (context->idle_func)
141 context->idle_func (context, context->idle_func_data);
142 }
143
144 /**
145 * \brief Start progress tracking.
146 *
147 * This function starts up a new progress tracking for a specified context.
148 * Several nested progress reports can happen at once, depending on the backend.
149 *
150 * \param context The context in which to start the progress.
151 * \param target The 100% value.
152 * \param format A sprintf style string to print out, including the following variable arguments.
153 */
154 unsigned int
gp_context_progress_start(GPContext * context,float target,const char * format,...)155 gp_context_progress_start (GPContext *context, float target,
156 const char *format, ...)
157 {
158 va_list args;
159 char *str;
160 unsigned int id;
161
162 if (!context)
163 return (0);
164 if (!context->progress_start_func)
165 return (0);
166
167 va_start (args, format);
168 str = gpi_vsnprintf(format, args);
169 va_end (args);
170
171 if (!str)
172 return 0;
173
174 id = context->progress_start_func (context, target, str,
175 context->progress_func_data);
176 free (str);
177 return (id);
178 }
179
180 void
gp_context_progress_update(GPContext * context,unsigned int id,float current)181 gp_context_progress_update (GPContext *context, unsigned int id, float current)
182 {
183 if (!context)
184 return;
185
186 if (context->progress_update_func)
187 context->progress_update_func (context, id, current,
188 context->progress_func_data);
189 }
190
191 void
gp_context_progress_stop(GPContext * context,unsigned int id)192 gp_context_progress_stop (GPContext *context, unsigned int id)
193 {
194 if (!context)
195 return;
196
197 if (context->progress_stop_func)
198 context->progress_stop_func (context, id,
199 context->progress_func_data);
200 }
201
202 void
gp_context_error(GPContext * context,const char * format,...)203 gp_context_error (GPContext *context, const char *format, ...)
204 {
205 va_list args;
206 char *str;
207
208 va_start (args, format);
209 str = gpi_vsnprintf(format, args);
210 va_end (args);
211
212 if (!str)
213 return;
214
215 /* Log the error message */
216 gp_log( GP_LOG_ERROR, __func__, "%s", str);
217
218 if (context && context->error_func)
219 context->error_func (context, str, context->error_func_data);
220 free (str);
221 }
222
223 void
gp_context_status(GPContext * context,const char * format,...)224 gp_context_status (GPContext *context, const char *format, ...)
225 {
226 va_list args;
227 char *str;
228
229 va_start (args, format);
230 str = gpi_vsnprintf(format, args);
231 va_end (args);
232
233 if (!str)
234 return;
235
236 /* Log the status message */
237 GP_LOG_D ("%s", str);
238
239 if (context && context->status_func)
240 context->status_func (context, str, context->status_func_data);
241 free (str);
242 }
243
244 /**
245 * \brief Print a message to the context
246 *
247 * This sends a message to the passed context, to be printed by
248 * it in some kind of way, but do no other action.
249 *
250 * To be used by camera drivers.
251 *
252 * \param context A GPContext
253 * \param format A sprintf style format string
254 * \param ... variable argument list depending on format string
255 */
256 void
gp_context_message(GPContext * context,const char * format,...)257 gp_context_message (GPContext *context, const char *format, ...)
258 {
259 va_list args;
260 char *str;
261
262 va_start (args, format);
263 str = gpi_vsnprintf(format, args);
264 va_end (args);
265
266 if (!str)
267 return;
268
269 /* Log the message */
270 GP_LOG_D ("%s", str);
271
272 if (context && context->message_func)
273 context->message_func (context, str, context->message_func_data);
274 free (str);
275 }
276
277 /**
278 * \brief Ask frontend user a question
279 *
280 * Asks the user a question that he must answer either with "Ok" or "Cancel".
281 *
282 * To be used by a camera driver. (So far no camera driver is using it,
283 * but this might change later.)
284 *
285 * \param context a GPContext
286 * \param format a sprintf format string
287 * \param ... variable arguments for format string
288 * \return The user's answer in form of a GPContextFeedback.
289 **/
290 GPContextFeedback
gp_context_question(GPContext * context,const char * format,...)291 gp_context_question (GPContext *context, const char *format, ...)
292 {
293 GPContextFeedback feedback;
294 va_list args;
295 char *str;
296
297 va_start (args, format);
298 str = gpi_vsnprintf(format, args);
299 va_end (args);
300
301 if (!str)
302 return GP_CONTEXT_FEEDBACK_OK;
303
304 feedback = GP_CONTEXT_FEEDBACK_OK;
305 if (context && context->question_func)
306 feedback = context->question_func (context, str, context->question_func_data);
307
308 free (str);
309
310 return feedback;
311 }
312
313 /**
314 * gp_context_cancel:
315 * @context: a #GPContext
316 *
317 * Gives the frontend the possibility to cancel the current operation that is
318 * executed in this @context.
319 *
320 * Return value: a #GPContextFeedback.
321 **/
322 GPContextFeedback
gp_context_cancel(GPContext * context)323 gp_context_cancel (GPContext *context)
324 {
325 if (!context)
326 return (GP_CONTEXT_FEEDBACK_OK);
327
328 if (context->cancel_func)
329 return (context->cancel_func (context,
330 context->cancel_func_data));
331 else
332 return (GP_CONTEXT_FEEDBACK_OK);
333 }
334
335 void
gp_context_set_idle_func(GPContext * context,GPContextIdleFunc func,void * data)336 gp_context_set_idle_func (GPContext *context, GPContextIdleFunc func,
337 void *data)
338 {
339 if (!context)
340 return;
341
342 context->idle_func = func;
343 context->idle_func_data = data;
344 }
345
346 void
gp_context_set_progress_funcs(GPContext * context,GPContextProgressStartFunc start_func,GPContextProgressUpdateFunc update_func,GPContextProgressStopFunc stop_func,void * data)347 gp_context_set_progress_funcs (GPContext *context,
348 GPContextProgressStartFunc start_func,
349 GPContextProgressUpdateFunc update_func,
350 GPContextProgressStopFunc stop_func,
351 void *data)
352 {
353 if (!context)
354 return;
355
356 context->progress_start_func = start_func;
357 context->progress_update_func = update_func;
358 context->progress_stop_func = stop_func;
359 context->progress_func_data = data;
360 }
361
362 void
gp_context_set_error_func(GPContext * context,GPContextErrorFunc func,void * data)363 gp_context_set_error_func (GPContext *context, GPContextErrorFunc func,
364 void *data)
365 {
366 if (!context)
367 return;
368
369 context->error_func = func;
370 context->error_func_data = data;
371 }
372
373 void
gp_context_set_question_func(GPContext * context,GPContextQuestionFunc func,void * data)374 gp_context_set_question_func (GPContext *context, GPContextQuestionFunc func,
375 void *data)
376 {
377 if (!context)
378 return;
379
380 context->question_func = func;
381 context->question_func_data = data;
382 }
383
384 void
gp_context_set_status_func(GPContext * context,GPContextStatusFunc func,void * data)385 gp_context_set_status_func (GPContext *context, GPContextStatusFunc func,
386 void *data)
387 {
388 if (!context)
389 return;
390
391 context->status_func = func;
392 context->status_func_data = data;
393 }
394
395 void
gp_context_set_cancel_func(GPContext * context,GPContextCancelFunc func,void * data)396 gp_context_set_cancel_func (GPContext *context, GPContextCancelFunc func,
397 void *data)
398 {
399 if (!context)
400 return;
401
402 context->cancel_func = func;
403 context->cancel_func_data = data;
404 }
405
406 void
gp_context_set_message_func(GPContext * context,GPContextMessageFunc func,void * data)407 gp_context_set_message_func (GPContext *context, GPContextMessageFunc func,
408 void *data)
409 {
410 if (!context)
411 return;
412
413 context->message_func = func;
414 context->message_func_data = data;
415 }
416