17
17
with this program. If not, see <http://www.gnu.org/licenses/>.
21
// Please pull in packagekit's client lib
22
// using apt-get install --no-install-recommends libpackagekit-glib2-dev
23
// make sure you don't install package-kit
24
#define I_KNOW_THE_PACKAGEKIT_GLIB2_API_IS_SUBJECT_TO_CHANGE
21
26
#include <glib/gi18n.h>
27
#include <packagekit-glib2/packagekit.h>
22
28
#include "apt-watcher.h"
23
#include "apt-transaction.h"
29
#include "dbus-shared-names.h"
25
31
static guint watcher_id;
29
35
GObject parent_instance;
31
GCancellable * proxy_cancel;
33
36
SessionDbus* session_dbus_interface;
34
37
DbusmenuMenuitem* apt_item;
35
38
AptState current_state;
36
AptTransaction* current_transaction;
39
GCancellable * proxy_cancel;
40
apt_watcher_on_name_appeared (GDBusConnection *connection,
42
const gchar *name_owner,
45
apt_watcher_on_name_vanished (GDBusConnection *connection,
48
static void fetch_proxy_cb (GObject * object,
52
static void apt_watcher_upgrade_system_cb (GObject * obj,
57
static void apt_watcher_show_apt_dialog (DbusmenuMenuitem* mi,
61
static void apt_watcher_signal_cb (GDBusProxy* proxy,
66
static void apt_watcher_manage_transactions (AptWatcher* self,
67
gchar* transaction_id);
68
static gboolean apt_watcher_query_reboot_status (gpointer self);
69
static void apt_watcher_transaction_state_simulation_update_cb (AptTransaction* trans,
72
static void apt_watcher_transaction_state_real_update_cb (AptTransaction* trans,
75
static gboolean apt_watcher_start_apt_interaction (gpointer data);
77
43
G_DEFINE_TYPE (AptWatcher, apt_watcher, G_TYPE_OBJECT);
80
apt_watcher_init (AptWatcher *self)
82
self->current_state = UP_TO_DATE;
83
self->proxy_cancel = g_cancellable_new();
85
self->reboot_query = 0;
86
self->current_transaction = NULL;
87
g_timeout_add_seconds (60,
88
apt_watcher_start_apt_interaction,
93
apt_watcher_start_apt_interaction (gpointer data)
95
g_return_val_if_fail (APT_IS_WATCHER (data), FALSE);
96
AptWatcher* self = APT_WATCHER (data);
97
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
98
G_DBUS_PROXY_FLAGS_NONE,
110
apt_watcher_finalize (GObject *object)
112
g_bus_unwatch_name (watcher_id);
113
AptWatcher* self = APT_WATCHER (object);
115
if (self->proxy != NULL)
116
g_object_unref (self->proxy);
118
G_OBJECT_CLASS (apt_watcher_parent_class)->finalize (object);
122
apt_watcher_class_init (AptWatcherClass *klass)
124
GObjectClass* object_class = G_OBJECT_CLASS (klass);
125
object_class->finalize = apt_watcher_finalize;
47
get_updates_complete (GObject *source_object,
51
g_return_if_fail (APT_IS_WATCHER (user_data));
52
AptWatcher* self = APT_WATCHER (user_data);
56
results = pk_client_generic_finish (PK_CLIENT(source_object), res, &error);
59
g_warning ("Unable to query for updates - error - %s", error->message);
64
packages = pk_results_get_package_array (results);
66
const gchar* disposition;
67
disposition = dbusmenu_menuitem_property_get (self->apt_item,
68
DBUSMENU_MENUITEM_PROP_DISPOSITION);
70
do_update = g_strcmp0 (disposition, DBUSMENU_MENUITEM_DISPOSITION_ALERT) != 0;
72
if (packages->len > 0){
73
g_print ("Apparently we have updates available - change dbmitem %i", do_update);
75
dbusmenu_menuitem_property_set (self->apt_item,
76
DBUSMENU_MENUITEM_PROP_LABEL,
77
_("Updates Available…"));
80
g_print ("No updates available - change dbmitem - %i", do_update);
82
dbusmenu_menuitem_property_set (self->apt_item,
83
DBUSMENU_MENUITEM_PROP_LABEL,
84
_("Software Up to Date"));
86
g_ptr_array_unref (packages);
87
g_object_unref (results);
88
g_object_unref (source_object);
92
apt_watcher_check_for_updates (AptWatcher* self)
95
client = pk_client_new ();
97
pk_client_get_updates_async (client,
100
(GAsyncReadyCallback)get_updates_complete,
104
static void apt_watcher_signal_cb ( GDBusProxy* proxy,
107
GVariant* parameters,
110
g_return_if_fail (APT_IS_WATCHER (user_data));
111
AptWatcher* self = APT_WATCHER (user_data);
113
g_debug ("apt-watcher-signal cb signal name - %s", signal_name);
114
if (g_strcmp0(signal_name, "UpdatesChanged") == 0){
115
g_debug ("updates changed signal received");
116
apt_watcher_check_for_updates (self);
118
else if (g_strcmp0(signal_name, "RestartScheduled") == 0) {
119
g_debug ("RestartScheduled signal received");
120
dbusmenu_menuitem_property_set (self->apt_item,
121
DBUSMENU_MENUITEM_PROP_LABEL,
122
_("Restart to Complete Updates…"));
123
dbusmenu_menuitem_property_set (self->apt_item,
124
DBUSMENU_MENUITEM_PROP_DISPOSITION,
125
DBUSMENU_MENUITEM_DISPOSITION_ALERT);
130
apt_watcher_on_name_appeared (GDBusConnection *connection,
132
const gchar *name_owner,
135
g_return_if_fail (APT_IS_WATCHER (user_data));
136
// AptWatcher* watcher = APT_WATCHER (user_data);
138
g_print ("Name %s on %s is owned by %s\n",
146
apt_watcher_on_name_vanished (GDBusConnection *connection,
150
g_debug ("Name %s does not exist or has just vanished",
152
g_return_if_fail (APT_IS_WATCHER (user_data));
129
156
fetch_proxy_cb (GObject * object, GAsyncResult * res, gpointer user_data)
131
GError * error = NULL;
133
AptWatcher* self = APT_WATCHER(user_data);
134
g_return_if_fail(self != NULL);
136
GDBusProxy * proxy = g_dbus_proxy_new_for_bus_finish(res, &error);
138
if (self->proxy_cancel != NULL) {
139
g_object_unref(self->proxy_cancel);
140
self->proxy_cancel = NULL;
144
g_warning("Could not grab DBus proxy for %s: %s",
158
GError * error = NULL;
160
AptWatcher* self = APT_WATCHER(user_data);
161
g_return_if_fail(self != NULL);
163
GDBusProxy * proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
165
if (self->proxy_cancel != NULL) {
166
g_object_unref (self->proxy_cancel);
167
self->proxy_cancel = NULL;
171
g_warning("Could not grab DBus proxy for %s: %s",
145
172
"org.debian.apt", error->message);
151
178
// Set up the watch.
152
179
watcher_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM,
180
"org.freedesktop.PackageKit",
154
181
G_BUS_NAME_WATCHER_FLAGS_NONE,
155
182
apt_watcher_on_name_appeared,
156
183
apt_watcher_on_name_vanished,
160
g_signal_connect (self->proxy,
186
g_signal_connect (self->proxy,
162
188
G_CALLBACK(apt_watcher_signal_cb),
167
apt_watcher_on_name_appeared (GDBusConnection *connection,
169
const gchar *name_owner,
172
g_return_if_fail (APT_IS_WATCHER (user_data));
173
AptWatcher* watcher = APT_WATCHER (user_data);
175
g_print ("Name %s on %s is owned by %s\n",
180
g_dbus_proxy_call (watcher->proxy,
182
g_variant_new("(b)", TRUE),
183
G_DBUS_CALL_FLAGS_NONE,
186
apt_watcher_upgrade_system_cb,
192
apt_watcher_on_name_vanished (GDBusConnection *connection,
196
g_debug ("Name %s does not exist or has just vanished",
198
g_return_if_fail (APT_IS_WATCHER (user_data));
202
apt_watcher_upgrade_system_cb (GObject * obj,
206
g_return_if_fail (APT_IS_WATCHER (user_data));
207
AptWatcher* self = APT_WATCHER (user_data);
209
GError * error = NULL;
212
result = g_dbus_proxy_call_finish(self->proxy, res, &error);
215
g_warning ("unable to complete the UpgradeSystem apt call");
216
g_error_free (error);
220
gchar* transaction_id = NULL;
221
g_variant_get (result, "(s)", &transaction_id);
223
if (transaction_id == NULL){
224
g_warning ("apt_watcher_upgrade_system_cb - transaction id is null");
228
apt_watcher_manage_transactions (self, transaction_id);
193
apt_watcher_start_apt_interaction (gpointer data)
195
g_return_val_if_fail (APT_IS_WATCHER (data), FALSE);
196
AptWatcher* self = APT_WATCHER (data);
197
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
198
G_DBUS_PROXY_FLAGS_NONE,
200
"org.freedesktop.PackageKit",
201
"/org/freedesktop/PackageKit",
202
"org.freedesktop.PackageKit",
206
apt_watcher_check_for_updates (self);
233
212
apt_watcher_show_apt_dialog (DbusmenuMenuitem * mi,
264
apt_watcher_transaction_state_real_update_cb (AptTransaction* trans,
268
g_debug ("apt-watcher -transaction update %i", update);
269
g_return_if_fail (APT_IS_WATCHER (user_data));
270
AptWatcher* self = APT_WATCHER (user_data);
272
AptState state = (AptState)update;
273
if (self->current_state != RESTART_NEEDED)
275
if (state == UP_TO_DATE){
276
dbusmenu_menuitem_property_set (self->apt_item,
277
DBUSMENU_MENUITEM_PROP_LABEL,
278
_("Software Up to Date"));
279
self->current_state = state;
281
else if (state == UPDATES_AVAILABLE){
282
dbusmenu_menuitem_property_set (self->apt_item,
283
DBUSMENU_MENUITEM_PROP_LABEL,
284
_("Updates Available…"));
285
self->current_state = state;
287
else if (state == UPGRADE_IN_PROGRESS){
288
dbusmenu_menuitem_property_set (self->apt_item,
289
DBUSMENU_MENUITEM_PROP_LABEL,
290
_("Updates Installing…"));
291
self->current_state = state;
293
else if (state == FINISHED){
294
gboolean query_again = FALSE;
296
// Only query if the previous state was an upgrade.
297
if (self->current_state != UPGRADE_IN_PROGRESS){
301
if (self->reboot_query != 0){
302
g_source_remove (self->reboot_query);
303
self->reboot_query = 0;
305
self->reboot_query = g_timeout_add_seconds (1,
306
apt_watcher_query_reboot_status,
309
self->current_state = state;
311
g_object_unref (G_OBJECT(self->current_transaction));
312
self->current_transaction = NULL;
314
// It is impossible to determine from a 'real' transaction whether
315
// updates are available therefore it is necessary to check again via a
316
// simulation whether there are updates available.
318
g_dbus_proxy_call (self->proxy,
320
g_variant_new("(b)", TRUE),
321
G_DBUS_CALL_FLAGS_NONE,
324
apt_watcher_upgrade_system_cb,
333
apt_watcher_transaction_state_simulation_update_cb (AptTransaction* trans,
337
g_debug ("apt-watcher -transaction update %i", update);
338
g_return_if_fail (APT_IS_WATCHER (user_data));
339
AptWatcher* self = APT_WATCHER (user_data);
341
AptState state = (AptState)update;
342
if (self->current_state != RESTART_NEEDED)
344
if (state == UP_TO_DATE){
345
dbusmenu_menuitem_property_set (self->apt_item,
346
DBUSMENU_MENUITEM_PROP_LABEL,
347
_("Software Up to Date"));
348
if (self->reboot_query != 0){
349
g_source_remove (self->reboot_query);
350
self->reboot_query = 0;
352
self->reboot_query = g_timeout_add_seconds (1,
353
apt_watcher_query_reboot_status,
356
else if (state == UPDATES_AVAILABLE){
357
dbusmenu_menuitem_property_set (self->apt_item,
358
DBUSMENU_MENUITEM_PROP_LABEL,
359
_("Updates Available…"));
361
else if (state == UPGRADE_IN_PROGRESS){
362
dbusmenu_menuitem_property_set (self->apt_item,
363
DBUSMENU_MENUITEM_PROP_LABEL,
364
_("Updates Installing…"));
366
self->current_state = state;
368
if (self->current_state != UPGRADE_IN_PROGRESS){
369
g_object_unref (G_OBJECT(self->current_transaction));
370
self->current_transaction = NULL;
375
apt_watcher_manage_transactions (AptWatcher* self, gchar* transaction_id)
377
if (self->current_transaction == NULL){
378
self->current_transaction = apt_transaction_new (transaction_id, SIMULATION);
379
g_signal_connect (G_OBJECT(self->current_transaction),
381
G_CALLBACK(apt_watcher_transaction_state_simulation_update_cb), self);
386
apt_watcher_query_reboot_status (gpointer data)
388
g_return_val_if_fail (APT_IS_WATCHER (data), FALSE);
389
AptWatcher* self = APT_WATCHER (data);
391
GVariant* reboot_result = g_dbus_proxy_get_cached_property (self->proxy,
393
gboolean reboot = FALSE;
394
g_variant_get (reboot_result, "b", &reboot);
395
g_debug ("apt_watcher_query_reboot_status: reboot prop = %i", reboot);
396
if (reboot == FALSE){
397
dbusmenu_menuitem_property_set (self->apt_item,
398
DBUSMENU_MENUITEM_PROP_LABEL,
399
_("Software Up to Date"));
400
dbusmenu_menuitem_property_set (self->apt_item,
401
DBUSMENU_MENUITEM_PROP_DISPOSITION,
402
DBUSMENU_MENUITEM_DISPOSITION_NORMAL);
406
dbusmenu_menuitem_property_set (self->apt_item,
407
DBUSMENU_MENUITEM_PROP_LABEL,
408
_("Restart to Complete Updates…"));
409
dbusmenu_menuitem_property_set (self->apt_item,
410
DBUSMENU_MENUITEM_PROP_DISPOSITION,
411
DBUSMENU_MENUITEM_DISPOSITION_ALERT);
412
session_dbus_restart_required (self->session_dbus_interface);
413
self->current_state = RESTART_NEEDED;
415
self->reboot_query = 0;
419
static void apt_watcher_signal_cb ( GDBusProxy* proxy,
422
GVariant* parameters,
425
g_return_if_fail (APT_IS_WATCHER (user_data));
426
AptWatcher* self = APT_WATCHER (user_data);
428
g_variant_ref_sink (parameters);
429
GVariant *value = g_variant_get_child_value (parameters, 0);
431
if (g_strcmp0(signal_name, "ActiveTransactionsChanged") == 0){
432
gchar* current = NULL;
433
g_debug ("ActiveTransactionsChanged");
435
g_variant_get(value, "s", ¤t);
437
if (g_str_has_prefix (current, "/org/debian/apt/transaction/") == TRUE){
438
g_debug ("ActiveTransactionsChanged - current is %s", current);
440
// Cancel all existing operations.
441
if (self->reboot_query != 0){
442
g_source_remove (self->reboot_query);
443
self->reboot_query = 0;
446
if (self->current_transaction != NULL)
448
g_object_unref (G_OBJECT(self->current_transaction));
449
self->current_transaction = NULL;
452
self->current_transaction = apt_transaction_new (current, REAL);
453
g_signal_connect (G_OBJECT(self->current_transaction),
455
G_CALLBACK(apt_watcher_transaction_state_real_update_cb), self);
458
else if (g_strcmp0(signal_name, "PropertyChanged") == 0)
460
gchar* prop_name= NULL;
461
GVariant* value = NULL;
462
g_variant_get (parameters, "(sv)", &prop_name, &value);
463
g_debug ("transaction prop update - prop = %s", prop_name);
465
if (g_strcmp0 (prop_name, "RebootRequired") == 0){
466
gboolean reboot_required = FALSE;
467
g_variant_get (value, "(b)", &reboot_required);
468
if (reboot_required){
469
dbusmenu_menuitem_property_set (self->apt_item,
470
DBUSMENU_MENUITEM_PROP_LABEL,
471
_("Restart to Complete Updates…"));
472
dbusmenu_menuitem_property_set (self->apt_item,
473
DBUSMENU_MENUITEM_PROP_DISPOSITION,
474
DBUSMENU_MENUITEM_DISPOSITION_ALERT);
475
self->current_state = RESTART_NEEDED;
480
g_variant_unref (value);
481
g_variant_unref (parameters);
243
apt_watcher_init (AptWatcher *self)
245
self->current_state = UP_TO_DATE;
246
g_timeout_add_seconds (60,
247
apt_watcher_start_apt_interaction,
252
apt_watcher_finalize (GObject *object)
254
g_bus_unwatch_name (watcher_id);
255
AptWatcher* self = APT_WATCHER (object);
257
if (self->proxy != NULL)
258
g_object_unref (self->proxy);
260
G_OBJECT_CLASS (apt_watcher_parent_class)->finalize (object);
264
apt_watcher_class_init (AptWatcherClass *klass)
266
GObjectClass* object_class = G_OBJECT_CLASS (klass);
267
object_class->finalize = apt_watcher_finalize;
484
270
AptWatcher* apt_watcher_new (SessionDbus* session_dbus,