[ABRT PATCH] applet: update seen list when X Session dies
Jakub Filak
jfilak at redhat.com
Mon Aug 12 11:55:56 UTC 2013
Closes rhbz#886094
Signed-off-by: Jakub Filak <jfilak at redhat.com>
---
configure.ac | 2 +
src/applet/Makefile.am | 4 ++
src/applet/applet.c | 192 +++++++++++++++++++++++++++++++++++++++++++------
3 files changed, 177 insertions(+), 21 deletions(-)
diff --git a/configure.ac b/configure.ac
index 70fafe1..97e6b76 100644
--- a/configure.ac
+++ b/configure.ac
@@ -92,6 +92,8 @@ PYTHON_LIBS=`python-config --libs 2> /dev/null`
AC_SUBST(PYTHON_CFLAGS)
AC_SUBST(PYTHON_LIBS)
+PKG_CHECK_MODULES([XICE], [ice])
+PKG_CHECK_MODULES([XSMP], [sm])
PKG_CHECK_MODULES([GTK], [gtk+-3.0])
PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.21])
PKG_CHECK_MODULES([DBUS], [dbus-1])
diff --git a/src/applet/Makefile.am b/src/applet/Makefile.am
index 2684ca5..ec50fcd 100644
--- a/src/applet/Makefile.am
+++ b/src/applet/Makefile.am
@@ -9,6 +9,8 @@ abrt_applet_CPPFLAGS = \
-DBIN_DIR=\"$(bindir)\" \
-DLIBEXEC_DIR=\"$(libexecdir)\" \
-DICON_DIR=\"${datadir}/abrt/icons/hicolor/48x48/status\" \
+ $(XICE_CFLAGS) \
+ $(XSMP_CFLAGS) \
$(GTK_CFLAGS) \
$(DBUS_CFLAGS) \
$(LIBREPORT_GTK_CFLAGS) \
@@ -23,6 +25,8 @@ abrt_applet_LDADD = \
-labrt_dbus \
-lglib-2.0 \
-lgthread-2.0 \
+ $(XICE_LIBS) \
+ $(XSMP_LIBS) \
$(DBUS_LIBS) \
$(LIBNOTIFY_LIBS) \
$(GTK_LIBS)
diff --git a/src/applet/applet.c b/src/applet/applet.c
index 91c8256..738c14e 100644
--- a/src/applet/applet.c
+++ b/src/applet/applet.c
@@ -19,6 +19,8 @@
#if HAVE_LOCALE_H
# include <locale.h>
#endif
+#include <X11/Xlib.h>
+#include <X11/SM/SMlib.h>
#include <gtk/gtk.h>
#include <libnotify/notify.h>
#include <dbus/dbus-shared.h>
@@ -1261,6 +1263,169 @@ static gboolean handle_sigterm_pipe(GIOChannel *gio, GIOCondition condition, gpo
return FALSE; /* Pointless (loop is done and signal handler was reset); "please remove this event" */
}
+/*
+ * XSMP client
+ */
+static void
+cb_smc_save_yourself(SmcConn smc_conn, SmPointer client_data, gint save_type,
+ gboolean shutdown, gint interact_style, gboolean fast)
+{
+ /* http://lesstif.sourceforge.net/doc/super-ux/g1ae04e/chap12.html#12.4.1.1 */
+ /* Since we do not save any state, we can declare that we succeeded (True) */
+ SmcSaveYourselfDone(smc_conn, True);
+}
+
+static void
+cb_smc_die(SmcConn smc_conn, SmPointer client_data)
+{
+ /* The session manager sends a Die message to a client when it wants it to
+ * die. The client should respond by calling SmcCloseConnection.
+ *
+ * http://lesstif.sourceforge.net/doc/super-ux/g1ae04e/chap12.html#12.4.1.2
+ *
+ * The reasons will most likely be NULL if resignation is expected by the
+ * client.
+ *
+ * http://lesstif.sourceforge.net/doc/super-ux/g1ae04e/chap12.html#12.4.2
+ */
+ SmcCloseConnection(smc_conn, 0 /* The number of reason messages */,
+ NULL /* The reasons for closing the connection */);
+
+ gtk_main_quit();
+}
+
+static void
+cb_smc_save_complete(SmcConn smc_conn, SmPointer client_data)
+{
+ /* No action needed */
+}
+
+static void
+cb_smc_shutdown_cancelled(SmcConn smc_conn, SmPointer client_data)
+{
+ /* Since we do not save any state, we can declare that we succeeded (True) */
+ SmcSaveYourselfDone(smc_conn, True);
+}
+
+static gboolean
+cb_ice_process_messages(GIOChannel *gio, GIOCondition condition, gpointer user_data)
+{
+ /* May return an error but we don't care, it isn't our problem */
+ IceConn ice_conn = (IceConn)user_data;
+ IceProcessMessages(ice_conn, NULL /* Indicates if a reply is being waited for */,
+ NULL /* If set to True on return, a reply is ready */);
+
+ return TRUE; /* do not remove this source */
+}
+
+/*
+ * We do not need to save any special state, we just want to be notified about
+ * session death.
+ */
+static void
+xsmp_client_connect(void)
+{
+ SmcCallbacks callbacks;
+ memset(&callbacks, 0, sizeof(callbacks));
+ callbacks.die.callback = cb_smc_die;
+ callbacks.save_yourself.callback = cb_smc_save_yourself;
+ callbacks.save_complete.callback = cb_smc_save_complete;
+ callbacks.shutdown_cancelled.callback = cb_smc_shutdown_cancelled;
+ char error_buf[256];
+ char *client_id;
+
+ SmcConn conn = SmcOpenConnection(NULL /* SESSION_MANAGER env variable */,
+ NULL /* share ICE connection */, SmProtoMajor, SmProtoMinor,
+ SmcSaveYourselfProcMask | SmcDieProcMask |
+ SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
+ &callbacks, NULL /* previous client id */,
+ &client_id, sizeof(error_buf), error_buf);
+
+ if (!conn)
+ {
+ log("Failed to open connection to session manager: %s", error_buf);
+ return;
+ }
+
+ free(client_id);
+
+ /* These 4 properties are required, however we do not need a special
+ * handling neither for restart nor for clone, because we just need to
+ * update seen problems list at exit.
+ *
+ * http://www.x.org/releases/X11R7.7/doc/libSM/xsmp.html#Predefined_Properties
+ */
+ SmProp prop_program, prop_user, prop_restart_cmd, prop_clone_cmd;
+ SmProp *prop_list[4];
+ SmPropValue val_program, val_user;
+ prop_program.name = (char *)SmProgram;
+ prop_program.type = (char *)SmARRAY8;
+ val_program.value = (char *)"abrt-applet";
+ val_program.length = (int)strlen(val_program.value);
+ prop_program.num_vals = 1;
+ prop_program.vals = &val_program;
+ prop_list[0] = &prop_program;
+
+ prop_user.name = (char *)SmUserID;
+ prop_user.type = (char *)SmARRAY8;
+
+ char userid_string[256];
+ uid_t uid = getuid();
+ struct passwd * pwd;
+ if ((pwd = getpwuid(uid)) != NULL)
+ snprintf(userid_string, sizeof(userid_string), "%s", pwd->pw_name);
+ else
+ snprintf(userid_string, sizeof(userid_string), "%d", uid);
+
+ val_user.value = (char *)userid_string;
+ val_user.length = (int) strlen(val_user.value);
+ prop_user.num_vals = 1;
+ prop_user.vals = &val_user;
+ prop_list[1] = &prop_user;
+
+ prop_restart_cmd.name = (char *)SmRestartCommand;
+ prop_restart_cmd.type = (char *)SmARRAY8;
+ prop_restart_cmd.num_vals = 1;
+ /* Use Program property */
+ prop_restart_cmd.vals = &val_program;
+ prop_list[2] = &prop_restart_cmd;
+
+ prop_clone_cmd.name = (char *)SmCloneCommand;
+ prop_clone_cmd.type = (char *)SmARRAY8;
+ prop_clone_cmd.num_vals = 1;
+ /* Use Program property */
+ prop_clone_cmd.vals = &val_program;
+ prop_list[3] = &prop_clone_cmd;
+
+ SmcSetProperties(conn, 4 /* number of properties */, prop_list);
+
+ /* The X Session Management Protocol is layered on top of the Inter-Client
+ * Exchange (ICE) Protocol.
+ *
+ * http://lesstif.sourceforge.net/doc/super-ux/g1ae04e/chap12.html#12.2
+ */
+ IceConn ice_conn = SmcGetIceConnection(conn);
+ gint fd = IceConnectionNumber(ice_conn);
+
+ /* Make sure we don't pass on these file descriptors to an
+ * exec'd child process.
+ */
+ fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
+
+ /* When a client detects that there is data to read on an ICE connection,
+ * it should call the IceProcessMessages function.
+ *
+ * http://lesstif.sourceforge.net/doc/super-ux/g1ae04e/chap12.html#12.2
+ */
+ GIOChannel *channel = g_io_channel_unix_new(fd);
+ g_io_add_watch(channel, G_IO_ERR | G_IO_HUP | G_IO_IN,
+ cb_ice_process_messages, (gpointer)ice_conn);
+ g_io_channel_unref(channel);
+}
+/*
+ * XSMP client finito
+ */
+
int main(int argc, char** argv)
{
/* I18n */
@@ -1473,10 +1638,14 @@ next:
handle_sigterm_pipe,
NULL);
+ /* Register a handler quiting from gtk main loop on X Session death.
+ */
+ xsmp_client_connect();
+
/* Enter main loop
*
- * Returns on SIGTERM signal or on menu button Quit click.
- * Please, see the comment below.
+ * Returns on SIGTERM signal, on menu button Quit click or on X Session
+ * death.
*/
gtk_main();
@@ -1484,25 +1653,6 @@ next:
ignored_problems_free(g_ignore_set);
- /* GTK3 doesn't return from main loop in case of termination due to desktop
- * session end. (GTK handles XSMP (X Session Management Protocol) messages
- * on its own and exits on session end.)
- *
- * https://bugs.freedesktop.org/show_bug.cgi?id=32839
- * https://bugzilla.gnome.org/show_bug.cgi?id=639770
- *
- * !!! None of the following commands will be executed. !!!
- *
- * The commands should be pushed into some callback used by deprecated
- * gtk_quit_add() or proposed g_flush_all()
- *
- * Or we can use proposed GtkSMClient (currently available in libegg)
- * https://live.gnome.org/SessionManagement/EggSMClient
- *
- * Or DBus GnomeSession manager (this won't work for other desktops)
- * http://people.gnome.org/~mccann/gnome-session/docs/gnome-session.html
- */
-
#if (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 31)
gdk_threads_leave();
#endif
--
1.8.3.1
More information about the Crash-catcher
mailing list