~ubuntu-branches/ubuntu/vivid/gnome-session/vivid

« back to all changes in this revision

Viewing changes to gnome-session/gsm-inhibit-dialog.c

  • Committer: Package Import Robot
  • Author(s): Tim Lunn
  • Date: 2014-10-31 09:19:52 UTC
  • mfrom: (1.1.86) (245.1.1 vivid-proposed)
  • Revision ID: package-import@ubuntu.com-20141031091952-ci78rlfuztpd0y47
Tags: 3.14.0-2ubuntu1
* Merge from Debian, Remaining Changes:
  - debian/control.in: 
    + Recommend session-migration
    * don't depend on xwayland
  - debian/gnome-session.install: Don't install wayland session for now
    since its not yet possible to run it
  - Split ubuntu-session out of gnome-session.
  - Add upstart user session
  - debian/gnome-session-bin.postinst, debian/gnome-session-bin.prerm:
     Moved registering gnome-session binary as a session manager to 
     gnome-session-bin package
  - don't install defaults.list (installed by desktop-file-utils in ubuntu):
     debian/gnome-session-common.dirs and gnome-session-common.install
 - debian/patches/22_support_autostart_delay.patch:
    Bugzilla patch to support adding a delay to autostart apps, using
    a "X-GNOME-Autostart-Delay" key in the desktop file
 - debian/patches/50_ubuntu_sessions.patch:
    + Add Ubuntu session
    + gnome-shell.desktop adds --session=gnome now that the "ubuntu" session
      is the default. Use TryExec to test if gnome-shell is installed.
 - debian/patches/51_remove_session_saving_from_gui.patch:
    add GNOME_SESSION_SAVE environment variable for people wanting to
    use the save session still, knowing that it can break your system
    if used unwisely (LP: #771896)
 - debian/patches/52_xdg_current_desktop.patch:
    Set XDG_CURRENT_DESKTOP inside gnome-session based on a
    new key 'DesktopName' in gnome-session .desktop files.
 - debian/patches/53_add_sessionmigration.patch, debian/control:
    recommends and launch the session-migration if present at the start
    of the session. This sync tool is running different session migration
    scripts that can be provided in various desktop packages.
 - debian/patches/95_dbus_request_shutdown.patch:
    Add "RequestShutdown" and "RequestReboot" DBus methods to allow other
    applications to shutdown or reboot the machine via the session manager.
  - debian/patches/103_kill_the_fail_whale.patch:
    Kill the Fail Whale as it tends to be more annoying than helpful
* debian/patches/revert_remove_gnome_session_properties.patch
* Dropped Changes:
* debian/patches/52_xdg_current_desktop.patch: Dropped Upsream includes a
  fallback to set this now. 
* Remove patches that have been disabled since 3.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2
 
 *
3
 
 * Copyright (C) 2008 William Jon McCann <mccann@jhu.edu>
4
 
 *
5
 
 * This program is free software; you can redistribute it and/or modify
6
 
 * it under the terms of the GNU General Public License as published by
7
 
 * the Free Software Foundation; either version 2 of the License, or
8
 
 * (at your option) any later version.
9
 
 *
10
 
 * This program is distributed in the hope that it will be useful,
11
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
 * GNU General Public License for more details.
14
 
 *
15
 
 * You should have received a copy of the GNU General Public License
16
 
 * along with this program; if not, write to the Free Software
17
 
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
 
 *
19
 
 */
20
 
 
21
 
#include "config.h"
22
 
 
23
 
#include <stdlib.h>
24
 
#include <stdio.h>
25
 
#include <unistd.h>
26
 
#include <string.h>
27
 
 
28
 
#include <glib.h>
29
 
#include <glib/gi18n.h>
30
 
#include <glib-object.h>
31
 
#include <gio/gdesktopappinfo.h>
32
 
#include <gtk/gtk.h>
33
 
#include <gdk/gdkx.h>
34
 
#include <cairo-xlib.h>
35
 
 
36
 
#include "gsm-inhibit-dialog.h"
37
 
#include "gsm-store.h"
38
 
#include "gsm-client.h"
39
 
#include "gsm-icon-names.h"
40
 
#include "gsm-inhibitor.h"
41
 
#include "gsm-util.h"
42
 
 
43
 
#ifdef HAVE_XRENDER
44
 
#include <X11/extensions/Xrender.h>
45
 
#endif
46
 
 
47
 
#define GSM_INHIBIT_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_INHIBIT_DIALOG, GsmInhibitDialogPrivate))
48
 
 
49
 
#define GTKBUILDER_FILE "gsm-inhibit-dialog.ui"
50
 
 
51
 
#ifndef DEFAULT_ICON_SIZE
52
 
#define DEFAULT_ICON_SIZE 32
53
 
#endif
54
 
 
55
 
#ifndef DEFAULT_SNAPSHOT_SIZE
56
 
#define DEFAULT_SNAPSHOT_SIZE 128
57
 
#endif
58
 
 
59
 
#define DIALOG_RESPONSE_LOCK_SCREEN 1
60
 
 
61
 
struct GsmInhibitDialogPrivate
62
 
{
63
 
        GtkBuilder        *xml;
64
 
        int                action;
65
 
        gboolean           is_done;
66
 
        GsmStore          *inhibitors;
67
 
        GsmStore          *clients;
68
 
        GtkListStore      *list_store;
69
 
        gboolean           have_xrender;
70
 
        int                xrender_event_base;
71
 
        int                xrender_error_base;
72
 
};
73
 
 
74
 
enum {
75
 
        PROP_0,
76
 
        PROP_ACTION,
77
 
        PROP_INHIBITOR_STORE,
78
 
        PROP_CLIENT_STORE
79
 
};
80
 
 
81
 
enum {
82
 
        INHIBIT_IMAGE_COLUMN = 0,
83
 
        INHIBIT_NAME_COLUMN,
84
 
        INHIBIT_REASON_COLUMN,
85
 
        INHIBIT_ID_COLUMN,
86
 
        NUMBER_OF_COLUMNS
87
 
};
88
 
 
89
 
static void     gsm_inhibit_dialog_class_init  (GsmInhibitDialogClass *klass);
90
 
static void     gsm_inhibit_dialog_init        (GsmInhibitDialog      *inhibit_dialog);
91
 
 
92
 
G_DEFINE_TYPE (GsmInhibitDialog, gsm_inhibit_dialog, GTK_TYPE_DIALOG)
93
 
 
94
 
static void
95
 
lock_screen (GsmInhibitDialog *dialog)
96
 
{
97
 
        GError *error;
98
 
        error = NULL;
99
 
        g_spawn_command_line_async ("gnome-screensaver-command --lock", &error);
100
 
        if (error != NULL) {
101
 
                g_warning ("Couldn't lock screen: %s", error->message);
102
 
                g_error_free (error);
103
 
        }
104
 
}
105
 
 
106
 
static void
107
 
on_response (GsmInhibitDialog *dialog,
108
 
             gint              response_id)
109
 
 
110
 
{
111
 
        if (dialog->priv->is_done) {
112
 
                g_signal_stop_emission_by_name (dialog, "response");
113
 
                return;
114
 
        }
115
 
 
116
 
        switch (response_id) {
117
 
        case DIALOG_RESPONSE_LOCK_SCREEN:
118
 
                g_signal_stop_emission_by_name (dialog, "response");
119
 
                lock_screen (dialog);
120
 
                break;
121
 
        default:
122
 
                dialog->priv->is_done = TRUE;
123
 
                break;
124
 
        }
125
 
}
126
 
 
127
 
static void
128
 
gsm_inhibit_dialog_set_action (GsmInhibitDialog *dialog,
129
 
                               int               action)
130
 
{
131
 
        dialog->priv->action = action;
132
 
}
133
 
 
134
 
static gboolean
135
 
find_inhibitor (GsmInhibitDialog *dialog,
136
 
                const char       *id,
137
 
                GtkTreeIter      *iter)
138
 
{
139
 
        GtkTreeModel *model;
140
 
        gboolean      found_item;
141
 
 
142
 
        g_assert (GSM_IS_INHIBIT_DIALOG (dialog));
143
 
 
144
 
        found_item = FALSE;
145
 
        model = GTK_TREE_MODEL (dialog->priv->list_store);
146
 
 
147
 
        if (!gtk_tree_model_get_iter_first (model, iter)) {
148
 
                return FALSE;
149
 
        }
150
 
 
151
 
        do {
152
 
                char *item_id;
153
 
 
154
 
                gtk_tree_model_get (model,
155
 
                                    iter,
156
 
                                    INHIBIT_ID_COLUMN, &item_id,
157
 
                                    -1);
158
 
                if (item_id != NULL
159
 
                    && id != NULL
160
 
                    && strcmp (item_id, id) == 0) {
161
 
                        found_item = TRUE;
162
 
                }
163
 
                g_free (item_id);
164
 
        } while (!found_item && gtk_tree_model_iter_next (model, iter));
165
 
 
166
 
        return found_item;
167
 
}
168
 
 
169
 
static GdkPixbuf *
170
 
scale_pixbuf (GdkPixbuf *pixbuf,
171
 
              int        max_width,
172
 
              int        max_height,
173
 
              gboolean   no_stretch_hint)
174
 
{
175
 
        int        pw;
176
 
        int        ph;
177
 
        float      scale_factor_x = 1.0;
178
 
        float      scale_factor_y = 1.0;
179
 
        float      scale_factor = 1.0;
180
 
 
181
 
        pw = gdk_pixbuf_get_width (pixbuf);
182
 
        ph = gdk_pixbuf_get_height (pixbuf);
183
 
 
184
 
        /* Determine which dimension requires the smallest scale. */
185
 
        scale_factor_x = (float) max_width / (float) pw;
186
 
        scale_factor_y = (float) max_height / (float) ph;
187
 
 
188
 
        if (scale_factor_x > scale_factor_y) {
189
 
                scale_factor = scale_factor_y;
190
 
        } else {
191
 
                scale_factor = scale_factor_x;
192
 
        }
193
 
 
194
 
        /* always scale down, allow to disable scaling up */
195
 
        if (scale_factor < 1.0 || !no_stretch_hint) {
196
 
                int scale_x = (int) (pw * scale_factor);
197
 
                int scale_y = (int) (ph * scale_factor);
198
 
                g_debug ("Scaling to %dx%d", scale_x, scale_y);
199
 
                return gdk_pixbuf_scale_simple (pixbuf,
200
 
                                                scale_x,
201
 
                                                scale_y,
202
 
                                                GDK_INTERP_BILINEAR);
203
 
        } else {
204
 
                return g_object_ref (pixbuf);
205
 
        }
206
 
}
207
 
 
208
 
#ifdef HAVE_XRENDER
209
 
 
210
 
static GdkPixbuf *
211
 
pixbuf_get_from_pixmap (Display *display,
212
 
                        Pixmap   xpixmap,
213
 
                        int      width,
214
 
                        int      height)
215
 
{
216
 
        cairo_surface_t *surface;
217
 
        GdkPixbuf       *retval;
218
 
        Visual          *visual;
219
 
 
220
 
        retval = NULL;
221
 
 
222
 
        visual = DefaultVisual (display, 0);
223
 
        g_debug ("GsmInhibitDialog: getting foreign pixmap for %u", (guint)xpixmap);
224
 
        surface = cairo_xlib_surface_create (display,
225
 
                                             xpixmap,
226
 
                                             visual,
227
 
                                             width,
228
 
                                             height);
229
 
        if (surface != NULL) {
230
 
                g_debug ("GsmInhibitDialog: getting pixbuf w=%d h=%d", width, height);
231
 
                retval = gdk_pixbuf_get_from_surface (surface,
232
 
                                                      0, 0,
233
 
                                                      width, height);
234
 
        }
235
 
 
236
 
        if (surface) {
237
 
                cairo_surface_destroy (surface);
238
 
        }
239
 
 
240
 
        return retval;
241
 
}
242
 
 
243
 
static Pixmap
244
 
get_pixmap_for_window (Display *display,
245
 
                       Window   window,
246
 
                       int     *widthp,
247
 
                       int     *heightp)
248
 
{
249
 
        XWindowAttributes        attr;
250
 
        XRenderPictureAttributes pa;
251
 
        Pixmap                   pixmap;
252
 
        XRenderPictFormat       *format;
253
 
        Picture                  src_picture;
254
 
        Picture                  dst_picture;
255
 
        gboolean                 has_alpha;
256
 
        int                      width;
257
 
        int                      height;
258
 
 
259
 
        XGetWindowAttributes (display, window, &attr);
260
 
 
261
 
        format = XRenderFindVisualFormat (display, attr.visual);
262
 
        has_alpha = (format->type == PictTypeDirect && format->direct.alphaMask);
263
 
        width = attr.width;
264
 
        height = attr.height;
265
 
 
266
 
        pa.subwindow_mode = IncludeInferiors; /* Don't clip child widgets */
267
 
 
268
 
        src_picture = XRenderCreatePicture (display, window, format, CPSubwindowMode, &pa);
269
 
 
270
 
        pixmap = XCreatePixmap (display,
271
 
                                window,
272
 
                                width, height,
273
 
                                attr.depth);
274
 
 
275
 
        dst_picture = XRenderCreatePicture (display, pixmap, format, 0, 0);
276
 
        XRenderComposite (display,
277
 
                          has_alpha ? PictOpOver : PictOpSrc,
278
 
                          src_picture,
279
 
                          None,
280
 
                          dst_picture,
281
 
                          0, 0, 0, 0,
282
 
                          0, 0,
283
 
                          width, height);
284
 
 
285
 
        if (widthp != NULL) {
286
 
                *widthp = width;
287
 
        }
288
 
        if (heightp != NULL) {
289
 
                *heightp = height;
290
 
        }
291
 
 
292
 
        return pixmap;
293
 
}
294
 
 
295
 
#endif /* HAVE_COMPOSITE */
296
 
 
297
 
static GdkPixbuf *
298
 
get_pixbuf_for_window (GdkDisplay *gdkdisplay,
299
 
                       guint       xid,
300
 
                       int         thumb_width,
301
 
                       int         thumb_height)
302
 
{
303
 
        GdkPixbuf *pixbuf = NULL;
304
 
#ifdef HAVE_XRENDER
305
 
        Display   *display;
306
 
        Window     xwindow;
307
 
        Pixmap     xpixmap;
308
 
        int        width;
309
 
        int        height;
310
 
 
311
 
        display = GDK_DISPLAY_XDISPLAY (gdkdisplay);
312
 
        xwindow = (Window) xid;
313
 
 
314
 
        xpixmap = get_pixmap_for_window (display, xwindow, &width, &height);
315
 
 
316
 
        if (xpixmap == None) {
317
 
                g_debug ("GsmInhibitDialog: Unable to get window snapshot for %u", xid);
318
 
                return NULL;
319
 
        } else {
320
 
                g_debug ("GsmInhibitDialog: Got xpixmap %u", (guint)xpixmap);
321
 
        }
322
 
 
323
 
        pixbuf = pixbuf_get_from_pixmap (display, xpixmap, width, height);
324
 
 
325
 
        if (xpixmap != None) {
326
 
                gdk_x11_display_error_trap_push (gdkdisplay);
327
 
                XFreePixmap (display, xpixmap);
328
 
                gdk_x11_display_error_trap_pop_ignored (gdkdisplay);
329
 
        }
330
 
 
331
 
        if (pixbuf != NULL) {
332
 
                GdkPixbuf *scaled;
333
 
                g_debug ("GsmInhibitDialog: scaling pixbuf to w=%d h=%d", width, height);
334
 
                scaled = scale_pixbuf (pixbuf, thumb_width, thumb_height, TRUE);
335
 
                g_object_unref (pixbuf);
336
 
                pixbuf = scaled;
337
 
        }
338
 
#else
339
 
        g_debug ("GsmInhibitDialog: no support for getting window snapshot");
340
 
#endif
341
 
        return pixbuf;
342
 
}
343
 
 
344
 
static void
345
 
add_inhibitor (GsmInhibitDialog *dialog,
346
 
               GsmInhibitor     *inhibitor)
347
 
{
348
 
        GdkDisplay     *gdkdisplay;
349
 
        const char     *name;
350
 
        const char     *app_id;
351
 
        char           *desktop_filename;
352
 
        GdkPixbuf      *pixbuf;
353
 
        GDesktopAppInfo *app_info;
354
 
        GKeyFile        *keyfile;
355
 
        GIcon           *gicon;
356
 
        char          **search_dirs;
357
 
        guint           xid;
358
 
        char           *freeme;
359
 
 
360
 
        gdkdisplay = gtk_widget_get_display (GTK_WIDGET (dialog));
361
 
 
362
 
        /* FIXME: get info from xid */
363
 
 
364
 
        app_info = NULL;
365
 
        name = NULL;
366
 
        pixbuf = NULL;
367
 
        freeme = NULL;
368
 
 
369
 
        app_id = gsm_inhibitor_peek_app_id (inhibitor);
370
 
 
371
 
        if (IS_STRING_EMPTY (app_id)) {
372
 
                desktop_filename = NULL;
373
 
        } else if (! g_str_has_suffix (app_id, ".desktop")) {
374
 
                desktop_filename = g_strdup_printf ("%s.desktop", app_id);
375
 
        } else {
376
 
                desktop_filename = g_strdup (app_id);
377
 
        }
378
 
 
379
 
        xid = gsm_inhibitor_peek_toplevel_xid (inhibitor);
380
 
        g_debug ("GsmInhibitDialog: inhibitor has XID %u", xid);
381
 
        if (xid > 0 && dialog->priv->have_xrender) {
382
 
                pixbuf = get_pixbuf_for_window (gdkdisplay, xid, DEFAULT_SNAPSHOT_SIZE, DEFAULT_SNAPSHOT_SIZE);
383
 
                if (pixbuf == NULL) {
384
 
                        g_debug ("GsmInhibitDialog: unable to read pixbuf from %u", xid);
385
 
                }
386
 
        }
387
 
 
388
 
        if (desktop_filename != NULL) {
389
 
                search_dirs = gsm_util_get_desktop_dirs (TRUE, FALSE);
390
 
 
391
 
                if (g_path_is_absolute (desktop_filename)) {
392
 
                        char *basename;
393
 
 
394
 
                        app_info = g_desktop_app_info_new_from_filename (desktop_filename);
395
 
                        if (app_info == NULL) {
396
 
                                g_warning ("Unable to load desktop file '%s'",
397
 
                                            desktop_filename);
398
 
 
399
 
                                basename = g_path_get_basename (desktop_filename);
400
 
                                g_free (desktop_filename);
401
 
                                desktop_filename = basename;
402
 
                        }
403
 
                }
404
 
 
405
 
                if (app_info == NULL) {
406
 
                        keyfile = g_key_file_new ();
407
 
                        if (g_key_file_load_from_dirs (keyfile, desktop_filename, (const gchar **)search_dirs, NULL, 0, NULL))
408
 
                                app_info = g_desktop_app_info_new_from_keyfile (keyfile);
409
 
                        g_key_file_free (keyfile);
410
 
                }
411
 
 
412
 
                /* look for a file with a vendor prefix */
413
 
                if (app_info == NULL) {
414
 
                        g_warning ("Unable to find desktop file '%s'",
415
 
                                   desktop_filename);
416
 
                        g_free (desktop_filename);
417
 
                        desktop_filename = g_strdup_printf ("gnome-%s.desktop", app_id);
418
 
                        keyfile = g_key_file_new ();
419
 
                        if (g_key_file_load_from_dirs (keyfile, desktop_filename, (const gchar **)search_dirs, NULL, 0, NULL))
420
 
                                app_info = g_desktop_app_info_new_from_keyfile (keyfile);
421
 
                        g_key_file_free (keyfile);
422
 
                }
423
 
                g_strfreev (search_dirs);
424
 
 
425
 
                if (app_info == NULL) {
426
 
                        g_warning ("Unable to find desktop file '%s'",
427
 
                                   desktop_filename);
428
 
                } else {
429
 
                        name = g_app_info_get_name (G_APP_INFO (app_info));
430
 
                        gicon = g_app_info_get_icon (G_APP_INFO (app_info));
431
 
 
432
 
                        if (pixbuf == NULL) {
433
 
                                GtkIconInfo *info;
434
 
                                info = gtk_icon_theme_lookup_by_gicon (gtk_icon_theme_get_default (),
435
 
                                                                       gicon,
436
 
                                                                       DEFAULT_ICON_SIZE,
437
 
                                                                       0);
438
 
                                pixbuf = gtk_icon_info_load_icon (info, NULL);
439
 
                                gtk_icon_info_free (info);
440
 
                        }
441
 
                }
442
 
        }
443
 
 
444
 
        /* try client info */
445
 
        if (name == NULL) {
446
 
                const char *client_id;
447
 
                client_id = gsm_inhibitor_peek_client_id (inhibitor);
448
 
                if (! IS_STRING_EMPTY (client_id)) {
449
 
                        GsmClient *client;
450
 
                        client = GSM_CLIENT (gsm_store_lookup (dialog->priv->clients, client_id));
451
 
                        if (client != NULL) {
452
 
                                freeme = gsm_client_get_app_name (client);
453
 
                                name = freeme;
454
 
                        }
455
 
                }
456
 
        }
457
 
 
458
 
        if (name == NULL) {
459
 
                if (! IS_STRING_EMPTY (app_id)) {
460
 
                        name = app_id;
461
 
                } else {
462
 
                        name = _("Unknown");
463
 
                }
464
 
        }
465
 
 
466
 
        if (pixbuf == NULL) {
467
 
                GtkIconInfo *info;
468
 
                info = gtk_icon_theme_lookup_icon (gtk_icon_theme_get_default (),
469
 
                                                   GSM_ICON_INHIBITOR_DEFAULT,
470
 
                                                   DEFAULT_ICON_SIZE,
471
 
                                                   0);
472
 
                pixbuf = gtk_icon_info_load_icon (info, NULL);
473
 
                gtk_icon_info_free (info);
474
 
        }
475
 
 
476
 
        gtk_list_store_insert_with_values (dialog->priv->list_store,
477
 
                                           NULL, 0,
478
 
                                           INHIBIT_IMAGE_COLUMN, pixbuf,
479
 
                                           INHIBIT_NAME_COLUMN, name,
480
 
                                           INHIBIT_REASON_COLUMN, gsm_inhibitor_peek_reason (inhibitor),
481
 
                                           INHIBIT_ID_COLUMN, gsm_inhibitor_peek_id (inhibitor),
482
 
                                           -1);
483
 
 
484
 
        g_free (desktop_filename);
485
 
        g_free (freeme);
486
 
        g_clear_object (&pixbuf);
487
 
        g_clear_object (&app_info);
488
 
}
489
 
 
490
 
static gboolean
491
 
model_has_one_entry (GtkTreeModel *model)
492
 
{
493
 
        guint n_rows;
494
 
 
495
 
        n_rows = gtk_tree_model_iter_n_children (model, NULL);
496
 
        g_debug ("Model has %d rows", n_rows);
497
 
 
498
 
        return (n_rows > 0 && n_rows < 2);
499
 
}
500
 
 
501
 
static void
502
 
update_dialog_text (GsmInhibitDialog *dialog)
503
 
{
504
 
        const char *description_text;
505
 
        const char *header_text;
506
 
        GtkWidget  *widget;
507
 
 
508
 
        if (model_has_one_entry (GTK_TREE_MODEL (dialog->priv->list_store))) {
509
 
                g_debug ("Found one entry in model");
510
 
                header_text = _("A program is still running:");
511
 
                description_text = _("Waiting for the program to finish. Interrupting the program may cause you to lose work.");
512
 
        } else {
513
 
                g_debug ("Found multiple entries (or none) in model");
514
 
                header_text = _("Some programs are still running:");
515
 
                description_text = _("Waiting for programs to finish. Interrupting these programs may cause you to lose work.");
516
 
        }
517
 
 
518
 
        widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->xml,
519
 
                                                     "header-label"));
