~ubuntu-core-dev/update-notifier/ubuntu

« back to all changes in this revision

Viewing changes to src/upgrade-notifier.c

  • Committer: mvo
  • Date: 2005-01-15 00:23:58 UTC
  • Revision ID: gustavo@niemeyer.net-20050115002358-469848491f936cd5
* big rename: upgrade-notifier -> update-notifier

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* upgrade-notifier.c
2
 
 * Copyright (C) 2004 Lukas Lipka <lukas@pmad.net>
3
 
 *           (C) 2004 Michael Vogt <mvo@debian.org>
4
 
 *           (C) Canonical
5
 
 *           (C) 2004 Michiel Sikkes <michiel@eyesopened.nl>
6
 
 *
7
 
 * This library is free software; you can redistribute it and/or
8
 
 * modify it under the terms of the GNU Lesser General Public
9
 
 * License as published by the Free Software Foundation; either
10
 
 * version 2 of the License, or (at your option) any later version.
11
 
 *
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
 
 * You should have received a copy of the GNU Lesser General Public
18
 
 * License along with this library; if not, write to the
19
 
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20
 
 * Boston, MA 02111-1307, USA.
21
 
 */
22
 
 
23
 
#ifdef HAVE_CONFIG_H
24
 
#include "config.h"
25
 
#endif
26
 
 
27
 
#define DBUS_API_SUBJECT_TO_CHANGE 1
28
 
#include <dbus/dbus.h>
29
 
#include <dbus/dbus-glib.h>
30
 
//#define DBUS_HELPER PACKAGE_LIB_DIR"/upgrade-notifier/dbus-helper"
31
 
 
32
 
 
33
 
#include <signal.h>
34
 
#include <gnome.h>
35
 
#include <gtk/gtk.h>
36
 
#include <glade/glade.h>
37
 
 
38
 
 
39
 
#include "upgrade-notifier.h"
40
 
#include "eggtrayicon.h"
41
 
#include "hal.h"
42
 
 
43
 
#define ICON_FILE PACKAGE_DATA_DIR"/pixmaps/upgrade-notifier.png"
44
 
#define UPGRADE_CHECKER PACKAGE_LIB_DIR"/upgrade-notifier/apt-check"
45
 
 
46
 
 
47
 
char* actions[][2] = {
48
 
   { "/usr/bin/update-manager", N_("Show updates") },
49
 
   { "/usr/sbin/synaptic --upgrade-mode --non-interactive --hide-main-window", N_("Install all updates") },
50
 
   { "/usr/sbin/synaptic", N_("Package Manager") },
51
 
   { "/usr/sbin/synaptic --update-at-startup --non-interactive --hide-main-window", N_("Update package list now") },
52
 
   { NULL, NULL }
53
 
};
54
 
 
55
 
#define GCONF_KEY_DEFAULT_ACTION "/apps/upgrade-notifer/default_action"
56
 
#define TIMEOUT_FAM 1000*60*5 /* 5 minutes */
57
 
 
58
 
static LibHalContext *hal_ctx;
59
 
 
60
 
void
61
 
invoke_with_gksu(gchar *cmd, gchar *descr)
62
 
{
63
 
        gchar *full_descr = NULL;
64
 
        if(descr != NULL)
65
 
           full_descr = g_strdup_printf(_("Please enter your password to run:\n %s"), descr);
66
 
 
67
 
        //g_print("invoke_update_manager ()\n");
68
 
        gchar *argv[6];
69
 
        argv[0] = "/usr/bin/gksudo";
70
 
        argv[1] = "--message";
71
 
        argv[2] = full_descr;
72
 
        argv[3] = "--";
73
 
        argv[4] = cmd;
74
 
        argv[5] = NULL;
75
 
 
76
 
        g_spawn_async (NULL, argv, NULL, 0, NULL, NULL, NULL, NULL);
77
 
        g_free(full_descr);
78
 
}
79
 
 
80
 
gboolean
81
 
