1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /*
4 * GThumb
5 *
6 * Copyright (C) 2009 Free Software Foundation, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include <config.h>
23 #include <glib.h>
24 #include "glib-utils.h"
25 #include "gth-marshal.h"
26 #include "gth-task.h"
27
28
29 /* Properties */
30 enum {
31 PROP_0,
32 PROP_DESCRIPTION
33 };
34
35
36 /* Signals */
37 enum {
38 COMPLETED,
39 PROGRESS,
40 DIALOG,
41 LAST_SIGNAL
42 };
43
44 struct _GthTaskPrivate {
45 char *description;
46 gboolean running;
47 GCancellable *cancellable;
48 gulong cancellable_cancelled;
49 };
50
51
52 static guint gth_task_signals[LAST_SIGNAL] = { 0 };
53
54
55
G_DEFINE_TYPE_WITH_CODE(GthTask,gth_task,G_TYPE_OBJECT,G_ADD_PRIVATE (GthTask))56 G_DEFINE_TYPE_WITH_CODE (GthTask,
57 gth_task,
58 G_TYPE_OBJECT,
59 G_ADD_PRIVATE (GthTask))
60
61
62 GQuark
63 gth_task_error_quark (void)
64 {
65 return g_quark_from_static_string ("gth-task-error-quark");
66 }
67
68
69 static void
gth_task_finalize(GObject * object)70 gth_task_finalize (GObject *object)
71 {
72 GthTask *task;
73
74 task = GTH_TASK (object);
75
76 if (task->priv->cancellable != NULL) {
77 g_cancellable_disconnect (task->priv->cancellable, task->priv->cancellable_cancelled);
78 g_object_unref (task->priv->cancellable);
79 }
80
81 g_free (task->priv->description);
82
83 G_OBJECT_CLASS (gth_task_parent_class)->finalize (object);
84 }
85
86
87 static void
base_exec(GthTask * task)88 base_exec (GthTask *task)
89 {
90 /* void */
91 }
92
93
94 static void
base_cancelled(GthTask * task)95 base_cancelled (GthTask *task)
96 {
97 /* void */
98 }
99
100
101 static void
gth_task_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)102 gth_task_set_property (GObject *object,
103 guint property_id,
104 const GValue *value,
105 GParamSpec *pspec)
106 {
107 GthTask *self;
108
109 self = GTH_TASK (object);
110
111 switch (property_id) {
112 case PROP_DESCRIPTION:
113 g_free (self->priv->description);
114 self->priv->description = g_strdup (g_value_get_string (value));
115 break;
116 default:
117 break;
118 }
119 }
120
121
122 static void
gth_task_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)123 gth_task_get_property (GObject *object,
124 guint property_id,
125 GValue *value,
126 GParamSpec *pspec)
127 {
128 GthTask *self;
129
130 self = GTH_TASK (object);
131
132 switch (property_id) {
133 case PROP_DESCRIPTION:
134 g_value_set_string (value, self->priv->description);
135 break;
136 default:
137 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
138 break;
139 }
140 }
141
142
143 static void
gth_task_class_init(GthTaskClass * class)144 gth_task_class_init (GthTaskClass *class)
145 {
146 GObjectClass *object_class;
147
148 object_class = (GObjectClass*) class;
149 object_class->set_property = gth_task_set_property;
150 object_class->get_property = gth_task_get_property;
151 object_class->finalize = gth_task_finalize;
152
153 class->exec = base_exec;
154 class->cancelled = base_cancelled;
155
156 /* properties */
157
158 g_object_class_install_property (object_class,
159 PROP_DESCRIPTION,
160 g_param_spec_string ("description",
161 "Description",
162 "The task description to be displayed in the progress dialog",
163 NULL,
164 G_PARAM_READWRITE));
165
166 /* signals */
167
168 gth_task_signals[COMPLETED] =
169 g_signal_new ("completed",
170 G_TYPE_FROM_CLASS (class),
171 G_SIGNAL_RUN_LAST,
172 G_STRUCT_OFFSET (GthTaskClass, completed),
173 NULL, NULL,
174 g_cclosure_marshal_VOID__BOXED,
175 G_TYPE_NONE,
176 1,
177 G_TYPE_ERROR);
178
179 gth_task_signals[PROGRESS] =
180 g_signal_new ("progress",
181 G_TYPE_FROM_CLASS (class),
182 G_SIGNAL_RUN_LAST,
183 G_STRUCT_OFFSET (GthTaskClass, progress),
184 NULL, NULL,
185 gth_marshal_VOID__STRING_STRING_BOOLEAN_DOUBLE,
186 G_TYPE_NONE,
187 4,
188 G_TYPE_STRING,
189 G_TYPE_STRING,
190 G_TYPE_BOOLEAN,
191 G_TYPE_DOUBLE);
192
193 gth_task_signals[DIALOG] =
194 g_signal_new ("dialog",
195 G_TYPE_FROM_CLASS (class),
196 G_SIGNAL_RUN_LAST,
197 G_STRUCT_OFFSET (GthTaskClass, dialog),
198 NULL, NULL,
199 gth_marshal_VOID__BOOLEAN_POINTER,
200 G_TYPE_NONE,
201 2,
202 G_TYPE_BOOLEAN,
203 G_TYPE_POINTER);
204 }
205
206
207 static void
gth_task_init(GthTask * self)208 gth_task_init (GthTask *self)
209 {
210 self->priv = gth_task_get_instance_private (self);
211 self->priv->running = FALSE;
212 self->priv->cancellable = NULL;
213 self->priv->cancellable_cancelled = 0;
214 self->priv->description = NULL;
215 }
216
217
218 void
gth_task_exec(GthTask * task,GCancellable * cancellable)219 gth_task_exec (GthTask *task,
220 GCancellable *cancellable)
221 {
222 if (task->priv->running)
223 return;
224
225 gth_task_set_cancellable (task, cancellable);
226
227 if (task->priv->description != NULL)
228 gth_task_progress (task, task->priv->description, NULL, TRUE, 0.0);
229
230 task->priv->running = TRUE;
231 GTH_TASK_GET_CLASS (task)->exec (task);
232 }
233
234
235 gboolean
gth_task_is_running(GthTask * task)236 gth_task_is_running (GthTask *task)
237 {
238 return task->priv->running;
239 }
240
241
242 static void
cancellable_cancelled_cb(GCancellable * cancellable,gpointer user_data)243 cancellable_cancelled_cb (GCancellable *cancellable,
244 gpointer user_data)
245 {
246 GthTask *task = user_data;
247
248 GTH_TASK_GET_CLASS (task)->cancelled (task);
249 }
250
251
252 void
gth_task_cancel(GthTask * task)253 gth_task_cancel (GthTask *task)
254 {
255 if (task->priv->cancellable != NULL)
256 g_cancellable_cancel (task->priv->cancellable);
257 else
258 cancellable_cancelled_cb (NULL, task);
259 }
260
261
262 void
gth_task_set_cancellable(GthTask * task,GCancellable * cancellable)263 gth_task_set_cancellable (GthTask *task,
264 GCancellable *cancellable)
265 {
266 if (task->priv->running)
267 return;
268
269 if (task->priv->cancellable != NULL) {
270 g_cancellable_disconnect (task->priv->cancellable, task->priv->cancellable_cancelled);
271 g_object_unref (task->priv->cancellable);
272 }
273
274 if (cancellable != NULL)
275 task->priv->cancellable = _g_object_ref (cancellable);
276 else
277 task->priv->cancellable = g_cancellable_new ();
278 task->priv->cancellable_cancelled = g_cancellable_connect (task->priv->cancellable,
279 G_CALLBACK (cancellable_cancelled_cb),
280 task,
281 NULL);
282 }
283
284
285 GCancellable *
gth_task_get_cancellable(GthTask * task)286 gth_task_get_cancellable (GthTask *task)
287 {
288 return task->priv->cancellable;
289 }
290
291
292 void
gth_task_completed(GthTask * task,GError * error)293 gth_task_completed (GthTask *task,
294 GError *error)
295 {
296 task->priv->running = FALSE;
297 g_signal_emit (task, gth_task_signals[COMPLETED], 0, error);
298 }
299
300
301 void
gth_task_dialog(GthTask * task,gboolean opened,GtkWidget * dialog)302 gth_task_dialog (GthTask *task,
303 gboolean opened,
304 GtkWidget *dialog)
305 {
306 g_signal_emit (task, gth_task_signals[DIALOG], 0, opened, dialog);
307 }
308
309
310 void
gth_task_progress(GthTask * task,const char * description,const char * details,gboolean pulse,double fraction)311 gth_task_progress (GthTask *task,
312 const char *description,
313 const char *details,
314 gboolean pulse,
315 double fraction)
316 {
317 g_signal_emit (task, gth_task_signals[PROGRESS], 0, description, details, pulse, fraction);
318 }
319