520
 
        if (widget != NULL) {
521
 
                char *markup;
522
 
                markup = g_strdup_printf ("<b>%s</b>", header_text);
523
 
                gtk_label_set_markup (GTK_LABEL (widget), markup);
524
 
                g_free (markup);
525
 
        }
526
 
 
527
 
        widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->xml,
528
 
                                                     "description-label"));
529
 
        if (widget != NULL) {
530
 
                gtk_label_set_text (GTK_LABEL (widget), description_text);
531
 
        }
532
 
}
533
 
 
534
 
static void
535
 
on_store_inhibitor_added (GsmStore          *store,
536
 
                          const char        *id,
537
 
                          GsmInhibitDialog  *dialog)
538
 
{
539
 
        GsmInhibitor *inhibitor;
540
 
        GtkTreeIter   iter;
541
 
 
542
 
        g_debug ("GsmInhibitDialog: inhibitor added: %s", id);
543
 
 
544
 
        if (dialog->priv->is_done) {
545
 
                return;
546
 
        }
547
 
 
548
 
        inhibitor = (GsmInhibitor *)gsm_store_lookup (store, id);
549
 
 
550
 
        /* Add to model */
551
 
        if (! find_inhibitor (dialog, id, &iter)) {
552
 
                add_inhibitor (dialog, inhibitor);
553
 
                update_dialog_text (dialog);
554
 
        }
555
 
 
556
 
}
557
 
 
558
 
