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

« back to all changes in this revision

Viewing changes to src/reboot.c

  • Committer: Michael Terry
  • Date: 2011-07-01 12:46:30 UTC
  • Revision ID: michael.terry@canonical.com-20110701124630-oesjak2rueshotbm
Tags: 0.112ubuntu2
* data/update-notifier.desktop.in:
  - Don't show in "Startup Applications" (LP: #803917)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#ifdef HAVE_CONFIG_H
 
2
#include "config.h"
 
3
#endif
 
4
 
 
5
#include <sys/types.h>
 
6
#include <sys/stat.h>
 
7
#include <unistd.h>
 
8
 
 
9
#include <libnotify/notify.h>
 
10
#include <dbus/dbus-glib.h>
 
11
#include <dbus/dbus.h>
 
12
 
 
13
#include "update-notifier.h"
 
14
#include "update.h"
 
15
 
 
16
static GtkBuilder *builder;
 
17
 
 
18
static gboolean
 
19
show_notification (TrayApplet *ta)
 
20
{
 
21
        NotifyNotification *n;
 
22
 
 
23
        // only show once the icon is realy availabe
 
24
        if(!gtk_status_icon_get_visible(ta->tray_icon))
 
25
           return TRUE;
 
26
 
 
27
        /* Create and show the notification */
 
28
        n = notify_notification_new(
 
29
                                     _("System restart required"),
 
30
                                     _("To complete the update of your system, "
 
31
                                       "please restart it.\n\n"
 
32
                                       "Click on the notification icon for "
 
33
                                       "details."),
 
34
                                     GTK_STOCK_DIALOG_WARNING);
 
35
        notify_notification_set_timeout (n, 60000);
 
36
        notify_notification_show (n, NULL);
 
37
 
 
38
        return FALSE;
 
39
}
 
40
 
 
41
static gboolean
 
42
gdm_action_reboot()
 
43
{
 
44
   DBusGConnection *connection;
 
45
   GError *error;
 
46
   DBusGProxy *proxy;
 
47
 
 
48
   error = NULL;
 
49
   connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
 
50
   if (connection == NULL) {
 
51
      g_error_free (error);
 
52
      return FALSE;
 
53
   }
 
54
 
 
55
  proxy = dbus_g_proxy_new_for_name (connection,
 
56
                                     "org.gnome.SessionManager",
 
57
                                     "/org/gnome/SessionManager",
 
58
                                     "org.gnome.SessionManager");
 
59
  if (proxy == NULL)
 
60
     return FALSE;
 
61
 
 
62
  error = NULL;
 
63
  if (!dbus_g_proxy_call (proxy, "RequestReboot", &error, 
 
64
                          G_TYPE_INVALID, G_TYPE_INVALID)) {
 
65
     g_error_free (error);
 
66
     return FALSE;
 
67
  }
 
68
  return TRUE;
 
69
}
 
70
 
 
71
static gboolean
 
72
ck_action_reboot()
 
73
{
 
74
   DBusGConnection *connection;
 
75
   GError *error;
 
76
   DBusGProxy *proxy;
 
77
 
 
78
   error = NULL;
 
79
   connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
 
80
   if (connection == NULL) {
 
81
      g_error_free (error);
 
82
      return FALSE;
 
83
   }
 
84
 
 
85
  proxy = dbus_g_proxy_new_for_name (connection,
 
86
                                     "org.freedesktop.ConsoleKit",
 
87
                                     "/org/freedesktop/ConsoleKit/Manager",
 
88
                                     "org.freedesktop.ConsoleKit.Manager");
 
89
  if (proxy == NULL)
 
90
     return FALSE;
 
91
 
 
92
  error = NULL;
 
93
  if (!dbus_g_proxy_call (proxy, "Restart", &error,
 
94
                          G_TYPE_INVALID, G_TYPE_INVALID)) {
 
95
     g_error_free (error);
 
96
     return FALSE;
 
97
  }
 
98
  return TRUE;
 
99
 
 
100
}
 
101
 
 
102
static void
 
103
request_reboot (void)
 
104
{
 
105
   if(!gdm_action_reboot() && !ck_action_reboot()) {
 
106
      const char *fmt, *msg, *details;
 
107
      fmt = "<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s\n";
 
108
      msg = _("Reboot failed");
 
109
      details = _("Failed to request reboot, please shutdown manually");
 
110
      GtkWidget *dlg = gtk_message_dialog_new_with_markup(NULL, 0,
 
111
                                                          GTK_MESSAGE_ERROR,
 
112
                                                          GTK_BUTTONS_CLOSE,
 
113
                                                          fmt, msg, details);
 
114
      gtk_dialog_run(GTK_DIALOG(dlg));
 
115
      gtk_widget_destroy(dlg);
 
116
   }
 
117
}
 
