~ubuntu-branches/ubuntu/precise/lxsession/precise

« back to all changes in this revision

Viewing changes to .pc/04_fix-ltsp-shutdown-reboot.patch/lxsession-logout/lxsession-logout.c

  • Committer: Bazaar Package Importer
  • Author(s): Julien Lavergne
  • Date: 2011-07-17 19:17:31 UTC
  • mfrom: (2.1.6 sid)
  • Revision ID: james.westby@ubuntu.com-20110717191731-sypvjc1zhmfl13zm
Tags: 0.4.5-1ubuntu1
* Merge from Debian LXDE git, remaining changes :
* debian/patches/05_not_launching-autostart-programs.patch:
 - Add an option to not autostart programs (LP: #655384)
* debian/patches/80_translations.patch:
 - Update translations from upstream git (2011-02-22)
* debian/gbp.conf:
 - Add specific settings for ubuntu branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * Copyright (c) 2010 LxDE Developers, see the file AUTHORS for details.
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify
 
5
 * it under the terms of the GNU General Public License as published by
 
6
 * the Free Software Foundation; either version 2 of the License, or
 
7
 * (at your option) any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program; if not, write to the Free Software Foundation,
 
16
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
17
 */
 
18
 
 
19
#include <config.h>
 
20
#include <locale.h>
 
21
#include <stdlib.h>
 
22
#include <gtk/gtk.h>
 
23
#include <gdk/gdk.h>
 
24
#include <gdk/gdkx.h>
 
25
#include <glib/gi18n.h>
 
26
#include <sys/types.h>
 
27
#include <sys/stat.h>
 
28
#include <fcntl.h>
 
29
#include <limits.h>
 
30
#include <signal.h>
 
31
#include <stdlib.h>
 
32
#include <string.h>
 
33
#include <unistd.h>
 
34
 
 
35
#include <X11/Xatom.h>
 
36
#include <X11/Xlib.h>
 
37
 
 
38
#include "dbus-interface.h"
 
39
 
 
40
/* Command parameters. */
 
41
static char * prompt = NULL;
 
42
static char * banner_side = NULL;
 
43
static char * banner_path = NULL;
 
44
 
 
45
static GOptionEntry opt_entries[] =
 
46
{
 
47
    { "prompt", 'p', 0, G_OPTION_ARG_STRING, &prompt, N_("Custom message to show on the dialog"), N_("message") },
 
48
    { "banner", 'b', 0, G_OPTION_ARG_STRING, &banner_path, N_("Banner to show on the dialog"), N_("image file") },
 
49
    { "side", 's', 0, G_OPTION_ARG_STRING, &banner_side, N_("Position of the banner"), "top|left|right|bottom" },
 
50
    { NULL }
 
51
};
 
52
 
 
53
typedef struct {
 
54
    GPid lxsession_pid;                 /* Process ID of lxsession */
 
55
    GtkWidget * error_label;            /* Text of an error, if we get one */
 
56
 
 
57
    int shutdown_available : 1;         /* Shutdown is available */
 
58
    int reboot_available : 1;           /* Reboot is available */
 
59
    int suspend_available : 1;          /* Suspend is available */
 
60
    int hibernate_available : 1;        /* Hibernate is available */
 
61
    int switch_user_available : 1;      /* Switch User is available */
 
62
 
 
63
    int shutdown_ConsoleKit : 1;        /* Shutdown is available via ConsoleKit */
 
64
    int reboot_ConsoleKit : 1;          /* Reboot is available via ConsoleKit */
 
65
    int suspend_UPower : 1;             /* Suspend is available via UPower */
 
66
    int hibernate_UPower : 1;           /* Hibernate is available via UPower */
 
67
    int shutdown_HAL : 1;               /* Shutdown is available via HAL */
 
68
    int reboot_HAL : 1;                 /* Reboot is available via HAL */
 
69
    int suspend_HAL : 1;                /* Suspend is available via HAL */
 
70
    int hibernate_HAL : 1;              /* Hibernate is available via HAL */
 
71
    int switch_user_GDM : 1;            /* Switch User is available via GDM */
 
72
    int switch_user_KDM : 1;            /* Switch User is available via KDM */
 
73
    int ltsp : 1;                       /* Shutdown and reboot is accomplished via LTSP */
 
74
} HandlerContext;
 
75
 
 
76
static gboolean verify_running(char * display_manager, char * executable);
 
77
static void logout_clicked(GtkButton * button, HandlerContext * handler_context);
 
78
static void change_root_property(GtkWidget* w, const char* prop_name, const char* value);
 
79
static void shutdown_clicked(GtkButton * button, HandlerContext * handler_context);
 
80
static void reboot_clicked(GtkButton * button, HandlerContext * handler_context);
 
81
static void suspend_clicked(GtkButton * button, HandlerContext * handler_context);
 
82
static void hibernate_clicked(GtkButton * button, HandlerContext * handler_context);
 
83
static void switch_user_clicked(GtkButton * button, HandlerContext * handler_context);
 
84
static void cancel_clicked(GtkButton * button, gpointer user_data);
 
85
static GtkPositionType get_banner_position(void);
 
86
static GdkPixbuf * get_background_pixbuf(void);
 
87
 
 
88
/* Verify that a program is running and that an executable is available. */
 
89
static gboolean verify_running(char * display_manager, char * executable)
 
90
{
 
91
    /* See if the executable we need to run is in the path. */
 
92
    gchar * full_path = g_find_program_in_path(executable);
 
93
    if (full_path != NULL)
 
94
    {
 
95
        g_free(full_path);
 
96
 
 
97
        /* Form the filespec of the pid file for the display manager. */
 
98
        char buffer[PATH_MAX];
 
99
        sprintf(buffer, "/var/run/%s.pid", display_manager);
 
100
 
 
101
        /* Open the pid file. */
 
102
        int fd = open(buffer, O_RDONLY);
 
103
        if (fd >= 0)
 
104
        {
 
105
            /* Pid file exists.  Read it. */
 
106
            ssize_t length = read(fd, buffer, sizeof(buffer));
 
107
            close(fd);
 
108
            if (length > 0)
 
109
            {
 
110
                /* Null terminate the buffer and convert the pid. */
 
111
                buffer[length] = '\0';
 
112
                pid_t pid = atoi(buffer);
 
113
                if (pid > 0)
 
114
                {
 
115
                    /* Form the filespec of the command line file under /proc.
 
116
                     * This is Linux specific.  Should be conditionalized to the appropriate /proc layout for
 
117
                     * other systems.  Your humble developer has no way to test on other systems. */
 
118
                    sprintf(buffer, "/proc/%d/cmdline", pid);
 
119
 
 
120
                    /* Open the file. */
 
121
                    int fd = open(buffer, O_RDONLY);
 
122
                    if (fd >= 0)
 
123
                    {
 
124
                        /* Read the command line. */
 
125
                        ssize_t length = read(fd, buffer, sizeof(buffer));
 
126
                        close(fd);
 
127
                        if (length > 0)
 
128
                        {
 
129
                            /* Null terminate the buffer and look for the display manager name in the command.
 
130
                             * If found, return success. */
 
131
                            buffer[length] = '\0';
 
132
                            if (strstr(buffer, display_manager) != NULL)
 
133
                                return TRUE;
 
134
                        }
 
135
                    }
 
136
                }
 
137
            }
 
138
        }
 
139
    }
 
140
    return FALSE;
 
141
}
 
142
 
 
143
/* Handler for "clicked" signal on Logout button. */
 
144
static void logout_clicked(GtkButton * button, HandlerContext * handler_context)
 
145
{
 
146
    kill(handler_context->lxsession_pid, SIGTERM);
 
147
    gtk_main_quit();
 
148
}
 
149
 
 
150
/* Replace a property on the root window. */
 
151
static void change_root_property(GtkWidget* w, const char* prop_name, const char* value)
 
152
{
 
153
    GdkDisplay* dpy = gtk_widget_get_display(w);
 
154
    GdkWindow* root = gtk_widget_get_root_window(w);
 
155
    XChangeProperty(GDK_DISPLAY_XDISPLAY(dpy), GDK_WINDOW_XID(root),
 
156
                      XInternAtom(GDK_DISPLAY_XDISPLAY(dpy), prop_name, False), XA_STRING, 8,
 
157
                      PropModeReplace, value, strlen(value) + 1);
 
158
}
 
159
 
 
160
/* Handler for "clicked" signal on Shutdown button. */
 
161
static void shutdown_clicked(GtkButton * button, HandlerContext * handler_context)
 
162
{
 
163
    char * error_result = NULL;
 
164
    gtk_label_set_text(GTK_LABEL(handler_context->error_label), NULL);
 
165
 
 
166
    if (handler_context->ltsp)
 
167
    {
 
168
        change_root_property(GTK_WIDGET(button), "LTSP_LOGOUT_ACTION", "HALT");
 
169
        kill(handler_context->lxsession_pid, SIGTERM);
 
170
    }
 
171
    else if (handler_context->shutdown_ConsoleKit)
 
172
        error_result = dbus_ConsoleKit_Stop();
 
173
    else if (handler_context->shutdown_HAL)
 
174
        error_result = dbus_HAL_Shutdown();
 
175
 
 
176
    if (error_result != NULL)
 
177
        gtk_label_set_text(GTK_LABEL(handler_context->error_label), error_result);
 
178
        else gtk_main_quit();
 
179
}
 
180
 
 
181
/* Handler for "clicked" signal on Reboot button. */
 
182
static void reboot_clicked(GtkButton * button, HandlerContext * handler_context)
 
183
{
 
184
    char * error_result = NULL;
 
185
    gtk_label_set_text(GTK_LABEL(handler_context->error_label), NULL);
 
186
 
 
187
    if (handler_context->ltsp)
 
188
    {
 
189
        change_root_property(GTK_WIDGET(button), "LTSP_LOGOUT_ACTION", "REBOOT");
 
190
        kill(handler_context->lxsession_pid, SIGTERM);
 
191
    }
 
192
    else if (handler_context->reboot_ConsoleKit)
 
193
        error_result = dbus_ConsoleKit_Restart();
 
194
    else if (handler_context->reboot_HAL)
 
195
        error_result = dbus_HAL_Reboot();
 
196
 
 
197
    if (error_result != NULL)
 
198
        gtk_label_set_text(GTK_LABEL(handler_context->error_label), error_result);
 
199
        else gtk_main_quit();
 
200
}
 
201
 
 
202
/* Handler for "clicked" signal on Suspend button. */
 
203
static void suspend_clicked(GtkButton * button, HandlerContext * handler_context)
 
204
{
 
205
    char * error_result = NULL;
 
206
    gtk_label_set_text(GTK_LABEL(handler_context->error_label), NULL);
 
207
 
 
208
    if (handler_context->suspend_UPower)
 
209
        error_result = dbus_UPower_Suspend();
 
210
    else if (handler_context->suspend_HAL)
 
211
        error_result = dbus_HAL_Suspend();
 
212
 
 
213
    if (error_result != NULL)
 
214
        gtk_label_set_text(GTK_LABEL(handler_context->error_label), error_result);
 
215
        else gtk_main_quit();
 
216
}
 
217
 
 
218
/* Handler for "clicked" signal on Hibernate button. */
 
219
static void hibernate_clicked(GtkButton * button, HandlerContext * handler_context)
 
220
{
 
221
    char * error_result = NULL;
 
222
    gtk_label_set_text(GTK_LABEL(handler_context->error_label), NULL);
 
223
 
 
224
    if (handler_context->hibernate_UPower)
 
225
        error_result = dbus_UPower_Hibernate();
 
226
    else if (handler_context->hibernate_HAL)
 
227
        error_result = dbus_HAL_Hibernate();
 
228
 
 
229
    if (error_result != NULL)
 
230
        gtk_label_set_text(GTK_LABEL(handler_context->error_label), error_result);
 
231
        else gtk_main_quit();
 
232
}
 
233
 
 
234
/* Handler for "clicked" signal on Switch User button. */
 
235
static void switch_user_clicked(GtkButton * button, HandlerContext * handler_context)
 
236
{
 
237
    gtk_label_set_text(GTK_LABEL(handler_context->error_label), NULL);
 
238
 
 
239
    if (handler_context->switch_user_GDM)
 
240
        g_spawn_command_line_sync("gdmflexiserver --startnew", NULL, NULL, NULL, NULL);
 
241
    else if (handler_context->switch_user_KDM)
 
242
        g_spawn_command_line_sync("kdmctl reserve", NULL, NULL, NULL, NULL);
 
243
    gtk_main_quit();
 
244
}
 
245
 
 
246
/* Handler for "clicked" signal on Cancel button. */
 
247
static void cancel_clicked(GtkButton * button, gpointer user_data)
 
248
{
 
249
    gtk_main_quit();
 
250
}
 
251
 
 
252
/* Convert the --side parameter to a GtkPositionType. */
 
253
static GtkPositionType get_banner_position(void)
 
254
{
 
255
    if (banner_side != NULL)
 
256
    {
 
257
        if (strcmp(banner_side, "right") == 0)
 
258
            return GTK_POS_RIGHT;
 
259
        if (strcmp(banner_side, "top") == 0)
 
260
            return GTK_POS_TOP;
 
261
        if (strcmp(banner_side, "bottom") == 0)
 
262
            return GTK_POS_BOTTOM;
 
263
    }
 
264
    return GTK_POS_LEFT;
 
265
}
 
266
 
 
267
/* Get the background pixbuf. */
 
268
static GdkPixbuf * get_background_pixbuf(void)
 
269
{
 
270
    /* Get the root window pixmap. */
 
271
    GdkScreen * screen = gdk_screen_get_default();
 
272
    GdkPixbuf * pixbuf = gdk_pixbuf_get_from_drawable(
 
273
        NULL,                                   /* Allocate a new pixbuf */
 
274
        gdk_get_default_root_window(),          /* The drawable */
 
275
        NULL,                                   /* Its colormap */
 
276
        0, 0, 0, 0,                             /* Coordinates */
 
277
        gdk_screen_get_width(screen),           /* Width */
 
278
        gdk_screen_get_height(screen));         /* Height */
 
279
 
 
280
    /* Make the background darker. */
 
281
    if (pixbuf != NULL)
 
282
    {
 
283
        unsigned char * pixels = gdk_pixbuf_get_pixels(pixbuf);
 
284
        int width = gdk_pixbuf_get_width(pixbuf);
 
285
        int height = gdk_pixbuf_get_height(pixbuf);
 
286
        int pixel_stride = ((gdk_pixbuf_get_has_alpha(pixbuf)) ? 4 : 3);
 
287
        int row_stride = gdk_pixbuf_get_rowstride(pixbuf);
 
288
        int y;
 
289
        for (y = 0; y < height; y += 1)
 
290
        {
 
291
            unsigned char * p = pixels;
 
292
            int x;
 
293
            for (x = 0; x < width; x += 1)
 
294
            {
 
295
                p[0] = p[0] / 2;
 
296
                p[1] = p[1] / 2;
 
297
                p[2] = p[2] / 2;
 
298
                p += pixel_stride;
 
299
            }
 
300
            pixels += row_stride;
 
301
        }
 
302
    }
 
303
    return pixbuf;
 
304
}
 
305
 
 
306
/* Handler for "expose_event" on background. */
 
307
gboolean expose_event(GtkWidget * widget, GdkEventExpose * event, GdkPixbuf * pixbuf)
 
308
{
 
309
    if (pixbuf != NULL)
 
310
    {
 
311
        /* Copy the appropriate rectangle of the root window pixmap to the drawing area.
 
312
         * All drawing areas are immediate children of the toplevel window, so the allocation yields the source coordinates directly. */
 
313
        gdk_draw_pixbuf(
 
314
            widget->window,                                     /* Drawable to render to */
 
315
            NULL,                                               /* GC for clipping */
 
316
            pixbuf,                                             /* Source pixbuf */
 
317
            widget->allocation.x, widget->allocation.y,         /* Source coordinates */
 
318
            0, 0,                                               /* Destination coordinates */
 
319
            widget->allocation.width, widget->allocation.height,
 
320
            GDK_RGB_DITHER_NORMAL,                              /* Dither type */
 
321
            0, 0);                                              /* Dither offsets */
 
322
    }
 
323
    return FALSE;
 
324
}
 
325
 
 
326
/* Main program. */
 
327
int main(int argc, char * argv[])
 
328
{
 
329
#ifdef ENABLE_NLS
 
330
    setlocale(LC_ALL, "");
 
331
    bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
 
332
    bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
 
333
    textdomain (GETTEXT_PACKAGE);
 
334
#endif
 
335
 
 
336
    /* Initialize GTK (via g_option_context_parse) and parse command line arguments. */
 
337
    GOptionContext * context = g_option_context_new("");
 
338
    g_option_context_add_main_entries(context, opt_entries, GETTEXT_PACKAGE);
 
339
    g_option_context_add_group(context, gtk_get_option_group(TRUE));
 
340
    GError * err = NULL;
 
341
    if ( ! g_option_context_parse(context, &argc, &argv, &err))
 
342
    {
 
343
        g_print(_("Error: %s\n"), err->message);
 
344
        g_error_free(err);
 
345
        return 1;
 
346
    }
 
347
    g_option_context_free(context);
 
348
 
 
349
    HandlerContext handler_context;
 
350
    memset(&handler_context, 0, sizeof(handler_context));
 
351
 
 
352
    /* Ensure that we are running under lxsession. */
 
353
    const char * p = g_getenv("_LXSESSION_PID");
 
354
    if (p != NULL) handler_context.lxsession_pid = atoi(p);
 
355
    if (handler_context.lxsession_pid == 0)
 
356
    {
 
357
        g_print( _("Error: %s\n"), _("LXSession is not running."));
 
358
        return 1;
 
359
    }
 
360
 
 
361
    /* Initialize capabilities of the ConsoleKit mechanism. */
 
362
    if (dbus_ConsoleKit_CanStop())
 
363
    {
 
364
        handler_context.shutdown_available = TRUE;
 
365
        handler_context.shutdown_ConsoleKit = TRUE;
 
366
    }
 
367
    if (dbus_ConsoleKit_CanRestart())
 
368
    {
 
369
        handler_context.reboot_available = TRUE;
 
370
        handler_context.reboot_ConsoleKit = TRUE;
 
371
    }
 
372
 
 
373
    /* Initialize capabilities of the UPower mechanism. */
 
374
    if (dbus_UPower_CanSuspend())
 
375
    {
 
376
        handler_context.suspend_available = TRUE;
 
377
        handler_context.suspend_UPower = TRUE;
 
378
    }
 
379
    if (dbus_UPower_CanHibernate())
 
380
    {
 
381
        handler_context.hibernate_available = TRUE;
 
382
        handler_context.hibernate_UPower = TRUE;
 
383
    }
 
384
 
 
385
    /* Initialize capabilities of the HAL mechanism. */
 
386
    if (!handler_context.shutdown_available && dbus_HAL_CanShutdown())
 
387
    {
 
388
        handler_context.shutdown_available = TRUE;
 
389
        handler_context.shutdown_HAL = TRUE;
 
390
    }
 
391
    if (!handler_context.reboot_available && dbus_HAL_CanReboot())
 
392
    {
 
393
        handler_context.reboot_available = TRUE;
 
394
        handler_context.reboot_HAL = TRUE;
 
395
    }
 
396
    if (!handler_context.suspend_available && dbus_HAL_CanSuspend())
 
397
    {
 
398
        handler_context.suspend_available = TRUE;
 
399
        handler_context.suspend_HAL = TRUE;
 
400
    }
 
401
    if (!handler_context.hibernate_available && dbus_HAL_CanHibernate())
 
402
    {
 
403
        handler_context.hibernate_available = TRUE;
 
404
        handler_context.hibernate_HAL = TRUE;
 
405
    }
 
406
 
 
407
    /* If we are under GDM, its "Switch User" is available. */
 
408
    if (verify_running("gdm", "gdmflexiserver"))
 
409
    {
 
410
        handler_context.switch_user_available = TRUE;
 
411
        handler_context.switch_user_GDM = TRUE;
 
412
    }
 
413
 
 
414
    /* If we are under KDM, its "Switch User" is available. */
 
415
    if (verify_running("kdm", "kdmctl"))
 
416
    {
 
417
        handler_context.switch_user_available = TRUE;
 
418
        handler_context.switch_user_KDM = TRUE;
 
419
    }
 
420
 
 
421
    /* LTSP support */
 
422
    if (g_getenv("LTSP_CLIENT"))
 
423
        handler_context.ltsp = TRUE;
 
424
 
 
425
    /* Make the button images accessible. */
 
426
    gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), PACKAGE_DATA_DIR "/lxsession/images");
 