static void
559
 
on_store_inhibitor_removed (GsmStore          *store,
560
 
                            const char        *id,
561
 
                            GsmInhibitDialog  *dialog)
562
 
{
563
 
        GtkTreeIter   iter;
564
 
 
565
 
        g_debug ("GsmInhibitDialog: inhibitor removed: %s", id);
566
 
 
567
 
        if (dialog->priv->is_done) {
568
 
                return;
569
 
        }
570
 
 
571
 
        /* Remove from model */
572
 
        if (find_inhibitor (dialog, id, &iter)) {
573
 
                gtk_list_store_remove (dialog->priv->list_store, &iter);
574
 
                update_dialog_text (dialog);
575
 
        }
576
 
 
577
 
        /* if there are no inhibitors left then trigger response */
578
 
        if (! gtk_tree_model_get_iter_first (GTK_TREE_MODEL (dialog->priv->list_store), &iter)) {
579
 
                gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
580
 
        }
581
 
}
582
 
 
583
 
static void
584
 
gsm_inhibit_dialog_set_inhibitor_store (GsmInhibitDialog *dialog,
585
 
                                        GsmStore         *store)
586
 
{
587
 
        g_return_if_fail (GSM_IS_INHIBIT_DIALOG (dialog));
588
 
 
589
 
        if (store != NULL) {
590
 
                g_object_ref (store);
591
 
        }
592
 
 
593
 
        if (dialog->priv->inhibitors != NULL) {
594
 
                g_signal_handlers_disconnect_by_func (dialog->priv->inhibitors,
595
 
                                                      on_store_inhibitor_added,
596
 
                                                      dialog);
597
 
                g_signal_handlers_disconnect_by_func (dialog->priv->inhibitors,
598
 
                                                      on_store_inhibitor_removed,
599
 
                                                      dialog);
600
 
 
601
 
                g_object_unref (dialog->priv->inhibitors);
602
 
        }
603
 
 
604
 
 
605
 
        g_debug ("GsmInhibitDialog: setting store %p", store);
606
 
 
607
 
        dialog->priv->inhibitors = store;
608
 
 
609
 
        if (dialog->priv->inhibitors != NULL) {
610
 
                g_signal_connect (dialog->priv->inhibitors,
611
 
                                  "added",
612
 
                                  G_CALLBACK (on_store_inhibitor_added),
613
 
                                  dialog);
614
 
                g_signal_connect (dialog->priv->inhibitors,
615
 
                                  "removed",
616
 
                                  G_CALLBACK (on_store_inhibitor_removed),
617
 
                                  dialog);
618
 
        }
619
 
}
620
 
 
621
 