118
 
 
119
 
 
120
static void
 
121
ask_reboot_required(TrayApplet *ta, gboolean focus_on_map)
 
122
{
 
123
   GtkWidget *dia;
 
124
   
 
125
   dia = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_reboot"));
 
126
   gtk_window_set_focus_on_map(GTK_WINDOW(dia), focus_on_map);
 
127
   if (gtk_dialog_run (GTK_DIALOG(dia)) == GTK_RESPONSE_OK)
 
128
      request_reboot ();
 
129
   gtk_widget_hide (dia);
 
130
}
 
131
 
 
132
static gboolean
 
133
is_aptdaemon_on_the_system_bus ()
 
134
{
 
135
   DBusConnection *connection;
 
136
   DBusError *dbus_error = NULL;
 
137
   DBusMessage *message, *reply;
 
138
   const char *aptdaemon_bus_name = "org.debian.apt";
 
139
   gboolean res;
 
140
 
 
141
   connection = dbus_bus_get(DBUS_BUS_SYSTEM, dbus_error);
 
142
   if (dbus_error != NULL) {
 
143
      g_warning("failed to connect to the system bus");
 
144
      return FALSE;
 
145
   }
 
146
   message = dbus_message_new_method_call(DBUS_SERVICE_DBUS, 
 
147
                                          DBUS_PATH_DBUS,
 
148
                                          DBUS_INTERFACE_DBUS,
 
149
                                          "GetNameOwner");
 
150
   if (message == NULL) {
 
151
      g_warning ("failed to create dbus message");
 
152
      return FALSE;
 
153
   }
 
154
   
 
155
   dbus_message_append_args(message,
 
156
                            DBUS_TYPE_STRING, &aptdaemon_bus_name,
 
157
                            DBUS_TYPE_INVALID);
 
158
 
 
159
   reply = dbus_connection_send_with_reply_and_block(connection,
 
160
                                                     message,
 
161
                                                     -1,
 
162
                                                     dbus_error);
 
163
   dbus_message_unref(message);
 
164
 
 
165
   if (reply) {
 
166
      dbus_message_unref(reply);
 
167
      res = TRUE;
 
168
   } else {
 
169
      res =  FALSE;
 
170
   }
 
171
 
 
172
   g_debug("aptdaemon on bus: %i", res);
 
173
   return res;
 
174
}
 
175
 
 
176
static gboolean
 
177
aptdaemon_pending_transactions ()
 
178
{
 
179
   DBusGConnection *connection;
 
180
   GError *error;
 
181
   DBusGProxy *proxy;
 
182
   char *current = NULL;
 
183
   char **pending = NULL;
 
184
  
 
185
   if (!is_aptdaemon_on_the_system_bus())
 
186
      return FALSE;
 
187
 
 
188
   error = NULL;
 
189
   connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
 
190
   if (connection == NULL) {
 
191
      g_debug ("Failed to open connection to bus: %s\n", error->message);
 
192
      g_error_free (error);
 
193
      return FALSE;
 
194
   }
 
195
 
 
196
  proxy = dbus_g_proxy_new_for_name (connection,
 
197
                                     "org.debian.apt",
 
198
                                     "/org/debian/apt",
 
199
                                     "org.debian.apt");
 
200
  error = NULL;
 
201
  if (!dbus_g_proxy_call (proxy, "GetActiveTransactions", &error, 
 
202
                          G_TYPE_INVALID,
 
203
                          G_TYPE_STRING, &current, 
 
204
                          G_TYPE_STRV, &pending,
 
205
                          G_TYPE_INVALID)) {
 
206
     g_debug ("error during dbus call: %s\n", error->message);
 
207
     g_error_free (error);
 
208
     g_object_unref (proxy);
 
209
     return FALSE;
 
210
  }
 
211
 
 
212
  gboolean has_pending = FALSE;
 
213
  if ((current && strcmp(current,"") != 0) || g_strv_length(pending) > 0)
 
214
     has_pending = TRUE;
 
215
 
 
216
  g_object_unref (proxy);
 
217
  g_free (current);
 
218
  g_strfreev (pending);
 
219
 
 
220
  return has_pending;
 
221
}
 