427
 
 
428
    /* Get the background pixbuf. */
 
429
    GdkPixbuf * pixbuf = get_background_pixbuf();
 
430
 
 
431
    /* Create the toplevel window. */
 
432
    GtkWidget * window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 
433
    gtk_window_set_decorated(GTK_WINDOW(window), FALSE);
 
434
    gtk_window_fullscreen(GTK_WINDOW(window));
 
435
    GdkScreen* screen = gtk_widget_get_screen(window);
 
436
    gtk_window_set_default_size(GTK_WINDOW(window), gdk_screen_get_width(screen), gdk_screen_get_height(screen));
 
437
    gtk_widget_set_app_paintable(window, TRUE);
 
438
    g_signal_connect(G_OBJECT(window), "expose_event", G_CALLBACK(expose_event), pixbuf);
 
439
 
 
440
    /* Toplevel container */
 
441
    GtkWidget* alignment = gtk_alignment_new(0.5, 0.5, 0.0, 0.0);
 
442
    gtk_container_add(GTK_CONTAINER(window), alignment);
 
443
 
 
444
    GtkWidget* center_area = gtk_event_box_new();
 
445
    gtk_container_add(GTK_CONTAINER(alignment), center_area);
 
446
 
 
447
    GtkWidget* center_vbox = gtk_vbox_new(FALSE, 6);
 
