summaryrefslogtreecommitdiff
path: root/mate-session
diff options
context:
space:
mode:
authorPerberos <[email protected]>2011-12-01 23:03:59 -0300
committerPerberos <[email protected]>2011-12-01 23:03:59 -0300
commit52d7aadcc57f3fa09653d315fc1a7fef52ae6bca (patch)
tree93f7e38ac79b2592d48d22e6912aeddfd227ffab /mate-session
downloadmate-session-manager-52d7aadcc57f3fa09653d315fc1a7fef52ae6bca.tar.bz2
mate-session-manager-52d7aadcc57f3fa09653d315fc1a7fef52ae6bca.tar.xz
moving from https://github.com/perberos/mate-desktop-environment
Diffstat (limited to 'mate-session')
-rw-r--r--mate-session/Makefile.am140
-rw-r--r--mate-session/Makefile.in1158
-rw-r--r--mate-session/README65
-rw-r--r--mate-session/gs-idle-monitor.c507
-rw-r--r--mate-session/gs-idle-monitor.h75
-rw-r--r--mate-session/gsm-app.c489
-rw-r--r--mate-session/gsm-app.h136
-rw-r--r--mate-session/gsm-autostart-app.c1144
-rw-r--r--mate-session/gsm-autostart-app.h78
-rw-r--r--mate-session/gsm-client.c531
-rw-r--r--mate-session/gsm-client.h175
-rw-r--r--mate-session/gsm-consolekit.c903
-rw-r--r--mate-session/gsm-consolekit.h105
-rw-r--r--mate-session/gsm-dbus-client.c700
-rw-r--r--mate-session/gsm-dbus-client.h77
-rw-r--r--mate-session/gsm-inhibit-dialog.c1164
-rw-r--r--mate-session/gsm-inhibit-dialog.h74
-rw-r--r--mate-session/gsm-inhibitor.c605
-rw-r--r--mate-session/gsm-inhibitor.h120
-rw-r--r--mate-session/gsm-logout-dialog.c461
-rw-r--r--mate-session/gsm-logout-dialog.h77
-rw-r--r--mate-session/gsm-manager.c3481
-rw-r--r--mate-session/gsm-manager.h190
-rw-r--r--mate-session/gsm-marshal.list3
-rw-r--r--mate-session/gsm-mateconf.c143
-rw-r--r--mate-session/gsm-mateconf.h31
-rw-r--r--mate-session/gsm-presence.c550
-rw-r--r--mate-session/gsm-presence.h100
-rw-r--r--mate-session/gsm-session-save.c254
-rw-r--r--mate-session/gsm-session-save.h38
-rw-r--r--mate-session/gsm-store.c413
-rw-r--r--mate-session/gsm-store.h101
-rw-r--r--mate-session/gsm-util.c505
-rw-r--r--mate-session/gsm-util.h56
-rw-r--r--mate-session/gsm-xsmp-client.c1332
-rw-r--r--mate-session/gsm-xsmp-client.h93
-rw-r--r--mate-session/gsm-xsmp-server.c732
-rw-r--r--mate-session/gsm-xsmp-server.h62
-rw-r--r--mate-session/main.c543
-rw-r--r--mate-session/mdm-log.c206
-rw-r--r--mate-session/mdm-log.h55
-rw-r--r--mate-session/mdm-signal-handler.c553
-rw-r--r--mate-session/mdm-signal-handler.h78
-rw-r--r--mate-session/mdm.c496
-rw-r--r--mate-session/mdm.h58
-rw-r--r--mate-session/org.mate.SessionManager.App.xml43
-rw-r--r--mate-session/org.mate.SessionManager.Client.xml73
-rw-r--r--mate-session/org.mate.SessionManager.ClientPrivate.xml123
-rw-r--r--mate-session/org.mate.SessionManager.Inhibitor.xml66
-rw-r--r--mate-session/org.mate.SessionManager.Presence.xml95
-rw-r--r--mate-session/org.mate.SessionManager.xml377
-rw-r--r--mate-session/test-client-dbus.c261
-rw-r--r--mate-session/test-inhibit.c198
53 files changed, 20093 insertions, 0 deletions
diff --git a/mate-session/Makefile.am b/mate-session/Makefile.am
new file mode 100644
index 0000000..ee98a30
--- /dev/null
+++ b/mate-session/Makefile.am
@@ -0,0 +1,140 @@
+bin_PROGRAMS = mate-session
+noinst_LTLIBRARIES = libgsmutil.la
+noinst_PROGRAMS = \
+ test-client-dbus \
+ test-inhibit
+
+AM_CPPFLAGS = \
+ $(MATE_SESSION_CFLAGS) \
+ $(DISABLE_DEPRECATED_CFLAGS)
+
+AM_CFLAGS = $(WARN_CFLAGS)
+
+mate_session_SOURCES = \
+ gsm-app.h \
+ gsm-app.c \
+ gsm-autostart-app.h \
+ gsm-autostart-app.c \
+ gsm-client.c \
+ gsm-client.h \
+ gsm-xsmp-client.h \
+ gsm-xsmp-client.c \
+ gsm-dbus-client.h \
+ gsm-dbus-client.c \
+ gsm-marshal.h \
+ gsm-marshal.c \
+ gsm-consolekit.c \
+ gsm-consolekit.h \
+ gsm-logout-dialog.h \
+ gsm-logout-dialog.c \
+ gsm-inhibit-dialog.h \
+ gsm-inhibit-dialog.c \
+ gs-idle-monitor.h \
+ gs-idle-monitor.c \
+ gsm-presence.h \
+ gsm-presence.c \
+ gsm-mateconf.c \
+ gsm-mateconf.h \
+ mdm.h \
+ mdm.c \
+ mdm-signal-handler.h \
+ mdm-signal-handler.c \
+ mdm-log.h \
+ mdm-log.c \
+ main.c \
+ gsm-store.h \
+ gsm-store.c \
+ gsm-inhibitor.h \
+ gsm-inhibitor.c \
+ gsm-manager.c \
+ gsm-manager.h \
+ gsm-session-save.c \
+ gsm-session-save.h \
+ gsm-xsmp-server.c \
+ gsm-xsmp-server.h
+
+mate_session_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ $(SM_CFLAGS) \
+ $(ICE_CFLAGS) \
+ $(XEXT_CFLAGS) \
+ $(MATECONF_CFLAGS) \
+ -I$(top_srcdir)/egg \
+ -DLOCALE_DIR=\""$(datadir)/locale"\" \
+ -DDATA_DIR=\""$(datadir)/mate-session"\" \
+ -DLIBEXECDIR=\"$(libexecdir)\" \
+ -DGTKBUILDER_DIR=\""$(pkgdatadir)"\" \
+ -DMATECONF_SANITY_CHECK=\""$(MATECONF_SANITY_CHECK)"\" \
+ -DMATECONFTOOL_CMD=\"$(MATECONFTOOL)\" \
+ -DI_KNOW_THE_DEVICEKIT_POWER_API_IS_SUBJECT_TO_CHANGE
+
+mate_session_LDADD = \
+ libgsmutil.la \
+ $(top_builddir)/egg/libeggdesktopfile.la \
+ $(SM_LIBS) \
+ $(ICE_LIBS) \
+ $(XRENDER_LIBS) \
+ $(XTEST_LIBS) \
+ $(XEXT_LIBS) \
+ $(MATE_SESSION_LIBS) \
+ $(MATECONF_LIBS) \
+ $(EXECINFO_LIBS)
+
+libgsmutil_la_SOURCES = \
+ gsm-util.c \
+ gsm-util.h
+
+libgsmutil_la_LIBADD = \
+ $(MATE_SESSION_LIBS)
+
+test_inhibit_SOURCES = test-inhibit.c
+test_inhibit_LDADD = $(MATE_SESSION_LIBS)
+
+test_client_dbus_SOURCES = test-client-dbus.c
+test_client_dbus_LDADD = $(DBUS_GLIB_LIBS)
+
+gsm-marshal.c: gsm-marshal.list
+ $(AM_V_GEN)echo "#include \"gsm-marshal.h\"" > [email protected] && \
+ $(GLIB_GENMARSHAL) $< --prefix=gsm_marshal --body >> [email protected]
+
+gsm-marshal.h: gsm-marshal.list
+ $(AM_V_GEN)$(GLIB_GENMARSHAL) $< --prefix=gsm_marshal --header > [email protected]
+
+gsm-manager-glue.h: org.mate.SessionManager.xml Makefile.am
+ $(AM_V_GEN)dbus-binding-tool --prefix=gsm_manager --mode=glib-server --output=gsm-manager-glue.h $(srcdir)/org.mate.SessionManager.xml
+
+gsm-client-glue.h: org.mate.SessionManager.Client.xml Makefile.am
+ $(AM_V_GEN)dbus-binding-tool --prefix=gsm_client --mode=glib-server --output=gsm-client-glue.h $(srcdir)/org.mate.SessionManager.Client.xml
+
+gsm-app-glue.h: org.mate.SessionManager.App.xml Makefile.am
+ $(AM_V_GEN)dbus-binding-tool --prefix=gsm_app --mode=glib-server --output=gsm-app-glue.h $(srcdir)/org.mate.SessionManager.App.xml
+
+gsm-inhibitor-glue.h: org.mate.SessionManager.Inhibitor.xml Makefile.am
+ $(AM_V_GEN)dbus-binding-tool --prefix=gsm_inhibitor --mode=glib-server --output=gsm-inhibitor-glue.h $(srcdir)/org.mate.SessionManager.Inhibitor.xml
+
+gsm-presence-glue.h: org.mate.SessionManager.Presence.xml Makefile.am
+ $(AM_V_GEN)dbus-binding-tool --prefix=gsm_presence --mode=glib-server --output=gsm-presence-glue.h $(srcdir)/org.mate.SessionManager.Presence.xml
+
+BUILT_SOURCES = \
+ gsm-marshal.c \
+ gsm-marshal.h \
+ gsm-manager-glue.h \
+ gsm-presence-glue.h \
+ gsm-inhibitor-glue.h \
+ gsm-client-glue.h \
+ gsm-app-glue.h
+
+EXTRA_DIST = \
+ README \
+ gsm-marshal.list \
+ org.mate.SessionManager.xml \
+ org.mate.SessionManager.App.xml \
+ org.mate.SessionManager.Client.xml \
+ org.mate.SessionManager.ClientPrivate.xml \
+ org.mate.SessionManager.Inhibitor.xml \
+ org.mate.SessionManager.Presence.xml
+
+CLEANFILES = \
+ $(BUILT_SOURCES)
+
+-include $(top_srcdir)/git.mk
diff --git a/mate-session/Makefile.in b/mate-session/Makefile.in
new file mode 100644
index 0000000..c2a5b48
--- /dev/null
+++ b/mate-session/Makefile.in
@@ -0,0 +1,1158 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+pkgdatadir = $(datadir)/@[email protected]
+pkgincludedir = $(includedir)/@[email protected]
+pkglibdir = $(libdir)/@[email protected]
+pkglibexecdir = $(libexecdir)/@[email protected]
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @[email protected]
+host_triplet = @[email protected]
+bin_PROGRAMS = mate-session$(EXEEXT)
+noinst_PROGRAMS = test-client-dbus$(EXEEXT) test-inhibit$(EXEEXT)
+subdir = mate-session
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/intltool.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgsmutil_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am_libgsmutil_la_OBJECTS = gsm-util.lo
+libgsmutil_la_OBJECTS = $(am_libgsmutil_la_OBJECTS)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+am__installdirs = "$(DESTDIR)$(bindir)"
+PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS)
+am_mate_session_OBJECTS = mate_session-gsm-app.$(OBJEXT) \
+ mate_session-gsm-autostart-app.$(OBJEXT) \
+ mate_session-gsm-client.$(OBJEXT) \
+ mate_session-gsm-xsmp-client.$(OBJEXT) \
+ mate_session-gsm-dbus-client.$(OBJEXT) \
+ mate_session-gsm-marshal.$(OBJEXT) \
+ mate_session-gsm-consolekit.$(OBJEXT) \
+ mate_session-gsm-logout-dialog.$(OBJEXT) \
+ mate_session-gsm-inhibit-dialog.$(OBJEXT) \
+ mate_session-gs-idle-monitor.$(OBJEXT) \
+ mate_session-gsm-presence.$(OBJEXT) \
+ mate_session-gsm-mateconf.$(OBJEXT) mate_session-mdm.$(OBJEXT) \
+ mate_session-mdm-signal-handler.$(OBJEXT) \
+ mate_session-mdm-log.$(OBJEXT) mate_session-main.$(OBJEXT) \
+ mate_session-gsm-store.$(OBJEXT) \
+ mate_session-gsm-inhibitor.$(OBJEXT) \
+ mate_session-gsm-manager.$(OBJEXT) \
+ mate_session-gsm-session-save.$(OBJEXT) \
+ mate_session-gsm-xsmp-server.$(OBJEXT)
+mate_session_OBJECTS = $(am_mate_session_OBJECTS)
+mate_session_DEPENDENCIES = libgsmutil.la \
+ $(top_builddir)/egg/libeggdesktopfile.la $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am_test_client_dbus_OBJECTS = test-client-dbus.$(OBJEXT)
+test_client_dbus_OBJECTS = $(am_test_client_dbus_OBJECTS)
+test_client_dbus_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am_test_inhibit_OBJECTS = test-inhibit.$(OBJEXT)
+test_inhibit_OBJECTS = $(am_test_inhibit_OBJECTS)
+test_inhibit_DEPENDENCIES = $(am__DEPENDENCIES_1)
+DEFAULT_INCLUDES = [email protected][email protected] -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo " CC " [email protected];
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o [email protected]
+AM_V_CCLD = $(am__v_CCLD_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo " CCLD " [email protected];
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " [email protected];
+SOURCES = $(libgsmutil_la_SOURCES) $(mate_session_SOURCES) \
+ $(test_client_dbus_SOURCES) $(test_inhibit_SOURCES)
+DIST_SOURCES = $(libgsmutil_la_SOURCES) $(mate_session_SOURCES) \
+ $(test_client_dbus_SOURCES) $(test_inhibit_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @[email protected]
+ACLOCAL_AMFLAGS = @[email protected]
+ALL_LINGUAS = @[email protected]
+AM_DEFAULT_VERBOSITY = @[email protected]
+AUTOCONF = @[email protected]
+AUTOHEADER = @[email protected]
+AUTOMAKE = @[email protected]
+CATALOGS = @[email protected]
+CATOBJEXT = @[email protected]
+CCDEPMODE = @[email protected]
+CPPFLAGS = @[email protected]
+CYGPATH_W = @[email protected]
+DATADIRNAME = @[email protected]
+DBUS_GLIB_CFLAGS = @[email protected]
+DBUS_GLIB_LIBS = @[email protected]
+DEFAULT_WM = @[email protected]
+DISABLE_DEPRECATED = @[email protected]
+DISABLE_DEPRECATED_CFLAGS = @[email protected]
+DLLTOOL = @[email protected]
+DSYMUTIL = @[email protected]
+DUMPBIN = @[email protected]
+EGG_SMCLIENT_CFLAGS = @[email protected]
+EGG_SMCLIENT_LIBS = @[email protected]
+EXECINFO_LIBS = @[email protected]
+GETTEXT_PACKAGE = @[email protected]
+GLIB_GENMARSHAL = @[email protected]
+GMOFILES = @[email protected]
+GMSGFMT = @[email protected]
+HAVE_XRENDER = @[email protected]
+HAVE_XTEST = @[email protected]
+ICE_CFLAGS = @[email protected]
+ICE_LIBS = @[email protected]
+INSTALL = @[email protected]
+INSTALL_DATA = @[email protected]
+INSTALL_PROGRAM = @[email protected]
+INSTALL_SCRIPT = @[email protected]
+INSTALL_STRIP_PROGRAM = @[email protected]
+INSTOBJEXT = @[email protected]
+INTLLIBS = @[email protected]
+INTLTOOL_EXTRACT = @[email protected]
+INTLTOOL_MERGE = @[email protected]
+INTLTOOL_PERL = @[email protected]
+INTLTOOL_UPDATE = @[email protected]
+LDFLAGS = @[email protected]
+LIBOBJS = @[email protected]
+LIBTOOL = @[email protected]
+LTLIBOBJS = @[email protected]
+MAKEINFO = @[email protected]
+MANIFEST_TOOL = @[email protected]
+MATECONFTOOL = @[email protected]
+MATECONF_CFLAGS = @[email protected]
+MATECONF_LIBS = @[email protected]
+MATECONF_SANITY_CHECK = @[email protected]
+MATECONF_SCHEMA_CONFIG_SOURCE = @[email protected]
+MATECONF_SCHEMA_FILE_DIR = @[email protected]
+MATE_SESSION_CFLAGS = @[email protected]
+MATE_SESSION_LIBS = @[email protected]
+MKDIR_P = @[email protected]
+MKINSTALLDIRS = @[email protected]
+MSGFMT_OPTS = @[email protected]
+MSGMERGE = @[email protected]
+OBJDUMP = @[email protected]
+OTOOL64 = @[email protected]
+PACKAGE = @[email protected]
+PACKAGE_BUGREPORT = @[email protected]
+PACKAGE_NAME = @[email protected]
+PACKAGE_STRING = @[email protected]
+PACKAGE_TARNAME = @[email protected]
+PACKAGE_URL = @[email protected]
+PACKAGE_VERSION = @[email protected]
+PATH_SEPARATOR = @[email protected]
+PKG_CONFIG = @[email protected]
+PKG_CONFIG_LIBDIR = @[email protected]
+PKG_CONFIG_PATH = @[email protected]
+POFILES = @[email protected]
+PO_IN_DATADIR_FALSE = @[email protected]
+PO_IN_DATADIR_TRUE = @[email protected]
+REBUILD = @[email protected]
+SESSION_PROPERTIES_CFLAGS = @[email protected]
+SESSION_PROPERTIES_LIBS = @[email protected]
+SET_MAKE = @[email protected]
+SM_CFLAGS = @[email protected]
+SM_LIBS = @[email protected]
+USE_NLS = @[email protected]
+VERSION = @[email protected]
+WARN_CFLAGS = @[email protected]
+XEXT_CFLAGS = @[email protected]
+XEXT_LIBS = @[email protected]
+XGETTEXT = @[email protected]
+XRENDER_CFLAGS = @[email protected]
+XRENDER_LIBS = @[email protected]
+XSLTPROC = @[email protected]
+XTEST_CFLAGS = @[email protected]
+XTEST_LIBS = @[email protected]
+X_CFLAGS = @[email protected]
+X_EXTRA_LIBS = @[email protected]
+X_PRE_LIBS = @[email protected]
+abs_builddir = @[email protected]
+abs_srcdir = @[email protected]
+abs_top_builddir = @[email protected]
+abs_top_srcdir = @[email protected]
+ac_ct_AR = @[email protected]
+ac_ct_CC = @[email protected]
+ac_ct_DUMPBIN = @[email protected]
+am__include = @[email protected]
+am__leading_dot = @[email protected]
+am__quote = @[email protected]
+am__tar = @[email protected]
+am__untar = @[email protected]
+build_alias = @[email protected]
+build_cpu = @[email protected]
+build_os = @[email protected]
+build_vendor = @[email protected]
+builddir = @[email protected]
+datadir = @[email protected]
+datarootdir = @[email protected]
+exec_prefix = @[email protected]
+host_alias = @[email protected]
+host_cpu = @[email protected]
+host_os = @[email protected]
+host_vendor = @[email protected]
+htmldir = @[email protected]
+includedir = @[email protected]
+infodir = @[email protected]
+install_sh = @[email protected]
+libexecdir = @[email protected]
+localedir = @[email protected]
+localstatedir = @[email protected]
+mkdir_p = @[email protected]
+oldincludedir = @[email protected]
+program_transform_name = @[email protected]
+sbindir = @[email protected]
+sharedstatedir = @[email protected]
+sysconfdir = @[email protected]
+target_alias = @[email protected]
+top_build_prefix = @[email protected]
+top_builddir = @[email protected]
+top_srcdir = @[email protected]
+noinst_LTLIBRARIES = libgsmutil.la
+AM_CPPFLAGS = \
+ $(MATE_SESSION_CFLAGS) \
+ $(DISABLE_DEPRECATED_CFLAGS)
+
+AM_CFLAGS = $(WARN_CFLAGS)
+mate_session_SOURCES = \
+ gsm-app.h \
+ gsm-app.c \
+ gsm-autostart-app.h \
+ gsm-autostart-app.c \
+ gsm-client.c \
+ gsm-client.h \
+ gsm-xsmp-client.h \
+ gsm-xsmp-client.c \
+ gsm-dbus-client.h \
+ gsm-dbus-client.c \
+ gsm-marshal.h \
+ gsm-marshal.c \
+ gsm-consolekit.c \
+ gsm-consolekit.h \
+ gsm-logout-dialog.h \
+ gsm-logout-dialog.c \
+ gsm-inhibit-dialog.h \
+ gsm-inhibit-dialog.c \
+ gs-idle-monitor.h \
+ gs-idle-monitor.c \
+ gsm-presence.h \
+ gsm-presence.c \
+ gsm-mateconf.c \
+ gsm-mateconf.h \
+ mdm.h \
+ mdm.c \
+ mdm-signal-handler.h \
+ mdm-signal-handler.c \
+ mdm-log.h \
+ mdm-log.c \
+ main.c \
+ gsm-store.h \
+ gsm-store.c \
+ gsm-inhibitor.h \
+ gsm-inhibitor.c \
+ gsm-manager.c \
+ gsm-manager.h \
+ gsm-session-save.c \
+ gsm-session-save.h \
+ gsm-xsmp-server.c \
+ gsm-xsmp-server.h
+
+mate_session_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ $(SM_CFLAGS) \
+ $(ICE_CFLAGS) \
+ $(XEXT_CFLAGS) \
+ $(MATECONF_CFLAGS) \
+ -I$(top_srcdir)/egg \
+ -DLOCALE_DIR=\""$(datadir)/locale"\" \
+ -DDATA_DIR=\""$(datadir)/mate-session"\" \
+ -DLIBEXECDIR=\"$(libexecdir)\" \
+ -DGTKBUILDER_DIR=\""$(pkgdatadir)"\" \
+ -DMATECONF_SANITY_CHECK=\""$(MATECONF_SANITY_CHECK)"\" \
+ -DMATECONFTOOL_CMD=\"$(MATECONFTOOL)\" \
+ -DI_KNOW_THE_DEVICEKIT_POWER_API_IS_SUBJECT_TO_CHANGE
+
+mate_session_LDADD = \
+ libgsmutil.la \
+ $(top_builddir)/egg/libeggdesktopfile.la \
+ $(SM_LIBS) \
+ $(ICE_LIBS) \
+ $(XRENDER_LIBS) \
+ $(XTEST_LIBS) \
+ $(XEXT_LIBS) \
+ $(MATE_SESSION_LIBS) \
+ $(MATECONF_LIBS) \
+ $(EXECINFO_LIBS)
+
+libgsmutil_la_SOURCES = \
+ gsm-util.c \
+ gsm-util.h
+
+libgsmutil_la_LIBADD = \
+ $(MATE_SESSION_LIBS)
+
+test_inhibit_SOURCES = test-inhibit.c
+test_inhibit_LDADD = $(MATE_SESSION_LIBS)
+test_client_dbus_SOURCES = test-client-dbus.c
+test_client_dbus_LDADD = $(DBUS_GLIB_LIBS)
+BUILT_SOURCES = \
+ gsm-marshal.c \
+ gsm-marshal.h \
+ gsm-manager-glue.h \
+ gsm-presence-glue.h \
+ gsm-inhibitor-glue.h \
+ gsm-client-glue.h \
+ gsm-app-glue.h
+
+EXTRA_DIST = \
+ README \
+ gsm-marshal.list \
+ org.mate.SessionManager.xml \
+ org.mate.SessionManager.App.xml \
+ org.mate.SessionManager.Client.xml \
+ org.mate.SessionManager.ClientPrivate.xml \
+ org.mate.SessionManager.Inhibitor.xml \
+ org.mate.SessionManager.Presence.xml
+
+CLEANFILES = \
+ $(BUILT_SOURCES)
+
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @[email protected] $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f [email protected]; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu mate-session/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu mate-session/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/[email protected] $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/[email protected] $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @[email protected] $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @[email protected] $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgsmutil.la: $(libgsmutil_la_OBJECTS) $(libgsmutil_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libgsmutil_la_OBJECTS) $(libgsmutil_la_LIBADD) $(LIBS)
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p || test -f $$p1; \
+ then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+mate-session$(EXEEXT): $(mate_session_OBJECTS) $(mate_session_DEPENDENCIES)
+ @rm -f mate-session$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(mate_session_OBJECTS) $(mate_session_LDADD) $(LIBS)
+test-client-dbus$(EXEEXT): $(test_client_dbus_OBJECTS) $(test_client_dbus_DEPENDENCIES)
+ @rm -f test-client-dbus$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_client_dbus_OBJECTS) $(test_client_dbus_LDADD) $(LIBS)
+test-inhibit$(EXEEXT): $(test_inhibit_OBJECTS) $(test_inhibit_DEPENDENCIES)
+ @rm -f test-inhibit$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_inhibit_OBJECTS) $(test_inhibit_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+
+.c.o:
[email protected][email protected] $(AM_V_CC)$(COMPILE) -MT [email protected] -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o [email protected] $<
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+
+.c.obj:
[email protected][email protected] $(AM_V_CC)$(COMPILE) -MT [email protected] -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o [email protected] `$(CYGPATH_W) '$<'`
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
[email protected][email protected] $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
[email protected][email protected] $(AM_V_CC)$(LTCOMPILE) -MT [email protected] -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o [email protected] $<
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+
+mate_session-gsm-app.o: gsm-app.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-app.o -MD -MP -MF $(DEPDIR)/mate_session-gsm-app.Tpo -c -o mate_session-gsm-app.o `test -f 'gsm-app.c' || echo '$(srcdir)/'`gsm-app.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-app.Tpo $(DEPDIR)/mate_session-gsm-app.Po
[email protected][email protected]@[email protected] source='gsm-app.c' object='mate_session-gsm-app.o' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-app.o `test -f 'gsm-app.c' || echo '$(srcdir)/'`gsm-app.c
+
+mate_session-gsm-app.obj: gsm-app.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-app.obj -MD -MP -MF $(DEPDIR)/mate_session-gsm-app.Tpo -c -o mate_session-gsm-app.obj `if test -f 'gsm-app.c'; then $(CYGPATH_W) 'gsm-app.c'; else $(CYGPATH_W) '$(srcdir)/gsm-app.c'; fi`
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-app.Tpo $(DEPDIR)/mate_session-gsm-app.Po
[email protected][email protected]@[email protected] source='gsm-app.c' object='mate_session-gsm-app.obj' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-app.obj `if test -f 'gsm-app.c'; then $(CYGPATH_W) 'gsm-app.c'; else $(CYGPATH_W) '$(srcdir)/gsm-app.c'; fi`
+
+mate_session-gsm-autostart-app.o: gsm-autostart-app.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-autostart-app.o -MD -MP -MF $(DEPDIR)/mate_session-gsm-autostart-app.Tpo -c -o mate_session-gsm-autostart-app.o `test -f 'gsm-autostart-app.c' || echo '$(srcdir)/'`gsm-autostart-app.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-autostart-app.Tpo $(DEPDIR)/mate_session-gsm-autostart-app.Po
[email protected][email protected]@[email protected] source='gsm-autostart-app.c' object='mate_session-gsm-autostart-app.o' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-autostart-app.o `test -f 'gsm-autostart-app.c' || echo '$(srcdir)/'`gsm-autostart-app.c
+
+mate_session-gsm-autostart-app.obj: gsm-autostart-app.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-autostart-app.obj -MD -MP -MF $(DEPDIR)/mate_session-gsm-autostart-app.Tpo -c -o mate_session-gsm-autostart-app.obj `if test -f 'gsm-autostart-app.c'; then $(CYGPATH_W) 'gsm-autostart-app.c'; else $(CYGPATH_W) '$(srcdir)/gsm-autostart-app.c'; fi`
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-autostart-app.Tpo $(DEPDIR)/mate_session-gsm-autostart-app.Po
[email protected][email protected]@[email protected] source='gsm-autostart-app.c' object='mate_session-gsm-autostart-app.obj' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-autostart-app.obj `if test -f 'gsm-autostart-app.c'; then $(CYGPATH_W) 'gsm-autostart-app.c'; else $(CYGPATH_W) '$(srcdir)/gsm-autostart-app.c'; fi`
+
+mate_session-gsm-client.o: gsm-client.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-client.o -MD -MP -MF $(DEPDIR)/mate_session-gsm-client.Tpo -c -o mate_session-gsm-client.o `test -f 'gsm-client.c' || echo '$(srcdir)/'`gsm-client.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-client.Tpo $(DEPDIR)/mate_session-gsm-client.Po
[email protected][email protected]@[email protected] source='gsm-client.c' object='mate_session-gsm-client.o' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-client.o `test -f 'gsm-client.c' || echo '$(srcdir)/'`gsm-client.c
+
+mate_session-gsm-client.obj: gsm-client.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-client.obj -MD -MP -MF $(DEPDIR)/mate_session-gsm-client.Tpo -c -o mate_session-gsm-client.obj `if test -f 'gsm-client.c'; then $(CYGPATH_W) 'gsm-client.c'; else $(CYGPATH_W) '$(srcdir)/gsm-client.c'; fi`
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-client.Tpo $(DEPDIR)/mate_session-gsm-client.Po
[email protected][email protected]@[email protected] source='gsm-client.c' object='mate_session-gsm-client.obj' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-client.obj `if test -f 'gsm-client.c'; then $(CYGPATH_W) 'gsm-client.c'; else $(CYGPATH_W) '$(srcdir)/gsm-client.c'; fi`
+
+mate_session-gsm-xsmp-client.o: gsm-xsmp-client.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-xsmp-client.o -MD -MP -MF $(DEPDIR)/mate_session-gsm-xsmp-client.Tpo -c -o mate_session-gsm-xsmp-client.o `test -f 'gsm-xsmp-client.c' || echo '$(srcdir)/'`gsm-xsmp-client.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-xsmp-client.Tpo $(DEPDIR)/mate_session-gsm-xsmp-client.Po
[email protected][email protected]@[email protected] source='gsm-xsmp-client.c' object='mate_session-gsm-xsmp-client.o' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-xsmp-client.o `test -f 'gsm-xsmp-client.c' || echo '$(srcdir)/'`gsm-xsmp-client.c
+
+mate_session-gsm-xsmp-client.obj: gsm-xsmp-client.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-xsmp-client.obj -MD -MP -MF $(DEPDIR)/mate_session-gsm-xsmp-client.Tpo -c -o mate_session-gsm-xsmp-client.obj `if test -f 'gsm-xsmp-client.c'; then $(CYGPATH_W) 'gsm-xsmp-client.c'; else $(CYGPATH_W) '$(srcdir)/gsm-xsmp-client.c'; fi`
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-xsmp-client.Tpo $(DEPDIR)/mate_session-gsm-xsmp-client.Po
[email protected][email protected]@[email protected] source='gsm-xsmp-client.c' object='mate_session-gsm-xsmp-client.obj' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-xsmp-client.obj `if test -f 'gsm-xsmp-client.c'; then $(CYGPATH_W) 'gsm-xsmp-client.c'; else $(CYGPATH_W) '$(srcdir)/gsm-xsmp-client.c'; fi`
+
+mate_session-gsm-dbus-client.o: gsm-dbus-client.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-dbus-client.o -MD -MP -MF $(DEPDIR)/mate_session-gsm-dbus-client.Tpo -c -o mate_session-gsm-dbus-client.o `test -f 'gsm-dbus-client.c' || echo '$(srcdir)/'`gsm-dbus-client.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-dbus-client.Tpo $(DEPDIR)/mate_session-gsm-dbus-client.Po
[email protected][email protected]@[email protected] source='gsm-dbus-client.c' object='mate_session-gsm-dbus-client.o' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-dbus-client.o `test -f 'gsm-dbus-client.c' || echo '$(srcdir)/'`gsm-dbus-client.c
+
+mate_session-gsm-dbus-client.obj: gsm-dbus-client.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-dbus-client.obj -MD -MP -MF $(DEPDIR)/mate_session-gsm-dbus-client.Tpo -c -o mate_session-gsm-dbus-client.obj `if test -f 'gsm-dbus-client.c'; then $(CYGPATH_W) 'gsm-dbus-client.c'; else $(CYGPATH_W) '$(srcdir)/gsm-dbus-client.c'; fi`
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-dbus-client.Tpo $(DEPDIR)/mate_session-gsm-dbus-client.Po
[email protected][email protected]@[email protected] source='gsm-dbus-client.c' object='mate_session-gsm-dbus-client.obj' libtool=no @[email protected]
[email protected][email protected]@[email protected] DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPB[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-dbus-client.obj `if test -f 'gsm-dbus-client.c'; then $(CYGPATH_W) 'gsm-dbus-client.c'; else $(CYGPATH_W) '$(srcdir)/gsm-dbus-client.c'; fi`
+
+mate_session-gsm-marshal.o: gsm-marshal.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-marshal.o -MD -MP -MF $(DEPDIR)/mate_session-gsm-marshal.Tpo -c -o mate_session-gsm-marshal.o `test -f 'gsm-marshal.c' || echo '$(srcdir)/'`gsm-marshal.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-marshal.Tpo $(DEPDIR)/mate_session-gsm-marshal.Po
[email protected][email protected]@[email protected] source='gsm-marshal.c' object='mate_session-gsm-marshal.o' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-marshal.o `test -f 'gsm-marshal.c' || echo '$(srcdir)/'`gsm-marshal.c
+
+mate_session-gsm-marshal.obj: gsm-marshal.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-marshal.obj -MD -MP -MF $(DEPDIR)/mate_session-gsm-marshal.Tpo -c -o mate_session-gsm-marshal.obj `if test -f 'gsm-marshal.c'; then $(CYGPATH_W) 'gsm-marshal.c'; else $(CYGPATH_W) '$(srcdir)/gsm-marshal.c'; fi`
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-marshal.Tpo $(DEPDIR)/mate_session-gsm-marshal.Po
[email protected][email protected]@[email protected] source='gsm-marshal.c' object='mate_session-gsm-marshal.obj' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-marshal.obj `if test -f 'gsm-marshal.c'; then $(CYGPATH_W) 'gsm-marshal.c'; else $(CYGPATH_W) '$(srcdir)/gsm-marshal.c'; fi`
+
+mate_session-gsm-consolekit.o: gsm-consolekit.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-consolekit.o -MD -MP -MF $(DEPDIR)/mate_session-gsm-consolekit.Tpo -c -o mate_session-gsm-consolekit.o `test -f 'gsm-consolekit.c' || echo '$(srcdir)/'`gsm-consolekit.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-consolekit.Tpo $(DEPDIR)/mate_session-gsm-consolekit.Po
[email protected][email protected]@[email protected] source='gsm-consolekit.c' object='mate_session-gsm-consolekit.o' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-consolekit.o `test -f 'gsm-consolekit.c' || echo '$(srcdir)/'`gsm-consolekit.c
+
+mate_session-gsm-consolekit.obj: gsm-consolekit.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-consolekit.obj -MD -MP -MF $(DEPDIR)/mate_session-gsm-consolekit.Tpo -c -o mate_session-gsm-consolekit.obj `if test -f 'gsm-consolekit.c'; then $(CYGPATH_W) 'gsm-consolekit.c'; else $(CYGPATH_W) '$(srcdir)/gsm-consolekit.c'; fi`
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-consolekit.Tpo $(DEPDIR)/mate_session-gsm-consolekit.Po
[email protected][email protected]@[email protected] source='gsm-consolekit.c' object='mate_session-gsm-consolekit.obj' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-consolekit.obj `if test -f 'gsm-consolekit.c'; then $(CYGPATH_W) 'gsm-consolekit.c'; else $(CYGPATH_W) '$(srcdir)/gsm-consolekit.c'; fi`
+
+mate_session-gsm-logout-dialog.o: gsm-logout-dialog.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-logout-dialog.o -MD -MP -MF $(DEPDIR)/mate_session-gsm-logout-dialog.Tpo -c -o mate_session-gsm-logout-dialog.o `test -f 'gsm-logout-dialog.c' || echo '$(srcdir)/'`gsm-logout-dialog.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-logout-dialog.Tpo $(DEPDIR)/mate_session-gsm-logout-dialog.Po
[email protected][email protected]@[email protected] source='gsm-logout-dialog.c' object='mate_session-gsm-logout-dialog.o' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-logout-dialog.o `test -f 'gsm-logout-dialog.c' || echo '$(srcdir)/'`gsm-logout-dialog.c
+
+mate_session-gsm-logout-dialog.obj: gsm-logout-dialog.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-logout-dialog.obj -MD -MP -MF $(DEPDIR)/mate_session-gsm-logout-dialog.Tpo -c -o mate_session-gsm-logout-dialog.obj `if test -f 'gsm-logout-dialog.c'; then $(CYGPATH_W) 'gsm-logout-dialog.c'; else $(CYGPATH_W) '$(srcdir)/gsm-logout-dialog.c'; fi`
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-logout-dialog.Tpo $(DEPDIR)/mate_session-gsm-logout-dialog.Po
[email protected][email protected]@[email protected] source='gsm-logout-dialog.c' object='mate_session-gsm-logout-dialog.obj' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-logout-dialog.obj `if test -f 'gsm-logout-dialog.c'; then $(CYGPATH_W) 'gsm-logout-dialog.c'; else $(CYGPATH_W) '$(srcdir)/gsm-logout-dialog.c'; fi`
+
+mate_session-gsm-inhibit-dialog.o: gsm-inhibit-dialog.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-inhibit-dialog.o -MD -MP -MF $(DEPDIR)/mate_session-gsm-inhibit-dialog.Tpo -c -o mate_session-gsm-inhibit-dialog.o `test -f 'gsm-inhibit-dialog.c' || echo '$(srcdir)/'`gsm-inhibit-dialog.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-inhibit-dialog.Tpo $(DEPDIR)/mate_session-gsm-inhibit-dialog.Po
[email protected][email protected]@[email protected] source='gsm-inhibit-dialog.c' object='mate_session-gsm-inhibit-dialog.o' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-inhibit-dialog.o `test -f 'gsm-inhibit-dialog.c' || echo '$(srcdir)/'`gsm-inhibit-dialog.c
+
+mate_session-gsm-inhibit-dialog.obj: gsm-inhibit-dialog.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-inhibit-dialog.obj -MD -MP -MF $(DEPDIR)/mate_session-gsm-inhibit-dialog.Tpo -c -o mate_session-gsm-inhibit-dialog.obj `if test -f 'gsm-inhibit-dialog.c'; then $(CYGPATH_W) 'gsm-inhibit-dialog.c'; else $(CYGPATH_W) '$(srcdir)/gsm-inhibit-dialog.c'; fi`
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-inhibit-dialog.Tpo $(DEPDIR)/mate_session-gsm-inhibit-dialog.Po
[email protected][email protected]@[email protected] source='gsm-inhibit-dialog.c' object='mate_session-gsm-inhibit-dialog.obj' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-inhibit-dialog.obj `if test -f 'gsm-inhibit-dialog.c'; then $(CYGPATH_W) 'gsm-inhibit-dialog.c'; else $(CYGPATH_W) '$(srcdir)/gsm-inhibit-dialog.c'; fi`
+
+mate_session-gs-idle-monitor.o: gs-idle-monitor.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gs-idle-monitor.o -MD -MP -MF $(DEPDIR)/mate_session-gs-idle-monitor.Tpo -c -o mate_session-gs-idle-monitor.o `test -f 'gs-idle-monitor.c' || echo '$(srcdir)/'`gs-idle-monitor.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gs-idle-monitor.Tpo $(DEPDIR)/mate_session-gs-idle-monitor.Po
[email protected][email protected]@[email protected] source='gs-idle-monitor.c' object='mate_session-gs-idle-monitor.o' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gs-idle-monitor.o `test -f 'gs-idle-monitor.c' || echo '$(srcdir)/'`gs-idle-monitor.c
+
+mate_session-gs-idle-monitor.obj: gs-idle-monitor.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gs-idle-monitor.obj -MD -MP -MF $(DEPDIR)/mate_session-gs-idle-monitor.Tpo -c -o mate_session-gs-idle-monitor.obj `if test -f 'gs-idle-monitor.c'; then $(CYGPATH_W) 'gs-idle-monitor.c'; else $(CYGPATH_W) '$(srcdir)/gs-idle-monitor.c'; fi`
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gs-idle-monitor.Tpo $(DEPDIR)/mate_session-gs-idle-monitor.Po
[email protected][email protected]@[email protected] source='gs-idle-monitor.c' object='mate_session-gs-idle-monitor.obj' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gs-idle-monitor.obj `if test -f 'gs-idle-monitor.c'; then $(CYGPATH_W) 'gs-idle-monitor.c'; else $(CYGPATH_W) '$(srcdir)/gs-idle-monitor.c'; fi`
+
+mate_session-gsm-presence.o: gsm-presence.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-presence.o -MD -MP -MF $(DEPDIR)/mate_session-gsm-presence.Tpo -c -o mate_session-gsm-presence.o `test -f 'gsm-presence.c' || echo '$(srcdir)/'`gsm-presence.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-presence.Tpo $(DEPDIR)/mate_session-gsm-presence.Po
[email protected][email protected]@[email protected] source='gsm-presence.c' object='mate_session-gsm-presence.o' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-presence.o `test -f 'gsm-presence.c' || echo '$(srcdir)/'`gsm-presence.c
+
+mate_session-gsm-presence.obj: gsm-presence.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-presence.obj -MD -MP -MF $(DEPDIR)/mate_session-gsm-presence.Tpo -c -o mate_session-gsm-presence.obj `if test -f 'gsm-presence.c'; then $(CYGPATH_W) 'gsm-presence.c'; else $(CYGPATH_W) '$(srcdir)/gsm-presence.c'; fi`
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-presence.Tpo $(DEPDIR)/mate_session-gsm-presence.Po
[email protected][email protected]@[email protected] source='gsm-presence.c' object='mate_session-gsm-presence.obj' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-presence.obj `if test -f 'gsm-presence.c'; then $(CYGPATH_W) 'gsm-presence.c'; else $(CYGPATH_W) '$(srcdir)/gsm-presence.c'; fi`
+
+mate_session-gsm-mateconf.o: gsm-mateconf.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-mateconf.o -MD -MP -MF $(DEPDIR)/mate_session-gsm-mateconf.Tpo -c -o mate_session-gsm-mateconf.o `test -f 'gsm-mateconf.c' || echo '$(srcdir)/'`gsm-mateconf.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-mateconf.Tpo $(DEPDIR)/mate_session-gsm-mateconf.Po
[email protected][email protected]@[email protected] source='gsm-mateconf.c' object='mate_session-gsm-mateconf.o' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-mateconf.o `test -f 'gsm-mateconf.c' || echo '$(srcdir)/'`gsm-mateconf.c
+
+mate_session-gsm-mateconf.obj: gsm-mateconf.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-mateconf.obj -MD -MP -MF $(DEPDIR)/mate_session-gsm-mateconf.Tpo -c -o mate_session-gsm-mateconf.obj `if test -f 'gsm-mateconf.c'; then $(CYGPATH_W) 'gsm-mateconf.c'; else $(CYGPATH_W) '$(srcdir)/gsm-mateconf.c'; fi`
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-mateconf.Tpo $(DEPDIR)/mate_session-gsm-mateconf.Po
[email protected][email protected]@[email protected] source='gsm-mateconf.c' object='mate_session-gsm-mateconf.obj' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-mateconf.obj `if test -f 'gsm-mateconf.c'; then $(CYGPATH_W) 'gsm-mateconf.c'; else $(CYGPATH_W) '$(srcdir)/gsm-mateconf.c'; fi`
+
+mate_session-mdm.o: mdm.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-mdm.o -MD -MP -MF $(DEPDIR)/mate_session-mdm.Tpo -c -o mate_session-mdm.o `test -f 'mdm.c' || echo '$(srcdir)/'`mdm.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-mdm.Tpo $(DEPDIR)/mate_session-mdm.Po
[email protected][email protected]@[email protected] source='mdm.c' object='mate_session-mdm.o' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-mdm.o `test -f 'mdm.c' || echo '$(srcdir)/'`mdm.c
+
+mate_session-mdm.obj: mdm.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-mdm.obj -MD -MP -MF $(DEPDIR)/mate_session-mdm.Tpo -c -o mate_session-mdm.obj `if test -f 'mdm.c'; then $(CYGPATH_W) 'mdm.c'; else $(CYGPATH_W) '$(srcdir)/mdm.c'; fi`
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-mdm.Tpo $(DEPDIR)/mate_session-mdm.Po
[email protected][email protected]@[email protected] source='mdm.c' object='mate_session-mdm.obj' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-mdm.obj `if test -f 'mdm.c'; then $(CYGPATH_W) 'mdm.c'; else $(CYGPATH_W) '$(srcdir)/mdm.c'; fi`
+
+mate_session-mdm-signal-handler.o: mdm-signal-handler.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-mdm-signal-handler.o -MD -MP -MF $(DEPDIR)/mate_session-mdm-signal-handler.Tpo -c -o mate_session-mdm-signal-handler.o `test -f 'mdm-signal-handler.c' || echo '$(srcdir)/'`mdm-signal-handler.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-mdm-signal-handler.Tpo $(DEPDIR)/mate_session-mdm-signal-handler.Po
[email protected][email protected]@[email protected] source='mdm-signal-handler.c' object='mate_session-mdm-signal-handler.o' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-mdm-signal-handler.o `test -f 'mdm-signal-handler.c' || echo '$(srcdir)/'`mdm-signal-handler.c
+
+mate_session-mdm-signal-handler.obj: mdm-signal-handler.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-mdm-signal-handler.obj -MD -MP -MF $(DEPDIR)/mate_session-mdm-signal-handler.Tpo -c -o mate_session-mdm-signal-handler.obj `if test -f 'mdm-signal-handler.c'; then $(CYGPATH_W) 'mdm-signal-handler.c'; else $(CYGPATH_W) '$(srcdir)/mdm-signal-handler.c'; fi`
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-mdm-signal-handler.Tpo $(DEPDIR)/mate_session-mdm-signal-handler.Po
[email protected][email protected]@[email protected] source='mdm-signal-handler.c' object='mate_session-mdm-signal-handler.obj' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-mdm-signal-handler.obj `if test -f 'mdm-signal-handler.c'; then $(CYGPATH_W) 'mdm-signal-handler.c'; else $(CYGPATH_W) '$(srcdir)/mdm-signal-handler.c'; fi`
+
+mate_session-mdm-log.o: mdm-log.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-mdm-log.o -MD -MP -MF $(DEPDIR)/mate_session-mdm-log.Tpo -c -o mate_session-mdm-log.o `test -f 'mdm-log.c' || echo '$(srcdir)/'`mdm-log.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-mdm-log.Tpo $(DEPDIR)/mate_session-mdm-log.Po
[email protected][email protected]@[email protected] source='mdm-log.c' object='mate_session-mdm-log.o' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-mdm-log.o `test -f 'mdm-log.c' || echo '$(srcdir)/'`mdm-log.c
+
+mate_session-mdm-log.obj: mdm-log.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-mdm-log.obj -MD -MP -MF $(DEPDIR)/mate_session-mdm-log.Tpo -c -o mate_session-mdm-log.obj `if test -f 'mdm-log.c'; then $(CYGPATH_W) 'mdm-log.c'; else $(CYGPATH_W) '$(srcdir)/mdm-log.c'; fi`
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-mdm-log.Tpo $(DEPDIR)/mate_session-mdm-log.Po
[email protected][email protected]@[email protected] source='mdm-log.c' object='mate_session-mdm-log.obj' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-mdm-log.obj `if test -f 'mdm-log.c'; then $(CYGPATH_W) 'mdm-log.c'; else $(CYGPATH_W) '$(srcdir)/mdm-log.c'; fi`
+
+mate_session-main.o: main.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-main.o -MD -MP -MF $(DEPDIR)/mate_session-main.Tpo -c -o mate_session-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-main.Tpo $(DEPDIR)/mate_session-main.Po
[email protected][email protected]@[email protected] source='main.c' object='mate_session-main.o' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c
+
+mate_session-main.obj: main.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-main.obj -MD -MP -MF $(DEPDIR)/mate_session-main.Tpo -c -o mate_session-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi`
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-main.Tpo $(DEPDIR)/mate_session-main.Po
[email protected][email protected]@[email protected] source='main.c' object='mate_session-main.obj' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi`
+
+mate_session-gsm-store.o: gsm-store.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-store.o -MD -MP -MF $(DEPDIR)/mate_session-gsm-store.Tpo -c -o mate_session-gsm-store.o `test -f 'gsm-store.c' || echo '$(srcdir)/'`gsm-store.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-store.Tpo $(DEPDIR)/mate_session-gsm-store.Po
[email protected][email protected]@[email protected] source='gsm-store.c' object='mate_session-gsm-store.o' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-store.o `test -f 'gsm-store.c' || echo '$(srcdir)/'`gsm-store.c
+
+mate_session-gsm-store.obj: gsm-store.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-store.obj -MD -MP -MF $(DEPDIR)/mate_session-gsm-store.Tpo -c -o mate_session-gsm-store.obj `if test -f 'gsm-store.c'; then $(CYGPATH_W) 'gsm-store.c'; else $(CYGPATH_W) '$(srcdir)/gsm-store.c'; fi`
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-store.Tpo $(DEPDIR)/mate_session-gsm-store.Po
[email protected][email protected]@[email protected] source='gsm-store.c' object='mate_session-gsm-store.obj' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-store.obj `if test -f 'gsm-store.c'; then $(CYGPATH_W) 'gsm-store.c'; else $(CYGPATH_W) '$(srcdir)/gsm-store.c'; fi`
+
+mate_session-gsm-inhibitor.o: gsm-inhibitor.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-inhibitor.o -MD -MP -MF $(DEPDIR)/mate_session-gsm-inhibitor.Tpo -c -o mate_session-gsm-inhibitor.o `test -f 'gsm-inhibitor.c' || echo '$(srcdir)/'`gsm-inhibitor.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-inhibitor.Tpo $(DEPDIR)/mate_session-gsm-inhibitor.Po
[email protected][email protected]@[email protected] source='gsm-inhibitor.c' object='mate_session-gsm-inhibitor.o' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-inhibitor.o `test -f 'gsm-inhibitor.c' || echo '$(srcdir)/'`gsm-inhibitor.c
+
+mate_session-gsm-inhibitor.obj: gsm-inhibitor.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-inhibitor.obj -MD -MP -MF $(DEPDIR)/mate_session-gsm-inhibitor.Tpo -c -o mate_session-gsm-inhibitor.obj `if test -f 'gsm-inhibitor.c'; then $(CYGPATH_W) 'gsm-inhibitor.c'; else $(CYGPATH_W) '$(srcdir)/gsm-inhibitor.c'; fi`
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-inhibitor.Tpo $(DEPDIR)/mate_session-gsm-inhibitor.Po
[email protected][email protected]@[email protected] source='gsm-inhibitor.c' object='mate_session-gsm-inhibitor.obj' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-inhibitor.obj `if test -f 'gsm-inhibitor.c'; then $(CYGPATH_W) 'gsm-inhibitor.c'; else $(CYGPATH_W) '$(srcdir)/gsm-inhibitor.c'; fi`
+
+mate_session-gsm-manager.o: gsm-manager.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-manager.o -MD -MP -MF $(DEPDIR)/mate_session-gsm-manager.Tpo -c -o mate_session-gsm-manager.o `test -f 'gsm-manager.c' || echo '$(srcdir)/'`gsm-manager.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-manager.Tpo $(DEPDIR)/mate_session-gsm-manager.Po
[email protected][email protected]@[email protected] source='gsm-manager.c' object='mate_session-gsm-manager.o' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-manager.o `test -f 'gsm-manager.c' || echo '$(srcdir)/'`gsm-manager.c
+
+mate_session-gsm-manager.obj: gsm-manager.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-manager.obj -MD -MP -MF $(DEPDIR)/mate_session-gsm-manager.Tpo -c -o mate_session-gsm-manager.obj `if test -f 'gsm-manager.c'; then $(CYGPATH_W) 'gsm-manager.c'; else $(CYGPATH_W) '$(srcdir)/gsm-manager.c'; fi`
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-manager.Tpo $(DEPDIR)/mate_session-gsm-manager.Po
[email protected][email protected]@[email protected] source='gsm-manager.c' object='mate_session-gsm-manager.obj' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-manager.obj `if test -f 'gsm-manager.c'; then $(CYGPATH_W) 'gsm-manager.c'; else $(CYGPATH_W) '$(srcdir)/gsm-manager.c'; fi`
+
+mate_session-gsm-session-save.o: gsm-session-save.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-session-save.o -MD -MP -MF $(DEPDIR)/mate_session-gsm-session-save.Tpo -c -o mate_session-gsm-session-save.o `test -f 'gsm-session-save.c' || echo '$(srcdir)/'`gsm-session-save.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-session-save.Tpo $(DEPDIR)/mate_session-gsm-session-save.Po
[email protected][email protected]@[email protected] source='gsm-session-save.c' object='mate_session-gsm-session-save.o' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-session-save.o `test -f 'gsm-session-save.c' || echo '$(srcdir)/'`gsm-session-save.c
+
+mate_session-gsm-session-save.obj: gsm-session-save.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-session-save.obj -MD -MP -MF $(DEPDIR)/mate_session-gsm-session-save.Tpo -c -o mate_session-gsm-session-save.obj `if test -f 'gsm-session-save.c'; then $(CYGPATH_W) 'gsm-session-save.c'; else $(CYGPATH_W) '$(srcdir)/gsm-session-save.c'; fi`
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-session-save.Tpo $(DEPDIR)/mate_session-gsm-session-save.Po
[email protected][email protected]@[email protected] source='gsm-session-save.c' object='mate_session-gsm-session-save.obj' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-session-save.obj `if test -f 'gsm-session-save.c'; then $(CYGPATH_W) 'gsm-session-save.c'; else $(CYGPATH_W) '$(srcdir)/gsm-session-save.c'; fi`
+
+mate_session-gsm-xsmp-server.o: gsm-xsmp-server.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-xsmp-server.o -MD -MP -MF $(DEPDIR)/mate_session-gsm-xsmp-server.Tpo -c -o mate_session-gsm-xsmp-server.o `test -f 'gsm-xsmp-server.c' || echo '$(srcdir)/'`gsm-xsmp-server.c
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-xsmp-server.Tpo $(DEPDIR)/mate_session-gsm-xsmp-server.Po
[email protected][email protected]@[email protected] source='gsm-xsmp-server.c' object='mate_session-gsm-xsmp-server.o' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-xsmp-server.o `test -f 'gsm-xsmp-server.c' || echo '$(srcdir)/'`gsm-xsmp-server.c
+
+mate_session-gsm-xsmp-server.obj: gsm-xsmp-server.c
[email protected][email protected] $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mate_session-gsm-xsmp-server.obj -MD -MP -MF $(DEPDIR)/mate_session-gsm-xsmp-server.Tpo -c -o mate_session-gsm-xsmp-server.obj `if test -f 'gsm-xsmp-server.c'; then $(CYGPATH_W) 'gsm-xsmp-server.c'; else $(CYGPATH_W) '$(srcdir)/gsm-xsmp-server.c'; fi`
[email protected][email protected] $(AM_V_at)$(am__mv) $(DEPDIR)/mate_session-gsm-xsmp-server.Tpo $(DEPDIR)/mate_session-gsm-xsmp-server.Po
[email protected][email protected]@[email protected] source='gsm-xsmp-server.c' object='mate_session-gsm-xsmp-server.obj' libtool=no @[email protected]
[email protected][email protected] $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_session_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mate_session-gsm-xsmp-server.obj `if test -f 'gsm-xsmp-server.c'; then $(CYGPATH_W) 'gsm-xsmp-server.c'; else $(CYGPATH_W) '$(srcdir)/gsm-xsmp-server.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "[email protected]" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool \
+ clean-noinstLTLIBRARIES clean-noinstPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS
+
+.MAKE: all check install install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ clean-noinstPROGRAMS ctags distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-binPROGRAMS install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am \
+ uninstall-binPROGRAMS
+
+
+gsm-marshal.c: gsm-marshal.list
+ $(AM_V_GEN)echo "#include \"gsm-marshal.h\"" > [email protected] && \
+ $(GLIB_GENMARSHAL) $< --prefix=gsm_marshal --body >> [email protected]
+
+gsm-marshal.h: gsm-marshal.list
+ $(AM_V_GEN)$(GLIB_GENMARSHAL) $< --prefix=gsm_marshal --header > [email protected]
+
+gsm-manager-glue.h: org.mate.SessionManager.xml Makefile.am
+ $(AM_V_GEN)dbus-binding-tool --prefix=gsm_manager --mode=glib-server --output=gsm-manager-glue.h $(srcdir)/org.mate.SessionManager.xml
+
+gsm-client-glue.h: org.mate.SessionManager.Client.xml Makefile.am
+ $(AM_V_GEN)dbus-binding-tool --prefix=gsm_client --mode=glib-server --output=gsm-client-glue.h $(srcdir)/org.mate.SessionManager.Client.xml
+
+gsm-app-glue.h: org.mate.SessionManager.App.xml Makefile.am
+ $(AM_V_GEN)dbus-binding-tool --prefix=gsm_app --mode=glib-server --output=gsm-app-glue.h $(srcdir)/org.mate.SessionManager.App.xml
+
+gsm-inhibitor-glue.h: org.mate.SessionManager.Inhibitor.xml Makefile.am
+ $(AM_V_GEN)dbus-binding-tool --prefix=gsm_inhibitor --mode=glib-server --output=gsm-inhibitor-glue.h $(srcdir)/org.mate.SessionManager.Inhibitor.xml
+
+gsm-presence-glue.h: org.mate.SessionManager.Presence.xml Makefile.am
+ $(AM_V_GEN)dbus-binding-tool --prefix=gsm_presence --mode=glib-server --output=gsm-presence-glue.h $(srcdir)/org.mate.SessionManager.Presence.xml
+
+-include $(top_srcdir)/git.mk
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/mate-session/README b/mate-session/README
new file mode 100644
index 0000000..05bfe9d
--- /dev/null
+++ b/mate-session/README
@@ -0,0 +1,65 @@
+See also http://live.gnome.org/SessionManagement/NewGnomeSession
+
+Startup
+-------
+
+main() creates the GsmSession object representing the session (either
+failsafe or normal). gsm_session_new() reads the appropriate autostart
+and session files to create a list of GsmApps to be started.
+(GsmAppAutostart represents an autostarted app, and GsmAppResumed
+represents an app resumed from the previous saved session.)
+
+Startup is divided into 6 phases (GsmSessionPhase):
+
+ * GSM_SESSION_PHASE_STARTUP covers mate-session's internal
+ startup, which also includes starting mateconfd and dbus-daemon (if
+ it's not already running). Mate-session starts up those
+ explicitly because it needs them for its own purposes.
+
+ * GSM_SESSION_PHASE_INITIALIZATION is the first phase of "normal"
+ startup (ie, startup controlled by .desktop files rather than
+ hardcoding). It covers low-level stuff like
+ mate-settings-daemon and at-spi-registryd, that need to be
+ running very early (before any windows are displayed).
+
+ Apps in this phase can make use of a D-Bus interface
+ (org.mate.SessionManager.Setenv) to set environment variables
+ in mate-session's environment. This can be used for things like
+ $GTK_MODULES, $MATE_KEYRING_SOCKET, etc
+
+ * GSM_SESSION_PHASE_WINDOW_MANAGER includes window managers and
+ compositing managers, and anything else that has to be running
+ before any windows are mapped
+
+ * GSM_SESSION_PHASE_PANEL includes anything that permanently takes
+ up screen real estate (via EWMH struts). This is the first phase
+ where things actually appear on the screen.
+
+ * GSM_SESSION_PHASE_DESKTOP includes anything that draws directly
+ on the desktop (eg, caja).
+
+ * GSM_SESSION_PHASE_APPLICATION is everything else (normal apps,
+ tray icons, etc)
+
+For each startup phase, GsmSession launches the appropriate GsmApps.
+When apps connect to the XSMP or D-Bus servers, GsmClients are created
+and added to the session. The session tries to map these clients to
+GsmApps. GsmApps signal when they register (via XSMP or SN) or exit,
+and GsmSession uses this to decide when the phase is complete.
+
+FIXME: after starting the session, we need to run the DiscardCommands
+of resumed apps.
+
+
+Running/Shutdown
+----------------
+
+GSM_SESSION_PHASE_RUNNING is pretty similar to the old mate-session;
+mostly it just tracks XSMP clients, and watches for
+SmRestartImmediately clients exiting (NOTE: THIS DOESN'T HAPPEN YET).
+
+GsmClient is in theory not XSMP-specific, but it's very very
+XSMP-like, and the shutdown procedure is also very XSMP-like. This is
+just because there's no way to do XSMP shutdown correctly otherwise.
+However, GsmClientDBus will still be able to present a more sane
+protocol to its clients than GsmClient presents to it.
diff --git a/mate-session/gs-idle-monitor.c b/mate-session/gs-idle-monitor.c
new file mode 100644
index 0000000..05dbb02
--- /dev/null
+++ b/mate-session/gs-idle-monitor.c
@@ -0,0 +1,507 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * 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.
+ *
+ * Authors: William Jon McCann <[email protected]>
+ *
+ */
+
+#include "config.h"
+
+#include <time.h>
+#include <string.h>
+
+#include <X11/Xlib.h>
+#include <X11/extensions/sync.h>
+
+#ifdef HAVE_XTEST
+#include <X11/keysym.h>
+#include <X11/extensions/XTest.h>
+#endif /* HAVE_XTEST */
+
+#include <glib.h>
+#include <gdk/gdkx.h>
+#include <gdk/gdk.h>
+
+#include "gs-idle-monitor.h"
+
+static void gs_idle_monitor_class_init (GSIdleMonitorClass *klass);
+static void gs_idle_monitor_init (GSIdleMonitor *idle_monitor);
+static void gs_idle_monitor_finalize (GObject *object);
+
+#define GS_IDLE_MONITOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GS_TYPE_IDLE_MONITOR, GSIdleMonitorPrivate))
+
+struct GSIdleMonitorPrivate
+{
+ GHashTable *watches;
+ int sync_event_base;
+ XSyncCounter counter;
+
+ /* For use with XTest */
+ int *keycode;
+ int keycode1;
+ int keycode2;
+ gboolean have_xtest;
+};
+
+typedef struct
+{
+ guint id;
+ XSyncValue interval;
+ GSIdleMonitorWatchFunc callback;
+ gpointer user_data;
+ XSyncAlarm xalarm_positive;
+ XSyncAlarm xalarm_negative;
+} GSIdleMonitorWatch;
+
+static guint32 watch_serial = 1;
+
+G_DEFINE_TYPE (GSIdleMonitor, gs_idle_monitor, G_TYPE_OBJECT)
+
+static gint64
+_xsyncvalue_to_int64 (XSyncValue value)
+{
+ return ((guint64) XSyncValueHigh32 (value)) << 32
+ | (guint64) XSyncValueLow32 (value);
+}
+
+static XSyncValue
+_int64_to_xsyncvalue (gint64 value)
+{
+ XSyncValue ret;
+
+ XSyncIntsToValue (&ret, value, ((guint64)value) >> 32);
+
+ return ret;
+}
+
+static void
+gs_idle_monitor_dispose (GObject *object)
+{
+ GSIdleMonitor *monitor;
+
+ g_return_if_fail (GS_IS_IDLE_MONITOR (object));
+
+ monitor = GS_IDLE_MONITOR (object);
+
+ if (monitor->priv->watches != NULL) {
+ g_hash_table_destroy (monitor->priv->watches);
+ monitor->priv->watches = NULL;
+ }
+
+ G_OBJECT_CLASS (gs_idle_monitor_parent_class)->dispose (object);
+}
+
+static gboolean
+_find_alarm (gpointer key,
+ GSIdleMonitorWatch *watch,
+ XSyncAlarm *alarm)
+{
+ g_debug ("Searching for %d in %d,%d", (int)*alarm, (int)watch->xalarm_positive, (int)watch->xalarm_negative);
+ if (watch->xalarm_positive == *alarm
+ || watch->xalarm_negative == *alarm) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static GSIdleMonitorWatch *
+find_watch_for_alarm (GSIdleMonitor *monitor,
+ XSyncAlarm alarm)
+{
+ GSIdleMonitorWatch *watch;
+
+ watch = g_hash_table_find (monitor->priv->watches,
+ (GHRFunc)_find_alarm,
+ &alarm);
+ return watch;
+}
+
+#ifdef HAVE_XTEST
+static gboolean
+send_fake_event (GSIdleMonitor *monitor)
+{
+ if (! monitor->priv->have_xtest) {
+ return FALSE;
+ }
+
+ g_debug ("GSIdleMonitor: sending fake key");
+
+ XLockDisplay (GDK_DISPLAY());
+ XTestFakeKeyEvent (GDK_DISPLAY(),
+ *monitor->priv->keycode,
+ True,
+ CurrentTime);
+ XTestFakeKeyEvent (GDK_DISPLAY(),
+ *monitor->priv->keycode,
+ False,
+ CurrentTime);
+ XUnlockDisplay (GDK_DISPLAY());
+
+ /* Swap the keycode */
+ if (monitor->priv->keycode == &monitor->priv->keycode1) {
+ monitor->priv->keycode = &monitor->priv->keycode2;
+ } else {
+ monitor->priv->keycode = &monitor->priv->keycode1;
+ }
+
+ return TRUE;
+}
+#endif /* HAVE_XTEST */
+
+void
+gs_idle_monitor_reset (GSIdleMonitor *monitor)
+{
+ g_return_if_fail (GS_IS_IDLE_MONITOR (monitor));
+
+#ifdef HAVE_XTEST
+ /* FIXME: is there a better way to reset the IDLETIME? */
+ send_fake_event (monitor);
+#endif
+}
+
+static void
+handle_alarm_notify_event (GSIdleMonitor *monitor,
+ XSyncAlarmNotifyEvent *alarm_event)
+{
+ GSIdleMonitorWatch *watch;
+ gboolean res;
+ gboolean condition;
+
+ if (alarm_event->state == XSyncAlarmDestroyed) {
+ return;
+ }
+
+ watch = find_watch_for_alarm (monitor, alarm_event->alarm);
+
+ if (watch == NULL) {
+ g_debug ("Unable to find watch for alarm %d", (int)alarm_event->alarm);
+ return;
+ }
+
+ g_debug ("Watch %d fired, idle time = %lld",
+ watch->id,
+ _xsyncvalue_to_int64 (alarm_event->counter_value));
+
+ if (alarm_event->alarm == watch->xalarm_positive) {
+ condition = TRUE;
+ } else {
+ condition = FALSE;
+ }
+
+ res = TRUE;
+ if (watch->callback != NULL) {
+ res = watch->callback (monitor,
+ watch->id,
+ condition,
+ watch->user_data);
+ }
+
+ if (! res) {
+ /* reset all timers */
+ g_debug ("GSIdleMonitor: callback returned FALSE; resetting idle time");
+ gs_idle_monitor_reset (monitor);
+ }
+}
+
+static GdkFilterReturn
+xevent_filter (GdkXEvent *xevent,
+ GdkEvent *event,
+ GSIdleMonitor *monitor)
+{
+ XEvent *ev;
+ XSyncAlarmNotifyEvent *alarm_event;
+
+ ev = xevent;
+ if (ev->xany.type != monitor->priv->sync_event_base + XSyncAlarmNotify) {
+ return GDK_FILTER_CONTINUE;
+ }
+
+ alarm_event = xevent;
+
+ handle_alarm_notify_event (monitor, alarm_event);
+
+ return GDK_FILTER_CONTINUE;
+}
+
+static gboolean
+init_xsync (GSIdleMonitor *monitor)
+{
+ int sync_error_base;
+ int res;
+ int major;
+ int minor;
+ int i;
+ int ncounters;
+ XSyncSystemCounter *counters;
+
+ res = XSyncQueryExtension (GDK_DISPLAY (),
+ &monitor->priv->sync_event_base,
+ &sync_error_base);
+ if (! res) {
+ g_warning ("GSIdleMonitor: Sync extension not present");
+ return FALSE;
+ }
+
+ res = XSyncInitialize (GDK_DISPLAY (), &major, &minor);
+ if (! res) {
+ g_warning ("GSIdleMonitor: Unable to initialize Sync extension");
+ return FALSE;
+ }
+
+ counters = XSyncListSystemCounters (GDK_DISPLAY (), &ncounters);
+ for (i = 0; i < ncounters; i++) {
+ if (counters[i].name != NULL
+ && strcmp (counters[i].name, "IDLETIME") == 0) {
+ monitor->priv->counter = counters[i].counter;
+ break;
+ }
+ }
+ XSyncFreeSystemCounterList (counters);
+
+ if (monitor->priv->counter == None) {
+ g_warning ("GSIdleMonitor: IDLETIME counter not found");
+ return FALSE;
+ }
+
+ gdk_window_add_filter (NULL, (GdkFilterFunc)xevent_filter, monitor);
+
+ return TRUE;
+}
+
+static void
+_init_xtest (GSIdleMonitor *monitor)
+{
+#ifdef HAVE_XTEST
+ int a, b, c, d;
+
+ XLockDisplay (GDK_DISPLAY());
+ monitor->priv->have_xtest = (XTestQueryExtension (GDK_DISPLAY(), &a, &b, &c, &d) == True);
+ if (monitor->priv->have_xtest) {
+ monitor->priv->keycode1 = XKeysymToKeycode (GDK_DISPLAY(), XK_Alt_L);
+ if (monitor->priv->keycode1 == 0) {
+ g_warning ("keycode1 not existant");
+ }
+ monitor->priv->keycode2 = XKeysymToKeycode (GDK_DISPLAY(), XK_Alt_R);
+ if (monitor->priv->keycode2 == 0) {
+ monitor->priv->keycode2 = XKeysymToKeycode (GDK_DISPLAY(), XK_Alt_L);
+ if (monitor->priv->keycode2 == 0) {
+ g_warning ("keycode2 not existant");
+ }
+ }
+ monitor->priv->keycode = &monitor->priv->keycode1;
+ }
+ XUnlockDisplay (GDK_DISPLAY());
+#endif /* HAVE_XTEST */
+}
+
+static GObject *
+gs_idle_monitor_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GSIdleMonitor *monitor;
+
+ monitor = GS_IDLE_MONITOR (G_OBJECT_CLASS (gs_idle_monitor_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_properties));
+
+ _init_xtest (monitor);
+
+ if (! init_xsync (monitor)) {
+ g_object_unref (monitor);
+ return NULL;
+ }
+
+ return G_OBJECT (monitor);
+}
+
+static void
+gs_idle_monitor_class_init (GSIdleMonitorClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gs_idle_monitor_finalize;
+ object_class->dispose = gs_idle_monitor_dispose;
+ object_class->constructor = gs_idle_monitor_constructor;
+
+ g_type_class_add_private (klass, sizeof (GSIdleMonitorPrivate));
+}
+
+static guint32
+get_next_watch_serial (void)
+{
+ guint32 serial;
+
+ serial = watch_serial++;
+
+ if ((gint32)watch_serial < 0) {
+ watch_serial = 1;
+ }
+
+ /* FIXME: make sure it isn't in the hash */
+
+ return serial;
+}
+
+static GSIdleMonitorWatch *
+idle_monitor_watch_new (guint interval)
+{
+ GSIdleMonitorWatch *watch;
+
+ watch = g_slice_new0 (GSIdleMonitorWatch);
+ watch->interval = _int64_to_xsyncvalue ((gint64)interval);
+ watch->id = get_next_watch_serial ();
+ watch->xalarm_positive = None;
+ watch->xalarm_negative = None;
+
+ return watch;
+}
+
+static void
+idle_monitor_watch_free (GSIdleMonitorWatch *watch)
+{
+ if (watch == NULL) {
+ return;
+ }
+ if (watch->xalarm_positive != None) {
+ XSyncDestroyAlarm (GDK_DISPLAY (), watch->xalarm_positive);
+ }
+ if (watch->xalarm_negative != None) {
+ XSyncDestroyAlarm (GDK_DISPLAY (), watch->xalarm_negative);
+ }
+ g_slice_free (GSIdleMonitorWatch, watch);
+}
+
+static void
+gs_idle_monitor_init (GSIdleMonitor *monitor)
+{
+ monitor->priv = GS_IDLE_MONITOR_GET_PRIVATE (monitor);
+
+ monitor->priv->watches = g_hash_table_new_full (NULL,
+ NULL,
+ NULL,
+ (GDestroyNotify)idle_monitor_watch_free);
+
+ monitor->priv->counter = None;
+}
+
+static void
+gs_idle_monitor_finalize (GObject *object)
+{
+ GSIdleMonitor *idle_monitor;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GS_IS_IDLE_MONITOR (object));
+
+ idle_monitor = GS_IDLE_MONITOR (object);
+
+ g_return_if_fail (idle_monitor->priv != NULL);
+
+ G_OBJECT_CLASS (gs_idle_monitor_parent_class)->finalize (object);
+}
+
+GSIdleMonitor *
+gs_idle_monitor_new (void)
+{
+ GObject *idle_monitor;
+
+ idle_monitor = g_object_new (GS_TYPE_IDLE_MONITOR,
+ NULL);
+
+ return GS_IDLE_MONITOR (idle_monitor);
+}
+
+static gboolean
+_xsync_alarm_set (GSIdleMonitor *monitor,
+ GSIdleMonitorWatch *watch)
+{
+ XSyncAlarmAttributes attr;
+ XSyncValue delta;
+ guint flags;
+
+ flags = XSyncCACounter
+ | XSyncCAValueType
+ | XSyncCATestType
+ | XSyncCAValue
+ | XSyncCADelta
+ | XSyncCAEvents;
+
+ XSyncIntToValue (&delta, 0);
+ attr.trigger.counter = monitor->priv->counter;
+ attr.trigger.value_type = XSyncAbsolute;
+ attr.trigger.wait_value = watch->interval;
+ attr.delta = delta;
+ attr.events = TRUE;
+
+ attr.trigger.test_type = XSyncPositiveTransition;
+ if (watch->xalarm_positive != None) {
+ g_debug ("GSIdleMonitor: updating alarm for positive transition wait=%lld",
+ _xsyncvalue_to_int64 (attr.trigger.wait_value));
+ XSyncChangeAlarm (GDK_DISPLAY (), watch->xalarm_positive, flags, &attr);
+ } else {
+ g_debug ("GSIdleMonitor: creating new alarm for positive transition wait=%lld",
+ _xsyncvalue_to_int64 (attr.trigger.wait_value));
+ watch->xalarm_positive = XSyncCreateAlarm (GDK_DISPLAY (), flags, &attr);
+ }
+
+ attr.trigger.test_type = XSyncNegativeTransition;
+ if (watch->xalarm_negative != None) {
+ g_debug ("GSIdleMonitor: updating alarm for negative transition wait=%lld",
+ _xsyncvalue_to_int64 (attr.trigger.wait_value));
+ XSyncChangeAlarm (GDK_DISPLAY (), watch->xalarm_negative, flags, &attr);
+ } else {
+ g_debug ("GSIdleMonitor: creating new alarm for negative transition wait=%lld",
+ _xsyncvalue_to_int64 (attr.trigger.wait_value));
+ watch->xalarm_negative = XSyncCreateAlarm (GDK_DISPLAY (), flags, &attr);
+ }
+
+ return TRUE;
+}
+
+guint
+gs_idle_monitor_add_watch (GSIdleMonitor *monitor,
+ guint interval,
+ GSIdleMonitorWatchFunc callback,
+ gpointer user_data)
+{
+ GSIdleMonitorWatch *watch;
+
+ g_return_val_if_fail (GS_IS_IDLE_MONITOR (monitor), 0);
+ g_return_val_if_fail (callback != NULL, 0);
+
+ watch = idle_monitor_watch_new (interval);
+ watch->callback = callback;
+ watch->user_data = user_data;
+
+ _xsync_alarm_set (monitor, watch);
+
+ g_hash_table_insert (monitor->priv->watches,
+ GUINT_TO_POINTER (watch->id),
+ watch);
+ return watch->id;
+}
+
+void
+gs_idle_monitor_remove_watch (GSIdleMonitor *monitor,
+ guint id)
+{
+ g_return_if_fail (GS_IS_IDLE_MONITOR (monitor));
+
+ g_hash_table_remove (monitor->priv->watches,
+ GUINT_TO_POINTER (id));
+}
diff --git a/mate-session/gs-idle-monitor.h b/mate-session/gs-idle-monitor.h
new file mode 100644
index 0000000..631f8eb
--- /dev/null
+++ b/mate-session/gs-idle-monitor.h
@@ -0,0 +1,75 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * 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.
+ *
+ * Authors: William Jon McCann <[email protected]>
+ *
+ */
+
+#ifndef __GS_IDLE_MONITOR_H
+#define __GS_IDLE_MONITOR_H
+
+#include <glib-object.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GS_TYPE_IDLE_MONITOR (gs_idle_monitor_get_type ())
+#define GS_IDLE_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GS_TYPE_IDLE_MONITOR, GSIdleMonitor))
+#define GS_IDLE_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GS_TYPE_IDLE_MONITOR, GSIdleMonitorClass))
+#define GS_IS_IDLE_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GS_TYPE_IDLE_MONITOR))
+#define GS_IS_IDLE_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GS_TYPE_IDLE_MONITOR))
+#define GS_IDLE_MONITOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GS_TYPE_IDLE_MONITOR, GSIdleMonitorClass))
+
+typedef struct GSIdleMonitorPrivate GSIdleMonitorPrivate;
+
+typedef struct
+{
+ GObject parent;
+ GSIdleMonitorPrivate *priv;
+} GSIdleMonitor;
+
+typedef struct
+{
+ GObjectClass parent_class;
+} GSIdleMonitorClass;
+
+typedef gboolean (*GSIdleMonitorWatchFunc) (GSIdleMonitor *monitor,
+ guint id,
+ gboolean condition,
+ gpointer user_data);
+
+GType gs_idle_monitor_get_type (void);
+
+GSIdleMonitor * gs_idle_monitor_new (void);
+
+guint gs_idle_monitor_add_watch (GSIdleMonitor *monitor,
+ guint interval,
+ GSIdleMonitorWatchFunc callback,
+ gpointer user_data);
+
+void gs_idle_monitor_remove_watch (GSIdleMonitor *monitor,
+ guint id);
+void gs_idle_monitor_reset (GSIdleMonitor *monitor);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GS_IDLE_MONITOR_H */
diff --git a/mate-session/gsm-app.c b/mate-session/gsm-app.c
new file mode 100644
index 0000000..8131177
--- /dev/null
+++ b/mate-session/gsm-app.c
@@ -0,0 +1,489 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Novell, Inc.
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * 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
+ * Lesser 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib.h>
+#include <string.h>
+
+#include "gsm-app.h"
+#include "gsm-app-glue.h"
+
+#define GSM_APP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_APP, GsmAppPrivate))
+
+struct _GsmAppPrivate
+{
+ char *id;
+ char *app_id;
+ int phase;
+ char *startup_id;
+ DBusGConnection *connection;
+};
+
+
+enum {
+ EXITED,
+ DIED,
+ REGISTERED,
+ LAST_SIGNAL
+};
+
+static guint32 app_serial = 1;
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+enum {
+ PROP_0,
+ PROP_ID,
+ PROP_STARTUP_ID,
+ PROP_PHASE,
+ LAST_PROP
+};
+
+G_DEFINE_TYPE (GsmApp, gsm_app, G_TYPE_OBJECT)
+
+GQuark
+gsm_app_error_quark (void)
+{
+ static GQuark ret = 0;
+ if (ret == 0) {
+ ret = g_quark_from_static_string ("gsm_app_error");
+ }
+
+ return ret;
+
+}
+
+static guint32
+get_next_app_serial (void)
+{
+ guint32 serial;
+
+ serial = app_serial++;
+
+ if ((gint32)app_serial < 0) {
+ app_serial = 1;
+ }
+
+ return serial;
+}
+
+static gboolean
+register_app (GsmApp *app)
+{
+ GError *error;
+
+ error = NULL;
+ app->priv->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+ if (app->priv->connection == NULL) {
+ if (error != NULL) {
+ g_critical ("error getting session bus: %s", error->message);
+ g_error_free (error);
+ }
+ return FALSE;
+ }
+
+ dbus_g_connection_register_g_object (app->priv->connection, app->priv->id, G_OBJECT (app));
+
+ return TRUE;
+}
+
+static GObject *
+gsm_app_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GsmApp *app;
+ gboolean res;
+
+ app = GSM_APP (G_OBJECT_CLASS (gsm_app_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_properties));
+
+ g_free (app->priv->id);
+ app->priv->id = g_strdup_printf ("/org/mate/SessionManager/App%u", get_next_app_serial ());
+
+ res = register_app (app);
+ if (! res) {
+ g_warning ("Unable to register app with session bus");
+ }
+
+ return G_OBJECT (app);
+}
+
+static void
+gsm_app_init (GsmApp *app)
+{
+ app->priv = GSM_APP_GET_PRIVATE (app);
+}
+
+static void
+gsm_app_set_phase (GsmApp *app,
+ int phase)
+{
+ g_return_if_fail (GSM_IS_APP (app));
+
+ app->priv->phase = phase;
+}
+
+static void
+gsm_app_set_id (GsmApp *app,
+ const char *id)
+{
+ g_return_if_fail (GSM_IS_APP (app));
+
+ g_free (app->priv->id);
+
+ app->priv->id = g_strdup (id);
+ g_object_notify (G_OBJECT (app), "id");
+
+}
+static void
+gsm_app_set_startup_id (GsmApp *app,
+ const char *startup_id)
+{
+ g_return_if_fail (GSM_IS_APP (app));
+
+ g_free (app->priv->startup_id);
+
+ app->priv->startup_id = g_strdup (startup_id);
+ g_object_notify (G_OBJECT (app), "startup-id");
+
+}
+
+static void
+gsm_app_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GsmApp *app = GSM_APP (object);
+
+ switch (prop_id) {
+ case PROP_STARTUP_ID:
+ gsm_app_set_startup_id (app, g_value_get_string (value));
+ break;
+ case PROP_ID:
+ gsm_app_set_id (app, g_value_get_string (value));
+ break;
+ case PROP_PHASE:
+ gsm_app_set_phase (app, g_value_get_int (value));
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gsm_app_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GsmApp *app = GSM_APP (object);
+
+ switch (prop_id) {
+ case PROP_STARTUP_ID:
+ g_value_set_string (value, app->priv->startup_id);
+ break;
+ case PROP_ID:
+ g_value_set_string (value, app->priv->id);
+ break;
+ case PROP_PHASE:
+ g_value_set_int (value, app->priv->phase);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gsm_app_dispose (GObject *object)
+{
+ GsmApp *app = GSM_APP (object);
+
+ g_free (app->priv->startup_id);
+ app->priv->startup_id = NULL;
+
+ g_free (app->priv->id);
+ app->priv->id = NULL;
+
+ G_OBJECT_CLASS (gsm_app_parent_class)->dispose (object);
+}
+
+static void
+gsm_app_class_init (GsmAppClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->set_property = gsm_app_set_property;
+ object_class->get_property = gsm_app_get_property;
+ object_class->dispose = gsm_app_dispose;
+ object_class->constructor = gsm_app_constructor;
+
+ klass->impl_start = NULL;
+ klass->impl_get_app_id = NULL;
+ klass->impl_get_autorestart = NULL;
+ klass->impl_provides = NULL;
+ klass->impl_is_running = NULL;
+
+ g_object_class_install_property (object_class,
+ PROP_PHASE,
+ g_param_spec_int ("phase",
+ "Phase",
+ "Phase",
+ -1,
+ G_MAXINT,
+ -1,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_ID,
+ g_param_spec_string ("id",
+ "ID",
+ "ID",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class,
+ PROP_STARTUP_ID,
+ g_param_spec_string ("startup-id",
+ "startup ID",
+ "Session management startup ID",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ signals[EXITED] =
+ g_signal_new ("exited",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GsmAppClass, exited),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+ signals[DIED] =
+ g_signal_new ("died",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GsmAppClass, died),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ signals[REGISTERED] =
+ g_signal_new ("registered",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GsmAppClass, registered),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ g_type_class_add_private (klass, sizeof (GsmAppPrivate));
+ dbus_g_object_type_install_info (GSM_TYPE_APP, &dbus_glib_gsm_app_object_info);
+}
+
+const char *
+gsm_app_peek_id (GsmApp *app)
+{
+ return app->priv->id;
+}
+
+const char *
+gsm_app_peek_app_id (GsmApp *app)
+{
+ return GSM_APP_GET_CLASS (app)->impl_get_app_id (app);
+}
+
+const char *
+gsm_app_peek_startup_id (GsmApp *app)
+{
+ return app->priv->startup_id;
+}
+
+/**
+ * gsm_app_peek_phase:
+ * @app: a %GsmApp
+ *
+ * Returns @app's startup phase.
+ *
+ * Return value: @app's startup phase
+ **/
+GsmManagerPhase
+gsm_app_peek_phase (GsmApp *app)
+{
+ g_return_val_if_fail (GSM_IS_APP (app), GSM_MANAGER_PHASE_APPLICATION);
+
+ return app->priv->phase;
+}
+
+gboolean
+gsm_app_peek_is_disabled (GsmApp *app)
+{
+ g_return_val_if_fail (GSM_IS_APP (app), FALSE);
+
+ if (GSM_APP_GET_CLASS (app)->impl_is_disabled) {
+ return GSM_APP_GET_CLASS (app)->impl_is_disabled (app);
+ } else {
+ return FALSE;
+ }
+}
+
+gboolean
+gsm_app_peek_is_conditionally_disabled (GsmApp *app)
+{
+ g_return_val_if_fail (GSM_IS_APP (app), FALSE);
+
+ if (GSM_APP_GET_CLASS (app)->impl_is_conditionally_disabled) {
+ return GSM_APP_GET_CLASS (app)->impl_is_conditionally_disabled (app);
+ } else {
+ return FALSE;
+ }
+}
+
+gboolean
+gsm_app_is_running (GsmApp *app)
+{
+ g_return_val_if_fail (GSM_IS_APP (app), FALSE);
+
+ if (GSM_APP_GET_CLASS (app)->impl_is_running) {
+ return GSM_APP_GET_CLASS (app)->impl_is_running (app);
+ } else {
+ return FALSE;
+ }
+}
+
+gboolean
+gsm_app_peek_autorestart (GsmApp *app)
+{
+ g_return_val_if_fail (GSM_IS_APP (app), FALSE);
+
+ if (GSM_APP_GET_CLASS (app)->impl_get_autorestart) {
+ return GSM_APP_GET_CLASS (app)->impl_get_autorestart (app);
+ } else {
+ return FALSE;
+ }
+}
+
+gboolean
+gsm_app_provides (GsmApp *app, const char *service)
+{
+
+ if (GSM_APP_GET_CLASS (app)->impl_provides) {
+ return GSM_APP_GET_CLASS (app)->impl_provides (app, service);
+ } else {
+ return FALSE;
+ }
+}
+
+gboolean
+gsm_app_has_autostart_condition (GsmApp *app,
+ const char *condition)
+{
+
+ if (GSM_APP_GET_CLASS (app)->impl_has_autostart_condition) {
+ return GSM_APP_GET_CLASS (app)->impl_has_autostart_condition (app, condition);
+ } else {
+ return FALSE;
+ }
+}
+
+gboolean
+gsm_app_start (GsmApp *app,
+ GError **error)
+{
+ g_debug ("Starting app: %s", app->priv->id);
+
+ return GSM_APP_GET_CLASS (app)->impl_start (app, error);
+}
+
+gboolean
+gsm_app_restart (GsmApp *app,
+ GError **error)
+{
+ g_debug ("Re-starting app: %s", app->priv->id);
+
+ return GSM_APP_GET_CLASS (app)->impl_restart (app, error);
+}
+
+gboolean
+gsm_app_stop (GsmApp *app,
+ GError **error)
+{
+ return GSM_APP_GET_CLASS (app)->impl_stop (app, error);
+}
+
+void
+gsm_app_registered (GsmApp *app)
+{
+ g_return_if_fail (GSM_IS_APP (app));
+
+ g_signal_emit (app, signals[REGISTERED], 0);
+}
+
+void
+gsm_app_exited (GsmApp *app)
+{
+ g_return_if_fail (GSM_IS_APP (app));
+
+ g_signal_emit (app, signals[EXITED], 0);
+}
+
+void
+gsm_app_died (GsmApp *app)
+{
+ g_return_if_fail (GSM_IS_APP (app));
+
+ g_signal_emit (app, signals[DIED], 0);
+}
+
+gboolean
+gsm_app_get_app_id (GsmApp *app,
+ char **id,
+ GError **error)
+{
+ g_return_val_if_fail (GSM_IS_APP (app), FALSE);
+ *id = g_strdup (GSM_APP_GET_CLASS (app)->impl_get_app_id (app));
+ return TRUE;
+}
+
+gboolean
+gsm_app_get_startup_id (GsmApp *app,
+ char **id,
+ GError **error)
+{
+ g_return_val_if_fail (GSM_IS_APP (app), FALSE);
+ *id = g_strdup (app->priv->startup_id);
+ return TRUE;
+}
+
+gboolean
+gsm_app_get_phase (GsmApp *app,
+ guint *phase,
+ GError **error)
+{
+ g_return_val_if_fail (GSM_IS_APP (app), FALSE);
+ *phase = app->priv->phase;
+ return TRUE;
+}
diff --git a/mate-session/gsm-app.h b/mate-session/gsm-app.h
new file mode 100644
index 0000000..eaef6c5
--- /dev/null
+++ b/mate-session/gsm-app.h
@@ -0,0 +1,136 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Novell, Inc.
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * 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
+ * Lesser 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_APP_H__
+#define __GSM_APP_H__
+
+#include <glib-object.h>
+#include <sys/types.h>
+
+#include "eggdesktopfile.h"
+
+#include "gsm-manager.h"
+#include "gsm-client.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GSM_TYPE_APP (gsm_app_get_type ())
+#define GSM_APP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSM_TYPE_APP, GsmApp))
+#define GSM_APP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSM_TYPE_APP, GsmAppClass))
+#define GSM_IS_APP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSM_TYPE_APP))
+#define GSM_IS_APP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSM_TYPE_APP))
+#define GSM_APP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSM_TYPE_APP, GsmAppClass))
+
+typedef struct _GsmApp GsmApp;
+typedef struct _GsmAppClass GsmAppClass;
+typedef struct _GsmAppPrivate GsmAppPrivate;
+
+struct _GsmApp
+{
+ GObject parent;
+ GsmAppPrivate *priv;
+};
+
+struct _GsmAppClass
+{
+ GObjectClass parent_class;
+
+ /* signals */
+ void (*exited) (GsmApp *app);
+ void (*died) (GsmApp *app);
+ void (*registered) (GsmApp *app);
+
+ /* virtual methods */
+ gboolean (*impl_start) (GsmApp *app,
+ GError **error);
+ gboolean (*impl_restart) (GsmApp *app,
+ GError **error);
+ gboolean (*impl_stop) (GsmApp *app,
+ GError **error);
+ gboolean (*impl_provides) (GsmApp *app,
+ const char *service);
+ gboolean (*impl_has_autostart_condition) (GsmApp *app,
+ const char *service);
+ gboolean (*impl_is_running) (GsmApp *app);
+
+ gboolean (*impl_get_autorestart) (GsmApp *app);
+ const char *(*impl_get_app_id) (GsmApp *app);
+ gboolean (*impl_is_disabled) (GsmApp *app);
+ gboolean (*impl_is_conditionally_disabled) (GsmApp *app);
+};
+
+typedef enum
+{
+ GSM_APP_ERROR_GENERAL = 0,
+ GSM_APP_ERROR_START,
+ GSM_APP_ERROR_STOP,
+ GSM_APP_NUM_ERRORS
+} GsmAppError;
+
+#define GSM_APP_ERROR gsm_app_error_quark ()
+
+GQuark gsm_app_error_quark (void);
+GType gsm_app_get_type (void) G_GNUC_CONST;
+
+gboolean gsm_app_peek_autorestart (GsmApp *app);
+
+const char *gsm_app_peek_id (GsmApp *app);
+const char *gsm_app_peek_app_id (GsmApp *app);
+const char *gsm_app_peek_startup_id (GsmApp *app);
+GsmManagerPhase gsm_app_peek_phase (GsmApp *app);
+gboolean gsm_app_peek_is_disabled (GsmApp *app);
+gboolean gsm_app_peek_is_conditionally_disabled (GsmApp *app);
+
+gboolean gsm_app_start (GsmApp *app,
+ GError **error);
+gboolean gsm_app_restart (GsmApp *app,
+ GError **error);
+gboolean gsm_app_stop (GsmApp *app,
+ GError **error);
+gboolean gsm_app_is_running (GsmApp *app);
+
+void gsm_app_exited (GsmApp *app);
+void gsm_app_died (GsmApp *app);
+
+gboolean gsm_app_provides (GsmApp *app,
+ const char *service);
+gboolean gsm_app_has_autostart_condition (GsmApp *app,
+ const char *condition);
+void gsm_app_registered (GsmApp *app);
+
+/* exported to bus */
+gboolean gsm_app_get_app_id (GsmApp *app,
+ char **id,
+ GError **error);
+gboolean gsm_app_get_startup_id (GsmApp *app,
+ char **id,
+ GError **error);
+gboolean gsm_app_get_phase (GsmApp *app,
+ guint *phase,
+ GError **error);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GSM_APP_H__ */
diff --git a/mate-session/gsm-autostart-app.c b/mate-session/gsm-autostart-app.c
new file mode 100644
index 0000000..a696a96
--- /dev/null
+++ b/mate-session/gsm-autostart-app.c
@@ -0,0 +1,1144 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Novell, Inc.
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * 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
+ * Lesser 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 <ctype.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#include <mateconf/mateconf-client.h>
+
+#include "gsm-autostart-app.h"
+#include "gsm-util.h"
+
+enum {
+ AUTOSTART_LAUNCH_SPAWN = 0,
+ AUTOSTART_LAUNCH_ACTIVATE
+};
+
+enum {
+ GSM_CONDITION_NONE = 0,
+ GSM_CONDITION_IF_EXISTS = 1,
+ GSM_CONDITION_UNLESS_EXISTS = 2,
+ GSM_CONDITION_MATE = 3,
+ GSM_CONDITION_UNKNOWN = 4
+};
+
+#define GSM_SESSION_CLIENT_DBUS_INTERFACE "org.mate.SessionClient"
+
+struct _GsmAutostartAppPrivate {
+ char *desktop_filename;
+ char *desktop_id;
+ char *startup_id;
+
+ EggDesktopFile *desktop_file;
+
+ /* desktop file state */
+ char *condition_string;
+ gboolean condition;
+ gboolean autorestart;
+
+ GFileMonitor *condition_monitor;
+ guint condition_notify_id;
+
+ int launch_type;
+ GPid pid;
+ guint child_watch_id;
+
+ DBusGProxy *proxy;
+ DBusGProxyCall *proxy_call;
+};
+
+enum {
+ CONDITION_CHANGED,
+ LAST_SIGNAL
+};
+
+enum {
+ PROP_0,
+ PROP_DESKTOP_FILENAME
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+#define GSM_AUTOSTART_APP_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), GSM_TYPE_AUTOSTART_APP, GsmAutostartAppPrivate))
+
+G_DEFINE_TYPE (GsmAutostartApp, gsm_autostart_app, GSM_TYPE_APP)
+
+static void
+gsm_autostart_app_init (GsmAutostartApp *app)
+{
+ app->priv = GSM_AUTOSTART_APP_GET_PRIVATE (app);
+
+ app->priv->pid = -1;
+ app->priv->condition_monitor = NULL;
+ app->priv->condition = FALSE;
+}
+
+static gboolean
+is_disabled (GsmApp *app)
+{
+ GsmAutostartAppPrivate *priv;
+
+ priv = GSM_AUTOSTART_APP (app)->priv;
+
+ /* GSM_AUTOSTART_APP_ENABLED_KEY key, used by old mate-session */
+ if (egg_desktop_file_has_key (priv->desktop_file,
+ GSM_AUTOSTART_APP_ENABLED_KEY, NULL) &&
+ !egg_desktop_file_get_boolean (priv->desktop_file,
+ GSM_AUTOSTART_APP_ENABLED_KEY, NULL)) {
+ g_debug ("app %s is disabled by " GSM_AUTOSTART_APP_ENABLED_KEY,
+ gsm_app_peek_id (app));
+ return TRUE;
+ }
+
+ /* Hidden key, used by autostart spec */
+ if (egg_desktop_file_get_boolean (priv->desktop_file,
+ EGG_DESKTOP_FILE_KEY_HIDDEN, NULL)) {
+ g_debug ("app %s is disabled by Hidden",
+ gsm_app_peek_id (app));
+ return TRUE;
+ }
+
+ /* Check OnlyShowIn/NotShowIn/TryExec */
+ if (!egg_desktop_file_can_launch (priv->desktop_file, "MATE")) {
+ g_debug ("app %s not installed or not for MATE",
+ gsm_app_peek_id (app));
+ return TRUE;
+ }
+
+ /* Do not check AutostartCondition - this method is only to determine
+ if the app is unconditionally disabled */
+
+ return FALSE;
+}
+
+static gboolean
+parse_condition_string (const char *condition_string,
+ guint *condition_kindp,
+ char **keyp)
+{
+ const char *space;
+ const char *key;
+ int len;
+ guint kind;
+
+ space = condition_string + strcspn (condition_string, " ");
+ len = space - condition_string;
+ key = space;
+ while (isspace ((unsigned char)*key)) {
+ key++;
+ }
+
+ if (!g_ascii_strncasecmp (condition_string, "if-exists", len) && key) {
+ kind = GSM_CONDITION_IF_EXISTS;
+ } else if (!g_ascii_strncasecmp (condition_string, "unless-exists", len) && key) {
+ kind = GSM_CONDITION_UNLESS_EXISTS;
+ } else if (!g_ascii_strncasecmp (condition_string, "MATE", len)) {
+ kind = GSM_CONDITION_MATE;
+ } else {
+ key = NULL;
+ kind = GSM_CONDITION_UNKNOWN;
+ }
+
+ if (keyp != NULL) {
+ *keyp = g_strdup (key);
+ }
+
+ if (condition_kindp != NULL) {
+ *condition_kindp = kind;
+ }
+
+ return (kind != GSM_CONDITION_UNKNOWN);
+}
+
+static void
+if_exists_condition_cb (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event,
+ GsmApp *app)
+{
+ GsmAutostartAppPrivate *priv;
+ gboolean condition = FALSE;
+
+ priv = GSM_AUTOSTART_APP (app)->priv;
+
+ switch (event) {
+ case G_FILE_MONITOR_EVENT_CREATED:
+ condition = TRUE;
+ break;
+ case G_FILE_MONITOR_EVENT_DELETED:
+ condition = FALSE;
+ break;
+ default:
+ /* Ignore any other monitor event */
+ return;
+ }
+
+ /* Emit only if the condition actually changed */
+ if (condition != priv->condition) {
+ priv->condition = condition;
+ g_signal_emit (app, signals[CONDITION_CHANGED], 0, condition);
+ }
+}
+
+static void
+unless_exists_condition_cb (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event,
+ GsmApp *app)
+{
+ GsmAutostartAppPrivate *priv;
+ gboolean condition = FALSE;
+
+ priv = GSM_AUTOSTART_APP (app)->priv;
+
+ switch (event) {
+ case G_FILE_MONITOR_EVENT_CREATED:
+ condition = FALSE;
+ break;
+ case G_FILE_MONITOR_EVENT_DELETED:
+ condition = TRUE;
+ break;
+ default:
+ /* Ignore any other monitor event */
+ return;
+ }
+
+ /* Emit only if the condition actually changed */
+ if (condition != priv->condition) {
+ priv->condition = condition;
+ g_signal_emit (app, signals[CONDITION_CHANGED], 0, condition);
+ }
+}
+
+static void
+mateconf_condition_cb (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ gpointer user_data)
+{
+ GsmApp *app;
+ GsmAutostartAppPrivate *priv;
+ gboolean condition;
+
+ g_return_if_fail (GSM_IS_APP (user_data));
+
+ app = GSM_APP (user_data);
+
+ priv = GSM_AUTOSTART_APP (app)->priv;
+
+ condition = FALSE;
+ if (entry->value != NULL && entry->value->type == MATECONF_VALUE_BOOL) {
+ condition = mateconf_value_get_bool (entry->value);
+ }
+
+ g_debug ("GsmAutostartApp: app:%s condition changed condition:%d",
+ gsm_app_peek_id (app),
+ condition);
+
+ /* Emit only if the condition actually changed */
+ if (condition != priv->condition) {
+ priv->condition = condition;
+ g_signal_emit (app, signals[CONDITION_CHANGED], 0, condition);
+ }
+}
+
+static void
+setup_condition_monitor (GsmAutostartApp *app)
+{
+ guint kind;
+ char *key;
+ gboolean res;
+ gboolean disabled;
+
+ if (app->priv->condition_monitor != NULL) {
+ g_file_monitor_cancel (app->priv->condition_monitor);
+ }
+
+ if (app->priv->condition_notify_id > 0) {
+ MateConfClient *client;
+ client = mateconf_client_get_default ();
+ mateconf_client_notify_remove (client,
+ app->priv->condition_notify_id);
+ app->priv->condition_notify_id = 0;
+ }
+
+ if (app->priv->condition_string == NULL) {
+ return;
+ }
+
+ /* if it is disabled outright there is no point in monitoring */
+ if (is_disabled (GSM_APP (app))) {
+ return;
+ }
+
+ key = NULL;
+ res = parse_condition_string (app->priv->condition_string, &kind, &key);
+ if (! res) {
+ g_free (key);
+ return;
+ }
+
+ if (key == NULL) {
+ return;
+ }
+
+ if (kind == GSM_CONDITION_IF_EXISTS) {
+ char *file_path;
+ GFile *file;
+
+ file_path = g_build_filename (g_get_user_config_dir (), key, NULL);
+
+ disabled = !g_file_test (file_path, G_FILE_TEST_EXISTS);
+
+ file = g_file_new_for_path (file_path);
+ app->priv->condition_monitor = g_file_monitor_file (file, 0, NULL, NULL);
+
+ g_signal_connect (app->priv->condition_monitor, "changed",
+ G_CALLBACK (if_exists_condition_cb),
+ app);
+
+ g_object_unref (file);
+ g_free (file_path);
+ } else if (kind == GSM_CONDITION_UNLESS_EXISTS) {
+ char *file_path;
+ GFile *file;
+
+ file_path = g_build_filename (g_get_user_config_dir (), key, NULL);
+
+ disabled = g_file_test (file_path, G_FILE_TEST_EXISTS);
+
+ file = g_file_new_for_path (file_path);
+ app->priv->condition_monitor = g_file_monitor_file (file, 0, NULL, NULL);
+
+ g_signal_connect (app->priv->condition_monitor, "changed",
+ G_CALLBACK (unless_exists_condition_cb),
+ app);
+
+ g_object_unref (file);
+ g_free (file_path);
+ } else if (kind == GSM_CONDITION_MATE) {
+ MateConfClient *client;
+ char *dir;
+
+ client = mateconf_client_get_default ();
+ g_assert (MATECONF_IS_CLIENT (client));
+
+ disabled = !mateconf_client_get_bool (client, key, NULL);
+
+ dir = g_path_get_dirname (key);
+
+ mateconf_client_add_dir (client,
+ dir,
+ MATECONF_CLIENT_PRELOAD_NONE, NULL);
+ g_free (dir);
+
+ app->priv->condition_notify_id = mateconf_client_notify_add (client,
+ key,
+ mateconf_condition_cb,
+ app, NULL, NULL);
+ g_object_unref (client);
+ } else {
+ disabled = TRUE;
+ }
+
+ g_free (key);
+
+ /* FIXME: cache the disabled value? */
+}
+
+static gboolean
+load_desktop_file (GsmAutostartApp *app)
+{
+ char *dbus_name;
+ char *startup_id;
+ char *phase_str;
+ int phase;
+ gboolean res;
+
+ if (app->priv->desktop_file == NULL) {
+ return FALSE;
+ }
+
+ phase_str = egg_desktop_file_get_string (app->priv->desktop_file,
+ GSM_AUTOSTART_APP_PHASE_KEY,
+ NULL);
+ if (phase_str != NULL) {
+ if (strcmp (phase_str, "Initialization") == 0) {
+ phase = GSM_MANAGER_PHASE_INITIALIZATION;
+ } else if (strcmp (phase_str, "WindowManager") == 0) {
+ phase = GSM_MANAGER_PHASE_WINDOW_MANAGER;
+ } else if (strcmp (phase_str, "Panel") == 0) {
+ phase = GSM_MANAGER_PHASE_PANEL;
+ } else if (strcmp (phase_str, "Desktop") == 0) {
+ phase = GSM_MANAGER_PHASE_DESKTOP;
+ } else {
+ phase = GSM_MANAGER_PHASE_APPLICATION;
+ }
+
+ g_free (phase_str);
+ } else {
+ phase = GSM_MANAGER_PHASE_APPLICATION;
+ }
+
+ dbus_name = egg_desktop_file_get_string (app->priv->desktop_file,
+ GSM_AUTOSTART_APP_DBUS_NAME_KEY,
+ NULL);
+ if (dbus_name != NULL) {
+ app->priv->launch_type = AUTOSTART_LAUNCH_ACTIVATE;
+ } else {
+ app->priv->launch_type = AUTOSTART_LAUNCH_SPAWN;
+ }
+
+ /* this must only be done on first load */
+ switch (app->priv->launch_type) {
+ case AUTOSTART_LAUNCH_SPAWN:
+ startup_id =
+ egg_desktop_file_get_string (app->priv->desktop_file,
+ GSM_AUTOSTART_APP_STARTUP_ID_KEY,
+ NULL);
+
+ if (startup_id == NULL) {
+ startup_id = gsm_util_generate_startup_id ();
+ }
+ break;
+ case AUTOSTART_LAUNCH_ACTIVATE:
+ startup_id = g_strdup (dbus_name);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ res = egg_desktop_file_has_key (app->priv->desktop_file,
+ GSM_AUTOSTART_APP_AUTORESTART_KEY,
+ NULL);
+ if (res) {
+ app->priv->autorestart = egg_desktop_file_get_boolean (app->priv->desktop_file,
+ GSM_AUTOSTART_APP_AUTORESTART_KEY,
+ NULL);
+ } else {
+ app->priv->autorestart = FALSE;
+ }
+
+ g_free (app->priv->condition_string);
+ app->priv->condition_string = egg_desktop_file_get_string (app->priv->desktop_file,
+ "AutostartCondition",
+ NULL);
+ setup_condition_monitor (app);
+
+ g_object_set (app,
+ "phase", phase,
+ "startup-id", startup_id,
+ NULL);
+
+ g_free (startup_id);
+ g_free (dbus_name);
+
+ return TRUE;
+}
+
+static void
+gsm_autostart_app_set_desktop_filename (GsmAutostartApp *app,
+ const char *desktop_filename)
+{
+ GError *error;
+
+ if (app->priv->desktop_file != NULL) {
+ egg_desktop_file_free (app->priv->desktop_file);
+ app->priv->desktop_file = NULL;
+ g_free (app->priv->desktop_id);
+ }
+
+ if (desktop_filename == NULL) {
+ return;
+ }
+
+ app->priv->desktop_id = g_path_get_basename (desktop_filename);
+
+ error = NULL;
+ app->priv->desktop_file = egg_desktop_file_new (desktop_filename, &error);
+ if (app->priv->desktop_file == NULL) {
+ g_warning ("Could not parse desktop file %s: %s",
+ desktop_filename,
+ error->message);
+ g_error_free (error);
+ return;
+ }
+}
+
+static void
+gsm_autostart_app_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GsmAutostartApp *self;
+
+ self = GSM_AUTOSTART_APP (object);
+
+ switch (prop_id) {
+ case PROP_DESKTOP_FILENAME:
+ gsm_autostart_app_set_desktop_filename (self, g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gsm_autostart_app_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GsmAutostartApp *self;
+
+ self = GSM_AUTOSTART_APP (object);
+
+ switch (prop_id) {
+ case PROP_DESKTOP_FILENAME:
+ if (self->priv->desktop_file != NULL) {
+ g_value_set_string (value, egg_desktop_file_get_source (self->priv->desktop_file));
+ } else {
+ g_value_set_string (value, NULL);
+ }
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gsm_autostart_app_dispose (GObject *object)
+{
+ GsmAutostartAppPrivate *priv;
+
+ priv = GSM_AUTOSTART_APP (object)->priv;
+
+ if (priv->startup_id) {
+ g_free (priv->startup_id);
+ priv->startup_id = NULL;
+ }
+
+ if (priv->condition_string) {
+ g_free (priv->condition_string);
+ priv->condition_string = NULL;
+ }
+
+ if (priv->desktop_file) {
+ egg_desktop_file_free (priv->desktop_file);
+ priv->desktop_file = NULL;
+ }
+
+ if (priv->desktop_id) {
+ g_free (priv->desktop_id);
+ priv->desktop_id = NULL;
+ }
+
+ if (priv->child_watch_id > 0) {
+ g_source_remove (priv->child_watch_id);
+ priv->child_watch_id = 0;
+ }
+
+ if (priv->proxy_call != NULL) {
+ dbus_g_proxy_cancel_call (priv->proxy, priv->proxy_call);
+ priv->proxy_call = NULL;
+ }
+
+ if (priv->proxy != NULL) {
+ g_object_unref (priv->proxy);
+ priv->proxy = NULL;
+ }
+
+ if (priv->condition_monitor) {
+ g_file_monitor_cancel (priv->condition_monitor);
+ }
+
+ G_OBJECT_CLASS (gsm_autostart_app_parent_class)->dispose (object);
+}
+
+static gboolean
+is_running (GsmApp *app)
+{
+ GsmAutostartAppPrivate *priv;
+ gboolean is;
+
+ priv = GSM_AUTOSTART_APP (app)->priv;
+
+ /* is running if pid is still valid or
+ * or a client is connected
+ */
+ /* FIXME: check client */
+ is = (priv->pid != -1);
+
+ return is;
+}
+
+static gboolean
+is_conditionally_disabled (GsmApp *app)
+{
+ GsmAutostartAppPrivate *priv;
+ gboolean res;
+ gboolean disabled;
+ char *key;
+ guint kind;
+
+ priv = GSM_AUTOSTART_APP (app)->priv;
+
+ /* Check AutostartCondition */
+ if (priv->condition_string == NULL) {
+ return FALSE;
+ }
+
+ key = NULL;
+ res = parse_condition_string (priv->condition_string, &kind, &key);
+ if (! res) {
+ g_free (key);
+ return TRUE;
+ }
+
+ if (key == NULL) {
+ return TRUE;
+ }
+
+ if (kind == GSM_CONDITION_IF_EXISTS) {
+ char *file_path;
+
+ file_path = g_build_filename (g_get_user_config_dir (), key, NULL);
+ disabled = !g_file_test (file_path, G_FILE_TEST_EXISTS);
+ g_free (file_path);
+ } else if (kind == GSM_CONDITION_UNLESS_EXISTS) {
+ char *file_path;
+
+ file_path = g_build_filename (g_get_user_config_dir (), key, NULL);
+ disabled = g_file_test (file_path, G_FILE_TEST_EXISTS);
+ g_free (file_path);
+ } else if (kind == GSM_CONDITION_MATE) {
+ MateConfClient *client;
+ client = mateconf_client_get_default ();
+ g_assert (MATECONF_IS_CLIENT (client));
+ disabled = !mateconf_client_get_bool (client, key, NULL);
+ g_object_unref (client);
+ } else {
+ disabled = TRUE;
+ }
+
+ /* Set initial condition */
+ priv->condition = !disabled;
+
+ g_free (key);
+
+ return disabled;
+}
+
+static void
+app_exited (GPid pid,
+ int status,
+ GsmAutostartApp *app)
+{
+ g_debug ("GsmAutostartApp: (pid:%d) done (%s:%d)",
+ (int) pid,
+ WIFEXITED (status) ? "status"
+ : WIFSIGNALED (status) ? "signal"
+ : "unknown",
+ WIFEXITED (status) ? WEXITSTATUS (status)
+ : WIFSIGNALED (status) ? WTERMSIG (status)
+ : -1);
+
+ g_spawn_close_pid (app->priv->pid);
+ app->priv->pid = -1;
+ app->priv->child_watch_id = 0;
+
+ if (WIFEXITED (status)) {
+ gsm_app_exited (GSM_APP (app));
+ } else if (WIFSIGNALED (status)) {
+ gsm_app_died (GSM_APP (app));
+ }
+}
+
+static int
+_signal_pid (int pid,
+ int signal)
+{
+ int status = -1;
+
+ /* perhaps block sigchld */
+ g_debug ("GsmAutostartApp: sending signal %d to process %d", signal, pid);
+ errno = 0;
+ status = kill (pid, signal);
+
+ if (status < 0) {
+ if (errno == ESRCH) {
+ g_warning ("Child process %d was already dead.",
+ (int)pid);
+ } else {
+ g_warning ("Couldn't kill child process %d: %s",
+ pid,
+ g_strerror (errno));
+ }
+ }
+
+ /* perhaps unblock sigchld */
+
+ return status;
+}
+
+static gboolean
+autostart_app_stop_spawn (GsmAutostartApp *app,
+ GError **error)
+{
+ int res;
+
+ if (app->priv->pid < 1) {
+ g_set_error (error,
+ GSM_APP_ERROR,
+ GSM_APP_ERROR_STOP,
+ "Not running");
+ return FALSE;
+ }
+
+ res = _signal_pid (app->priv->pid, SIGTERM);
+ if (res != 0) {
+ g_set_error (error,
+ GSM_APP_ERROR,
+ GSM_APP_ERROR_STOP,
+ "Unable to stop: %s",
+ g_strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+autostart_app_stop_activate (GsmAutostartApp *app,
+ GError **error)
+{
+ return TRUE;
+}
+
+static gboolean
+gsm_autostart_app_stop (GsmApp *app,
+ GError **error)
+{
+ GsmAutostartApp *aapp;
+ gboolean ret;
+
+ aapp = GSM_AUTOSTART_APP (app);
+
+ g_return_val_if_fail (aapp->priv->desktop_file != NULL, FALSE);
+
+ switch (aapp->priv->launch_type) {
+ case AUTOSTART_LAUNCH_SPAWN:
+ ret = autostart_app_stop_spawn (aapp, error);
+ break;
+ case AUTOSTART_LAUNCH_ACTIVATE:
+ ret = autostart_app_stop_activate (aapp, error);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ return ret;
+}
+
+static gboolean
+autostart_app_start_spawn (GsmAutostartApp *app,
+ GError **error)
+{
+ char *env[2] = { NULL, NULL };
+ gboolean success;
+ GError *local_error;
+ const char *startup_id;
+ char *command;
+
+ startup_id = gsm_app_peek_startup_id (GSM_APP (app));
+ g_assert (startup_id != NULL);
+
+ env[0] = g_strdup_printf ("DESKTOP_AUTOSTART_ID=%s", startup_id);
+
+ local_error = NULL;
+ command = egg_desktop_file_parse_exec (app->priv->desktop_file,
+ NULL,
+ &local_error);
+ if (command == NULL) {
+ g_warning ("Unable to parse command from '%s': %s",
+ egg_desktop_file_get_source (app->priv->desktop_file),
+ local_error->message);
+ g_error_free (local_error);
+ }
+
+ g_debug ("GsmAutostartApp: starting %s: command=%s startup-id=%s", app->priv->desktop_id, command, startup_id);
+ g_free (command);
+
+ g_free (app->priv->startup_id);
+ local_error = NULL;
+ success = egg_desktop_file_launch (app->priv->desktop_file,
+ NULL,
+ &local_error,
+ EGG_DESKTOP_FILE_LAUNCH_PUTENV, env,
+ EGG_DESKTOP_FILE_LAUNCH_FLAGS, G_SPAWN_DO_NOT_REAP_CHILD,
+ EGG_DESKTOP_FILE_LAUNCH_RETURN_PID, &app->priv->pid,
+ EGG_DESKTOP_FILE_LAUNCH_RETURN_STARTUP_ID, &app->priv->startup_id,
+ NULL);
+ g_free (env[0]);
+
+ if (success) {
+ g_debug ("GsmAutostartApp: started pid:%d", app->priv->pid);
+ app->priv->child_watch_id = g_child_watch_add (app->priv->pid,
+ (GChildWatchFunc)app_exited,
+ app);
+ } else {
+ g_set_error (error,
+ GSM_APP_ERROR,
+ GSM_APP_ERROR_START,
+ "Unable to start application: %s", local_error->message);
+ g_error_free (local_error);
+ }
+
+ return success;
+}
+
+static void
+start_notify (DBusGProxy *proxy,
+ DBusGProxyCall *call,
+ GsmAutostartApp *app)
+{
+ gboolean res;
+ GError *error;
+
+ error = NULL;
+ res = dbus_g_proxy_end_call (proxy,
+ call,
+ &error,
+ G_TYPE_INVALID);
+ app->priv->proxy_call = NULL;
+
+ if (! res) {
+ g_warning ("GsmAutostartApp: Error starting application: %s", error->message);
+ g_error_free (error);
+ } else {
+ g_debug ("GsmAutostartApp: Started application %s", app->priv->desktop_id);
+ }
+}
+
+static gboolean
+autostart_app_start_activate (GsmAutostartApp *app,
+ GError **error)
+{
+ const char *name;
+ char *path;
+ char *arguments;
+ DBusGConnection *bus;
+ GError *local_error;
+
+ local_error = NULL;
+ bus = dbus_g_bus_get (DBUS_BUS_SESSION, &local_error);
+ if (bus == NULL) {
+ if (local_error != NULL) {
+ g_warning ("error getting session bus: %s", local_error->message);
+ }
+ g_propagate_error (error, local_error);
+ return FALSE;
+ }
+
+ name = gsm_app_peek_startup_id (GSM_APP (app));
+ g_assert (name != NULL);
+
+ path = egg_desktop_file_get_string (app->priv->desktop_file,
+ GSM_AUTOSTART_APP_DBUS_PATH_KEY,
+ NULL);
+ if (path == NULL) {
+ /* just pick one? */
+ path = g_strdup ("/");
+ }
+
+ arguments = egg_desktop_file_get_string (app->priv->desktop_file,
+ GSM_AUTOSTART_APP_DBUS_ARGS_KEY,
+ NULL);
+
+ app->priv->proxy = dbus_g_proxy_new_for_name (bus,
+ name,
+ path,
+ GSM_SESSION_CLIENT_DBUS_INTERFACE);
+ if (app->priv->proxy == NULL) {
+ g_set_error (error,
+ GSM_APP_ERROR,
+ GSM_APP_ERROR_START,
+ "Unable to start application: unable to create proxy for client");
+ return FALSE;
+ }
+
+ app->priv->proxy_call = dbus_g_proxy_begin_call (app->priv->proxy,
+ "Start",
+ (DBusGProxyCallNotify)start_notify,
+ app,
+ NULL,
+ G_TYPE_STRING, arguments,
+ G_TYPE_INVALID);
+ if (app->priv->proxy_call == NULL) {
+ g_object_unref (app->priv->proxy);
+ app->priv->proxy = NULL;
+ g_set_error (error,
+ GSM_APP_ERROR,
+ GSM_APP_ERROR_START,
+ "Unable to start application: unable to call Start on client");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+gsm_autostart_app_start (GsmApp *app,
+ GError **error)
+{
+ GsmAutostartApp *aapp;
+ gboolean ret;
+
+ aapp = GSM_AUTOSTART_APP (app);
+
+ g_return_val_if_fail (aapp->priv->desktop_file != NULL, FALSE);
+
+ switch (aapp->priv->launch_type) {
+ case AUTOSTART_LAUNCH_SPAWN:
+ ret = autostart_app_start_spawn (aapp, error);
+ break;
+ case AUTOSTART_LAUNCH_ACTIVATE:
+ ret = autostart_app_start_activate (aapp, error);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ return ret;
+}
+
+static gboolean
+gsm_autostart_app_restart (GsmApp *app,
+ GError **error)
+{
+ GError *local_error;
+ gboolean res;
+
+ /* ignore stop errors - it is fine if it is already stopped */
+ local_error = NULL;
+ res = gsm_app_stop (app, &local_error);
+ if (! res) {
+ g_debug ("GsmAutostartApp: Couldn't stop app: %s", local_error->message);
+ g_error_free (local_error);
+ }
+
+ res = gsm_app_start (app, &local_error);
+ if (! res) {
+ g_propagate_error (error, local_error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+gsm_autostart_app_provides (GsmApp *app,
+ const char *service)
+{
+ char **provides;
+ gsize len;
+ gsize i;
+ GsmAutostartApp *aapp;
+
+ g_return_val_if_fail (GSM_IS_APP (app), FALSE);
+
+ aapp = GSM_AUTOSTART_APP (app);
+
+ if (aapp->priv->desktop_file == NULL) {
+ return FALSE;
+ }
+
+ provides = egg_desktop_file_get_string_list (aapp->priv->desktop_file,
+ GSM_AUTOSTART_APP_PROVIDES_KEY,
+ &len, NULL);
+ if (!provides) {
+ return FALSE;
+ }
+
+ for (i = 0; i < len; i++) {
+ if (!strcmp (provides[i], service)) {
+ g_strfreev (provides);
+ return TRUE;
+ }
+ }
+
+ g_strfreev (provides);
+ return FALSE;
+}
+
+static gboolean
+gsm_autostart_app_has_autostart_condition (GsmApp *app,
+ const char *condition)
+{
+ GsmAutostartApp *aapp;
+
+ g_return_val_if_fail (GSM_IS_APP (app), FALSE);
+ g_return_val_if_fail (condition != NULL, FALSE);
+
+ aapp = GSM_AUTOSTART_APP (app);
+
+ if (aapp->priv->condition_string == NULL) {
+ return FALSE;
+ }
+
+ if (strcmp (aapp->priv->condition_string, condition) == 0) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+gsm_autostart_app_get_autorestart (GsmApp *app)
+{
+ gboolean res;
+ gboolean autorestart;
+
+ if (GSM_AUTOSTART_APP (app)->priv->desktop_file == NULL) {
+ return FALSE;
+ }
+
+ autorestart = FALSE;
+
+ res = egg_desktop_file_has_key (GSM_AUTOSTART_APP (app)->priv->desktop_file,
+ GSM_AUTOSTART_APP_AUTORESTART_KEY,
+ NULL);
+ if (res) {
+ autorestart = egg_desktop_file_get_boolean (GSM_AUTOSTART_APP (app)->priv->desktop_file,
+ GSM_AUTOSTART_APP_AUTORESTART_KEY,
+ NULL);
+ }
+
+ return autorestart;
+}
+
+static const char *
+gsm_autostart_app_get_app_id (GsmApp *app)
+{
+ const char *location;
+ const char *slash;
+
+ if (GSM_AUTOSTART_APP (app)->priv->desktop_file == NULL) {
+ return NULL;
+ }
+
+ location = egg_desktop_file_get_source (GSM_AUTOSTART_APP (app)->priv->desktop_file);
+
+ slash = strrchr (location, '/');
+ if (slash != NULL) {
+ return slash + 1;
+ } else {
+ return location;
+ }
+}
+
+static GObject *
+gsm_autostart_app_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GsmAutostartApp *app;
+
+ app = GSM_AUTOSTART_APP (G_OBJECT_CLASS (gsm_autostart_app_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_properties));
+
+ if (! load_desktop_file (app)) {
+ g_object_unref (app);
+ app = NULL;
+ }
+
+ return G_OBJECT (app);
+}
+
+static void
+gsm_autostart_app_class_init (GsmAutostartAppClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GsmAppClass *app_class = GSM_APP_CLASS (klass);
+
+ object_class->set_property = gsm_autostart_app_set_property;
+ object_class->get_property = gsm_autostart_app_get_property;
+ object_class->dispose = gsm_autostart_app_dispose;
+ object_class->constructor = gsm_autostart_app_constructor;
+
+ app_class->impl_is_disabled = is_disabled;
+ app_class->impl_is_conditionally_disabled = is_conditionally_disabled;
+ app_class->impl_is_running = is_running;
+ app_class->impl_start = gsm_autostart_app_start;
+ app_class->impl_restart = gsm_autostart_app_restart;
+ app_class->impl_stop = gsm_autostart_app_stop;
+ app_class->impl_provides = gsm_autostart_app_provides;
+ app_class->impl_has_autostart_condition = gsm_autostart_app_has_autostart_condition;
+ app_class->impl_get_app_id = gsm_autostart_app_get_app_id;
+ app_class->impl_get_autorestart = gsm_autostart_app_get_autorestart;
+
+ g_object_class_install_property (object_class,
+ PROP_DESKTOP_FILENAME,
+ g_param_spec_string ("desktop-filename",
+ "Desktop filename",
+ "Freedesktop .desktop file",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ signals[CONDITION_CHANGED] =
+ g_signal_new ("condition-changed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GsmAutostartAppClass, condition_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__BOOLEAN,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_BOOLEAN);
+
+ g_type_class_add_private (object_class, sizeof (GsmAutostartAppPrivate));
+}
+
+GsmApp *
+gsm_autostart_app_new (const char *desktop_file)
+{
+ GsmAutostartApp *app;
+
+ app = g_object_new (GSM_TYPE_AUTOSTART_APP,
+ "desktop-filename", desktop_file,
+ NULL);
+
+ return GSM_APP (app);
+}
diff --git a/mate-session/gsm-autostart-app.h b/mate-session/gsm-autostart-app.h
new file mode 100644
index 0000000..866522d
--- /dev/null
+++ b/mate-session/gsm-autostart-app.h
@@ -0,0 +1,78 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Novell, Inc.
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * 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
+ * Lesser 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_AUTOSTART_APP_H__
+#define __GSM_AUTOSTART_APP_H__
+
+#include "gsm-app.h"
+
+#include <X11/SM/SMlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GSM_TYPE_AUTOSTART_APP (gsm_autostart_app_get_type ())
+#define GSM_AUTOSTART_APP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSM_TYPE_AUTOSTART_APP, GsmAutostartApp))
+#define GSM_AUTOSTART_APP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSM_TYPE_AUTOSTART_APP, GsmAutostartAppClass))
+#define GSM_IS_AUTOSTART_APP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSM_TYPE_AUTOSTART_APP))
+#define GSM_IS_AUTOSTART_APP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSM_TYPE_AUTOSTART_APP))
+#define GSM_AUTOSTART_APP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSM_TYPE_AUTOSTART_APP, GsmAutostartAppClass))
+
+typedef struct _GsmAutostartApp GsmAutostartApp;
+typedef struct _GsmAutostartAppClass GsmAutostartAppClass;
+typedef struct _GsmAutostartAppPrivate GsmAutostartAppPrivate;
+
+struct _GsmAutostartApp
+{
+ GsmApp parent;
+
+ GsmAutostartAppPrivate *priv;
+};
+
+struct _GsmAutostartAppClass
+{
+ GsmAppClass parent_class;
+
+ /* signals */
+ void (*condition_changed) (GsmApp *app,
+ gboolean condition);
+};
+
+GType gsm_autostart_app_get_type (void) G_GNUC_CONST;
+
+GsmApp *gsm_autostart_app_new (const char *desktop_file);
+
+#define GSM_AUTOSTART_APP_ENABLED_KEY "X-MATE-Autostart-enabled"
+#define GSM_AUTOSTART_APP_PHASE_KEY "X-MATE-Autostart-Phase"
+#define GSM_AUTOSTART_APP_PROVIDES_KEY "X-MATE-Provides"
+#define GSM_AUTOSTART_APP_STARTUP_ID_KEY "X-MATE-Autostart-startup-id"
+#define GSM_AUTOSTART_APP_AUTORESTART_KEY "X-MATE-AutoRestart"
+#define GSM_AUTOSTART_APP_DBUS_NAME_KEY "X-MATE-DBus-Name"
+#define GSM_AUTOSTART_APP_DBUS_PATH_KEY "X-MATE-DBus-Path"
+#define GSM_AUTOSTART_APP_DBUS_ARGS_KEY "X-MATE-DBus-Start-Arguments"
+#define GSM_AUTOSTART_APP_DISCARD_KEY "X-MATE-Autostart-discard-exec"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GSM_AUTOSTART_APP_H__ */
diff --git a/mate-session/gsm-client.c b/mate-session/gsm-client.c
new file mode 100644
index 0000000..9cb1d81
--- /dev/null
+++ b/mate-session/gsm-client.c
@@ -0,0 +1,531 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Novell, Inc.
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * 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
+ * Lesser 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 <dbus/dbus-glib.h>
+
+#include "eggdesktopfile.h"
+
+#include "gsm-marshal.h"
+#include "gsm-client.h"
+#include "gsm-client-glue.h"
+
+static guint32 client_serial = 1;
+
+#define GSM_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_CLIENT, GsmClientPrivate))
+
+struct GsmClientPrivate
+{
+ char *id;
+ char *startup_id;
+ char *app_id;
+ guint status;
+ DBusGConnection *connection;
+};
+
+enum {
+ PROP_0,
+ PROP_ID,
+ PROP_STARTUP_ID,
+ PROP_APP_ID,
+ PROP_STATUS
+};
+
+enum {
+ DISCONNECTED,
+ END_SESSION_RESPONSE,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_ABSTRACT_TYPE (GsmClient, gsm_client, G_TYPE_OBJECT)
+
+GQuark
+gsm_client_error_quark (void)
+{
+ static GQuark ret = 0;
+ if (ret == 0) {
+ ret = g_quark_from_static_string ("gsm_client_error");
+ }
+
+ return ret;
+}
+
+#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
+
+GType
+gsm_client_error_get_type (void)
+{
+ static GType etype = 0;
+
+ if (etype == 0) {
+ static const GEnumValue values[] = {
+ ENUM_ENTRY (GSM_CLIENT_ERROR_GENERAL, "GeneralError"),
+ ENUM_ENTRY (GSM_CLIENT_ERROR_NOT_REGISTERED, "NotRegistered"),
+ { 0, 0, 0 }
+ };
+
+ g_assert (GSM_CLIENT_NUM_ERRORS == G_N_ELEMENTS (values) - 1);
+
+ etype = g_enum_register_static ("GsmClientError", values);
+ }
+
+ return etype;
+}
+
+static guint32
+get_next_client_serial (void)
+{
+ guint32 serial;
+
+ serial = client_serial++;
+
+ if ((gint32)client_serial < 0) {
+ client_serial = 1;
+ }
+
+ return serial;
+}
+
+static gboolean
+register_client (GsmClient *client)
+{
+ GError *error;
+
+ error = NULL;
+ client->priv->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+ if (client->priv->connection == NULL) {
+ if (error != NULL) {
+ g_critical ("error getting session bus: %s", error->message);
+ g_error_free (error);
+ }
+ return FALSE;
+ }
+
+ dbus_g_connection_register_g_object (client->priv->connection, client->priv->id, G_OBJECT (client));
+
+ return TRUE;
+}
+
+static GObject *
+gsm_client_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GsmClient *client;
+ gboolean res;
+
+ client = GSM_CLIENT (G_OBJECT_CLASS (gsm_client_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_properties));
+
+ g_free (client->priv->id);
+ client->priv->id = g_strdup_printf ("/org/mate/SessionManager/Client%u", get_next_client_serial ());
+
+ res = register_client (client);
+ if (! res) {
+ g_warning ("Unable to register client with session bus");
+ }
+
+ return G_OBJECT (client);
+}
+
+static void
+gsm_client_init (GsmClient *client)
+{
+ client->priv = GSM_CLIENT_GET_PRIVATE (client);
+}
+
+static void
+gsm_client_finalize (GObject *object)
+{
+ GsmClient *client;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GSM_IS_CLIENT (object));
+
+ client = GSM_CLIENT (object);
+
+ g_return_if_fail (client->priv != NULL);
+
+ g_free (client->priv->id);
+ g_free (client->priv->startup_id);
+ g_free (client->priv->app_id);
+
+ G_OBJECT_CLASS (gsm_client_parent_class)->finalize (object);
+}
+
+void
+gsm_client_set_status (GsmClient *client,
+ guint status)
+{
+ g_return_if_fail (GSM_IS_CLIENT (client));
+ if (client->priv->status != status) {
+ client->priv->status = status;
+ g_object_notify (G_OBJECT (client), "status");
+ }
+}
+
+static void
+gsm_client_set_startup_id (GsmClient *client,
+ const char *startup_id)
+{
+ g_return_if_fail (GSM_IS_CLIENT (client));
+
+ g_free (client->priv->startup_id);
+
+ if (startup_id != NULL) {
+ client->priv->startup_id = g_strdup (startup_id);
+ } else {
+ client->priv->startup_id = g_strdup ("");
+ }
+ g_object_notify (G_OBJECT (client), "startup-id");
+}
+
+void
+gsm_client_set_app_id (GsmClient *client,
+ const char *app_id)
+{
+ g_return_if_fail (GSM_IS_CLIENT (client));
+
+ g_free (client->priv->app_id);
+
+ if (app_id != NULL) {
+ client->priv->app_id = g_strdup (app_id);
+ } else {
+ client->priv->app_id = g_strdup ("");
+ }
+ g_object_notify (G_OBJECT (client), "app-id");
+}
+
+static void
+gsm_client_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GsmClient *self;
+
+ self = GSM_CLIENT (object);
+
+ switch (prop_id) {
+ case PROP_STARTUP_ID:
+ gsm_client_set_startup_id (self, g_value_get_string (value));
+ break;
+ case PROP_APP_ID:
+ gsm_client_set_app_id (self, g_value_get_string (value));
+ break;
+ case PROP_STATUS:
+ gsm_client_set_status (self, g_value_get_uint (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gsm_client_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GsmClient *self;
+
+ self = GSM_CLIENT (object);
+
+ switch (prop_id) {
+ case PROP_STARTUP_ID:
+ g_value_set_string (value, self->priv->startup_id);
+ break;
+ case PROP_APP_ID:
+ g_value_set_string (value, self->priv->app_id);
+ break;
+ case PROP_STATUS:
+ g_value_set_uint (value, self->priv->status);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+default_stop (GsmClient *client,
+ GError **error)
+{
+ g_return_val_if_fail (GSM_IS_CLIENT (client), FALSE);
+
+ g_warning ("Stop not implemented");
+
+ return TRUE;
+}
+
+static void
+gsm_client_dispose (GObject *object)
+{
+ GsmClient *client;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GSM_IS_CLIENT (object));
+
+ client = GSM_CLIENT (object);
+
+ g_debug ("GsmClient: disposing %s", client->priv->id);
+
+ G_OBJECT_CLASS (gsm_client_parent_class)->dispose (object);
+}
+
+static void
+gsm_client_class_init (GsmClientClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->get_property = gsm_client_get_property;
+ object_class->set_property = gsm_client_set_property;
+ object_class->constructor = gsm_client_constructor;
+ object_class->finalize = gsm_client_finalize;
+ object_class->dispose = gsm_client_dispose;
+
+ klass->impl_stop = default_stop;
+
+ signals[DISCONNECTED] =
+ g_signal_new ("disconnected",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GsmClientClass, disconnected),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+ signals[END_SESSION_RESPONSE] =
+ g_signal_new ("end-session-response",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GsmClientClass, end_session_response),
+ NULL, NULL,
+ gsm_marshal_VOID__BOOLEAN_BOOLEAN_BOOLEAN_STRING,
+ G_TYPE_NONE,
+ 4, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_STRING);
+
+ g_object_class_install_property (object_class,
+ PROP_STARTUP_ID,
+ g_param_spec_string ("startup-id",
+ "startup-id",
+ "startup-id",
+ "",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class,
+ PROP_APP_ID,
+ g_param_spec_string ("app-id",
+ "app-id",
+ "app-id",
+ "",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class,
+ PROP_STATUS,
+ g_param_spec_uint ("status",
+ "status",
+ "status",
+ 0,
+ G_MAXINT,
+ GSM_CLIENT_UNREGISTERED,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_type_class_add_private (klass, sizeof (GsmClientPrivate));
+
+ dbus_g_object_type_install_info (GSM_TYPE_CLIENT, &dbus_glib_gsm_client_object_info);
+}
+
+const char *
+gsm_client_peek_id (GsmClient *client)
+{
+ g_return_val_if_fail (GSM_IS_CLIENT (client), NULL);
+
+ return client->priv->id;
+}
+
+const char *
+gsm_client_peek_app_id (GsmClient *client)
+{
+ g_return_val_if_fail (GSM_IS_CLIENT (client), NULL);
+
+ return client->priv->app_id;
+}
+
+const char *
+gsm_client_peek_startup_id (GsmClient *client)
+{
+ g_return_val_if_fail (GSM_IS_CLIENT (client), NULL);
+
+ return client->priv->startup_id;
+}
+
+guint
+gsm_client_peek_status (GsmClient *client)
+{
+ g_return_val_if_fail (GSM_IS_CLIENT (client), GSM_CLIENT_UNREGISTERED);
+
+ return client->priv->status;
+}
+
+guint
+gsm_client_peek_restart_style_hint (GsmClient *client)
+{
+ g_return_val_if_fail (GSM_IS_CLIENT (client), GSM_CLIENT_RESTART_NEVER);
+
+ return GSM_CLIENT_GET_CLASS (client)->impl_get_restart_style_hint (client);
+}
+
+gboolean
+gsm_client_get_startup_id (GsmClient *client,
+ char **id,
+ GError **error)
+{
+ g_return_val_if_fail (GSM_IS_CLIENT (client), FALSE);
+
+ *id = g_strdup (client->priv->startup_id);
+
+ return TRUE;
+}
+
+gboolean
+gsm_client_get_app_id (GsmClient *client,
+ char **id,
+ GError **error)
+{
+ g_return_val_if_fail (GSM_IS_CLIENT (client), FALSE);
+
+ *id = g_strdup (client->priv->app_id);
+
+ return TRUE;
+}
+
+gboolean
+gsm_client_get_restart_style_hint (GsmClient *client,
+ guint *hint,
+ GError **error)
+{
+ g_return_val_if_fail (GSM_IS_CLIENT (client), FALSE);
+
+ *hint = GSM_CLIENT_GET_CLASS (client)->impl_get_restart_style_hint (client);
+
+ return TRUE;
+}
+
+gboolean
+gsm_client_get_status (GsmClient *client,
+ guint *status,
+ GError **error)
+{
+ g_return_val_if_fail (GSM_IS_CLIENT (client), FALSE);
+
+ *status = client->priv->status;
+
+ return TRUE;
+}
+
+gboolean
+gsm_client_get_unix_process_id (GsmClient *client,
+ guint *pid,
+ GError **error)
+{
+ g_return_val_if_fail (GSM_IS_CLIENT (client), FALSE);
+
+ *pid = GSM_CLIENT_GET_CLASS (client)->impl_get_unix_process_id (client);
+
+ return TRUE;
+}
+
+char *
+gsm_client_get_app_name (GsmClient *client)
+{
+ g_return_val_if_fail (GSM_IS_CLIENT (client), NULL);
+
+ return GSM_CLIENT_GET_CLASS (client)->impl_get_app_name (client);
+}
+
+gboolean
+gsm_client_cancel_end_session (GsmClient *client,
+ GError **error)
+{
+ g_return_val_if_fail (GSM_IS_CLIENT (client), FALSE);
+
+ return GSM_CLIENT_GET_CLASS (client)->impl_cancel_end_session (client, error);
+}
+
+
+gboolean
+gsm_client_query_end_session (GsmClient *client,
+ guint flags,
+ GError **error)
+{
+ g_return_val_if_fail (GSM_IS_CLIENT (client), FALSE);
+
+ return GSM_CLIENT_GET_CLASS (client)->impl_query_end_session (client, flags, error);
+}
+
+gboolean
+gsm_client_end_session (GsmClient *client,
+ guint flags,
+ GError **error)
+{
+ g_return_val_if_fail (GSM_IS_CLIENT (client), FALSE);
+
+ return GSM_CLIENT_GET_CLASS (client)->impl_end_session (client, flags, error);
+}
+
+gboolean
+gsm_client_stop (GsmClient *client,
+ GError **error)
+{
+ g_return_val_if_fail (GSM_IS_CLIENT (client), FALSE);
+
+ return GSM_CLIENT_GET_CLASS (client)->impl_stop (client, error);
+}
+
+void
+gsm_client_disconnected (GsmClient *client)
+{
+ g_signal_emit (client, signals[DISCONNECTED], 0);
+}
+
+GKeyFile *
+gsm_client_save (GsmClient *client,
+ GError **error)
+{
+ g_return_val_if_fail (GSM_IS_CLIENT (client), FALSE);
+
+ return GSM_CLIENT_GET_CLASS (client)->impl_save (client, error);
+}
+
+void
+gsm_client_end_session_response (GsmClient *client,
+ gboolean is_ok,
+ gboolean do_last,
+ gboolean cancel,
+ const char *reason)
+{
+ g_signal_emit (client, signals[END_SESSION_RESPONSE], 0,
+ is_ok, do_last, cancel, reason);
+}
diff --git a/mate-session/gsm-client.h b/mate-session/gsm-client.h
new file mode 100644
index 0000000..8c096a6
--- /dev/null
+++ b/mate-session/gsm-client.h
@@ -0,0 +1,175 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Novell, Inc.
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * 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
+ * Lesser 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_CLIENT_H__
+#define __GSM_CLIENT_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GSM_TYPE_CLIENT (gsm_client_get_type ())
+#define GSM_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSM_TYPE_CLIENT, GsmClient))
+#define GSM_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSM_TYPE_CLIENT, GsmClientClass))
+#define GSM_IS_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSM_TYPE_CLIENT))
+#define GSM_IS_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSM_TYPE_CLIENT))
+#define GSM_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSM_TYPE_CLIENT, GsmClientClass))
+
+typedef struct _GsmClient GsmClient;
+typedef struct _GsmClientClass GsmClientClass;
+
+typedef struct GsmClientPrivate GsmClientPrivate;
+
+typedef enum {
+ GSM_CLIENT_UNREGISTERED = 0,
+ GSM_CLIENT_REGISTERED,
+ GSM_CLIENT_FINISHED,
+ GSM_CLIENT_FAILED
+} GsmClientStatus;
+
+typedef enum {
+ GSM_CLIENT_RESTART_NEVER = 0,
+ GSM_CLIENT_RESTART_IF_RUNNING,
+ GSM_CLIENT_RESTART_ANYWAY,
+ GSM_CLIENT_RESTART_IMMEDIATELY
+} GsmClientRestartStyle;
+
+typedef enum {
+ GSM_CLIENT_END_SESSION_FLAG_FORCEFUL = 1 << 0,
+ GSM_CLIENT_END_SESSION_FLAG_SAVE = 1 << 1,
+ GSM_CLIENT_END_SESSION_FLAG_LAST = 1 << 2
+} GsmClientEndSessionFlag;
+
+struct _GsmClient
+{
+ GObject parent;
+ GsmClientPrivate *priv;
+};
+
+struct _GsmClientClass
+{
+ GObjectClass parent_class;
+
+ /* signals */
+ void (*disconnected) (GsmClient *client);
+ void (*end_session_response) (GsmClient *client,
+ gboolean ok,
+ gboolean do_last,
+ gboolean cancel,
+ const char *reason);
+
+ /* virtual methods */
+ char * (*impl_get_app_name) (GsmClient *client);
+ GsmClientRestartStyle (*impl_get_restart_style_hint) (GsmClient *client);
+ guint (*impl_get_unix_process_id) (GsmClient *client);
+ gboolean (*impl_query_end_session) (GsmClient *client,
+ guint flags,
+ GError **error);
+ gboolean (*impl_end_session) (GsmClient *client,
+ guint flags,
+ GError **error);
+ gboolean (*impl_cancel_end_session) (GsmClient *client,
+ GError **error);
+ gboolean (*impl_stop) (GsmClient *client,
+ GError **error);
+ GKeyFile * (*impl_save) (GsmClient *client,
+ GError **error);
+};
+
+typedef enum
+{
+ GSM_CLIENT_ERROR_GENERAL = 0,
+ GSM_CLIENT_ERROR_NOT_REGISTERED,
+ GSM_CLIENT_NUM_ERRORS
+} GsmClientError;
+
+#define GSM_CLIENT_ERROR gsm_client_error_quark ()
+#define GSM_CLIENT_TYPE_ERROR (gsm_client_error_get_type ())
+
+GType gsm_client_error_get_type (void);
+GQuark gsm_client_error_quark (void);
+
+GType gsm_client_get_type (void) G_GNUC_CONST;
+
+const char *gsm_client_peek_id (GsmClient *client);
+
+
+const char * gsm_client_peek_startup_id (GsmClient *client);
+const char * gsm_client_peek_app_id (GsmClient *client);
+guint gsm_client_peek_restart_style_hint (GsmClient *client);
+guint gsm_client_peek_status (GsmClient *client);
+
+
+char *gsm_client_get_app_name (GsmClient *client);
+void gsm_client_set_app_id (GsmClient *client,
+ const char *app_id);
+void gsm_client_set_status (GsmClient *client,
+ guint status);
+
+gboolean gsm_client_end_session (GsmClient *client,
+ guint flags,
+ GError **error);
+gboolean gsm_client_query_end_session (GsmClient *client,
+ guint flags,
+ GError **error);
+gboolean gsm_client_cancel_end_session (GsmClient *client,
+ GError **error);
+
+void gsm_client_disconnected (GsmClient *client);
+
+GKeyFile *gsm_client_save (GsmClient *client,
+ GError **error);
+/* exported to bus */
+gboolean gsm_client_stop (GsmClient *client,
+ GError **error);
+gboolean gsm_client_get_startup_id (GsmClient *client,
+ char **startup_id,
+ GError **error);
+gboolean gsm_client_get_app_id (GsmClient *client,
+ char **app_id,
+ GError **error);
+gboolean gsm_client_get_restart_style_hint (GsmClient *client,
+ guint *hint,
+ GError **error);
+gboolean gsm_client_get_status (GsmClient *client,
+ guint *status,
+ GError **error);
+gboolean gsm_client_get_unix_process_id (GsmClient *client,
+ guint *pid,
+ GError **error);
+
+/* private */
+
+void gsm_client_end_session_response (GsmClient *client,
+ gboolean is_ok,
+ gboolean do_last,
+ gboolean cancel,
+ const char *reason);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GSM_CLIENT_H__ */
diff --git a/mate-session/gsm-consolekit.c b/mate-session/gsm-consolekit.c
new file mode 100644
index 0000000..e8dd726
--- /dev/null
+++ b/mate-session/gsm-consolekit.c
@@ -0,0 +1,903 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Jon McCann <[email protected]>
+ *
+ * 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, 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 <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n.h>
+
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include "gsm-marshal.h"
+#include "gsm-consolekit.h"
+
+#define CK_NAME "org.freedesktop.ConsoleKit"
+#define CK_PATH "/org/freedesktop/ConsoleKit"
+#define CK_INTERFACE "org.freedesktop.ConsoleKit"
+
+#define CK_MANAGER_PATH "/org/freedesktop/ConsoleKit/Manager"
+#define CK_MANAGER_INTERFACE "org.freedesktop.ConsoleKit.Manager"
+#define CK_SEAT_INTERFACE "org.freedesktop.ConsoleKit.Seat"
+#define CK_SESSION_INTERFACE "org.freedesktop.ConsoleKit.Session"
+
+#define GSM_CONSOLEKIT_GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_CONSOLEKIT, GsmConsolekitPrivate))
+
+struct _GsmConsolekitPrivate
+{
+ DBusGConnection *dbus_connection;
+ DBusGProxy *bus_proxy;
+ DBusGProxy *ck_proxy;
+ guint32 is_connected : 1;
+};
+
+enum {
+ PROP_0,
+ PROP_IS_CONNECTED
+};
+
+enum {
+ REQUEST_COMPLETED = 0,
+ PRIVILEGES_COMPLETED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void gsm_consolekit_class_init (GsmConsolekitClass *klass);
+static void gsm_consolekit_init (GsmConsolekit *ck);
+static void gsm_consolekit_finalize (GObject *object);
+
+static void gsm_consolekit_free_dbus (GsmConsolekit *manager);
+
+static DBusHandlerResult gsm_consolekit_dbus_filter (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data);
+
+static void gsm_consolekit_on_name_owner_changed (DBusGProxy *bus_proxy,
+ const char *name,
+ const char *prev_owner,
+ const char *new_owner,
+ GsmConsolekit *manager);
+
+G_DEFINE_TYPE (GsmConsolekit, gsm_consolekit, G_TYPE_OBJECT);
+
+static void
+gsm_consolekit_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GsmConsolekit *manager = GSM_CONSOLEKIT (object);
+
+ switch (prop_id) {
+ case PROP_IS_CONNECTED:
+ g_value_set_boolean (value,
+ manager->priv->is_connected);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
+ prop_id,
+ pspec);
+ }
+}
+
+static void
+gsm_consolekit_class_init (GsmConsolekitClass *manager_class)
+{
+ GObjectClass *object_class;
+ GParamSpec *param_spec;
+
+ object_class = G_OBJECT_CLASS (manager_class);
+
+ object_class->finalize = gsm_consolekit_finalize;
+ object_class->get_property = gsm_consolekit_get_property;
+
+ param_spec = g_param_spec_boolean ("is-connected",
+ "Is connected",
+ "Whether the session is connected to ConsoleKit",
+ FALSE,
+ G_PARAM_READABLE);
+
+ g_object_class_install_property (object_class, PROP_IS_CONNECTED,
+ param_spec);
+
+ signals [REQUEST_COMPLETED] =
+ g_signal_new ("request-completed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GsmConsolekitClass, request_completed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1, G_TYPE_POINTER);
+
+ signals [PRIVILEGES_COMPLETED] =
+ g_signal_new ("privileges-completed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GsmConsolekitClass, privileges_completed),
+ NULL,
+ NULL,
+ gsm_marshal_VOID__BOOLEAN_BOOLEAN_POINTER,
+ G_TYPE_NONE,
+ 3, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_POINTER);
+
+ g_type_class_add_private (manager_class, sizeof (GsmConsolekitPrivate));
+}
+
+static DBusHandlerResult
+gsm_consolekit_dbus_filter (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ GsmConsolekit *manager;
+
+ manager = GSM_CONSOLEKIT (user_data);
+
+ if (dbus_message_is_signal (message,
+ DBUS_INTERFACE_LOCAL, "Disconnected") &&
+ strcmp (dbus_message_get_path (message), DBUS_PATH_LOCAL) == 0) {
+ gsm_consolekit_free_dbus (manager);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static gboolean
+gsm_consolekit_ensure_ck_connection (GsmConsolekit *manager,
+ GError **error)
+{
+ GError *connection_error;
+ gboolean is_connected;
+
+ connection_error = NULL;
+
+ if (manager->priv->dbus_connection == NULL) {
+ DBusConnection *connection;
+
+ manager->priv->dbus_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM,
+ &connection_error);
+
+ if (manager->priv->dbus_connection == NULL) {
+ g_propagate_error (error, connection_error);
+ is_connected = FALSE;
+ goto out;
+ }
+
+ connection = dbus_g_connection_get_connection (manager->priv->dbus_connection);
+ dbus_connection_set_exit_on_disconnect (connection, FALSE);
+ dbus_connection_add_filter (connection,
+ gsm_consolekit_dbus_filter,
+ manager, NULL);
+ }
+
+ if (manager->priv->bus_proxy == NULL) {
+ manager->priv->bus_proxy =
+ dbus_g_proxy_new_for_name_owner (manager->priv->dbus_connection,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS,
+ &connection_error);
+
+ if (manager->priv->bus_proxy == NULL) {
+ g_propagate_error (error, connection_error);
+ is_connected = FALSE;
+ goto out;
+ }
+
+ dbus_g_proxy_add_signal (manager->priv->bus_proxy,
+ "NameOwnerChanged",
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_INVALID);
+
+ dbus_g_proxy_connect_signal (manager->priv->bus_proxy,
+ "NameOwnerChanged",
+ G_CALLBACK (gsm_consolekit_on_name_owner_changed),
+ manager, NULL);
+ }
+
+ if (manager->priv->ck_proxy == NULL) {
+ manager->priv->ck_proxy =
+ dbus_g_proxy_new_for_name_owner (manager->priv->dbus_connection,
+ "org.freedesktop.ConsoleKit",
+ "/org/freedesktop/ConsoleKit/Manager",
+ "org.freedesktop.ConsoleKit.Manager",
+ &connection_error);
+
+ if (manager->priv->ck_proxy == NULL) {
+ g_propagate_error (error, connection_error);
+ is_connected = FALSE;
+ goto out;
+ }
+ }
+
+ is_connected = TRUE;
+
+ out:
+ if (manager->priv->is_connected != is_connected) {
+ manager->priv->is_connected = is_connected;
+ g_object_notify (G_OBJECT (manager), "is-connected");
+ }
+
+ if (!is_connected) {
+ if (manager->priv->dbus_connection == NULL) {
+ if (manager->priv->bus_proxy != NULL) {
+ g_object_unref (manager->priv->bus_proxy);
+ manager->priv->bus_proxy = NULL;
+ }
+
+ if (manager->priv->ck_proxy != NULL) {
+ g_object_unref (manager->priv->ck_proxy);
+ manager->priv->ck_proxy = NULL;
+ }
+ } else if (manager->priv->bus_proxy == NULL) {
+ if (manager->priv->ck_proxy != NULL) {
+ g_object_unref (manager->priv->ck_proxy);
+ manager->priv->ck_proxy = NULL;
+ }
+ }
+ }
+
+ return is_connected;
+}
+
+static void
+gsm_consolekit_on_name_owner_changed (DBusGProxy *bus_proxy,
+ const char *name,
+ const char *prev_owner,
+ const char *new_owner,
+ GsmConsolekit *manager)
+{
+ if (name != NULL && strcmp (name, "org.freedesktop.ConsoleKit") != 0) {
+ return;
+ }
+
+ if (manager->priv->ck_proxy != NULL) {
+ g_object_unref (manager->priv->ck_proxy);
+ manager->priv->ck_proxy = NULL;
+ }
+
+ gsm_consolekit_ensure_ck_connection (manager, NULL);
+}
+
+static void
+gsm_consolekit_init (GsmConsolekit *manager)
+{
+ GError *error;
+
+ manager->priv = GSM_CONSOLEKIT_GET_PRIVATE (manager);
+
+ error = NULL;
+
+ if (!gsm_consolekit_ensure_ck_connection (manager, &error)) {
+ g_warning ("Could not connect to ConsoleKit: %s",
+ error->message);
+ g_error_free (error);
+ }
+}
+
+static void
+gsm_consolekit_free_dbus (GsmConsolekit *manager)
+{
+ if (manager->priv->bus_proxy != NULL) {
+ g_object_unref (manager->priv->bus_proxy);
+ manager->priv->bus_proxy = NULL;
+ }
+
+ if (manager->priv->ck_proxy != NULL) {
+ g_object_unref (manager->priv->ck_proxy);
+ manager->priv->ck_proxy = NULL;
+ }
+
+ if (manager->priv->dbus_connection != NULL) {
+ DBusConnection *connection;
+ connection = dbus_g_connection_get_connection (manager->priv->dbus_connection);
+ dbus_connection_remove_filter (connection,
+ gsm_consolekit_dbus_filter,
+ manager);
+
+ dbus_g_connection_unref (manager->priv->dbus_connection);
+ manager->priv->dbus_connection = NULL;
+ }
+}
+
+static void
+gsm_consolekit_finalize (GObject *object)
+{
+ GsmConsolekit *manager;
+ GObjectClass *parent_class;
+
+ manager = GSM_CONSOLEKIT (object);
+
+ parent_class = G_OBJECT_CLASS (gsm_consolekit_parent_class);
+
+ gsm_consolekit_free_dbus (manager);
+
+ if (parent_class->finalize != NULL) {
+ parent_class->finalize (object);
+ }
+}
+
+GQuark
+gsm_consolekit_error_quark (void)
+{
+ static GQuark error_quark = 0;
+
+ if (error_quark == 0) {
+ error_quark = g_quark_from_static_string ("gsm-consolekit-error");
+ }
+
+ return error_quark;
+}
+
+GsmConsolekit *
+gsm_consolekit_new (void)
+{
+ GsmConsolekit *manager;
+
+ manager = g_object_new (GSM_TYPE_CONSOLEKIT, NULL);
+
+ return manager;
+}
+
+static void
+emit_restart_complete (GsmConsolekit *manager,
+ GError *error)
+{
+ GError *call_error;
+
+ call_error = NULL;
+
+ if (error != NULL) {
+ call_error = g_error_new_literal (GSM_CONSOLEKIT_ERROR,
+ GSM_CONSOLEKIT_ERROR_RESTARTING,
+ error->message);
+ }
+
+ g_signal_emit (G_OBJECT (manager),
+ signals [REQUEST_COMPLETED],
+ 0, call_error);
+
+ if (call_error != NULL) {
+ g_error_free (call_error);
+ }
+}
+
+static void
+emit_stop_complete (GsmConsolekit *manager,
+ GError *error)
+{
+ GError *call_error;
+
+ call_error = NULL;
+
+ if (error != NULL) {
+ call_error = g_error_new_literal (GSM_CONSOLEKIT_ERROR,
+ GSM_CONSOLEKIT_ERROR_STOPPING,
+ error->message);
+ }
+
+ g_signal_emit (G_OBJECT (manager),
+ signals [REQUEST_COMPLETED],
+ 0, call_error);
+
+ if (call_error != NULL) {
+ g_error_free (call_error);
+ }
+}
+
+void
+gsm_consolekit_attempt_restart (GsmConsolekit *manager)
+{
+ gboolean res;
+ GError *error;
+
+ error = NULL;
+
+ if (!gsm_consolekit_ensure_ck_connection (manager, &error)) {
+ g_warning ("Could not connect to ConsoleKit: %s",
+ error->message);
+ emit_restart_complete (manager, error);
+ g_error_free (error);
+ return;
+ }
+
+ res = dbus_g_proxy_call_with_timeout (manager->priv->ck_proxy,
+ "Restart",
+ INT_MAX,
+ &error,
+ G_TYPE_INVALID,
+ G_TYPE_INVALID);
+
+ if (!res) {
+ g_warning ("Unable to restart system: %s", error->message);
+ emit_restart_complete (manager, error);
+ g_error_free (error);
+ } else {
+ emit_restart_complete (manager, NULL);
+ }
+}
+
+void
+gsm_consolekit_attempt_stop (GsmConsolekit *manager)
+{
+ gboolean res;
+ GError *error;
+
+ error = NULL;
+
+ if (!gsm_consolekit_ensure_ck_connection (manager, &error)) {
+ g_warning ("Could not connect to ConsoleKit: %s",
+ error->message);
+ emit_stop_complete (manager, error);
+ g_error_free (error);
+ return;
+ }
+
+ res = dbus_g_proxy_call_with_timeout (manager->priv->ck_proxy,
+ "Stop",
+ INT_MAX,
+ &error,
+ G_TYPE_INVALID,
+ G_TYPE_INVALID);
+
+ if (!res) {
+ g_warning ("Unable to stop system: %s", error->message);
+ emit_stop_complete (manager, error);
+ g_error_free (error);
+ } else {
+ emit_stop_complete (manager, NULL);
+ }
+}
+
+static gboolean
+get_current_session_id (DBusConnection *connection,
+ char **session_id)
+{
+ DBusError local_error;
+ DBusMessage *message;
+ DBusMessage *reply;
+ gboolean ret;
+ DBusMessageIter iter;
+ const char *value;
+
+ ret = FALSE;
+ reply = NULL;
+
+ dbus_error_init (&local_error);
+ message = dbus_message_new_method_call (CK_NAME,
+ CK_MANAGER_PATH,
+ CK_MANAGER_INTERFACE,
+ "GetCurrentSession");
+ if (message == NULL) {
+ goto out;
+ }
+
+ dbus_error_init (&local_error);
+ reply = dbus_connection_send_with_reply_and_block (connection,
+ message,
+ -1,
+ &local_error);
+ if (reply == NULL) {
+ if (dbus_error_is_set (&local_error)) {
+ g_warning ("Unable to determine session: %s", local_error.message);
+ dbus_error_free (&local_error);
+ goto out;
+ }
+ }
+
+ dbus_message_iter_init (reply, &iter);
+ dbus_message_iter_get_basic (&iter, &value);
+ if (session_id != NULL) {
+ *session_id = g_strdup (value);
+ }
+
+ ret = TRUE;
+ out:
+ if (message != NULL) {
+ dbus_message_unref (message);
+ }
+ if (reply != NULL) {
+ dbus_message_unref (reply);
+ }
+
+ return ret;
+}
+
+static gboolean
+get_seat_id_for_session (DBusConnection *connection,
+ const char *session_id,
+ char **seat_id)
+{
+ DBusError local_error;
+ DBusMessage *message;
+ DBusMessage *reply;
+ gboolean ret;
+ DBusMessageIter iter;
+ const char *value;
+
+ ret = FALSE;
+ reply = NULL;
+
+ dbus_error_init (&local_error);
+ message = dbus_message_new_method_call (CK_NAME,
+ session_id,
+ CK_SESSION_INTERFACE,
+ "GetSeatId");
+ if (message == NULL) {
+ goto out;
+ }
+
+ dbus_error_init (&local_error);
+ reply = dbus_connection_send_with_reply_and_block (connection,
+ message,
+ -1,
+ &local_error);
+ if (reply == NULL) {
+ if (dbus_error_is_set (&local_error)) {
+ g_warning ("Unable to determine seat: %s", local_error.message);
+ dbus_error_free (&local_error);
+ goto out;
+ }
+ }
+
+ dbus_message_iter_init (reply, &iter);
+ dbus_message_iter_get_basic (&iter, &value);
+ if (seat_id != NULL) {
+ *seat_id = g_strdup (value);
+ }
+
+ ret = TRUE;
+ out:
+ if (message != NULL) {
+ dbus_message_unref (message);
+ }
+ if (reply != NULL) {
+ dbus_message_unref (reply);
+ }
+
+ return ret;
+}
+
+static char *
+get_current_seat_id (DBusConnection *connection)
+{
+ gboolean res;
+ char *session_id;
+ char *seat_id;
+
+ session_id = NULL;
+ seat_id = NULL;
+
+ res = get_current_session_id (connection, &session_id);
+ if (res) {
+ res = get_seat_id_for_session (connection, session_id, &seat_id);
+ }
+ g_free (session_id);
+
+ return seat_id;
+}
+
+void
+gsm_consolekit_set_session_idle (GsmConsolekit *manager,
+ gboolean is_idle)
+{
+ gboolean res;
+ GError *error;
+ char *session_id;
+ DBusMessage *message;
+ DBusMessage *reply;
+ DBusError dbus_error;
+ DBusMessageIter iter;
+
+ error = NULL;
+
+ if (!gsm_consolekit_ensure_ck_connection (manager, &error)) {
+ g_warning ("Could not connect to ConsoleKit: %s",
+ error->message);
+ g_error_free (error);
+ return;
+ }
+
+ session_id = NULL;
+ res = get_current_session_id (dbus_g_connection_get_connection (manager->priv->dbus_connection),
+ &session_id);
+ if (!res) {
+ goto out;
+ }
+
+
+ g_debug ("Updating ConsoleKit idle status: %d", is_idle);
+ message = dbus_message_new_method_call (CK_NAME,
+ session_id,
+ CK_SESSION_INTERFACE,
+ "SetIdleHint");
+ if (message == NULL) {
+ g_debug ("Couldn't allocate the D-Bus message");
+ return;
+ }
+
+ dbus_message_iter_init_append (message, &iter);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &is_idle);
+
+ /* FIXME: use async? */
+ dbus_error_init (&dbus_error);
+ reply = dbus_connection_send_with_reply_and_block (dbus_g_connection_get_connection (manager->priv->dbus_connection),
+ message,
+ -1,
+ &dbus_error);
+ dbus_message_unref (message);
+
+ if (reply != NULL) {
+ dbus_message_unref (reply);
+ }
+
+ if (dbus_error_is_set (&dbus_error)) {
+ g_debug ("%s raised:\n %s\n\n", dbus_error.name, dbus_error.message);
+ dbus_error_free (&dbus_error);
+ }
+
+out:
+ g_free (session_id);
+}
+
+static gboolean
+seat_can_activate_sessions (DBusConnection *connection,
+ const char *seat_id)
+{
+ DBusError local_error;
+ DBusMessage *message;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ gboolean can_activate;
+
+ can_activate = FALSE;
+ reply = NULL;
+
+ dbus_error_init (&local_error);
+ message = dbus_message_new_method_call (CK_NAME,
+ seat_id,
+ CK_SEAT_INTERFACE,
+ "CanActivateSessions");
+ if (message == NULL) {
+ goto out;
+ }
+
+ dbus_error_init (&local_error);
+ reply = dbus_connection_send_with_reply_and_block (connection,
+ message,
+ -1,
+ &local_error);
+ if (reply == NULL) {
+ if (dbus_error_is_set (&local_error)) {
+ g_warning ("Unable to activate session: %s", local_error.message);
+ dbus_error_free (&local_error);
+ goto out;
+ }
+ }
+
+ dbus_message_iter_init (reply, &iter);
+ dbus_message_iter_get_basic (&iter, &can_activate);
+
+ out:
+ if (message != NULL) {
+ dbus_message_unref (message);
+ }
+ if (reply != NULL) {
+ dbus_message_unref (reply);
+ }
+
+ return can_activate;
+}
+
+gboolean
+gsm_consolekit_can_switch_user (GsmConsolekit *manager)
+{
+ GError *error;
+ char *seat_id;
+ gboolean ret;
+
+ error = NULL;
+
+ if (!gsm_consolekit_ensure_ck_connection (manager, &error)) {
+ g_warning ("Could not connect to ConsoleKit: %s",
+ error->message);
+ g_error_free (error);
+ return FALSE;
+ }
+
+ seat_id = get_current_seat_id (dbus_g_connection_get_connection (manager->priv->dbus_connection));
+ if (seat_id == NULL || seat_id[0] == '\0') {
+ g_debug ("seat id is not set; can't switch sessions");
+ return FALSE;
+ }
+
+ ret = seat_can_activate_sessions (dbus_g_connection_get_connection (manager->priv->dbus_connection),
+ seat_id);
+ g_free (seat_id);
+
+ return ret;
+}
+
+gboolean
+gsm_consolekit_get_restart_privileges (GsmConsolekit *manager)
+{
+ g_signal_emit (G_OBJECT (manager),
+ signals [PRIVILEGES_COMPLETED],
+ 0, TRUE, TRUE, NULL);
+
+ return TRUE;
+}
+
+gboolean
+gsm_consolekit_get_stop_privileges (GsmConsolekit *manager)
+{
+ g_signal_emit (G_OBJECT (manager),
+ signals [PRIVILEGES_COMPLETED],
+ 0, TRUE, TRUE, NULL);
+
+ return TRUE;
+}
+
+gboolean
+gsm_consolekit_can_restart (GsmConsolekit *manager)
+{
+ gboolean res;
+ gboolean can_restart;
+ GError *error;
+
+ error = NULL;
+
+ if (!gsm_consolekit_ensure_ck_connection (manager, &error)) {
+ g_warning ("Could not connect to ConsoleKit: %s",
+ error->message);
+ g_error_free (error);
+ return FALSE;
+ }
+
+ res = dbus_g_proxy_call_with_timeout (manager->priv->ck_proxy,
+ "CanRestart",
+ INT_MAX,
+ &error,
+ G_TYPE_INVALID,
+ G_TYPE_BOOLEAN, &can_restart,
+ G_TYPE_INVALID);
+
+ return can_restart;
+}
+
+gboolean
+gsm_consolekit_can_stop (GsmConsolekit *manager)
+{
+ gboolean res;
+ gboolean can_stop;
+ GError *error;
+
+ error = NULL;
+
+ if (!gsm_consolekit_ensure_ck_connection (manager, &error)) {
+ g_warning ("Could not connect to ConsoleKit: %s",
+ error->message);
+ g_error_free (error);
+ return FALSE;
+ }
+
+ res = dbus_g_proxy_call_with_timeout (manager->priv->ck_proxy,
+ "CanStop",
+ INT_MAX,
+ &error,
+ G_TYPE_INVALID,
+ G_TYPE_BOOLEAN, &can_stop,
+ G_TYPE_INVALID);
+
+ return can_stop;
+}
+
+gchar *
+gsm_consolekit_get_current_session_type (GsmConsolekit *manager)
+{
+ GError *gerror;
+ DBusConnection *connection;
+ DBusError error;
+ DBusMessage *message = NULL;
+ DBusMessage *reply = NULL;
+ gchar *session_id;
+ gchar *ret;
+ DBusMessageIter iter;
+ const char *value;
+
+ session_id = NULL;
+ ret = NULL;
+ gerror = NULL;
+
+ if (!gsm_consolekit_ensure_ck_connection (manager, &gerror)) {
+ g_warning ("Could not connect to ConsoleKit: %s",
+ gerror->message);
+ g_error_free (gerror);
+ goto out;
+ }
+
+ connection = dbus_g_connection_get_connection (manager->priv->dbus_connection);
+ if (!get_current_session_id (connection, &session_id)) {
+ goto out;
+ }
+
+ dbus_error_init (&error);
+ message = dbus_message_new_method_call (CK_NAME,
+ session_id,
+ CK_SESSION_INTERFACE,
+ "GetSessionType");
+ if (message == NULL) {
+ goto out;
+ }
+
+ reply = dbus_connection_send_with_reply_and_block (connection,
+ message,
+ -1,
+ &error);
+
+ if (reply == NULL) {
+ if (dbus_error_is_set (&error)) {
+ g_warning ("Unable to determine session type: %s", error.message);
+ dbus_error_free (&error);
+ }
+ goto out;
+ }
+
+ dbus_message_iter_init (reply, &iter);
+ dbus_message_iter_get_basic (&iter, &value);
+ ret = g_strdup (value);
+
+out:
+ if (message != NULL) {
+ dbus_message_unref (message);
+ }
+ if (reply != NULL) {
+ dbus_message_unref (reply);
+ }
+ g_free (session_id);
+
+ return ret;
+}
+
+
+GsmConsolekit *
+gsm_get_consolekit (void)
+{
+ static GsmConsolekit *manager = NULL;
+
+ if (manager == NULL) {
+ manager = gsm_consolekit_new ();
+ }
+
+ return g_object_ref (manager);
+}
diff --git a/mate-session/gsm-consolekit.h b/mate-session/gsm-consolekit.h
new file mode 100644
index 0000000..203ec40
--- /dev/null
+++ b/mate-session/gsm-consolekit.h
@@ -0,0 +1,105 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Jon McCann <[email protected]>
+ *
+ * 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.
+ *
+ * Authors:
+ * Jon McCann <[email protected]>
+ */
+
+#ifndef __GSM_CONSOLEKIT_H__
+#define __GSM_CONSOLEKIT_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GSM_TYPE_CONSOLEKIT (gsm_consolekit_get_type ())
+#define GSM_CONSOLEKIT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSM_TYPE_CONSOLEKIT, GsmConsolekit))
+#define GSM_CONSOLEKIT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSM_TYPE_CONSOLEKIT, GsmConsolekitClass))
+#define GSM_IS_CONSOLEKIT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSM_TYPE_CONSOLEKIT))
+#define GSM_IS_CONSOLEKIT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSM_TYPE_CONSOLEKIT))
+#define GSM_CONSOLEKIT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GSM_TYPE_CONSOLEKIT, GsmConsolekitClass))
+#define GSM_CONSOLEKIT_ERROR (gsm_consolekit_error_quark ())
+
+typedef struct _GsmConsolekit GsmConsolekit;
+typedef struct _GsmConsolekitClass GsmConsolekitClass;
+typedef struct _GsmConsolekitPrivate GsmConsolekitPrivate;
+typedef enum _GsmConsolekitError GsmConsolekitError;
+
+struct _GsmConsolekit
+{
+ GObject parent;
+
+ GsmConsolekitPrivate *priv;
+};
+
+struct _GsmConsolekitClass
+{
+ GObjectClass parent_class;
+
+ void (* request_completed) (GsmConsolekit *manager,
+ GError *error);
+
+ void (* privileges_completed) (GsmConsolekit *manager,
+ gboolean success,
+ gboolean ask_later,
+ GError *error);
+};
+
+enum _GsmConsolekitError {
+ GSM_CONSOLEKIT_ERROR_RESTARTING = 0,
+ GSM_CONSOLEKIT_ERROR_STOPPING
+};
+
+#define GSM_CONSOLEKIT_SESSION_TYPE_LOGIN_WINDOW "LoginWindow"
+
+GType gsm_consolekit_get_type (void);
+
+GQuark gsm_consolekit_error_quark (void);
+
+GsmConsolekit *gsm_consolekit_new (void) G_GNUC_MALLOC;
+
+gboolean gsm_consolekit_can_switch_user (GsmConsolekit *manager);
+
+gboolean gsm_consolekit_get_restart_privileges (GsmConsolekit *manager);
+
+gboolean gsm_consolekit_get_stop_privileges (GsmConsolekit *manager);
+
+gboolean gsm_consolekit_can_stop (GsmConsolekit *manager);
+
+gboolean gsm_consolekit_can_restart (GsmConsolekit *manager);
+
+void gsm_consolekit_attempt_stop (GsmConsolekit *manager);
+
+void gsm_consolekit_attempt_restart (GsmConsolekit *manager);
+
+void gsm_consolekit_set_session_idle (GsmConsolekit *manager,
+ gboolean is_idle);
+
+gchar *gsm_consolekit_get_current_session_type (GsmConsolekit *manager);
+
+GsmConsolekit *gsm_get_consolekit (void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GSM_CONSOLEKIT_H__ */
diff --git a/mate-session/gsm-dbus-client.c b/mate-session/gsm-dbus-client.c
new file mode 100644
index 0000000..65b393c
--- /dev/null
+++ b/mate-session/gsm-dbus-client.c
@@ -0,0 +1,700 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * 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
+ * Lesser 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 <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include "gsm-dbus-client.h"
+#include "gsm-marshal.h"
+
+#include "gsm-manager.h"
+
+#define GSM_DBUS_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_DBUS_CLIENT, GsmDBusClientPrivate))
+
+#define IS_STRING_EMPTY(x) ((x)==NULL||(x)[0]=='\0')
+
+
+#define SM_DBUS_NAME "org.mate.SessionManager"
+#define SM_DBUS_CLIENT_PRIVATE_INTERFACE "org.mate.SessionManager.ClientPrivate"
+
+struct GsmDBusClientPrivate
+{
+ char *bus_name;
+ GPid caller_pid;
+ GsmClientRestartStyle restart_style_hint;
+ DBusConnection *connection;
+};
+
+enum {
+ PROP_0,
+ PROP_BUS_NAME
+};
+
+G_DEFINE_TYPE (GsmDBusClient, gsm_dbus_client, GSM_TYPE_CLIENT)
+
+GQuark
+gsm_dbus_client_error_quark (void)
+{
+ static GQuark ret = 0;
+ if (ret == 0) {
+ ret = g_quark_from_static_string ("gsm_dbus_client_error");
+ }
+
+ return ret;
+}
+
+#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
+
+GType
+gsm_dbus_client_error_get_type (void)
+{
+ static GType etype = 0;
+
+ if (etype == 0) {
+ static const GEnumValue values[] = {
+ ENUM_ENTRY (GSM_DBUS_CLIENT_ERROR_GENERAL, "GeneralError"),
+ ENUM_ENTRY (GSM_DBUS_CLIENT_ERROR_NOT_CLIENT, "NotClient"),
+ { 0, 0, 0 }
+ };
+
+ g_assert (GSM_DBUS_CLIENT_NUM_ERRORS == G_N_ELEMENTS (values) - 1);
+
+ etype = g_enum_register_static ("GsmDbusClientError", values);
+ }
+
+ return etype;
+}
+
+static gboolean
+setup_connection (GsmDBusClient *client)
+{
+ DBusError error;
+
+ dbus_error_init (&error);
+
+ if (client->priv->connection == NULL) {
+ client->priv->connection = dbus_bus_get (DBUS_BUS_SESSION, &error);
+ if (client->priv->connection == NULL) {
+ if (dbus_error_is_set (&error)) {
+ g_debug ("GsmDbusClient: Couldn't connect to session bus: %s",
+ error.message);
+ dbus_error_free (&error);
+ }
+ return FALSE;
+ }
+
+ dbus_connection_setup_with_g_main (client->priv->connection, NULL);
+ dbus_connection_set_exit_on_disconnect (client->priv->connection, FALSE);
+ }
+
+ return TRUE;
+}
+
+static void
+raise_error (DBusConnection *connection,
+ DBusMessage *in_reply_to,
+ const char *error_name,
+ char *format, ...)
+{
+ char buf[512];
+ DBusMessage *reply;
+
+ va_list args;
+ va_start (args, format);
+ vsnprintf (buf, sizeof (buf), format, args);
+ va_end (args);
+
+ reply = dbus_message_new_error (in_reply_to, error_name, buf);
+ if (reply == NULL) {
+ g_error ("No memory");
+ }
+ if (! dbus_connection_send (connection, reply, NULL)) {
+ g_error ("No memory");
+ }
+
+ dbus_message_unref (reply);
+}
+
+static void
+handle_end_session_response (GsmDBusClient *client,
+ DBusMessage *message)
+{
+ const char *sender;
+ DBusMessage *reply;
+ DBusError error;
+ dbus_bool_t is_ok;
+ const char *reason;
+
+ dbus_error_init (&error);
+ if (! dbus_message_get_args (message, &error,
+ DBUS_TYPE_BOOLEAN, &is_ok,
+ DBUS_TYPE_STRING, &reason,
+ DBUS_TYPE_INVALID)) {
+ if (dbus_error_is_set (&error)) {
+ g_warning ("Invalid method call: %s", error.message);
+ dbus_error_free (&error);
+ }
+ raise_error (client->priv->connection,
+ message,
+ DBUS_ERROR_FAILED,
+ "There is a syntax error in the invocation of the method EndSessionResponse");
+ return;
+ }
+
+ g_debug ("GsmDBusClient: got EndSessionResponse is-ok:%d reason=%s", is_ok, reason);
+
+ /* make sure it is from our client */
+ sender = dbus_message_get_sender (message);
+ if (sender == NULL
+ || IS_STRING_EMPTY (client->priv->bus_name)
+ || strcmp (sender, client->priv->bus_name) != 0) {
+
+ raise_error (client->priv->connection,
+ message,
+ DBUS_ERROR_FAILED,
+ "Caller not recognized as the client");
+ return;
+ }
+
+ reply = dbus_message_new_method_return (message);
+ if (reply == NULL) {
+ g_error ("No memory");
+ }
+
+ gsm_client_end_session_response (GSM_CLIENT (client),
+ is_ok, FALSE, FALSE, reason);
+
+
+ if (! dbus_connection_send (client->priv->connection, reply, NULL)) {
+ g_error ("No memory");
+ }
+
+ dbus_message_unref (reply);
+}
+
+static DBusHandlerResult
+client_dbus_filter_function (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ GsmDBusClient *client = GSM_DBUS_CLIENT (user_data);
+ const char *path;
+
+ g_return_val_if_fail (connection != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+ g_return_val_if_fail (message != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+
+ path = dbus_message_get_path (message);
+
+ g_debug ("GsmDBusClient: obj_path=%s interface=%s method=%s",
+ dbus_message_get_path (message),
+ dbus_message_get_interface (message),
+ dbus_message_get_member (message));
+
+ if (dbus_message_is_method_call (message, SM_DBUS_CLIENT_PRIVATE_INTERFACE, "EndSessionResponse")) {
+ g_assert (gsm_client_peek_id (GSM_CLIENT (client)) != NULL);
+
+ if (path != NULL && strcmp (path, gsm_client_peek_id (GSM_CLIENT (client))) != 0) {
+ /* Different object path */
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ handle_end_session_response (client, message);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static GObject *
+gsm_dbus_client_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GsmDBusClient *client;
+
+ client = GSM_DBUS_CLIENT (G_OBJECT_CLASS (gsm_dbus_client_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_properties));
+
+ if (! setup_connection (client)) {
+ g_object_unref (client);
+ return NULL;
+ }
+
+ /* Object path is already registered by base class */
+ dbus_connection_add_filter (client->priv->connection, client_dbus_filter_function, client, NULL);
+
+ return G_OBJECT (client);
+}
+
+static void
+gsm_dbus_client_init (GsmDBusClient *client)
+{
+ client->priv = GSM_DBUS_CLIENT_GET_PRIVATE (client);
+}
+
+/* adapted from PolicyKit */
+static gboolean
+get_caller_info (GsmDBusClient *client,
+ const char *sender,
+ uid_t *calling_uid,
+ pid_t *calling_pid)
+{
+ gboolean res;
+ GError *error;
+ DBusGConnection *connection;
+ DBusGProxy *bus_proxy;
+
+ res = FALSE;
+ bus_proxy = NULL;
+
+ if (sender == NULL) {
+ goto out;
+ }
+
+ error = NULL;
+ connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+ if (connection == NULL) {
+ if (error != NULL) {
+ g_warning ("error getting session bus: %s", error->message);
+ g_error_free (error);
+ }
+ goto out;
+ }
+
+ bus_proxy = dbus_g_proxy_new_for_name (connection,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS);
+
+ error = NULL;
+ if (! dbus_g_proxy_call (bus_proxy, "GetConnectionUnixUser", &error,
+ G_TYPE_STRING, sender,
+ G_TYPE_INVALID,
+ G_TYPE_UINT, calling_uid,
+ G_TYPE_INVALID)) {
+ g_debug ("GetConnectionUnixUser() failed: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ error = NULL;
+ if (! dbus_g_proxy_call (bus_proxy, "GetConnectionUnixProcessID", &error,
+ G_TYPE_STRING, sender,
+ G_TYPE_INVALID,
+ G_TYPE_UINT, calling_pid,
+ G_TYPE_INVALID)) {
+ g_debug ("GetConnectionUnixProcessID() failed: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ res = TRUE;
+
+ g_debug ("uid = %d", *calling_uid);
+ g_debug ("pid = %d", *calling_pid);
+
+out:
+ if (bus_proxy != NULL) {
+ g_object_unref (bus_proxy);
+ }
+ return res;
+}
+
+static void
+gsm_dbus_client_set_bus_name (GsmDBusClient *client,
+ const char *bus_name)
+{
+ uid_t uid;
+ pid_t pid;
+
+ g_return_if_fail (GSM_IS_DBUS_CLIENT (client));
+
+ g_free (client->priv->bus_name);
+
+ client->priv->bus_name = g_strdup (bus_name);
+ g_object_notify (G_OBJECT (client), "bus-name");
+
+ if (client->priv->bus_name != NULL) {
+ gboolean res;
+
+ res = get_caller_info (client, bus_name, &uid, &pid);
+ if (! res) {
+ pid = 0;
+ }
+ } else {
+ pid = 0;
+ }
+ client->priv->caller_pid = pid;
+}
+
+const char *
+gsm_dbus_client_get_bus_name (GsmDBusClient *client)
+{
+ g_return_val_if_fail (GSM_IS_DBUS_CLIENT (client), NULL);
+
+ return client->priv->bus_name;
+}
+
+static void
+gsm_dbus_client_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GsmDBusClient *self;
+
+ self = GSM_DBUS_CLIENT (object);
+
+ switch (prop_id) {
+ case PROP_BUS_NAME:
+ gsm_dbus_client_set_bus_name (self, g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gsm_dbus_client_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GsmDBusClient *self;
+
+ self = GSM_DBUS_CLIENT (object);
+
+ switch (prop_id) {
+ case PROP_BUS_NAME:
+ g_value_set_string (value, self->priv->bus_name);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gsm_dbus_client_finalize (GObject *object)
+{
+ GsmDBusClient *client = (GsmDBusClient *) object;
+
+ g_free (client->priv->bus_name);
+
+ G_OBJECT_CLASS (gsm_dbus_client_parent_class)->finalize (object);
+}
+
+static GKeyFile *
+dbus_client_save (GsmClient *client,
+ GError **error)
+{
+ g_debug ("GsmDBusClient: saving client with id %s",
+ gsm_client_peek_id (client));
+
+ /* FIXME: We still don't support client saving for D-Bus
+ * session clients */
+
+ return NULL;
+}
+
+static gboolean
+dbus_client_stop (GsmClient *client,
+ GError **error)
+{
+ GsmDBusClient *dbus_client = (GsmDBusClient *) client;
+ DBusMessage *message;
+ gboolean ret;
+
+ ret = FALSE;
+
+ /* unicast the signal to only the registered bus name */
+ message = dbus_message_new_signal (gsm_client_peek_id (client),
+ SM_DBUS_CLIENT_PRIVATE_INTERFACE,
+ "Stop");
+ if (message == NULL) {
+ goto out;
+ }
+ if (!dbus_message_set_destination (message, dbus_client->priv->bus_name)) {
+ goto out;
+ }
+
+ if (!dbus_connection_send (dbus_client->priv->connection, message, NULL)) {
+ goto out;
+ }
+
+ ret = TRUE;
+
+ out:
+ if (message != NULL) {
+ dbus_message_unref (message);
+ }
+
+ return ret;
+}
+
+static char *
+dbus_client_get_app_name (GsmClient *client)
+{
+ /* Always use app-id instead */
+ return NULL;
+}
+
+static GsmClientRestartStyle
+dbus_client_get_restart_style_hint (GsmClient *client)
+{
+ return (GSM_DBUS_CLIENT (client)->priv->restart_style_hint);
+}
+
+static guint
+dbus_client_get_unix_process_id (GsmClient *client)
+{
+ return (GSM_DBUS_CLIENT (client)->priv->caller_pid);
+}
+
+static gboolean
+dbus_client_query_end_session (GsmClient *client,
+ guint flags,
+ GError **error)
+{
+ GsmDBusClient *dbus_client = (GsmDBusClient *) client;
+ DBusMessage *message;
+ DBusMessageIter iter;
+ gboolean ret;
+
+ ret = FALSE;
+
+ if (dbus_client->priv->bus_name == NULL) {
+ g_set_error (error,
+ GSM_CLIENT_ERROR,
+ GSM_CLIENT_ERROR_NOT_REGISTERED,
+ "Client is not registered");
+ return FALSE;
+ }
+
+ g_debug ("GsmDBusClient: sending QueryEndSession signal to %s", dbus_client->priv->bus_name);
+
+ /* unicast the signal to only the registered bus name */
+ message = dbus_message_new_signal (gsm_client_peek_id (client),
+ SM_DBUS_CLIENT_PRIVATE_INTERFACE,
+ "QueryEndSession");
+ if (message == NULL) {
+ g_set_error (error,
+ GSM_CLIENT_ERROR,
+ GSM_CLIENT_ERROR_NOT_REGISTERED,
+ "Unable to send QueryEndSession message");
+ goto out;
+ }
+ if (!dbus_message_set_destination (message, dbus_client->priv->bus_name)) {
+ g_set_error (error,
+ GSM_CLIENT_ERROR,
+ GSM_CLIENT_ERROR_NOT_REGISTERED,
+ "Unable to send QueryEndSession message");
+ goto out;
+ }
+
+ dbus_message_iter_init_append (message, &iter);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT32, &flags);
+
+ if (!dbus_connection_send (dbus_client->priv->connection, message, NULL)) {
+ g_set_error (error,
+ GSM_CLIENT_ERROR,
+ GSM_CLIENT_ERROR_NOT_REGISTERED,
+ "Unable to send QueryEndSession message");
+ goto out;
+ }
+
+ ret = TRUE;
+
+ out:
+ if (message != NULL) {
+ dbus_message_unref (message);
+ }
+
+ return ret;
+}
+
+static gboolean
+dbus_client_end_session (GsmClient *client,
+ guint flags,
+ GError **error)
+{
+ GsmDBusClient *dbus_client = (GsmDBusClient *) client;
+ DBusMessage *message;
+ DBusMessageIter iter;
+ gboolean ret;
+
+ ret = FALSE;
+
+ /* unicast the signal to only the registered bus name */
+ message = dbus_message_new_signal (gsm_client_peek_id (client),
+ SM_DBUS_CLIENT_PRIVATE_INTERFACE,
+ "EndSession");
+ if (message == NULL) {
+ g_set_error (error,
+ GSM_CLIENT_ERROR,
+ GSM_CLIENT_ERROR_NOT_REGISTERED,
+ "Unable to send EndSession message");
+ goto out;
+ }
+ if (!dbus_message_set_destination (message, dbus_client->priv->bus_name)) {
+ g_set_error (error,
+ GSM_CLIENT_ERROR,
+ GSM_CLIENT_ERROR_NOT_REGISTERED,
+ "Unable to send EndSession message");
+ goto out;
+ }
+
+ dbus_message_iter_init_append (message, &iter);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT32, &flags);
+
+ if (!dbus_connection_send (dbus_client->priv->connection, message, NULL)) {
+ g_set_error (error,
+ GSM_CLIENT_ERROR,
+ GSM_CLIENT_ERROR_NOT_REGISTERED,
+ "Unable to send EndSession message");
+ goto out;
+ }
+
+ ret = TRUE;
+
+ out:
+ if (message != NULL) {
+ dbus_message_unref (message);
+ }
+ return ret;
+}
+
+static gboolean
+dbus_client_cancel_end_session (GsmClient *client,
+ GError **error)
+{
+ GsmDBusClient *dbus_client = (GsmDBusClient *) client;
+ DBusMessage *message;
+ gboolean ret;
+
+ /* unicast the signal to only the registered bus name */
+ message = dbus_message_new_signal (gsm_client_peek_id (client),
+ SM_DBUS_CLIENT_PRIVATE_INTERFACE,
+ "CancelEndSession");
+ if (message == NULL) {
+ g_set_error (error,
+ GSM_CLIENT_ERROR,
+ GSM_CLIENT_ERROR_NOT_REGISTERED,
+ "Unable to send CancelEndSession message");
+ goto out;
+ }
+ if (!dbus_message_set_destination (message, dbus_client->priv->bus_name)) {
+ g_set_error (error,
+ GSM_CLIENT_ERROR,
+ GSM_CLIENT_ERROR_NOT_REGISTERED,
+ "Unable to send CancelEndSession message");
+ goto out;
+ }
+
+ if (!dbus_connection_send (dbus_client->priv->connection, message, NULL)) {
+ g_set_error (error,
+ GSM_CLIENT_ERROR,
+ GSM_CLIENT_ERROR_NOT_REGISTERED,
+ "Unable to send CancelEndSession message");
+ goto out;
+ }
+
+ ret = TRUE;
+
+ out:
+ if (message != NULL) {
+ dbus_message_unref (message);
+ }
+
+ return ret;
+}
+
+static void
+gsm_dbus_client_dispose (GObject *object)
+{
+ GsmDBusClient *client;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GSM_IS_DBUS_CLIENT (object));
+
+ client = GSM_DBUS_CLIENT (object);
+
+ dbus_connection_remove_filter (client->priv->connection, client_dbus_filter_function, client);
+
+ G_OBJECT_CLASS (gsm_dbus_client_parent_class)->dispose (object);
+}
+
+static void
+gsm_dbus_client_class_init (GsmDBusClientClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GsmClientClass *client_class = GSM_CLIENT_CLASS (klass);
+
+ object_class->finalize = gsm_dbus_client_finalize;
+ object_class->constructor = gsm_dbus_client_constructor;
+ object_class->get_property = gsm_dbus_client_get_property;
+ object_class->set_property = gsm_dbus_client_set_property;
+ object_class->dispose = gsm_dbus_client_dispose;
+
+ client_class->impl_save = dbus_client_save;
+ client_class->impl_stop = dbus_client_stop;
+ client_class->impl_query_end_session = dbus_client_query_end_session;
+ client_class->impl_end_session = dbus_client_end_session;
+ client_class->impl_cancel_end_session = dbus_client_cancel_end_session;
+ client_class->impl_get_app_name = dbus_client_get_app_name;
+ client_class->impl_get_restart_style_hint = dbus_client_get_restart_style_hint;
+ client_class->impl_get_unix_process_id = dbus_client_get_unix_process_id;
+
+ g_object_class_install_property (object_class,
+ PROP_BUS_NAME,
+ g_param_spec_string ("bus-name",
+ "bus-name",
+ "bus-name",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_type_class_add_private (klass, sizeof (GsmDBusClientPrivate));
+}
+
+GsmClient *
+gsm_dbus_client_new (const char *startup_id,
+ const char *bus_name)
+{
+ GsmDBusClient *client;
+
+ client = g_object_new (GSM_TYPE_DBUS_CLIENT,
+ "startup-id", startup_id,
+ "bus-name", bus_name,
+ NULL);
+
+ return GSM_CLIENT (client);
+}
diff --git a/mate-session/gsm-dbus-client.h b/mate-session/gsm-dbus-client.h
new file mode 100644
index 0000000..4b1895d
--- /dev/null
+++ b/mate-session/gsm-dbus-client.h
@@ -0,0 +1,77 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * 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
+ * Lesser 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_DBUS_CLIENT_H__
+#define __GSM_DBUS_CLIENT_H__
+
+#include "gsm-client.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GSM_TYPE_DBUS_CLIENT (gsm_dbus_client_get_type ())
+#define GSM_DBUS_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSM_TYPE_DBUS_CLIENT, GsmDBusClient))
+#define GSM_DBUS_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSM_TYPE_DBUS_CLIENT, GsmDBusClientClass))
+#define GSM_IS_DBUS_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSM_TYPE_DBUS_CLIENT))
+#define GSM_IS_DBUS_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSM_TYPE_DBUS_CLIENT))
+#define GSM_DBUS_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSM_TYPE_DBUS_CLIENT, GsmDBusClientClass))
+
+typedef struct _GsmDBusClient GsmDBusClient;
+typedef struct _GsmDBusClientClass GsmDBusClientClass;
+
+typedef struct GsmDBusClientPrivate GsmDBusClientPrivate;
+
+struct _GsmDBusClient
+{
+ GsmClient parent;
+ GsmDBusClientPrivate *priv;
+};
+
+struct _GsmDBusClientClass
+{
+ GsmClientClass parent_class;
+};
+
+typedef enum
+{
+ GSM_DBUS_CLIENT_ERROR_GENERAL = 0,
+ GSM_DBUS_CLIENT_ERROR_NOT_CLIENT,
+ GSM_DBUS_CLIENT_NUM_ERRORS
+} GsmDBusClientError;
+
+#define GSM_DBUS_CLIENT_ERROR gsm_dbus_client_error_quark ()
+
+GType gsm_dbus_client_error_get_type (void);
+#define GSM_DBUS_CLIENT_TYPE_ERROR (gsm_dbus_client_error_get_type ())
+
+GQuark gsm_dbus_client_error_quark (void);
+
+GType gsm_dbus_client_get_type (void) G_GNUC_CONST;
+
+GsmClient * gsm_dbus_client_new (const char *startup_id,
+ const char *bus_name);
+const char * gsm_dbus_client_get_bus_name (GsmDBusClient *client);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GSM_DBUS_CLIENT_H__ */
diff --git a/mate-session/gsm-inhibit-dialog.c b/mate-session/gsm-inhibit-dialog.c
new file mode 100644
index 0000000..d5b4d57
--- /dev/null
+++ b/mate-session/gsm-inhibit-dialog.c
@@ -0,0 +1,1164 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 William Jon McCann <[email protected]>
+ *
+ * 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 <mateconf/mateconf-client.h>
+
+#include "gsm-inhibit-dialog.h"
+#include "gsm-store.h"
+#include "gsm-client.h"
+#include "gsm-inhibitor.h"
+#include "eggdesktopfile.h"
+#include "gsm-util.h"
+
+#ifdef HAVE_XRENDER
+#include <X11/extensions/Xrender.h>
+#endif
+
+#define GSM_INHIBIT_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_INHIBIT_DIALOG, GsmInhibitDialogPrivate))
+
+#define IS_STRING_EMPTY(x) ((x)==NULL||(x)[0]=='\0')
+
+#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
+
+struct GsmInhibitDialogPrivate
+{
+ GtkBuilder *xml;
+ int action;
+ gboolean is_done;
+ GsmStore *inhibitors;
+ GsmStore *clients;
+ GtkListStore *list_store;
+ gboolean have_xrender;
+ int xrender_event_base;
+ int xrender_error_base;
+};
+
+enum {
+ PROP_0,
+ PROP_ACTION,
+ PROP_INHIBITOR_STORE,
+ PROP_CLIENT_STORE
+};
+
+enum {
+ INHIBIT_IMAGE_COLUMN = 0,
+ INHIBIT_NAME_COLUMN,
+ INHIBIT_REASON_COLUMN,
+ INHIBIT_ID_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 ("mate-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 gboolean
+find_inhibitor (GsmInhibitDialog *dialog,
+ const char *id,
+ GtkTreeIter *iter)
+{
+ GtkTreeModel *model;
+ gboolean found_item;
+
+ g_assert (GSM_IS_INHIBIT_DIALOG (dialog));
+
+ found_item = FALSE;
+ model = GTK_TREE_MODEL (dialog->priv->list_store);
+
+ if (!gtk_tree_model_get_iter_first (model, iter)) {
+ return FALSE;
+ }
+
+ do {
+ char *item_id;
+
+ gtk_tree_model_get (model,
+ iter,
+ INHIBIT_ID_COLUMN, &item_id,
+ -1);
+ if (item_id != NULL
+ && id != NULL
+ && strcmp (item_id, id) == 0) {
+ found_item = TRUE;
+ }
+ g_free (item_id);
+ } while (!found_item && gtk_tree_model_iter_next (model, iter));
+
+ return found_item;
+}
+
+/* copied from mate-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 mate-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));
+ gtk_icon_info_free (info);
+ } else
+ retval = NULL;
+
+ return retval;
+}
+
+/* copied from mate-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
+
+/* adapted from marco */
+static GdkColormap*
+get_cmap (GdkPixmap *pixmap)
+{
+ GdkColormap *cmap;
+
+ cmap = gdk_drawable_get_colormap (pixmap);
+ if (cmap) {
+ g_object_ref (G_OBJECT (cmap));
+ }
+
+ if (cmap == NULL) {
+ if (gdk_drawable_get_depth (pixmap) == 1) {
+ g_debug ("Using NULL colormap for snapshotting bitmap\n");
+ cmap = NULL;
+ } else {
+ g_debug ("Using system cmap to snapshot pixmap\n");
+ cmap = gdk_screen_get_system_colormap (gdk_drawable_get_screen (pixmap));
+
+ g_object_ref (G_OBJECT (cmap));
+ }
+ }
+
+ /* Be sure we aren't going to blow up due to visual mismatch */
+ if (cmap &&
+ (gdk_visual_get_depth (gdk_colormap_get_visual (cmap)) !=
+ gdk_drawable_get_depth (pixmap))) {
+ cmap = NULL;
+ g_debug ("Switching back to NULL cmap because of depth mismatch\n");
+ }
+
+ return cmap;
+}
+
+static GdkPixbuf *
+pixbuf_get_from_pixmap (Pixmap xpixmap)
+{
+ GdkDrawable *drawable;
+ GdkPixbuf *retval;
+ GdkColormap *cmap;
+ int width;
+ int height;
+
+ retval = NULL;
+ cmap = NULL;
+
+ g_debug ("GsmInhibitDialog: getting foreign pixmap for %u", (guint)xpixmap);
+ drawable = gdk_pixmap_foreign_new (xpixmap);
+ if (GDK_IS_PIXMAP (drawable)) {
+ cmap = get_cmap (drawable);
+
+ #if GTK_CHECK_VERSION(3, 0, 0)
+ width = gdk_window_get_width(drawable);
+ height = gdk_window_get_height(drawable);
+ #else
+ gdk_drawable_get_size(drawable, &width, &height);
+ #endif
+
+ g_debug ("GsmInhibitDialog: getting pixbuf w=%d h=%d", width, height);
+
+ retval = gdk_pixbuf_get_from_drawable (NULL,
+ drawable,
+ cmap,
+ 0, 0,
+ 0, 0,
+ width, height);
+ }
+ if (cmap) {
+ g_object_unref (G_OBJECT (cmap));
+ }
+ if (drawable) {
+ g_object_unref (G_OBJECT (drawable));
+ }
+
+ return retval;
+}
+
+static Pixmap
+get_pixmap_for_window (Window window)
+{
+ XWindowAttributes attr;
+ XRenderPictureAttributes pa;
+ Pixmap pixmap;
+ XRenderPictFormat *format;
+ Picture src_picture;
+ Picture dst_picture;
+ gboolean has_alpha;
+ int x;
+ int y;
+ int width;
+ int height;
+
+ XGetWindowAttributes (GDK_DISPLAY (), window, &attr);
+
+ format = XRenderFindVisualFormat (GDK_DISPLAY (), attr.visual);
+ has_alpha = (format->type == PictTypeDirect && format->direct.alphaMask);
+ x = attr.x;
+ y = attr.y;
+ width = attr.width;
+ height = attr.height;
+
+ pa.subwindow_mode = IncludeInferiors; /* Don't clip child widgets */
+
+ src_picture = XRenderCreatePicture (GDK_DISPLAY (), window, format, CPSubwindowMode, &pa);
+
+ pixmap = XCreatePixmap (GDK_DISPLAY (),
+ window,
+ width, height,
+ attr.depth);
+
+ dst_picture = XRenderCreatePicture (GDK_DISPLAY (), pixmap, format, 0, 0);
+ XRenderComposite (GDK_DISPLAY (),
+ has_alpha ? PictOpOver : PictOpSrc,
+ src_picture,
+ None,
+ dst_picture,
+ 0, 0, 0, 0,
+ 0, 0,
+ width, height);
+
+
+ return pixmap;
+}
+
+#endif /* HAVE_COMPOSITE */
+
+static GdkPixbuf *
+get_pixbuf_for_window (guint xid,
+ int width,
+ int height)
+{
+ GdkPixbuf *pixbuf = NULL;
+#ifdef HAVE_XRENDER
+ Window xwindow;
+ Pixmap xpixmap;
+
+ xwindow = (Window) xid;
+ xpixmap = get_pixmap_for_window (xwindow);
+ 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 (xpixmap);
+
+ if (xpixmap != None) {
+ gdk_error_trap_push ();
+ XFreePixmap (GDK_DISPLAY (), xpixmap);
+ gdk_display_sync (gdk_display_get_default ());
+ gdk_error_trap_pop ();
+ }
+
+ if (pixbuf != NULL) {
+ GdkPixbuf *scaled;
+ g_debug ("GsmInhibitDialog: scaling pixbuf to w=%d h=%d", width, height);
+ scaled = scale_pixbuf (pixbuf, width, height, TRUE);
+ g_object_unref (pixbuf);
+ pixbuf = scaled;
+ }
+#else
+ g_debug ("GsmInhibitDialog: no support for getting window snapshot");
+#endif
+ return pixbuf;
+}
+
+static void
+add_inhibitor (GsmInhibitDialog *dialog,
+ GsmInhibitor *inhibitor)
+{
+ const char *name;
+ const char *icon_name;
+ const char *app_id;
+ char *desktop_filename;
+ GdkPixbuf *pixbuf;
+ EggDesktopFile *desktop_file;
+ GError *error;
+ char **search_dirs;
+ guint xid;
+ char *freeme;
+
+ /* FIXME: get info from xid */
+
+ desktop_file = NULL;
+ name = NULL;
+ pixbuf = NULL;
+ freeme = NULL;
+
+ app_id = gsm_inhibitor_peek_app_id (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);
+ }
+
+ xid = gsm_inhibitor_peek_toplevel_xid (inhibitor);
+ g_debug ("GsmInhibitDialog: inhibitor has XID %u", xid);
+ if (xid > 0 && dialog->priv->have_xrender) {
+ pixbuf = get_pixbuf_for_window (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 ();
+
+ 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 ("mate-%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);
+ }
+ }
+ }
+
+ /* try client info */
+ if (name == NULL) {
+ const char *client_id;
+ client_id = gsm_inhibitor_peek_client_id (inhibitor);
+ if (! IS_STRING_EMPTY (client_id)) {
+ GsmClient *client;
+ client = GSM_CLIENT (gsm_store_lookup (dialog->priv->clients, client_id));
+ if (client != NULL) {
+ freeme = gsm_client_get_app_name (client);
+ name = freeme;
+ }
+ }
+ }
+
+ 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 (),
+ "mate-windows",
+ 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, gsm_inhibitor_peek_reason (inhibitor),
+ INHIBIT_ID_COLUMN, gsm_inhibitor_peek_id (inhibitor),
+ -1);
+
+ g_free (desktop_filename);
+ g_free (freeme);
+ if (pixbuf != NULL) {
+ g_object_unref (pixbuf);
+ }
+ if (desktop_file != NULL) {
+ egg_desktop_file_free (desktop_file);
+ }
+}
+
+static gboolean
+model_has_one_entry (GtkTreeModel *model)
+{
+ guint n_rows;
+
+ n_rows = gtk_tree_model_iter_n_children (model, NULL);
+ g_debug ("Model has %d rows", n_rows);
+
+ return (n_rows > 0 && n_rows < 2);
+}
+
+static void
+update_dialog_text (GsmInhibitDialog *dialog)
+{
+ const char *description_text;
+ const char *header_text;
+ GtkWidget *widget;
+
+ if (model_has_one_entry (GTK_TREE_MODEL (dialog->priv->list_store))) {
+ g_debug ("Found one entry in model");
+ header_text = _("A program is still running:");
+ description_text = _("Waiting for the program to finish. Interrupting the program may cause you to lose work.");
+ } else {
+ g_debug ("Found multiple entries (or none) in model");
+ header_text = _("Some programs are still running:");
+ description_text = _("Waiting for programs to finish. Interrupting these programs may cause you to lose work.");
+ }
+
+ widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->xml,
+ "header-label"));
+ if (widget != NULL) {
+ char *markup;
+ markup = g_strdup_printf ("<b>%s</b>", header_text);
+ gtk_label_set_markup (GTK_LABEL (widget), markup);
+ g_free (markup);
+ }
+
+ widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->xml,
+ "description-label"));
+ if (widget != NULL) {
+ gtk_label_set_text (GTK_LABEL (widget), description_text);
+ }
+}
+
+static void
+on_store_inhibitor_added (GsmStore *store,
+ const char *id,
+ GsmInhibitDialog *dialog)
+{
+ GsmInhibitor *inhibitor;
+ GtkTreeIter iter;
+
+ g_debug ("GsmInhibitDialog: inhibitor added: %s", id);
+
+ if (dialog->priv->is_done) {
+ return;
+ }
+
+ inhibitor = (GsmInhibitor *)gsm_store_lookup (store, id);
+
+ /* Add to model */
+ if (! find_inhibitor (dialog, id, &iter)) {
+ add_inhibitor (dialog, inhibitor);
+ update_dialog_text (dialog);
+ }
+
+}
+
+static void
+on_store_inhibitor_removed (GsmStore *store,
+ const char *id,
+ GsmInhibitDialog *dialog)
+{
+ GtkTreeIter iter;
+
+ g_debug ("GsmInhibitDialog: inhibitor removed: %s", id);
+
+ if (dialog->priv->is_done) {
+ return;
+ }
+
+ /* Remove from model */
+ if (find_inhibitor (dialog, id, &iter)) {
+ gtk_list_store_remove (dialog->priv->list_store, &iter);
+ update_dialog_text (dialog);
+ }
+
+ /* if there are no inhibitors left then trigger response */
+ if (! gtk_tree_model_get_iter_first (GTK_TREE_MODEL (dialog->priv->list_store), &iter)) {
+ gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
+ }
+}
+
+static void
+gsm_inhibit_dialog_set_inhibitor_store (GsmInhibitDialog *dialog,
+ GsmStore *store)
+{
+ g_return_if_fail (GSM_IS_INHIBIT_DIALOG (dialog));
+
+ if (store != NULL) {
+ g_object_ref (store);
+ }
+
+ if (dialog->priv->inhibitors != NULL) {
+ g_signal_handlers_disconnect_by_func (dialog->priv->inhibitors,
+ on_store_inhibitor_added,
+ dialog);
+ g_signal_handlers_disconnect_by_func (dialog->priv->inhibitors,
+ on_store_inhibitor_removed,
+ dialog);
+
+ g_object_unref (dialog->priv->inhibitors);
+ }
+
+
+ g_debug ("GsmInhibitDialog: setting store %p", store);
+
+ dialog->priv->inhibitors = store;
+
+ if (dialog->priv->inhibitors != NULL) {
+ g_signal_connect (dialog->priv->inhibitors,
+ "added",
+ G_CALLBACK (on_store_inhibitor_added),
+ dialog);
+ g_signal_connect (dialog->priv->inhibitors,
+ "removed",
+ G_CALLBACK (on_store_inhibitor_removed),
+ dialog);
+ }
+}
+
+static void
+gsm_inhibit_dialog_set_client_store (GsmInhibitDialog *dialog,
+ GsmStore *store)
+{
+ g_return_if_fail (GSM_IS_INHIBIT_DIALOG (dialog));
+
+ if (store != NULL) {
+ g_object_ref (store);
+ }
+
+ if (dialog->priv->clients != NULL) {
+ g_object_unref (dialog->priv->clients);
+ }
+
+ dialog->priv->clients = store;
+}
+
+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_INHIBITOR_STORE:
+ gsm_inhibit_dialog_set_inhibitor_store (dialog, g_value_get_object (value));
+ break;
+ case PROP_CLIENT_STORE:
+ gsm_inhibit_dialog_set_client_store (dialog, g_value_get_object (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_INHIBITOR_STORE:
+ g_value_set_object (value, dialog->priv->inhibitors);
+ break;
+ case PROP_CLIENT_STORE:
+ g_value_set_object (value, dialog->priv->clients);
+ 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 gboolean
+add_to_model (const char *id,
+ GsmInhibitor *inhibitor,
+ GsmInhibitDialog *dialog)
+{
+ add_inhibitor (dialog, inhibitor);
+ return FALSE;
+}
+
+static void
+populate_model (GsmInhibitDialog *dialog)
+{
+ gsm_store_foreach_remove (dialog->priv->inhibitors,
+ (GsmStoreFunc)add_to_model,
+ dialog);
+ update_dialog_text (dialog);
+}
+
+static void
+setup_dialog (GsmInhibitDialog *dialog)
+{
+ const char *button_text;
+ GtkWidget *treeview;
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+
+ switch (dialog->priv->action) {
+ case GSM_LOGOUT_ACTION_SWITCH_USER:
+ button_text = _("Switch User Anyway");
+ break;
+ case GSM_LOGOUT_ACTION_LOGOUT:
+ button_text = _("Log Out Anyway");
+ break;
+ case GSM_LOGOUT_ACTION_SLEEP:
+ button_text = _("Suspend Anyway");
+ break;
+ case GSM_LOGOUT_ACTION_HIBERNATE:
+ button_text = _("Hibernate Anyway");
+ break;
+ case GSM_LOGOUT_ACTION_SHUTDOWN:
+ button_text = _("Shut Down Anyway");
+ break;
+ case GSM_LOGOUT_ACTION_REBOOT:
+ button_text = _("Reboot Anyway");
+ 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);
+
+ 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;
+
+ dialog = GSM_INHIBIT_DIALOG (G_OBJECT_CLASS (gsm_inhibit_dialog_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_properties));
+
+#ifdef HAVE_XRENDER
+ gdk_error_trap_push ();
+ if (XRenderQueryExtension (GDK_DISPLAY (), &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 (gdk_display_get_default ());
+ gdk_error_trap_pop ();
+#endif /* HAVE_XRENDER */
+
+ /* FIXME: turn this on when it is ready */
+ dialog->priv->have_xrender = FALSE;
+
+ setup_dialog (dialog);
+
+ gtk_widget_show_all (GTK_WIDGET (dialog));
+
+ return G_OBJECT (dialog);
+}
+
+static void
+gsm_inhibit_dialog_dispose (GObject *object)
+{
+ GsmInhibitDialog *dialog;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GSM_IS_INHIBIT_DIALOG (object));
+
+ dialog = GSM_INHIBIT_DIALOG (object);
+
+ g_debug ("GsmInhibitDialog: dispose called");
+
+ if (dialog->priv->list_store != NULL) {
+ g_object_unref (dialog->priv->list_store);
+ dialog->priv->list_store = NULL;
+ }
+
+ if (dialog->priv->inhibitors != NULL) {
+ g_signal_handlers_disconnect_by_func (dialog->priv->inhibitors,
+ on_store_inhibitor_added,
+ dialog);
+ g_signal_handlers_disconnect_by_func (dialog->priv->inhibitors,
+ on_store_inhibitor_removed,
+ dialog);
+
+ g_object_unref (dialog->priv->inhibitors);
+ dialog->priv->inhibitors = NULL;
+ }
+
+ if (dialog->priv->xml != NULL) {
+ g_object_unref (dialog->priv->xml);
+ dialog->priv->xml = NULL;
+ }
+
+ G_OBJECT_CLASS (gsm_inhibit_dialog_parent_class)->dispose (object);
+}
+
+static void
+gsm_inhibit_dialog_class_init (GsmInhibitDialogClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_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;
+
+ 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_INHIBITOR_STORE,
+ g_param_spec_object ("inhibitor-store",
+ NULL,
+ NULL,
+ GSM_TYPE_STORE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class,
+ PROP_CLIENT_STORE,
+ g_param_spec_object ("client-store",
+ NULL,
+ NULL,
+ GSM_TYPE_STORE,
+ 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_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+ gtk_window_set_icon_name (GTK_WINDOW (dialog), "system-log-out");
+ gtk_window_set_title (GTK_WINDOW (dialog), "");
+ g_object_set (dialog,
+ "allow-shrink", FALSE,
+ "allow-grow", FALSE,
+ NULL);
+}
+
+static void
+gsm_inhibit_dialog_finalize (GObject *object)
+{
+ GsmInhibitDialog *dialog;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GSM_IS_INHIBIT_DIALOG (object));
+
+ dialog = GSM_INHIBIT_DIALOG (object);
+
+ g_return_if_fail (dialog->priv != NULL);
+
+ g_debug ("GsmInhibitDialog: finalizing");
+
+ G_OBJECT_CLASS (gsm_inhibit_dialog_parent_class)->finalize (object);
+}
+
+GtkWidget *
+gsm_inhibit_dialog_new (GsmStore *inhibitors,
+ GsmStore *clients,
+ int action)
+{
+ GObject *object;
+
+ object = g_object_new (GSM_TYPE_INHIBIT_DIALOG,
+ "action", action,
+ "inhibitor-store", inhibitors,
+ "client-store", clients,
+ NULL);
+
+ return GTK_WIDGET (object);
+}
diff --git a/mate-session/gsm-inhibit-dialog.h b/mate-session/gsm-inhibit-dialog.h
new file mode 100644
index 0000000..035f424
--- /dev/null
+++ b/mate-session/gsm-inhibit-dialog.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 William Jon McCann <[email protected]>
+ *
+ * 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>
+
+#include "gsm-store.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#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 (GsmStore *inhibitors,
+ GsmStore *clients,
+ int action);
+GtkTreeModel * gsm_inhibit_dialog_get_model (GsmInhibitDialog *dialog);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GSM_INHIBIT_DIALOG_H */
diff --git a/mate-session/gsm-inhibitor.c b/mate-session/gsm-inhibitor.c
new file mode 100644
index 0000000..13124a4
--- /dev/null
+++ b/mate-session/gsm-inhibitor.c
@@ -0,0 +1,605 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * 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
+ * Lesser 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 <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <dbus/dbus-glib.h>
+
+#include "gsm-inhibitor.h"
+#include "gsm-inhibitor-glue.h"
+
+static guint32 inhibitor_serial = 1;
+
+#define IS_STRING_EMPTY(x) ((x)==NULL||(x)[0]=='\0')
+
+#define GSM_INHIBITOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_INHIBITOR, GsmInhibitorPrivate))
+
+struct GsmInhibitorPrivate
+{
+ char *id;
+ char *bus_name;
+ char *app_id;
+ char *client_id;
+ char *reason;
+ guint flags;
+ guint toplevel_xid;
+ guint cookie;
+ DBusGConnection *connection;
+};
+
+enum {
+ PROP_0,
+ PROP_BUS_NAME,
+ PROP_REASON,
+ PROP_APP_ID,
+ PROP_CLIENT_ID,
+ PROP_FLAGS,
+ PROP_TOPLEVEL_XID,
+ PROP_COOKIE
+};
+
+G_DEFINE_TYPE (GsmInhibitor, gsm_inhibitor, G_TYPE_OBJECT)
+
+GQuark
+gsm_inhibitor_error_quark (void)
+{
+ static GQuark ret = 0;
+ if (ret == 0) {
+ ret = g_quark_from_static_string ("gsm_inhibitor_error");
+ }
+
+ return ret;
+}
+
+#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
+
+GType
+gsm_inhibitor_error_get_type (void)
+{
+ static GType etype = 0;
+
+ if (etype == 0) {
+ static const GEnumValue values[] = {
+ ENUM_ENTRY (GSM_INHIBITOR_ERROR_GENERAL, "GeneralError"),
+ ENUM_ENTRY (GSM_INHIBITOR_ERROR_NOT_SET, "NotSet"),
+ { 0, 0, 0 }
+ };
+
+ g_assert (GSM_INHIBITOR_NUM_ERRORS == G_N_ELEMENTS (values) - 1);
+
+ etype = g_enum_register_static ("GsmInhibitorError", values);
+ }
+
+ return etype;
+}
+
+static guint32
+get_next_inhibitor_serial (void)
+{
+ guint32 serial;
+
+ serial = inhibitor_serial++;
+
+ if ((gint32)inhibitor_serial < 0) {
+ inhibitor_serial = 1;
+ }
+
+ return serial;
+}
+
+static gboolean
+register_inhibitor (GsmInhibitor *inhibitor)
+{
+ GError *error;
+
+ error = NULL;
+ inhibitor->priv->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+ if (inhibitor->priv->connection == NULL) {
+ if (error != NULL) {
+ g_critical ("error getting session bus: %s", error->message);
+ g_error_free (error);
+ }
+ return FALSE;
+ }
+
+ dbus_g_connection_register_g_object (inhibitor->priv->connection, inhibitor->priv->id, G_OBJECT (inhibitor));
+
+ return TRUE;
+}
+
+static GObject *
+gsm_inhibitor_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GsmInhibitor *inhibitor;
+ gboolean res;
+
+ inhibitor = GSM_INHIBITOR (G_OBJECT_CLASS (gsm_inhibitor_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_properties));
+
+ g_free (inhibitor->priv->id);
+ inhibitor->priv->id = g_strdup_printf ("/org/mate/SessionManager/Inhibitor%u", get_next_inhibitor_serial ());
+ res = register_inhibitor (inhibitor);
+ if (! res) {
+ g_warning ("Unable to register inhibitor with session bus");
+ }
+
+ return G_OBJECT (inhibitor);
+}
+
+static void
+gsm_inhibitor_init (GsmInhibitor *inhibitor)
+{
+ inhibitor->priv = GSM_INHIBITOR_GET_PRIVATE (inhibitor);
+}
+
+static void
+gsm_inhibitor_set_bus_name (GsmInhibitor *inhibitor,
+ const char *bus_name)
+{
+ g_return_if_fail (GSM_IS_INHIBITOR (inhibitor));
+
+ g_free (inhibitor->priv->bus_name);
+
+ if (bus_name != NULL) {
+ inhibitor->priv->bus_name = g_strdup (bus_name);
+ } else {
+ inhibitor->priv->bus_name = g_strdup ("");
+ }
+ g_object_notify (G_OBJECT (inhibitor), "bus-name");
+}
+
+static void
+gsm_inhibitor_set_app_id (GsmInhibitor *inhibitor,
+ const char *app_id)
+{
+ g_return_if_fail (GSM_IS_INHIBITOR (inhibitor));
+
+ g_free (inhibitor->priv->app_id);
+
+ inhibitor->priv->app_id = g_strdup (app_id);
+ g_object_notify (G_OBJECT (inhibitor), "app-id");
+}
+
+static void
+gsm_inhibitor_set_client_id (GsmInhibitor *inhibitor,
+ const char *client_id)
+{
+ g_return_if_fail (GSM_IS_INHIBITOR (inhibitor));
+
+ g_free (inhibitor->priv->client_id);
+
+ g_debug ("GsmInhibitor: setting client-id = %s", client_id);
+
+ if (client_id != NULL) {
+ inhibitor->priv->client_id = g_strdup (client_id);
+ } else {
+ inhibitor->priv->client_id = g_strdup ("");
+ }
+ g_object_notify (G_OBJECT (inhibitor), "client-id");
+}
+
+static void
+gsm_inhibitor_set_reason (GsmInhibitor *inhibitor,
+ const char *reason)
+{
+ g_return_if_fail (GSM_IS_INHIBITOR (inhibitor));
+
+ g_free (inhibitor->priv->reason);
+
+ if (reason != NULL) {
+ inhibitor->priv->reason = g_strdup (reason);
+ } else {
+ inhibitor->priv->reason = g_strdup ("");
+ }
+ g_object_notify (G_OBJECT (inhibitor), "reason");
+}
+
+static void
+gsm_inhibitor_set_cookie (GsmInhibitor *inhibitor,
+ guint cookie)
+{
+ g_return_if_fail (GSM_IS_INHIBITOR (inhibitor));
+
+ if (inhibitor->priv->cookie != cookie) {
+ inhibitor->priv->cookie = cookie;
+ g_object_notify (G_OBJECT (inhibitor), "cookie");
+ }
+}
+
+static void
+gsm_inhibitor_set_flags (GsmInhibitor *inhibitor,
+ guint flags)
+{
+ g_return_if_fail (GSM_IS_INHIBITOR (inhibitor));
+
+ if (inhibitor->priv->flags != flags) {
+ inhibitor->priv->flags = flags;
+ g_object_notify (G_OBJECT (inhibitor), "flags");
+ }
+}
+
+static void
+gsm_inhibitor_set_toplevel_xid (GsmInhibitor *inhibitor,
+ guint xid)
+{
+ g_return_if_fail (GSM_IS_INHIBITOR (inhibitor));
+
+ if (inhibitor->priv->toplevel_xid != xid) {
+ inhibitor->priv->toplevel_xid = xid;
+ g_object_notify (G_OBJECT (inhibitor), "toplevel-xid");
+ }
+}
+
+const char *
+gsm_inhibitor_peek_bus_name (GsmInhibitor *inhibitor)
+{
+ g_return_val_if_fail (GSM_IS_INHIBITOR (inhibitor), NULL);
+
+ return inhibitor->priv->bus_name;
+}
+
+gboolean
+gsm_inhibitor_get_app_id (GsmInhibitor *inhibitor,
+ char **id,
+ GError **error)
+{
+ g_return_val_if_fail (GSM_IS_INHIBITOR (inhibitor), FALSE);
+
+ if (inhibitor->priv->app_id != NULL) {
+ *id = g_strdup (inhibitor->priv->app_id);
+ } else {
+ *id = g_strdup ("");
+ }
+
+ return TRUE;
+}
+
+gboolean
+gsm_inhibitor_get_client_id (GsmInhibitor *inhibitor,
+ char **id,
+ GError **error)
+{
+ g_return_val_if_fail (GSM_IS_INHIBITOR (inhibitor), FALSE);
+
+ /* object paths are not allowed to be NULL or blank */
+ if (IS_STRING_EMPTY (inhibitor->priv->client_id)) {
+ g_set_error (error,
+ GSM_INHIBITOR_ERROR,
+ GSM_INHIBITOR_ERROR_NOT_SET,
+ "Value is not set");
+ return FALSE;
+ }
+
+ *id = g_strdup (inhibitor->priv->client_id);
+
+ g_debug ("GsmInhibitor: getting client-id = '%s'", *id);
+
+ return TRUE;
+}
+
+gboolean
+gsm_inhibitor_get_reason (GsmInhibitor *inhibitor,
+ char **reason,
+ GError **error)
+{
+ g_return_val_if_fail (GSM_IS_INHIBITOR (inhibitor), FALSE);
+
+ if (inhibitor->priv->reason != NULL) {
+ *reason = g_strdup (inhibitor->priv->reason);
+ } else {
+ *reason = g_strdup ("");
+ }
+
+ return TRUE;
+}
+
+gboolean
+gsm_inhibitor_get_flags (GsmInhibitor *inhibitor,
+ guint *flags,
+ GError **error)
+{
+ g_return_val_if_fail (GSM_IS_INHIBITOR (inhibitor), FALSE);
+
+ *flags = inhibitor->priv->flags;
+
+ return TRUE;
+}
+
+gboolean
+gsm_inhibitor_get_toplevel_xid (GsmInhibitor *inhibitor,
+ guint *xid,
+ GError **error)
+{
+ g_return_val_if_fail (GSM_IS_INHIBITOR (inhibitor), FALSE);
+
+ *xid = inhibitor->priv->toplevel_xid;
+
+ return TRUE;
+}
+
+const char *
+gsm_inhibitor_peek_id (GsmInhibitor *inhibitor)
+{
+ g_return_val_if_fail (GSM_IS_INHIBITOR (inhibitor), NULL);
+
+ return inhibitor->priv->id;
+}
+
+const char *
+gsm_inhibitor_peek_app_id (GsmInhibitor *inhibitor)
+{
+ g_return_val_if_fail (GSM_IS_INHIBITOR (inhibitor), NULL);
+
+ return inhibitor->priv->app_id;
+}
+
+const char *
+gsm_inhibitor_peek_client_id (GsmInhibitor *inhibitor)
+{
+ g_return_val_if_fail (GSM_IS_INHIBITOR (inhibitor), NULL);
+
+ return inhibitor->priv->client_id;
+}
+
+const char *
+gsm_inhibitor_peek_reason (GsmInhibitor *inhibitor)
+{
+ g_return_val_if_fail (GSM_IS_INHIBITOR (inhibitor), NULL);
+
+ return inhibitor->priv->reason;
+}
+
+guint
+gsm_inhibitor_peek_flags (GsmInhibitor *inhibitor)
+{
+ g_return_val_if_fail (GSM_IS_INHIBITOR (inhibitor), 0);
+
+ return inhibitor->priv->flags;
+}
+
+guint
+gsm_inhibitor_peek_toplevel_xid (GsmInhibitor *inhibitor)
+{
+ g_return_val_if_fail (GSM_IS_INHIBITOR (inhibitor), 0);
+
+ return inhibitor->priv->toplevel_xid;
+}
+
+guint
+gsm_inhibitor_peek_cookie (GsmInhibitor *inhibitor)
+{
+ g_return_val_if_fail (GSM_IS_INHIBITOR (inhibitor), 0);
+
+ return inhibitor->priv->cookie;
+}
+
+static void
+gsm_inhibitor_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GsmInhibitor *self;
+
+ self = GSM_INHIBITOR (object);
+
+ switch (prop_id) {
+ case PROP_BUS_NAME:
+ gsm_inhibitor_set_bus_name (self, g_value_get_string (value));
+ break;
+ case PROP_APP_ID:
+ gsm_inhibitor_set_app_id (self, g_value_get_string (value));
+ break;
+ case PROP_CLIENT_ID:
+ gsm_inhibitor_set_client_id (self, g_value_get_string (value));
+ break;
+ case PROP_REASON:
+ gsm_inhibitor_set_reason (self, g_value_get_string (value));
+ break;
+ case PROP_FLAGS:
+ gsm_inhibitor_set_flags (self, g_value_get_uint (value));
+ break;
+ case PROP_COOKIE:
+ gsm_inhibitor_set_cookie (self, g_value_get_uint (value));
+ break;
+ case PROP_TOPLEVEL_XID:
+ gsm_inhibitor_set_toplevel_xid (self, g_value_get_uint (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gsm_inhibitor_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GsmInhibitor *self;
+
+ self = GSM_INHIBITOR (object);
+
+ switch (prop_id) {
+ case PROP_BUS_NAME:
+ g_value_set_string (value, self->priv->bus_name);
+ break;
+ case PROP_APP_ID:
+ g_value_set_string (value, self->priv->app_id);
+ break;
+ case PROP_CLIENT_ID:
+ g_value_set_string (value, self->priv->client_id);
+ break;
+ case PROP_REASON:
+ g_value_set_string (value, self->priv->reason);
+ break;
+ case PROP_FLAGS:
+ g_value_set_uint (value, self->priv->flags);
+ break;
+ case PROP_COOKIE:
+ g_value_set_uint (value, self->priv->cookie);
+ break;
+ case PROP_TOPLEVEL_XID:
+ g_value_set_uint (value, self->priv->toplevel_xid);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gsm_inhibitor_finalize (GObject *object)
+{
+ GsmInhibitor *inhibitor = (GsmInhibitor *) object;
+
+ g_free (inhibitor->priv->id);
+ g_free (inhibitor->priv->bus_name);
+ g_free (inhibitor->priv->app_id);
+ g_free (inhibitor->priv->client_id);
+ g_free (inhibitor->priv->reason);
+
+ G_OBJECT_CLASS (gsm_inhibitor_parent_class)->finalize (object);
+}
+
+static void
+gsm_inhibitor_class_init (GsmInhibitorClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gsm_inhibitor_finalize;
+ object_class->constructor = gsm_inhibitor_constructor;
+ object_class->get_property = gsm_inhibitor_get_property;
+ object_class->set_property = gsm_inhibitor_set_property;
+
+ g_object_class_install_property (object_class,
+ PROP_BUS_NAME,
+ g_param_spec_string ("bus-name",
+ "bus-name",
+ "bus-name",
+ "",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class,
+ PROP_APP_ID,
+ g_param_spec_string ("app-id",
+ "app-id",
+ "app-id",
+ "",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class,
+ PROP_CLIENT_ID,
+ g_param_spec_string ("client-id",
+ "client-id",
+ "client-id",
+ "",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class,
+ PROP_REASON,
+ g_param_spec_string ("reason",
+ "reason",
+ "reason",
+ "",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class,
+ PROP_FLAGS,
+ g_param_spec_uint ("flags",
+ "flags",
+ "flags",
+ 0,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class,
+ PROP_TOPLEVEL_XID,
+ g_param_spec_uint ("toplevel-xid",
+ "toplevel-xid",
+ "toplevel-xid",
+ 0,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class,
+ PROP_COOKIE,
+ g_param_spec_uint ("cookie",
+ "cookie",
+ "cookie",
+ 0,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ dbus_g_object_type_install_info (GSM_TYPE_INHIBITOR, &dbus_glib_gsm_inhibitor_object_info);
+ dbus_g_error_domain_register (GSM_INHIBITOR_ERROR, NULL, GSM_INHIBITOR_TYPE_ERROR);
+ g_type_class_add_private (klass, sizeof (GsmInhibitorPrivate));
+}
+
+GsmInhibitor *
+gsm_inhibitor_new (const char *app_id,
+ guint toplevel_xid,
+ guint flags,
+ const char *reason,
+ const char *bus_name,
+ guint cookie)
+{
+ GsmInhibitor *inhibitor;
+
+ inhibitor = g_object_new (GSM_TYPE_INHIBITOR,
+ "app-id", app_id,
+ "reason", reason,
+ "bus-name", bus_name,
+ "flags", flags,
+ "toplevel-xid", toplevel_xid,
+ "cookie", cookie,
+ NULL);
+
+ return inhibitor;
+}
+
+GsmInhibitor *
+gsm_inhibitor_new_for_client (const char *client_id,
+ const char *app_id,
+ guint flags,
+ const char *reason,
+ const char *bus_name,
+ guint cookie)
+{
+ GsmInhibitor *inhibitor;
+
+ inhibitor = g_object_new (GSM_TYPE_INHIBITOR,
+ "client-id", client_id,
+ "app-id", app_id,
+ "reason", reason,
+ "bus-name", bus_name,
+ "flags", flags,
+ "cookie", cookie,
+ NULL);
+
+ return inhibitor;
+}
diff --git a/mate-session/gsm-inhibitor.h b/mate-session/gsm-inhibitor.h
new file mode 100644
index 0000000..c4fc5b3
--- /dev/null
+++ b/mate-session/gsm-inhibitor.h
@@ -0,0 +1,120 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * 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
+ * Lesser 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_INHIBITOR_H__
+#define __GSM_INHIBITOR_H__
+
+#include <glib-object.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GSM_TYPE_INHIBITOR (gsm_inhibitor_get_type ())
+#define GSM_INHIBITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSM_TYPE_INHIBITOR, GsmInhibitor))
+#define GSM_INHIBITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSM_TYPE_INHIBITOR, GsmInhibitorClass))
+#define GSM_IS_INHIBITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSM_TYPE_INHIBITOR))
+#define GSM_IS_INHIBITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSM_TYPE_INHIBITOR))
+#define GSM_INHIBITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSM_TYPE_INHIBITOR, GsmInhibitorClass))
+
+typedef struct _GsmInhibitor GsmInhibitor;
+typedef struct _GsmInhibitorClass GsmInhibitorClass;
+
+typedef struct GsmInhibitorPrivate GsmInhibitorPrivate;
+
+struct _GsmInhibitor
+{
+ GObject parent;
+ GsmInhibitorPrivate *priv;
+};
+
+struct _GsmInhibitorClass
+{
+ GObjectClass parent_class;
+};
+
+typedef enum {
+ GSM_INHIBITOR_FLAG_LOGOUT = 1 << 0,
+ GSM_INHIBITOR_FLAG_SWITCH_USER = 1 << 1,
+ GSM_INHIBITOR_FLAG_SUSPEND = 1 << 2,
+ GSM_INHIBITOR_FLAG_IDLE = 1 << 3
+} GsmInhibitorFlag;
+
+typedef enum
+{
+ GSM_INHIBITOR_ERROR_GENERAL = 0,
+ GSM_INHIBITOR_ERROR_NOT_SET,
+ GSM_INHIBITOR_NUM_ERRORS
+} GsmInhibitorError;
+
+#define GSM_INHIBITOR_ERROR gsm_inhibitor_error_quark ()
+GType gsm_inhibitor_error_get_type (void);
+#define GSM_INHIBITOR_TYPE_ERROR (gsm_inhibitor_error_get_type ())
+
+GQuark gsm_inhibitor_error_quark (void);
+
+GType gsm_inhibitor_get_type (void) G_GNUC_CONST;
+
+GsmInhibitor * gsm_inhibitor_new (const char *app_id,
+ guint toplevel_xid,
+ guint flags,
+ const char *reason,
+ const char *bus_name,
+ guint cookie);
+GsmInhibitor * gsm_inhibitor_new_for_client (const char *client_id,
+ const char *app_id,
+ guint flags,
+ const char *reason,
+ const char *bus_name,
+ guint cookie);
+
+const char * gsm_inhibitor_peek_id (GsmInhibitor *inhibitor);
+const char * gsm_inhibitor_peek_app_id (GsmInhibitor *inhibitor);
+const char * gsm_inhibitor_peek_client_id (GsmInhibitor *inhibitor);
+const char * gsm_inhibitor_peek_reason (GsmInhibitor *inhibitor);
+const char * gsm_inhibitor_peek_bus_name (GsmInhibitor *inhibitor);
+guint gsm_inhibitor_peek_cookie (GsmInhibitor *inhibitor);
+guint gsm_inhibitor_peek_flags (GsmInhibitor *inhibitor);
+guint gsm_inhibitor_peek_toplevel_xid (GsmInhibitor *inhibitor);
+
+/* exported to bus */
+gboolean gsm_inhibitor_get_app_id (GsmInhibitor *inhibitor,
+ char **id,
+ GError **error);
+gboolean gsm_inhibitor_get_client_id (GsmInhibitor *inhibitor,
+ char **id,
+ GError **error);
+gboolean gsm_inhibitor_get_reason (GsmInhibitor *inhibitor,
+ char **reason,
+ GError **error);
+gboolean gsm_inhibitor_get_flags (GsmInhibitor *inhibitor,
+ guint *flags,
+ GError **error);
+gboolean gsm_inhibitor_get_toplevel_xid (GsmInhibitor *inhibitor,
+ guint *xid,
+ GError **error);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GSM_INHIBITOR_H__ */
diff --git a/mate-session/gsm-logout-dialog.c b/mate-session/gsm-logout-dialog.c
new file mode 100644
index 0000000..de606a4
--- /dev/null
+++ b/mate-session/gsm-logout-dialog.c
@@ -0,0 +1,461 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2006 Vincent Untz
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * 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.
+ *
+ * Authors:
+ * Vincent Untz <[email protected]>
+ */
+
+#include <config.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include <upower.h>
+
+#include "gsm-logout-dialog.h"
+#include "gsm-consolekit.h"
+#include "mdm.h"
+
+#define GSM_LOGOUT_DIALOG_GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_LOGOUT_DIALOG, GsmLogoutDialogPrivate))
+
+#define AUTOMATIC_ACTION_TIMEOUT 60
+
+#define GSM_ICON_LOGOUT "system-log-out"
+#define GSM_ICON_SHUTDOWN "system-shutdown"
+
+typedef enum {
+ GSM_DIALOG_LOGOUT_TYPE_LOGOUT,
+ GSM_DIALOG_LOGOUT_TYPE_SHUTDOWN
+} GsmDialogLogoutType;
+
+struct _GsmLogoutDialogPrivate
+{
+ GsmDialogLogoutType type;
+
+ UpClient *up_client;
+ GsmConsolekit *consolekit;
+
+ int timeout;
+ unsigned int timeout_id;
+
+ unsigned int default_response;
+};
+
+static GsmLogoutDialog *current_dialog = NULL;
+
+static void gsm_logout_dialog_set_timeout (GsmLogoutDialog *logout_dialog);
+
+static void gsm_logout_dialog_destroy (GsmLogoutDialog *logout_dialog,
+ gpointer data);
+
+static void gsm_logout_dialog_show (GsmLogoutDialog *logout_dialog,
+ gpointer data);
+
+enum {
+ PROP_0,
+ PROP_MESSAGE_TYPE
+};
+
+G_DEFINE_TYPE (GsmLogoutDialog, gsm_logout_dialog, GTK_TYPE_MESSAGE_DIALOG);
+
+static void
+gsm_logout_dialog_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id) {
+ case PROP_MESSAGE_TYPE:
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gsm_logout_dialog_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id) {
+ case PROP_MESSAGE_TYPE:
+ g_value_set_enum (value, GTK_MESSAGE_WARNING);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gsm_logout_dialog_class_init (GsmLogoutDialogClass *klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+
+ /* This is a workaround to avoid a stupid crash: libmateui
+ * listens for the "show" signal on all GtkMessageDialog and
+ * gets the "message-type" of the dialogs. We will crash when
+ * it accesses this property if we don't override it since we
+ * didn't define it. */
+ gobject_class->set_property = gsm_logout_dialog_set_property;
+ gobject_class->get_property = gsm_logout_dialog_get_property;
+
+ g_object_class_override_property (gobject_class,
+ PROP_MESSAGE_TYPE,
+ "message-type");
+
+ g_type_class_add_private (klass, sizeof (GsmLogoutDialogPrivate));
+}
+
+static void
+gsm_logout_dialog_init (GsmLogoutDialog *logout_dialog)
+{
+ logout_dialog->priv = GSM_LOGOUT_DIALOG_GET_PRIVATE (logout_dialog);
+
+ logout_dialog->priv->timeout_id = 0;
+ logout_dialog->priv->timeout = 0;
+ logout_dialog->priv->default_response = GTK_RESPONSE_CANCEL;
+
+ gtk_window_set_skip_taskbar_hint (GTK_WINDOW (logout_dialog), TRUE);
+ gtk_window_set_keep_above (GTK_WINDOW (logout_dialog), TRUE);
+ gtk_window_stick (GTK_WINDOW (logout_dialog));
+
+ logout_dialog->priv->up_client = up_client_new ();
+
+ logout_dialog->priv->consolekit = gsm_get_consolekit ();
+
+ g_signal_connect (logout_dialog,
+ "destroy",
+ G_CALLBACK (gsm_logout_dialog_destroy),
+ NULL);
+
+ g_signal_connect (logout_dialog,
+ "show",
+ G_CALLBACK (gsm_logout_dialog_show),
+ NULL);
+}
+
+static void
+gsm_logout_dialog_destroy (GsmLogoutDialog *logout_dialog,
+ gpointer data)
+{
+ if (logout_dialog->priv->timeout_id != 0) {
+ g_source_remove (logout_dialog->priv->timeout_id);
+ logout_dialog->priv->timeout_id = 0;
+ }
+
+ if (logout_dialog->priv->up_client) {
+ g_object_unref (logout_dialog->priv->up_client);
+ logout_dialog->priv->up_client = NULL;
+ }
+
+ if (logout_dialog->priv->consolekit) {
+ g_object_unref (logout_dialog->priv->consolekit);
+ logout_dialog->priv->consolekit = NULL;
+ }
+
+ current_dialog = NULL;
+}
+
+static gboolean
+gsm_logout_supports_system_suspend (GsmLogoutDialog *logout_dialog)
+{
+ return up_client_get_can_suspend (logout_dialog->priv->up_client);
+}
+
+static gboolean
+gsm_logout_supports_system_hibernate (GsmLogoutDialog *logout_dialog)
+{
+ return up_client_get_can_hibernate (logout_dialog->priv->up_client);
+}
+
+static gboolean
+gsm_logout_supports_switch_user (GsmLogoutDialog *logout_dialog)
+{
+ gboolean ret;
+
+ ret = gsm_consolekit_can_switch_user (logout_dialog->priv->consolekit);
+
+ return ret;
+}
+
+static gboolean
+gsm_logout_supports_reboot (GsmLogoutDialog *logout_dialog)
+{
+ gboolean ret;
+
+ ret = gsm_consolekit_can_restart (logout_dialog->priv->consolekit);
+ if (!ret) {
+ ret = mdm_supports_logout_action (MDM_LOGOUT_ACTION_REBOOT);
+ }
+
+ return ret;
+}
+
+static gboolean
+gsm_logout_supports_shutdown (GsmLogoutDialog *logout_dialog)
+{
+ gboolean ret;
+
+ ret = gsm_consolekit_can_stop (logout_dialog->priv->consolekit);
+
+ if (!ret) {
+ ret = mdm_supports_logout_action (MDM_LOGOUT_ACTION_SHUTDOWN);
+ }
+
+ return ret;
+}
+
+static void
+gsm_logout_dialog_show (GsmLogoutDialog *logout_dialog, gpointer user_data)
+{
+ gsm_logout_dialog_set_timeout (logout_dialog);
+}
+
+static gboolean
+gsm_logout_dialog_timeout (gpointer data)
+{
+ GsmLogoutDialog *logout_dialog;
+ char *seconds_warning;
+ char *secondary_text;
+ int seconds_to_show;
+ static char *session_type = NULL;
+
+ logout_dialog = (GsmLogoutDialog *) data;
+
+ if (!logout_dialog->priv->timeout) {
+ gtk_dialog_response (GTK_DIALOG (logout_dialog),
+ logout_dialog->priv->default_response);
+
+ return FALSE;
+ }
+
+ if (logout_dialog->priv->timeout <= 30) {
+ seconds_to_show = logout_dialog->priv->timeout;
+ } else {
+ seconds_to_show = (logout_dialog->priv->timeout/10) * 10;
+
+ if (logout_dialog->priv->timeout % 10)
+ seconds_to_show += 10;
+ }
+
+ switch (logout_dialog->priv->type) {
+ case GSM_DIALOG_LOGOUT_TYPE_LOGOUT:
+ seconds_warning = ngettext ("You will be automatically logged "
+ "out in %d second.",
+ "You will be automatically logged "
+ "out in %d seconds.",
+ seconds_to_show);
+ break;
+
+ case GSM_DIALOG_LOGOUT_TYPE_SHUTDOWN:
+ seconds_warning = ngettext ("This system will be automatically "
+ "shut down in %d second.",
+ "This system will be automatically "
+ "shut down in %d seconds.",
+ seconds_to_show);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ if (session_type == NULL) {
+ GsmConsolekit *consolekit;
+
+ consolekit = gsm_get_consolekit ();
+ session_type = gsm_consolekit_get_current_session_type (consolekit);
+ g_object_unref (consolekit);
+ }
+
+ if (g_strcmp0 (session_type, GSM_CONSOLEKIT_SESSION_TYPE_LOGIN_WINDOW) != 0) {
+ char *name, *tmp;
+
+ name = g_locale_to_utf8 (g_get_real_name (), -1, NULL, NULL, NULL);
+
+ if (!name || name[0] == '\0' || strcmp (name, "Unknown") == 0) {
+ name = g_locale_to_utf8 (g_get_user_name (), -1 , NULL, NULL, NULL);
+ }
+
+ if (!name) {
+ name = g_strdup (g_get_user_name ());
+ }
+
+ tmp = g_strdup_printf (_("You are currently logged in as \"%s\"."), name);
+ secondary_text = g_strconcat (tmp, "\n", seconds_warning, NULL);
+ g_free (tmp);
+
+ g_free (name);
+ } else {
+ secondary_text = g_strdup (seconds_warning);
+ }
+
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (logout_dialog),
+ secondary_text,
+ seconds_to_show,
+ NULL);
+
+ logout_dialog->priv->timeout--;
+
+ g_free (secondary_text);
+
+ return TRUE;
+}
+
+static void
+gsm_logout_dialog_set_timeout (GsmLogoutDialog *logout_dialog)
+{
+ logout_dialog->priv->timeout = AUTOMATIC_ACTION_TIMEOUT;
+
+ /* Sets the secondary text */
+ gsm_logout_dialog_timeout (logout_dialog);
+
+ if (logout_dialog->priv->timeout_id != 0) {
+ g_source_remove (logout_dialog->priv->timeout_id);
+ }
+
+ logout_dialog->priv->timeout_id = g_timeout_add (1000,
+ gsm_logout_dialog_timeout,
+ logout_dialog);
+}
+
+static GtkWidget *
+gsm_get_dialog (GsmDialogLogoutType type,
+ GdkScreen *screen,
+ guint32 activate_time)
+{
+ GsmLogoutDialog *logout_dialog;
+ GtkWidget *dialog_image;
+ const char *primary_text;
+ const char *icon_name;
+
+ if (current_dialog != NULL) {
+ gtk_widget_destroy (GTK_WIDGET (current_dialog));
+ }
+
+ logout_dialog = g_object_new (GSM_TYPE_LOGOUT_DIALOG, NULL);
+
+ current_dialog = logout_dialog;
+
+ gtk_window_set_title (GTK_WINDOW (logout_dialog), "");
+
+ logout_dialog->priv->type = type;
+
+ icon_name = NULL;
+ primary_text = NULL;
+
+ switch (type) {
+ case GSM_DIALOG_LOGOUT_TYPE_LOGOUT:
+ icon_name = GSM_ICON_LOGOUT;
+ primary_text = _("Log out of this system now?");
+
+ logout_dialog->priv->default_response = GSM_LOGOUT_RESPONSE_LOGOUT;
+
+ if (gsm_logout_supports_switch_user (logout_dialog)) {
+ gtk_dialog_add_button (GTK_DIALOG (logout_dialog),
+ _("_Switch User"),
+ GSM_LOGOUT_RESPONSE_SWITCH_USER);
+ }
+
+ gtk_dialog_add_button (GTK_DIALOG (logout_dialog),
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL);
+
+ gtk_dialog_add_button (GTK_DIALOG (logout_dialog),
+ _("_Log Out"),
+ GSM_LOGOUT_RESPONSE_LOGOUT);
+
+ break;
+ case GSM_DIALOG_LOGOUT_TYPE_SHUTDOWN:
+ icon_name = GSM_ICON_SHUTDOWN;
+ primary_text = _("Shut down this system now?");
+
+ logout_dialog->priv->default_response = GSM_LOGOUT_RESPONSE_SHUTDOWN;
+
+ if (gsm_logout_supports_system_suspend (logout_dialog)) {
+ gtk_dialog_add_button (GTK_DIALOG (logout_dialog),
+ _("S_uspend"),
+ GSM_LOGOUT_RESPONSE_SLEEP);
+ }
+
+ if (gsm_logout_supports_system_hibernate (logout_dialog)) {
+ gtk_dialog_add_button (GTK_DIALOG (logout_dialog),
+ _("_Hibernate"),
+ GSM_LOGOUT_RESPONSE_HIBERNATE);
+ }
+
+ if (gsm_logout_supports_reboot (logout_dialog)) {
+ gtk_dialog_add_button (GTK_DIALOG (logout_dialog),
+ _("_Restart"),
+ GSM_LOGOUT_RESPONSE_REBOOT);
+ }
+
+ gtk_dialog_add_button (GTK_DIALOG (logout_dialog),
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL);
+
+ if (gsm_logout_supports_shutdown (logout_dialog)) {
+ gtk_dialog_add_button (GTK_DIALOG (logout_dialog),
+ _("_Shut Down"),
+ GSM_LOGOUT_RESPONSE_SHUTDOWN);
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ dialog_image = gtk_message_dialog_get_image (GTK_MESSAGE_DIALOG (logout_dialog));
+
+ gtk_image_set_from_icon_name (GTK_IMAGE (dialog_image),
+ icon_name, GTK_ICON_SIZE_DIALOG);
+ gtk_window_set_icon_name (GTK_WINDOW (logout_dialog), icon_name);
+ gtk_window_set_position (GTK_WINDOW (logout_dialog), GTK_WIN_POS_CENTER_ALWAYS);
+ gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (logout_dialog), primary_text);
+
+ gtk_dialog_set_default_response (GTK_DIALOG (logout_dialog),
+ logout_dialog->priv->default_response);
+
+ gtk_window_set_screen (GTK_WINDOW (logout_dialog), screen);
+
+ return GTK_WIDGET (logout_dialog);
+}
+
+GtkWidget *
+gsm_get_shutdown_dialog (GdkScreen *screen,
+ guint32 activate_time)
+{
+ return gsm_get_dialog (GSM_DIALOG_LOGOUT_TYPE_SHUTDOWN,
+ screen,
+ activate_time);
+}
+
+GtkWidget *
+gsm_get_logout_dialog (GdkScreen *screen,
+ guint32 activate_time)
+{
+ return gsm_get_dialog (GSM_DIALOG_LOGOUT_TYPE_LOGOUT,
+ screen,
+ activate_time);
+}
diff --git a/mate-session/gsm-logout-dialog.h b/mate-session/gsm-logout-dialog.h
new file mode 100644
index 0000000..c3aad69
--- /dev/null
+++ b/mate-session/gsm-logout-dialog.h
@@ -0,0 +1,77 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2006 Vincent Untz
+ *
+ * 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.
+ *
+ * Authors:
+ * Vincent Untz <[email protected]>
+ */
+
+#ifndef __GSM_LOGOUT_DIALOG_H__
+#define __GSM_LOGOUT_DIALOG_H__
+
+#include <gtk/gtk.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum
+{
+ GSM_LOGOUT_RESPONSE_LOGOUT,
+ GSM_LOGOUT_RESPONSE_SWITCH_USER,
+ GSM_LOGOUT_RESPONSE_SHUTDOWN,
+ GSM_LOGOUT_RESPONSE_REBOOT,
+ GSM_LOGOUT_RESPONSE_HIBERNATE,
+ GSM_LOGOUT_RESPONSE_SLEEP
+};
+
+#define GSM_TYPE_LOGOUT_DIALOG (gsm_logout_dialog_get_type ())
+#define GSM_LOGOUT_DIALOG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSM_TYPE_LOGOUT_DIALOG, GsmLogoutDialog))
+#define GSM_LOGOUT_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GSM_TYPE_LOGOUT_DIALOG, GsmLogoutDialogClass))
+#define GSM_IS_LOGOUT_DIALOG(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSM_TYPE_LOGOUT_DIALOG))
+#define GSM_IS_LOGOUT_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSM_TYPE_LOGOUT_DIALOG))
+#define GSM_LOGOUT_DIALOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSM_TYPE_LOGOUT_DIALOG, GsmLogoutDialogClass))
+
+typedef struct _GsmLogoutDialog GsmLogoutDialog;
+typedef struct _GsmLogoutDialogClass GsmLogoutDialogClass;
+typedef struct _GsmLogoutDialogPrivate GsmLogoutDialogPrivate;
+
+struct _GsmLogoutDialog
+{
+ GtkMessageDialog parent;
+
+ GsmLogoutDialogPrivate *priv;
+};
+
+struct _GsmLogoutDialogClass
+{
+ GtkMessageDialogClass parent_class;
+};
+
+GType gsm_logout_dialog_get_type (void) G_GNUC_CONST;
+
+GtkWidget *gsm_get_logout_dialog (GdkScreen *screen,
+ guint32 activate_time);
+GtkWidget *gsm_get_shutdown_dialog (GdkScreen *screen,
+ guint32 activate_time);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GSM_LOGOUT_DIALOG_H__ */
diff --git a/mate-session/gsm-manager.c b/mate-session/gsm-manager.c
new file mode 100644
index 0000000..cbddf21
--- /dev/null
+++ b/mate-session/gsm-manager.c
@@ -0,0 +1,3481 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Novell, Inc.
+ * Copyright (C) 2008 Red Hat, Inc.
+ * Copyright (C) 2008 William Jon McCann <[email protected]>
+ *
+ * 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 <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <glib-object.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include <upower.h>
+
+#include <gtk/gtk.h> /* for logout dialog */
+#include <mateconf/mateconf-client.h>
+
+#include "gsm-manager.h"
+#include "gsm-manager-glue.h"
+
+#include "gsm-store.h"
+#include "gsm-inhibitor.h"
+#include "gsm-presence.h"
+
+#include "gsm-xsmp-client.h"
+#include "gsm-dbus-client.h"
+
+#include "gsm-autostart-app.h"
+
+#include "gsm-util.h"
+#include "mdm.h"
+#include "gsm-logout-dialog.h"
+#include "gsm-inhibit-dialog.h"
+#include "gsm-consolekit.h"
+#include "gsm-session-save.h"
+
+#define GSM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_MANAGER, GsmManagerPrivate))
+
+#define GSM_MANAGER_DBUS_PATH "/org/mate/SessionManager"
+#define GSM_MANAGER_DBUS_NAME "org.mate.SessionManager"
+
+#define GSM_MANAGER_PHASE_TIMEOUT 10 /* seconds */
+
+#define MDM_FLEXISERVER_COMMAND "mdmflexiserver"
+#define MDM_FLEXISERVER_ARGS "--startnew Standard"
+
+
+#define KEY_LOCKDOWN_DIR "/desktop/mate/lockdown"
+#define KEY_LOCK_DISABLE KEY_LOCKDOWN_DIR "/disable_lock_screen"
+#define KEY_USER_SWITCH_DISABLE KEY_LOCKDOWN_DIR "/disable_user_switching"
+
+#define KEY_DESKTOP_DIR "/desktop/mate/session"
+#define KEY_IDLE_DELAY KEY_DESKTOP_DIR "/idle_delay"
+
+#define KEY_MATE_SESSION_DIR "/apps/mate-session/options"
+#define KEY_AUTOSAVE KEY_MATE_SESSION_DIR "/auto_save_session"
+
+#define KEY_SLEEP_LOCK "/apps/mate-screensaver/lock_enabled"
+
+#define IS_STRING_EMPTY(x) ((x)==NULL||(x)[0]=='\0')
+
+typedef enum
+{
+ GSM_MANAGER_LOGOUT_NONE,
+ GSM_MANAGER_LOGOUT_LOGOUT,
+ GSM_MANAGER_LOGOUT_REBOOT,
+ GSM_MANAGER_LOGOUT_REBOOT_INTERACT,
+ GSM_MANAGER_LOGOUT_REBOOT_MDM,
+ GSM_MANAGER_LOGOUT_SHUTDOWN,
+ GSM_MANAGER_LOGOUT_SHUTDOWN_INTERACT,
+ GSM_MANAGER_LOGOUT_SHUTDOWN_MDM
+} GsmManagerLogoutType;
+
+struct GsmManagerPrivate
+{
+ gboolean failsafe;
+ GsmStore *clients;
+ GsmStore *inhibitors;
+ GsmStore *apps;
+ GsmPresence *presence;
+
+ /* Current status */
+ GsmManagerPhase phase;
+ guint phase_timeout_id;
+ GSList *pending_apps;
+ gboolean forceful_logout;
+ GSList *query_clients;
+ guint query_timeout_id;
+ /* This is used for GSM_MANAGER_PHASE_END_SESSION only at the moment,
+ * since it uses a sublist of all running client that replied in a
+ * specific way */
+ GSList *next_query_clients;
+ /* This is the action that will be done just before we exit */
+ GsmManagerLogoutType logout_type;
+
+ GtkWidget *inhibit_dialog;
+
+ /* List of clients which were disconnected due to disabled condition
+ * and shouldn't be automatically restarted */
+ GSList *condition_clients;
+
+ MateConfClient *mateconf_client;
+ guint desktop_notify_id;
+ guint lockdown_notify_id;
+
+ DBusGProxy *bus_proxy;
+ DBusGConnection *connection;
+
+ /* Interface with other parts of the system */
+ UpClient *up_client;
+};
+
+enum {
+ PROP_0,
+ PROP_CLIENT_STORE,
+ PROP_FAILSAFE
+};
+
+enum {
+ PHASE_CHANGED,
+ CLIENT_ADDED,
+ CLIENT_REMOVED,
+ INHIBITOR_ADDED,
+ INHIBITOR_REMOVED,
+ SESSION_RUNNING,
+ SESSION_OVER,
+ LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0 };
+
+static void gsm_manager_class_init (GsmManagerClass *klass);
+static void gsm_manager_init (GsmManager *manager);
+static void gsm_manager_finalize (GObject *object);
+
+static gboolean auto_save_is_enabled (GsmManager *manager);
+static void maybe_save_session (GsmManager *manager);
+
+static gpointer manager_object = NULL;
+
+G_DEFINE_TYPE (GsmManager, gsm_manager, G_TYPE_OBJECT)
+
+GQuark
+gsm_manager_error_quark (void)
+{
+ static GQuark ret = 0;
+ if (ret == 0) {
+ ret = g_quark_from_static_string ("gsm_manager_error");
+ }
+
+ return ret;
+}
+
+#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
+
+GType
+gsm_manager_error_get_type (void)
+{
+ static GType etype = 0;
+
+ if (etype == 0) {
+ static const GEnumValue values[] = {
+ ENUM_ENTRY (GSM_MANAGER_ERROR_GENERAL, "GeneralError"),
+ ENUM_ENTRY (GSM_MANAGER_ERROR_NOT_IN_INITIALIZATION, "NotInInitialization"),
+ ENUM_ENTRY (GSM_MANAGER_ERROR_NOT_IN_RUNNING, "NotInRunning"),
+ ENUM_ENTRY (GSM_MANAGER_ERROR_ALREADY_REGISTERED, "AlreadyRegistered"),
+ ENUM_ENTRY (GSM_MANAGER_ERROR_NOT_REGISTERED, "NotRegistered"),
+ ENUM_ENTRY (GSM_MANAGER_ERROR_INVALID_OPTION, "InvalidOption"),
+ { 0, 0, 0 }
+ };
+
+ g_assert (GSM_MANAGER_NUM_ERRORS == G_N_ELEMENTS (values) - 1);
+
+ etype = g_enum_register_static ("GsmManagerError", values);
+ }
+
+ return etype;
+}
+
+static gboolean
+_debug_client (const char *id,
+ GsmClient *client,
+ GsmManager *manager)
+{
+ g_debug ("GsmManager: Client %s", gsm_client_peek_id (client));
+ return FALSE;
+}
+
+static void
+debug_clients (GsmManager *manager)
+{
+ gsm_store_foreach (manager->priv->clients,
+ (GsmStoreFunc)_debug_client,
+ manager);
+}
+
+static gboolean
+_debug_inhibitor (const char *id,
+ GsmInhibitor *inhibitor,
+ GsmManager *manager)
+{
+ g_debug ("GsmManager: Inhibitor app:%s client:%s bus-name:%s reason:%s",
+ gsm_inhibitor_peek_app_id (inhibitor),
+ gsm_inhibitor_peek_client_id (inhibitor),
+ gsm_inhibitor_peek_bus_name (inhibitor),
+ gsm_inhibitor_peek_reason (inhibitor));
+ return FALSE;
+}
+
+static void
+debug_inhibitors (GsmManager *manager)
+{
+ gsm_store_foreach (manager->priv->inhibitors,
+ (GsmStoreFunc)_debug_inhibitor,
+ manager);
+}
+
+static gboolean
+_find_by_cookie (const char *id,
+ GsmInhibitor *inhibitor,
+ guint *cookie_ap)
+{
+ guint cookie_b;
+
+ cookie_b = gsm_inhibitor_peek_cookie (inhibitor);
+
+ return (*cookie_ap == cookie_b);
+}
+
+static gboolean
+_find_by_startup_id (const char *id,
+ GsmClient *client,
+ const char *startup_id_a)
+{
+ const char *startup_id_b;
+
+ startup_id_b = gsm_client_peek_startup_id (client);
+ if (IS_STRING_EMPTY (startup_id_b)) {
+ return FALSE;
+ }
+
+ return (strcmp (startup_id_a, startup_id_b) == 0);
+}
+
+static void
+app_condition_changed (GsmApp *app,
+ gboolean condition,
+ GsmManager *manager)
+{
+ GsmClient *client;
+
+ g_debug ("GsmManager: app:%s condition changed condition:%d",
+ gsm_app_peek_id (app),
+ condition);
+
+ client = (GsmClient *)gsm_store_find (manager->priv->clients,
+ (GsmStoreFunc)_find_by_startup_id,
+ (char *)gsm_app_peek_startup_id (app));
+
+ if (condition) {
+ if (!gsm_app_is_running (app) && client == NULL) {
+ GError *error;
+ gboolean res;
+
+ g_debug ("GsmManager: starting app '%s'", gsm_app_peek_id (app));
+
+ error = NULL;
+ res = gsm_app_start (app, &error);
+ if (error != NULL) {
+ g_warning ("Not able to start app from its condition: %s",
+ error->message);
+ g_error_free (error);
+ }
+ } else {
+ g_debug ("GsmManager: not starting - app still running '%s'", gsm_app_peek_id (app));
+ }
+ } else {
+ GError *error;
+ gboolean res;
+
+ if (client != NULL) {
+ /* Kill client in case condition if false and make sure it won't
+ * be automatically restarted by adding the client to
+ * condition_clients */
+ manager->priv->condition_clients =
+ g_slist_prepend (manager->priv->condition_clients, client);
+
+ g_debug ("GsmManager: stopping client %s for app", gsm_client_peek_id (client));
+
+ error = NULL;
+ res = gsm_client_stop (client, &error);
+ if (error != NULL) {
+ g_warning ("Not able to stop app client from its condition: %s",
+ error->message);
+ g_error_free (error);
+ }
+ } else {
+ g_debug ("GsmManager: stopping app %s", gsm_app_peek_id (app));
+
+ /* If we don't have a client then we should try to kill the app */
+ error = NULL;
+ res = gsm_app_stop (app, &error);
+ if (error != NULL) {
+ g_warning ("Not able to stop app from its condition: %s",
+ error->message);
+ g_error_free (error);
+ }
+ }
+ }
+}
+
+static const char *
+phase_num_to_name (guint phase)
+{
+ const char *name;
+
+ switch (phase) {
+ case GSM_MANAGER_PHASE_STARTUP:
+ name = "STARTUP";
+ break;
+ case GSM_MANAGER_PHASE_INITIALIZATION:
+ name = "INITIALIZATION";
+ break;
+ case GSM_MANAGER_PHASE_WINDOW_MANAGER:
+ name = "WINDOW_MANAGER";
+ break;
+ case GSM_MANAGER_PHASE_PANEL:
+ name = "PANEL";
+ break;
+ case GSM_MANAGER_PHASE_DESKTOP:
+ name = "DESKTOP";
+ break;
+ case GSM_MANAGER_PHASE_APPLICATION:
+ name = "APPLICATION";
+ break;
+ case GSM_MANAGER_PHASE_RUNNING:
+ name = "RUNNING";
+ break;
+ case GSM_MANAGER_PHASE_QUERY_END_SESSION:
+ name = "QUERY_END_SESSION";
+ break;
+ case GSM_MANAGER_PHASE_END_SESSION:
+ name = "END_SESSION";
+ break;
+ case GSM_MANAGER_PHASE_EXIT:
+ name = "EXIT";
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ return name;
+}
+
+static void start_phase (GsmManager *manager);
+
+static void
+quit_request_completed (GsmConsolekit *consolekit,
+ GError *error,
+ gpointer user_data)
+{
+ MdmLogoutAction fallback_action = GPOINTER_TO_INT (user_data);
+
+ if (error != NULL) {
+ mdm_set_logout_action (fallback_action);
+ }
+
+ g_object_unref (consolekit);
+
+ gtk_main_quit ();
+}
+
+static void
+gsm_manager_quit (GsmManager *manager)
+{
+ GsmConsolekit *consolekit;
+
+ /* See the comment in request_reboot() for some more details about how
+ * this works. */
+
+ switch (manager->priv->logout_type) {
+ case GSM_MANAGER_LOGOUT_LOGOUT:
+ gtk_main_quit ();
+ break;
+ case GSM_MANAGER_LOGOUT_REBOOT:
+ case GSM_MANAGER_LOGOUT_REBOOT_INTERACT:
+ mdm_set_logout_action (MDM_LOGOUT_ACTION_NONE);
+
+ consolekit = gsm_get_consolekit ();
+ g_signal_connect (consolekit,
+ "request-completed",
+ G_CALLBACK (quit_request_completed),
+ GINT_TO_POINTER (MDM_LOGOUT_ACTION_REBOOT));
+ gsm_consolekit_attempt_restart (consolekit);
+ break;
+ case GSM_MANAGER_LOGOUT_REBOOT_MDM:
+ mdm_set_logout_action (MDM_LOGOUT_ACTION_REBOOT);
+ gtk_main_quit ();
+ break;
+ case GSM_MANAGER_LOGOUT_SHUTDOWN:
+ case GSM_MANAGER_LOGOUT_SHUTDOWN_INTERACT:
+ mdm_set_logout_action (MDM_LOGOUT_ACTION_NONE);
+
+ consolekit = gsm_get_consolekit ();
+ g_signal_connect (consolekit,
+ "request-completed",
+ G_CALLBACK (quit_request_completed),
+ GINT_TO_POINTER (MDM_LOGOUT_ACTION_SHUTDOWN));
+ gsm_consolekit_attempt_stop (consolekit);
+ break;
+ case GSM_MANAGER_LOGOUT_SHUTDOWN_MDM:
+ mdm_set_logout_action (MDM_LOGOUT_ACTION_SHUTDOWN);
+ gtk_main_quit ();
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+static void
+end_phase (GsmManager *manager)
+{
+ g_debug ("GsmManager: ending phase %s\n",
+ phase_num_to_name (manager->priv->phase));
+
+ g_slist_free (manager->priv->pending_apps);
+ manager->priv->pending_apps = NULL;
+
+ g_slist_free (manager->priv->query_clients);
+ manager->priv->query_clients = NULL;
+
+ g_slist_free (manager->priv->next_query_clients);
+ manager->priv->next_query_clients = NULL;
+
+ if (manager->priv->phase_timeout_id > 0) {
+ g_source_remove (manager->priv->phase_timeout_id);
+ manager->priv->phase_timeout_id = 0;
+ }
+
+ switch (manager->priv->phase) {
+ case GSM_MANAGER_PHASE_STARTUP:
+ case GSM_MANAGER_PHASE_INITIALIZATION:
+ case GSM_MANAGER_PHASE_WINDOW_MANAGER:
+ case GSM_MANAGER_PHASE_PANEL:
+ case GSM_MANAGER_PHASE_DESKTOP:
+ case GSM_MANAGER_PHASE_APPLICATION:
+ case GSM_MANAGER_PHASE_RUNNING:
+ case GSM_MANAGER_PHASE_QUERY_END_SESSION:
+ manager->priv->phase++;
+ start_phase (manager);
+ break;
+ case GSM_MANAGER_PHASE_END_SESSION:
+ if (auto_save_is_enabled (manager)) {
+ maybe_save_session (manager);
+ }
+ manager->priv->phase++;
+ start_phase (manager);
+ break;
+ case GSM_MANAGER_PHASE_EXIT:
+ gsm_manager_quit (manager);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+static void
+app_registered (GsmApp *app,
+ GsmManager *manager)
+{
+ manager->priv->pending_apps = g_slist_remove (manager->priv->pending_apps, app);
+ g_signal_handlers_disconnect_by_func (app, app_registered, manager);
+
+ if (manager->priv->pending_apps == NULL) {
+ if (manager->priv->phase_timeout_id > 0) {
+ g_source_remove (manager->priv->phase_timeout_id);
+ manager->priv->phase_timeout_id = 0;
+ }
+
+ end_phase (manager);
+ }
+}
+
+static gboolean
+_client_failed_to_stop (const char *id,
+ GsmClient *client,
+ gpointer user_data)
+{
+ g_debug ("GsmManager: client failed to stop: %s, %s", gsm_client_peek_id (client), gsm_client_peek_app_id (client));
+ return FALSE;
+}
+
+static gboolean
+on_phase_timeout (GsmManager *manager)
+{
+ GSList *a;
+
+ manager->priv->phase_timeout_id = 0;
+
+ switch (manager->priv->phase) {
+ case GSM_MANAGER_PHASE_STARTUP:
+ case GSM_MANAGER_PHASE_INITIALIZATION:
+ case GSM_MANAGER_PHASE_WINDOW_MANAGER:
+ case GSM_MANAGER_PHASE_PANEL:
+ case GSM_MANAGER_PHASE_DESKTOP:
+ case GSM_MANAGER_PHASE_APPLICATION:
+ for (a = manager->priv->pending_apps; a; a = a->next) {
+ g_warning ("Application '%s' failed to register before timeout",
+ gsm_app_peek_app_id (a->data));
+ g_signal_handlers_disconnect_by_func (a->data, app_registered, manager);
+ /* FIXME: what if the app was filling in a required slot? */
+ }
+ break;
+ case GSM_MANAGER_PHASE_RUNNING:
+ break;
+ case GSM_MANAGER_PHASE_QUERY_END_SESSION:
+ case GSM_MANAGER_PHASE_END_SESSION:
+ break;
+ case GSM_MANAGER_PHASE_EXIT:
+ gsm_store_foreach (manager->priv->clients,
+ (GsmStoreFunc)_client_failed_to_stop,
+ NULL);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ end_phase (manager);
+
+ return FALSE;
+}
+
+static gboolean
+_start_app (const char *id,
+ GsmApp *app,
+ GsmManager *manager)
+{
+ GError *error;
+ gboolean res;
+
+ if (gsm_app_peek_phase (app) != manager->priv->phase) {
+ goto out;
+ }
+
+ /* Keep track of app autostart condition in order to react
+ * accordingly in the future. */
+ g_signal_connect (app,
+ "condition-changed",
+ G_CALLBACK (app_condition_changed),
+ manager);
+
+ if (gsm_app_peek_is_disabled (app)
+ || gsm_app_peek_is_conditionally_disabled (app)) {
+ g_debug ("GsmManager: Skipping disabled app: %s", id);
+ goto out;
+ }
+
+ error = NULL;
+ res = gsm_app_start (app, &error);
+ if (!res) {
+ if (error != NULL) {
+ g_warning ("Could not launch application '%s': %s",
+ gsm_app_peek_app_id (app),
+ error->message);
+ g_error_free (error);
+ error = NULL;
+ }
+ goto out;
+ }
+
+ if (manager->priv->phase < GSM_MANAGER_PHASE_APPLICATION) {
+ g_signal_connect (app,
+ "exited",
+ G_CALLBACK (app_registered),
+ manager);
+ g_signal_connect (app,
+ "registered",
+ G_CALLBACK (app_registered),
+ manager);
+ manager->priv->pending_apps = g_slist_prepend (manager->priv->pending_apps, app);
+ }
+ out:
+ return FALSE;
+}
+
+static void
+do_phase_startup (GsmManager *manager)
+{
+ gsm_store_foreach (manager->priv->apps,
+ (GsmStoreFunc)_start_app,
+ manager);
+
+ if (manager->priv->pending_apps != NULL) {
+ if (manager->priv->phase < GSM_MANAGER_PHASE_APPLICATION) {
+ manager->priv->phase_timeout_id = g_timeout_add_seconds (GSM_MANAGER_PHASE_TIMEOUT,
+ (GSourceFunc)on_phase_timeout,
+ manager);
+ }
+ } else {
+ end_phase (manager);
+ }
+}
+
+typedef struct {
+ GsmManager *manager;
+ guint flags;
+} ClientEndSessionData;
+
+
+static gboolean
+_client_end_session (GsmClient *client,
+ ClientEndSessionData *data)
+{
+ gboolean ret;
+ GError *error;
+
+ error = NULL;
+ ret = gsm_client_end_session (client, data->flags, &error);
+ if (! ret) {
+ g_warning ("Unable to query client: %s", error->message);
+ g_error_free (error);
+ /* FIXME: what should we do if we can't communicate with client? */
+ } else {
+ g_debug ("GsmManager: adding client to end-session clients: %s", gsm_client_peek_id (client));
+ data->manager->priv->query_clients = g_slist_prepend (data->manager->priv->query_clients,
+ client);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+_client_end_session_helper (const char *id,
+ GsmClient *client,
+ ClientEndSessionData *data)
+{
+ return _client_end_session (client, data);
+}
+
+static void
+do_phase_end_session (GsmManager *manager)
+{
+ ClientEndSessionData data;
+
+ data.manager = manager;
+ data.flags = 0;
+
+ if (manager->priv->forceful_logout) {
+ data.flags |= GSM_CLIENT_END_SESSION_FLAG_FORCEFUL;
+ }
+ if (auto_save_is_enabled (manager)) {
+ data.flags |= GSM_CLIENT_END_SESSION_FLAG_SAVE;
+ }
+
+ if (manager->priv->phase_timeout_id > 0) {
+ g_source_remove (manager->priv->phase_timeout_id);
+ manager->priv->phase_timeout_id = 0;
+ }
+
+ if (gsm_store_size (manager->priv->clients) > 0) {
+ manager->priv->phase_timeout_id = g_timeout_add_seconds (GSM_MANAGER_PHASE_TIMEOUT,
+ (GSourceFunc)on_phase_timeout,
+ manager);
+
+ gsm_store_foreach (manager->priv->clients,
+ (GsmStoreFunc)_client_end_session_helper,
+ &data);
+ } else {
+ end_phase (manager);
+ }
+}
+
+static void
+do_phase_end_session_part_2 (GsmManager *manager)
+{
+ ClientEndSessionData data;
+
+ data.manager = manager;
+ data.flags = 0;
+
+ if (manager->priv->forceful_logout) {
+ data.flags |= GSM_CLIENT_END_SESSION_FLAG_FORCEFUL;
+ }
+ if (auto_save_is_enabled (manager)) {
+ data.flags |= GSM_CLIENT_END_SESSION_FLAG_SAVE;
+ }
+ data.flags |= GSM_CLIENT_END_SESSION_FLAG_LAST;
+
+ /* keep the timeout that was started at the beginning of the
+ * GSM_MANAGER_PHASE_END_SESSION phase */
+
+ if (g_slist_length (manager->priv->next_query_clients) > 0) {
+ g_slist_foreach (manager->priv->next_query_clients,
+ (GFunc)_client_end_session,
+ &data);
+
+ g_slist_free (manager->priv->next_query_clients);
+ manager->priv->next_query_clients = NULL;
+ } else {
+ end_phase (manager);
+ }
+}
+
+static gboolean
+_client_stop (const char *id,
+ GsmClient *client,
+ gpointer user_data)
+{
+ gboolean ret;
+ GError *error;
+
+ error = NULL;
+ ret = gsm_client_stop (client, &error);
+ if (! ret) {
+ g_warning ("Unable to stop client: %s", error->message);
+ g_error_free (error);
+ /* FIXME: what should we do if we can't communicate with client? */
+ } else {
+ g_debug ("GsmManager: stopped client: %s", gsm_client_peek_id (client));
+ }
+
+ return FALSE;
+}
+
+static void
+do_phase_exit (GsmManager *manager)
+{
+ if (gsm_store_size (manager->priv->clients) > 0) {
+ manager->priv->phase_timeout_id = g_timeout_add_seconds (GSM_MANAGER_PHASE_TIMEOUT,
+ (GSourceFunc)on_phase_timeout,
+ manager);
+
+ gsm_store_foreach (manager->priv->clients,
+ (GsmStoreFunc)_client_stop,
+ NULL);
+ } else {
+ end_phase (manager);
+ }
+}
+
+static gboolean
+_client_query_end_session (const char *id,
+ GsmClient *client,
+ ClientEndSessionData *data)
+{
+ gboolean ret;
+ GError *error;
+
+ error = NULL;
+ ret = gsm_client_query_end_session (client, data->flags, &error);
+ if (! ret) {
+ g_warning ("Unable to query client: %s", error->message);
+ g_error_free (error);
+ /* FIXME: what should we do if we can't communicate with client? */
+ } else {
+ g_debug ("GsmManager: adding client to query clients: %s", gsm_client_peek_id (client));
+ data->manager->priv->query_clients = g_slist_prepend (data->manager->priv->query_clients,
+ client);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+inhibitor_has_flag (gpointer key,
+ GsmInhibitor *inhibitor,
+ gpointer data)
+{
+ guint flag;
+ guint flags;
+
+ flag = GPOINTER_TO_UINT (data);
+
+ flags = gsm_inhibitor_peek_flags (inhibitor);
+
+ return (flags & flag);
+}
+
+static gboolean
+gsm_manager_is_logout_inhibited (GsmManager *manager)
+{
+ GsmInhibitor *inhibitor;
+
+ if (manager->priv->inhibitors == NULL) {
+ return FALSE;
+ }
+
+ inhibitor = (GsmInhibitor *)gsm_store_find (manager->priv->inhibitors,
+ (GsmStoreFunc)inhibitor_has_flag,
+ GUINT_TO_POINTER (GSM_INHIBITOR_FLAG_LOGOUT));
+ if (inhibitor == NULL) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+gsm_manager_is_idle_inhibited (GsmManager *manager)
+{
+ GsmInhibitor *inhibitor;
+
+ if (manager->priv->inhibitors == NULL) {
+ return FALSE;
+ }
+
+ inhibitor = (GsmInhibitor *)gsm_store_find (manager->priv->inhibitors,
+ (GsmStoreFunc)inhibitor_has_flag,
+ GUINT_TO_POINTER (GSM_INHIBITOR_FLAG_IDLE));
+ if (inhibitor == NULL) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+_client_cancel_end_session (const char *id,
+ GsmClient *client,
+ GsmManager *manager)
+{
+ gboolean res;
+ GError *error;
+
+ error = NULL;
+ res = gsm_client_cancel_end_session (client, &error);
+ if (! res) {
+ g_warning ("Unable to cancel end session: %s", error->message);
+ g_error_free (error);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+inhibitor_is_jit (gpointer key,
+ GsmInhibitor *inhibitor,
+ GsmManager *manager)
+{
+ gboolean matches;
+ const char *id;
+
+ id = gsm_inhibitor_peek_client_id (inhibitor);
+
+ matches = (id != NULL && id[0] != '\0');
+
+ return matches;
+}
+
+static void
+cancel_end_session (GsmManager *manager)
+{
+ /* just ignore if received outside of shutdown */
+ if (manager->priv->phase < GSM_MANAGER_PHASE_QUERY_END_SESSION) {
+ return;
+ }
+
+ /* switch back to running phase */
+ g_debug ("GsmManager: Cancelling the end of session");
+
+ /* remove the dialog before we remove the inhibitors, else the dialog
+ * will activate itself automatically when the last inhibitor will be
+ * removed */
+ if (manager->priv->inhibit_dialog)
+ gtk_widget_destroy (GTK_WIDGET (manager->priv->inhibit_dialog));
+ manager->priv->inhibit_dialog = NULL;
+
+ /* clear all JIT inhibitors */
+ gsm_store_foreach_remove (manager->priv->inhibitors,
+ (GsmStoreFunc)inhibitor_is_jit,
+ (gpointer)manager);
+
+ gsm_store_foreach (manager->priv->clients,
+ (GsmStoreFunc)_client_cancel_end_session,
+ NULL);
+
+ gsm_manager_set_phase (manager, GSM_MANAGER_PHASE_RUNNING);
+ manager->priv->forceful_logout = FALSE;
+
+ manager->priv->logout_type = GSM_MANAGER_LOGOUT_NONE;
+ mdm_set_logout_action (MDM_LOGOUT_ACTION_NONE);
+
+ start_phase (manager);
+}
+
+
+static void
+manager_switch_user (GsmManager *manager)
+{
+ GError *error;
+ gboolean res;
+ char *command;
+
+ command = g_strdup_printf ("%s %s",
+ MDM_FLEXISERVER_COMMAND,
+ MDM_FLEXISERVER_ARGS);
+
+ error = NULL;
+ res = gdk_spawn_command_line_on_screen (gdk_screen_get_default (),
+ command,
+ &error);
+
+ g_free (command);
+
+ if (! res) {
+ g_debug ("GsmManager: Unable to start MDM greeter: %s", error->message);
+ g_error_free (error);
+ }
+}
+
+static gboolean
+sleep_lock_is_enabled (GsmManager *manager)
+{
+ GError *error;
+ gboolean enable_lock;
+
+ error = NULL;
+ enable_lock = mateconf_client_get_bool (manager->priv->mateconf_client,
+ KEY_SLEEP_LOCK, &error);
+
+ if (error) {
+ g_warning ("Error retrieving configuration key '%s': %s",
+ KEY_SLEEP_LOCK, error->message);
+ g_error_free (error);
+
+ /* If we fail to query mateconf key, just enable locking */
+ enable_lock = TRUE;
+ }
+
+ return enable_lock;
+}
+
+static void
+manager_perhaps_lock (GsmManager *manager)
+{
+ GError *error;
+ gboolean ret;
+
+ /* only lock if mate-screensaver is set to lock */
+ if (!sleep_lock_is_enabled (manager)) {
+ return;
+ }
+
+ /* do this sync to ensure it's on the screen when we start suspending */
+ error = NULL;
+ ret = g_spawn_command_line_sync ("mate-screensaver-command --lock", NULL, NULL, NULL, &error);
+ if (!ret) {
+ g_warning ("Couldn't lock screen: %s", error->message);
+ g_error_free (error);
+ }
+}
+
+static void
+manager_attempt_hibernate (GsmManager *manager)
+{
+ gboolean can_hibernate;
+ GError *error;
+ gboolean ret;
+
+ can_hibernate = up_client_get_can_hibernate (manager->priv->up_client);
+ if (can_hibernate) {
+
+ /* lock the screen before we suspend */
+ manager_perhaps_lock (manager);
+
+ error = NULL;
+ ret = up_client_hibernate_sync (manager->priv->up_client, NULL, &error);
+ if (!ret) {
+ g_warning ("Unexpected hibernate failure: %s",
+ error->message);
+ g_error_free (error);
+ }
+ }
+}
+
+static void
+manager_attempt_suspend (GsmManager *manager)
+{
+ gboolean can_suspend;
+ GError *error;
+ gboolean ret;
+
+ can_suspend = up_client_get_can_suspend (manager->priv->up_client);
+ if (can_suspend) {
+
+ /* lock the screen before we suspend */
+ manager_perhaps_lock (manager);
+
+ error = NULL;
+ ret = up_client_suspend_sync (manager->priv->up_client, NULL, &error);
+ if (!ret) {
+ g_warning ("Unexpected suspend failure: %s",
+ error->message);
+ g_error_free (error);
+ }
+ }
+}
+
+static void
+do_inhibit_dialog_action (GsmManager *manager,
+ int action)
+{
+ switch (action) {
+ case GSM_LOGOUT_ACTION_SWITCH_USER:
+ manager_switch_user (manager);
+ break;
+ case GSM_LOGOUT_ACTION_HIBERNATE:
+ manager_attempt_hibernate (manager);
+ break;
+ case GSM_LOGOUT_ACTION_SLEEP:
+ manager_attempt_suspend (manager);
+ break;
+ case GSM_LOGOUT_ACTION_SHUTDOWN:
+ case GSM_LOGOUT_ACTION_REBOOT:
+ case GSM_LOGOUT_ACTION_LOGOUT:
+ manager->priv->forceful_logout = TRUE;
+ end_phase (manager);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+static void
+inhibit_dialog_response (GsmInhibitDialog *dialog,
+ guint response_id,
+ GsmManager *manager)
+{
+ int action;
+
+ g_debug ("GsmManager: Inhibit dialog response: %d", response_id);
+
+ /* must destroy dialog before cancelling since we'll
+ remove JIT inhibitors and we don't want to trigger
+ action. */
+ g_object_get (dialog, "action", &action, NULL);
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ manager->priv->inhibit_dialog = NULL;
+
+ /* In case of dialog cancel, switch user, hibernate and
+ * suspend, we just perform the respective action and return,
+ * without shutting down the session. */
+ 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) {
+ cancel_end_session (manager);
+ }
+ break;
+ case GTK_RESPONSE_ACCEPT:
+ g_debug ("GsmManager: doing action %d", action);
+ do_inhibit_dialog_action (manager, action);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+static void
+query_end_session_complete (GsmManager *manager)
+{
+ GsmLogoutAction action;
+
+ g_debug ("GsmManager: query end session complete");
+
+ /* Remove the timeout since this can be called from outside the timer
+ * and we don't want to have it called twice */
+ if (manager->priv->query_timeout_id > 0) {
+ g_source_remove (manager->priv->query_timeout_id);
+ manager->priv->query_timeout_id = 0;
+ }
+
+ if (! gsm_manager_is_logout_inhibited (manager)) {
+ end_phase (manager);
+ return;
+ }
+
+ if (manager->priv->inhibit_dialog != NULL) {
+ g_debug ("GsmManager: inhibit dialog already up");
+ gtk_window_present (GTK_WINDOW (manager->priv->inhibit_dialog));
+ return;
+ }
+
+ switch (manager->priv->logout_type) {
+ case GSM_MANAGER_LOGOUT_LOGOUT:
+ action = GSM_LOGOUT_ACTION_LOGOUT;
+ break;
+ case GSM_MANAGER_LOGOUT_REBOOT:
+ case GSM_MANAGER_LOGOUT_REBOOT_INTERACT:
+ case GSM_MANAGER_LOGOUT_REBOOT_MDM:
+ action = GSM_LOGOUT_ACTION_REBOOT;
+ break;
+ case GSM_MANAGER_LOGOUT_SHUTDOWN:
+ case GSM_MANAGER_LOGOUT_SHUTDOWN_INTERACT:
+ case GSM_MANAGER_LOGOUT_SHUTDOWN_MDM:
+ action = GSM_LOGOUT_ACTION_SHUTDOWN;
+ break;
+ default:
+ g_warning ("Unexpected logout type %d when creating inhibit dialog",
+ manager->priv->logout_type);
+ action = GSM_LOGOUT_ACTION_LOGOUT;
+ break;
+ }
+
+ /* Note: GSM_LOGOUT_ACTION_SHUTDOWN and GSM_LOGOUT_ACTION_REBOOT are
+ * actually handled the same way as GSM_LOGOUT_ACTION_LOGOUT in the
+ * inhibit dialog; the action, if the button is clicked, will be to
+ * simply go to the next phase. */
+ manager->priv->inhibit_dialog = gsm_inhibit_dialog_new (manager->priv->inhibitors,
+ manager->priv->clients,
+ action);
+
+ g_signal_connect (manager->priv->inhibit_dialog,
+ "response",
+ G_CALLBACK (inhibit_dialog_response),
+ manager);
+ gtk_widget_show (manager->priv->inhibit_dialog);
+
+}
+
+static guint32
+generate_cookie (void)
+{
+ guint32 cookie;
+
+ cookie = (guint32)g_random_int_range (1, G_MAXINT32);
+
+ return cookie;
+}
+
+static guint32
+_generate_unique_cookie (GsmManager *manager)
+{
+ guint32 cookie;
+
+ do {
+ cookie = generate_cookie ();
+ } while (gsm_store_find (manager->priv->inhibitors, (GsmStoreFunc)_find_by_cookie, &cookie) != NULL);
+
+ return cookie;
+}
+
+static gboolean
+_on_query_end_session_timeout (GsmManager *manager)
+{
+ GSList *l;
+
+ manager->priv->query_timeout_id = 0;
+
+ g_debug ("GsmManager: query end session timed out");
+
+ for (l = manager->priv->query_clients; l != NULL; l = l->next) {
+ guint cookie;
+ GsmInhibitor *inhibitor;
+ const char *bus_name;
+ char *app_id;
+
+ g_warning ("Client '%s' failed to reply before timeout",
+ gsm_client_peek_id (l->data));
+
+ /* Add JIT inhibit for unresponsive client */
+ if (GSM_IS_DBUS_CLIENT (l->data)) {
+ bus_name = gsm_dbus_client_get_bus_name (l->data);
+ } else {
+ bus_name = NULL;
+ }
+
+ app_id = g_strdup (gsm_client_peek_app_id (l->data));
+ if (IS_STRING_EMPTY (app_id)) {
+ /* XSMP clients don't give us an app id unless we start them */
+ g_free (app_id);
+ app_id = gsm_client_get_app_name (l->data);
+ }
+
+ cookie = _generate_unique_cookie (manager);
+ inhibitor = gsm_inhibitor_new_for_client (gsm_client_peek_id (l->data),
+ app_id,
+ GSM_INHIBITOR_FLAG_LOGOUT,
+ _("Not responding"),
+ bus_name,
+ cookie);
+ g_free (app_id);
+ gsm_store_add (manager->priv->inhibitors, gsm_inhibitor_peek_id (inhibitor), G_OBJECT (inhibitor));
+ g_object_unref (inhibitor);
+ }
+
+ g_slist_free (manager->priv->query_clients);
+ manager->priv->query_clients = NULL;
+
+ query_end_session_complete (manager);
+
+ return FALSE;
+}
+
+static void
+do_phase_query_end_session (GsmManager *manager)
+{
+ ClientEndSessionData data;
+
+ data.manager = manager;
+ data.flags = 0;
+
+ if (manager->priv->forceful_logout) {
+ data.flags |= GSM_CLIENT_END_SESSION_FLAG_FORCEFUL;
+ }
+ /* We only query if an app is ready to log out, so we don't use
+ * GSM_CLIENT_END_SESSION_FLAG_SAVE here.
+ */
+
+ debug_clients (manager);
+ g_debug ("GsmManager: sending query-end-session to clients forceful:%d", manager->priv->forceful_logout);
+ gsm_store_foreach (manager->priv->clients,
+ (GsmStoreFunc)_client_query_end_session,
+ &data);
+
+ /* This phase doesn't time out. This separate timer is only used to
+ * show UI. */
+ manager->priv->query_timeout_id = g_timeout_add_seconds (1, (GSourceFunc)_on_query_end_session_timeout, manager);
+}
+
+static void
+update_idle (GsmManager *manager)
+{
+ if (gsm_manager_is_idle_inhibited (manager)) {
+ gsm_presence_set_idle_enabled (manager->priv->presence, FALSE);
+ } else {
+ gsm_presence_set_idle_enabled (manager->priv->presence, TRUE);
+ }
+}
+
+static void
+start_phase (GsmManager *manager)
+{
+
+ g_debug ("GsmManager: starting phase %s\n",
+ phase_num_to_name (manager->priv->phase));
+
+ /* reset state */
+ g_slist_free (manager->priv->pending_apps);
+ manager->priv->pending_apps = NULL;
+ g_slist_free (manager->priv->query_clients);
+ manager->priv->query_clients = NULL;
+ g_slist_free (manager->priv->next_query_clients);
+ manager->priv->next_query_clients = NULL;
+
+ if (manager->priv->query_timeout_id > 0) {
+ g_source_remove (manager->priv->query_timeout_id);
+ manager->priv->query_timeout_id = 0;
+ }
+ if (manager->priv->phase_timeout_id > 0) {
+ g_source_remove (manager->priv->phase_timeout_id);
+ manager->priv->phase_timeout_id = 0;
+ }
+
+ switch (manager->priv->phase) {
+ case GSM_MANAGER_PHASE_STARTUP:
+ case GSM_MANAGER_PHASE_INITIALIZATION:
+ case GSM_MANAGER_PHASE_WINDOW_MANAGER:
+ case GSM_MANAGER_PHASE_PANEL:
+ case GSM_MANAGER_PHASE_DESKTOP:
+ case GSM_MANAGER_PHASE_APPLICATION:
+ do_phase_startup (manager);
+ break;
+ case GSM_MANAGER_PHASE_RUNNING:
+ g_signal_emit (manager, signals[SESSION_RUNNING], 0);
+ update_idle (manager);
+ break;
+ case GSM_MANAGER_PHASE_QUERY_END_SESSION:
+ do_phase_query_end_session (manager);
+ break;
+ case GSM_MANAGER_PHASE_END_SESSION:
+ do_phase_end_session (manager);
+ break;
+ case GSM_MANAGER_PHASE_EXIT:
+ do_phase_exit (manager);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+static gboolean
+_debug_app_for_phase (const char *id,
+ GsmApp *app,
+ gpointer data)
+{
+ guint phase;
+
+ phase = GPOINTER_TO_UINT (data);
+
+ if (gsm_app_peek_phase (app) != phase) {
+ return FALSE;
+ }
+
+ g_debug ("GsmManager:\tID: %s\tapp-id:%s\tis-disabled:%d\tis-conditionally-disabled:%d",
+ gsm_app_peek_id (app),
+ gsm_app_peek_app_id (app),
+ gsm_app_peek_is_disabled (app),
+ gsm_app_peek_is_conditionally_disabled (app));
+
+ return FALSE;
+}
+
+static void
+debug_app_summary (GsmManager *manager)
+{
+ guint phase;
+
+ g_debug ("GsmManager: App startup summary");
+ for (phase = GSM_MANAGER_PHASE_INITIALIZATION; phase < GSM_MANAGER_PHASE_RUNNING; phase++) {
+ g_debug ("GsmManager: Phase %s", phase_num_to_name (phase));
+ gsm_store_foreach (manager->priv->apps,
+ (GsmStoreFunc)_debug_app_for_phase,
+ GUINT_TO_POINTER (phase));
+ }
+}
+
+void
+gsm_manager_start (GsmManager *manager)
+{
+ g_debug ("GsmManager: GSM starting to manage");
+
+ g_return_if_fail (GSM_IS_MANAGER (manager));
+
+ gsm_manager_set_phase (manager, GSM_MANAGER_PHASE_INITIALIZATION);
+ debug_app_summary (manager);
+ start_phase (manager);
+}
+
+static gboolean
+_app_has_app_id (const char *id,
+ GsmApp *app,
+ const char *app_id_a)
+{
+ const char *app_id_b;
+
+ app_id_b = gsm_app_peek_app_id (app);
+ return (app_id_b != NULL && strcmp (app_id_a, app_id_b) == 0);
+}
+
+static GsmApp *
+find_app_for_app_id (GsmManager *manager,
+ const char *app_id)
+{
+ GsmApp *app;
+ app = (GsmApp *)gsm_store_find (manager->priv->apps,
+ (GsmStoreFunc)_app_has_app_id,
+ (char *)app_id);
+ return app;
+}
+
+static gboolean
+inhibitor_has_client_id (gpointer key,
+ GsmInhibitor *inhibitor,
+ const char *client_id_a)
+{
+ gboolean matches;
+ const char *client_id_b;
+
+ client_id_b = gsm_inhibitor_peek_client_id (inhibitor);
+
+ matches = FALSE;
+ if (! IS_STRING_EMPTY (client_id_a) && ! IS_STRING_EMPTY (client_id_b)) {
+ matches = (strcmp (client_id_a, client_id_b) == 0);
+ if (matches) {
+ g_debug ("GsmManager: removing JIT inhibitor for %s for reason '%s'",
+ gsm_inhibitor_peek_client_id (inhibitor),
+ gsm_inhibitor_peek_reason (inhibitor));
+ }
+ }
+
+ return matches;
+}
+
+static gboolean
+_app_has_startup_id (const char *id,
+ GsmApp *app,
+ const char *startup_id_a)
+{
+ const char *startup_id_b;
+
+ startup_id_b = gsm_app_peek_startup_id (app);
+
+ if (IS_STRING_EMPTY (startup_id_b)) {
+ return FALSE;
+ }
+
+ return (strcmp (startup_id_a, startup_id_b) == 0);
+}
+
+static GsmApp *
+find_app_for_startup_id (GsmManager *manager,
+ const char *startup_id)
+{
+ GsmApp *found_app;
+ GSList *a;
+
+ found_app = NULL;
+
+ /* If we're starting up the session, try to match the new client
+ * with one pending apps for the current phase. If not, try to match
+ * with any of the autostarted apps. */
+ if (manager->priv->phase < GSM_MANAGER_PHASE_APPLICATION) {
+ for (a = manager->priv->pending_apps; a != NULL; a = a->next) {
+ GsmApp *app = GSM_APP (a->data);
+
+ if (strcmp (startup_id, gsm_app_peek_startup_id (app)) == 0) {
+ found_app = app;
+ goto out;
+ }
+ }
+ } else {
+ GsmApp *app;
+
+ app = (GsmApp *)gsm_store_find (manager->priv->apps,
+ (GsmStoreFunc)_app_has_startup_id,
+ (char *)startup_id);
+ if (app != NULL) {
+ found_app = app;
+ goto out;
+ }
+ }
+ out:
+ return found_app;
+}
+
+static void
+_disconnect_client (GsmManager *manager,
+ GsmClient *client)
+{
+ gboolean is_condition_client;
+ GsmApp *app;
+ GError *error;
+ gboolean res;
+ const char *app_id;
+ const char *startup_id;
+ gboolean app_restart;
+ GsmClientRestartStyle client_restart_hint;
+
+ g_debug ("GsmManager: disconnect client: %s", gsm_client_peek_id (client));
+
+ /* take a ref so it doesn't get finalized */
+ g_object_ref (client);
+
+ gsm_client_set_status (client, GSM_CLIENT_FINISHED);
+
+ is_condition_client = FALSE;
+ if (g_slist_find (manager->priv->condition_clients, client)) {
+ manager->priv->condition_clients = g_slist_remove (manager->priv->condition_clients, client);
+
+ is_condition_client = TRUE;
+ }
+
+ /* remove any inhibitors for this client */
+ gsm_store_foreach_remove (manager->priv->inhibitors,
+ (GsmStoreFunc)inhibitor_has_client_id,
+ (gpointer)gsm_client_peek_id (client));
+
+ app = NULL;
+
+ /* first try to match on startup ID */
+ startup_id = gsm_client_peek_startup_id (client);
+ if (! IS_STRING_EMPTY (startup_id)) {
+ app = find_app_for_startup_id (manager, startup_id);
+
+ }
+
+ /* then try to find matching app-id */
+ if (app == NULL) {
+ app_id = gsm_client_peek_app_id (client);
+ if (! IS_STRING_EMPTY (app_id)) {
+ g_debug ("GsmManager: disconnect for app '%s'", app_id);
+ app = find_app_for_app_id (manager, app_id);
+ }
+ }
+
+ if (app == NULL) {
+ g_debug ("GsmManager: unable to find application for client - not restarting");
+ goto out;
+ }
+
+ if (manager->priv->phase >= GSM_MANAGER_PHASE_QUERY_END_SESSION) {
+ g_debug ("GsmManager: in shutdown, not restarting application");
+ goto out;
+ }
+
+ app_restart = gsm_app_peek_autorestart (app);
+ client_restart_hint = gsm_client_peek_restart_style_hint (client);
+
+ /* allow legacy clients to override the app info */
+ if (! app_restart
+ && client_restart_hint != GSM_CLIENT_RESTART_IMMEDIATELY) {
+ g_debug ("GsmManager: autorestart not set, not restarting application");
+ goto out;
+ }
+
+ if (is_condition_client) {
+ g_debug ("GsmManager: app conditionally disabled, not restarting application");
+ goto out;
+ }
+
+ g_debug ("GsmManager: restarting app");
+
+ error = NULL;
+ res = gsm_app_restart (app, &error);
+ if (error != NULL) {
+ g_warning ("Error on restarting session managed app: %s", error->message);
+ g_error_free (error);
+ }
+
+ out:
+ g_object_unref (client);
+}
+
+typedef struct {
+ const char *service_name;
+ GsmManager *manager;
+} RemoveClientData;
+
+static gboolean
+_disconnect_dbus_client (const char *id,
+ GsmClient *client,
+ RemoveClientData *data)
+{
+ const char *name;
+
+ if (! GSM_IS_DBUS_CLIENT (client)) {
+ return FALSE;
+ }
+
+ name = gsm_dbus_client_get_bus_name (GSM_DBUS_CLIENT (client));
+ if (IS_STRING_EMPTY (name)) {
+ return FALSE;
+ }
+
+ if (strcmp (data->service_name, name) == 0) {
+ _disconnect_client (data->manager, client);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+remove_clients_for_connection (GsmManager *manager,
+ const char *service_name)
+{
+ RemoveClientData data;
+
+ data.service_name = service_name;
+ data.manager = manager;
+
+ /* disconnect dbus clients for name */
+ gsm_store_foreach_remove (manager->priv->clients,
+ (GsmStoreFunc)_disconnect_dbus_client,
+ &data);
+
+ if (manager->priv->phase >= GSM_MANAGER_PHASE_QUERY_END_SESSION
+ && gsm_store_size (manager->priv->clients) == 0) {
+ g_debug ("GsmManager: last client disconnected - exiting");
+ end_phase (manager);
+ }
+}
+
+static gboolean
+inhibitor_has_bus_name (gpointer key,
+ GsmInhibitor *inhibitor,
+ RemoveClientData *data)
+{
+ gboolean matches;
+ const char *bus_name_b;
+
+ bus_name_b = gsm_inhibitor_peek_bus_name (inhibitor);
+
+ matches = FALSE;
+ if (! IS_STRING_EMPTY (data->service_name) && ! IS_STRING_EMPTY (bus_name_b)) {
+ matches = (strcmp (data->service_name, bus_name_b) == 0);
+ if (matches) {
+ g_debug ("GsmManager: removing inhibitor from %s for reason '%s' on connection %s",
+ gsm_inhibitor_peek_app_id (inhibitor),
+ gsm_inhibitor_peek_reason (inhibitor),
+ gsm_inhibitor_peek_bus_name (inhibitor));
+ }
+ }
+
+ return matches;
+}
+
+static void
+remove_inhibitors_for_connection (GsmManager *manager,
+ const char *service_name)
+{
+ guint n_removed;
+ RemoveClientData data;
+
+ data.service_name = service_name;
+ data.manager = manager;
+
+ debug_inhibitors (manager);
+
+ n_removed = gsm_store_foreach_remove (manager->priv->inhibitors,
+ (GsmStoreFunc)inhibitor_has_bus_name,
+ &data);
+}
+
+static void
+bus_name_owner_changed (DBusGProxy *bus_proxy,
+ const char *service_name,
+ const char *old_service_name,
+ const char *new_service_name,
+ GsmManager *manager)
+{
+ if (strlen (new_service_name) == 0
+ && strlen (old_service_name) > 0) {
+ /* service removed */
+ remove_inhibitors_for_connection (manager, old_service_name);
+ remove_clients_for_connection (manager, old_service_name);
+ } else if (strlen (old_service_name) == 0
+ && strlen (new_service_name) > 0) {
+ /* service added */
+
+ /* use this if we support automatically registering
+ * well known bus names */
+ }
+}
+
+static gboolean
+register_manager (GsmManager *manager)
+{
+ GError *error = NULL;
+
+ error = NULL;
+ manager->priv->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+ if (manager->priv->connection == NULL) {
+ if (error != NULL) {
+ g_critical ("error getting session bus: %s", error->message);
+ g_error_free (error);
+ }
+ exit (1);
+ }
+
+ manager->priv->bus_proxy = dbus_g_proxy_new_for_name (manager->priv->connection,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS);
+ dbus_g_proxy_add_signal (manager->priv->bus_proxy,
+ "NameOwnerChanged",
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal (manager->priv->bus_proxy,
+ "NameOwnerChanged",
+ G_CALLBACK (bus_name_owner_changed),
+ manager,
+ NULL);
+
+ dbus_g_connection_register_g_object (manager->priv->connection, GSM_MANAGER_DBUS_PATH, G_OBJECT (manager));
+
+ return TRUE;
+}
+
+static void
+gsm_manager_set_failsafe (GsmManager *manager,
+ gboolean enabled)
+{
+ g_return_if_fail (GSM_IS_MANAGER (manager));
+
+ manager->priv->failsafe = enabled;
+}
+
+static gboolean
+_client_has_startup_id (const char *id,
+ GsmClient *client,
+ const char *startup_id_a)
+{
+ const char *startup_id_b;
+
+ startup_id_b = gsm_client_peek_startup_id (client);
+
+ if (IS_STRING_EMPTY (startup_id_b)) {
+ return FALSE;
+ }
+
+ return (strcmp (startup_id_a, startup_id_b) == 0);
+}
+
+static void
+on_client_disconnected (GsmClient *client,
+ GsmManager *manager)
+{
+ g_debug ("GsmManager: disconnect client");
+ _disconnect_client (manager, client);
+ gsm_store_remove (manager->priv->clients, gsm_client_peek_id (client));
+ if (manager->priv->phase >= GSM_MANAGER_PHASE_QUERY_END_SESSION
+ && gsm_store_size (manager->priv->clients) == 0) {
+ g_debug ("GsmManager: last client disconnected - exiting");
+ end_phase (manager);
+ }
+}
+
+static gboolean
+on_xsmp_client_register_request (GsmXSMPClient *client,
+ char **id,
+ GsmManager *manager)
+{
+ gboolean handled;
+ char *new_id;
+ GsmApp *app;
+
+ handled = TRUE;
+ new_id = NULL;
+
+ if (manager->priv->phase >= GSM_MANAGER_PHASE_QUERY_END_SESSION) {
+ goto out;
+ }
+
+ if (IS_STRING_EMPTY (*id)) {
+ new_id = gsm_util_generate_startup_id ();
+ } else {
+ GsmClient *client;
+
+ client = (GsmClient *)gsm_store_find (manager->priv->clients,
+ (GsmStoreFunc)_client_has_startup_id,
+ *id);
+ /* We can't have two clients with the same id. */
+ if (client != NULL) {
+ goto out;
+ }
+
+ new_id = g_strdup (*id);
+ }
+
+ g_debug ("GsmManager: Adding new client %s to session", new_id);
+
+ g_signal_connect (client,
+ "disconnected",
+ G_CALLBACK (on_client_disconnected),
+ manager);
+
+ /* If it's a brand new client id, we just accept the client*/
+ if (IS_STRING_EMPTY (*id)) {
+ goto out;
+ }
+
+ app = find_app_for_startup_id (manager, new_id);
+ if (app != NULL) {
+ gsm_client_set_app_id (GSM_CLIENT (client), gsm_app_peek_app_id (app));
+ gsm_app_registered (app);
+ goto out;
+ }
+
+ /* app not found */
+ g_free (new_id);
+ new_id = NULL;
+
+ out:
+ g_free (*id);
+ *id = new_id;
+
+ return handled;
+}
+
+static gboolean
+auto_save_is_enabled (GsmManager *manager)
+{
+ GError *error;
+ gboolean auto_save;
+
+ error = NULL;
+ auto_save = mateconf_client_get_bool (manager->priv->mateconf_client,
+ KEY_AUTOSAVE,
+ &error);
+
+ if (error) {
+ g_warning ("Error retrieving configuration key '%s': %s",
+ KEY_AUTOSAVE,
+ error->message);
+ g_error_free (error);
+
+ /* If we fail to query mateconf key, disable auto save */
+ auto_save = FALSE;
+ }
+
+ return auto_save;
+}
+
+static void
+maybe_save_session (GsmManager *manager)
+{
+ GsmConsolekit *consolekit;
+ char *session_type;
+ GError *error;
+
+ consolekit = gsm_get_consolekit ();
+ session_type = gsm_consolekit_get_current_session_type (consolekit);
+
+ if (g_strcmp0 (session_type, GSM_CONSOLEKIT_SESSION_TYPE_LOGIN_WINDOW) == 0) {
+ goto out;
+ }
+
+ /* We only allow session saving when session is running or when
+ * logging out */
+ if (manager->priv->phase != GSM_MANAGER_PHASE_RUNNING &&
+ manager->priv->phase != GSM_MANAGER_PHASE_END_SESSION) {
+ goto out;
+ }
+
+ error = NULL;
+ gsm_session_save (manager->priv->clients, &error);
+
+ if (error) {
+ g_warning ("Error saving session: %s", error->message);
+ g_error_free (error);
+ }
+
+out:
+ g_object_unref (consolekit);
+ g_free (session_type);
+}
+
+static void
+on_client_end_session_response (GsmClient *client,
+ gboolean is_ok,
+ gboolean do_last,
+ gboolean cancel,
+ const char *reason,
+ GsmManager *manager)
+{
+ /* just ignore if received outside of shutdown */
+ if (manager->priv->phase < GSM_MANAGER_PHASE_QUERY_END_SESSION) {
+ return;
+ }
+
+ g_debug ("GsmManager: Response from end session request: is-ok=%d do-last=%d cancel=%d reason=%s", is_ok, do_last, cancel, reason ? reason :"");
+
+ if (cancel) {
+ cancel_end_session (manager);
+ return;
+ }
+
+ manager->priv->query_clients = g_slist_remove (manager->priv->query_clients, client);
+
+ if (! is_ok) {
+ guint cookie;
+ GsmInhibitor *inhibitor;
+ char *app_id;
+ const char *bus_name;
+
+ /* FIXME: do we support updating the reason? */
+
+ /* Create JIT inhibit */
+ if (GSM_IS_DBUS_CLIENT (client)) {
+ bus_name = gsm_dbus_client_get_bus_name (GSM_DBUS_CLIENT (client));
+ } else {
+ bus_name = NULL;
+ }
+
+ app_id = g_strdup (gsm_client_peek_app_id (client));
+ if (IS_STRING_EMPTY (app_id)) {
+ /* XSMP clients don't give us an app id unless we start them */
+ g_free (app_id);
+ app_id = gsm_client_get_app_name (client);
+ }
+
+ cookie = _generate_unique_cookie (manager);
+ inhibitor = gsm_inhibitor_new_for_client (gsm_client_peek_id (client),
+ app_id,
+ GSM_INHIBITOR_FLAG_LOGOUT,
+ reason != NULL ? reason : _("Not responding"),
+ bus_name,
+ cookie);
+ g_free (app_id);
+ gsm_store_add (manager->priv->inhibitors, gsm_inhibitor_peek_id (inhibitor), G_OBJECT (inhibitor));
+ g_object_unref (inhibitor);
+ } else {
+ gsm_store_foreach_remove (manager->priv->inhibitors,
+ (GsmStoreFunc)inhibitor_has_client_id,
+ (gpointer)gsm_client_peek_id (client));
+ }
+
+ if (manager->priv->phase == GSM_MANAGER_PHASE_QUERY_END_SESSION) {
+ if (manager->priv->query_clients == NULL) {
+ query_end_session_complete (manager);
+ }
+ } else if (manager->priv->phase == GSM_MANAGER_PHASE_END_SESSION) {
+ if (do_last) {
+ /* This only makes sense if we're in part 1 of
+ * GSM_MANAGER_PHASE_END_SESSION. Doing this in part 2
+ * can only happen because of a buggy client that loops
+ * wanting to be last again and again. The phase
+ * timeout will take care of this issue. */
+ manager->priv->next_query_clients = g_slist_prepend (manager->priv->next_query_clients,
+ client);
+ }
+
+ /* we can continue to the next step if all clients have replied
+ * and if there's no inhibitor */
+ if (manager->priv->query_clients != NULL
+ || gsm_manager_is_logout_inhibited (manager)) {
+ return;
+ }
+
+ if (manager->priv->next_query_clients != NULL) {
+ do_phase_end_session_part_2 (manager);
+ } else {
+ end_phase (manager);
+ }
+ }
+}
+
+static void
+on_xsmp_client_logout_request (GsmXSMPClient *client,
+ gboolean show_dialog,
+ GsmManager *manager)
+{
+ GError *error;
+ int logout_mode;
+
+ if (show_dialog) {
+ logout_mode = GSM_MANAGER_LOGOUT_MODE_NORMAL;
+ } else {
+ logout_mode = GSM_MANAGER_LOGOUT_MODE_NO_CONFIRMATION;
+ }
+
+ error = NULL;
+ gsm_manager_logout (manager, logout_mode, &error);
+ if (error != NULL) {
+ g_warning ("Unable to logout: %s", error->message);
+ g_error_free (error);
+ }
+}
+
+static void
+on_store_client_added (GsmStore *store,
+ const char *id,
+ GsmManager *manager)
+{
+ GsmClient *client;
+
+ g_debug ("GsmManager: Client added: %s", id);
+
+ client = (GsmClient *)gsm_store_lookup (store, id);
+
+ /* a bit hacky */
+ if (GSM_IS_XSMP_CLIENT (client)) {
+ g_signal_connect (client,
+ "register-request",
+ G_CALLBACK (on_xsmp_client_register_request),
+ manager);
+ g_signal_connect (client,
+ "logout-request",
+ G_CALLBACK (on_xsmp_client_logout_request),
+ manager);
+ }
+
+ g_signal_connect (client,
+ "end-session-response",
+ G_CALLBACK (on_client_end_session_response),
+ manager);
+
+ g_signal_emit (manager, signals [CLIENT_ADDED], 0, id);
+ /* FIXME: disconnect signal handler */
+}
+
+static void
+on_store_client_removed (GsmStore *store,
+ const char *id,
+ GsmManager *manager)
+{
+ g_debug ("GsmManager: Client removed: %s", id);
+
+ g_signal_emit (manager, signals [CLIENT_REMOVED], 0, id);
+}
+
+static void
+gsm_manager_set_client_store (GsmManager *manager,
+ GsmStore *store)
+{
+ g_return_if_fail (GSM_IS_MANAGER (manager));
+
+ if (store != NULL) {
+ g_object_ref (store);
+ }
+
+ if (manager->priv->clients != NULL) {
+ g_signal_handlers_disconnect_by_func (manager->priv->clients,
+ on_store_client_added,
+ manager);
+ g_signal_handlers_disconnect_by_func (manager->priv->clients,
+ on_store_client_removed,
+ manager);
+
+ g_object_unref (manager->priv->clients);
+ }
+
+
+ g_debug ("GsmManager: setting client store %p", store);
+
+ manager->priv->clients = store;
+
+ if (manager->priv->clients != NULL) {
+ g_signal_connect (manager->priv->clients,
+ "added",
+ G_CALLBACK (on_store_client_added),
+ manager);
+ g_signal_connect (manager->priv->clients,
+ "removed",
+ G_CALLBACK (on_store_client_removed),
+ manager);
+ }
+}
+
+static void
+gsm_manager_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GsmManager *self;
+
+ self = GSM_MANAGER (object);
+
+ switch (prop_id) {
+ case PROP_FAILSAFE:
+ gsm_manager_set_failsafe (self, g_value_get_boolean (value));
+ break;
+ case PROP_CLIENT_STORE:
+ gsm_manager_set_client_store (self, g_value_get_object (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gsm_manager_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GsmManager *self;
+
+ self = GSM_MANAGER (object);
+
+ switch (prop_id) {
+ case PROP_FAILSAFE:
+ g_value_set_boolean (value, self->priv->failsafe);
+ break;
+ case PROP_CLIENT_STORE:
+ g_value_set_object (value, self->priv->clients);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+_find_app_provides (const char *id,
+ GsmApp *app,
+ const char *service)
+{
+ return gsm_app_provides (app, service);
+}
+
+static GObject *
+gsm_manager_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GsmManager *manager;
+
+ manager = GSM_MANAGER (G_OBJECT_CLASS (gsm_manager_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_properties));
+ return G_OBJECT (manager);
+}
+
+static void
+on_store_inhibitor_added (GsmStore *store,
+ const char *id,
+ GsmManager *manager)
+{
+ g_debug ("GsmManager: Inhibitor added: %s", id);
+ g_signal_emit (manager, signals [INHIBITOR_ADDED], 0, id);
+ update_idle (manager);
+}
+
+static void
+on_store_inhibitor_removed (GsmStore *store,
+ const char *id,
+ GsmManager *manager)
+{
+ g_debug ("GsmManager: Inhibitor removed: %s", id);
+ g_signal_emit (manager, signals [INHIBITOR_REMOVED], 0, id);
+ update_idle (manager);
+}
+
+static void
+gsm_manager_dispose (GObject *object)
+{
+ GsmManager *manager = GSM_MANAGER (object);
+
+ g_debug ("GsmManager: disposing manager");
+
+ if (manager->priv->clients != NULL) {
+ g_signal_handlers_disconnect_by_func (manager->priv->clients,
+ on_store_client_added,
+ manager);
+ g_signal_handlers_disconnect_by_func (manager->priv->clients,
+ on_store_client_removed,
+ manager);
+ g_object_unref (manager->priv->clients);
+ manager->priv->clients = NULL;
+ }
+
+ if (manager->priv->apps != NULL) {
+ g_object_unref (manager->priv->apps);
+ manager->priv->apps = NULL;
+ }
+
+ if (manager->priv->inhibitors != NULL) {
+ g_signal_handlers_disconnect_by_func (manager->priv->inhibitors,
+ on_store_inhibitor_added,
+ manager);
+ g_signal_handlers_disconnect_by_func (manager->priv->inhibitors,
+ on_store_inhibitor_removed,
+ manager);
+
+ g_object_unref (manager->priv->inhibitors);
+ manager->priv->inhibitors = NULL;
+ }
+
+ if (manager->priv->presence != NULL) {
+ g_object_unref (manager->priv->presence);
+ manager->priv->presence = NULL;
+ }
+
+ if (manager->priv->mateconf_client) {
+ if (manager->priv->desktop_notify_id != 0) {
+ mateconf_client_remove_dir (manager->priv->mateconf_client,
+ KEY_DESKTOP_DIR,
+ NULL);
+ mateconf_client_notify_remove (manager->priv->mateconf_client,
+ manager->priv->desktop_notify_id);
+ manager->priv->desktop_notify_id = 0;
+ }
+ if (manager->priv->lockdown_notify_id != 0) {
+ mateconf_client_remove_dir (manager->priv->mateconf_client,
+ KEY_LOCKDOWN_DIR,
+ NULL);
+ mateconf_client_notify_remove (manager->priv->mateconf_client,
+ manager->priv->lockdown_notify_id);
+ manager->priv->lockdown_notify_id = 0;
+ }
+
+ g_object_unref (manager->priv->mateconf_client);
+ manager->priv->mateconf_client = NULL;
+ }
+
+ if (manager->priv->up_client != NULL) {
+ g_object_unref (manager->priv->up_client);
+ manager->priv->up_client = NULL;
+ }
+
+ G_OBJECT_CLASS (gsm_manager_parent_class)->dispose (object);
+}
+
+static void
+gsm_manager_class_init (GsmManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->get_property = gsm_manager_get_property;
+ object_class->set_property = gsm_manager_set_property;
+ object_class->constructor = gsm_manager_constructor;
+ object_class->finalize = gsm_manager_finalize;
+ object_class->dispose = gsm_manager_dispose;
+
+ signals [PHASE_CHANGED] =
+ g_signal_new ("phase-changed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GsmManagerClass, phase_changed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1, G_TYPE_STRING);
+
+ signals [SESSION_RUNNING] =
+ g_signal_new ("session-running",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GsmManagerClass, session_running),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ signals [SESSION_OVER] =
+ g_signal_new ("session-over",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GsmManagerClass, session_over),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+ signals [CLIENT_ADDED] =
+ g_signal_new ("client-added",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GsmManagerClass, client_added),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__BOXED,
+ G_TYPE_NONE,
+ 1, DBUS_TYPE_G_OBJECT_PATH);
+ signals [CLIENT_REMOVED] =
+ g_signal_new ("client-removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GsmManagerClass, client_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__BOXED,
+ G_TYPE_NONE,
+ 1, DBUS_TYPE_G_OBJECT_PATH);
+ signals [INHIBITOR_ADDED] =
+ g_signal_new ("inhibitor-added",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GsmManagerClass, inhibitor_added),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__BOXED,
+ G_TYPE_NONE,
+ 1, DBUS_TYPE_G_OBJECT_PATH);
+ signals [INHIBITOR_REMOVED] =
+ g_signal_new ("inhibitor-removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GsmManagerClass, inhibitor_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__BOXED,
+ G_TYPE_NONE,
+ 1, DBUS_TYPE_G_OBJECT_PATH);
+
+ g_object_class_install_property (object_class,
+ PROP_FAILSAFE,
+ g_param_spec_boolean ("failsafe",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class,
+ PROP_CLIENT_STORE,
+ g_param_spec_object ("client-store",
+ NULL,
+ NULL,
+ GSM_TYPE_STORE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_type_class_add_private (klass, sizeof (GsmManagerPrivate));
+
+ dbus_g_object_type_install_info (GSM_TYPE_MANAGER, &dbus_glib_gsm_manager_object_info);
+ dbus_g_error_domain_register (GSM_MANAGER_ERROR, NULL, GSM_MANAGER_TYPE_ERROR);
+}
+
+static void
+invalid_type_warning (const char *type)
+{
+ g_warning ("Error retrieving configuration key '%s': Invalid type",
+ type);
+}
+
+static void
+load_idle_delay_from_mateconf (GsmManager *manager)
+{
+ GError *error;
+ glong value;
+
+ error = NULL;
+ value = mateconf_client_get_int (manager->priv->mateconf_client,
+ KEY_IDLE_DELAY,
+ &error);
+ if (error == NULL) {
+ gsm_presence_set_idle_timeout (manager->priv->presence, value * 60000);
+ } else {
+ g_warning ("Error retrieving configuration key '%s': %s",
+ KEY_IDLE_DELAY,
+ error->message);
+ g_error_free (error);
+ }
+
+}
+
+static void
+on_mateconf_key_changed (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ GsmManager *manager)
+{
+ const char *key;
+ MateConfValue *value;
+
+ key = mateconf_entry_get_key (entry);
+
+ if (! g_str_has_prefix (key, KEY_DESKTOP_DIR)
+ && ! g_str_has_prefix (key, KEY_LOCKDOWN_DIR)) {
+ return;
+ }
+
+ value = mateconf_entry_get_value (entry);
+
+ if (strcmp (key, KEY_IDLE_DELAY) == 0) {
+ if (value->type == MATECONF_VALUE_INT) {
+ int delay;
+
+ delay = mateconf_value_get_int (value);
+
+ gsm_presence_set_idle_timeout (manager->priv->presence, delay * 60000);
+ } else {
+ invalid_type_warning (key);
+ }
+ } else if (strcmp (key, KEY_LOCK_DISABLE) == 0) {
+ if (value->type == MATECONF_VALUE_BOOL) {
+ gboolean disabled;
+
+ disabled = mateconf_value_get_bool (value);
+
+ /* FIXME: handle this */
+ } else {
+ invalid_type_warning (key);
+ }
+ } else if (strcmp (key, KEY_USER_SWITCH_DISABLE) == 0) {
+
+ if (value->type == MATECONF_VALUE_BOOL) {
+ gboolean disabled;
+
+ disabled = mateconf_value_get_bool (value);
+
+ /* FIXME: handle this */
+ } else {
+ invalid_type_warning (key);
+ }
+
+ } else {
+ g_debug ("Config key not handled: %s", key);
+ }
+}
+
+static void
+on_presence_status_changed (GsmPresence *presence,
+ guint status,
+ GsmManager *manager)
+{
+ GsmConsolekit *consolekit;
+
+ consolekit = gsm_get_consolekit ();
+ gsm_consolekit_set_session_idle (consolekit,
+ (status == GSM_PRESENCE_STATUS_IDLE));
+}
+
+static void
+gsm_manager_init (GsmManager *manager)
+{
+
+ manager->priv = GSM_MANAGER_GET_PRIVATE (manager);
+
+ manager->priv->mateconf_client = mateconf_client_get_default ();
+
+ manager->priv->inhibitors = gsm_store_new ();
+ g_signal_connect (manager->priv->inhibitors,
+ "added",
+ G_CALLBACK (on_store_inhibitor_added),
+ manager);
+ g_signal_connect (manager->priv->inhibitors,
+ "removed",
+ G_CALLBACK (on_store_inhibitor_removed),
+ manager);
+
+ manager->priv->apps = gsm_store_new ();
+
+ manager->priv->presence = gsm_presence_new ();
+ g_signal_connect (manager->priv->presence,
+ "status-changed",
+ G_CALLBACK (on_presence_status_changed),
+ manager);
+
+ manager->priv->up_client = up_client_new ();
+
+ /* MateConf setup */
+ mateconf_client_add_dir (manager->priv->mateconf_client,
+ KEY_DESKTOP_DIR,
+ MATECONF_CLIENT_PRELOAD_RECURSIVE, NULL);
+ mateconf_client_add_dir (manager->priv->mateconf_client,
+ KEY_LOCKDOWN_DIR,
+ MATECONF_CLIENT_PRELOAD_NONE, NULL);
+
+ manager->priv->desktop_notify_id = mateconf_client_notify_add (manager->priv->mateconf_client,
+ KEY_DESKTOP_DIR,
+ (MateConfClientNotifyFunc)on_mateconf_key_changed,
+ manager,
+ NULL, NULL);
+ manager->priv->lockdown_notify_id = mateconf_client_notify_add (manager->priv->mateconf_client,
+ KEY_LOCKDOWN_DIR,
+ (MateConfClientNotifyFunc)on_mateconf_key_changed,
+ manager,
+ NULL, NULL);
+
+ load_idle_delay_from_mateconf (manager);
+}
+
+static void
+gsm_manager_finalize (GObject *object)
+{
+ GsmManager *manager;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GSM_IS_MANAGER (object));
+
+ manager = GSM_MANAGER (object);
+
+ g_return_if_fail (manager->priv != NULL);
+
+ G_OBJECT_CLASS (gsm_manager_parent_class)->finalize (object);
+}
+
+GsmManager *
+gsm_manager_new (GsmStore *client_store,
+ gboolean failsafe)
+{
+ if (manager_object != NULL) {
+ g_object_ref (manager_object);
+ } else {
+ gboolean res;
+
+ manager_object = g_object_new (GSM_TYPE_MANAGER,
+ "client-store", client_store,
+ "failsafe", failsafe,
+ NULL);
+
+ g_object_add_weak_pointer (manager_object,
+ (gpointer *) &manager_object);
+ res = register_manager (manager_object);
+ if (! res) {
+ g_object_unref (manager_object);
+ return NULL;
+ }
+ }
+
+ return GSM_MANAGER (manager_object);
+}
+
+gboolean
+gsm_manager_setenv (GsmManager *manager,
+ const char *variable,
+ const char *value,
+ GError **error)
+{
+ g_return_val_if_fail (GSM_IS_MANAGER (manager), FALSE);
+
+ if (manager->priv->phase > GSM_MANAGER_PHASE_INITIALIZATION) {
+ g_set_error (error,
+ GSM_MANAGER_ERROR,
+ GSM_MANAGER_ERROR_NOT_IN_INITIALIZATION,
+ "Setenv interface is only available during the Initialization phase");
+ return FALSE;
+ }
+
+ gsm_util_setenv (variable, value);
+
+ return TRUE;
+}
+
+gboolean
+gsm_manager_initialization_error (GsmManager *manager,
+ const char *message,
+ gboolean fatal,
+ GError **error)
+{
+ g_return_val_if_fail (GSM_IS_MANAGER (manager), FALSE);
+
+ if (manager->priv->phase > GSM_MANAGER_PHASE_INITIALIZATION) {
+ g_set_error (error,
+ GSM_MANAGER_ERROR,
+ GSM_MANAGER_ERROR_NOT_IN_INITIALIZATION,
+ "InitializationError interface is only available during the Initialization phase");
+ return FALSE;
+ }
+
+ gsm_util_init_error (fatal, "%s", message);
+
+ return TRUE;
+}
+
+static gboolean
+gsm_manager_is_switch_user_inhibited (GsmManager *manager)
+{
+ GsmInhibitor *inhibitor;
+
+ if (manager->priv->inhibitors == NULL) {
+ return FALSE;
+ }
+
+ inhibitor = (GsmInhibitor *)gsm_store_find (manager->priv->inhibitors,
+ (GsmStoreFunc)inhibitor_has_flag,
+ GUINT_TO_POINTER (GSM_INHIBITOR_FLAG_SWITCH_USER));
+ if (inhibitor == NULL) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+gsm_manager_is_suspend_inhibited (GsmManager *manager)
+{
+ GsmInhibitor *inhibitor;
+
+ if (manager->priv->inhibitors == NULL) {
+ return FALSE;
+ }
+
+ inhibitor = (GsmInhibitor *)gsm_store_find (manager->priv->inhibitors,
+ (GsmStoreFunc)inhibitor_has_flag,
+ GUINT_TO_POINTER (GSM_INHIBITOR_FLAG_SUSPEND));
+ if (inhibitor == NULL) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+request_reboot_privileges_completed (GsmConsolekit *consolekit,
+ gboolean success,
+ gboolean ask_later,
+ GError *error,
+ GsmManager *manager)
+{
+ /* make sure we disconnect the signal handler so that it's not called
+ * again next time the event is fired -- this can happen if the reboot
+ * is cancelled. */
+ g_signal_handlers_disconnect_by_func (consolekit,
+ request_reboot_privileges_completed,
+ manager);
+
+ g_object_unref (consolekit);
+
+ if (success) {
+ if (ask_later) {
+ manager->priv->logout_type = GSM_MANAGER_LOGOUT_REBOOT_INTERACT;
+ } else {
+ manager->priv->logout_type = GSM_MANAGER_LOGOUT_REBOOT;
+ }
+
+ end_phase (manager);
+ }
+}
+
+static void
+request_reboot (GsmManager *manager)
+{
+ GsmConsolekit *consolekit;
+ gboolean success;
+
+ g_debug ("GsmManager: requesting reboot");
+
+ /* We request the privileges before doing anything. There are a few
+ * different cases here:
+ *
+ * - no ConsoleKit: we fallback on MDM
+ * - no password required: everything is fine
+ * - password asked once: we ask for it now. If the user enters it
+ * fine, then all is great. If the user doesn't enter it fine, we
+ * don't do anything (so no logout).
+ * - password asked each time: we don't ask it for now since we don't
+ * want to ask for it twice. Instead we'll ask for it at the very
+ * end. If the user will enter it fine, then all is great again. If
+ * the user doesn't enter it fine, then we'll just fallback to MDM.
+ *
+ * The last case (password asked each time) is a bit broken, but
+ * there's really nothing we can do about it. Generally speaking,
+ * though, the password will only be asked once (unless the system is
+ * configured in paranoid mode), and most probably only if there are
+ * more than one user connected. So the general case is that it will
+ * just work fine.
+ */
+
+ consolekit = gsm_get_consolekit ();
+ g_signal_connect (consolekit,
+ "privileges-completed",
+ G_CALLBACK (request_reboot_privileges_completed),
+ manager);
+ success = gsm_consolekit_get_restart_privileges (consolekit);
+
+ if (!success) {
+ g_signal_handlers_disconnect_by_func (consolekit,
+ request_reboot_privileges_completed,
+ manager);
+ g_object_unref (consolekit);
+
+ manager->priv->logout_type = GSM_MANAGER_LOGOUT_REBOOT_MDM;
+ end_phase (manager);
+ }
+}
+
+static void
+request_shutdown_privileges_completed (GsmConsolekit *consolekit,
+ gboolean success,
+ gboolean ask_later,
+ GError *error,
+ GsmManager *manager)
+{
+ /* make sure we disconnect the signal handler so that it's not called
+ * again next time the event is fired -- this can happen if the reboot
+ * is cancelled. */
+ g_signal_handlers_disconnect_by_func (consolekit,
+ request_shutdown_privileges_completed,
+ manager);
+
+ g_object_unref (consolekit);
+
+ if (success) {
+ if (ask_later) {
+ manager->priv->logout_type = GSM_MANAGER_LOGOUT_SHUTDOWN_INTERACT;
+ } else {
+ manager->priv->logout_type = GSM_MANAGER_LOGOUT_SHUTDOWN;
+ }
+
+ end_phase (manager);
+ }
+}
+
+static void
+request_shutdown (GsmManager *manager)
+{
+ GsmConsolekit *consolekit;
+ gboolean success;
+
+ g_debug ("GsmManager: requesting shutdown");
+
+ /* See the comment in request_reboot() for some more details about how
+ * this works. */
+
+ consolekit = gsm_get_consolekit ();
+ g_signal_connect (consolekit,
+ "privileges-completed",
+ G_CALLBACK (request_shutdown_privileges_completed),
+ manager);
+ success = gsm_consolekit_get_stop_privileges (consolekit);
+
+ if (!success) {
+ g_signal_handlers_disconnect_by_func (consolekit,
+ request_shutdown_privileges_completed,
+ manager);
+ g_object_unref (consolekit);
+
+ manager->priv->logout_type = GSM_MANAGER_LOGOUT_SHUTDOWN_MDM;
+ end_phase (manager);
+ }
+}
+
+static void
+request_suspend (GsmManager *manager)
+{
+ g_debug ("GsmManager: requesting suspend");
+
+ if (! gsm_manager_is_suspend_inhibited (manager)) {
+ manager_attempt_suspend (manager);
+ return;
+ }
+
+ if (manager->priv->inhibit_dialog != NULL) {
+ g_debug ("GsmManager: inhibit dialog already up");
+ gtk_window_present (GTK_WINDOW (manager->priv->inhibit_dialog));
+ return;
+ }
+
+ manager->priv->inhibit_dialog = gsm_inhibit_dialog_new (manager->priv->inhibitors,
+ manager->priv->clients,
+ GSM_LOGOUT_ACTION_SLEEP);
+
+ g_signal_connect (manager->priv->inhibit_dialog,
+ "response",
+ G_CALLBACK (inhibit_dialog_response),
+ manager);
+ gtk_widget_show (manager->priv->inhibit_dialog);
+}
+
+static void
+request_hibernate (GsmManager *manager)
+{
+ g_debug ("GsmManager: requesting hibernate");
+
+ /* hibernate uses suspend inhibit */
+ if (! gsm_manager_is_suspend_inhibited (manager)) {
+ manager_attempt_hibernate (manager);
+ return;
+ }
+
+ if (manager->priv->inhibit_dialog != NULL) {
+ g_debug ("GsmManager: inhibit dialog already up");
+ gtk_window_present (GTK_WINDOW (manager->priv->inhibit_dialog));
+ return;
+ }
+
+ manager->priv->inhibit_dialog = gsm_inhibit_dialog_new (manager->priv->inhibitors,
+ manager->priv->clients,
+ GSM_LOGOUT_ACTION_HIBERNATE);
+
+ g_signal_connect (manager->priv->inhibit_dialog,
+ "response",
+ G_CALLBACK (inhibit_dialog_response),
+ manager);
+ gtk_widget_show (manager->priv->inhibit_dialog);
+}
+
+
+static void
+request_logout (GsmManager *manager,
+ gboolean forceful_logout)
+{
+ g_debug ("GsmManager: requesting logout");
+
+ manager->priv->forceful_logout = forceful_logout;
+ manager->priv->logout_type = GSM_MANAGER_LOGOUT_LOGOUT;
+
+ end_phase (manager);
+}
+
+static void
+request_switch_user (GsmManager *manager)
+{
+ g_debug ("GsmManager: requesting user switch");
+
+ if (! gsm_manager_is_switch_user_inhibited (manager)) {
+ manager_switch_user (manager);
+ return;
+ }
+
+ if (manager->priv->inhibit_dialog != NULL) {
+ g_debug ("GsmManager: inhibit dialog already up");
+ gtk_window_present (GTK_WINDOW (manager->priv->inhibit_dialog));
+ return;
+ }
+
+ manager->priv->inhibit_dialog = gsm_inhibit_dialog_new (manager->priv->inhibitors,
+ manager->priv->clients,
+ GSM_LOGOUT_ACTION_SWITCH_USER);
+
+ g_signal_connect (manager->priv->inhibit_dialog,
+ "response",
+ G_CALLBACK (inhibit_dialog_response),
+ manager);
+ gtk_widget_show (manager->priv->inhibit_dialog);
+}
+
+static void
+logout_dialog_response (GsmLogoutDialog *logout_dialog,
+ guint response_id,
+ GsmManager *manager)
+{
+ g_debug ("GsmManager: Logout dialog response: %d", response_id);
+
+ gtk_widget_destroy (GTK_WIDGET (logout_dialog));
+
+ /* In case of dialog cancel, switch user, hibernate and
+ * suspend, we just perform the respective action and return,
+ * without shutting down the session. */
+ switch (response_id) {
+ case GTK_RESPONSE_CANCEL:
+ case GTK_RESPONSE_NONE:
+ case GTK_RESPONSE_DELETE_EVENT:
+ break;
+ case GSM_LOGOUT_RESPONSE_SWITCH_USER:
+ request_switch_user (manager);
+ break;
+ case GSM_LOGOUT_RESPONSE_HIBERNATE:
+ request_hibernate (manager);
+ break;
+ case GSM_LOGOUT_RESPONSE_SLEEP:
+ request_suspend (manager);
+ break;
+ case GSM_LOGOUT_RESPONSE_SHUTDOWN:
+ request_shutdown (manager);
+ break;
+ case GSM_LOGOUT_RESPONSE_REBOOT:
+ request_reboot (manager);
+ break;
+ case GSM_LOGOUT_RESPONSE_LOGOUT:
+ request_logout (manager, FALSE);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+static void
+show_shutdown_dialog (GsmManager *manager)
+{
+ GtkWidget *dialog;
+
+ if (manager->priv->phase >= GSM_MANAGER_PHASE_QUERY_END_SESSION) {
+ /* Already shutting down, nothing more to do */
+ return;
+ }
+
+ dialog = gsm_get_shutdown_dialog (gdk_screen_get_default (),
+ gtk_get_current_event_time ());
+
+ g_signal_connect (dialog,
+ "response",
+ G_CALLBACK (logout_dialog_response),
+ manager);
+ gtk_widget_show (dialog);
+}
+
+static void
+show_logout_dialog (GsmManager *manager)
+{
+ GtkWidget *dialog;
+
+ if (manager->priv->phase >= GSM_MANAGER_PHASE_QUERY_END_SESSION) {
+ /* Already shutting down, nothing more to do */
+ return;
+ }
+
+ dialog = gsm_get_logout_dialog (gdk_screen_get_default (),
+ gtk_get_current_event_time ());
+
+ g_signal_connect (dialog,
+ "response",
+ G_CALLBACK (logout_dialog_response),
+ manager);
+ gtk_widget_show (dialog);
+}
+
+static void
+user_logout (GsmManager *manager,
+ gboolean show_confirmation,
+ gboolean forceful_logout)
+{
+ gboolean logout_prompt;
+
+ if (manager->priv->phase >= GSM_MANAGER_PHASE_QUERY_END_SESSION) {
+ /* Already shutting down, nothing more to do */
+ return;
+ }
+
+ logout_prompt =
+ mateconf_client_get_bool (manager->priv->mateconf_client,
+ "/apps/mate-session/options/logout_prompt",
+ NULL);
+
+ /* Global settings overides input parameter in order to disable confirmation
+ * dialog accordingly. If we're shutting down, we always show the confirmation
+ * dialog */
+ logout_prompt = (logout_prompt && show_confirmation);
+
+ if (logout_prompt) {
+ show_logout_dialog (manager);
+ } else {
+ request_logout (manager, forceful_logout);
+ }
+}
+
+/*
+ dbus-send --session --type=method_call --print-reply
+ --dest=org.mate.SessionManager
+ /org/mate/SessionManager
+ org.freedesktop.DBus.Introspectable.Introspect
+*/
+
+gboolean
+gsm_manager_set_phase (GsmManager *manager,
+ GsmManagerPhase phase)
+{
+ g_return_val_if_fail (GSM_IS_MANAGER (manager), FALSE);
+ manager->priv->phase = phase;
+ return (TRUE);
+}
+
+gboolean
+gsm_manager_shutdown (GsmManager *manager,
+ GError **error)
+{
+ g_debug ("GsmManager: Shutdown called");
+
+ g_return_val_if_fail (GSM_IS_MANAGER (manager), FALSE);
+
+ if (manager->priv->phase != GSM_MANAGER_PHASE_RUNNING) {
+ g_set_error (error,
+ GSM_MANAGER_ERROR,
+ GSM_MANAGER_ERROR_NOT_IN_RUNNING,
+ "Shutdown interface is only available during the Running phase");
+ return FALSE;
+ }
+
+ show_shutdown_dialog (manager);
+
+ return TRUE;
+}
+
+gboolean
+gsm_manager_can_shutdown (GsmManager *manager,
+ gboolean *shutdown_available,
+ GError **error)
+{
+ GsmConsolekit *consolekit;
+ gboolean can_suspend;
+ gboolean can_hibernate;
+
+ g_object_get (manager->priv->up_client,
+ "can-suspend", &can_suspend,
+ "can-hibernate", &can_hibernate,
+ NULL);
+
+ g_debug ("GsmManager: CanShutdown called");
+
+ g_return_val_if_fail (GSM_IS_MANAGER (manager), FALSE);
+
+ consolekit = gsm_get_consolekit ();
+ *shutdown_available = gsm_consolekit_can_stop (consolekit)
+ || gsm_consolekit_can_restart (consolekit)
+ || can_suspend
+ || can_hibernate;
+ g_object_unref (consolekit);
+
+ return TRUE;
+}
+
+gboolean
+gsm_manager_logout (GsmManager *manager,
+ guint logout_mode,
+ GError **error)
+{
+ g_debug ("GsmManager: Logout called");
+
+ g_return_val_if_fail (GSM_IS_MANAGER (manager), FALSE);
+
+ if (manager->priv->phase != GSM_MANAGER_PHASE_RUNNING) {
+ g_set_error (error,
+ GSM_MANAGER_ERROR,
+ GSM_MANAGER_ERROR_NOT_IN_RUNNING,
+ "Shutdown interface is only available during the Running phase");
+ return FALSE;
+ }
+
+ switch (logout_mode) {
+ case GSM_MANAGER_LOGOUT_MODE_NORMAL:
+ user_logout (manager, TRUE, FALSE);
+ break;
+
+ case GSM_MANAGER_LOGOUT_MODE_NO_CONFIRMATION:
+ user_logout (manager, FALSE, FALSE);
+ break;
+
+ case GSM_MANAGER_LOGOUT_MODE_FORCE:
+ user_logout (manager, FALSE, TRUE);
+ break;
+
+ default:
+ g_debug ("Unknown logout mode option");
+
+ g_set_error (error,
+ GSM_MANAGER_ERROR,
+ GSM_MANAGER_ERROR_INVALID_OPTION,
+ "Unknown logout mode flag");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+gsm_manager_register_client (GsmManager *manager,
+ const char *app_id,
+ const char *startup_id,
+ DBusGMethodInvocation *context)
+{
+ char *new_startup_id;
+ char *sender;
+ GsmClient *client;
+ GsmApp *app;
+
+ g_return_val_if_fail (GSM_IS_MANAGER (manager), FALSE);
+
+ app = NULL;
+ client = NULL;
+
+ g_debug ("GsmManager: RegisterClient %s", startup_id);
+
+ if (manager->priv->phase >= GSM_MANAGER_PHASE_QUERY_END_SESSION) {
+ GError *new_error;
+
+ g_debug ("Unable to register client: shutting down");
+
+ new_error = g_error_new (GSM_MANAGER_ERROR,
+ GSM_MANAGER_ERROR_NOT_IN_RUNNING,
+ "Unable to register client");
+ dbus_g_method_return_error (context, new_error);
+ g_error_free (new_error);
+ return FALSE;
+ }
+
+ if (IS_STRING_EMPTY (startup_id)) {
+ new_startup_id = gsm_util_generate_startup_id ();
+ } else {
+
+ client = (GsmClient *)gsm_store_find (manager->priv->clients,
+ (GsmStoreFunc)_client_has_startup_id,
+ (char *)startup_id);
+ /* We can't have two clients with the same startup id. */
+ if (client != NULL) {
+ GError *new_error;
+
+ g_debug ("Unable to register client: already registered");
+
+ new_error = g_error_new (GSM_MANAGER_ERROR,
+ GSM_MANAGER_ERROR_ALREADY_REGISTERED,
+ "Unable to register client");
+ dbus_g_method_return_error (context, new_error);
+ g_error_free (new_error);
+ return FALSE;
+ }
+
+ new_startup_id = g_strdup (startup_id);
+ }
+
+ g_debug ("GsmManager: Adding new client %s to session", new_startup_id);
+
+ if (app == NULL && !IS_STRING_EMPTY (startup_id)) {
+ app = find_app_for_startup_id (manager, startup_id);
+ }
+ if (app == NULL && !IS_STRING_EMPTY (app_id)) {
+ /* try to associate this app id with a known app */
+ app = find_app_for_app_id (manager, app_id);
+ }
+
+ sender = dbus_g_method_get_sender (context);
+ client = gsm_dbus_client_new (new_startup_id, sender);
+ g_free (sender);
+ if (client == NULL) {
+ GError *new_error;
+
+ g_debug ("Unable to create client");
+
+ new_error = g_error_new (GSM_MANAGER_ERROR,
+ GSM_MANAGER_ERROR_GENERAL,
+ "Unable to register client");
+ dbus_g_method_return_error (context, new_error);
+ g_error_free (new_error);
+ return FALSE;
+ }
+
+ gsm_store_add (manager->priv->clients, gsm_client_peek_id (client), G_OBJECT (client));
+ /* the store will own the ref */
+ g_object_unref (client);
+
+ if (app != NULL) {
+ gsm_client_set_app_id (client, gsm_app_peek_app_id (app));
+ gsm_app_registered (app);
+ } else {
+ /* if an app id is specified store it in the client
+ so we can save it later */
+ gsm_client_set_app_id (client, app_id);
+ }
+
+ gsm_client_set_status (client, GSM_CLIENT_REGISTERED);
+
+ g_assert (new_startup_id != NULL);
+ g_free (new_startup_id);
+
+ dbus_g_method_return (context, gsm_client_peek_id (client));
+
+ return TRUE;
+}
+
+gboolean
+gsm_manager_unregister_client (GsmManager *manager,
+ const char *client_id,
+ DBusGMethodInvocation *context)
+{
+ GsmClient *client;
+
+ g_return_val_if_fail (GSM_IS_MANAGER (manager), FALSE);
+
+ g_debug ("GsmManager: UnregisterClient %s", client_id);
+
+ client = (GsmClient *)gsm_store_lookup (manager->priv->clients, client_id);
+ if (client == NULL) {
+ GError *new_error;
+
+ g_debug ("Unable to unregister client: not registered");
+
+ new_error = g_error_new (GSM_MANAGER_ERROR,
+ GSM_MANAGER_ERROR_NOT_REGISTERED,
+ "Unable to unregister client");
+ dbus_g_method_return_error (context, new_error);
+ g_error_free (new_error);
+ return FALSE;
+ }
+
+ /* don't disconnect client here, only change the status.
+ Wait until it leaves the bus before disconnecting it */
+ gsm_client_set_status (client, GSM_CLIENT_UNREGISTERED);
+
+ dbus_g_method_return (context);
+
+ return TRUE;
+}
+
+gboolean
+gsm_manager_inhibit (GsmManager *manager,
+ const char *app_id,
+ guint toplevel_xid,
+ const char *reason,
+ guint flags,
+ DBusGMethodInvocation *context)
+{
+ GsmInhibitor *inhibitor;
+ guint cookie;
+
+ g_return_val_if_fail (GSM_IS_MANAGER (manager), FALSE);
+
+ g_debug ("GsmManager: Inhibit xid=%u app_id=%s reason=%s flags=%u",
+ toplevel_xid,
+ app_id,
+ reason,
+ flags);
+
+ if (IS_STRING_EMPTY (app_id)) {
+ GError *new_error;
+
+ new_error = g_error_new (GSM_MANAGER_ERROR,
+ GSM_MANAGER_ERROR_GENERAL,
+ "Application ID not specified");
+ g_debug ("GsmManager: Unable to inhibit: %s", new_error->message);
+ dbus_g_method_return_error (context, new_error);
+ g_error_free (new_error);
+ return FALSE;
+ }
+
+ if (IS_STRING_EMPTY (reason)) {
+ GError *new_error;
+
+ new_error = g_error_new (GSM_MANAGER_ERROR,
+ GSM_MANAGER_ERROR_GENERAL,
+ "Reason not specified");
+ g_debug ("GsmManager: Unable to inhibit: %s", new_error->message);
+ dbus_g_method_return_error (context, new_error);
+ g_error_free (new_error);
+ return FALSE;
+ }
+
+ if (flags == 0) {
+ GError *new_error;
+
+ new_error = g_error_new (GSM_MANAGER_ERROR,
+ GSM_MANAGER_ERROR_GENERAL,
+ "Invalid inhibit flags");
+ g_debug ("GsmManager: Unable to inhibit: %s", new_error->message);
+ dbus_g_method_return_error (context, new_error);
+ g_error_free (new_error);
+ return FALSE;
+ }
+
+ cookie = _generate_unique_cookie (manager);
+ inhibitor = gsm_inhibitor_new (app_id,
+ toplevel_xid,
+ flags,
+ reason,
+ dbus_g_method_get_sender (context),
+ cookie);
+ gsm_store_add (manager->priv->inhibitors, gsm_inhibitor_peek_id (inhibitor), G_OBJECT (inhibitor));
+ g_object_unref (inhibitor);
+
+ dbus_g_method_return (context, cookie);
+
+ return TRUE;
+}
+
+gboolean
+gsm_manager_uninhibit (GsmManager *manager,
+ guint cookie,
+ DBusGMethodInvocation *context)
+{
+ GsmInhibitor *inhibitor;
+
+ g_return_val_if_fail (GSM_IS_MANAGER (manager), FALSE);
+
+ g_debug ("GsmManager: Uninhibit %u", cookie);
+
+ inhibitor = (GsmInhibitor *)gsm_store_find (manager->priv->inhibitors,
+ (GsmStoreFunc)_find_by_cookie,
+ &cookie);
+ if (inhibitor == NULL) {
+ GError *new_error;
+
+ new_error = g_error_new (GSM_MANAGER_ERROR,
+ GSM_MANAGER_ERROR_GENERAL,
+ "Unable to uninhibit: Invalid cookie");
+ dbus_g_method_return_error (context, new_error);
+ g_debug ("Unable to uninhibit: %s", new_error->message);
+ g_error_free (new_error);
+ return FALSE;
+ }
+
+ g_debug ("GsmManager: removing inhibitor %s %u reason '%s' %u connection %s",
+ gsm_inhibitor_peek_app_id (inhibitor),
+ gsm_inhibitor_peek_toplevel_xid (inhibitor),
+ gsm_inhibitor_peek_reason (inhibitor),
+ gsm_inhibitor_peek_flags (inhibitor),
+ gsm_inhibitor_peek_bus_name (inhibitor));
+
+ gsm_store_remove (manager->priv->inhibitors, gsm_inhibitor_peek_id (inhibitor));
+
+ dbus_g_method_return (context);
+
+ return TRUE;
+}
+
+gboolean
+gsm_manager_is_inhibited (GsmManager *manager,
+ guint flags,
+ gboolean *is_inhibited,
+ GError *error)
+{
+ GsmInhibitor *inhibitor;
+
+ g_return_val_if_fail (GSM_IS_MANAGER (manager), FALSE);
+
+ if (manager->priv->inhibitors == NULL
+ || gsm_store_size (manager->priv->inhibitors) == 0) {
+ *is_inhibited = FALSE;
+ return TRUE;
+ }
+
+ inhibitor = (GsmInhibitor *) gsm_store_find (manager->priv->inhibitors,
+ (GsmStoreFunc)inhibitor_has_flag,
+ GUINT_TO_POINTER (flags));
+ if (inhibitor == NULL) {
+ *is_inhibited = FALSE;
+ } else {
+ *is_inhibited = TRUE;
+ }
+
+ return TRUE;
+
+}
+
+static gboolean
+listify_store_ids (char *id,
+ GObject *object,
+ GPtrArray **array)
+{
+ g_ptr_array_add (*array, g_strdup (id));
+ return FALSE;
+}
+
+gboolean
+gsm_manager_get_clients (GsmManager *manager,
+ GPtrArray **clients,
+ GError **error)
+{
+ g_return_val_if_fail (GSM_IS_MANAGER (manager), FALSE);
+
+ if (clients == NULL) {
+ return FALSE;
+ }
+
+ *clients = g_ptr_array_new ();
+ gsm_store_foreach (manager->priv->clients, (GsmStoreFunc)listify_store_ids, clients);
+
+ return TRUE;
+}
+
+gboolean
+gsm_manager_get_inhibitors (GsmManager *manager,
+ GPtrArray **inhibitors,
+ GError **error)
+{
+ g_return_val_if_fail (GSM_IS_MANAGER (manager), FALSE);
+
+ if (inhibitors == NULL) {
+ return FALSE;
+ }
+
+ *inhibitors = g_ptr_array_new ();
+ gsm_store_foreach (manager->priv->inhibitors,
+ (GsmStoreFunc) listify_store_ids,
+ inhibitors);
+
+ return TRUE;
+}
+
+
+static gboolean
+_app_has_autostart_condition (const char *id,
+ GsmApp *app,
+ const char *condition)
+{
+ gboolean has;
+ gboolean disabled;
+
+ has = gsm_app_has_autostart_condition (app, condition);
+ disabled = gsm_app_peek_is_disabled (app);
+
+ return has && !disabled;
+}
+
+gboolean
+gsm_manager_is_autostart_condition_handled (GsmManager *manager,
+ const char *condition,
+ gboolean *handled,
+ GError **error)
+{
+ GsmApp *app;
+
+ g_return_val_if_fail (GSM_IS_MANAGER (manager), FALSE);
+
+ app = (GsmApp *) gsm_store_find (manager->priv->apps,(
+ GsmStoreFunc) _app_has_autostart_condition,
+ (char *)condition);
+
+ if (app != NULL) {
+ *handled = TRUE;
+ } else {
+ *handled = FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+append_app (GsmManager *manager,
+ GsmApp *app)
+{
+ const char *id;
+ const char *app_id;
+ GsmApp *dup;
+
+ id = gsm_app_peek_id (app);
+ if (IS_STRING_EMPTY (id)) {
+ g_debug ("GsmManager: not adding app: no id");
+ return;
+ }
+
+ dup = (GsmApp *)gsm_store_lookup (manager->priv->apps, id);
+ if (dup != NULL) {
+ g_debug ("GsmManager: not adding app: already added");
+ return;
+ }
+
+ app_id = gsm_app_peek_app_id (app);
+ if (IS_STRING_EMPTY (app_id)) {
+ g_debug ("GsmManager: not adding app: no app-id");
+ return;
+ }
+
+ dup = find_app_for_app_id (manager, app_id);
+ if (dup != NULL) {
+ g_debug ("GsmManager: not adding app: app-id already exists");
+ return;
+ }
+
+ gsm_store_add (manager->priv->apps, id, G_OBJECT (app));
+}
+
+gboolean
+gsm_manager_add_autostart_app (GsmManager *manager,
+ const char *path,
+ const char *provides)
+{
+ GsmApp *app;
+
+ g_return_val_if_fail (GSM_IS_MANAGER (manager), FALSE);
+ g_return_val_if_fail (path != NULL, FALSE);
+
+ /* first check to see if service is already provided */
+ if (provides != NULL) {
+ GsmApp *dup;
+
+ dup = (GsmApp *)gsm_store_find (manager->priv->apps,
+ (GsmStoreFunc)_find_app_provides,
+ (char *)provides);
+ if (dup != NULL) {
+ g_debug ("GsmManager: service '%s' is already provided", provides);
+ return FALSE;
+ }
+ }
+
+ app = gsm_autostart_app_new (path);
+ if (app == NULL) {
+ g_warning ("could not read %s", path);
+ return FALSE;
+ }
+
+ g_debug ("GsmManager: read %s", path);
+ append_app (manager, app);
+ g_object_unref (app);
+
+ return TRUE;
+}
+
+gboolean
+gsm_manager_add_autostart_apps_from_dir (GsmManager *manager,
+ const char *path)
+{
+ GDir *dir;
+ const char *name;
+
+ g_return_val_if_fail (GSM_IS_MANAGER (manager), FALSE);
+ g_return_val_if_fail (path != NULL, FALSE);
+
+ g_debug ("GsmManager: *** Adding autostart apps for %s", path);
+
+ dir = g_dir_open (path, 0, NULL);
+ if (dir == NULL) {
+ return FALSE;
+ }
+
+ while ((name = g_dir_read_name (dir))) {
+ char *desktop_file;
+
+ if (!g_str_has_suffix (name, ".desktop")) {
+ continue;
+ }
+
+ desktop_file = g_build_filename (path, name, NULL);
+ gsm_manager_add_autostart_app (manager, desktop_file, NULL);
+ g_free (desktop_file);
+ }
+
+ g_dir_close (dir);
+
+ return TRUE;
+}
diff --git a/mate-session/gsm-manager.h b/mate-session/gsm-manager.h
new file mode 100644
index 0000000..635590c
--- /dev/null
+++ b/mate-session/gsm-manager.h
@@ -0,0 +1,190 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 William Jon McCann <[email protected]>
+ *
+ * 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_MANAGER_H
+#define __GSM_MANAGER_H
+
+#include <glib-object.h>
+#include <dbus/dbus-glib.h>
+
+#include "gsm-store.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GSM_TYPE_MANAGER (gsm_manager_get_type ())
+#define GSM_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSM_TYPE_MANAGER, GsmManager))
+#define GSM_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GSM_TYPE_MANAGER, GsmManagerClass))
+#define GSM_IS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSM_TYPE_MANAGER))
+#define GSM_IS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSM_TYPE_MANAGER))
+#define GSM_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSM_TYPE_MANAGER, GsmManagerClass))
+
+typedef struct GsmManagerPrivate GsmManagerPrivate;
+
+typedef struct
+{
+ GObject parent;
+ GsmManagerPrivate *priv;
+} GsmManager;
+
+typedef struct
+{
+ GObjectClass parent_class;
+
+ void (* session_running) (GsmManager *manager);
+ void (* session_over) (GsmManager *manager);
+ void (* session_over_notice) (GsmManager *manager);
+
+ void (* phase_changed) (GsmManager *manager,
+ const char *phase);
+
+ void (* client_added) (GsmManager *manager,
+ const char *id);
+ void (* client_removed) (GsmManager *manager,
+ const char *id);
+ void (* inhibitor_added) (GsmManager *manager,
+ const char *id);
+ void (* inhibitor_removed) (GsmManager *manager,
+ const char *id);
+} GsmManagerClass;
+
+typedef enum {
+ /* gsm's own startup/initialization phase */
+ GSM_MANAGER_PHASE_STARTUP = 0,
+ /* xrandr setup, mate-settings-daemon, etc */
+ GSM_MANAGER_PHASE_INITIALIZATION,
+ /* window/compositing managers */
+ GSM_MANAGER_PHASE_WINDOW_MANAGER,
+ /* apps that will create _NET_WM_WINDOW_TYPE_PANEL windows */
+ GSM_MANAGER_PHASE_PANEL,
+ /* apps that will create _NET_WM_WINDOW_TYPE_DESKTOP windows */
+ GSM_MANAGER_PHASE_DESKTOP,
+ /* everything else */
+ GSM_MANAGER_PHASE_APPLICATION,
+ /* done launching */
+ GSM_MANAGER_PHASE_RUNNING,
+ /* shutting down */
+ GSM_MANAGER_PHASE_QUERY_END_SESSION,
+ GSM_MANAGER_PHASE_END_SESSION,
+ GSM_MANAGER_PHASE_EXIT
+} GsmManagerPhase;
+
+typedef enum
+{
+ GSM_MANAGER_ERROR_GENERAL = 0,
+ GSM_MANAGER_ERROR_NOT_IN_INITIALIZATION,
+ GSM_MANAGER_ERROR_NOT_IN_RUNNING,
+ GSM_MANAGER_ERROR_ALREADY_REGISTERED,
+ GSM_MANAGER_ERROR_NOT_REGISTERED,
+ GSM_MANAGER_ERROR_INVALID_OPTION,
+ GSM_MANAGER_NUM_ERRORS
+} GsmManagerError;
+
+#define GSM_MANAGER_ERROR gsm_manager_error_quark ()
+
+typedef enum {
+ GSM_MANAGER_LOGOUT_MODE_NORMAL = 0,
+ GSM_MANAGER_LOGOUT_MODE_NO_CONFIRMATION,
+ GSM_MANAGER_LOGOUT_MODE_FORCE
+} GsmManagerLogoutMode;
+
+GType gsm_manager_error_get_type (void);
+#define GSM_MANAGER_TYPE_ERROR (gsm_manager_error_get_type ())
+
+GQuark gsm_manager_error_quark (void);
+GType gsm_manager_get_type (void);
+
+GsmManager * gsm_manager_new (GsmStore *client_store,
+ gboolean failsafe);
+
+gboolean gsm_manager_add_autostart_app (GsmManager *manager,
+ const char *path,
+ const char *provides);
+gboolean gsm_manager_add_autostart_apps_from_dir (GsmManager *manager,
+ const char *path);
+gboolean gsm_manager_add_legacy_session_apps (GsmManager *manager,
+ const char *path);
+
+void gsm_manager_start (GsmManager *manager);
+
+
+/* exported methods */
+
+gboolean gsm_manager_register_client (GsmManager *manager,
+ const char *app_id,
+ const char *client_startup_id,
+ DBusGMethodInvocation *context);
+gboolean gsm_manager_unregister_client (GsmManager *manager,
+ const char *session_client_id,
+ DBusGMethodInvocation *context);
+
+gboolean gsm_manager_inhibit (GsmManager *manager,
+ const char *app_id,
+ guint toplevel_xid,
+ const char *reason,
+ guint flags,
+ DBusGMethodInvocation *context);
+gboolean gsm_manager_uninhibit (GsmManager *manager,
+ guint inhibit_cookie,
+ DBusGMethodInvocation *context);
+gboolean gsm_manager_is_inhibited (GsmManager *manager,
+ guint flags,
+ gboolean *is_inhibited,
+ GError *error);
+
+gboolean gsm_manager_shutdown (GsmManager *manager,
+ GError **error);
+
+gboolean gsm_manager_can_shutdown (GsmManager *manager,
+ gboolean *shutdown_available,
+ GError **error);
+gboolean gsm_manager_logout (GsmManager *manager,
+ guint logout_mode,
+ GError **error);
+
+gboolean gsm_manager_setenv (GsmManager *manager,
+ const char *variable,
+ const char *value,
+ GError **error);
+gboolean gsm_manager_initialization_error (GsmManager *manager,
+ const char *message,
+ gboolean fatal,
+ GError **error);
+
+gboolean gsm_manager_get_clients (GsmManager *manager,
+ GPtrArray **clients,
+ GError **error);
+gboolean gsm_manager_get_inhibitors (GsmManager *manager,
+ GPtrArray **inhibitors,
+ GError **error);
+gboolean gsm_manager_is_autostart_condition_handled (GsmManager *manager,
+ const char *condition,
+ gboolean *handled,
+ GError **error);
+gboolean gsm_manager_set_phase (GsmManager *manager,
+ GsmManagerPhase phase);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GSM_MANAGER_H */
diff --git a/mate-session/gsm-marshal.list b/mate-session/gsm-marshal.list
new file mode 100644
index 0000000..f31a8b1
--- /dev/null
+++ b/mate-session/gsm-marshal.list
@@ -0,0 +1,3 @@
+BOOLEAN:POINTER
+VOID:BOOLEAN,BOOLEAN,BOOLEAN,STRING
+VOID:BOOLEAN,BOOLEAN,POINTER
diff --git a/mate-session/gsm-mateconf.c b/mate-session/gsm-mateconf.c
new file mode 100644
index 0000000..cd5adc4
--- /dev/null
+++ b/mate-session/gsm-mateconf.c
@@ -0,0 +1,143 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ * gsm-mateconf.c
+ * Copyright (C) 2007 Novell, Inc.
+ *
+ * FIXME: (C) on mateconf-sanity-check call, gsm_get_conf_client,
+ * gsm_shutdown_mateconfd
+ *
+ * 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
+ * Lesser 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 <glib/gi18n.h>
+
+#include <sys/wait.h>
+#include <sys/types.h>
+
+#include "gsm-mateconf.h"
+#include "gsm-util.h"
+
+static pid_t gsc_pid;
+
+static void unset_display_setup (gpointer user_data);
+
+/**
+ * gsm_mateconf_init:
+ *
+ * Starts mateconfd asynchronously if it is not already running. This
+ * must be called very soon after startup. It requires no
+ * initialization beyond g_type_init().
+ **/
+void
+gsm_mateconf_init (void)
+{
+ GError *error = NULL;
+ char *argv[2];
+
+ /* Run mateconf-sanity-check. As a side effect, this will cause mateconfd
+ * to be started. (We do this asynchronously so that other GSM
+ * initialization can happen in parallel.)
+ */
+
+ argv[0] = MATECONF_SANITY_CHECK;
+ argv[1] = NULL;
+
+ g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD,
+ unset_display_setup, NULL, &gsc_pid, &error);
+ if (error != NULL) {
+ g_warning ("Failed to run mateconf-sanity-check-2: %s\n",
+ error->message);
+ g_error_free (error);
+
+ /* This probably means mateconf-sanity-check wasn't found, which
+ * really shouldn't happen, but we'll just ignore it for now as
+ * long as mateconf seems to be working later on...
+ */
+
+ gsc_pid = 0;
+ }
+}
+
+static void
+unset_display_setup (gpointer user_data)
+{
+ /* Unset DISPLAY to make sure mateconf-sanity-check spews errors to
+ * stderr instead of trying to show a dialog (since it doesn't
+ * compensate for the fact that a window manager isn't running yet.)
+ */
+ g_unsetenv ("DISPLAY");
+}
+
+/**
+ * gsm_mateconf_check:
+ *
+ * Verifies that gsm_mateconf_init() succeeded. (Exits with an error
+ * dialog on failure.)
+ **/
+void
+gsm_mateconf_check (void)
+{
+ if (gsc_pid) {
+ int status;
+
+ /* Wait for mateconf-sanity-check to finish */
+ while (waitpid (gsc_pid, &status, 0) != gsc_pid) {
+ ;
+ }
+ gsc_pid = 0;
+
+ if (!WIFEXITED (status) || WEXITSTATUS (status) != 0) {
+ /* FIXME: capture mateconf-sanity-check's stderr */
+ gsm_util_init_error (TRUE,
+ _("There is a problem with the configuration server.\n"
+ "(%s exited with status %d)"),
+ MATECONF_SANITY_CHECK, status);
+ }
+ }
+}
+
+/**
+ * gsm_mateconf_shutdown:
+ *
+ * Shuts down mateconfd before exiting.
+ *
+ * FIXME: does this need to be called even if mateconf-sanity-check fails?
+ **/
+void
+gsm_mateconf_shutdown (void)
+{
+ GError *error;
+ char *command;
+ int status;
+
+ command = g_strjoin (" ", MATECONFTOOL_CMD, "--shutdown", NULL);
+
+ status = 0;
+ error = NULL;
+ if (!g_spawn_command_line_sync (command, NULL, NULL, &status, &error)) {
+ g_warning ("Failed to execute '%s' on logout: %s\n",
+ command, error->message);
+ g_error_free (error);
+ }
+
+ if (status) {
+ g_warning ("Running '%s' at logout returned an exit status of '%d'",
+ command, status);
+ }
+
+ g_free (command);
+}
diff --git a/mate-session/gsm-mateconf.h b/mate-session/gsm-mateconf.h
new file mode 100644
index 0000000..d30d548
--- /dev/null
+++ b/mate-session/gsm-mateconf.h
@@ -0,0 +1,31 @@
+/* gsm-mateconf.h
+ * Copyright (C) 2007 Novell, Inc.
+ *
+ * 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
+ * Lesser 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_MATECONF_H__
+#define __GSM_MATECONF_H__
+
+#include <mateconf/mateconf-client.h>
+
+void gsm_mateconf_init (void);
+void gsm_mateconf_check (void);
+void gsm_mateconf_shutdown (void);
+
+MateConfClient *gsm_mateconf_get_client (void);
+
+#endif /* __GSM_MATECONF_H__ */
diff --git a/mate-session/gsm-presence.c b/mate-session/gsm-presence.c
new file mode 100644
index 0000000..dc179c0
--- /dev/null
+++ b/mate-session/gsm-presence.c
@@ -0,0 +1,550 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * 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
+ * Lesser 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 <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <dbus/dbus-glib.h>
+
+#include "gs-idle-monitor.h"
+
+#include "gsm-presence.h"
+#include "gsm-presence-glue.h"
+
+#define GSM_PRESENCE_DBUS_PATH "/org/mate/SessionManager/Presence"
+
+#define GS_NAME "org.mate.ScreenSaver"
+#define GS_PATH "/org/mate/ScreenSaver"
+#define GS_INTERFACE "org.mate.ScreenSaver"
+
+#define MAX_STATUS_TEXT 140
+
+#define IS_STRING_EMPTY(x) ((x)==NULL||(x)[0]=='\0')
+
+#define GSM_PRESENCE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_PRESENCE, GsmPresencePrivate))
+
+struct GsmPresencePrivate
+{
+ guint status;
+ guint saved_status;
+ char *status_text;
+ gboolean idle_enabled;
+ GSIdleMonitor *idle_monitor;
+ guint idle_watch_id;
+ guint idle_timeout;
+ gboolean screensaver_active;
+ DBusGConnection *bus_connection;
+ DBusGProxy *bus_proxy;
+ DBusGProxy *screensaver_proxy;
+};
+
+enum {
+ PROP_0,
+ PROP_STATUS,
+ PROP_STATUS_TEXT,
+ PROP_IDLE_ENABLED,
+ PROP_IDLE_TIMEOUT,
+};
+
+
+enum {
+ STATUS_CHANGED,
+ STATUS_TEXT_CHANGED,
+ LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (GsmPresence, gsm_presence, G_TYPE_OBJECT)
+
+GQuark
+gsm_presence_error_quark (void)
+{
+ static GQuark ret = 0;
+ if (ret == 0) {
+ ret = g_quark_from_static_string ("gsm_presence_error");
+ }
+
+ return ret;
+}
+
+#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
+
+GType
+gsm_presence_error_get_type (void)
+{
+ static GType etype = 0;
+
+ if (etype == 0) {
+ static const GEnumValue values[] = {
+ ENUM_ENTRY (GSM_PRESENCE_ERROR_GENERAL, "GeneralError"),
+ { 0, 0, 0 }
+ };
+
+ g_assert (GSM_PRESENCE_NUM_ERRORS == G_N_ELEMENTS (values) - 1);
+
+ etype = g_enum_register_static ("GsmPresenceError", values);
+ }
+
+ return etype;
+}
+
+static void
+set_session_idle (GsmPresence *presence,
+ gboolean is_idle)
+{
+ g_debug ("GsmPresence: setting idle: %d", is_idle);
+
+ if (is_idle) {
+ if (presence->priv->status == GSM_PRESENCE_STATUS_IDLE) {
+ g_debug ("GsmPresence: already idle, ignoring");
+ return;
+ }
+
+ /* save current status */
+ presence->priv->saved_status = presence->priv->status;
+ gsm_presence_set_status (presence, GSM_PRESENCE_STATUS_IDLE, NULL);
+ } else {
+ if (presence->priv->status != GSM_PRESENCE_STATUS_IDLE) {
+ g_debug ("GsmPresence: already not idle, ignoring");
+ return;
+ }
+
+ /* restore saved status */
+ gsm_presence_set_status (presence, presence->priv->saved_status, NULL);
+ presence->priv->saved_status = GSM_PRESENCE_STATUS_AVAILABLE;
+ }
+}
+
+static gboolean
+on_idle_timeout (GSIdleMonitor *monitor,
+ guint id,
+ gboolean condition,
+ GsmPresence *presence)
+{
+ gboolean handled;
+
+ handled = TRUE;
+ set_session_idle (presence, condition);
+
+ return handled;
+}
+
+static void
+reset_idle_watch (GsmPresence *presence)
+{
+ if (presence->priv->idle_monitor == NULL) {
+ return;
+ }
+
+ if (presence->priv->idle_watch_id > 0) {
+ g_debug ("GsmPresence: removing idle watch");
+ gs_idle_monitor_remove_watch (presence->priv->idle_monitor,
+ presence->priv->idle_watch_id);
+ presence->priv->idle_watch_id = 0;
+ }
+
+ if (! presence->priv->screensaver_active
+ && presence->priv->idle_enabled) {
+ g_debug ("GsmPresence: adding idle watch");
+
+ presence->priv->idle_watch_id = gs_idle_monitor_add_watch (presence->priv->idle_monitor,
+ presence->priv->idle_timeout,
+ (GSIdleMonitorWatchFunc)on_idle_timeout,
+ presence);
+ }
+}
+
+static void
+on_screensaver_active_changed (DBusGProxy *proxy,
+ gboolean is_active,
+ GsmPresence *presence)
+{
+ g_debug ("screensaver status changed: %d", is_active);
+ if (presence->priv->screensaver_active != is_active) {
+ presence->priv->screensaver_active = is_active;
+ reset_idle_watch (presence);
+ set_session_idle (presence, is_active);
+ }
+}
+
+static void
+on_screensaver_proxy_destroy (GObject *proxy,
+ GsmPresence *presence)
+{
+ g_warning ("Detected that screensaver has left the bus");
+
+ presence->priv->screensaver_proxy = NULL;
+ presence->priv->screensaver_active = FALSE;
+ set_session_idle (presence, FALSE);
+ reset_idle_watch (presence);
+}
+
+static void
+on_bus_name_owner_changed (DBusGProxy *bus_proxy,
+ const char *service_name,
+ const char *old_service_name,
+ const char *new_service_name,
+ GsmPresence *presence)
+{
+ GError *error;
+
+ if (service_name == NULL
+ || strcmp (service_name, GS_NAME) != 0) {
+ /* ignore */
+ return;
+ }
+
+ if (strlen (new_service_name) == 0
+ && strlen (old_service_name) > 0) {
+ /* service removed */
+ /* let destroy signal handle this? */
+ } else if (strlen (old_service_name) == 0
+ && strlen (new_service_name) > 0) {
+ /* service added */
+ error = NULL;
+ presence->priv->screensaver_proxy = dbus_g_proxy_new_for_name_owner (presence->priv->bus_connection,
+ GS_NAME,
+ GS_PATH,
+ GS_INTERFACE,
+ &error);
+ if (presence->priv->screensaver_proxy != NULL) {
+ g_signal_connect (presence->priv->screensaver_proxy,
+ "destroy",
+ G_CALLBACK (on_screensaver_proxy_destroy),
+ presence);
+ dbus_g_proxy_add_signal (presence->priv->screensaver_proxy,
+ "ActiveChanged",
+ G_TYPE_BOOLEAN,
+ G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal (presence->priv->screensaver_proxy,
+ "ActiveChanged",
+ G_CALLBACK (on_screensaver_active_changed),
+ presence,
+ NULL);
+ } else {
+ g_warning ("Unable to get screensaver proxy: %s", error->message);
+ g_error_free (error);
+ }
+ }
+}
+
+static gboolean
+register_presence (GsmPresence *presence)
+{
+ GError *error;
+
+ error = NULL;
+ presence->priv->bus_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+ if (presence->priv->bus_connection == NULL) {
+ if (error != NULL) {
+ g_critical ("error getting session bus: %s", error->message);
+ g_error_free (error);
+ }
+ return FALSE;
+ }
+
+ dbus_g_connection_register_g_object (presence->priv->bus_connection, GSM_PRESENCE_DBUS_PATH, G_OBJECT (presence));
+
+ return TRUE;
+}
+
+static GObject *
+gsm_presence_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GsmPresence *presence;
+ gboolean res;
+
+ presence = GSM_PRESENCE (G_OBJECT_CLASS (gsm_presence_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_properties));
+
+ res = register_presence (presence);
+ if (! res) {
+ g_warning ("Unable to register presence with session bus");
+ }
+
+ presence->priv->bus_proxy = dbus_g_proxy_new_for_name (presence->priv->bus_connection,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS);
+ if (presence->priv->bus_proxy != NULL) {
+ dbus_g_proxy_add_signal (presence->priv->bus_proxy,
+ "NameOwnerChanged",
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal (presence->priv->bus_proxy,
+ "NameOwnerChanged",
+ G_CALLBACK (on_bus_name_owner_changed),
+ presence,
+ NULL);
+ }
+
+ return G_OBJECT (presence);
+}
+
+static void
+gsm_presence_init (GsmPresence *presence)
+{
+ presence->priv = GSM_PRESENCE_GET_PRIVATE (presence);
+
+ presence->priv->idle_monitor = gs_idle_monitor_new ();
+}
+
+void
+gsm_presence_set_idle_enabled (GsmPresence *presence,
+ gboolean enabled)
+{
+ g_return_if_fail (GSM_IS_PRESENCE (presence));
+
+ if (presence->priv->idle_enabled != enabled) {
+ presence->priv->idle_enabled = enabled;
+ reset_idle_watch (presence);
+ g_object_notify (G_OBJECT (presence), "idle-enabled");
+
+ }
+}
+
+gboolean
+gsm_presence_set_status_text (GsmPresence *presence,
+ const char *status_text,
+ GError **error)
+{
+ g_return_val_if_fail (GSM_IS_PRESENCE (presence), FALSE);
+
+ g_free (presence->priv->status_text);
+
+ /* check length */
+ if (status_text != NULL && strlen (status_text) > MAX_STATUS_TEXT) {
+ g_set_error (error,
+ GSM_PRESENCE_ERROR,
+ GSM_PRESENCE_ERROR_GENERAL,
+ "Status text too long");
+ return FALSE;
+ }
+
+ if (status_text != NULL) {
+ presence->priv->status_text = g_strdup (status_text);
+ } else {
+ presence->priv->status_text = g_strdup ("");
+ }
+ g_object_notify (G_OBJECT (presence), "status-text");
+ g_signal_emit (presence, signals[STATUS_TEXT_CHANGED], 0, presence->priv->status_text);
+ return TRUE;
+}
+
+gboolean
+gsm_presence_set_status (GsmPresence *presence,
+ guint status,
+ GError **error)
+{
+ g_return_val_if_fail (GSM_IS_PRESENCE (presence), FALSE);
+
+ if (status != presence->priv->status) {
+ presence->priv->status = status;
+ g_object_notify (G_OBJECT (presence), "status");
+ g_signal_emit (presence, signals[STATUS_CHANGED], 0, presence->priv->status);
+ }
+ return TRUE;
+}
+
+void
+gsm_presence_set_idle_timeout (GsmPresence *presence,
+ guint timeout)
+{
+ g_return_if_fail (GSM_IS_PRESENCE (presence));
+
+ if (timeout != presence->priv->idle_timeout) {
+ presence->priv->idle_timeout = timeout;
+ reset_idle_watch (presence);
+ g_object_notify (G_OBJECT (presence), "idle-timeout");
+ }
+}
+
+static void
+gsm_presence_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GsmPresence *self;
+
+ self = GSM_PRESENCE (object);
+
+ switch (prop_id) {
+ case PROP_STATUS:
+ gsm_presence_set_status (self, g_value_get_uint (value), NULL);
+ break;
+ case PROP_STATUS_TEXT:
+ gsm_presence_set_status_text (self, g_value_get_string (value), NULL);
+ break;
+ case PROP_IDLE_ENABLED:
+ gsm_presence_set_idle_enabled (self, g_value_get_boolean (value));
+ break;
+ case PROP_IDLE_TIMEOUT:
+ gsm_presence_set_idle_timeout (self, g_value_get_uint (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gsm_presence_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GsmPresence *self;
+
+ self = GSM_PRESENCE (object);
+
+ switch (prop_id) {
+ case PROP_STATUS:
+ g_value_set_uint (value, self->priv->status);
+ break;
+ case PROP_STATUS_TEXT:
+ g_value_set_string (value, self->priv->status_text);
+ break;
+ case PROP_IDLE_ENABLED:
+ g_value_set_boolean (value, self->priv->idle_enabled);
+ break;
+ case PROP_IDLE_TIMEOUT:
+ g_value_set_uint (value, self->priv->idle_timeout);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gsm_presence_finalize (GObject *object)
+{
+ GsmPresence *presence = (GsmPresence *) object;
+
+ if (presence->priv->idle_watch_id > 0) {
+ gs_idle_monitor_remove_watch (presence->priv->idle_monitor,
+ presence->priv->idle_watch_id);
+ presence->priv->idle_watch_id = 0;
+ }
+
+ if (presence->priv->status_text != NULL) {
+ g_free (presence->priv->status_text);
+ presence->priv->status_text = NULL;
+ }
+
+ if (presence->priv->idle_monitor != NULL) {
+ g_object_unref (presence->priv->idle_monitor);
+ presence->priv->idle_monitor = NULL;
+ }
+
+ G_OBJECT_CLASS (gsm_presence_parent_class)->finalize (object);
+}
+
+static void
+gsm_presence_class_init (GsmPresenceClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gsm_presence_finalize;
+ object_class->constructor = gsm_presence_constructor;
+ object_class->get_property = gsm_presence_get_property;
+ object_class->set_property = gsm_presence_set_property;
+
+ signals [STATUS_CHANGED] =
+ g_signal_new ("status-changed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GsmPresenceClass, status_changed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE,
+ 1, G_TYPE_UINT);
+ signals [STATUS_TEXT_CHANGED] =
+ g_signal_new ("status-text-changed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GsmPresenceClass, status_text_changed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1, G_TYPE_STRING);
+
+ g_object_class_install_property (object_class,
+ PROP_STATUS,
+ g_param_spec_uint ("status",
+ "status",
+ "status",
+ 0,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class,
+ PROP_STATUS_TEXT,
+ g_param_spec_string ("status-text",
+ "status text",
+ "status text",
+ "",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class,
+ PROP_IDLE_ENABLED,
+ g_param_spec_boolean ("idle-enabled",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class,
+ PROP_IDLE_TIMEOUT,
+ g_param_spec_uint ("idle-timeout",
+ "idle timeout",
+ "idle timeout",
+ 0,
+ G_MAXINT,
+ 300000,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ dbus_g_object_type_install_info (GSM_TYPE_PRESENCE, &dbus_glib_gsm_presence_object_info);
+ dbus_g_error_domain_register (GSM_PRESENCE_ERROR, NULL, GSM_PRESENCE_TYPE_ERROR);
+ g_type_class_add_private (klass, sizeof (GsmPresencePrivate));
+}
+
+GsmPresence *
+gsm_presence_new (void)
+{
+ GsmPresence *presence;
+
+ presence = g_object_new (GSM_TYPE_PRESENCE,
+ NULL);
+
+ return presence;
+}
diff --git a/mate-session/gsm-presence.h b/mate-session/gsm-presence.h
new file mode 100644
index 0000000..8762569
--- /dev/null
+++ b/mate-session/gsm-presence.h
@@ -0,0 +1,100 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * 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
+ * Lesser 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_PRESENCE_H__
+#define __GSM_PRESENCE_H__
+
+#include <glib-object.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GSM_TYPE_PRESENCE (gsm_presence_get_type ())
+#define GSM_PRESENCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSM_TYPE_PRESENCE, GsmPresence))
+#define GSM_PRESENCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSM_TYPE_PRESENCE, GsmPresenceClass))
+#define GSM_IS_PRESENCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSM_TYPE_PRESENCE))
+#define GSM_IS_PRESENCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSM_TYPE_PRESENCE))
+#define GSM_PRESENCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSM_TYPE_PRESENCE, GsmPresenceClass))
+
+typedef struct _GsmPresence GsmPresence;
+typedef struct _GsmPresenceClass GsmPresenceClass;
+
+typedef struct GsmPresencePrivate GsmPresencePrivate;
+
+struct _GsmPresence
+{
+ GObject parent;
+ GsmPresencePrivate *priv;
+};
+
+struct _GsmPresenceClass
+{
+ GObjectClass parent_class;
+
+ void (* status_changed) (GsmPresence *presence,
+ guint status);
+ void (* status_text_changed) (GsmPresence *presence,
+ const char *status_text);
+
+};
+
+typedef enum {
+ GSM_PRESENCE_STATUS_AVAILABLE = 0,
+ GSM_PRESENCE_STATUS_INVISIBLE,
+ GSM_PRESENCE_STATUS_BUSY,
+ GSM_PRESENCE_STATUS_IDLE,
+} GsmPresenceStatus;
+
+typedef enum
+{
+ GSM_PRESENCE_ERROR_GENERAL = 0,
+ GSM_PRESENCE_NUM_ERRORS
+} GsmPresenceError;
+
+#define GSM_PRESENCE_ERROR gsm_presence_error_quark ()
+GType gsm_presence_error_get_type (void);
+#define GSM_PRESENCE_TYPE_ERROR (gsm_presence_error_get_type ())
+
+GQuark gsm_presence_error_quark (void);
+
+GType gsm_presence_get_type (void) G_GNUC_CONST;
+
+GsmPresence * gsm_presence_new (void);
+
+void gsm_presence_set_idle_enabled (GsmPresence *presence,
+ gboolean enabled);
+void gsm_presence_set_idle_timeout (GsmPresence *presence,
+ guint n_seconds);
+
+/* exported to bus */
+gboolean gsm_presence_set_status (GsmPresence *presence,
+ guint status,
+ GError **error);
+gboolean gsm_presence_set_status_text (GsmPresence *presence,
+ const char *status_text,
+ GError **error);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GSM_PRESENCE_H__ */
diff --git a/mate-session/gsm-session-save.c b/mate-session/gsm-session-save.c
new file mode 100644
index 0000000..b31d9fa
--- /dev/null
+++ b/mate-session/gsm-session-save.c
@@ -0,0 +1,254 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ * gsm-session-save.c
+ * Copyright (C) 2008 Lucas Rocha.
+ *
+ * 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
+ * Lesser 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 <glib.h>
+#include <glib/gstdio.h>
+
+#include "gsm-util.h"
+#include "gsm-autostart-app.h"
+#include "gsm-client.h"
+
+#include "gsm-session-save.h"
+
+static gboolean gsm_session_clear_saved_session (const char *directory,
+ GHashTable *discard_hash);
+
+typedef struct {
+ char *dir;
+ GHashTable *discard_hash;
+ GError **error;
+} SessionSaveData;
+
+static gboolean
+save_one_client (char *id,
+ GObject *object,
+ SessionSaveData *data)
+{
+ GsmClient *client;
+ GKeyFile *keyfile;
+ char *path = NULL;
+ char *filename = NULL;
+ char *contents = NULL;
+ gsize length = 0;
+ char *discard_exec;
+ GError *local_error;
+
+ client = GSM_CLIENT (object);
+
+ local_error = NULL;
+
+ keyfile = gsm_client_save (client, &local_error);
+
+ if (keyfile == NULL || local_error) {
+ goto out;
+ }
+
+ contents = g_key_file_to_data (keyfile, &length, &local_error);
+
+ if (local_error) {
+ goto out;
+ }
+
+ filename = g_strdup_printf ("%s.desktop",
+ gsm_client_peek_startup_id (client));
+
+ path = g_build_filename (data->dir, filename, NULL);
+
+ g_file_set_contents (path,
+ contents,
+ length,
+ &local_error);
+
+ if (local_error) {
+ goto out;
+ }
+
+ discard_exec = g_key_file_get_string (keyfile,
+ G_KEY_FILE_DESKTOP_GROUP,
+ GSM_AUTOSTART_APP_DISCARD_KEY,
+ NULL);
+ if (discard_exec) {
+ g_hash_table_insert (data->discard_hash,
+ discard_exec, discard_exec);
+ }
+
+ g_debug ("GsmSessionSave: saved client %s to %s", id, filename);
+
+out:
+ if (keyfile != NULL) {
+ g_key_file_free (keyfile);
+ }
+
+ g_free (contents);
+ g_free (filename);
+ g_free (path);
+
+ /* in case of any error, stop saving session */
+ if (local_error) {
+ g_propagate_error (data->error, local_error);
+ g_error_free (local_error);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void
+gsm_session_save (GsmStore *client_store,
+ GError **error)
+{
+ const char *save_dir;
+ char *tmp_dir;
+ SessionSaveData data;
+
+ g_debug ("GsmSessionSave: Saving session");
+
+ save_dir = gsm_util_get_saved_session_dir ();
+ if (save_dir == NULL) {
+ g_warning ("GsmSessionSave: cannot create saved session directory");
+ return;
+ }
+
+ tmp_dir = gsm_util_get_empty_tmp_session_dir ();
+ if (tmp_dir == NULL) {
+ g_warning ("GsmSessionSave: cannot create new saved session directory");
+ return;
+ }
+
+ /* save the session in a temp directory, and remember the discard
+ * commands */
+ data.dir = tmp_dir;
+ data.discard_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+ data.error = error;
+
+ gsm_store_foreach (client_store,
+ (GsmStoreFunc) save_one_client,
+ &data);
+
+ if (!*error) {
+ /* remove the old saved session */
+ gsm_session_clear_saved_session (save_dir, data.discard_hash);
+
+ /* rename the temp session dir */
+ if (g_file_test (save_dir, G_FILE_TEST_IS_DIR))
+ g_rmdir (save_dir);
+ g_rename (tmp_dir, save_dir);
+ } else {
+ g_warning ("GsmSessionSave: error saving session: %s", (*error)->message);
+ /* FIXME: we should create a hash table filled with the discard
+ * commands that are in desktop files from save_dir. */
+ gsm_session_clear_saved_session (tmp_dir, NULL);
+ g_rmdir (tmp_dir);
+ }
+
+ g_hash_table_destroy (data.discard_hash);
+ g_free (tmp_dir);
+}
+
+static gboolean
+gsm_session_clear_one_client (const char *filename,
+ GHashTable *discard_hash)
+{
+ gboolean result = TRUE;
+ GKeyFile *key_file = NULL;
+ char *discard_exec = NULL;
+
+ g_debug ("GsmSessionSave: removing '%s' from saved session", filename);
+
+ key_file = g_key_file_new ();
+ if (g_key_file_load_from_file (key_file, filename,
+ G_KEY_FILE_NONE, NULL)) {
+ char **argv;
+ int argc;
+
+ discard_exec = g_key_file_get_string (key_file,
+ G_KEY_FILE_DESKTOP_GROUP,
+ GSM_AUTOSTART_APP_DISCARD_KEY,
+ NULL);
+ if (!discard_exec)
+ goto out;
+
+ if (g_hash_table_lookup (discard_hash, discard_exec))
+ goto out;
+
+ if (!g_shell_parse_argv (discard_exec, &argc, &argv, NULL))
+ goto out;
+
+ result = g_spawn_async (NULL, argv, NULL, G_SPAWN_SEARCH_PATH,
+ NULL, NULL, NULL, NULL) && result;
+
+ g_strfreev (argv);
+ } else {
+ result = FALSE;
+ }
+
+out:
+ if (key_file)
+ g_key_file_free (key_file);
+ if (discard_exec)
+ g_free (discard_exec);
+
+ result = (g_unlink (filename) == 0) && result;
+
+ return result;
+}
+
+static gboolean
+gsm_session_clear_saved_session (const char *directory,
+ GHashTable *discard_hash)
+{
+ GDir *dir;
+ const char *filename;
+ gboolean result = TRUE;
+ GError *error;
+
+ g_debug ("GsmSessionSave: clearing currently saved session at %s",
+ directory);
+
+ if (directory == NULL) {
+ return FALSE;
+ }
+
+ error = NULL;
+ dir = g_dir_open (directory, 0, &error);
+ if (error) {
+ g_warning ("GsmSessionSave: error loading saved session directory: %s", error->message);
+ g_error_free (error);
+ return FALSE;
+ }
+
+ while ((filename = g_dir_read_name (dir))) {
+ char *path = g_build_filename (directory,
+ filename, NULL);
+
+ result = gsm_session_clear_one_client (path, discard_hash)
+ && result;
+
+ g_free (path);
+ }
+
+ g_dir_close (dir);
+
+ return result;
+}
diff --git a/mate-session/gsm-session-save.h b/mate-session/gsm-session-save.h
new file mode 100644
index 0000000..2939bd9
--- /dev/null
+++ b/mate-session/gsm-session-save.h
@@ -0,0 +1,38 @@
+/* gsm-session-save.h
+ * Copyright (C) 2008 Lucas Rocha.
+ *
+ * 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
+ * Lesser 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_SESSION_SAVE_H__
+#define __GSM_SESSION_SAVE_H__
+
+#include <glib.h>
+
+#include "gsm-store.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void gsm_session_save (GsmStore *client_store,
+ GError **error);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GSM_SESSION_SAVE_H__ */
diff --git a/mate-session/gsm-store.c b/mate-session/gsm-store.c
new file mode 100644
index 0000000..e250d8d
--- /dev/null
+++ b/mate-session/gsm-store.c
@@ -0,0 +1,413 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007-2008 William Jon McCann <[email protected]>
+ *
+ * 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 <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+
+#include "gsm-store.h"
+
+#define GSM_STORE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_STORE, GsmStorePrivate))
+
+struct GsmStorePrivate
+{
+ GHashTable *objects;
+ gboolean locked;
+};
+
+enum {
+ ADDED,
+ REMOVED,
+ LAST_SIGNAL
+};
+
+enum {
+ PROP_0,
+ PROP_LOCKED
+};
+
+static guint signals [LAST_SIGNAL] = { 0 };
+
+static void gsm_store_class_init (GsmStoreClass *klass);
+static void gsm_store_init (GsmStore *store);
+static void gsm_store_finalize (GObject *object);
+
+G_DEFINE_TYPE (GsmStore, gsm_store, G_TYPE_OBJECT)
+
+GQuark
+gsm_store_error_quark (void)
+{
+ static GQuark ret = 0;
+ if (ret == 0) {
+ ret = g_quark_from_static_string ("gsm_store_error");
+ }
+
+ return ret;
+}
+
+guint
+gsm_store_size (GsmStore *store)
+{
+ return g_hash_table_size (store->priv->objects);
+}
+
+gboolean
+gsm_store_remove (GsmStore *store,
+ const char *id)
+{
+ GObject *found;
+ gboolean removed;
+ char *id_copy;
+
+ g_return_val_if_fail (store != NULL, FALSE);
+
+ found = g_hash_table_lookup (store->priv->objects, id);
+ if (found == NULL) {
+ return FALSE;
+ }
+
+ id_copy = g_strdup (id);
+
+ g_object_ref (found);
+
+ removed = g_hash_table_remove (store->priv->objects, id_copy);
+ g_assert (removed);
+
+ g_signal_emit (store, signals [REMOVED], 0, id_copy);
+
+ g_object_unref (found);
+ g_free (id_copy);
+
+ return TRUE;
+}
+
+void
+gsm_store_foreach (GsmStore *store,
+ GsmStoreFunc func,
+ gpointer user_data)
+{
+ g_return_if_fail (store != NULL);
+ g_return_if_fail (func != NULL);
+
+ g_hash_table_find (store->priv->objects,
+ (GHRFunc)func,
+ user_data);
+}
+
+GObject *
+gsm_store_find (GsmStore *store,
+ GsmStoreFunc predicate,
+ gpointer user_data)
+{
+ GObject *object;
+
+ g_return_val_if_fail (store != NULL, NULL);
+ g_return_val_if_fail (predicate != NULL, NULL);
+
+ object = g_hash_table_find (store->priv->objects,
+ (GHRFunc)predicate,
+ user_data);
+ return object;
+}
+
+GObject *
+gsm_store_lookup (GsmStore *store,
+ const char *id)
+{
+ GObject *object;
+
+ g_return_val_if_fail (store != NULL, NULL);
+ g_return_val_if_fail (id != NULL, NULL);
+
+ object = g_hash_table_lookup (store->priv->objects, id);
+
+ return object;
+}
+
+
+typedef struct
+{
+ GsmStoreFunc func;
+ gpointer user_data;
+ GsmStore *store;
+ GList *removed;
+} WrapperData;
+
+static gboolean
+foreach_remove_wrapper (const char *id,
+ GObject *object,
+ WrapperData *data)
+{
+ gboolean res;
+
+ res = (data->func) (id, object, data->user_data);
+ if (res) {
+ data->removed = g_list_prepend (data->removed, g_strdup (id));
+ }
+
+ return res;
+}
+
+guint
+gsm_store_foreach_remove (GsmStore *store,
+ GsmStoreFunc func,
+ gpointer user_data)
+{
+ guint ret;
+ WrapperData data;
+
+ g_return_val_if_fail (store != NULL, 0);
+ g_return_val_if_fail (func != NULL, 0);
+
+ data.store = store;
+ data.user_data = user_data;
+ data.func = func;
+ data.removed = NULL;
+
+ ret = g_hash_table_foreach_remove (store->priv->objects,
+ (GHRFunc)foreach_remove_wrapper,
+ &data);
+
+ while (data.removed != NULL) {
+ char *id;
+ id = data.removed->data;
+ g_debug ("GsmStore: emitting removed for %s", id);
+ g_signal_emit (store, signals [REMOVED], 0, id);
+ g_free (data.removed->data);
+ data.removed->data = NULL;
+ data.removed = g_list_delete_link (data.removed, data.removed);
+ }
+
+ return ret;
+}
+
+static gboolean
+_remove_all (const char *id,
+ GObject *object,
+ gpointer data)
+{
+ return TRUE;
+}
+
+void
+gsm_store_clear (GsmStore *store)
+{
+ g_return_if_fail (store != NULL);
+
+ g_debug ("GsmStore: Clearing object store");
+
+ gsm_store_foreach_remove (store,
+ _remove_all,
+ NULL);
+}
+
+gboolean
+gsm_store_add (GsmStore *store,
+ const char *id,
+ GObject *object)
+{
+ g_return_val_if_fail (store != NULL, FALSE);
+ g_return_val_if_fail (id != NULL, FALSE);
+ g_return_val_if_fail (object != NULL, FALSE);
+
+ /* If we're locked, we don't accept any new session
+ objects. */
+ if (store->priv->locked) {
+ return FALSE;
+ }
+
+ g_debug ("GsmStore: Adding object id %s to store", id);
+
+ g_hash_table_insert (store->priv->objects,
+ g_strdup (id),
+ g_object_ref (object));
+
+ g_signal_emit (store, signals [ADDED], 0, id);
+
+ return TRUE;
+}
+
+void
+gsm_store_set_locked (GsmStore *store,
+ gboolean locked)
+{
+ g_return_if_fail (GSM_IS_STORE (store));
+
+ store->priv->locked = locked;
+}
+
+gboolean
+gsm_store_get_locked (GsmStore *store)
+{
+ g_return_val_if_fail (GSM_IS_STORE (store), FALSE);
+
+ return store->priv->locked;
+}
+
+static void
+gsm_store_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GsmStore *self;
+
+ self = GSM_STORE (object);
+
+ switch (prop_id) {
+ case PROP_LOCKED:
+ gsm_store_set_locked (self, g_value_get_boolean (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gsm_store_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GsmStore *self;
+
+ self = GSM_STORE (object);
+
+ switch (prop_id) {
+ case PROP_LOCKED:
+ g_value_set_boolean (value, self->priv->locked);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gsm_store_dispose (GObject *object)
+{
+ GsmStore *store;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GSM_IS_STORE (object));
+
+ store = GSM_STORE (object);
+
+ gsm_store_clear (store);
+
+ G_OBJECT_CLASS (gsm_store_parent_class)->dispose (object);
+}
+
+static void
+gsm_store_class_init (GsmStoreClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->get_property = gsm_store_get_property;
+ object_class->set_property = gsm_store_set_property;
+ object_class->finalize = gsm_store_finalize;
+ object_class->dispose = gsm_store_dispose;
+
+ signals [ADDED] =
+ g_signal_new ("added",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GsmStoreClass, added),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1, G_TYPE_STRING);
+ signals [REMOVED] =
+ g_signal_new ("removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GsmStoreClass, removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1, G_TYPE_STRING);
+ g_object_class_install_property (object_class,
+ PROP_LOCKED,
+ g_param_spec_boolean ("locked",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_type_class_add_private (klass, sizeof (GsmStorePrivate));
+}
+
+static void
+_destroy_object (GObject *object)
+{
+ g_debug ("GsmStore: Unreffing object: %p", object);
+ g_object_unref (object);
+}
+
+static void
+gsm_store_init (GsmStore *store)
+{
+
+ store->priv = GSM_STORE_GET_PRIVATE (store);
+
+ store->priv->objects = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify) _destroy_object);
+}
+
+static void
+gsm_store_finalize (GObject *object)
+{
+ GsmStore *store;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GSM_IS_STORE (object));
+
+ store = GSM_STORE (object);
+
+ g_return_if_fail (store->priv != NULL);
+
+ g_hash_table_destroy (store->priv->objects);
+
+ G_OBJECT_CLASS (gsm_store_parent_class)->finalize (object);
+}
+
+GsmStore *
+gsm_store_new (void)
+{
+ GObject *object;
+
+ object = g_object_new (GSM_TYPE_STORE,
+ NULL);
+
+ return GSM_STORE (object);
+}
diff --git a/mate-session/gsm-store.h b/mate-session/gsm-store.h
new file mode 100644
index 0000000..ee7be10
--- /dev/null
+++ b/mate-session/gsm-store.h
@@ -0,0 +1,101 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007-2008 William Jon McCann <[email protected]>
+ *
+ * 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_STORE_H
+#define __GSM_STORE_H
+
+#include <glib-object.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GSM_TYPE_STORE (gsm_store_get_type ())
+#define GSM_STORE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSM_TYPE_STORE, GsmStore))
+#define GSM_STORE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GSM_TYPE_STORE, GsmStoreClass))
+#define GSM_IS_STORE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSM_TYPE_STORE))
+#define GSM_IS_STORE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSM_TYPE_STORE))
+#define GSM_STORE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSM_TYPE_STORE, GsmStoreClass))
+
+typedef struct GsmStorePrivate GsmStorePrivate;
+
+typedef struct
+{
+ GObject parent;
+ GsmStorePrivate *priv;
+} GsmStore;
+
+typedef struct
+{
+ GObjectClass parent_class;
+
+ void (* added) (GsmStore *store,
+ const char *id);
+ void (* removed) (GsmStore *store,
+ const char *id);
+} GsmStoreClass;
+
+typedef enum
+{
+ GSM_STORE_ERROR_GENERAL
+} GsmStoreError;
+
+#define GSM_STORE_ERROR gsm_store_error_quark ()
+
+typedef gboolean (*GsmStoreFunc) (const char *id,
+ GObject *object,
+ gpointer user_data);
+
+GQuark gsm_store_error_quark (void);
+GType gsm_store_get_type (void);
+
+GsmStore * gsm_store_new (void);
+
+gboolean gsm_store_get_locked (GsmStore *store);
+void gsm_store_set_locked (GsmStore *store,
+ gboolean locked);
+
+guint gsm_store_size (GsmStore *store);
+gboolean gsm_store_add (GsmStore *store,
+ const char *id,
+ GObject *object);
+void gsm_store_clear (GsmStore *store);
+gboolean gsm_store_remove (GsmStore *store,
+ const char *id);
+
+void gsm_store_foreach (GsmStore *store,
+ GsmStoreFunc func,
+ gpointer user_data);
+guint gsm_store_foreach_remove (GsmStore *store,
+ GsmStoreFunc func,
+ gpointer user_data);
+GObject * gsm_store_find (GsmStore *store,
+ GsmStoreFunc predicate,
+ gpointer user_data);
+GObject * gsm_store_lookup (GsmStore *store,
+ const char *id);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GSM_STORE_H */
diff --git a/mate-session/gsm-util.c b/mate-session/gsm-util.c
new file mode 100644
index 0000000..5d2983e
--- /dev/null
+++ b/mate-session/gsm-util.c
@@ -0,0 +1,505 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ * gsm-util.c
+ * Copyright (C) 2008 Lucas Rocha.
+ *
+ * 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
+ * Lesser 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 <ctype.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <gtk/gtk.h>
+
+#include <dbus/dbus-glib.h>
+
+#include "gsm-util.h"
+
+static gchar *_saved_session_dir = NULL;
+
+char *
+gsm_util_find_desktop_file_for_app_name (const char *name,
+ char **autostart_dirs)
+{
+ char *app_path;
+ char **app_dirs;
+ GKeyFile *key_file;
+ char *desktop_file;
+ int i;
+
+ app_path = NULL;
+
+ app_dirs = gsm_util_get_app_dirs ();
+
+ key_file = g_key_file_new ();
+
+ desktop_file = g_strdup_printf ("%s.desktop", name);
+
+ g_debug ("GsmUtil: Looking for file '%s'", desktop_file);
+
+ for (i = 0; app_dirs[i] != NULL; i++) {
+ g_debug ("GsmUtil: Looking in '%s'", app_dirs[i]);
+ }
+
+ g_key_file_load_from_dirs (key_file,
+ desktop_file,
+ (const char **) app_dirs,
+ &app_path,
+ G_KEY_FILE_NONE,
+ NULL);
+
+ if (app_path != NULL) {
+ g_debug ("GsmUtil: found in XDG app dirs: '%s'", app_path);
+ }
+
+ if (app_path == NULL && autostart_dirs != NULL) {
+ g_key_file_load_from_dirs (key_file,
+ desktop_file,
+ (const char **) autostart_dirs,
+ &app_path,
+ G_KEY_FILE_NONE,
+ NULL);
+ if (app_path != NULL) {
+ g_debug ("GsmUtil: found in autostart dirs: '%s'", app_path);
+ }
+
+ }
+
+ /* look for mate vender prefix */
+ if (app_path == NULL) {
+ g_free (desktop_file);
+ desktop_file = g_strdup_printf ("mate-%s.desktop", name);
+
+ g_key_file_load_from_dirs (key_file,
+ desktop_file,
+ (const char **) app_dirs,
+ &app_path,
+ G_KEY_FILE_NONE,
+ NULL);
+ if (app_path != NULL) {
+ g_debug ("GsmUtil: found in XDG app dirs: '%s'", app_path);
+ }
+ }
+
+ if (app_path == NULL && autostart_dirs != NULL) {
+ g_key_file_load_from_dirs (key_file,
+ desktop_file,
+ (const char **) autostart_dirs,
+ &app_path,
+ G_KEY_FILE_NONE,
+ NULL);
+ if (app_path != NULL) {
+ g_debug ("GsmUtil: found in autostart dirs: '%s'", app_path);
+ }
+ }
+
+ g_free (desktop_file);
+ g_key_file_free (key_file);
+
+ g_strfreev (app_dirs);
+
+ return app_path;
+}
+
+static gboolean
+ensure_dir_exists (const char *dir)
+{
+ if (g_file_test (dir, G_FILE_TEST_IS_DIR))
+ return TRUE;
+
+ if (g_mkdir_with_parents (dir, 0755) == 0)
+ return TRUE;
+
+ if (errno == EEXIST)
+ return g_file_test (dir, G_FILE_TEST_IS_DIR);
+
+ g_warning ("GsmSessionSave: Failed to create directory %s: %s", dir, strerror (errno));
+
+ return FALSE;
+}
+
+gchar *
+gsm_util_get_empty_tmp_session_dir (void)
+{
+ char *tmp;
+ gboolean exists;
+
+ tmp = g_build_filename (g_get_user_config_dir (),
+ "mate-session",
+ "saved-session.new",
+ NULL);
+
+ exists = ensure_dir_exists (tmp);
+
+ if (G_UNLIKELY (!exists)) {
+ g_warning ("GsmSessionSave: could not create directory for saved session: %s", tmp);
+ g_free (tmp);
+ return NULL;
+ } else {
+ /* make sure it's empty */
+ GDir *dir;
+ const char *filename;
+
+ dir = g_dir_open (tmp, 0, NULL);
+ if (dir) {
+ while ((filename = g_dir_read_name (dir))) {
+ char *path = g_build_filename (tmp, filename,
+ NULL);
+ g_unlink (path);
+ }
+ g_dir_close (dir);
+ }
+ }
+
+ return tmp;
+}
+
+const gchar *
+gsm_util_get_saved_session_dir (void)
+{
+ if (_saved_session_dir == NULL) {
+ gboolean exists;
+
+ _saved_session_dir =
+ g_build_filename (g_get_user_config_dir (),
+ "mate-session",
+ "saved-session",
+ NULL);
+
+ exists = ensure_dir_exists (_saved_session_dir);
+
+ if (G_UNLIKELY (!exists)) {
+ static gboolean printed_warning = FALSE;
+
+ if (!printed_warning) {
+ g_warning ("GsmSessionSave: could not create directory for saved session: %s", _saved_session_dir);
+ printed_warning = TRUE;
+ }
+
+ _saved_session_dir = NULL;
+
+ return NULL;
+ }
+ }
+
+ return _saved_session_dir;
+}
+
+
+char **
+gsm_util_get_autostart_dirs ()
+{
+ GPtrArray *dirs;
+ const char * const *system_config_dirs;
+ const char * const *system_data_dirs;
+ int i;
+
+ dirs = g_ptr_array_new ();
+
+ g_ptr_array_add (dirs,
+ g_build_filename (g_get_user_config_dir (),
+ "autostart", NULL));
+
+ system_data_dirs = g_get_system_data_dirs ();
+ for (i = 0; system_data_dirs[i]; i++) {
+ g_ptr_array_add (dirs,
+ g_build_filename (system_data_dirs[i],
+ "mate", "autostart", NULL));
+ }
+
+ system_config_dirs = g_get_system_config_dirs ();
+ for (i = 0; system_config_dirs[i]; i++) {
+ g_ptr_array_add (dirs,
+ g_build_filename (system_config_dirs[i],
+ "autostart", NULL));
+ }
+
+ g_ptr_array_add (dirs, NULL);
+
+ return (char **) g_ptr_array_free (dirs, FALSE);
+}
+
+char **
+gsm_util_get_app_dirs ()
+{
+ GPtrArray *dirs;
+ const char * const *system_data_dirs;
+ int i;
+
+ dirs = g_ptr_array_new ();
+
+ g_ptr_array_add (dirs,
+ g_build_filename (g_get_user_data_dir (),
+ "applications",
+ NULL));
+
+ system_data_dirs = g_get_system_data_dirs ();
+ for (i = 0; system_data_dirs[i]; i++) {
+ g_ptr_array_add (dirs,
+ g_build_filename (system_data_dirs[i],
+ "applications",
+ NULL));
+ }
+
+ g_ptr_array_add (dirs, NULL);
+
+ return (char **) g_ptr_array_free (dirs, FALSE);
+}
+
+char **
+gsm_util_get_desktop_dirs ()
+{
+ char **apps;
+ char **autostart;
+ char **result;
+ int size;
+ int i;
+
+ apps = gsm_util_get_app_dirs ();
+ autostart = gsm_util_get_autostart_dirs ();
+
+ size = 0;
+ for (i = 0; apps[i] != NULL; i++) { size++; }
+ for (i = 0; autostart[i] != NULL; i++) { size++; }
+ size += 2; /* saved session + last NULL */
+
+ result = g_new (char *, size + 1);
+
+ for (i = 0; apps[i] != NULL; i++) {
+ result[i] = apps[i];
+ }
+ g_free (apps);
+ size = i;
+
+ for (i = 0; autostart[i] != NULL; i++) {
+ result[size + i] = autostart[i];
+ }
+ g_free (autostart);
+ size = size + i;
+
+ result[size] = g_strdup (gsm_util_get_saved_session_dir ());
+ result[size + 1] = NULL;
+
+ return result;
+}
+
+gboolean
+gsm_util_text_is_blank (const char *str)
+{
+ if (str == NULL) {
+ return TRUE;
+ }
+
+ while (*str) {
+ if (!isspace(*str)) {
+ return FALSE;
+ }
+
+ str++;
+ }
+
+ return TRUE;
+}
+
+/**
+ * gsm_util_init_error:
+ * @fatal: whether or not the error is fatal to the login session
+ * @format: printf-style error message format
+ * @...: error message args
+ *
+ * Displays the error message to the user. If @fatal is %TRUE, gsm
+ * will exit after displaying the message.
+ *
+ * This should be called for major errors that occur before the
+ * session is up and running. (Notably, it positions the dialog box
+ * itself, since no window manager will be running yet.)
+ **/
+void
+gsm_util_init_error (gboolean fatal,
+ const char *format, ...)
+{
+ GtkWidget *dialog;
+ char *msg;
+ va_list args;
+
+ va_start (args, format);
+ msg = g_strdup_vprintf (format, args);
+ va_end (args);
+
+ /* If option parsing failed, Gtk won't have been initialized... */
+ if (!gdk_display_get_default ()) {
+ if (!gtk_init_check (NULL, NULL)) {
+ /* Oh well, no X for you! */
+ g_printerr (_("Unable to start login session (and unable to connect to the X server)"));
+ g_printerr ("%s", msg);
+ exit (1);
+ }
+ }
+
+ dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE, "%s", msg);
+
+ g_free (msg);
+
+ gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+
+ gtk_widget_destroy (dialog);
+
+ if (fatal) {
+ gtk_main_quit ();
+ }
+}
+
+/**
+ * gsm_util_generate_startup_id:
+ *
+ * Generates a new SM client ID.
+ *
+ * Return value: an SM client ID.
+ **/
+char *
+gsm_util_generate_startup_id (void)
+{
+ static int sequence = -1;
+ static guint rand1 = 0;
+ static guint rand2 = 0;
+ static pid_t pid = 0;
+ struct timeval tv;
+
+ /* The XSMP spec defines the ID as:
+ *
+ * Version: "1"
+ * Address type and address:
+ * "1" + an IPv4 address as 8 hex digits
+ * "2" + a DECNET address as 12 hex digits
+ * "6" + an IPv6 address as 32 hex digits
+ * Time stamp: milliseconds since UNIX epoch as 13 decimal digits
+ * Process-ID type and process-ID:
+ * "1" + POSIX PID as 10 decimal digits
+ * Sequence number as 4 decimal digits
+ *
+ * XSMP client IDs are supposed to be globally unique: if
+ * SmsGenerateClientID() is unable to determine a network
+ * address for the machine, it gives up and returns %NULL.
+ * MATE and KDE have traditionally used a fourth address
+ * format in this case:
+ * "0" + 16 random hex digits
+ *
+ * We don't even bother trying SmsGenerateClientID(), since the
+ * user's IP address is probably "192.168.1.*" anyway, so a random
+ * number is actually more likely to be globally unique.
+ */
+
+ if (!rand1) {
+ rand1 = g_random_int ();
+ rand2 = g_random_int ();
+ pid = getpid ();
+ }
+
+ sequence = (sequence + 1) % 10000;
+ gettimeofday (&tv, NULL);
+ return g_strdup_printf ("10%.04x%.04x%.10lu%.3u%.10lu%.4d",
+ rand1,
+ rand2,
+ (unsigned long) tv.tv_sec,
+ (unsigned) tv.tv_usec,
+ (unsigned long) pid,
+ sequence);
+}
+
+static gboolean
+gsm_util_update_activation_environment (const char *variable,
+ const char *value,
+ GError **error)
+{
+ DBusGConnection *dbus_connection;
+ DBusGProxy *bus_proxy;
+ GHashTable *environment;
+ gboolean environment_updated;
+
+ environment_updated = FALSE;
+ bus_proxy = NULL;
+ environment = NULL;
+
+ dbus_connection = dbus_g_bus_get (DBUS_BUS_SESSION, error);
+
+ if (dbus_connection == NULL) {
+ return FALSE;
+ }
+
+ bus_proxy = dbus_g_proxy_new_for_name_owner (dbus_connection,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS,
+ error);
+
+ if (bus_proxy == NULL) {
+ goto out;
+ }
+
+ environment = g_hash_table_new (g_str_hash, g_str_equal);
+
+ g_hash_table_insert (environment, (void *) variable, (void *) value);
+
+ if (!dbus_g_proxy_call (bus_proxy,
+ "UpdateActivationEnvironment", error,
+ DBUS_TYPE_G_STRING_STRING_HASHTABLE,
+ environment, G_TYPE_INVALID,
+ G_TYPE_INVALID))
+ goto out;
+
+ environment_updated = TRUE;
+
+ out:
+
+ if (bus_proxy != NULL) {
+ g_object_unref (bus_proxy);
+ }
+
+ if (environment != NULL) {
+ g_hash_table_destroy (environment);
+ }
+
+ return environment_updated;
+}
+
+void
+gsm_util_setenv (const char *variable,
+ const char *value)
+{
+ GError *bus_error;
+
+ g_setenv (variable, value, TRUE);
+
+ bus_error = NULL;
+
+ /* If this fails it isn't fatal, it means some things like session
+ * management and keyring won't work in activated clients.
+ */
+ if (!gsm_util_update_activation_environment (variable, value, &bus_error)) {
+ g_warning ("Could not make bus activated clients aware of %s=%s environment variable: %s", variable, value, bus_error->message);
+ g_error_free (bus_error);
+ }
+}
diff --git a/mate-session/gsm-util.h b/mate-session/gsm-util.h
new file mode 100644
index 0000000..2521f9d
--- /dev/null
+++ b/mate-session/gsm-util.h
@@ -0,0 +1,56 @@
+/* gsm-util.h
+ * Copyright (C) 2008 Lucas Rocha.
+ *
+ * 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
+ * Lesser 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_UTIL_H__
+#define __GSM_UTIL_H__
+
+#include <glib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+char * gsm_util_find_desktop_file_for_app_name (const char *app_name,
+ char **dirs);
+
+gchar *gsm_util_get_empty_tmp_session_dir (void);
+
+const char *gsm_util_get_saved_session_dir (void);
+
+gchar** gsm_util_get_app_dirs (void);
+
+gchar** gsm_util_get_autostart_dirs (void);
+
+gchar ** gsm_util_get_desktop_dirs (void);
+
+gboolean gsm_util_text_is_blank (const char *str);
+
+void gsm_util_init_error (gboolean fatal,
+ const char *format, ...);
+
+char * gsm_util_generate_startup_id (void);
+
+void gsm_util_setenv (const char *variable,
+ const char *value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GSM_UTIL_H__ */
diff --git a/mate-session/gsm-xsmp-client.c b/mate-session/gsm-xsmp-client.c
new file mode 100644
index 0000000..ce0c92f
--- /dev/null
+++ b/mate-session/gsm-xsmp-client.c
@@ -0,0 +1,1332 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Novell, Inc.
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * 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
+ * Lesser 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 <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <gio/gio.h>
+#include <glib/gi18n.h>
+
+#include "gsm-xsmp-client.h"
+#include "gsm-marshal.h"
+
+#include "gsm-util.h"
+#include "gsm-autostart-app.h"
+#include "gsm-manager.h"
+
+#define GsmDesktopFile "_GSM_DesktopFile"
+
+#define IS_STRING_EMPTY(x) ((x)==NULL||(x)[0]=='\0')
+
+#define GSM_XSMP_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_XSMP_CLIENT, GsmXSMPClientPrivate))
+
+struct GsmXSMPClientPrivate
+{
+
+ SmsConn conn;
+ IceConn ice_connection;
+
+ guint watch_id;
+
+ char *description;
+ GPtrArray *props;
+
+ /* SaveYourself state */
+ int current_save_yourself;
+ int next_save_yourself;
+ guint next_save_yourself_allow_interact : 1;
+};
+
+enum {
+ PROP_0,
+ PROP_ICE_CONNECTION
+};
+
+enum {
+ REGISTER_REQUEST,
+ LOGOUT_REQUEST,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (GsmXSMPClient, gsm_xsmp_client, GSM_TYPE_CLIENT)
+
+static gboolean
+client_iochannel_watch (GIOChannel *channel,
+ GIOCondition condition,
+ GsmXSMPClient *client)
+{
+ gboolean keep_going;
+
+ g_object_ref (client);
+ switch (IceProcessMessages (client->priv->ice_connection, NULL, NULL)) {
+ case IceProcessMessagesSuccess:
+ keep_going = TRUE;
+ break;
+
+ case IceProcessMessagesIOError:
+ g_debug ("GsmXSMPClient: IceProcessMessagesIOError on '%s'", client->priv->description);
+ gsm_client_set_status (GSM_CLIENT (client), GSM_CLIENT_FAILED);
+ /* Emitting "disconnected" will eventually cause
+ * IceCloseConnection() to be called.
+ */
+ gsm_client_disconnected (GSM_CLIENT (client));
+ keep_going = FALSE;
+ break;
+
+ case IceProcessMessagesConnectionClosed:
+ g_debug ("GsmXSMPClient: IceProcessMessagesConnectionClosed on '%s'",
+ client->priv->description);
+ client->priv->ice_connection = NULL;
+ keep_going = FALSE;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+ g_object_unref (client);
+
+ return keep_going;
+}
+
+static SmProp *
+find_property (GsmXSMPClient *client,
+ const char *name,
+ int *index)
+{
+ SmProp *prop;
+ int i;
+
+ for (i = 0; i < client->priv->props->len; i++) {
+ prop = client->priv->props->pdata[i];
+
+ if (!strcmp (prop->name, name)) {
+ if (index) {
+ *index = i;
+ }
+ return prop;
+ }
+ }
+
+ return NULL;
+}
+
+static void
+set_description (GsmXSMPClient *client)
+{
+ SmProp *prop;
+ const char *id;
+
+ prop = find_property (client, SmProgram, NULL);
+ id = gsm_client_peek_startup_id (GSM_CLIENT (client));
+
+ g_free (client->priv->description);
+ if (prop) {
+ client->priv->description = g_strdup_printf ("%p [%.*s %s]",
+ client,
+ prop->vals[0].length,
+ (char *)prop->vals[0].value,
+ id);
+ } else if (id != NULL) {
+ client->priv->description = g_strdup_printf ("%p [%s]", client, id);
+ } else {
+ client->priv->description = g_strdup_printf ("%p", client);
+ }
+}
+
+static void
+setup_connection (GsmXSMPClient *client)
+{
+ GIOChannel *channel;
+ int fd;
+
+ g_debug ("GsmXSMPClient: Setting up new connection");
+
+ fd = IceConnectionNumber (client->priv->ice_connection);
+ fcntl (fd, F_SETFD, fcntl (fd, F_GETFD, 0) | FD_CLOEXEC);
+ channel = g_io_channel_unix_new (fd);
+ client->priv->watch_id = g_io_add_watch (channel,
+ G_IO_IN | G_IO_ERR,
+ (GIOFunc)client_iochannel_watch,
+ client);
+ g_io_channel_unref (channel);
+
+ set_description (client);
+
+ g_debug ("GsmXSMPClient: New client '%s'", client->priv->description);
+}
+
+static GObject *
+gsm_xsmp_client_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GsmXSMPClient *client;
+
+ client = GSM_XSMP_CLIENT (G_OBJECT_CLASS (gsm_xsmp_client_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_properties));
+ setup_connection (client);
+
+ return G_OBJECT (client);
+}
+
+static void
+gsm_xsmp_client_init (GsmXSMPClient *client)
+{
+ client->priv = GSM_XSMP_CLIENT_GET_PRIVATE (client);
+
+ client->priv->props = g_ptr_array_new ();
+ client->priv->current_save_yourself = -1;
+ client->priv->next_save_yourself = -1;
+ client->priv->next_save_yourself_allow_interact = FALSE;
+}
+
+
+static void
+delete_property (GsmXSMPClient *client,
+ const char *name)
+{
+ int index;
+ SmProp *prop;
+
+ prop = find_property (client, name, &index);
+ if (!prop) {
+ return;
+ }
+
+#if 0
+ /* This is wrong anyway; we can't unconditionally run the current
+ * discard command; if this client corresponds to a GsmAppResumed,
+ * and the current discard command is identical to the app's
+ * discard_command, then we don't run the discard command now,
+ * because that would delete a saved state we may want to resume
+ * again later.
+ */
+ if (!strcmp (name, SmDiscardCommand)) {
+ gsm_client_run_discard (GSM_CLIENT (client));
+ }
+#endif
+
+ g_ptr_array_remove_index_fast (client->priv->props, index);
+ SmFreeProperty (prop);
+}
+
+
+static void
+debug_print_property (SmProp *prop)
+{
+ GString *tmp;
+ int i;
+
+ switch (prop->type[0]) {
+ case 'C': /* CARD8 */
+ g_debug ("GsmXSMPClient: %s = %d", prop->name, *(unsigned char *)prop->vals[0].value);
+ break;
+
+ case 'A': /* ARRAY8 */
+ g_debug ("GsmXSMPClient: %s = '%s'", prop->name, (char *)prop->vals[0].value);
+ break;
+
+ case 'L': /* LISTofARRAY8 */
+ tmp = g_string_new (NULL);
+ for (i = 0; i < prop->num_vals; i++) {
+ g_string_append_printf (tmp, "'%.*s' ", prop->vals[i].length,
+ (char *)prop->vals[i].value);
+ }
+ g_debug ("GsmXSMPClient: %s = %s", prop->name, tmp->str);
+ g_string_free (tmp, TRUE);
+ break;
+
+ default:
+ g_debug ("GsmXSMPClient: %s = ??? (%s)", prop->name, prop->type);
+ break;
+ }
+}
+
+
+static void
+set_properties_callback (SmsConn conn,
+ SmPointer manager_data,
+ int num_props,
+ SmProp **props)
+{
+ GsmXSMPClient *client = manager_data;
+ int i;
+
+ g_debug ("GsmXSMPClient: Set properties from client '%s'", client->priv->description);
+
+ for (i = 0; i < num_props; i++) {
+ delete_property (client, props[i]->name);
+ g_ptr_array_add (client->priv->props, props[i]);
+
+ debug_print_property (props[i]);
+
+ if (!strcmp (props[i]->name, SmProgram))
+ set_description (client);
+ }
+
+ free (props);
+
+}
+
+static void
+delete_properties_callback (SmsConn conn,
+ SmPointer manager_data,
+ int num_props,
+ char **prop_names)
+{
+ GsmXSMPClient *client = manager_data;
+ int i;
+
+ g_debug ("GsmXSMPClient: Delete properties from '%s'", client->priv->description);
+
+ for (i = 0; i < num_props; i++) {
+ delete_property (client, prop_names[i]);
+
+ g_debug (" %s", prop_names[i]);
+ }
+
+ free (prop_names);
+}
+
+static void
+get_properties_callback (SmsConn conn,
+ SmPointer manager_data)
+{
+ GsmXSMPClient *client = manager_data;
+
+ g_debug ("GsmXSMPClient: Get properties request from '%s'", client->priv->description);
+
+ SmsReturnProperties (conn,
+ client->priv->props->len,
+ (SmProp **)client->priv->props->pdata);
+}
+
+static char *
+prop_to_command (SmProp *prop)
+{
+ GString *str;
+ int i, j;
+ gboolean need_quotes;
+
+ str = g_string_new (NULL);
+ for (i = 0; i < prop->num_vals; i++) {
+ char *val = prop->vals[i].value;
+
+ need_quotes = FALSE;
+ for (j = 0; j < prop->vals[i].length; j++) {
+ if (!g_ascii_isalnum (val[j]) && !strchr ("-_=:./", val[j])) {
+ need_quotes = TRUE;
+ break;
+ }
+ }
+
+ if (i > 0) {
+ g_string_append_c (str, ' ');
+ }
+
+ if (!need_quotes) {
+ g_string_append_printf (str,
+ "%.*s",
+ prop->vals[i].length,
+ (char *)prop->vals[i].value);
+ } else {
+ g_string_append_c (str, '\'');
+ while (val < (char *)prop->vals[i].value + prop->vals[i].length) {
+ if (*val == '\'') {
+ g_string_append (str, "'\''");
+ } else {
+ g_string_append_c (str, *val);
+ }
+ val++;
+ }
+ g_string_append_c (str, '\'');
+ }
+ }
+
+ return g_string_free (str, FALSE);
+}
+
+static char *
+xsmp_get_restart_command (GsmClient *client)
+{
+ SmProp *prop;
+
+ prop = find_property (GSM_XSMP_CLIENT (client), SmRestartCommand, NULL);
+
+ if (!prop || strcmp (prop->type, SmLISTofARRAY8) != 0) {
+ return NULL;
+ }
+
+ return prop_to_command (prop);
+}
+
+static char *
+xsmp_get_discard_command (GsmClient *client)
+{
+ SmProp *prop;
+
+ prop = find_property (GSM_XSMP_CLIENT (client), SmDiscardCommand, NULL);
+
+ if (!prop || strcmp (prop->type, SmLISTofARRAY8) != 0) {
+ return NULL;
+ }
+
+ return prop_to_command (prop);
+}
+
+static void
+do_save_yourself (GsmXSMPClient *client,
+ int save_type,
+ gboolean allow_interact)
+{
+ g_assert (client->priv->conn != NULL);
+
+ if (client->priv->next_save_yourself != -1) {
+ /* Either we're currently doing a shutdown and there's a checkpoint
+ * queued after it, or vice versa. Either way, the new SaveYourself
+ * is redundant.
+ */
+ g_debug ("GsmXSMPClient: skipping redundant SaveYourself for '%s'",
+ client->priv->description);
+ } else if (client->priv->current_save_yourself != -1) {
+ g_debug ("GsmXSMPClient: queuing new SaveYourself for '%s'",
+ client->priv->description);
+ client->priv->next_save_yourself = save_type;
+ client->priv->next_save_yourself_allow_interact = allow_interact;
+ } else {
+ client->priv->current_save_yourself = save_type;
+ /* make sure we don't have anything queued */
+ client->priv->next_save_yourself = -1;
+ client->priv->next_save_yourself_allow_interact = FALSE;
+
+ switch (save_type) {
+ case SmSaveLocal:
+ /* Save state */
+ SmsSaveYourself (client->priv->conn,
+ SmSaveLocal,
+ FALSE,
+ SmInteractStyleNone,
+ FALSE);
+ break;
+
+ default:
+ /* Logout */
+ if (!allow_interact) {
+ SmsSaveYourself (client->priv->conn,
+ save_type, /* save type */
+ TRUE, /* shutdown */
+ SmInteractStyleNone, /* interact style */
+ TRUE); /* fast */
+ } else {
+ SmsSaveYourself (client->priv->conn,
+ save_type, /* save type */
+ TRUE, /* shutdown */
+ SmInteractStyleAny, /* interact style */
+ FALSE /* fast */);
+ }
+ break;
+ }
+ }
+}
+
+static void
+xsmp_save_yourself_phase2 (GsmClient *client)
+{
+ GsmXSMPClient *xsmp = (GsmXSMPClient *) client;
+
+ g_debug ("GsmXSMPClient: xsmp_save_yourself_phase2 ('%s')", xsmp->priv->description);
+
+ SmsSaveYourselfPhase2 (xsmp->priv->conn);
+}
+
+static void
+xsmp_interact (GsmClient *client)
+{
+ GsmXSMPClient *xsmp = (GsmXSMPClient *) client;
+
+ g_debug ("GsmXSMPClient: xsmp_interact ('%s')", xsmp->priv->description);
+
+ SmsInteract (xsmp->priv->conn);
+}
+
+static gboolean
+xsmp_cancel_end_session (GsmClient *client,
+ GError **error)
+{
+ GsmXSMPClient *xsmp = (GsmXSMPClient *) client;
+
+ g_debug ("GsmXSMPClient: xsmp_cancel_end_session ('%s')", xsmp->priv->description);
+
+ if (xsmp->priv->conn == NULL) {
+ g_set_error (error,
+ GSM_CLIENT_ERROR,
+ GSM_CLIENT_ERROR_NOT_REGISTERED,
+ "Client is not registered");
+ return FALSE;
+ }
+
+ SmsShutdownCancelled (xsmp->priv->conn);
+
+ /* reset the state */
+ xsmp->priv->current_save_yourself = -1;
+ xsmp->priv->next_save_yourself = -1;
+ xsmp->priv->next_save_yourself_allow_interact = FALSE;
+
+ return TRUE;
+}
+
+static char *
+get_desktop_file_path (GsmXSMPClient *client)
+{
+ SmProp *prop;
+ char *desktop_file_path = NULL;
+ char **dirs;
+ const char *program_name;
+
+ /* XSMP clients using eggsmclient defines a special property
+ * pointing to their respective desktop entry file */
+ prop = find_property (client, GsmDesktopFile, NULL);
+
+ if (prop) {
+ GFile *file = g_file_new_for_uri (prop->vals[0].value);
+ desktop_file_path = g_file_get_path (file);
+ g_object_unref (file);
+ goto out;
+ }
+
+ /* If we can't get desktop file from GsmDesktopFile then we
+ * try to find the desktop file from its program name */
+ prop = find_property (client, SmProgram, NULL);
+ program_name = prop->vals[0].value;
+
+ dirs = gsm_util_get_autostart_dirs ();
+
+ desktop_file_path =
+ gsm_util_find_desktop_file_for_app_name (program_name,
+ dirs);
+
+ g_strfreev (dirs);
+
+out:
+ g_debug ("GsmXSMPClient: desktop file for client %s is %s",
+ gsm_client_peek_id (GSM_CLIENT (client)),
+ desktop_file_path ? desktop_file_path : "(null)");
+
+ return desktop_file_path;
+}
+
+static void
+set_desktop_file_keys_from_client (GsmClient *client,
+ GKeyFile *keyfile)
+{
+ SmProp *prop;
+ char *name;
+ char *comment;
+
+ prop = find_property (GSM_XSMP_CLIENT (client), SmProgram, NULL);
+ name = g_strdup (prop->vals[0].value);
+
+ comment = g_strdup_printf ("Client %s which was automatically saved",
+ gsm_client_peek_startup_id (client));
+
+ g_key_file_set_string (keyfile,
+ G_KEY_FILE_DESKTOP_GROUP,
+ G_KEY_FILE_DESKTOP_KEY_NAME,
+ name);
+
+ g_key_file_set_string (keyfile,
+ G_KEY_FILE_DESKTOP_GROUP,
+ G_KEY_FILE_DESKTOP_KEY_COMMENT,
+ comment);
+
+ g_key_file_set_string (keyfile,
+ G_KEY_FILE_DESKTOP_GROUP,
+ G_KEY_FILE_DESKTOP_KEY_ICON,
+ "system-run");
+
+ g_key_file_set_string (keyfile,
+ G_KEY_FILE_DESKTOP_GROUP,
+ G_KEY_FILE_DESKTOP_KEY_TYPE,
+ "Application");
+
+ g_key_file_set_boolean (keyfile,
+ G_KEY_FILE_DESKTOP_GROUP,
+ G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY,
+ TRUE);
+
+ g_free (name);
+ g_free (comment);
+}
+
+static GKeyFile *
+create_client_key_file (GsmClient *client,
+ const char *desktop_file_path,
+ GError **error) {
+ GKeyFile *keyfile;
+
+ keyfile = g_key_file_new ();
+
+ if (desktop_file_path != NULL) {
+ g_key_file_load_from_file (keyfile,
+ desktop_file_path,
+ G_KEY_FILE_KEEP_COMMENTS |
+ G_KEY_FILE_KEEP_TRANSLATIONS,
+ error);
+ } else {
+ set_desktop_file_keys_from_client (client, keyfile);
+ }
+
+ return keyfile;
+}
+
+static GsmClientRestartStyle
+xsmp_get_restart_style_hint (GsmClient *client);
+
+static GKeyFile *
+xsmp_save (GsmClient *client,
+ GError **error)
+{
+ GsmClientRestartStyle restart_style;
+
+ GKeyFile *keyfile = NULL;
+ char *desktop_file_path = NULL;
+ char *exec_program = NULL;
+ char *exec_discard = NULL;
+ char *startup_id = NULL;
+ GError *local_error;
+
+ g_debug ("GsmXSMPClient: saving client with id %s",
+ gsm_client_peek_id (client));
+
+ local_error = NULL;
+
+ restart_style = xsmp_get_restart_style_hint (client);
+ if (restart_style == GSM_CLIENT_RESTART_NEVER) {
+ goto out;
+ }
+
+ exec_program = xsmp_get_restart_command (client);
+ if (!exec_program) {
+ goto out;
+ }
+
+ desktop_file_path = get_desktop_file_path (GSM_XSMP_CLIENT (client));
+
+ keyfile = create_client_key_file (client,
+ desktop_file_path,
+ &local_error);
+
+ if (local_error) {
+ goto out;
+ }
+
+ g_object_get (client,
+ "startup-id", &startup_id,
+ NULL);
+
+ g_key_file_set_string (keyfile,
+ G_KEY_FILE_DESKTOP_GROUP,
+ GSM_AUTOSTART_APP_STARTUP_ID_KEY,
+ startup_id);
+
+ g_key_file_set_string (keyfile,
+ G_KEY_FILE_DESKTOP_GROUP,
+ G_KEY_FILE_DESKTOP_KEY_EXEC,
+ exec_program);
+
+ exec_discard = xsmp_get_discard_command (client);
+ if (exec_discard)
+ g_key_file_set_string (keyfile,
+ G_KEY_FILE_DESKTOP_GROUP,
+ GSM_AUTOSTART_APP_DISCARD_KEY,
+ exec_discard);
+
+out:
+ g_free (desktop_file_path);
+ g_free (exec_program);
+ g_free (exec_discard);
+ g_free (startup_id);
+
+ if (local_error != NULL) {
+ g_propagate_error (error, local_error);
+ g_key_file_free (keyfile);
+
+ return NULL;
+ }
+
+ return keyfile;
+}
+
+static gboolean
+xsmp_stop (GsmClient *client,
+ GError **error)
+{
+ GsmXSMPClient *xsmp = (GsmXSMPClient *) client;
+
+ g_debug ("GsmXSMPClient: xsmp_stop ('%s')", xsmp->priv->description);
+
+ if (xsmp->priv->conn == NULL) {
+ g_set_error (error,
+ GSM_CLIENT_ERROR,
+ GSM_CLIENT_ERROR_NOT_REGISTERED,
+ "Client is not registered");
+ return FALSE;
+ }
+
+ SmsDie (xsmp->priv->conn);
+
+ return TRUE;
+}
+
+static gboolean
+xsmp_query_end_session (GsmClient *client,
+ guint flags,
+ GError **error)
+{
+ gboolean allow_interact;
+ int save_type;
+
+ if (GSM_XSMP_CLIENT (client)->priv->conn == NULL) {
+ g_set_error (error,
+ GSM_CLIENT_ERROR,
+ GSM_CLIENT_ERROR_NOT_REGISTERED,
+ "Client is not registered");
+ return FALSE;
+ }
+
+ allow_interact = !(flags & GSM_CLIENT_END_SESSION_FLAG_FORCEFUL);
+
+ /* we don't want to save the session state, but we just want to know if
+ * there's user data the client has to save and we want to give the
+ * client a chance to tell the user about it. This is consistent with
+ * the manager not setting GSM_CLIENT_END_SESSION_FLAG_SAVE for this
+ * phase. */
+ save_type = SmSaveGlobal;
+
+ do_save_yourself (GSM_XSMP_CLIENT (client), save_type, allow_interact);
+ return TRUE;
+}
+
+static gboolean
+xsmp_end_session (GsmClient *client,
+ guint flags,
+ GError **error)
+{
+ gboolean phase2;
+
+ if (GSM_XSMP_CLIENT (client)->priv->conn == NULL) {
+ g_set_error (error,
+ GSM_CLIENT_ERROR,
+ GSM_CLIENT_ERROR_NOT_REGISTERED,
+ "Client is not registered");
+ return FALSE;
+ }
+
+ phase2 = (flags & GSM_CLIENT_END_SESSION_FLAG_LAST);
+
+ if (phase2) {
+ xsmp_save_yourself_phase2 (client);
+ } else {
+ gboolean allow_interact;
+ int save_type;
+
+ /* we gave a chance to interact to the app during
+ * xsmp_query_end_session(), now it's too late to interact */
+ allow_interact = FALSE;
+
+ if (flags & GSM_CLIENT_END_SESSION_FLAG_SAVE) {
+ save_type = SmSaveBoth;
+ } else {
+ save_type = SmSaveGlobal;
+ }
+
+ do_save_yourself (GSM_XSMP_CLIENT (client),
+ save_type, allow_interact);
+ }
+
+ return TRUE;
+}
+
+static char *
+xsmp_get_app_name (GsmClient *client)
+{
+ SmProp *prop;
+ char *name;
+
+ prop = find_property (GSM_XSMP_CLIENT (client), SmProgram, NULL);
+ name = prop_to_command (prop);
+
+ return name;
+}
+
+static void
+gsm_client_set_ice_connection (GsmXSMPClient *client,
+ gpointer conn)
+{
+ client->priv->ice_connection = conn;
+}
+
+static void
+gsm_xsmp_client_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GsmXSMPClient *self;
+
+ self = GSM_XSMP_CLIENT (object);
+
+ switch (prop_id) {
+ case PROP_ICE_CONNECTION:
+ gsm_client_set_ice_connection (self, g_value_get_pointer (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gsm_xsmp_client_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GsmXSMPClient *self;
+
+ self = GSM_XSMP_CLIENT (object);
+
+ switch (prop_id) {
+ case PROP_ICE_CONNECTION:
+ g_value_set_pointer (value, self->priv->ice_connection);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gsm_xsmp_client_disconnect (GsmXSMPClient *client)
+{
+ if (client->priv->watch_id > 0) {
+ g_source_remove (client->priv->watch_id);
+ }
+
+ if (client->priv->conn != NULL) {
+ SmsCleanUp (client->priv->conn);
+ }
+
+ if (client->priv->ice_connection != NULL) {
+ IceSetShutdownNegotiation (client->priv->ice_connection, FALSE);
+ IceCloseConnection (client->priv->ice_connection);
+ }
+}
+
+static void
+gsm_xsmp_client_finalize (GObject *object)
+{
+ GsmXSMPClient *client = (GsmXSMPClient *) object;
+
+ g_debug ("GsmXSMPClient: xsmp_finalize (%s)", client->priv->description);
+ gsm_xsmp_client_disconnect (client);
+
+ g_free (client->priv->description);
+ g_ptr_array_foreach (client->priv->props, (GFunc)SmFreeProperty, NULL);
+ g_ptr_array_free (client->priv->props, TRUE);
+
+ G_OBJECT_CLASS (gsm_xsmp_client_parent_class)->finalize (object);
+}
+
+static gboolean
+_boolean_handled_accumulator (GSignalInvocationHint *ihint,
+ GValue *return_accu,
+ const GValue *handler_return,
+ gpointer dummy)
+{
+ gboolean continue_emission;
+ gboolean signal_handled;
+
+ signal_handled = g_value_get_boolean (handler_return);
+ g_value_set_boolean (return_accu, signal_handled);
+ continue_emission = !signal_handled;
+
+ return continue_emission;
+}
+
+static GsmClientRestartStyle
+xsmp_get_restart_style_hint (GsmClient *client)
+{
+ SmProp *prop;
+ GsmClientRestartStyle hint;
+
+ g_debug ("GsmXSMPClient: getting restart style");
+ hint = GSM_CLIENT_RESTART_IF_RUNNING;
+
+ prop = find_property (GSM_XSMP_CLIENT (client), SmRestartStyleHint, NULL);
+
+ if (!prop || strcmp (prop->type, SmCARD8) != 0) {
+ return GSM_CLIENT_RESTART_IF_RUNNING;
+ }
+
+ switch (((unsigned char *)prop->vals[0].value)[0]) {
+ case SmRestartIfRunning:
+ hint = GSM_CLIENT_RESTART_IF_RUNNING;
+ break;
+ case SmRestartAnyway:
+ hint = GSM_CLIENT_RESTART_ANYWAY;
+ break;
+ case SmRestartImmediately:
+ hint = GSM_CLIENT_RESTART_IMMEDIATELY;
+ break;
+ case SmRestartNever:
+ hint = GSM_CLIENT_RESTART_NEVER;
+ break;
+ default:
+ break;
+ }
+
+ return hint;
+}
+
+static gboolean
+_parse_value_as_uint (const char *value,
+ guint *uintval)
+{
+ char *end_of_valid_uint;
+ gulong ulong_value;
+ guint uint_value;
+
+ errno = 0;
+ ulong_value = strtoul (value, &end_of_valid_uint, 10);
+
+ if (*value == '\0' || *end_of_valid_uint != '\0') {
+ return FALSE;
+ }
+
+ uint_value = ulong_value;
+ if (uint_value != ulong_value || errno == ERANGE) {
+ return FALSE;
+ }
+
+ *uintval = uint_value;
+
+ return TRUE;
+}
+
+static guint
+xsmp_get_unix_process_id (GsmClient *client)
+{
+ SmProp *prop;
+ guint pid;
+ gboolean res;
+
+ g_debug ("GsmXSMPClient: getting pid");
+
+ prop = find_property (GSM_XSMP_CLIENT (client), SmProcessID, NULL);
+
+ if (!prop || strcmp (prop->type, SmARRAY8) != 0) {
+ return 0;
+ }
+
+ pid = 0;
+ res = _parse_value_as_uint ((char *)prop->vals[0].value, &pid);
+ if (! res) {
+ pid = 0;
+ }
+
+ return pid;
+}
+
+static void
+gsm_xsmp_client_class_init (GsmXSMPClientClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GsmClientClass *client_class = GSM_CLIENT_CLASS (klass);
+
+ object_class->finalize = gsm_xsmp_client_finalize;
+ object_class->constructor = gsm_xsmp_client_constructor;
+ object_class->get_property = gsm_xsmp_client_get_property;
+ object_class->set_property = gsm_xsmp_client_set_property;
+
+ client_class->impl_save = xsmp_save;
+ client_class->impl_stop = xsmp_stop;
+ client_class->impl_query_end_session = xsmp_query_end_session;
+ client_class->impl_end_session = xsmp_end_session;
+ client_class->impl_cancel_end_session = xsmp_cancel_end_session;
+ client_class->impl_get_app_name = xsmp_get_app_name;
+ client_class->impl_get_restart_style_hint = xsmp_get_restart_style_hint;
+ client_class->impl_get_unix_process_id = xsmp_get_unix_process_id;
+
+ signals[REGISTER_REQUEST] =
+ g_signal_new ("register-request",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GsmXSMPClientClass, register_request),
+ _boolean_handled_accumulator,
+ NULL,
+ gsm_marshal_BOOLEAN__POINTER,
+ G_TYPE_BOOLEAN,
+ 1, G_TYPE_POINTER);
+ signals[LOGOUT_REQUEST] =
+ g_signal_new ("logout-request",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GsmXSMPClientClass, logout_request),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__BOOLEAN,
+ G_TYPE_NONE,
+ 1, G_TYPE_BOOLEAN);
+
+ g_object_class_install_property (object_class,
+ PROP_ICE_CONNECTION,
+ g_param_spec_pointer ("ice-connection",
+ "ice-connection",
+ "ice-connection",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_type_class_add_private (klass, sizeof (GsmXSMPClientPrivate));
+}
+
+GsmClient *
+gsm_xsmp_client_new (IceConn ice_conn)
+{
+ GsmXSMPClient *xsmp;
+
+ xsmp = g_object_new (GSM_TYPE_XSMP_CLIENT,
+ "ice-connection", ice_conn,
+ NULL);
+
+ return GSM_CLIENT (xsmp);
+}
+
+static Status
+register_client_callback (SmsConn conn,
+ SmPointer manager_data,
+ char *previous_id)
+{
+ GsmXSMPClient *client = manager_data;
+ gboolean handled;
+ char *id;
+
+ g_debug ("GsmXSMPClient: Client '%s' received RegisterClient(%s)",
+ client->priv->description,
+ previous_id ? previous_id : "NULL");
+
+
+ /* There are three cases:
+ * 1. id is NULL - we'll use a new one
+ * 2. id is known - we'll use known one
+ * 3. id is unknown - this is an error
+ */
+ id = g_strdup (previous_id);
+
+ handled = FALSE;
+ g_signal_emit (client, signals[REGISTER_REQUEST], 0, &id, &handled);
+ if (! handled) {
+ g_debug ("GsmXSMPClient: RegisterClient not handled!");
+ g_free (id);
+ free (previous_id);
+ g_assert_not_reached ();
+ return FALSE;
+ }
+
+ if (IS_STRING_EMPTY (id)) {
+ g_debug ("GsmXSMPClient: rejected: invalid previous_id");
+ free (previous_id);
+ return FALSE;
+ }
+
+ g_object_set (client, "startup-id", id, NULL);
+
+ set_description (client);
+
+ g_debug ("GsmXSMPClient: Sending RegisterClientReply to '%s'", client->priv->description);
+
+ SmsRegisterClientReply (conn, id);
+
+ if (IS_STRING_EMPTY (previous_id)) {
+ /* Send the initial SaveYourself. */
+ g_debug ("GsmXSMPClient: Sending initial SaveYourself");
+ SmsSaveYourself (conn, SmSaveLocal, False, SmInteractStyleNone, False);
+ client->priv->current_save_yourself = SmSaveLocal;
+ }
+
+ gsm_client_set_status (GSM_CLIENT (client), GSM_CLIENT_REGISTERED);
+
+ g_free (id);
+ free (previous_id);
+
+ return TRUE;
+}
+
+
+static void
+save_yourself_request_callback (SmsConn conn,
+ SmPointer manager_data,
+ int save_type,
+ Bool shutdown,
+ int interact_style,
+ Bool fast,
+ Bool global)
+{
+ GsmXSMPClient *client = manager_data;
+
+ g_debug ("GsmXSMPClient: Client '%s' received SaveYourselfRequest(%s, %s, %s, %s, %s)",
+ client->priv->description,
+ save_type == SmSaveLocal ? "SmSaveLocal" :
+ save_type == SmSaveGlobal ? "SmSaveGlobal" : "SmSaveBoth",
+ shutdown ? "Shutdown" : "!Shutdown",
+ interact_style == SmInteractStyleAny ? "SmInteractStyleAny" :
+ interact_style == SmInteractStyleErrors ? "SmInteractStyleErrors" :
+ "SmInteractStyleNone", fast ? "Fast" : "!Fast",
+ global ? "Global" : "!Global");
+
+ /* Examining the g_debug above, you can see that there are a total
+ * of 72 different combinations of options that this could have been
+ * called with. However, most of them are stupid.
+ *
+ * If @shutdown and @global are both TRUE, that means the caller is
+ * requesting that a logout message be sent to all clients, so we do
+ * that. We use @fast to decide whether or not to show a
+ * confirmation dialog. (This isn't really what @fast is for, but
+ * the old mate-session and ksmserver both interpret it that way,
+ * so we do too.) We ignore @save_type because we pick the correct
+ * save_type ourselves later based on user prefs, dialog choices,
+ * etc, and we ignore @interact_style, because clients have not used
+ * it correctly consistently enough to make it worth honoring.
+ *
+ * If @shutdown is TRUE and @global is FALSE, the caller is
+ * confused, so we ignore the request.
+ *
+ * If @shutdown is FALSE and @save_type is SmSaveGlobal or
+ * SmSaveBoth, then the client wants us to ask some or all open
+ * applications to save open files to disk, but NOT quit. This is
+ * silly and so we ignore the request.
+ *
+ * If @shutdown is FALSE and @save_type is SmSaveLocal, then the
+ * client wants us to ask some or all open applications to update
+ * their current saved state, but not log out. At the moment, the
+ * code only supports this for the !global case (ie, a client
+ * requesting that it be allowed to update *its own* saved state,
+ * but not having everyone else update their saved state).
+ */
+
+ if (shutdown && global) {
+ g_debug ("GsmXSMPClient: initiating shutdown");
+ g_signal_emit (client, signals[LOGOUT_REQUEST], 0, !fast);
+ } else if (!shutdown && !global) {
+ g_debug ("GsmXSMPClient: initiating checkpoint");
+ do_save_yourself (client, SmSaveLocal, TRUE);
+ } else {
+ g_debug ("GsmXSMPClient: ignoring");
+ }
+}
+
+static void
+save_yourself_phase2_request_callback (SmsConn conn,
+ SmPointer manager_data)
+{
+ GsmXSMPClient *client = manager_data;
+
+ g_debug ("GsmXSMPClient: Client '%s' received SaveYourselfPhase2Request",
+ client->priv->description);
+
+ client->priv->current_save_yourself = -1;
+
+ /* this is a valid response to SaveYourself and therefore
+ may be a response to a QES or ES */
+ gsm_client_end_session_response (GSM_CLIENT (client),
+ TRUE, TRUE, FALSE,
+ NULL);
+}
+
+static void
+interact_request_callback (SmsConn conn,
+ SmPointer manager_data,
+ int dialog_type)
+{
+ GsmXSMPClient *client = manager_data;
+#if 0
+ gboolean res;
+ GError *error;
+#endif
+
+ g_debug ("GsmXSMPClient: Client '%s' received InteractRequest(%s)",
+ client->priv->description,
+ dialog_type == SmDialogNormal ? "Dialog" : "Errors");
+
+ gsm_client_end_session_response (GSM_CLIENT (client),
+ FALSE, FALSE, FALSE,
+ _("This program is blocking logout."));
+
+#if 0
+ /* Can't just call back with Interact because session client
+ grabs the keyboard! So, we try to get it to release
+ grabs by telling it we've cancelled the shutdown.
+ This grabbing is clearly bullshit and is not supported by
+ the client spec or protocol spec.
+ */
+ res = xsmp_cancel_end_session (GSM_CLIENT (client), &error);
+ if (! res) {
+ g_warning ("Unable to cancel end session: %s", error->message);
+ g_error_free (error);
+ }
+#endif
+ xsmp_interact (GSM_CLIENT (client));
+}
+
+static void
+interact_done_callback (SmsConn conn,
+ SmPointer manager_data,
+ Bool cancel_shutdown)
+{
+ GsmXSMPClient *client = manager_data;
+
+ g_debug ("GsmXSMPClient: Client '%s' received InteractDone(cancel_shutdown = %s)",
+ client->priv->description,
+ cancel_shutdown ? "True" : "False");
+
+ gsm_client_end_session_response (GSM_CLIENT (client),
+ TRUE, FALSE, cancel_shutdown,
+ NULL);
+}
+
+static void
+save_yourself_done_callback (SmsConn conn,
+ SmPointer manager_data,
+ Bool success)
+{
+ GsmXSMPClient *client = manager_data;
+
+ g_debug ("GsmXSMPClient: Client '%s' received SaveYourselfDone(success = %s)",
+ client->priv->description,
+ success ? "True" : "False");
+
+ if (client->priv->current_save_yourself != -1) {
+ SmsSaveComplete (client->priv->conn);
+ client->priv->current_save_yourself = -1;
+ }
+
+ /* If success is false then the application couldn't save data. Nothing
+ * the session manager can do about, though. FIXME: we could display a
+ * dialog about this, I guess. */
+ gsm_client_end_session_response (GSM_CLIENT (client),
+ TRUE, FALSE, FALSE,
+ NULL);
+
+ if (client->priv->next_save_yourself) {
+ int save_type = client->priv->next_save_yourself;
+ gboolean allow_interact = client->priv->next_save_yourself_allow_interact;
+
+ client->priv->next_save_yourself = -1;
+ client->priv->next_save_yourself_allow_interact = -1;
+ do_save_yourself (client, save_type, allow_interact);
+ }
+}
+
+static void
+close_connection_callback (SmsConn conn,
+ SmPointer manager_data,
+ int count,
+ char **reason_msgs)
+{
+ GsmXSMPClient *client = manager_data;
+ int i;
+
+ g_debug ("GsmXSMPClient: Client '%s' received CloseConnection", client->priv->description);
+ for (i = 0; i < count; i++) {
+ g_debug ("GsmXSMPClient: close reason: '%s'", reason_msgs[i]);
+ }
+ SmFreeReasons (count, reason_msgs);
+
+ gsm_client_set_status (GSM_CLIENT (client), GSM_CLIENT_FINISHED);
+ gsm_client_disconnected (GSM_CLIENT (client));
+}
+
+void
+gsm_xsmp_client_connect (GsmXSMPClient *client,
+ SmsConn conn,
+ unsigned long *mask_ret,
+ SmsCallbacks *callbacks_ret)
+{
+ client->priv->conn = conn;
+
+ g_debug ("GsmXSMPClient: Initializing client %s", client->priv->description);
+
+ *mask_ret = 0;
+
+ *mask_ret |= SmsRegisterClientProcMask;
+ callbacks_ret->register_client.callback = register_client_callback;
+ callbacks_ret->register_client.manager_data = client;
+
+ *mask_ret |= SmsInteractRequestProcMask;
+ callbacks_ret->interact_request.callback = interact_request_callback;
+ callbacks_ret->interact_request.manager_data = client;
+
+ *mask_ret |= SmsInteractDoneProcMask;
+ callbacks_ret->interact_done.callback = interact_done_callback;
+ callbacks_ret->interact_done.manager_data = client;
+
+ *mask_ret |= SmsSaveYourselfRequestProcMask;
+ callbacks_ret->save_yourself_request.callback = save_yourself_request_callback;
+ callbacks_ret->save_yourself_request.manager_data = client;
+
+ *mask_ret |= SmsSaveYourselfP2RequestProcMask;
+ callbacks_ret->save_yourself_phase2_request.callback = save_yourself_phase2_request_callback;
+ callbacks_ret->save_yourself_phase2_request.manager_data = client;
+
+ *mask_ret |= SmsSaveYourselfDoneProcMask;
+ callbacks_ret->save_yourself_done.callback = save_yourself_done_callback;
+ callbacks_ret->save_yourself_done.manager_data = client;
+
+ *mask_ret |= SmsCloseConnectionProcMask;
+ callbacks_ret->close_connection.callback = close_connection_callback;
+ callbacks_ret->close_connection.manager_data = client;
+
+ *mask_ret |= SmsSetPropertiesProcMask;
+ callbacks_ret->set_properties.callback = set_properties_callback;
+ callbacks_ret->set_properties.manager_data = client;
+
+ *mask_ret |= SmsDeletePropertiesProcMask;
+ callbacks_ret->delete_properties.callback = delete_properties_callback;
+ callbacks_ret->delete_properties.manager_data = client;
+
+ *mask_ret |= SmsGetPropertiesProcMask;
+ callbacks_ret->get_properties.callback = get_properties_callback;
+ callbacks_ret->get_properties.manager_data = client;
+}
+
+void
+gsm_xsmp_client_save_state (GsmXSMPClient *client)
+{
+ g_return_if_fail (GSM_IS_XSMP_CLIENT (client));
+}
diff --git a/mate-session/gsm-xsmp-client.h b/mate-session/gsm-xsmp-client.h
new file mode 100644
index 0000000..20ef3df
--- /dev/null
+++ b/mate-session/gsm-xsmp-client.h
@@ -0,0 +1,93 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Novell, Inc.
+ *
+ * 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
+ * Lesser 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_XSMP_CLIENT_H__
+#define __GSM_XSMP_CLIENT_H__
+
+#include "gsm-client.h"
+
+#include <X11/SM/SMlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GSM_TYPE_XSMP_CLIENT (gsm_xsmp_client_get_type ())
+#define GSM_XSMP_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSM_TYPE_XSMP_CLIENT, GsmXSMPClient))
+#define GSM_XSMP_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSM_TYPE_XSMP_CLIENT, GsmXSMPClientClass))
+#define GSM_IS_XSMP_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSM_TYPE_XSMP_CLIENT))
+#define GSM_IS_XSMP_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSM_TYPE_XSMP_CLIENT))
+#define GSM_XSMP_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSM_TYPE_XSMP_CLIENT, GsmXSMPClientClass))
+
+typedef struct _GsmXSMPClient GsmXSMPClient;
+typedef struct _GsmXSMPClientClass GsmXSMPClientClass;
+
+typedef struct GsmXSMPClientPrivate GsmXSMPClientPrivate;
+
+struct _GsmXSMPClient
+{
+ GsmClient parent;
+ GsmXSMPClientPrivate *priv;
+};
+
+struct _GsmXSMPClientClass
+{
+ GsmClientClass parent_class;
+
+ /* signals */
+ gboolean (*register_request) (GsmXSMPClient *client,
+ char **client_id);
+ gboolean (*logout_request) (GsmXSMPClient *client,
+ gboolean prompt);
+
+
+ void (*saved_state) (GsmXSMPClient *client);
+
+ void (*request_phase2) (GsmXSMPClient *client);
+
+ void (*request_interaction) (GsmXSMPClient *client);
+ void (*interaction_done) (GsmXSMPClient *client,
+ gboolean cancel_shutdown);
+
+ void (*save_yourself_done) (GsmXSMPClient *client);
+
+};
+
+GType gsm_xsmp_client_get_type (void) G_GNUC_CONST;
+
+GsmClient *gsm_xsmp_client_new (IceConn ice_conn);
+
+void gsm_xsmp_client_connect (GsmXSMPClient *client,
+ SmsConn conn,
+ unsigned long *mask_ret,
+ SmsCallbacks *callbacks_ret);
+
+void gsm_xsmp_client_save_state (GsmXSMPClient *client);
+void gsm_xsmp_client_save_yourself (GsmXSMPClient *client,
+ gboolean save_state);
+void gsm_xsmp_client_save_yourself_phase2 (GsmXSMPClient *client);
+void gsm_xsmp_client_interact (GsmXSMPClient *client);
+void gsm_xsmp_client_shutdown_cancelled (GsmXSMPClient *client);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GSM_XSMP_CLIENT_H__ */
diff --git a/mate-session/gsm-xsmp-server.c b/mate-session/gsm-xsmp-server.c
new file mode 100644
index 0000000..1f0e045
--- /dev/null
+++ b/mate-session/gsm-xsmp-server.c
@@ -0,0 +1,732 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Novell, Inc.
+ * Copyright (C) 2008 Red Hat, Inc.
+ * Copyright (C) 2008 William Jon McCann <[email protected]>
+ *
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+
+#include <X11/ICE/ICElib.h>
+#include <X11/ICE/ICEutil.h>
+#include <X11/ICE/ICEconn.h>
+#include <X11/SM/SMlib.h>
+
+#ifdef HAVE_X11_XTRANS_XTRANS_H
+/* Get the proto for _IceTransNoListen */
+#define ICE_t
+#define TRANS_SERVER
+#include <X11/Xtrans/Xtrans.h>
+#undef ICE_t
+#undef TRANS_SERVER
+#endif /* HAVE_X11_XTRANS_XTRANS_H */
+
+#include "gsm-xsmp-server.h"
+#include "gsm-xsmp-client.h"
+#include "gsm-util.h"
+
+/* ICEauthority stuff */
+/* Various magic numbers stolen from iceauth.c */
+#define GSM_ICE_AUTH_RETRIES 10
+#define GSM_ICE_AUTH_INTERVAL 2 /* 2 seconds */
+#define GSM_ICE_AUTH_LOCK_TIMEOUT 600 /* 10 minutes */
+
+#define GSM_ICE_MAGIC_COOKIE_AUTH_NAME "MIT-MAGIC-COOKIE-1"
+#define GSM_ICE_MAGIC_COOKIE_LEN 16
+
+#define GSM_XSMP_SERVER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_XSMP_SERVER, GsmXsmpServerPrivate))
+
+struct GsmXsmpServerPrivate
+{
+ GsmStore *client_store;
+
+ IceListenObj *xsmp_sockets;
+ int num_xsmp_sockets;
+ int num_local_xsmp_sockets;
+
+};
+
+enum {
+ PROP_0,
+ PROP_CLIENT_STORE
+};
+
+static void gsm_xsmp_server_class_init (GsmXsmpServerClass *klass);
+static void gsm_xsmp_server_init (GsmXsmpServer *xsmp_server);
+static void gsm_xsmp_server_finalize (GObject *object);
+
+static gpointer xsmp_server_object = NULL;
+
+G_DEFINE_TYPE (GsmXsmpServer, gsm_xsmp_server, G_TYPE_OBJECT)
+
+typedef struct {
+ GsmXsmpServer *server;
+ IceListenObj listener;
+} GsmIceConnectionData;
+
+typedef struct {
+ guint watch_id;
+ guint protocol_timeout;
+} GsmIceConnectionWatch;
+
+static void
+disconnect_ice_connection (IceConn ice_conn)
+{
+ IceSetShutdownNegotiation (ice_conn, FALSE);
+ IceCloseConnection (ice_conn);
+}
+
+static void
+free_ice_connection_watch (GsmIceConnectionWatch *data)
+{
+ if (data->watch_id) {
+ g_source_remove (data->watch_id);
+ data->watch_id = 0;
+ }
+
+ if (data->protocol_timeout) {
+ g_source_remove (data->protocol_timeout);
+ data->protocol_timeout = 0;
+ }
+
+ g_free (data);
+}
+
+static gboolean
+ice_protocol_timeout (IceConn ice_conn)
+{
+ GsmIceConnectionWatch *data;
+
+ g_debug ("GsmXsmpServer: ice_protocol_timeout for IceConn %p with status %d",
+ ice_conn, IceConnectionStatus (ice_conn));
+
+ data = ice_conn->context;
+
+ free_ice_connection_watch (data);
+ disconnect_ice_connection (ice_conn);
+
+ return FALSE;
+}
+
+static gboolean
+auth_iochannel_watch (GIOChannel *source,
+ GIOCondition condition,
+ IceConn ice_conn)
+{
+
+ GsmIceConnectionWatch *data;
+ gboolean keep_going;
+
+ data = ice_conn->context;
+
+ switch (IceProcessMessages (ice_conn, NULL, NULL)) {
+ case IceProcessMessagesSuccess:
+ keep_going = TRUE;
+ break;
+ case IceProcessMessagesIOError:
+ g_debug ("GsmXsmpServer: IceProcessMessages returned IceProcessMessagesIOError");
+ free_ice_connection_watch (data);
+ disconnect_ice_connection (ice_conn);
+ keep_going = FALSE;
+ break;
+ case IceProcessMessagesConnectionClosed:
+ g_debug ("GsmXsmpServer: IceProcessMessages returned IceProcessMessagesConnectionClosed");
+ free_ice_connection_watch (data);
+ keep_going = FALSE;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ return keep_going;
+}
+
+/* IceAcceptConnection returns a new ICE connection that is in a "pending" state,
+ * this is because authentification may be necessary.
+ * So we've to authenticate it, before accept_xsmp_connection() is called.
+ * Then each GsmXSMPClient will have its own IceConn watcher
+ */
+static void
+auth_ice_connection (IceConn ice_conn)
+{
+ GIOChannel *channel;
+ GsmIceConnectionWatch *data;
+ int fd;
+
+ g_debug ("GsmXsmpServer: auth_ice_connection()");
+
+ fd = IceConnectionNumber (ice_conn);
+ fcntl (fd, F_SETFD, fcntl (fd, F_GETFD, 0) | FD_CLOEXEC);
+ channel = g_io_channel_unix_new (fd);
+
+ data = g_new0 (GsmIceConnectionWatch, 1);
+ ice_conn->context = data;
+
+ data->protocol_timeout = g_timeout_add_seconds (5,
+ (GSourceFunc)ice_protocol_timeout,
+ ice_conn);
+ data->watch_id = g_io_add_watch (channel,
+ G_IO_IN | G_IO_ERR,
+ (GIOFunc)auth_iochannel_watch,
+ ice_conn);
+ g_io_channel_unref (channel);
+}
+
+/* This is called (by glib via xsmp->ice_connection_watch) when a
+ * connection is first received on the ICE listening socket.
+ */
+static gboolean
+accept_ice_connection (GIOChannel *source,
+ GIOCondition condition,
+ GsmIceConnectionData *data)
+{
+ IceConn ice_conn;
+ IceAcceptStatus status;
+
+ g_debug ("GsmXsmpServer: accept_ice_connection()");
+
+ ice_conn = IceAcceptConnection (data->listener, &status);
+ if (status != IceAcceptSuccess) {
+ g_debug ("GsmXsmpServer: IceAcceptConnection returned %d", status);
+ return TRUE;
+ }
+
+ auth_ice_connection (ice_conn);
+
+ return TRUE;
+}
+
+void
+gsm_xsmp_server_start (GsmXsmpServer *server)
+{
+ GIOChannel *channel;
+ int i;
+
+ for (i = 0; i < server->priv->num_local_xsmp_sockets; i++) {
+ GsmIceConnectionData *data;
+
+ data = g_new0 (GsmIceConnectionData, 1);
+ data->server = server;
+ data->listener = server->priv->xsmp_sockets[i];
+
+ channel = g_io_channel_unix_new (IceGetListenConnectionNumber (server->priv->xsmp_sockets[i]));
+ g_io_add_watch_full (channel,
+ G_PRIORITY_DEFAULT,
+ G_IO_IN | G_IO_HUP | G_IO_ERR,
+ (GIOFunc)accept_ice_connection,
+ data,
+ (GDestroyNotify)g_free);
+ g_io_channel_unref (channel);
+ }
+}
+
+static void
+gsm_xsmp_server_set_client_store (GsmXsmpServer *xsmp_server,
+ GsmStore *store)
+{
+ g_return_if_fail (GSM_IS_XSMP_SERVER (xsmp_server));
+
+ if (store != NULL) {
+ g_object_ref (store);
+ }
+
+ if (xsmp_server->priv->client_store != NULL) {
+ g_object_unref (xsmp_server->priv->client_store);
+ }
+
+ xsmp_server->priv->client_store = store;
+}
+
+static void
+gsm_xsmp_server_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GsmXsmpServer *self;
+
+ self = GSM_XSMP_SERVER (object);
+
+ switch (prop_id) {
+ case PROP_CLIENT_STORE:
+ gsm_xsmp_server_set_client_store (self, g_value_get_object (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gsm_xsmp_server_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GsmXsmpServer *self;
+
+ self = GSM_XSMP_SERVER (object);
+
+ switch (prop_id) {
+ case PROP_CLIENT_STORE:
+ g_value_set_object (value, self->priv->client_store);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+/* This is called (by libSM) when XSMP is initiated on an ICE
+ * connection that was already accepted by accept_ice_connection.
+ */
+static Status
+accept_xsmp_connection (SmsConn sms_conn,
+ GsmXsmpServer *server,
+ unsigned long *mask_ret,
+ SmsCallbacks *callbacks_ret,
+ char **failure_reason_ret)
+{
+ IceConn ice_conn;
+ GsmClient *client;
+ GsmIceConnectionWatch *data;
+
+ /* FIXME: what about during shutdown but before gsm_xsmp_shutdown? */
+ if (server->priv->xsmp_sockets == NULL) {
+ g_debug ("GsmXsmpServer: In shutdown, rejecting new client");
+
+ *failure_reason_ret = strdup (_("Refusing new client connection because the session is currently being shut down\n"));
+ return FALSE;
+ }
+
+ ice_conn = SmsGetIceConnection (sms_conn);
+ data = ice_conn->context;
+
+ /* Each GsmXSMPClient has its own IceConn watcher */
+ free_ice_connection_watch (data);
+
+ client = gsm_xsmp_client_new (ice_conn);
+
+ gsm_store_add (server->priv->client_store, gsm_client_peek_id (client), G_OBJECT (client));
+ /* the store will own the ref */
+ g_object_unref (client);
+
+ gsm_xsmp_client_connect (GSM_XSMP_CLIENT (client), sms_conn, mask_ret, callbacks_ret);
+
+ return TRUE;
+}
+
+static void
+ice_error_handler (IceConn conn,
+ Bool swap,
+ int offending_minor_opcode,
+ unsigned long offending_sequence,
+ int error_class,
+ int severity,
+ IcePointer values)
+{
+ g_debug ("GsmXsmpServer: ice_error_handler (%p, %s, %d, %lx, %d, %d)",
+ conn, swap ? "TRUE" : "FALSE", offending_minor_opcode,
+ offending_sequence, error_class, severity);
+
+ if (severity == IceCanContinue) {
+ return;
+ }
+
+ /* FIXME: the ICElib docs are completely vague about what we're
+ * supposed to do in this case. Need to verify that calling
+ * IceCloseConnection() here is guaranteed to cause neither
+ * free-memory-reads nor leaks.
+ */
+ IceCloseConnection (conn);
+}
+
+static void
+ice_io_error_handler (IceConn conn)
+{
+ g_debug ("GsmXsmpServer: ice_io_error_handler (%p)", conn);
+
+ /* We don't need to do anything here; the next call to
+ * IceProcessMessages() for this connection will receive
+ * IceProcessMessagesIOError and we can handle the error there.
+ */
+}
+
+static void
+sms_error_handler (SmsConn conn,
+ Bool swap,
+ int offending_minor_opcode,
+ unsigned long offending_sequence_num,
+ int error_class,
+ int severity,
+ IcePointer values)
+{
+ g_debug ("GsmXsmpServer: sms_error_handler (%p, %s, %d, %lx, %d, %d)",
+ conn, swap ? "TRUE" : "FALSE", offending_minor_opcode,
+ offending_sequence_num, error_class, severity);
+
+ /* We don't need to do anything here; if the connection needs to be
+ * closed, libSM will do that itself.
+ */
+}
+
+static IceAuthFileEntry *
+auth_entry_new (const char *protocol,
+ const char *network_id)
+{
+ IceAuthFileEntry *file_entry;
+ IceAuthDataEntry data_entry;
+
+ file_entry = malloc (sizeof (IceAuthFileEntry));
+
+ file_entry->protocol_name = strdup (protocol);
+ file_entry->protocol_data = NULL;
+ file_entry->protocol_data_length = 0;
+ file_entry->network_id = strdup (network_id);
+ file_entry->auth_name = strdup (GSM_ICE_MAGIC_COOKIE_AUTH_NAME);
+ file_entry->auth_data = IceGenerateMagicCookie (GSM_ICE_MAGIC_COOKIE_LEN);
+ file_entry->auth_data_length = GSM_ICE_MAGIC_COOKIE_LEN;
+
+ /* Also create an in-memory copy, which is what the server will
+ * actually use for checking client auth.
+ */
+ data_entry.protocol_name = file_entry->protocol_name;
+ data_entry.network_id = file_entry->network_id;
+ data_entry.auth_name = file_entry->auth_name;
+ data_entry.auth_data = file_entry->auth_data;
+ data_entry.auth_data_length = file_entry->auth_data_length;
+ IceSetPaAuthData (1, &data_entry);
+
+ return file_entry;
+}
+
+static gboolean
+update_iceauthority (GsmXsmpServer *server,
+ gboolean adding)
+{
+ char *filename;
+ char **our_network_ids;
+ FILE *fp;
+ IceAuthFileEntry *auth_entry;
+ GSList *entries;
+ GSList *e;
+ int i;
+ gboolean ok = FALSE;
+
+ filename = IceAuthFileName ();
+ if (IceLockAuthFile (filename,
+ GSM_ICE_AUTH_RETRIES,
+ GSM_ICE_AUTH_INTERVAL,
+ GSM_ICE_AUTH_LOCK_TIMEOUT) != IceAuthLockSuccess) {
+ return FALSE;
+ }
+
+ our_network_ids = g_malloc (server->priv->num_local_xsmp_sockets * sizeof (char *));
+ for (i = 0; i < server->priv->num_local_xsmp_sockets; i++) {
+ our_network_ids[i] = IceGetListenConnectionString (server->priv->xsmp_sockets[i]);
+ }
+
+ entries = NULL;
+
+ fp = fopen (filename, "r+");
+ if (fp != NULL) {
+ while ((auth_entry = IceReadAuthFileEntry (fp)) != NULL) {
+ /* Skip/delete entries with no network ID (invalid), or with
+ * our network ID; if we're starting up, an entry with our
+ * ID must be a stale entry left behind by an old process,
+ * and if we're shutting down, it won't be valid in the
+ * future, so either way we want to remove it from the list.
+ */
+ if (!auth_entry->network_id) {
+ IceFreeAuthFileEntry (auth_entry);
+ continue;
+ }
+
+ for (i = 0; i < server->priv->num_local_xsmp_sockets; i++) {
+ if (!strcmp (auth_entry->network_id, our_network_ids[i])) {
+ IceFreeAuthFileEntry (auth_entry);
+ break;
+ }
+ }
+ if (i != server->priv->num_local_xsmp_sockets) {
+ continue;
+ }
+
+ entries = g_slist_prepend (entries, auth_entry);
+ }
+
+ rewind (fp);
+ } else {
+ int fd;
+
+ if (g_file_test (filename, G_FILE_TEST_EXISTS)) {
+ g_warning ("Unable to read ICE authority file: %s", filename);
+ goto cleanup;
+ }
+
+ fd = open (filename, O_CREAT | O_WRONLY, 0600);
+ fp = fdopen (fd, "w");
+ if (!fp) {
+ g_warning ("Unable to write to ICE authority file: %s", filename);
+ if (fd != -1) {
+ close (fd);
+ }
+ goto cleanup;
+ }
+ }
+
+ if (adding) {
+ for (i = 0; i < server->priv->num_local_xsmp_sockets; i++) {
+ entries = g_slist_append (entries,
+ auth_entry_new ("ICE", our_network_ids[i]));
+ entries = g_slist_prepend (entries,
+ auth_entry_new ("XSMP", our_network_ids[i]));
+ }
+ }
+
+ for (e = entries; e; e = e->next) {
+ IceAuthFileEntry *auth_entry = e->data;
+ IceWriteAuthFileEntry (fp, auth_entry);
+ IceFreeAuthFileEntry (auth_entry);
+ }
+ g_slist_free (entries);
+
+ fclose (fp);
+ ok = TRUE;
+
+ cleanup:
+ IceUnlockAuthFile (filename);
+ for (i = 0; i < server->priv->num_local_xsmp_sockets; i++) {
+ free (our_network_ids[i]);
+ }
+ g_free (our_network_ids);
+
+ return ok;
+}
+
+
+static void
+setup_listener (GsmXsmpServer *server)
+{
+ char error[256];
+ mode_t saved_umask;
+ char *network_id_list;
+ int i;
+ int res;
+
+ /* Set up sane error handlers */
+ IceSetErrorHandler (ice_error_handler);
+ IceSetIOErrorHandler (ice_io_error_handler);
+ SmsSetErrorHandler (sms_error_handler);
+
+ /* Initialize libSM; we pass NULL for hostBasedAuthProc to disable
+ * host-based authentication.
+ */
+ res = SmsInitialize (PACKAGE,
+ VERSION,
+ (SmsNewClientProc)accept_xsmp_connection,
+ server,
+ NULL,
+ sizeof (error),
+ error);
+ if (! res) {
+ gsm_util_init_error (TRUE, "Could not initialize libSM: %s", error);
+ }
+
+#ifdef HAVE_X11_XTRANS_XTRANS_H
+ /* By default, IceListenForConnections will open one socket for each
+ * transport type known to X. We don't want connections from remote
+ * hosts, so for security reasons it would be best if ICE didn't
+ * even open any non-local sockets. So we use an internal ICElib
+ * method to disable them here. Unfortunately, there is no way to
+ * ask X what transport types it knows about, so we're forced to
+ * guess.
+ */
+ _IceTransNoListen ("tcp");
+#endif
+
+ /* Create the XSMP socket. Older versions of IceListenForConnections
+ * have a bug which causes the umask to be set to 0 on certain types
+ * of failures. Probably not an issue on any modern systems, but
+ * we'll play it safe.
+ */
+ saved_umask = umask (0);
+ umask (saved_umask);
+ res = IceListenForConnections (&server->priv->num_xsmp_sockets,
+ &server->priv->xsmp_sockets,
+ sizeof (error),
+ error);
+ if (! res) {
+ gsm_util_init_error (TRUE, _("Could not create ICE listening socket: %s"), error);
+ }
+
+ umask (saved_umask);
+
+ /* Find the local sockets in the returned socket list and move them
+ * to the start of the list.
+ */
+ for (i = server->priv->num_local_xsmp_sockets = 0; i < server->priv->num_xsmp_sockets; i++) {
+ char *id = IceGetListenConnectionString (server->priv->xsmp_sockets[i]);
+
+ if (!strncmp (id, "local/", sizeof ("local/") - 1) ||
+ !strncmp (id, "unix/", sizeof ("unix/") - 1)) {
+ if (i > server->priv->num_local_xsmp_sockets) {
+ IceListenObj tmp;
+ tmp = server->priv->xsmp_sockets[i];
+ server->priv->xsmp_sockets[i] = server->priv->xsmp_sockets[server->priv->num_local_xsmp_sockets];
+ server->priv->xsmp_sockets[server->priv->num_local_xsmp_sockets] = tmp;
+ }
+ server->priv->num_local_xsmp_sockets++;
+ }
+ free (id);
+ }
+
+ if (server->priv->num_local_xsmp_sockets == 0) {
+ gsm_util_init_error (TRUE, "IceListenForConnections did not return a local listener!");
+ }
+
+#ifdef HAVE_X11_XTRANS_XTRANS_H
+ if (server->priv->num_local_xsmp_sockets != server->priv->num_xsmp_sockets) {
+ /* Xtrans was apparently compiled with support for some
+ * non-local transport besides TCP (which we disabled above); we
+ * won't create IO watches on those extra sockets, so
+ * connections to them will never be noticed, but they're still
+ * there, which is inelegant.
+ *
+ * If the g_warning below is triggering for you and you want to
+ * stop it, the fix is to add additional _IceTransNoListen()
+ * calls above.
+ */
+ network_id_list = IceComposeNetworkIdList (server->priv->num_xsmp_sockets - server->priv->num_local_xsmp_sockets,
+ server->priv->xsmp_sockets + server->priv->num_local_xsmp_sockets);
+ g_warning ("IceListenForConnections returned %d non-local listeners: %s",
+ server->priv->num_xsmp_sockets - server->priv->num_local_xsmp_sockets,
+ network_id_list);
+ free (network_id_list);
+ }
+#endif
+
+ /* Update .ICEauthority with new auth entries for our socket */
+ if (!update_iceauthority (server, TRUE)) {
+ /* FIXME: is this really fatal? Hm... */
+ gsm_util_init_error (TRUE,
+ "Could not update ICEauthority file %s",
+ IceAuthFileName ());
+ }
+
+ network_id_list = IceComposeNetworkIdList (server->priv->num_local_xsmp_sockets,
+ server->priv->xsmp_sockets);
+
+ gsm_util_setenv ("SESSION_MANAGER", network_id_list);
+ g_debug ("GsmXsmpServer: SESSION_MANAGER=%s\n", network_id_list);
+ free (network_id_list);
+}
+
+static GObject *
+gsm_xsmp_server_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GsmXsmpServer *xsmp_server;
+
+ xsmp_server = GSM_XSMP_SERVER (G_OBJECT_CLASS (gsm_xsmp_server_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_properties));
+ setup_listener (xsmp_server);
+
+ return G_OBJECT (xsmp_server);
+}
+
+static void
+gsm_xsmp_server_class_init (GsmXsmpServerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->get_property = gsm_xsmp_server_get_property;
+ object_class->set_property = gsm_xsmp_server_set_property;
+ object_class->constructor = gsm_xsmp_server_constructor;
+ object_class->finalize = gsm_xsmp_server_finalize;
+
+ g_object_class_install_property (object_class,
+ PROP_CLIENT_STORE,
+ g_param_spec_object ("client-store",
+ NULL,
+ NULL,
+ GSM_TYPE_STORE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_type_class_add_private (klass, sizeof (GsmXsmpServerPrivate));
+}
+
+static void
+gsm_xsmp_server_init (GsmXsmpServer *xsmp_server)
+{
+ xsmp_server->priv = GSM_XSMP_SERVER_GET_PRIVATE (xsmp_server);
+
+}
+
+static void
+gsm_xsmp_server_finalize (GObject *object)
+{
+ GsmXsmpServer *xsmp_server;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GSM_IS_XSMP_SERVER (object));
+
+ xsmp_server = GSM_XSMP_SERVER (object);
+
+ g_return_if_fail (xsmp_server->priv != NULL);
+
+ IceFreeListenObjs (xsmp_server->priv->num_xsmp_sockets,
+ xsmp_server->priv->xsmp_sockets);
+
+ if (xsmp_server->priv->client_store != NULL) {
+ g_object_unref (xsmp_server->priv->client_store);
+ }
+
+ G_OBJECT_CLASS (gsm_xsmp_server_parent_class)->finalize (object);
+}
+
+GsmXsmpServer *
+gsm_xsmp_server_new (GsmStore *client_store)
+{
+ if (xsmp_server_object != NULL) {
+ g_object_ref (xsmp_server_object);
+ } else {
+ xsmp_server_object = g_object_new (GSM_TYPE_XSMP_SERVER,
+ "client-store", client_store,
+ NULL);
+
+ g_object_add_weak_pointer (xsmp_server_object,
+ (gpointer *) &xsmp_server_object);
+ }
+
+ return GSM_XSMP_SERVER (xsmp_server_object);
+}
diff --git a/mate-session/gsm-xsmp-server.h b/mate-session/gsm-xsmp-server.h
new file mode 100644
index 0000000..afefa4e
--- /dev/null
+++ b/mate-session/gsm-xsmp-server.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 William Jon McCann <[email protected]>
+ *
+ * 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_XSMP_SERVER_H
+#define __GSM_XSMP_SERVER_H
+
+#include <glib-object.h>
+
+#include "gsm-store.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GSM_TYPE_XSMP_SERVER (gsm_xsmp_server_get_type ())
+#define GSM_XSMP_SERVER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSM_TYPE_XSMP_SERVER, GsmXsmpServer))
+#define GSM_XSMP_SERVER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GSM_TYPE_XSMP_SERVER, GsmXsmpServerClass))
+#define GSM_IS_XSMP_SERVER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSM_TYPE_XSMP_SERVER))
+#define GSM_IS_XSMP_SERVER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSM_TYPE_XSMP_SERVER))
+#define GSM_XSMP_SERVER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSM_TYPE_XSMP_SERVER, GsmXsmpServerClass))
+
+typedef struct GsmXsmpServerPrivate GsmXsmpServerPrivate;
+
+typedef struct
+{
+ GObject parent;
+ GsmXsmpServerPrivate *priv;
+} GsmXsmpServer;
+
+typedef struct
+{
+ GObjectClass parent_class;
+} GsmXsmpServerClass;
+
+GType gsm_xsmp_server_get_type (void);
+
+GsmXsmpServer * gsm_xsmp_server_new (GsmStore *client_store);
+void gsm_xsmp_server_start (GsmXsmpServer *server);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GSM_XSMP_SERVER_H */
diff --git a/mate-session/main.c b/mate-session/main.c
new file mode 100644
index 0000000..2d7dd64
--- /dev/null
+++ b/mate-session/main.c
@@ -0,0 +1,543 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2006 Novell, Inc.
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * 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
+ * Lesser 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 <libintl.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <glib/gi18n.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-bindings.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include "mdm-signal-handler.h"
+#include "mdm-log.h"
+
+#include "gsm-consolekit.h"
+#include "gsm-mateconf.h"
+#include "gsm-util.h"
+#include "gsm-manager.h"
+#include "gsm-xsmp-server.h"
+#include "gsm-store.h"
+
+#define GSM_MATECONF_DEFAULT_SESSION_KEY "/desktop/mate/session/default_session"
+#define GSM_MATECONF_REQUIRED_COMPONENTS_DIRECTORY "/desktop/mate/session/required_components"
+#define GSM_MATECONF_REQUIRED_COMPONENTS_LIST_KEY "/desktop/mate/session/required_components_list"
+
+#define GSM_DBUS_NAME "org.mate.SessionManager"
+
+#define IS_STRING_EMPTY(x) \
+ ((x) == NULL || (x)[0] == '\0')
+
+static gboolean failsafe = FALSE;
+static gboolean show_version = FALSE;
+static gboolean debug = FALSE;
+
+static void on_bus_name_lost(DBusGProxy* bus_proxy, const char* name, gpointer data)
+{
+ g_warning("Lost name on bus: %s, exiting", name);
+ exit(1);
+}
+
+static gboolean acquire_name_on_proxy(DBusGProxy* bus_proxy, const char* name)
+{
+ GError* error;
+ guint result;
+ gboolean res;
+ gboolean ret;
+
+ ret = FALSE;
+
+ if (bus_proxy == NULL)
+ {
+ goto out;
+ }
+
+ error = NULL;
+ res = dbus_g_proxy_call(bus_proxy, "RequestName", &error, G_TYPE_STRING, name, G_TYPE_UINT, 0, G_TYPE_INVALID, G_TYPE_UINT, &result, G_TYPE_INVALID);
+
+ if (! res)
+ {
+ if (error != NULL)
+ {
+ g_warning("Failed to acquire %s: %s", name, error->message);
+ g_error_free(error);
+ }
+ else
+ {
+ g_warning ("Failed to acquire %s", name);
+ }
+
+ goto out;
+ }
+
+ if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
+ {
+ if (error != NULL)
+ {
+ g_warning("Failed to acquire %s: %s", name, error->message);
+ g_error_free(error);
+ }
+ else
+ {
+ g_warning("Failed to acquire %s", name);
+ }
+
+ goto out;
+ }
+
+ /* register for name lost */
+ dbus_g_proxy_add_signal(bus_proxy, "NameLost", G_TYPE_STRING, G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal(bus_proxy, "NameLost", G_CALLBACK(on_bus_name_lost), NULL, NULL);
+
+ ret = TRUE;
+
+ out:
+
+ return ret;
+}
+
+static gboolean acquire_name(void)
+{
+ DBusGProxy* bus_proxy;
+ GError* error;
+ DBusGConnection* connection;
+
+ error = NULL;
+ connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
+
+ if (connection == NULL)
+ {
+ gsm_util_init_error(TRUE, "Could not connect to session bus: %s", error->message);
+ /* not reached */
+ }
+
+ bus_proxy = dbus_g_proxy_new_for_name(connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
+
+ if (!acquire_name_on_proxy(bus_proxy, GSM_DBUS_NAME))
+ {
+ gsm_util_init_error(TRUE, "%s", "Could not acquire name on session bus");
+ /* not reached */
+ }
+
+ g_object_unref(bus_proxy);
+
+ return TRUE;
+}
+
+/* This doesn't contain the required components, so we need to always
+ * call append_required_apps() after a call to append_default_apps(). */
+static void append_default_apps(GsmManager* manager, const char* default_session_key, char** autostart_dirs)
+{
+ GSList* default_apps;
+ GSList* a;
+ MateConfClient* client;
+
+ g_debug("main: *** Adding default apps");
+
+ g_assert(default_session_key != NULL);
+ g_assert(autostart_dirs != NULL);
+
+ client = mateconf_client_get_default();
+ default_apps = mateconf_client_get_list(client, default_session_key, MATECONF_VALUE_STRING, NULL);
+ g_object_unref(client);
+
+ for (a = default_apps; a; a = a->next)
+ {
+ char* app_path;
+
+ if (IS_STRING_EMPTY((char*) a->data))
+ {
+ continue;
+ }
+
+ app_path = gsm_util_find_desktop_file_for_app_name(a->data, autostart_dirs);
+
+ if (app_path != NULL)
+ {
+ gsm_manager_add_autostart_app(manager, app_path, NULL);
+ g_free(app_path);
+ }
+ }
+
+ g_slist_foreach(default_apps, (GFunc) g_free, NULL);
+ g_slist_free(default_apps);
+}
+
+static void append_required_apps(GsmManager* manager)
+{
+ GSList* required_components;
+ GSList* r;
+ MateConfClient* client;
+
+ g_debug("main: *** Adding required apps");
+
+ client = mateconf_client_get_default();
+ required_components = mateconf_client_get_list(client, GSM_MATECONF_REQUIRED_COMPONENTS_LIST_KEY, MATECONF_VALUE_STRING, NULL);
+
+ if (required_components == NULL)
+ {
+ g_warning("No required applications specified");
+ }
+
+ for (r = required_components; r != NULL; r = r->next)
+ {
+ char* path;
+ char* default_provider;
+ const char* component;
+
+ if (IS_STRING_EMPTY((char*) r->data))
+ {
+ continue;
+ }
+
+ component = r->data;
+
+ path = g_strdup_printf("%s/%s", GSM_MATECONF_REQUIRED_COMPONENTS_DIRECTORY, component);
+
+ default_provider = mateconf_client_get_string(client, path, NULL);
+
+ g_debug ("main: %s looking for component: '%s'", path, default_provider);
+
+ if (default_provider != NULL)
+ {
+ char* app_path;
+
+ app_path = gsm_util_find_desktop_file_for_app_name(default_provider, NULL);
+
+ if (app_path != NULL)
+ {
+ gsm_manager_add_autostart_app(manager, app_path, component);
+ }
+ else
+ {
+ g_warning("Unable to find provider '%s' of required component '%s'", default_provider, component);
+ }
+
+ g_free(app_path);
+ }
+
+ g_free(default_provider);
+ g_free(path);
+ }
+
+ g_debug("main: *** Done adding required apps");
+
+ g_slist_foreach(required_components, (GFunc) g_free, NULL);
+ g_slist_free(required_components);
+
+ g_object_unref(client);
+}
+
+static void maybe_load_saved_session_apps(GsmManager* manager)
+{
+ GsmConsolekit* consolekit;
+ char* session_type;
+
+ consolekit = gsm_get_consolekit();
+ session_type = gsm_consolekit_get_current_session_type(consolekit);
+
+ if (g_strcmp0 (session_type, GSM_CONSOLEKIT_SESSION_TYPE_LOGIN_WINDOW) != 0)
+ {
+ gsm_manager_add_autostart_apps_from_dir(manager, gsm_util_get_saved_session_dir());
+ }
+
+ g_object_unref(consolekit);
+ g_free(session_type);
+}
+
+static void load_standard_apps (GsmManager* manager, const char* default_session_key)
+{
+ char** autostart_dirs;
+ int i;
+
+ autostart_dirs = gsm_util_get_autostart_dirs();
+
+ if (!failsafe)
+ {
+ maybe_load_saved_session_apps(manager);
+
+ for (i = 0; autostart_dirs[i]; i++)
+ {
+ gsm_manager_add_autostart_apps_from_dir(manager, autostart_dirs[i]);
+ }
+ }
+
+ /* We do this at the end in case a saved session contains an
+ * application that already provides one of the components. */
+ append_default_apps(manager, default_session_key, autostart_dirs);
+ append_required_apps(manager);
+
+ g_strfreev(autostart_dirs);
+}
+
+static void load_override_apps(GsmManager* manager, char** override_autostart_dirs)
+{
+ int i;
+
+ for (i = 0; override_autostart_dirs[i]; i++)
+ {
+ gsm_manager_add_autostart_apps_from_dir(manager, override_autostart_dirs[i]);
+ }
+}
+
+static gboolean signal_cb(int signo, gpointer data)
+{
+ int ret;
+ GsmManager* manager;
+
+ g_debug("Got callback for signal %d", signo);
+
+ ret = TRUE;
+
+ switch (signo)
+ {
+ case SIGFPE:
+ case SIGPIPE:
+ /* let the fatal signals interrupt us */
+ g_debug ("Caught signal %d, shutting down abnormally.", signo);
+ ret = FALSE;
+ break;
+ case SIGINT:
+ case SIGTERM:
+ manager = (GsmManager*) data;
+ gsm_manager_logout(manager, GSM_MANAGER_LOGOUT_MODE_FORCE, NULL);
+
+ /* let the fatal signals interrupt us */
+ g_debug("Caught signal %d, shutting down normally.", signo);
+ ret = TRUE;
+ break;
+ case SIGHUP:
+ g_debug("Got HUP signal");
+ ret = TRUE;
+ break;
+ case SIGUSR1:
+ g_debug("Got USR1 signal");
+ ret = TRUE;
+ mdm_log_toggle_debug();
+ break;
+ default:
+ g_debug("Caught unhandled signal %d", signo);
+ ret = TRUE;
+
+ break;
+ }
+
+ return ret;
+}
+
+static void shutdown_cb(gpointer data)
+{
+ GsmManager* manager = (GsmManager*) data;
+ g_debug("Calling shutdown callback function");
+
+ /*
+ * When the signal handler gets a shutdown signal, it calls
+ * this function to inform GsmManager to not restart
+ * applications in the off chance a handler is already queued
+ * to dispatch following the below call to gtk_main_quit.
+ */
+ gsm_manager_set_phase(manager, GSM_MANAGER_PHASE_EXIT);
+
+ gtk_main_quit();
+}
+
+static gboolean require_dbus_session(int argc, char** argv, GError** error)
+{
+ char** new_argv;
+ int i;
+
+ if (g_getenv("DBUS_SESSION_BUS_ADDRESS"))
+ {
+ return TRUE;
+ }
+
+ /* Just a sanity check to prevent infinite recursion if
+ * dbus-launch fails to set DBUS_SESSION_BUS_ADDRESS
+ */
+ g_return_val_if_fail(!g_str_has_prefix(argv[0], "dbus-launch"), TRUE);
+
+ /* +2 for our new arguments, +1 for NULL */
+ new_argv = g_malloc(argc + 3 * sizeof (*argv));
+
+ new_argv[0] = "dbus-launch";
+ new_argv[1] = "--exit-with-session";
+
+ for (i = 0; i < argc; i++)
+ {
+ new_argv[i + 2] = argv[i];
+ }
+
+ new_argv[i + 2] = NULL;
+
+ if (!execvp("dbus-launch", new_argv))
+ {
+ g_set_error(error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, "No session bus and could not exec dbus-launch: %s", g_strerror(errno));
+ return FALSE;
+ }
+
+ /* Should not be reached */
+ return TRUE;
+}
+
+int main(int argc, char** argv)
+{
+ struct sigaction sa;
+ GError* error;
+ char* display_str;
+ GsmManager* manager;
+ GsmStore* client_store;
+ GsmXsmpServer* xsmp_server;
+ MdmSignalHandler* signal_handler;
+ static char** override_autostart_dirs = NULL;
+ static char* default_session_key = NULL;
+
+ static GOptionEntry entries[] = {
+ {"autostart", 'a', 0, G_OPTION_ARG_STRING_ARRAY, &override_autostart_dirs, N_("Override standard autostart directories"), NULL},
+ {"default-session-key", 0, 0, G_OPTION_ARG_STRING, &default_session_key, N_("MateConf key used to look up default session"), NULL},
+ {"debug", 0, 0, G_OPTION_ARG_NONE, &debug, N_("Enable debugging code"), NULL},
+ {"failsafe", 'f', 0, G_OPTION_ARG_NONE, &failsafe, N_("Do not load user-specified applications"), NULL},
+ {"version", 0, 0, G_OPTION_ARG_NONE, &show_version, N_("Version of this application"), NULL},
+ {NULL, 0, 0, 0, NULL, NULL, NULL }
+ };
+
+ /* Make sure that we have a session bus */
+ if (!require_dbus_session(argc, argv, &error))
+ {
+ gsm_util_init_error(TRUE, "%s", error->message);
+ }
+
+ bindtextdomain(GETTEXT_PACKAGE, LOCALE_DIR);
+ bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
+ textdomain(GETTEXT_PACKAGE);
+
+ sa.sa_handler = SIG_IGN;
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+ sigaction(SIGPIPE, &sa, 0);
+
+ error = NULL;
+ gtk_init_with_args(&argc, &argv, (char*) _(" - the MATE session manager"), entries, GETTEXT_PACKAGE, &error);
+
+ if (error != NULL)
+ {
+ g_warning("%s", error->message);
+ exit(1);
+ }
+
+ if (show_version)
+ {
+ g_print("%s %s\n", argv [0], VERSION);
+ exit(1);
+ }
+
+ mdm_log_init();
+ mdm_log_set_debug(debug);
+
+ /* Set DISPLAY explicitly for all our children, in case --display
+ * was specified on the command line.
+ */
+ display_str = gdk_get_display();
+ gsm_util_setenv("DISPLAY", display_str);
+ g_free(display_str);
+
+ /* Some third-party programs rely on MATE_DESKTOP_SESSION_ID to
+ * detect if MATE is running. We keep this for compatibility reasons.
+ */
+ gsm_util_setenv("MATE_DESKTOP_SESSION_ID", "this-is-deprecated");
+
+ client_store = gsm_store_new();
+
+
+ /* Start up mateconfd if not already running. */
+ gsm_mateconf_init();
+
+ xsmp_server = gsm_xsmp_server_new(client_store);
+
+ /* Now make sure they succeeded. (They'll call
+ * gsm_util_init_error() if they failed.)
+ */
+ gsm_mateconf_check();
+ acquire_name();
+
+ manager = gsm_manager_new(client_store, failsafe);
+
+ signal_handler = mdm_signal_handler_new();
+ mdm_signal_handler_add_fatal(signal_handler);
+ mdm_signal_handler_add(signal_handler, SIGFPE, signal_cb, NULL);
+ mdm_signal_handler_add(signal_handler, SIGHUP, signal_cb, NULL);
+ mdm_signal_handler_add(signal_handler, SIGUSR1, signal_cb, NULL);
+ mdm_signal_handler_add(signal_handler, SIGTERM, signal_cb, manager);
+ mdm_signal_handler_add(signal_handler, SIGINT, signal_cb, manager);
+ mdm_signal_handler_set_fatal_func(signal_handler, shutdown_cb, manager);
+
+ if (override_autostart_dirs != NULL)
+ {
+ load_override_apps(manager, override_autostart_dirs);
+ }
+ else
+ {
+ if (!IS_STRING_EMPTY(default_session_key))
+ {
+ load_standard_apps(manager, default_session_key);
+ }
+ else
+ {
+ load_standard_apps(manager, GSM_MATECONF_DEFAULT_SESSION_KEY);
+ }
+ }
+
+ gsm_xsmp_server_start(xsmp_server);
+ gsm_manager_start(manager);
+
+ gtk_main();
+
+ if (xsmp_server != NULL)
+ {
+ g_object_unref(xsmp_server);
+ }
+
+ if (manager != NULL)
+ {
+ g_debug("Unreffing manager");
+ g_object_unref(manager);
+ }
+
+ if (client_store != NULL)
+ {
+ g_object_unref(client_store);
+ }
+
+ gsm_mateconf_shutdown();
+
+ mdm_log_shutdown();
+
+ return 0;
+}
diff --git a/mate-session/mdm-log.c b/mate-session/mdm-log.c
new file mode 100644
index 0000000..ba384bb
--- /dev/null
+++ b/mate-session/mdm-log.c
@@ -0,0 +1,206 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU G