[gnome-panel/end-session-dialog] Add end session dialog



commit d6f339b529f383c0998c2371d9791685314d290f
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Sat Jun 7 18:33:46 2014 +0300

    Add end session dialog

 Makefile.am                                        |    1 +
 configure.ac                                       |    7 +
 data/gnome-flashback.session.desktop.in            |    2 +-
 end-session-dialog/Makefile.am                     |    5 +
 end-session-dialog/data/Makefile.am                |   18 +
 .../gnome-flashback-end-session-dialog.desktop.in  |    5 +
 end-session-dialog/data/gsm-inhibit-dialog.ui      |   63 ++
 end-session-dialog/src/Makefile.am                 |   35 +
 end-session-dialog/src/inhibit-dialog.c            | 1165 ++++++++++++++++++++
 end-session-dialog/src/inhibit-dialog.h            |   67 ++
 end-session-dialog/src/main.c                      |  141 +++
 .../org.gnome.SessionManager.EndSessionDialog.xml  |   53 +
 12 files changed, 1561 insertions(+), 1 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 23e1543..bc02df5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,6 +1,7 @@
 SUBDIRS =                      \
        gnome-panel             \
        libpanel-applet         \
+       end-session-dialog \
        applets                 \
        doc                     \
        help                    \
diff --git a/configure.ac b/configure.ac
index 64aef07..e234728 100644
--- a/configure.ac
+++ b/configure.ac
@@ -99,6 +99,10 @@ PKG_CHECK_MODULES(PANEL, gmodule-2.0 >= $GLIB_REQUIRED
 AC_SUBST(PANEL_CFLAGS)
 AC_SUBST(PANEL_LIBS)
 
+PKG_CHECK_MODULES(END_SESSION_DIALOG, gtk+-3.0 >= $GTK_REQUIRED)
+AC_SUBST(END_SESSION_DIALOG_CFLAGS)
+AC_SUBST(END_SESSION_DIALOG_LIBS)
+
 AC_ARG_ENABLE(telepathy_glib, AS_HELP_STRING([--enable-telepathy-glib],[Enable telepathy-glib support 
(auto)]),enable_telepathy_glib=$enableval,enable_telepathy_glib=auto)
 if test "x$enable_telepathy_glib" = "xno" ; then
   HAVE_TELEPATHY_GLIB=no
@@ -336,6 +340,9 @@ applets/wncklet/Makefile
 doc/Makefile
 doc/reference/Makefile
 doc/reference/panel-applet/Makefile
+end-session-dialog/Makefile
+end-session-dialog/data/Makefile
+end-session-dialog/src/Makefile
 help/Makefile
 help/clock/Makefile
 help/fish/Makefile
diff --git a/data/gnome-flashback.session.desktop.in b/data/gnome-flashback.session.desktop.in
index 5ba2d46..2e7e1a5 100644
--- a/data/gnome-flashback.session.desktop.in
+++ b/data/gnome-flashback.session.desktop.in
@@ -1,3 +1,3 @@
 [GNOME Session]
 _Name=GNOME Flashback (Metacity)
-RequiredComponents=gnome-panel;gnome-settings-daemon;gnome-screensaver;metacity;
+RequiredComponents=gnome-panel;gnome-settings-daemon;gnome-screensaver;metacity;gnome-flashback-end-session-dialog;
diff --git a/end-session-dialog/Makefile.am b/end-session-dialog/Makefile.am
new file mode 100644
index 0000000..97a836c
--- /dev/null
+++ b/end-session-dialog/Makefile.am
@@ -0,0 +1,5 @@
+SUBDIRS = \
+       data \
+       src
+
+-include $(top_srcdir)/git.mk
diff --git a/end-session-dialog/data/Makefile.am b/end-session-dialog/data/Makefile.am
new file mode 100644
index 0000000..ba34054
--- /dev/null
+++ b/end-session-dialog/data/Makefile.am
@@ -0,0 +1,18 @@
+uidir = $(pkgdatadir)
+ui_DATA = \
+       gsm-inhibit-dialog.ui
+
+desktopdir       = $(datadir)/applications
+desktop_in_files = gnome-flashback-end-session-dialog.desktop.in
+desktop_DATA     = $(desktop_in_files:.desktop.in=.desktop)
+
+ INTLTOOL_DESKTOP_RULE@
+
+EXTRA_DIST = \
+       $(desktop_in_files) \
+       $(ui_DATA)
+
+CLEANFILES = \
+       $(desktop_DATA)
+
+-include $(top_srcdir)/git.mk
diff --git a/end-session-dialog/data/gnome-flashback-end-session-dialog.desktop.in 
b/end-session-dialog/data/gnome-flashback-end-session-dialog.desktop.in
new file mode 100644
index 0000000..0bab104
--- /dev/null
+++ b/end-session-dialog/data/gnome-flashback-end-session-dialog.desktop.in
@@ -0,0 +1,5 @@
+[Desktop Entry]
+Type=Application
+Name=GNOME Flashback End Session Dialog
+Exec=gnome-flashback-end-session-dialog
+OnlyShowIn=GNOME;
diff --git a/end-session-dialog/data/gsm-inhibit-dialog.ui b/end-session-dialog/data/gsm-inhibit-dialog.ui
new file mode 100644
index 0000000..588caa1
--- /dev/null
+++ b/end-session-dialog/data/gsm-inhibit-dialog.ui
@@ -0,0 +1,63 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy toplevel-contextual -->
+  <object class="GtkVBox" id="main-box">
+    <property name="visible">True</property>
+    <property name="border_width">6</property>
+    <property name="orientation">vertical</property>
+    <property name="spacing">6</property>
+    <child>
+      <object class="GtkLabel" id="header-label">
+        <property name="visible">True</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">Some programs are still running:</property>
+        <property name="wrap">True</property>
+        <attributes>
+          <attribute name="weight" value="bold"/>
+        </attributes>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">False</property>
+        <property name="position">0</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkScrolledWindow" id="scrolledwindow1">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="hscrollbar_policy">automatic</property>
+        <property name="vscrollbar_policy">automatic</property>
+        <property name="shadow_type">in</property>
+        <child>
+          <object class="GtkTreeView" id="inhibitors-treeview">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="headers_visible">False</property>
+            <property name="enable_search">False</property>
+            <property name="show_expanders">False</property>
+          </object>
+        </child>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">False</property>
+        <property name="position">1</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="description-label">
+        <property name="visible">True</property>
+        <property name="xalign">0</property>
+        <property name="yalign">0</property>
+        <property name="margin-bottom">18</property>
+        <property name="label" translatable="yes">Waiting for the program to finish.  Interrupting the 
program may cause you to lose work.</property>
+        <property name="wrap">True</property>
+      </object>
+      <packing>
+        <property name="position">2</property>
+      </packing>
+    </child>
+  </object>
+</interface>
diff --git a/end-session-dialog/src/Makefile.am b/end-session-dialog/src/Makefile.am
new file mode 100644
index 0000000..0c8f22b
--- /dev/null
+++ b/end-session-dialog/src/Makefile.am
@@ -0,0 +1,35 @@
+bin_PROGRAMS = gnome-flashback-end-session-dialog
+
+AM_CPPFLAGS = \
+       -I$(top_builddir)/end-session-dialog \
+       -I$(top_builddir)/gnome-panel/libegg \
+       -DGTKBUILDER_DIR=\""$(pkgdatadir)"\" \
+       $(END_SESSION_DIALOG_CFLAGS)
+
+gnome_flashback_end_session_dialog_SOURCES = \
+       main.c \
+       inhibit-dialog.c \
+       inhibit-dialog.h \
+       end-session-dialog-generated.c \
+       end-session-dialog-generated.h
+
+gnome_flashback_end_session_dialog_LDADD = \
+       $(top_builddir)/gnome-panel/libegg/libegg.la \
+       $(END_SESSION_DIALOG_LIBS)
+
+end-session-dialog-generated.h:
+end-session-dialog-generated.c: org.gnome.SessionManager.EndSessionDialog.xml Makefile.am
+       $(AM_V_GEN) gdbus-codegen \
+               --interface-prefix=org.gnome.SessionManager \
+               --generate-c-code end-session-dialog-generated \
+               --c-namespace Gsm \
+               org.gnome.SessionManager.EndSessionDialog.xml
+
+BUILT_SOURCES = \
+       end-session-dialog-generated.h \
+       end-session-dialog-generated.c
+
+CLEANFILES = \
+       $(BUILT_SOURCES)
+
+-include $(top_srcdir)/git.mk
diff --git a/end-session-dialog/src/inhibit-dialog.c b/end-session-dialog/src/inhibit-dialog.c
new file mode 100644
index 0000000..157326c
--- /dev/null
+++ b/end-session-dialog/src/inhibit-dialog.c
@@ -0,0 +1,1165 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 William Jon McCann <mccann jhu edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include <cairo-xlib.h>
+
+#include "inhibit-dialog.h"
+#include "eggdesktopfile.h"
+/*#include "gsm-client.h"
+#include "gsm-icon-names.h"
+#include "gsm-util.h"*/
+
+#ifdef HAVE_XRENDER
+#include <X11/extensions/Xrender.h>
+#endif
+
+#define IS_STRING_EMPTY(x) ((x)==NULL||(x)[0]=='\0')
+
+#define GSM_INHIBIT_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_INHIBIT_DIALOG, 
GsmInhibitDialogPrivate))
+
+#define GTKBUILDER_FILE "gsm-inhibit-dialog.ui"
+
+#ifndef DEFAULT_ICON_SIZE
+#define DEFAULT_ICON_SIZE 32
+#endif
+
+#ifndef DEFAULT_SNAPSHOT_SIZE
+#define DEFAULT_SNAPSHOT_SIZE 128
+#endif
+
+#define DIALOG_RESPONSE_LOCK_SCREEN 1
+
+#define GSM_ICON_COMPUTER_FAIL       "computer-fail-symbolic"
+#define GSM_ICON_INHIBITOR_DEFAULT   "gnome-windows"
+#define GSM_ICON_LOGOUT              "system-log-out"
+#define GSM_ICON_SHUTDOWN            "system-shutdown"
+#define GSM_ICON_XSMP_DEFAULT        "system-run"
+
+struct GsmInhibitDialogPrivate
+{
+        GtkBuilder        *xml;
+        int                action;
+        int                timeout;
+        guint              timeout_id;
+        gboolean           is_done;
+        const char *const *inhibitor_paths;
+        GtkListStore      *list_store;
+        gboolean           have_xrender;
+        int                xrender_event_base;
+        int                xrender_error_base;
+};
+
+enum {
+        PROP_0,
+        PROP_ACTION,
+        PROP_TIMEOUT,
+        PROP_INHIBITOR_PATHS
+};
+
+enum {
+        INHIBIT_IMAGE_COLUMN = 0,
+        INHIBIT_NAME_COLUMN,
+        INHIBIT_REASON_COLUMN,
+        INHIBIT_ID_COLUMN,
+        INHIBIT_PROXY_COLUMN,
+        NUMBER_OF_COLUMNS
+};
+
+static void     gsm_inhibit_dialog_class_init  (GsmInhibitDialogClass *klass);
+static void     gsm_inhibit_dialog_init        (GsmInhibitDialog      *inhibit_dialog);
+static void     gsm_inhibit_dialog_finalize    (GObject               *object);
+
+G_DEFINE_TYPE (GsmInhibitDialog, gsm_inhibit_dialog, GTK_TYPE_DIALOG)
+
+static void
+lock_screen (GsmInhibitDialog *dialog)
+{
+        GError *error;
+        error = NULL;
+        g_spawn_command_line_async ("gnome-screensaver-command --lock", &error);
+        if (error != NULL) {
+                g_warning ("Couldn't lock screen: %s", error->message);
+                g_error_free (error);
+        }
+}
+
+static void
+on_response (GsmInhibitDialog *dialog,
+             gint              response_id)
+
+{
+        if (dialog->priv->is_done) {
+                g_signal_stop_emission_by_name (dialog, "response");
+                return;
+        }
+
+        switch (response_id) {
+        case DIALOG_RESPONSE_LOCK_SCREEN:
+                g_signal_stop_emission_by_name (dialog, "response");
+                lock_screen (dialog);
+                break;
+        default:
+                dialog->priv->is_done = TRUE;
+                break;
+        }
+}
+
+static void
+gsm_inhibit_dialog_set_action (GsmInhibitDialog *dialog,
+                               int               action)
+{
+        dialog->priv->action = action;
+}
+
+static void
+gsm_inhibit_dialog_set_timeout (GsmInhibitDialog *dialog,
+                                int               timeout)
+{
+        dialog->priv->timeout = timeout;
+}
+
+static void
+gsm_inhibit_dialog_set_inhibitor_paths (GsmInhibitDialog  *dialog,
+                                        const char *const *paths)
+{
+        dialog->priv->inhibitor_paths = (const char *const*)g_strdupv ((gchar **)paths);
+}
+
+/* copied from gnome-panel panel-util.c */
+static char *
+_util_icon_remove_extension (const char *icon)
+{
+        char *icon_no_extension;
+        char *p;
+
+        icon_no_extension = g_strdup (icon);
+        p = strrchr (icon_no_extension, '.');
+        if (p &&
+            (strcmp (p, ".png") == 0 ||
+             strcmp (p, ".xpm") == 0 ||
+             strcmp (p, ".svg") == 0)) {
+            *p = 0;
+        }
+
+        return icon_no_extension;
+}
+
+/* copied from gnome-panel panel-util.c */
+static char *
+_find_icon (GtkIconTheme  *icon_theme,
+            const char    *icon_name,
+            gint           size)
+{
+        GtkIconInfo *info;
+        char        *retval;
+        char        *icon_no_extension;
+
+        if (icon_name == NULL || strcmp (icon_name, "") == 0)
+                return NULL;
+
+        if (g_path_is_absolute (icon_name)) {
+                if (g_file_test (icon_name, G_FILE_TEST_EXISTS)) {
+                        return g_strdup (icon_name);
+                } else {
+                        char *basename;
+
+                        basename = g_path_get_basename (icon_name);
+                        retval = _find_icon (icon_theme, basename,
+                                             size);
+                        g_free (basename);
+
+                        return retval;
+                }
+        }
+
+        // This is needed because some .desktop files have an icon name *and*
+        // an extension as icon
+        icon_no_extension = _util_icon_remove_extension (icon_name);
+
+        info = gtk_icon_theme_lookup_icon (icon_theme, icon_no_extension,
+                                           size, 0);
+
+        g_free (icon_no_extension);
+
+        if (info) {
+                retval = g_strdup (gtk_icon_info_get_filename (info));
+                g_object_unref (info);
+        } else
+                retval = NULL;
+
+        return retval;
+}
+
+/* copied from gnome-panel panel-util.c */
+static GdkPixbuf *
+_load_icon (GtkIconTheme  *icon_theme,
+            const char    *icon_name,
+            int            size,
+            int            desired_width,
+            int            desired_height,
+            char         **error_msg)
+{
+        GdkPixbuf *retval;
+        char      *file;
+        GError    *error;
+
+        g_return_val_if_fail (error_msg == NULL || *error_msg == NULL, NULL);
+
+        file = _find_icon (icon_theme, icon_name, size);
+        if (!file) {
+                if (error_msg)
+                        *error_msg = g_strdup_printf (_("Icon '%s' not found"),
+                                                      icon_name);
+
+                return NULL;
+        }
+
+        error = NULL;
+        retval = gdk_pixbuf_new_from_file_at_size (file,
+                                                   desired_width,
+                                                   desired_height,
+                                                   &error);
+        if (error) {
+                if (error_msg)
+                        *error_msg = g_strdup (error->message);
+                g_error_free (error);
+        }
+
+        g_free (file);
+
+        return retval;
+}
+
+static GdkPixbuf *
+scale_pixbuf (GdkPixbuf *pixbuf,
+              int        max_width,
+              int        max_height,
+              gboolean   no_stretch_hint)
+{
+        int        pw;
+        int        ph;
+        float      scale_factor_x = 1.0;
+        float      scale_factor_y = 1.0;
+        float      scale_factor = 1.0;
+
+        pw = gdk_pixbuf_get_width (pixbuf);
+        ph = gdk_pixbuf_get_height (pixbuf);
+
+        /* Determine which dimension requires the smallest scale. */
+        scale_factor_x = (float) max_width / (float) pw;
+        scale_factor_y = (float) max_height / (float) ph;
+
+        if (scale_factor_x > scale_factor_y) {
+                scale_factor = scale_factor_y;
+        } else {
+                scale_factor = scale_factor_x;
+        }
+
+        /* always scale down, allow to disable scaling up */
+        if (scale_factor < 1.0 || !no_stretch_hint) {
+                int scale_x = (int) (pw * scale_factor);
+                int scale_y = (int) (ph * scale_factor);
+                g_debug ("Scaling to %dx%d", scale_x, scale_y);
+                return gdk_pixbuf_scale_simple (pixbuf,
+                                                scale_x,
+                                                scale_y,
+                                                GDK_INTERP_BILINEAR);
+        } else {
+                return g_object_ref (pixbuf);
+        }
+}
+
+#ifdef HAVE_XRENDER
+
+static GdkPixbuf *
+pixbuf_get_from_pixmap (Display *display,
+                        Pixmap   xpixmap,
+                        int      width,
+                        int      height)
+{
+        cairo_surface_t *surface;
+        GdkPixbuf       *retval;
+        Visual          *visual;
+
+        retval = NULL;
+
+        visual = DefaultVisual (display, 0);
+        g_debug ("GsmInhibitDialog: getting foreign pixmap for %u", (guint)xpixmap);
+        surface = cairo_xlib_surface_create (display,
+                                             xpixmap,
+                                             visual,
+                                             width,
+                                             height);
+        if (surface != NULL) {
+                g_debug ("GsmInhibitDialog: getting pixbuf w=%d h=%d", width, height);
+                retval = gdk_pixbuf_get_from_surface (surface,
+                                                      0, 0,
+                                                      width, height);
+        }
+
+        if (surface) {
+                cairo_surface_destroy (surface);
+        }
+
+        return retval;
+}
+
+static Pixmap
+get_pixmap_for_window (Display *display,
+                       Window   window,
+                       int     *widthp,
+                       int     *heightp)
+{
+        XWindowAttributes        attr;
+        XRenderPictureAttributes pa;
+        Pixmap                   pixmap;
+        XRenderPictFormat       *format;
+        Picture                  src_picture;
+        Picture                  dst_picture;
+        gboolean                 has_alpha;
+        int                      width;
+        int                      height;
+
+        XGetWindowAttributes (display, window, &attr);
+
+        format = XRenderFindVisualFormat (display, attr.visual);
+        has_alpha = (format->type == PictTypeDirect && format->direct.alphaMask);
+        width = attr.width;
+        height = attr.height;
+
+        pa.subwindow_mode = IncludeInferiors; /* Don't clip child widgets */
+
+        src_picture = XRenderCreatePicture (display, window, format, CPSubwindowMode, &pa);
+
+        pixmap = XCreatePixmap (display,
+                                window,
+                                width, height,
+                                attr.depth);
+
+        dst_picture = XRenderCreatePicture (display, pixmap, format, 0, 0);
+        XRenderComposite (display,
+                          has_alpha ? PictOpOver : PictOpSrc,
+                          src_picture,
+                          None,
+                          dst_picture,
+                          0, 0, 0, 0,
+                          0, 0,
+                          width, height);
+
+        if (widthp != NULL) {
+                *widthp = width;
+        }
+        if (heightp != NULL) {
+                *heightp = height;
+        }
+
+        return pixmap;
+}
+
+#endif /* HAVE_COMPOSITE */
+
+static GdkPixbuf *
+get_pixbuf_for_window (GdkDisplay *gdkdisplay,
+                       guint       xid,
+                       int         thumb_width,
+                       int         thumb_height)
+{
+        GdkPixbuf *pixbuf = NULL;
+#ifdef HAVE_XRENDER
+        Display   *display;
+        Window     xwindow;
+        Pixmap     xpixmap;
+        int        width;
+        int        height;
+
+        display = GDK_DISPLAY_XDISPLAY (gdkdisplay);
+        xwindow = (Window) xid;
+
+        xpixmap = get_pixmap_for_window (display, xwindow, &width, &height);
+
+        if (xpixmap == None) {
+                g_debug ("GsmInhibitDialog: Unable to get window snapshot for %u", xid);
+                return NULL;
+        } else {
+                g_debug ("GsmInhibitDialog: Got xpixmap %u", (guint)xpixmap);
+        }
+
+        pixbuf = pixbuf_get_from_pixmap (display, xpixmap, width, height);
+
+        if (xpixmap != None) {
+                gdk_x11_display_error_trap_push (gdkdisplay);
+                XFreePixmap (display, xpixmap);
+                gdk_x11_display_error_trap_pop_ignored (gdkdisplay);
+        }
+
+        if (pixbuf != NULL) {
+                GdkPixbuf *scaled;
+                g_debug ("GsmInhibitDialog: scaling pixbuf to w=%d h=%d", width, height);
+                scaled = scale_pixbuf (pixbuf, thumb_width, thumb_height, TRUE);
+                g_object_unref (pixbuf);
+                pixbuf = scaled;
+        }
+#else
+        g_debug ("GsmInhibitDialog: no support for getting window snapshot");
+#endif
+        return pixbuf;
+}
+
+static gchar *
+inhibitor_get_app_id (GDBusProxy *proxy)
+{
+        GError *error = NULL;
+        GVariant *res;
+        gchar *app_id;
+
+        res = g_dbus_proxy_call_sync (proxy, "GetAppId", NULL, 0, G_MAXINT, NULL, &error);
+        if (res == NULL) {
+                g_warning ("Failed to get Inhibitor app id: %s", error->message);
+                g_error_free (error);
+                return NULL;
+        }
+        g_variant_get (res, "(s)", &app_id);
+        g_variant_unref (res);
+
+        return app_id;
+}
+
+static gchar *
+inhibitor_get_reason (GDBusProxy *proxy)
+{
+        GError *error = NULL;
+        GVariant *res;
+        gchar *reason;
+
+        res = g_dbus_proxy_call_sync (proxy, "GetReason", NULL, 0, G_MAXINT, NULL, &error);
+        if (res == NULL) {
+                g_warning ("Failed to get Inhibitor reason: %s", error->message);
+                g_error_free (error);
+                return NULL;
+        }
+        g_variant_get (res, "(s)", &reason);
+        g_variant_unref (res);
+
+        return reason;
+}
+
+static guint
+inhibitor_get_xid (GDBusProxy *proxy)
+{
+        GError *error = NULL;
+        GVariant *res;
+        guint xid;
+
+        res = g_dbus_proxy_call_sync (proxy, "GetToplevelXid", NULL, 0, G_MAXINT, NULL, &error);
+        if (res == NULL) {
+                g_warning ("Failed to get Inhibitor xid: %s", error->message);
+                g_error_free (error);
+                return 0;
+        }
+        g_variant_get (res, "(u)", &xid);
+        g_variant_unref (res);
+
+        return xid;
+}
+static void
+add_inhibitor (GsmInhibitDialog *dialog,
+               GDBusProxy       *inhibitor)
+{
+        GdkDisplay     *gdkdisplay;
+        const char     *name;
+        const char     *icon_name;
+        char           *app_id;
+        char           *desktop_filename;
+        GdkPixbuf      *pixbuf;
+        EggDesktopFile *desktop_file;
+        GError         *error;
+        char          **search_dirs;
+        guint           xid;
+        char           *freeme;
+        gchar          *reason;
+
+        gdkdisplay = gtk_widget_get_display (GTK_WIDGET (dialog));
+
+        // FIXME: get info from xid
+
+        desktop_file = NULL;
+        name = NULL;
+        pixbuf = NULL;
+        freeme = NULL;
+
+        app_id = inhibitor_get_app_id (inhibitor);
+        reason = inhibitor_get_reason (inhibitor);
+        xid = inhibitor_get_xid (inhibitor);
+
+        if (IS_STRING_EMPTY (app_id)) {
+                desktop_filename = NULL;
+        } else if (! g_str_has_suffix (app_id, ".desktop")) {
+                desktop_filename = g_strdup_printf ("%s.desktop", app_id);
+        } else {
+                desktop_filename = g_strdup (app_id);
+        }
+
+        g_debug ("GsmInhibitDialog: inhibitor has XID %u", xid);
+        if (xid > 0 && dialog->priv->have_xrender) {
+                pixbuf = get_pixbuf_for_window (gdkdisplay, xid, DEFAULT_SNAPSHOT_SIZE, 
DEFAULT_SNAPSHOT_SIZE);
+                if (pixbuf == NULL) {
+                        g_debug ("GsmInhibitDialog: unable to read pixbuf from %u", xid);
+                }
+        }
+
+        if (desktop_filename != NULL) {
+                /*search_dirs = gsm_util_get_desktop_dirs (TRUE, FALSE);
+
+                if (g_path_is_absolute (desktop_filename)) {
+                        char *basename;
+
+                        error = NULL;
+                        desktop_file = egg_desktop_file_new (desktop_filename,
+                                                             &error);
+                        if (desktop_file == NULL) {
+                                if (error) {
+                                        g_warning ("Unable to load desktop file '%s': %s",
+                                                   desktop_filename, error->message);
+                                        g_error_free (error);
+                                } else {
+                                        g_warning ("Unable to load desktop file '%s'",
+                                                   desktop_filename);
+                                }
+
+                                basename = g_path_get_basename (desktop_filename);
+                                g_free (desktop_filename);
+                                desktop_filename = basename;
+                        }
+                }
+
+                if (desktop_file == NULL) {
+                        error = NULL;
+                        desktop_file = egg_desktop_file_new_from_dirs (desktop_filename,
+                                                                       (const char **)search_dirs,
+                                                                       &error);
+                }
+
+                // look for a file with a vendor prefix
+                if (desktop_file == NULL) {
+                        if (error) {
+                                g_warning ("Unable to find desktop file '%s': %s",
+                                           desktop_filename, error->message);
+                                g_error_free (error);
+                        } else {
+                                g_warning ("Unable to find desktop file '%s'",
+                                           desktop_filename);
+                        }
+                        g_free (desktop_filename);
+                        desktop_filename = g_strdup_printf ("gnome-%s.desktop", app_id);
+                        error = NULL;
+                        desktop_file = egg_desktop_file_new_from_dirs (desktop_filename,
+                                                                       (const char **)search_dirs,
+                                                                       &error);
+                }
+                g_strfreev (search_dirs);*/
+
+                if (desktop_file == NULL) {
+                        if (error) {
+                                g_warning ("Unable to find desktop file '%s': %s",
+                                           desktop_filename, error->message);
+                                g_error_free (error);
+                        } else {
+                                g_warning ("Unable to find desktop file '%s'",
+                                           desktop_filename);
+                        }
+                } else {
+                        name = egg_desktop_file_get_name (desktop_file);
+                        icon_name = egg_desktop_file_get_icon (desktop_file);
+
+                        if (pixbuf == NULL) {
+                                pixbuf = _load_icon (gtk_icon_theme_get_default (),
+                                                     icon_name,
+                                                     DEFAULT_ICON_SIZE,
+                                                     DEFAULT_ICON_SIZE,
+                                                     DEFAULT_ICON_SIZE,
+                                                     NULL);
+                        }
+                }
+        }
+
+        if (name == NULL) {
+                if (! IS_STRING_EMPTY (app_id)) {
+                        name = app_id;
+                } else {
+                        name = _("Unknown");
+                }
+        }
+
+        if (pixbuf == NULL) {
+                pixbuf = _load_icon (gtk_icon_theme_get_default (),
+                                     GSM_ICON_INHIBITOR_DEFAULT,
+                                     DEFAULT_ICON_SIZE,
+                                     DEFAULT_ICON_SIZE,
+                                     DEFAULT_ICON_SIZE,
+                                     NULL);
+        }
+
+        gtk_list_store_insert_with_values (dialog->priv->list_store,
+                                           NULL, 0,
+                                           INHIBIT_IMAGE_COLUMN, pixbuf,
+                                           INHIBIT_NAME_COLUMN, name,
+                                           INHIBIT_REASON_COLUMN, reason,
+                                           INHIBIT_ID_COLUMN, g_dbus_proxy_get_object_path (inhibitor),
+                                           INHIBIT_PROXY_COLUMN, inhibitor,
+                                           -1);
+
+        g_free (desktop_filename);
+        g_free (freeme);
+        g_clear_object (&pixbuf);
+        g_clear_pointer (&desktop_file, egg_desktop_file_free);
+
+        g_free (app_id);
+        g_free (reason);
+}
+
+static gboolean
+model_is_empty (GtkTreeModel *model)
+{
+        gint n;
+
+        n = gtk_tree_model_iter_n_children (model, NULL);
+        g_print ("model rows: %d\n", n);
+        return n == 0;
+}
+
+static void gsm_inhibit_dialog_start_timer (GsmInhibitDialog *dialog);
+static void gsm_inhibit_dialog_stop_timer (GsmInhibitDialog *dialog);
+
+static void
+update_dialog_text (GsmInhibitDialog *dialog)
+{
+        const char *header_text;
+        gchar *description_text;
+        GtkWidget  *widget;
+        gchar *title;
+        const gchar *user;
+        gchar *markup;
+        gboolean inhibited;
+        gint seconds;
+
+        user = g_get_real_name ();
+        inhibited = !model_is_empty (GTK_TREE_MODEL (dialog->priv->list_store));
+
+        g_print ("update dialog text: inhibited %d\n", inhibited);
+
+        if (inhibited) {
+                gsm_inhibit_dialog_stop_timer (dialog);
+        }
+        else {
+                gsm_inhibit_dialog_start_timer (dialog);
+        }
+
+        if (dialog->priv->timeout <= 30) {
+                seconds = dialog->priv->timeout;
+        } else {
+                seconds = (dialog->priv->timeout / 10) * 10;
+                if (dialog->priv->timeout % 10) {
+                        seconds += 10;
+                }
+        }
+
+        if (dialog->priv->action == GSM_LOGOUT_ACTION_LOGOUT) {
+                title = g_strdup_printf (_("Log Out %s"), user);
+                if (inhibited) {
+                        header_text = _("Some applications are still running:");
+                        description_text = g_strdup (_("Click Log Out to quit these applications and log out 
of the system."));
+                } else {
+                        header_text = NULL;
+                        description_text = g_strdup_printf (ngettext ("%s will be logged out automatically 
in %d second.",
+                                                                      "%s will be logged out automatically 
in %d seconds.", seconds), user, seconds);
+                }
+        } else if (dialog->priv->action == GSM_LOGOUT_ACTION_SHUTDOWN) {
+                title = g_strdup_printf (_("Power Off"));
+                if (inhibited) {
+                        header_text = _("Some applications are still running:");
+                        description_text = g_strdup (_("Click Power Off to quit these applications and power 
off the system."));
+                } else {
+                        header_text = NULL;
+                        description_text = g_strdup_printf (ngettext ("The system will power off 
automatically in %d second.",
+                                                                      "The system will power off 
automatically in %d seconds.", seconds), seconds);
+                }
+        } else if (dialog->priv->action == GSM_LOGOUT_ACTION_REBOOT) {
+                title = g_strdup_printf (_("Restart"));
+                if (inhibited) {
+                        header_text = _("Some applications are still running:");
+                        description_text = g_strdup (_("Click Restart to quit these applications and restart 
the system."));
+                } else {
+                        header_text = NULL;
+                        description_text = g_strdup_printf (ngettext ("The system will restart automatically 
in %d second.",
+                                                                      "The system will restart automatically 
in %d seconds.", seconds), seconds);
+                }
+        }
+        else {
+                title = g_strdup ("");
+                if (inhibited) {
+                        header_text = _("Some applications are still running:");
+                        description_text = g_strdup (_("Waiting for these application to finish.  
Interrupting them can lead to loss of data."));
+
+                } else {
+                        header_text = NULL;
+                        description_text = g_strdup_printf (ngettext ("The action will proceed automatically 
in %d second.",
+                                                                      "The action will proceed automatically 
in %d seconds.", seconds), seconds);
+                }
+        }
+
+        gtk_window_set_title (GTK_WINDOW (dialog), title);
+
+        widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->xml, "header-label"));
+        if (header_text) {
+                markup = g_strdup_printf ("<b>%s</b>", header_text);
+                gtk_label_set_markup (GTK_LABEL (widget), markup);
+                g_free (markup);
+                gtk_widget_show (widget);
+        } else {
+                gtk_widget_hide (widget);
+        }
+
+        widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->xml, "scrolledwindow1"));
+        if (inhibited) {
+                gtk_widget_show (widget);
+        } else {
+                gtk_widget_hide (widget);
+        }
+
+        widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->xml, "description-label"));
+        gtk_label_set_text (GTK_LABEL (widget), description_text);
+
+        g_free (description_text);
+        g_free (title);
+}
+
+static void
+gsm_inhibit_dialog_set_property (GObject        *object,
+                                 guint           prop_id,
+                                 const GValue   *value,
+                                 GParamSpec     *pspec)
+{
+        GsmInhibitDialog *dialog = GSM_INHIBIT_DIALOG (object);
+
+        switch (prop_id) {
+        case PROP_ACTION:
+                gsm_inhibit_dialog_set_action (dialog, g_value_get_int (value));
+                break;
+        case PROP_TIMEOUT:
+                gsm_inhibit_dialog_set_timeout (dialog, g_value_get_int (value));
+                break;
+        case PROP_INHIBITOR_PATHS:
+                gsm_inhibit_dialog_set_inhibitor_paths (dialog, g_value_get_boxed (value));
+                break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static void
+gsm_inhibit_dialog_get_property (GObject        *object,
+                                 guint           prop_id,
+                                 GValue         *value,
+                                 GParamSpec     *pspec)
+{
+        GsmInhibitDialog *dialog = GSM_INHIBIT_DIALOG (object);
+
+        switch (prop_id) {
+        case PROP_ACTION:
+                g_value_set_int (value, dialog->priv->action);
+                break;
+        case PROP_TIMEOUT:
+                g_value_set_int (value, dialog->priv->action);
+                break;
+        case PROP_INHIBITOR_PATHS:
+                g_value_set_boxed (value, dialog->priv->inhibitor_paths);
+                break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static void
+name_cell_data_func (GtkTreeViewColumn *tree_column,
+                     GtkCellRenderer   *cell,
+                     GtkTreeModel      *model,
+                     GtkTreeIter       *iter,
+                     GsmInhibitDialog  *dialog)
+{
+        char    *name;
+        char    *reason;
+        char    *markup;
+
+        name = NULL;
+        reason = NULL;
+        gtk_tree_model_get (model,
+                            iter,
+                            INHIBIT_NAME_COLUMN, &name,
+                            INHIBIT_REASON_COLUMN, &reason,
+                            -1);
+
+        markup = g_strdup_printf ("<b>%s</b>\n"
+                                  "<span size=\"small\">%s</span>",
+                                  name ? name : "(null)",
+                                  reason ? reason : "(null)");
+
+        g_free (name);
+        g_free (reason);
+
+        g_object_set (cell, "markup", markup, NULL);
+        g_free (markup);
+}
+
+static void
+on_inhibitor_created (GObject *source, GAsyncResult *res, gpointer user_data)
+{
+        GsmInhibitDialog *dialog = user_data;
+        GError *error = NULL;
+        GDBusProxy *proxy;
+
+        proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
+        if (proxy == NULL) {
+                g_warning ("Failed to create Inhibitor proxy: %s", error->message);
+                g_error_free (error);
+                return;
+        }
+
+        add_inhibitor (dialog, proxy);
+
+        g_object_unref (proxy);
+}
+
+static void
+populate_model (GsmInhibitDialog *dialog)
+{
+        gint i;
+        for (i = 0; dialog->priv->inhibitor_paths && dialog->priv->inhibitor_paths[i]; i++) {
+                g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
+                                          0,
+                                          NULL,
+                                          "org.gnome.SessionManager",
+                                          dialog->priv->inhibitor_paths[i],
+                                          "org.gnome.SessionManager.Inhibitor",
+                                          NULL,
+                                          on_inhibitor_created,
+                                          dialog);
+        }
+        update_dialog_text (dialog);
+}
+
+static void
+setup_dialog (GsmInhibitDialog *dialog)
+{
+        const char        *button_text;
+        GtkWidget         *treeview;
+        GtkTreeViewColumn *column;
+        GtkCellRenderer   *renderer;
+
+        g_print ("setting up dialog\n");
+        switch (dialog->priv->action) {
+        case GSM_LOGOUT_ACTION_SWITCH_USER:
+                button_text = _("Switch User");
+                break;
+        case GSM_LOGOUT_ACTION_LOGOUT:
+                button_text = _("Log Out");
+                break;
+        case GSM_LOGOUT_ACTION_SLEEP:
+                button_text = _("Suspend");
+                break;
+        case GSM_LOGOUT_ACTION_HIBERNATE:
+                button_text = _("Hibernate");
+                break;
+        case GSM_LOGOUT_ACTION_SHUTDOWN:
+                button_text = _("Power Off");
+                break;
+        case GSM_LOGOUT_ACTION_REBOOT:
+                button_text = _("Restart");
+                break;
+        default:
+                g_assert_not_reached ();
+                break;
+        }
+
+        gtk_dialog_add_button (GTK_DIALOG (dialog),
+                               _("Lock Screen"),
+                               DIALOG_RESPONSE_LOCK_SCREEN);
+        gtk_dialog_add_button (GTK_DIALOG (dialog),
+                               _("Cancel"),
+                               GTK_RESPONSE_CANCEL);
+        gtk_dialog_add_button (GTK_DIALOG (dialog),
+                               button_text,
+                               GTK_RESPONSE_ACCEPT);
+        g_signal_connect (dialog,
+                          "response",
+                          G_CALLBACK (on_response),
+                          dialog);
+
+        dialog->priv->list_store = gtk_list_store_new (NUMBER_OF_COLUMNS,
+                                                       GDK_TYPE_PIXBUF,
+                                                       G_TYPE_STRING,
+                                                       G_TYPE_STRING,
+                                                       G_TYPE_STRING,
+                                                       G_TYPE_OBJECT);
+        g_print ("empty model: %d\n", gtk_tree_model_iter_n_children (GTK_TREE_MODEL 
(dialog->priv->list_store), NULL));
+
+        treeview = GTK_WIDGET (gtk_builder_get_object (dialog->priv->xml,
+                                                       "inhibitors-treeview"));
+        gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
+        gtk_tree_view_set_model (GTK_TREE_VIEW (treeview),
+                                 GTK_TREE_MODEL (dialog->priv->list_store));
+
+        /* IMAGE COLUMN */
+        renderer = gtk_cell_renderer_pixbuf_new ();
+        column = gtk_tree_view_column_new ();
+        gtk_tree_view_column_pack_start (column, renderer, FALSE);
+        gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+
+        gtk_tree_view_column_set_attributes (column,
+                                             renderer,
+                                             "pixbuf", INHIBIT_IMAGE_COLUMN,
+                                             NULL);
+
+        g_object_set (renderer, "xalign", 1.0, NULL);
+
+        /* NAME COLUMN */
+        renderer = gtk_cell_renderer_text_new ();
+        column = gtk_tree_view_column_new ();
+        gtk_tree_view_column_pack_start (column, renderer, FALSE);
+        gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+        gtk_tree_view_column_set_cell_data_func (column,
+                                                 renderer,
+                                                 (GtkTreeCellDataFunc) name_cell_data_func,
+                                                 dialog,
+                                                 NULL);
+
+        gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (treeview),
+                                          INHIBIT_REASON_COLUMN);
+
+        populate_model (dialog);
+}
+
+static GObject *
+gsm_inhibit_dialog_constructor (GType                  type,
+                                guint                  n_construct_properties,
+                                GObjectConstructParam *construct_properties)
+{
+        GsmInhibitDialog *dialog;
+#ifdef HAVE_XRENDER
+        GdkDisplay *gdkdisplay;
+#endif /* HAVE_XRENDER */
+
+        dialog = GSM_INHIBIT_DIALOG (G_OBJECT_CLASS (gsm_inhibit_dialog_parent_class)->constructor (type,
+                                                                                                             
     n_construct_properties,
+                                                                                                             
     construct_properties));
+
+#ifdef HAVE_XRENDER
+        gdkdisplay = gdk_display_get_default ();
+
+        gdk_x11_display_error_trap_push (gdkdisplay);
+        if (XRenderQueryExtension (GDK_DISPLAY_XDISPLAY (gdkdisplay), &dialog->priv->xrender_event_base, 
&dialog->priv->xrender_error_base)) {
+                g_debug ("GsmInhibitDialog: Initialized XRender extension");
+                dialog->priv->have_xrender = TRUE;
+        } else {
+                g_debug ("GsmInhibitDialog: Unable to initialize XRender extension");
+                dialog->priv->have_xrender = FALSE;
+        }
+        gdk_display_sync (gdkdisplay);
+        gdk_x11_display_error_trap_pop_ignored (gdkdisplay);
+#endif /* HAVE_XRENDER */
+
+        /* FIXME: turn this on when it is ready */
+        dialog->priv->have_xrender = FALSE;
+
+        setup_dialog (dialog);
+
+        gtk_widget_show (GTK_WIDGET (dialog));
+
+        return G_OBJECT (dialog);
+}
+
+static void
+gsm_inhibit_dialog_dispose (GObject *object)
+{
+        GsmInhibitDialog *dialog = GSM_INHIBIT_DIALOG (object);
+
+        gsm_inhibit_dialog_stop_timer (dialog);
+
+        g_clear_object (&dialog->priv->list_store);
+        g_clear_object (&dialog->priv->xml);
+
+        G_OBJECT_CLASS (gsm_inhibit_dialog_parent_class)->dispose (object);
+}
+
+static gboolean
+gsm_inhibit_dialog_timeout (GsmInhibitDialog *dialog)
+{
+        if (dialog->priv->timeout == 0) {
+                gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
+                return G_SOURCE_REMOVE;
+        }
+
+        update_dialog_text (dialog);
+
+        dialog->priv->timeout--;
+
+        return G_SOURCE_CONTINUE;
+}
+
+static void
+gsm_inhibit_dialog_start_timer (GsmInhibitDialog *dialog)
+{
+        if (dialog->priv->timeout_id == 0) {
+                dialog->priv->timeout_id = g_timeout_add (1000, (GSourceFunc)gsm_inhibit_dialog_timeout, 
dialog);
+        }
+}
+
+static void
+gsm_inhibit_dialog_stop_timer (GsmInhibitDialog *dialog)
+{
+        if (dialog->priv->timeout_id != 0) {
+                g_source_remove (dialog->priv->timeout_id);
+                dialog->priv->timeout_id = 0;
+        }
+}
+
+static void
+gsm_inhibit_dialog_show (GtkWidget *widget)
+{
+        GsmInhibitDialog *dialog = GSM_INHIBIT_DIALOG (widget);
+
+        GTK_WIDGET_CLASS (gsm_inhibit_dialog_parent_class)->show (widget);
+
+        update_dialog_text (dialog);
+}
+
+static void
+gsm_inhibit_dialog_class_init (GsmInhibitDialogClass *klass)
+{
+        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
+        GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+        object_class->get_property = gsm_inhibit_dialog_get_property;
+        object_class->set_property = gsm_inhibit_dialog_set_property;
+        object_class->constructor = gsm_inhibit_dialog_constructor;
+        object_class->dispose = gsm_inhibit_dialog_dispose;
+        object_class->finalize = gsm_inhibit_dialog_finalize;
+
+        widget_class->show = gsm_inhibit_dialog_show;
+
+        g_object_class_install_property (object_class,
+                                         PROP_ACTION,
+                                         g_param_spec_int ("action",
+                                                           "action",
+                                                           "action",
+                                                           -1,
+                                                           G_MAXINT,
+                                                           -1,
+                                                           G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+        g_object_class_install_property (object_class,
+                                         PROP_TIMEOUT,
+                                         g_param_spec_int ("timeout",
+                                                           "timeout",
+                                                           "timeout",
+                                                           -1,
+                                                           G_MAXINT,
+                                                           -1,
+                                                           G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+        g_object_class_install_property (object_class,
+                                         PROP_INHIBITOR_PATHS,
+                                         g_param_spec_boxed ("inhibitor-paths",
+                                                             "inhibitor-paths",
+                                                             "inhibitor-paths",
+                                                             G_TYPE_STRV,
+                                                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+        g_type_class_add_private (klass, sizeof (GsmInhibitDialogPrivate));
+}
+
+static void
+gsm_inhibit_dialog_init (GsmInhibitDialog *dialog)
+{
+        GtkWidget *content_area;
+        GtkWidget *widget;
+        GError    *error;
+
+        dialog->priv = GSM_INHIBIT_DIALOG_GET_PRIVATE (dialog);
+
+        dialog->priv->xml = gtk_builder_new ();
+        gtk_builder_set_translation_domain (dialog->priv->xml, GETTEXT_PACKAGE);
+
+        error = NULL;
+        if (!gtk_builder_add_from_file (dialog->priv->xml,
+                                        GTKBUILDER_DIR "/" GTKBUILDER_FILE,
+                                        &error)) {
+                if (error) {
+                        g_warning ("Could not load inhibitor UI file: %s",
+                                   error->message);
+                        g_error_free (error);
+                } else {
+                        g_warning ("Could not load inhibitor UI file.");
+                }
+        }
+
+        content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+        widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->xml, "main-box"));
+        gtk_container_add (GTK_CONTAINER (content_area), widget);
+
+        gtk_container_set_border_width (GTK_CONTAINER (dialog), 6);
+        gtk_window_set_icon_name (GTK_WINDOW (dialog), GSM_ICON_LOGOUT);
+        gtk_window_set_title (GTK_WINDOW (dialog), "");
+        g_object_set (dialog, "resizable", FALSE, NULL);
+
+}
+
+static void
+gsm_inhibit_dialog_finalize (GObject *object)
+{
+        G_OBJECT_CLASS (gsm_inhibit_dialog_parent_class)->finalize (object);
+}
+
+GtkWidget *
+gsm_inhibit_dialog_new (int action,
+                        int seconds,
+                        const char *const *inhibitor_paths)
+{
+        GObject *object;
+
+        object = g_object_new (GSM_TYPE_INHIBIT_DIALOG,
+                               "action", action,
+                               "timeout", seconds,
+                               "inhibitor-paths", inhibitor_paths,
+                               NULL);
+
+        return GTK_WIDGET (object);
+}
diff --git a/end-session-dialog/src/inhibit-dialog.h b/end-session-dialog/src/inhibit-dialog.h
new file mode 100644
index 0000000..351c7cc
--- /dev/null
+++ b/end-session-dialog/src/inhibit-dialog.h
@@ -0,0 +1,67 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 William Jon McCann <mccann jhu edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef __GSM_INHIBIT_DIALOG_H
+#define __GSM_INHIBIT_DIALOG_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GSM_TYPE_INHIBIT_DIALOG         (gsm_inhibit_dialog_get_type ())
+#define GSM_INHIBIT_DIALOG(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GSM_TYPE_INHIBIT_DIALOG, 
GsmInhibitDialog))
+#define GSM_INHIBIT_DIALOG_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GSM_TYPE_INHIBIT_DIALOG, 
GsmInhibitDialogClass))
+#define GSM_IS_INHIBIT_DIALOG(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSM_TYPE_INHIBIT_DIALOG))
+#define GSM_IS_INHIBIT_DIALOG_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GSM_TYPE_INHIBIT_DIALOG))
+#define GSM_INHIBIT_DIALOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSM_TYPE_INHIBIT_DIALOG, 
GsmInhibitDialogClass))
+
+typedef struct GsmInhibitDialogPrivate GsmInhibitDialogPrivate;
+
+typedef enum
+{
+        GSM_LOGOUT_ACTION_LOGOUT,
+        GSM_LOGOUT_ACTION_SWITCH_USER,
+        GSM_LOGOUT_ACTION_SHUTDOWN,
+        GSM_LOGOUT_ACTION_REBOOT,
+        GSM_LOGOUT_ACTION_HIBERNATE,
+        GSM_LOGOUT_ACTION_SLEEP
+} GsmLogoutAction;
+
+typedef struct
+{
+        GtkDialog                parent;
+        GsmInhibitDialogPrivate *priv;
+} GsmInhibitDialog;
+
+typedef struct
+{
+        GtkDialogClass   parent_class;
+} GsmInhibitDialogClass;
+
+GType                  gsm_inhibit_dialog_get_type           (void);
+
+GtkWidget            * gsm_inhibit_dialog_new                (int action,
+                                                              int seconds,
+                                                              const char *const *inhibitor_paths);
+
+G_END_DECLS
+
+#endif /* __GSM_INHIBIT_DIALOG_H */
diff --git a/end-session-dialog/src/main.c b/end-session-dialog/src/main.c
new file mode 100644
index 0000000..12c7981
--- /dev/null
+++ b/end-session-dialog/src/main.c
@@ -0,0 +1,141 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+
+#include "inhibit-dialog.h"
+#include "end-session-dialog-generated.h"
+
+static GtkWidget *
+gsm_end_session_dialog_new (guint               action,
+                            guint               seconds,
+                            const gchar *const *inhibitor_paths)
+{
+       return gsm_inhibit_dialog_new (action, seconds, inhibitor_paths);
+}
+
+static void
+inhibit_dialog_response (GsmInhibitDialog    *dialog,
+                         guint                response_id,
+                         GsmEndSessionDialog *object)
+{
+       int action;
+
+       g_object_get (dialog, "action", &action, NULL);
+       gtk_widget_destroy (GTK_WIDGET (dialog));
+
+       switch (response_id) {
+       case GTK_RESPONSE_CANCEL:
+       case GTK_RESPONSE_NONE:
+       case GTK_RESPONSE_DELETE_EVENT:
+               if (action == GSM_LOGOUT_ACTION_LOGOUT || action == GSM_LOGOUT_ACTION_SHUTDOWN || action == 
GSM_LOGOUT_ACTION_REBOOT) {
+                       g_print ("cancel action %d\n", action);
+                       gsm_end_session_dialog_emit_canceled (object);
+                       gsm_end_session_dialog_emit_closed (object);
+               }
+               break;
+       case GTK_RESPONSE_ACCEPT:
+               g_print ("confirm action %d\n", action);
+               if (action == GSM_LOGOUT_ACTION_LOGOUT) {
+                       gsm_end_session_dialog_emit_confirmed_logout (object);
+               } else if (action == GSM_LOGOUT_ACTION_SHUTDOWN) {
+                       gsm_end_session_dialog_emit_confirmed_shutdown (object);
+               } else if (action == GSM_LOGOUT_ACTION_REBOOT) {
+                       gsm_end_session_dialog_emit_confirmed_reboot (object);
+               }
+               break;
+       default:
+               g_assert_not_reached ();
+               break;
+       }
+}
+
+static gboolean
+handle_open (GsmEndSessionDialog   *object,
+             GDBusMethodInvocation *invocation,
+             guint                  arg_type,
+             guint                  arg_timestamp,
+             guint                  arg_seconds_to_stay_open,
+             const gchar *const    *arg_inhibitor_object_paths,
+             gpointer               user_data)
+{
+       GtkWidget *dialog;
+
+       g_print ("handle open\n");
+
+       dialog = gsm_end_session_dialog_new (arg_type, arg_seconds_to_stay_open, arg_inhibitor_object_paths);
+
+       g_signal_connect (dialog, "response", G_CALLBACK (inhibit_dialog_response), object);
+
+       gtk_window_present_with_time (GTK_WINDOW (dialog), arg_timestamp);
+
+       gsm_end_session_dialog_complete_open (object, invocation);
+
+       return TRUE;
+}
+
+static void
+on_bus_acquired (GDBusConnection *connection,
+                 const gchar     *name,
+                 gpointer         user_data)
+{
+       GDBusInterfaceSkeleton *iface;
+       GError *error = NULL;
+
+       g_print ("Acquired a message bus connection\n");
+
+       iface = G_DBUS_INTERFACE_SKELETON (gsm_end_session_dialog_skeleton_new ());
+       g_signal_connect (iface, "handle-open", G_CALLBACK (handle_open), NULL);
+
+       if (!g_dbus_interface_skeleton_export (iface,
+                                              connection,
+                                              "/org/gnome/SessionManager/EndSessionDialog",
+                                              &error)) {
+               g_warning ("Failed to export interface: %s", error->message);
+               g_error_free (error);
+               return;
+       }
+}
+
+static void
+on_name_acquired (GDBusConnection *connection,
+                  const gchar     *name,
+                  gpointer         user_data)
+{
+       g_print ("Acquired the name %s\n", name);
+}
+
+static void
+on_name_lost (GDBusConnection *connection,
+              const gchar     *name,
+              gpointer         user_data)
+{
+       g_print ("Lost the name %s\n", name);
+}
+
+int
+main (int argc, char *argv[])
+{
+       guint id;
+
+       gtk_init (&argc, &argv);
+
+       id = g_bus_own_name (G_BUS_TYPE_SESSION,
+                            "org.gnome.Shell",
+                            G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
+                            G_BUS_NAME_OWNER_FLAGS_REPLACE,
+                            on_bus_acquired,
+                            on_name_acquired,
+                            on_name_lost,
+                            NULL,
+                            NULL);
+
+       gtk_main ();
+
+       g_bus_unown_name (id);
+
+       return 0;
+}
diff --git a/end-session-dialog/src/org.gnome.SessionManager.EndSessionDialog.xml 
b/end-session-dialog/src/org.gnome.SessionManager.EndSessionDialog.xml
new file mode 100644
index 0000000..5392de0
--- /dev/null
+++ b/end-session-dialog/src/org.gnome.SessionManager.EndSessionDialog.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" 
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd";>
+<node xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd";>
+  <interface name="org.gnome.SessionManager.EndSessionDialog">
+    <method name="Open">
+      <arg type="u" name="type" direction="in">
+        <doc:doc>
+          <doc:summary>
+            The type of dialog to show.
+            0 for logout, 1 for shutdown, 2 for restart.
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg type="u" name="timestamp" direction="in">
+        <doc:doc>
+          <doc:summary>
+            Timestamp of the user-initiated event which triggered
+            the call, or 0 if the call was not triggered by an event.
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg type="u" name="seconds_to_stay_open" direction="in">
+        <doc:doc>
+          <doc:summary>
+            The number of seconds which the dialog should stay open
+            before automatic action is taken.
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg type="ao" name="inhibitor_object_paths" direction="in">
+        <doc:doc>
+          <doc:summary>
+            The object paths of all inhibitors that are registered
+            for the action.
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <doc:doc>
+        <doc:summary>
+          This function opens a dialog which asks the user for confirmation
+          of a logout, poweroff or reboot action. The dialog has a timeout
+          after which the action is automatically taken, and it should show
+          the inhibitors to the user.
+        </doc:summary>
+      </doc:doc>
+    </method>
+    <signal name="ConfirmedLogout" />
+    <signal name="ConfirmedReboot" />
+    <signal name="ConfirmedShutdown" />
+    <signal name="Canceled" />
+    <signal name="Closed" />
+  </interface>
+</node>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]