448
    gtk_container_set_border_width(GTK_CONTAINER(center_vbox), 12);
 
449
    gtk_container_add(GTK_CONTAINER(center_area), center_vbox);
 
450
 
 
451
    GtkWidget* controls = gtk_vbox_new(FALSE, 6);
 
452
 
 
453
    /* If specified, apply a user-specified banner image. */
 
454
    if (banner_path != NULL)
 
455
    {
 
456
        GtkWidget * banner_image = gtk_image_new_from_file(banner_path);
 
457
        GtkPositionType banner_position = get_banner_position();
 
458
 
 
459
        switch (banner_position)
 
460
        {
 
461
            case GTK_POS_LEFT:
 
462
            case GTK_POS_RIGHT:
 
463
                {
 
464
                /* Create a horizontal box to contain the image and the controls. */
 
465
                GtkWidget * box = gtk_hbox_new(FALSE, 2);
 
466
                gtk_box_pack_start(GTK_BOX(center_vbox), box, FALSE, FALSE, 0);
 
467
 
 
468
                /* Pack the image and a separator. */
 
469
                gtk_misc_set_alignment(GTK_MISC(banner_image), 0.5, 0.0);
 
470
                if (banner_position == GTK_POS_LEFT)
 
471
                {
 
472
                    gtk_box_pack_start(GTK_BOX(box), banner_image, FALSE, FALSE, 2);
 
473
                    gtk_box_pack_start(GTK_BOX(box), gtk_vseparator_new(), FALSE, FALSE, 2);
 
474
                    gtk_box_pack_start(GTK_BOX(box), controls, FALSE, FALSE, 2);
 
475
                }
 
476
                else
 
477
                {
 
478
                    gtk_box_pack_start(GTK_BOX(box), controls, FALSE, FALSE, 2);
 
479
                    gtk_box_pack_end(GTK_BOX(box), gtk_vseparator_new(), FALSE, FALSE, 2);
 
480
                    gtk_box_pack_end(GTK_BOX(box), banner_image, FALSE, FALSE, 2);
 
481
                }
 
482
                }
 
483
                break;
 
484
 
 
485
            case GTK_POS_TOP:
 
486
                gtk_box_pack_start(GTK_BOX(controls), banner_image, FALSE, FALSE, 2);
 
487
                gtk_box_pack_start(GTK_BOX(controls), gtk_hseparator_new(), FALSE, FALSE, 2);
 
488
                gtk_box_pack_start(GTK_BOX(center_vbox), controls, FALSE, FALSE, 0);
 
489
                break;
 
490
 
 
491
            case GTK_POS_BOTTOM:
 
492
                gtk_box_pack_end(GTK_BOX(controls), banner_image, FALSE, FALSE, 2);
 
493
                gtk_box_pack_end(GTK_BOX(controls), gtk_hseparator_new(), FALSE, FALSE, 2);
 
494
                gtk_box_pack_start(GTK_BOX(center_vbox), controls, FALSE, FALSE, 0);
 
495
                break;
 
496
        }
 
497
    }
 