button_release_cb (GtkWidget *widget, 
82
 
                   GdkEventButton *event, 
83
 
                   UpgradeNotifier *un)
84
 
{
85
 
        int index;
86
 
        if (event->button == 1 && event->type == GDK_BUTTON_RELEASE) {
87
 
                index = gconf_client_get_int(un->gconf, GCONF_KEY_DEFAULT_ACTION, NULL);
88
 
                //g_print("%s %s\n",actions[index][0],actions[index][1]);
89
 
                invoke_with_gksu (actions[index][0], actions[index][1]);
90
 
        }
91
 
        return TRUE;
92
 
}
93
 
 
94
 
gboolean
95
 
button_press_cb (GtkWidget *widget,
96
 
                 GdkEventButton *event,
97
 
                 UpgradeNotifier *un)
98
 
{
99
 
        if (event->button == 3) {
100
 
                gtk_menu_popup (GTK_MENU (un->menu), NULL, NULL, NULL, NULL,
101
 
                                event->button, event->time);
102
 
        }
103
 
        return TRUE;
104
 
}
105
 
 
106
 
void
107
 
trayicon_update_tooltip (UpgradeNotifier *un)
108
 
{
109
 
        //g_print("update_tooltip: %x \n", un);
110
 
        gchar *updates;
111
 
        gchar *explanation;
112
 
 
113
 
        updates = g_strdup_printf(_("There are %i updates available!"), 
114
 
                                  un->num_upgrades);
115
 
 
116
 
        explanation = g_strdup(_("Press this icon to show the updates."));
117
 
 
118
 
        gtk_tooltips_set_tip(GTK_TOOLTIPS(un->tooltip), 
119
 
                             GTK_WIDGET (un->eventbox), 
120
 
                             updates, explanation);
121
 
 
122
 
        g_free (updates);
123
 
        g_free (explanation);
124
 
}
125
 
 
126
 
 
127
 
void 
128
 
cb_action(GObject *self, void *user_data)
129
 
{
130
 
        UpgradeNotifier *un = user_data;
131
 
        
132
 
        int i = g_object_get_data(G_OBJECT(self), "action");
133
 
        invoke_with_gksu (actions[i][0], actions[i][1]);
134
 
}
135
 
 
136
 
void cb_preferences(GObject *self, void *user_data)
137
 
{
138
 
   int i;
139
 
   //g_print("Trying to open: %s\n",GLADEDIR"/preferences.glade");
140
 
   UpgradeNotifier *un = user_data;
141
 
 
142
 
   GladeXML *xml = glade_xml_new(GLADEDIR"/preferences.glade",
143
 
                                 "preferences", NULL);
144
 
   GtkWidget *prefs = glade_xml_get_widget(xml, "preferences");
145
 
   GtkWidget *combo = glade_xml_get_widget(xml, "combobox_default");
146
 
 
147
 
   for(i=0;actions[i][0]!=NULL;i++) {
148
 
      gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _(actions[i][1]));
149
 
   }
150
 
   int default_action = gconf_client_get_int(un->gconf, 
151
 
                                             GCONF_KEY_DEFAULT_ACTION, NULL);
152
 
   gtk_combo_box_set_active(GTK_COMBO_BOX(combo), default_action);
153
 
 
154
 
   int res = gtk_dialog_run(GTK_DIALOG(prefs));
155
 
   if(res == GTK_RESPONSE_CLOSE) {
156
 
      int index = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
157
 
      gconf_client_set_int(un->gconf, GCONF_KEY_DEFAULT_ACTION, index, NULL);
158
 
   }
159
 
   gtk_widget_destroy(prefs);
160
 
}
161
 
 
162
 
void
163
 
trayicon_create_menu (UpgradeNotifier *un)
164
 
