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