498
    else
 
499
        gtk_box_pack_start(GTK_BOX(center_vbox), controls, FALSE, FALSE, 0);
 
500
 
 
501
    /* Create the label. */
 
502
    GtkWidget * label = gtk_label_new("");
 
503
    if (prompt == NULL)
 
504
    {
 
505
        const char * session_name = g_getenv("DESKTOP_SESSION");
 
506
        if (session_name == NULL)
 
507
            session_name = "LXDE";
 
508
        prompt = g_strdup_printf(_("<b><big>Logout %s session?</big></b>"), session_name);
 
509
    }
 
510
    gtk_label_set_markup(GTK_LABEL(label), prompt);
 
511
    gtk_box_pack_start(GTK_BOX(controls), label, FALSE, FALSE, 4);
 
512
 
 
513
    /* Create the Shutdown button. */
 
514
    if (handler_context.shutdown_available)
 
515
    {
 
516
        GtkWidget * shutdown_button = gtk_button_new_with_mnemonic(_("Sh_utdown"));
 
517
        GtkWidget * image = gtk_image_new_from_icon_name("system-shutdown", GTK_ICON_SIZE_BUTTON);
 
518
        gtk_button_set_image(GTK_BUTTON(shutdown_button), image);
 
519
        gtk_button_set_alignment(GTK_BUTTON(shutdown_button), 0.0, 0.5);
 
520
        g_signal_connect(G_OBJECT(shutdown_button), "clicked", G_CALLBACK(shutdown_clicked), &handler_context);
 
521
        gtk_box_pack_start(GTK_BOX(controls), shutdown_button, FALSE, FALSE, 4);
 
522
    }
 
523
 
 
524
    /* Create the Reboot button. */
 
525
    if (handler_context.reboot_available)
 
526
    {
 
527
        GtkWidget * reboot_button = gtk_button_new_with_mnemonic(_("_Reboot"));
 
528
        GtkWidget * image = gtk_image_new_from_icon_name("gnome-session-reboot", GTK_ICON_SIZE_BUTTON);
 
529
        gtk_button_set_image(GTK_BUTTON(reboot_button), image);
 
530
        gtk_button_set_alignment(GTK_BUTTON(reboot_button), 0.0, 0.5);
 
531
        g_signal_connect(G_OBJECT(reboot_button), "clicked", G_CALLBACK(reboot_clicked), &handler_context);
 
532
        gtk_box_pack_start(GTK_BOX(controls), reboot_button, FALSE, FALSE, 4);
 
533
    }
 
534
 
 
535
    /* Create the Suspend button. */
 
536
    if (handler_context.suspend_available && !handler_context.ltsp)
 
537
    {
 
538
        GtkWidget * suspend_button = gtk_button_new_with_mnemonic(_("_Suspend"));
 
539
        GtkWidget * image = gtk_image_new_from_icon_name("gnome-session-suspend", GTK_ICON_SIZE_BUTTON);
 
540
        gtk_button_set_image(GTK_BUTTON(suspend_button), image);
 
541
        gtk_button_set_alignment(GTK_BUTTON(suspend_button), 0.0, 0.5);
 
542
        g_signal_connect(G_OBJECT(suspend_button), "clicked", G_CALLBACK(suspend_clicked), &handler_context);
 
543
        gtk_box_pack_start(GTK_BOX(controls), suspend_button, FALSE, FALSE, 4);
 
544
    }
 
545
 
 
546
    /* Create the Hibernate button. */
 
547
    if (handler_context.hibernate_available && !handler_context.ltsp)
 
548
    {
 
549
        GtkWidget * hibernate_button = gtk_button_new_with_mnemonic(_("_Hibernate"));
 
550
        GtkWidget * image = gtk_image_new_from_icon_name("gnome-session-hibernate", GTK_ICON_SIZE_BUTTON);
 
551
        gtk_button_set_image(GTK_BUTTON(hibernate_button), image);
 
552
        gtk_button_set_alignment(GTK_BUTTON(hibernate_button), 0.0, 0.5);
 
553
        g_signal_connect(G_OBJECT(hibernate_button), "clicked", G_CALLBACK(hibernate_clicked), &handler_context);
 
554
        gtk_box_pack_start(GTK_BOX(controls), hibernate_button, FALSE, FALSE, 4);
 
555
    }
 
556
 
 
557
    /* Create the Switch User button. */
 
558
    if (handler_context.switch_user_available && !handler_context.ltsp)
 
559
    {
 
560
        GtkWidget * switch_user_button = gtk_button_new_with_mnemonic(_("S_witch User"));
 
561
        GtkWidget * image = gtk_image_new_from_icon_name("gnome-session-switch", GTK_ICON_SIZE_BUTTON);
 
562
        gtk_button_set_image(GTK_BUTTON(switch_user_button), image);
 
563
        gtk_button_set_alignment(GTK_BUTTON(switch_user_button), 0.0, 0.5);
 
564
        g_signal_connect(G_OBJECT(switch_user_button), "clicked", G_CALLBACK(switch_user_clicked), &handler_context);
 
565
        gtk_box_pack_start(GTK_BOX(controls), switch_user_button, FALSE, FALSE, 4);
 
566
    }
 
567
 
 
568
    /* Create the Logout button. */
 
569
    GtkWidget * logout_button = gtk_button_new_with_mnemonic(_("_Logout"));
 
570
    GtkWidget * image = gtk_image_new_from_icon_name("system-log-out", GTK_ICON_SIZE_BUTTON);
 
571
    gtk_button_set_image(GTK_BUTTON(logout_button), image);
 
572
    gtk_button_set_alignment(GTK_BUTTON(logout_button), 0.0, 0.5);
 
573
    g_signal_connect(G_OBJECT(logout_button), "clicked", G_CALLBACK(logout_clicked), &handler_context);
 
574
    gtk_box_pack_start(GTK_BOX(controls), logout_button, FALSE, FALSE, 4);
 
575
 
 
576
    /* Create the Cancel button. */
 
577
    GtkWidget * cancel_button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
 
578
    gtk_button_set_alignment(GTK_BUTTON(cancel_button), 0.0, 0.5);
 
579
    g_signal_connect(G_OBJECT(cancel_button), "clicked", G_CALLBACK(cancel_clicked), NULL);
 
580
    gtk_box_pack_start(GTK_BOX(controls), cancel_button, FALSE, FALSE, 4);
 
581
 
 
582
    /* Create the error text. */
 
583
    handler_context.error_label = gtk_label_new("");
 
584
    gtk_label_set_justify(GTK_LABEL(handler_context.error_label), GTK_JUSTIFY_CENTER);
 
585
    gtk_box_pack_start(GTK_BOX(controls), handler_context.error_label, FALSE, FALSE, 4);
 
586
 
 
587
    /* Show everything. */
 
588
    gtk_widget_show_all(window);
 
589
 
 
590
    /* Run the main event loop. */
 
591
    gtk_main();
 
592
 
 
593
    /* Return. */
 
594
    return 0;
 
595
}