{
165
 
        GtkWidget *menuitem;
166
 
        GtkAccelGroup *accelgroup;
167
 
        int i;
168
 
 
169
 
        un->menu = gtk_menu_new ();
170
 
 
171
 
        for(i=0;actions[i][0]!=NULL;i++) {
172
 
           menuitem = gtk_menu_item_new_with_label (_(actions[i][1]));
173
 
           gtk_menu_shell_append (GTK_MENU_SHELL (un->menu), menuitem);
174
 
           g_object_set_data(G_OBJECT(menuitem), "action", i);
175
 
           g_signal_connect(G_OBJECT(menuitem), "activate", cb_action, un);
176
 
        }
177
 
 
178
 
        menuitem = gtk_separator_menu_item_new();
179
 
        gtk_menu_shell_append (GTK_MENU_SHELL (un->menu), menuitem);
180
 
 
181
 
        menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_PREFERENCES, accelgroup);
182
 
        gtk_menu_shell_append (GTK_MENU_SHELL (un->menu), menuitem);
183
 
        g_signal_connect(G_OBJECT(menuitem), "activate", cb_preferences, un);
184
 
 
185
 
        gtk_widget_show_all (un->menu);
186
 
}
187
 
 
188
 
void 
189
 
trayicon_load (UpgradeNotifier *un)
190
 
{
191
 
        GdkPixbuf *pixbuf;
192
 
 
193
 
        pixbuf = gtk_image_get_pixbuf (GTK_IMAGE (un->icon));
194
 
        
195
 
        if (pixbuf)
196
 
                g_object_unref (G_OBJECT (pixbuf));
197
 
 
198
 
        pixbuf = gdk_pixbuf_new_from_file (ICON_FILE, NULL);
199
 
 
200
 
        gtk_image_set_from_pixbuf (GTK_IMAGE (un->icon), pixbuf);
201
 
}
202
 
 
203
 
gboolean
204
 
trayicon_create (UpgradeNotifier *un)
205
 
{
206
 
        //g_print("trayicon_create()\n");
207
 
        un->tooltip = gtk_tooltips_new ();
208
 
        //g_object_ref(un->tooltip);
209
 
        un->tray_icon = egg_tray_icon_new ("apt upgrade-notifier");
210
 
        un->eventbox = gtk_event_box_new ();
211
 
        un->icon = gtk_image_new ();
212
 
        un->gconf = gconf_client_get_default();
213
 
 
214
 
        trayicon_load (un);
215
 
 
216
 
        gtk_container_add (GTK_CONTAINER (un->eventbox), un->icon);
217
 
        gtk_container_add (GTK_CONTAINER (un->tray_icon), un->eventbox);
218
 
 
219
 
        g_signal_connect (G_OBJECT(un->tray_icon),
220
 
                          "button-release-event",
221
 
                          G_CALLBACK (button_release_cb),
222
 
                          un);
223
 
 
224
 
        g_signal_connect (G_OBJECT(un->tray_icon),
225
 
                          "button-press-event",
226
 
                          G_CALLBACK (button_press_cb),
227
 
                          un);
228
 
 
229
 
        gtk_widget_show_all (GTK_WIDGET (un->tray_icon));
230
 
 
231
 
        /* Initial tooltip update */
232
 
        trayicon_update_tooltip (un);
233
 
 
234
 
        /* Menu initialization */
235
 
        trayicon_create_menu (un);
236
 
 
237
 
        return TRUE;
238
 
}
239
 
 
240
 
/* 
241
 
 the following files change:
242
 
 on "install":
243
 
  - /var/lib/dpkg/lock
244
 
  - /var/lib/dpkg/*
245
 
  - /var/lib/upgrade-notifier/dpkg-run-stamp
246
 
 on "update":
247
 
  - /var/lib/apt/lists/lock
248
 
  - /var/lib/apt/lists/*
249
 
  - /var/lib/dpkg/lock
250
 
*/
251
 
gboolean 
252
 
fam_check(UpgradeNotifier *un)
253
 