static void
622
 
gsm_inhibit_dialog_set_client_store (GsmInhibitDialog *dialog,
623
 
                                     GsmStore         *store)
624
 
{
625
 
        g_return_if_fail (GSM_IS_INHIBIT_DIALOG (dialog));
626
 
 
627
 
        if (store != NULL) {
628
 
                g_object_ref (store);
629
 
        }
630
 
 
631
 
        if (dialog->priv->clients != NULL) {
632
 
                g_object_unref (dialog->priv->clients);
633
 
        }
634
 
 
635
 
        dialog->priv->clients = store;
636
 
}
637
 
 
638
 
static void
639
 
gsm_inhibit_dialog_set_property (GObject        *object,
640
 
                                 guint           prop_id,
641
 
                                 const GValue   *value,
642
 
                                 GParamSpec     *pspec)
643
 
{
644
 
        GsmInhibitDialog *dialog = GSM_INHIBIT_DIALOG (object);
645
 
 
646
 
        switch (prop_id) {
647
 
        case PROP_ACTION:
648
 
                gsm_inhibit_dialog_set_action (dialog, g_value_get_int (value));
649
 
                break;
650
 
        case PROP_INHIBITOR_STORE:
651
 
                gsm_inhibit_dialog_set_inhibitor_store (dialog, g_value_get_object (value));
652
 
                break;
653
 
        case PROP_CLIENT_STORE:
654
 
                gsm_inhibit_dialog_set_client_store (dialog, g_value_get_object (value));
655
 
                break;
656
 
        default:
657
 
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
658
 
                break;
659
 
        }
660
 
}
661
 
 
662
 
static void
663
 
gsm_inhibit_dialog_get_property (GObject        *object,
664
 
                                 guint           prop_id,
665
 
                                 GValue         *value,
666
 
                                 GParamSpec     *pspec)
667
 
{
668
 
        GsmInhibitDialog *dialog = GSM_INHIBIT_DIALOG (object);
669
 
 
670
 
        switch (prop_id) {
671
 
        case PROP_ACTION:
672
 
                g_value_set_int (value, dialog->priv->action);
673
 
                break;
674
 
        case PROP_INHIBITOR_STORE:
675
 
                g_value_set_object (value, dialog->priv->inhibitors);
676
 
                break;
677
 
        case PROP_CLIENT_STORE:
678
 
                g_value_set_object (value, dialog->priv->clients);
679
 
                break;
680
 
        default:
681
 
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
682
 
                break;
683
 
        }
684
 
}
685
 
 
686
 
static void
687
 
name_cell_data_func (GtkTreeViewColumn *tree_column,
688
 
                     GtkCellRenderer   *cell,
689
 
                     GtkTreeModel      *model,
690
 
                     GtkTreeIter       *iter,
691
 
                     GsmInhibitDialog  *dialog)
692
 
{
693
 
        char    *name;
694
 
        char    *reason;
695
 
        char    *markup;
696
 
 
697
 
        name = NULL;
698
 
        reason = NULL;
699
 
        gtk_tree_model_get (model,
700
 
                            iter,
701
 
                            INHIBIT_NAME_COLUMN, &name,
702
 
                            INHIBIT_REASON_COLUMN, &reason,
703
 
                            -1);
704
 
 
705
 
        markup = g_strdup_printf ("<b>%s</b>\n"
706
 
                                  "<span size=\"small\">%s</span>",
707
 
                                  name ? name : "(null)",
708
 
                                  reason ? reason : "(null)");
709
 
 
710
 
        g_free (name);
711
 
        g_free (reason);
712
 
 
713
 
        g_object_set (cell, "markup", markup, NULL);
714
 
        g_free (markup);
715
 
}
716
 
 
717
 
static gboolean
718
 
add_to_model (const char       *id,
719
 
              GsmInhibitor     *inhibitor,
720
 
              GsmInhibitDialog *dialog)
721
 
{
722
 
        add_inhibitor (dialog, inhibitor);
723
 
        return FALSE;
724
 
}
725
 
 
726
 
static void
727
 
populate_model (GsmInhibitDialog *dialog)
728
 
{
729
 
        gsm_store_foreach_remove (dialog->priv->inhibitors,
730
 
                                  (GsmStoreFunc)add_to_model,
731
 
                                  dialog);
732
 
        update_dialog_text (dialog);
733
 
}
734
 
 
735
 
static void
736
 
setup_dialog (GsmInhibitDialog *dialog)
737
 
{
738
 
        const char        *button_text;
739
 
        GtkWidget         *treeview;
740
 
        GtkTreeViewColumn *column;
741
 
        GtkCellRenderer   *renderer;
742
 
 
743
 
        switch (dialog->priv->action) {
744
 
        case GSM_LOGOUT_ACTION_SWITCH_USER:
745
 
                button_text = _("Switch User Anyway");
746
 
                break;
747
 
        case GSM_LOGOUT_ACTION_LOGOUT:
748
 
                button_text = _("Log Out Anyway");
749
 
                break;
750
 
        case GSM_LOGOUT_ACTION_SLEEP:
751
 
                button_text = _("Suspend Anyway");
752
 
                break;
753
 
        case GSM_LOGOUT_ACTION_HIBERNATE:
754
 
                button_text = _("Hibernate Anyway");
755
 
                break;
756
 
        case GSM_LOGOUT_ACTION_SHUTDOWN:
757
 
                button_text = _("Shut Down Anyway");
758
 
                break;
759
 
        case GSM_LOGOUT_ACTION_REBOOT:
760
 
                button_text = _("Restart Anyway");
761
 
                break;
762
 
        default:
763
 
                g_assert_not_reached ();
764
 
                break;
765
 
        }
766
 
 
767
 
        gtk_dialog_add_button (GTK_DIALOG (dialog),
768
 
                               _("Lock Screen"),
769
 
                               DIALOG_RESPONSE_LOCK_SCREEN);
770
 
        gtk_dialog_add_button (GTK_DIALOG (dialog),
771
 
                               _("Cancel"),
772
 
                               GTK_RESPONSE_CANCEL);
773
 
        gtk_dialog_add_button (GTK_DIALOG (dialog),
774
 
                               button_text,
775
 
                               GTK_RESPONSE_ACCEPT);
776
 
        g_signal_connect (dialog,
777
 
                          "response",
778
 
                          G_CALLBACK (on_response),
779
 
                          dialog);
780
 
 
781
 
        dialog->priv->list_store = gtk_list_store_new (NUMBER_OF_COLUMNS,
782
 
                                                       GDK_TYPE_PIXBUF,
783
 
                                                       G_TYPE_STRING,
784
 
                                                       G_TYPE_STRING,
785
 
                                                       G_TYPE_STRING);
786
 
 
787
 
        treeview = GTK_WIDGET (gtk_builder_get_object (dialog->priv->xml,
788
 
                                                       "inhibitors-treeview"));
789
 
        gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
790
 
        gtk_tree_view_set_model (GTK_TREE_VIEW (treeview),
791
 
                                 GTK_TREE_MODEL (dialog->priv->list_store));
792
 
 
793
 
        /* IMAGE COLUMN */
794
 
        renderer = gtk_cell_renderer_pixbuf_new ();
795
 
        column = gtk_tree_view_column_new ();
796
 
        gtk_tree_view_column_pack_start (column, renderer, FALSE);
797
 
        gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
798
 
 
799
 
        gtk_tree_view_column_set_attributes (column,
800
 
                                             renderer,
801
 
                                             "pixbuf", INHIBIT_IMAGE_COLUMN,
802
 
                                             NULL);
803
 
 
804
 
        g_object_set (renderer, "xalign", 1.0, NULL);
805
 
 
806
 
        /* NAME COLUMN */
807
 
        renderer = gtk_cell_renderer_text_new ();
808
 
        column = gtk_tree_view_column_new ();
809
 
        gtk_tree_view_column_pack_start (column, renderer, FALSE);
810
 
        gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
811
 
        gtk_tree_view_column_set_cell_data_func (column,
812
 
                                                 renderer,
813
 
                                                 (GtkTreeCellDataFunc) name_cell_data_func,
814
 
                                                 dialog,
815
 
                                                 NULL);
816
 
 
817
 
        gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (treeview),
818
 
                                          INHIBIT_REASON_COLUMN);