222
 
 
223
static void
 
224
do_reboot_check (TrayApplet *ta)
 
225
{
 
226
        struct stat statbuf;
 
227
 
 
228
        // if we are not supposed to show the reboot notification
 
229
        // just skip it 
 
230
        if(gconf_client_get_bool((GConfClient*) ta->user_data,
 
231
                                 GCONF_KEY_HIDE_REBOOT, NULL))
 
232
           return;
 
233
        // no auto-open of this dialog 
 
234
        if(gconf_client_get_bool((GConfClient*) ta->user_data,
 
235
                                 GCONF_KEY_AUTO_LAUNCH, NULL)) {
 
236
           g_debug ("Skipping reboot required");
 
237
           return;
 
238
        }
 
239
 
 
240
        /* If the file doesn't exist, we don't need to reboot */
 
241
        if (stat (REBOOT_FILE, &statbuf)) {
 
242
                NotifyNotification *n;
 
243
 
 
244
                gtk_status_icon_set_visible (ta->tray_icon, FALSE);
 
245
                /* Hide any notification popup */
 
246
                n = g_object_get_data (G_OBJECT(ta->tray_icon), "notification");
 
247
                if (n)
 
248
                        notify_notification_close (n, NULL);
 
249
                g_object_set_data (G_OBJECT(ta->tray_icon), "notification", NULL);
 
250
 
 
251
                return;
 
252
        }
 
253
 
 
254
        /* Skip the rest if the icon is already visible */
 
255
        if (gtk_status_icon_get_visible (ta->tray_icon))
 
256
           return;
 
257
        gtk_status_icon_set_tooltip (ta->tray_icon,  
 
258
                                     _("System restart required"));
 
259
        gtk_status_icon_set_visible (ta->tray_icon, TRUE);
 
260
 
 
261
        /* Check whether the user doesn't like notifications */
 
262
        if (gconf_client_get_bool ((GConfClient*) ta->user_data,
 
263
                                   GCONF_KEY_NO_UPDATE_NOTIFICATIONS, NULL))
 
264
                return;
 
265
 
 
266
        /* Show the notification, after a delay so it doesn't look ugly
 
267
         * if we've just logged in */
 
268
        g_timeout_add(5000, (GSourceFunc)(show_notification), ta);
 
269
 
 
270
}
 
271
 
 
272
gboolean
 
273
reboot_check (TrayApplet *ta)
 
274
{
 
275
   if (aptdaemon_pending_transactions())
 
276
      g_timeout_add_seconds (5, (GSourceFunc)reboot_check, ta);
 
277
   else
 
278
      do_reboot_check(ta);
 
279
   return FALSE;
 
280
}
 
281
 
 
282
static gboolean
 
283
button_release_cb (GtkWidget *widget,
 
284
                   TrayApplet *ta)
 
285
{
 
286
   ask_reboot_required(ta, TRUE);
 
287
 
 
288
   return TRUE;
 
289
}
 
290
 
 
291
 
 
292
void
 
293
reboot_tray_icon_init (TrayApplet *ta)
 
294
{
 
295
        GtkWidget *widget;
 
296
        GError* error = NULL;
 
297
 
 
298
        builder = gtk_builder_new ();
 
299
        if (!gtk_builder_add_from_file (builder, UIDIR"reboot-dialog.ui", &error)) {
 
300
                g_warning ("Couldn't load builder file: %s", error->message);
 
301
                g_error_free (error);
 
302
        }
 
303
 
 
304
        widget = GTK_WIDGET (gtk_builder_get_object (builder, "image"));
 
305
        GtkIconTheme* icon_theme = gtk_icon_theme_get_default();
 
306
        GdkPixbuf *pixbuf = gtk_icon_theme_load_icon (icon_theme, "un-reboot",
 
307
                                                      48, 0,NULL);
 
308
        gtk_status_icon_set_from_pixbuf (ta->tray_icon, pixbuf);
 
309
        ta->user_data = gconf_client_get_default();
 
310
 
 
311
        g_signal_connect (G_OBJECT(ta->tray_icon),
 
312
                          "activate",
 
313
                          G_CALLBACK (button_release_cb),
 
314
                          ta);
 
315
 
 
316
        gtk_image_set_from_pixbuf(GTK_IMAGE(widget), pixbuf);
 
317
 
 
318
        /* Check for updates for the first time */
 
319
        reboot_check (ta);
 
320
}