{
254
 
   FAMEvent fe;
255
 
   gboolean need_update_check = FALSE;
256
 
   while(FAMPending(&un->fc)) {
257
 
      if(FAMNextEvent(&un->fc, &fe) < 0) {
258
 
         g_critical("FAMNextEvent() failed");
259
 
         break;
260
 
      }
261
 
      //g_print("FAMPending() %i %s\n",fe.code,fe.filename);
262
 
#if 0
263
 
      /* apt-get update */
264
 
      if(strstr(fe.filename,"/var/lib/apt/lists") )
265
 
         if(fe.code == FAMChanged || fe.code == FAMDeleted) 
266
 
            need_update_check = TRUE;
267
 
 
268
 
      /* apt run */
269
 
      if(strstr(fe.filename,"/var/lib/upgrade-notifier/dpkg-run-stamp"))
270
 
         if(fe.code == FAMChanged) 
271
 
            need_update_check = TRUE;
272
 
#endif
273
 
      if(fe.code == FAMChanged || fe.code == FAMDeleted) 
274
 
         need_update_check = TRUE;
275
 
   }
276
 
 
277
 
   if(need_update_check)
278
 
      update_check(un);
279
 
 
280
 
   return TRUE;
281
 
}
282
 
 
283
 
 
284
 
gboolean
285
 
update_check (UpgradeNotifier *un)
286
 
{
287
 
        //g_print("upgrade_check(): %x \n", un);
288
 
        FILE *f = popen(UPGRADE_CHECKER, "r");
289
 
        char s[400];
290
 
 
291
 
        un->num_upgrades = 0;
292
 
 
293
 
        /* Check the number of upgrades trough the helper script */
294
 
        while (fgets (s, 400, f) != NULL) {
295
 
                un->num_upgrades++;
296
 
        }
297
 
        pclose (f);
298
 
 
299
 
        if (un->num_upgrades == 0) {
300
 
                /* We don't have any updates. */
301
 
                if (un->is_displayed) {
302
 
                        /* We're still displayed, shoot ourselves */
303
 
                        gtk_widget_destroy (GTK_WIDGET (un->tray_icon));
304
 
                        un->is_displayed = FALSE;
305
 
                }
306
 
        } else {
307
 
                /* There are updates */
308
 
                if (un->is_displayed) {
309
 
                        /* We're already displayed, update tooltip */
310
 
                        trayicon_update_tooltip (un);
311
 
                } else {
312
 
                        /* We're not already displayed, display ourselves */
313
 
                        if (trayicon_create (un))
314
 
                                un->is_displayed = TRUE;
315
 
                }
316
 
        }
317
 
        //g_print("upgrades: %i\n", un->num_upgrades);
318
 
        return TRUE;
319
 
}
320
 
 
321
 
static DBusHandlerResult
322
 
signal_filter(DBusConnection *connection, DBusMessage *message, void *data)
323
 
{
324
 
#if 0 // DEBUG stuff to better understand about dbus
325
 
        g_print("path: %s\n", dbus_message_get_path(message));
326
 
        g_print("interface: %s\n", dbus_message_get_interface(message));
327
 
        g_print("type: %i\n", dbus_message_get_type(message));
328
 
        g_print("dest: %s\n", dbus_message_get_destination(message));   
329
 
        g_print("member: %s\n", dbus_message_get_member(message));      
330
 
#endif
331
 
        //g_print("signal_filter: \n");
332
 
 
333
 
        if(dbus_message_is_signal(message, "app.apt.dbus", "changed") 
334
 
           || dbus_message_is_signal(message, "app.apt.dbus", "updated")) {
335
 
           DBusError error;
336
 
           gboolean finished=FALSE;
337
 
           dbus_error_init(&error);
338
 
           if(dbus_message_get_args(message, &error, 
339
 
                                    DBUS_TYPE_BOOLEAN, &finished, 
340
 
                                    DBUS_TYPE_INVALID)) {
341
 
              if(finished) {
342
 
                 //g_print("dbus message triggered update_check\n");
343
 
                 update_check(data);
344
 
              }
345
 
           }
346
 
              
347
 
        }
348
 
 
349
 
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
350
 
}
351
 
 
352
 
 
353
 
 
354
 