819
 
 
820
 
        populate_model (dialog);
821
 
}
822
 
 
823
 
static GObject *
824
 
gsm_inhibit_dialog_constructor (GType                  type,
825
 
                                guint                  n_construct_properties,
826
 
                                GObjectConstructParam *construct_properties)
827
 
{
828
 
        GsmInhibitDialog *dialog;
829
 
#ifdef HAVE_XRENDER
830
 
        GdkDisplay *gdkdisplay;
831
 
#endif /* HAVE_XRENDER */
832
 
 
833
 
        dialog = GSM_INHIBIT_DIALOG (G_OBJECT_CLASS (gsm_inhibit_dialog_parent_class)->constructor (type,
834
 
                                                                                                                  n_construct_properties,
835
 
                                                                                                                  construct_properties));
836
 
 
837
 
#ifdef HAVE_XRENDER
838
 
        gdkdisplay = gdk_display_get_default ();
839
 
 
840
 
        gdk_x11_display_error_trap_push (gdkdisplay);
841
 
        if (XRenderQueryExtension (GDK_DISPLAY_XDISPLAY (gdkdisplay), &dialog->priv->xrender_event_base, &dialog->priv->xrender_error_base)) {
842
 
                g_debug ("GsmInhibitDialog: Initialized XRender extension");
843
 
                dialog->priv->have_xrender = TRUE;
844
 
        } else {
845
 
                g_debug ("GsmInhibitDialog: Unable to initialize XRender extension");
846
 
                dialog->priv->have_xrender = FALSE;
847
 
        }
848
 
        gdk_display_sync (gdkdisplay);
849
 
        gdk_x11_display_error_trap_pop_ignored (gdkdisplay);
850
 
#endif /* HAVE_XRENDER */
851
 
 
852
 
        /* FIXME: turn this on when it is ready */
853
 
        dialog->priv->have_xrender = FALSE;
854
 
 
855
 
        setup_dialog (dialog);
856
 
 
857
 
        gtk_widget_show_all (GTK_WIDGET (dialog));
858
 
 
859
 
        return G_OBJECT (dialog);
860
 
}
861
 
 
862
 
