comparison pkui-backend.c @ 14:64f05992d8ec

GObject-based rewrite use asynchronous packagekit-glib API use persistent menu widget and notification object update existing notification when new updates become available, close it when no updates are available show status icon when updates are available, hide it when no updates are available hide icon when gpk-update-viewer is executed, check for updates when gpk-update-viewer exits introduce a startup delay before the first check for updates is made add context menu item to manually trigger a check for updates remove context menu item for quitting pk-update-icon
author Guido Berhoerster <guido@berhoerster.name>
date Thu, 20 Oct 2011 08:19:22 +0200
parents
children a8d8fba520ec
comparison
equal deleted inserted replaced
13:dca97330d81e 14:64f05992d8ec
1 /*
2 * (C) 2011 Guido Berhoerster <gber@opensuse.org>
3 *
4 * Licensed under the GNU General Public License Version 2
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include <packagekit-glib2/packagekit.h>
22 #include "pkui-backend.h"
23
24 G_DEFINE_TYPE(PkuiBackend, pkui_backend, G_TYPE_OBJECT)
25
26 #define PKUI_BACKEND_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), \
27 PKUI_TYPE_BACKEND, PkuiBackendPrivate))
28
29 struct _PkuiBackendPrivate
30 {
31 PkuiBackend *backend;
32 PkClient *pk_client;
33 guint periodic_check_id;
34 guint updates_normal;
35 guint updates_important;
36 guint previous_updates_normal;
37 guint previous_updates_important;
38 guint startup_delay;
39 guint check_interval;
40 gint64 last_check;
41 gboolean inhibit_check;
42 };
43
44 enum
45 {
46 PROP_0,
47
48 PROP_UPDATES_NORMAL,
49 PROP_UPDATES_IMPORTANT,
50 PROP_STARTUP_DELAY,
51 PROP_CHECK_INTERVAL,
52 PROP_INHIBIT_CHECK
53 };
54
55 enum
56 {
57 STATE_CHANGED_SIGNAL,
58
59 LAST_SIGNAL
60 };
61
62 static guint pkui_backend_signals[LAST_SIGNAL] = { 0, };
63
64 static gboolean periodic_check(gpointer data);
65
66 static void
67 pkui_backend_set_property(GObject *object, guint property_id,
68 const GValue *value, GParamSpec *pspec)
69 {
70 PkuiBackend *self = PKUI_BACKEND(object);
71 gboolean inhibit_check;
72 gint64 time_to_check;
73
74 switch (property_id) {
75 case PROP_STARTUP_DELAY:
76 self->priv->startup_delay = g_value_get_uint(value);
77
78 g_source_remove(self->priv->periodic_check_id);
79 self->priv->periodic_check_id =
80 g_timeout_add_seconds(self->priv->startup_delay,
81 (GSourceFunc)periodic_check, self);
82 break;
83 case PROP_CHECK_INTERVAL:
84 self->priv->check_interval = g_value_get_uint(value);
85
86 /*
87 * reschedule only if the first run has been completed and
88 * checks are currently not inibited, otherwise the new
89 * interval will be picked up anyway
90 */
91 if (!self->priv->inhibit_check && self->priv->last_check > 0) {
92 time_to_check = g_get_real_time() -
93 self->priv->last_check;
94 if (time_to_check <= 0)
95 pkui_backend_check_now(self);
96 else {
97 g_source_remove(self->priv->periodic_check_id);
98 self->priv->periodic_check_id =
99 g_timeout_add_seconds(time_to_check,
100 periodic_check, self);
101 }
102 }
103 break;
104 case PROP_INHIBIT_CHECK:
105 inhibit_check = g_value_get_boolean(value);
106
107 /*
108 * when changing self->priv->inhibit_check from FALSE to TRUE
109 * and the first run has been completed remove the periodic
110 * check, when changing from TRUE to FALSE either trigger a run
111 * immediately when more time than self->priv->check_interval
112 * has passed or just reschedule the next check
113 */
114 if (!self->priv->inhibit_check && inhibit_check &&
115 self->priv->periodic_check_id != 0) {
116 g_source_remove(self->priv->periodic_check_id);
117 self->priv->periodic_check_id = 0;
118 } else if (self->priv->inhibit_check && !inhibit_check) {
119 self->priv->periodic_check_id =
120 g_timeout_add_seconds(self->priv->check_interval,
121 (GSourceFunc)periodic_check, self);
122 }
123 self->priv->inhibit_check = inhibit_check;
124 break;
125 default:
126 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
127 break;
128 }
129 }
130
131 static void
132 pkui_backend_get_property(GObject *object, guint property_id, GValue *value,
133 GParamSpec *pspec)
134 {
135 PkuiBackend *self = PKUI_BACKEND(object);
136
137 switch (property_id) {
138 case PROP_UPDATES_NORMAL:
139 g_value_set_uint(value, self->priv->updates_normal);
140 break;
141 case PROP_UPDATES_IMPORTANT:
142 g_value_set_uint(value, self->priv->updates_important);
143 break;
144 case PROP_STARTUP_DELAY:
145 g_value_set_uint(value, self->priv->startup_delay);
146 break;
147 case PROP_CHECK_INTERVAL:
148 g_value_set_uint(value, self->priv->check_interval);
149 break;
150 case PROP_INHIBIT_CHECK:
151 g_value_set_boolean(value, self->priv->inhibit_check);
152 break;
153 default:
154 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
155 break;
156 }
157 }
158
159 static void
160 pkui_backend_finalize(GObject *gobject)
161 {
162 PkuiBackend *self = PKUI_BACKEND(gobject);
163
164 if (self->priv->pk_client != NULL)
165 g_object_unref(self->priv->pk_client);
166
167 G_OBJECT_CLASS(pkui_backend_parent_class)->finalize(gobject);
168 }
169
170 static void
171 pkui_backend_class_init(PkuiBackendClass *klass)
172 {
173 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
174 GParamSpec *pspec;
175
176 gobject_class->set_property = pkui_backend_set_property;
177 gobject_class->get_property = pkui_backend_get_property;
178 gobject_class->finalize = pkui_backend_finalize;
179
180 pspec = g_param_spec_uint("updates-normal", "Normal updates",
181 "Number of normal package updates", 0, G_MAXUINT, 0,
182 G_PARAM_READABLE);
183 g_object_class_install_property(gobject_class, PROP_UPDATES_NORMAL,
184 pspec);
185
186 pspec = g_param_spec_uint("updates-important", "Important updates",
187 "Number of important package updates", 0, G_MAXUINT, 0,
188 G_PARAM_READABLE);
189 g_object_class_install_property(gobject_class, PROP_UPDATES_IMPORTANT,
190 pspec);
191
192 pspec = g_param_spec_uint("startup-delay", "Startup delay",
193 "Initial delay in second before the first check for new package "
194 "updates", 0, G_MAXUINT, 60,
195 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
196 g_object_class_install_property(gobject_class, PROP_STARTUP_DELAY,
197 pspec);
198
199 pspec = g_param_spec_uint("check-interval", "Check interval",
200 "Interval in seconds for checking for new package updates", 1,
201 G_MAXUINT, 3600, G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
202 g_object_class_install_property(gobject_class, PROP_CHECK_INTERVAL,
203 pspec);
204
205 pspec = g_param_spec_boolean("inhibit-check", "Inhibit check",
206 "Whether to inhibit checks for new package updates", FALSE,
207 G_PARAM_READWRITE);
208 g_object_class_install_property(gobject_class, PROP_INHIBIT_CHECK,
209 pspec);
210
211 pkui_backend_signals[STATE_CHANGED_SIGNAL] =
212 g_signal_newv("state-changed", G_TYPE_FROM_CLASS(gobject_class),
213 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, NULL,
214 NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL);
215
216 g_type_class_add_private(klass, sizeof (PkuiBackendPrivate));
217 }
218
219 static void
220 pkui_backend_init(PkuiBackend *self)
221 {
222 self->priv = PKUI_BACKEND_GET_PRIVATE(self);
223
224 self->priv->pk_client = pk_client_new();
225 self->priv->updates_normal = 0;
226 self->priv->updates_important = 0;
227 self->priv->periodic_check_id =
228 g_timeout_add_seconds(self->priv->startup_delay,
229 (GSourceFunc)periodic_check, self);
230 self->priv->last_check = 0;
231 }
232
233 static gboolean
234 periodic_check(gpointer data)
235 {
236 PkuiBackend *self = PKUI_BACKEND(data);
237
238 pkui_backend_check_now(self);
239
240 /* rescheduling happens after results are available */
241 return (FALSE);
242 }
243
244 static void
245 process_pk_package_info(PkPackage *pkg, gpointer *user_data)
246 {
247 PkuiBackend *self = PKUI_BACKEND(user_data);
248 PkInfoEnum type_info = pk_package_get_info(pkg);
249
250 switch (type_info) {
251 case PK_INFO_ENUM_LOW:
252 case PK_INFO_ENUM_ENHANCEMENT:
253 case PK_INFO_ENUM_NORMAL:
254 self->priv->updates_normal++;
255 break;
256 case PK_INFO_ENUM_BUGFIX:
257 case PK_INFO_ENUM_IMPORTANT:
258 case PK_INFO_ENUM_SECURITY:
259 self->priv->updates_important++;
260 break;
261 default:
262 break;
263 }
264 }
265
266 static void
267 get_updates_finished(GObject *object, GAsyncResult *res, gpointer user_data)
268 {
269 PkClient *client = PK_CLIENT(object);
270 PkuiBackend *self = PKUI_BACKEND(user_data);
271 PkResults *results = NULL;
272 GError *error = NULL;
273 GPtrArray *list = NULL;
274
275 g_debug("PackageKit finished checking for updates");
276
277 results = pk_client_generic_finish(PK_CLIENT(client), res, &error);
278 if (results == NULL) {
279 g_warning("error: %s\n", error->message);
280 g_error_free(error);
281 goto out;
282 }
283
284 list = pk_results_get_package_array(results);
285 if (list == NULL)
286 goto out;
287 self->priv->previous_updates_normal = self->priv->updates_normal;
288 self->priv->previous_updates_important = self->priv->updates_important;
289 self->priv->updates_normal = 0;
290 self->priv->updates_important = 0;
291 g_ptr_array_foreach(list, (GFunc)process_pk_package_info, self);
292
293 if (self->priv->updates_normal != self->priv->previous_updates_normal ||
294 self->priv->updates_important !=
295 self->priv->previous_updates_important) {
296 g_debug("normal updates: %d, important updates: %d",
297 self->priv->updates_normal, self->priv->updates_important);
298 g_debug("emit state-changed");
299
300 g_signal_emit(self, pkui_backend_signals[STATE_CHANGED_SIGNAL],
301 0);
302 }
303
304 out:
305 if (results != NULL)
306 g_object_unref(results);
307 if (list != NULL)
308 g_ptr_array_unref(list);
309
310 self->priv->last_check = g_get_real_time();
311
312 if (!self->priv->inhibit_check) {
313 if (self->priv->periodic_check_id != 0)
314 g_source_remove(self->priv->periodic_check_id);
315 self->priv->periodic_check_id =
316 g_timeout_add_seconds(self->priv->check_interval,
317 (GSourceFunc)periodic_check, self);
318 }
319 }
320
321 PkuiBackend *
322 pkui_backend_new(guint startup_delay, guint check_interval)
323 {
324 g_return_val_if_fail(check_interval > 0, NULL);
325
326 return (g_object_new(PKUI_TYPE_BACKEND, "startup-delay", startup_delay,
327 "check-interval", check_interval, NULL));
328 }
329
330 guint
331 pkui_backend_get_updates_normal(PkuiBackend *self)
332 {
333 guint updates_normal;
334
335 g_return_val_if_fail(PKUI_IS_BACKEND(self), 0);
336
337 g_object_get(G_OBJECT(self), "updates-normal", &updates_normal, NULL);
338
339 return (updates_normal);
340 }
341
342 guint
343 pkui_backend_get_updates_important(PkuiBackend *self)
344 {
345 guint updates_important;
346
347 g_return_val_if_fail(PKUI_IS_BACKEND(self), 0);
348
349 g_object_get(G_OBJECT(self), "updates-important", &updates_important,
350 NULL);
351
352 return (updates_important);
353 }
354
355 void
356 pkui_backend_set_inhibit_check(PkuiBackend *self, gboolean inhibit_check)
357 {
358 g_return_if_fail(PKUI_IS_BACKEND(self));
359
360 g_object_set(G_OBJECT(self), "inhibit-check", inhibit_check, NULL);
361 }
362
363 gboolean
364 pkui_backend_get_inhibit_check(PkuiBackend *self)
365 {
366 gboolean inhibit_check;
367
368 g_return_val_if_fail(PKUI_IS_BACKEND(self), FALSE);
369
370 g_object_get(G_OBJECT(self), "inhibit-check", &inhibit_check, NULL);
371
372 return (inhibit_check);
373 }
374
375 guint
376 pkui_backend_get_startup_interval(PkuiBackend *self)
377 {
378 guint startup_interval;
379
380 g_return_val_if_fail(PKUI_IS_BACKEND(self), 0);
381
382 g_object_get(G_OBJECT(self), "startup-interval", &startup_interval,
383 NULL);
384
385 return (startup_interval);
386 }
387
388 void
389 pkui_backend_set_check_interval(PkuiBackend *self, guint check_interval)
390 {
391 g_return_if_fail(PKUI_IS_BACKEND(self));
392
393 g_object_set(G_OBJECT(self), "check-interval", check_interval, NULL);
394 }
395
396 guint
397 pkui_backend_get_check_interval(PkuiBackend *self)
398 {
399 guint check_interval;
400
401 g_return_val_if_fail(PKUI_IS_BACKEND(self), 0);
402
403 g_object_get(G_OBJECT(self), "check-interval", &check_interval, NULL);
404
405 return (check_interval);
406 }
407
408 void
409 pkui_backend_check_now(PkuiBackend *self)
410 {
411 g_return_if_fail(PKUI_IS_BACKEND(self));
412
413 g_debug("querying PackageKit for updates");
414
415 pk_client_get_updates_async(self->priv->pk_client,
416 pk_bitfield_value(PK_FILTER_ENUM_NONE), NULL, NULL, NULL,
417 get_updates_finished, self);
418 }