int 
355
 
main (int argc, char *argv[])
356
 
{
357
 
        GnomeClient *client;
358
 
        UpgradeNotifier *un;
359
 
        GMainLoop *loop;
360
 
 
361
 
        gnome_program_init (PACKAGE, PACKAGE_VERSION, 
362
 
                            LIBGNOMEUI_MODULE,
363
 
                            argc, argv, 
364
 
                            GNOME_PARAM_NONE);
365
 
 
366
 
        client = gnome_master_client ();
367
 
        if (up_get_clipboard ())
368
 
           gnome_client_set_restart_style (client, GNOME_RESTART_ANYWAY);
369
 
        else {
370
 
           gnome_client_set_restart_style (client, GNOME_RESTART_NEVER);
371
 
           warn ("already running?\n");
372
 
           return 1;
373
 
        }
374
 
 
375
 
        /* Make sure we die when the session dies */
376
 
        g_signal_connect (G_OBJECT (client), "die",
377
 
                          G_CALLBACK (gtk_main_quit), NULL);
378
 
        
379
 
        /* Create the UpgradeNotifier object */
380
 
        un = g_new0 (UpgradeNotifier, 1);
381
 
 
382
 
 
383
 
        /* setup a dbus channel */
384
 
        DBusConnection *bus;
385
 
        DBusError error;
386
 
        loop = g_main_loop_new(NULL, FALSE);
387
 
        dbus_error_init(&error);
388
 
        bus = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
389
 
        if(!bus) {
390
 
           g_error("Failed to connect to D-BUS: %s",error.message);
391
 
           return 1;
392
 
        }
393
 
        dbus_connection_setup_with_g_main(bus, NULL);
394
 
        dbus_bus_add_match(bus, "type='signal',interface='app.apt.dbus'", 
395
 
                           &error);
396
 
        dbus_connection_add_filter(bus, signal_filter, un, NULL);
397
 
 
398
 
 
399
 
        /* setup hal so that inserted cdroms can be checked */
400
 
        LibHalFunctions hal_functions = { hal_mainloop_integration,
401
 
                                          NULL /*hal_device_added*/,
402
 
                                          NULL /*hal_device_removed*/,
403
 
                                          NULL /*hal_device_new_capability*/,
404
 
                                          NULL /*hal_device_lost_capability*/,
405
 
                                          hal_property_modified,
406
 
                                          NULL /*hal_device_condition*/};
407
 
        hal_ctx = up_do_hal_init(&hal_functions);
408
 
        if (!hal_ctx) {
409
 
                g_error("failed to initialize HAL!\n");
410
 
                return 1;
411
 
        }
412
 
        hal_ctx_set_user_data(hal_ctx, un);
413
 
 
414
 
        /* setup FAM/GAMIN, monitor the importend directories */
415
 
        FAMRequest frq;
416
 
        if(FAMOpen(&un->fc) >= 0) {
417
 
           if(FAMMonitorDirectory(&un->fc, "/var/lib/apt/lists/", 
418
 
                             &frq, NULL))
419
 
              g_error("FAMMonitorFile() failed");
420
 
 
421
 
           if(FAMMonitorFile(&un->fc, 
422
 
                             "/var/lib/upgrade-notifier/dpkg-run-stamp", 
423
 
                             &frq, NULL))
424
 
              g_error("FAMMonitorFile() failed");
425
 
        } else {
426
 
           g_critical("FAMOpen() failed");
427
 
        }
428
 
 
429
 
        /* Check for updates for the first time */
430
 
        update_check (un);
431
 
 
432
 
        /* Set a time-out for the fam check */
433
 
        g_timeout_add (TIMEOUT_FAM, (GSourceFunc)fam_check, un);
434
 
 
435
 
        /* Start the main gtk loop */
436
 
        gtk_main ();
437
 
 
438
 
        FAMClose(&un->fc);
439
 
        return 0;
440
 
}