Mercurial > projects > pk-update-icon
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 } |