static void
863
 
gsm_inhibit_dialog_dispose (GObject *object)
864
 
{
865
 
        GsmInhibitDialog *dialog;
866
 
 
867
 
        g_return_if_fail (object != NULL);
868
 
        g_return_if_fail (GSM_IS_INHIBIT_DIALOG (object));
869
 
 
870
 
        dialog = GSM_INHIBIT_DIALOG (object);
871
 
 
872
 
        g_debug ("GsmInhibitDialog: dispose called");
873
 
 
874
 
        g_clear_object (&dialog->priv->list_store);
875
 
 
876
 
        if (dialog->priv->inhibitors != NULL) {
877
 
                g_signal_handlers_disconnect_by_func (dialog->priv->inhibitors,
878
 
                                                      on_store_inhibitor_added,
879
 
                                                      dialog);
880
 
                g_signal_handlers_disconnect_by_func (dialog->priv->inhibitors,
881
 
                                                      on_store_inhibitor_removed,
882
 
                                                      dialog);
883
 
 
884
 
                g_clear_object (&dialog->priv->inhibitors);
885
 
        }
886
 
 
887
 
        g_clear_object (&dialog->priv->xml);
888
 
 
889
 
        G_OBJECT_CLASS (gsm_inhibit_dialog_parent_class)->dispose (object);
890
 
}
891
 
 
892
 
static void
893
 
gsm_inhibit_dialog_class_init (GsmInhibitDialogClass *klass)
894
 
{
895
 
        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
896
 
 
897
 
        object_class->get_property = gsm_inhibit_dialog_get_property;
898
 
        object_class->set_property = gsm_inhibit_dialog_set_property;
899
 
        object_class->constructor = gsm_inhibit_dialog_constructor;
900
 
        object_class->dispose = gsm_inhibit_dialog_dispose;
901
 
 
902
 
        g_object_class_install_property (object_class,
903
 
                                         PROP_ACTION,
904
 
                                         g_param_spec_int ("action",
905
 
                                                           "action",
906
 
                                                           "action",
907
 
                                                           -1,
908
 
                                                           G_MAXINT,
909
 
                                                           -1,
910
 
                                                           G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
911
 
        g_object_class_install_property (object_class,
912
 
                                         PROP_INHIBITOR_STORE,
913
 
                                         g_param_spec_object ("inhibitor-store",
914
 
                                                              NULL,
915
 
                                                              NULL,
916
 
                                                              GSM_TYPE_STORE,
917
 
                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
918
 
        g_object_class_install_property (object_class,
919
 
                                         PROP_CLIENT_STORE,
920
 
                                         g_param_spec_object ("client-store",
921
 
                                                              NULL,
922
 
                                                              NULL,
923
 
                                                              GSM_TYPE_STORE,
924
 
                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
925
 
 
926
 
        g_type_class_add_private (klass, sizeof (GsmInhibitDialogPrivate));
927
 
}
928
 
 
929
 
static void
930
 
gsm_inhibit_dialog_init (GsmInhibitDialog *dialog)
931
 
{
932
 
        GtkWidget *content_area;
933
 
        GtkWidget *widget;
934
 
        GError    *error;
935
 
 
936
 
        dialog->priv = GSM_INHIBIT_DIALOG_GET_PRIVATE (dialog);
937
 
 
938
 
        dialog->priv->xml = gtk_builder_new ();
939
 
        gtk_builder_set_translation_domain (dialog->priv->xml, GETTEXT_PACKAGE);
940
 
 
941
 
        error = NULL;
942
 
        if (!gtk_builder_add_from_file (dialog->priv->xml,
943
 
                                        GTKBUILDER_DIR "/" GTKBUILDER_FILE,
944
 
                                        &error)) {
945
 
                if (error) {
946
 
                        g_warning ("Could not load inhibitor UI file: %s",
947
 
                                   error->message);
948
 
                        g_error_free (error);
949
 
                } else {
950
 
                        g_warning ("Could not load inhibitor UI file.");
951
 
                }
952
 
        }
953
 
 
954
 
        content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
955
 
        widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->xml,
956
 
                                                     "main-box"));
957
 
        gtk_container_add (GTK_CONTAINER (content_area), widget);
958
 
 
959
 
        gtk_container_set_border_width (GTK_CONTAINER (dialog), 6);
960
 
        gtk_window_set_icon_name (GTK_WINDOW (dialog), GSM_ICON_LOGOUT);
961
 
        gtk_window_set_title (GTK_WINDOW (dialog), "");
962
 
        g_object_set (dialog,
963
 
                      "resizable", FALSE,
964
 
                      NULL);
965
 
}
966
 
 
967
 
GtkWidget *
968
 
gsm_inhibit_dialog_new (GsmStore *inhibitors,
969
 
                        GsmStore *clients,
970
 
                        int       action)
971
 
{
972
 
        GObject *object;
973
 
 
974
 
        object = g_object_new (GSM_TYPE_INHIBIT_DIALOG,
975
 
                               "action", action,
976
 
                               "inhibitor-store", inhibitors,
977
 
                               "client-store", clients,
978
 
                               NULL);
979
 
 
980
 
        return GTK_WIDGET (object);
981
 
}