From ae39f7001e5603010afc02de29787ade6d48ef14 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Fri, 22 Mar 2013 16:34:34 -0500 Subject: port indicator-session to GMenu/cmake. Code coverage increased from 0% to 95.4%. --- AUTHORS | 2 - ChangeLog | 2 - INSTALL | 72 ++ Makefile.am | 43 - Makefile.am.coverage | 48 - README | 47 + autogen.sh | 11 - configure.ac | 231 ---- m4/gcov.m4 | 86 -- m4/gtest.m4 | 63 - src/CMakeLists.txt | 19 + src/Makefile.am | 207 ---- src/actions.c | 383 ++++++ src/actions.h | 129 ++ src/backend-dbus/CMakeLists.txt | 86 ++ src/backend-dbus/actions.c | 730 ++++++++++++ src/backend-dbus/actions.h | 73 ++ src/backend-dbus/backend-dbus.c | 117 ++ src/backend-dbus/backend-dbus.h | 38 + .../com.canonical.indicators.webcredentials.xml | 82 ++ src/backend-dbus/display-manager.xml | 30 + src/backend-dbus/guest.c | 570 +++++++++ src/backend-dbus/guest.h | 72 ++ src/backend-dbus/org.freedesktop.Accounts.User.xml | 744 ++++++++++++ src/backend-dbus/org.freedesktop.Accounts.xml | 194 ++++ .../org.freedesktop.ConsoleKit.Manager.xml | 353 ++++++ .../org.freedesktop.ConsoleKit.Seat.xml | 164 +++ .../org.freedesktop.ConsoleKit.Session.xml | 435 +++++++ src/backend-dbus/org.gnome.ScreenSaver.xml | 16 + .../org.gnome.SessionManager.EndSessionDialog.xml | 53 + src/backend-dbus/org.gnome.SessionManager.xml | 451 +++++++ src/backend-dbus/session-dbus.xml | 20 + src/backend-dbus/upower.xml | 309 +++++ src/backend-dbus/users.c | 810 +++++++++++++ src/backend-dbus/users.h | 71 ++ src/backend-dbus/utils.c | 399 +++++++ src/backend-dbus/utils.h | 53 + src/backend.h | 47 + src/dialog.c | 248 ---- src/dialog.h | 64 - src/display-manager.xml | 30 - src/gtk-logout-helper.c | 266 ----- src/guest.c | 190 +++ src/guest.h | 82 ++ src/indicator-session.c | 495 -------- src/main.c | 87 ++ src/online-accounts-mgr.c | 166 --- src/online-accounts-mgr.h | 50 - src/org.freedesktop.Accounts.User.xml | 744 ------------ src/org.freedesktop.Accounts.xml | 194 ---- src/org.freedesktop.ConsoleKit.Manager.xml | 353 ------ src/org.freedesktop.ConsoleKit.Seat.xml | 164 --- src/org.freedesktop.ConsoleKit.Session.xml | 435 ------- src/service.c | 1192 +++++++++++++++++++ src/service.h | 64 + src/session-dbus.c | 282 ----- src/session-dbus.h | 56 - src/session-dbus.xml | 20 - src/session-menu-mgr.c | 1226 -------------------- src/session-menu-mgr.h | 55 - src/session-service.c | 96 -- src/shared-names.h | 52 - src/upower.xml | 309 ----- src/user-widget.c | 292 ----- src/user-widget.h | 55 - src/users-service-dbus.c | 1044 ----------------- src/users-service-dbus.h | 97 -- src/users.c | 198 ++++ src/users.h | 146 +++ tests/CMakeLists.txt | 53 + tests/Makefile.am | 51 - tests/Makefile.am.strings | 38 - tests/backend-dbus/CMakeLists.txt | 62 + tests/backend-dbus/gtest-mock-dbus-fixture.h | 130 +++ tests/backend-dbus/mock-accounts.cc | 156 +++ tests/backend-dbus/mock-accounts.h | 74 ++ tests/backend-dbus/mock-consolekit-manager.cc | 156 +++ tests/backend-dbus/mock-consolekit-manager.h | 77 ++ tests/backend-dbus/mock-consolekit-seat.cc | 220 ++++ tests/backend-dbus/mock-consolekit-seat.h | 75 ++ tests/backend-dbus/mock-consolekit-session.cc | 113 ++ tests/backend-dbus/mock-consolekit-session.h | 65 ++ tests/backend-dbus/mock-display-manager-seat.cc | 140 +++ tests/backend-dbus/mock-display-manager-seat.h | 72 ++ tests/backend-dbus/mock-end-session-dialog.cc | 89 ++ tests/backend-dbus/mock-end-session-dialog.h | 67 ++ tests/backend-dbus/mock-object.cc | 122 ++ tests/backend-dbus/mock-object.h | 62 + tests/backend-dbus/mock-screen-saver.cc | 71 ++ tests/backend-dbus/mock-screen-saver.h | 53 + tests/backend-dbus/mock-session-manager.cc | 66 ++ tests/backend-dbus/mock-session-manager.h | 50 + tests/backend-dbus/mock-upower.cc | 103 ++ tests/backend-dbus/mock-upower.h | 72 ++ tests/backend-dbus/mock-user.cc | 131 +++ tests/backend-dbus/mock-user.h | 57 + tests/backend-dbus/mock-webcredentials.cc | 54 + tests/backend-dbus/mock-webcredentials.h | 42 + tests/backend-dbus/test-actions.cc | 454 ++++++++ tests/backend-dbus/test-guest.cc | 192 +++ tests/backend-dbus/test-users.cc | 377 ++++++ tests/backend-mock-actions.c | 229 ++++ tests/backend-mock-actions.h | 61 + tests/backend-mock-guest.c | 129 ++ tests/backend-mock-guest.h | 61 + tests/backend-mock-users.c | 189 +++ tests/backend-mock-users.h | 70 ++ tests/backend-mock.c | 44 + tests/backend-mock.h | 38 + ...nical.indicator.session.backendmock.gschema.xml | 41 + tests/com.canonical.indicator.session.gschema.xml | 32 + tests/gtest-dbus-fixture.h | 134 +++ tests/indicator-session.service.in | 4 +- tests/test-service.cc | 831 +++++++++++-- trim-lcov.py | 53 + 115 files changed, 13799 insertions(+), 7673 deletions(-) delete mode 100644 AUTHORS delete mode 100644 ChangeLog create mode 100644 INSTALL delete mode 100644 Makefile.am delete mode 100644 Makefile.am.coverage delete mode 100755 autogen.sh delete mode 100644 configure.ac delete mode 100644 m4/gcov.m4 delete mode 100644 m4/gtest.m4 create mode 100644 src/CMakeLists.txt delete mode 100644 src/Makefile.am create mode 100644 src/actions.c create mode 100644 src/actions.h create mode 100644 src/backend-dbus/CMakeLists.txt create mode 100644 src/backend-dbus/actions.c create mode 100644 src/backend-dbus/actions.h create mode 100644 src/backend-dbus/backend-dbus.c create mode 100644 src/backend-dbus/backend-dbus.h create mode 100644 src/backend-dbus/com.canonical.indicators.webcredentials.xml create mode 100644 src/backend-dbus/display-manager.xml create mode 100644 src/backend-dbus/guest.c create mode 100644 src/backend-dbus/guest.h create mode 100644 src/backend-dbus/org.freedesktop.Accounts.User.xml create mode 100644 src/backend-dbus/org.freedesktop.Accounts.xml create mode 100644 src/backend-dbus/org.freedesktop.ConsoleKit.Manager.xml create mode 100644 src/backend-dbus/org.freedesktop.ConsoleKit.Seat.xml create mode 100644 src/backend-dbus/org.freedesktop.ConsoleKit.Session.xml create mode 100644 src/backend-dbus/org.gnome.ScreenSaver.xml create mode 100644 src/backend-dbus/org.gnome.SessionManager.EndSessionDialog.xml create mode 100644 src/backend-dbus/org.gnome.SessionManager.xml create mode 100644 src/backend-dbus/session-dbus.xml create mode 100644 src/backend-dbus/upower.xml create mode 100644 src/backend-dbus/users.c create mode 100644 src/backend-dbus/users.h create mode 100644 src/backend-dbus/utils.c create mode 100644 src/backend-dbus/utils.h create mode 100644 src/backend.h delete mode 100644 src/dialog.c delete mode 100644 src/dialog.h delete mode 100644 src/display-manager.xml delete mode 100644 src/gtk-logout-helper.c create mode 100644 src/guest.c create mode 100644 src/guest.h delete mode 100644 src/indicator-session.c create mode 100644 src/main.c delete mode 100644 src/online-accounts-mgr.c delete mode 100644 src/online-accounts-mgr.h delete mode 100644 src/org.freedesktop.Accounts.User.xml delete mode 100644 src/org.freedesktop.Accounts.xml delete mode 100644 src/org.freedesktop.ConsoleKit.Manager.xml delete mode 100644 src/org.freedesktop.ConsoleKit.Seat.xml delete mode 100644 src/org.freedesktop.ConsoleKit.Session.xml create mode 100644 src/service.c create mode 100644 src/service.h delete mode 100644 src/session-dbus.c delete mode 100644 src/session-dbus.h delete mode 100644 src/session-dbus.xml delete mode 100644 src/session-menu-mgr.c delete mode 100644 src/session-menu-mgr.h delete mode 100644 src/session-service.c delete mode 100644 src/shared-names.h delete mode 100644 src/upower.xml delete mode 100644 src/user-widget.c delete mode 100644 src/user-widget.h delete mode 100644 src/users-service-dbus.c delete mode 100644 src/users-service-dbus.h create mode 100644 src/users.c create mode 100644 src/users.h create mode 100644 tests/CMakeLists.txt delete mode 100644 tests/Makefile.am delete mode 100644 tests/Makefile.am.strings create mode 100644 tests/backend-dbus/CMakeLists.txt create mode 100644 tests/backend-dbus/gtest-mock-dbus-fixture.h create mode 100644 tests/backend-dbus/mock-accounts.cc create mode 100644 tests/backend-dbus/mock-accounts.h create mode 100644 tests/backend-dbus/mock-consolekit-manager.cc create mode 100644 tests/backend-dbus/mock-consolekit-manager.h create mode 100644 tests/backend-dbus/mock-consolekit-seat.cc create mode 100644 tests/backend-dbus/mock-consolekit-seat.h create mode 100644 tests/backend-dbus/mock-consolekit-session.cc create mode 100644 tests/backend-dbus/mock-consolekit-session.h create mode 100644 tests/backend-dbus/mock-display-manager-seat.cc create mode 100644 tests/backend-dbus/mock-display-manager-seat.h create mode 100644 tests/backend-dbus/mock-end-session-dialog.cc create mode 100644 tests/backend-dbus/mock-end-session-dialog.h create mode 100644 tests/backend-dbus/mock-object.cc create mode 100644 tests/backend-dbus/mock-object.h create mode 100644 tests/backend-dbus/mock-screen-saver.cc create mode 100644 tests/backend-dbus/mock-screen-saver.h create mode 100644 tests/backend-dbus/mock-session-manager.cc create mode 100644 tests/backend-dbus/mock-session-manager.h create mode 100644 tests/backend-dbus/mock-upower.cc create mode 100644 tests/backend-dbus/mock-upower.h create mode 100644 tests/backend-dbus/mock-user.cc create mode 100644 tests/backend-dbus/mock-user.h create mode 100644 tests/backend-dbus/mock-webcredentials.cc create mode 100644 tests/backend-dbus/mock-webcredentials.h create mode 100644 tests/backend-dbus/test-actions.cc create mode 100644 tests/backend-dbus/test-guest.cc create mode 100644 tests/backend-dbus/test-users.cc create mode 100644 tests/backend-mock-actions.c create mode 100644 tests/backend-mock-actions.h create mode 100644 tests/backend-mock-guest.c create mode 100644 tests/backend-mock-guest.h create mode 100644 tests/backend-mock-users.c create mode 100644 tests/backend-mock-users.h create mode 100644 tests/backend-mock.c create mode 100644 tests/backend-mock.h create mode 100644 tests/com.canonical.indicator.session.backendmock.gschema.xml create mode 100644 tests/com.canonical.indicator.session.gschema.xml create mode 100644 tests/gtest-dbus-fixture.h create mode 100755 trim-lcov.py diff --git a/AUTHORS b/AUTHORS deleted file mode 100644 index a741f25..0000000 --- a/AUTHORS +++ /dev/null @@ -1,2 +0,0 @@ -# Generated by Makefile - diff --git a/ChangeLog b/ChangeLog deleted file mode 100644 index a741f25..0000000 --- a/ChangeLog +++ /dev/null @@ -1,2 +0,0 @@ -# Generated by Makefile - diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..ef5d8e5 --- /dev/null +++ b/INSTALL @@ -0,0 +1,72 @@ +# +# Copyright (C) 2013 Canonical Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 3 as +# published by the Free Software Foundation. +# +# 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, see . +# + +Build dependencies +------------------ + +List of packages required to build and test the code: +- glib (libglib2.0, 2.35.4 or later) +- cmake (cmake, 2.8.9 or later) +- gcovr (gcovr, 2.4 or later) +- lcov (lcov, 1.9 or later) +- google test (libgtest-dev, 1.6.0 or later) +- cppcheck (cppcheck) + +Building the code +----------------- + +The simplest case is: + + $ cd indicator-session-X.Y.Z + $ mkdir build + $ cd build + $ cmake .. + $ make + +Running the tests +----------------- + + $ cd indicator-session-X.Y.Z + $ mkdir build + $ cd build + $ cmake .. + $ make + $ make test + $ make cppcheck + +Generating Test Coverage Reports +-------------------------------- + + $ cd indicator-session-X.Y.Z + $ mkdir build-coverage + $ cd build-coverage + $ cmake -DCMAKE_BUILD_TYPE=coverage .. + $ make + $ make coverage-html + +Installation +------------ + +FIXME: not tested +To get files that form part of an installation, run a "make install" +in the build directory. By default, this installs them in the "install" +subdirectory of the build directory. If you want to install into a +different directory, use + +$ cmake -DCMAKE_INSTALL_PREFIX=/usr/local # Or wherever... +$ make release +$ make install + diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index 8fb5d77..0000000 --- a/Makefile.am +++ /dev/null @@ -1,43 +0,0 @@ - -SUBDIRS = \ - src \ - data \ - po - -if BUILD_TESTS -SUBDIRS += tests -# build src first -tests: src -endif - -EXTRA_DIST = autogen.sh - -DISTCHECK_CONFIGURE_FLAGS = --enable-localinstall - -dist-hook: - @if test -d "$(top_srcdir)/.bzr"; \ - then \ - echo Creating ChangeLog && \ - ( cd "$(top_srcdir)" && \ - echo '# Generated by Makefile. Do not edit.'; echo; \ - $(top_srcdir)/missing --run bzr log --gnu-changelog ) > ChangeLog.tmp \ - && mv -f ChangeLog.tmp $(top_distdir)/ChangeLog \ - || (rm -f ChangeLog.tmp; \ - echo Failed to generate ChangeLog >&2 ); \ - else \ - echo Failed to generate ChangeLog: not a branch >&2; \ - fi - @if test -d "$(top_srcdir)/.bzr"; \ - then \ - echo Creating AUTHORS && \ - ( cd "$(top_srcdir)" && \ - echo '# Generated by Makefile. Do not edit.'; echo; \ - $(top_srcdir)/missing --run bzr log --long --levels=0 | grep -e "^\s*author:" -e "^\s*committer:" | cut -d ":" -f 2 | cut -d "<" -f 1 | sort -u) > AUTHORS.tmp \ - && mv -f AUTHORS.tmp $(top_distdir)/AUTHORS \ - || (rm -f AUTHORS.tmp; \ - echo Failed to generate AUTHORS >&2 ); \ - else \ - echo Failed to generate AUTHORS: not a branch >&2; \ - fi - -include $(top_srcdir)/Makefile.am.coverage diff --git a/Makefile.am.coverage b/Makefile.am.coverage deleted file mode 100644 index fb97747..0000000 --- a/Makefile.am.coverage +++ /dev/null @@ -1,48 +0,0 @@ - -# Coverage targets - -.PHONY: clean-gcno clean-gcda \ - coverage-html generate-coverage-html clean-coverage-html \ - coverage-gcovr generate-coverage-gcovr clean-coverage-gcovr - -clean-local: clean-gcno clean-coverage-html clean-coverage-gcovr - -if HAVE_GCOV - -clean-gcno: - @echo Removing old coverage instrumentation - -find -name '*.gcno' -print | xargs -r rm - -clean-gcda: - @echo Removing old coverage results - -find -name '*.gcda' -print | xargs -r rm - -coverage-html: clean-gcda - -$(MAKE) $(AM_MAKEFLAGS) -k check - $(MAKE) $(AM_MAKEFLAGS) generate-coverage-html - -generate-coverage-html: - @echo Collecting coverage data - $(LCOV) --directory $(top_builddir) --capture --output-file coverage.info --no-checksum --compat-libtool - LANG=C $(GENHTML) --prefix $(top_builddir) --output-directory coveragereport --title "Code Coverage" --legend --show-details coverage.info - -clean-coverage-html: clean-gcda - -$(LCOV) --directory $(top_builddir) -z - -rm -rf coverage.info coveragereport - -if HAVE_GCOVR - -coverage-gcovr: clean-gcda - -$(MAKE) $(AM_MAKEFLAGS) -k check - $(MAKE) $(AM_MAKEFLAGS) generate-coverage-gcovr - -generate-coverage-gcovr: - @echo Generating coverage GCOVR report - $(GCOVR) -x -r $(top_builddir) -o $(top_builddir)/coverage.xml - -clean-coverage-gcovr: clean-gcda - -rm -rf $(top_builddir)/coverage.xml - -endif # HAVE_GCOVR - -endif # HAVE_GCOV diff --git a/README b/README index e69de29..8834cc2 100644 --- a/README +++ b/README @@ -0,0 +1,47 @@ +Indicator-Session is the the session menu indicator for Unity. +Its behavior and features are listed at https://wiki.ubuntu.com/SystemMenu. + +For instructions on building and running built-in tests, see the INSTALL file. + + +Notes for Client Renderers +-------------------------- + +Indicator-Session has two custom types: the Guest menuitem and User menuitems. +Referencing the spec at ,https://wiki.ubuntu.com/SystemMenu.>, both have four +visual components: (1) an Active Session Mark and the user's (2) icon, +(3) name, and (4) Logged In Mark. + +== User menuitems can be recognized by their "indicator.switch-to-user" action. + Their four visual components are determined by: + + 1. You can test for the Action Session Mark by checking the action's state. + The state is a dicionary whose "active-user" key yields the current + session's owner's username. If it matches the username in this menuitem's + "target" attribute, show the Active Session Mark. + + 2. The icon is stored in the menuitem's "icon" attribute. If none is set, + the client should use a fallback icon such as "avatar-default." + + 3. The name is stored in the menuitem's "label" attribute. + + 4. You can test for the Logged In Mark by checking the action's state. + The state is a dictionary whose "logged-in-users" key will give + an array of usernames. If the array contains the username in this + menuitem's "target" attribute, show the Logged In Mark. + +== Guest menuitems can be recognized by their "indicator.switch-to-guest" action. + Its four visual components is determined by: + + 1. You can test for the Active Session Mark by checking the action's state. + The state is a dictionary whose "is-active" key yields a boolean. + If the booelan is true, show the Active Session Mark. + + 2. The guest user should use a fallback icon such as "avatar-default." + + 3. The name ("Guest") is stored in the menuitem's "label" attribute. + + 4. You can test for the Logged In Mark by checking the action's state. + The state is a dictionary whose "is-logged-in" key yields a boolean. + If the boolean is true, show the Logged In Mark. + diff --git a/autogen.sh b/autogen.sh deleted file mode 100755 index 7c01ea7..0000000 --- a/autogen.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -PKG_NAME="indicator-session" - -which gnome-autogen.sh || { - echo "You need gnome-common from GNOME SVN" - exit 1 -} - -USE_GNOME2_MACROS=1 \ -. gnome-autogen.sh diff --git a/configure.ac b/configure.ac deleted file mode 100644 index ee90bae..0000000 --- a/configure.ac +++ /dev/null @@ -1,231 +0,0 @@ -AC_INIT([indicator-session],[12.10.4]) -AC_CONFIG_SRCDIR([src/session-menu-mgr.c]) -AM_INIT_AUTOMAKE([check-news]) -AC_CONFIG_HEADERS([config.h]) - -AM_MAINTAINER_MODE - -GLIB_GSETTINGS - -IT_PROG_INTLTOOL([0.35.0]) - -AC_ISC_POSIX -AC_PROG_CC -AC_PROG_CXX -AM_PROG_CC_C_O -AC_HEADER_STDC -LT_INIT - -AC_SUBST(VERSION) -AC_CONFIG_MACRO_DIR([m4]) - -m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) - -########################### -# Dependencies -########################### - -GIO_REQUIRED_VERSION=2.33 -GLIB_REQUIRED_VERSION=2.35.4 -GTK_REQUIRED_VERSION=3.0 -INDICATOR_REQUIRED_VERSION=0.3.19 -DBUSMENUGTK_REQUIRED_VERSION=0.5.90 -DBUSTEST_REQUIRED_VERSION=0.0.5 -DBUSMENUGLIB_REQUIRED_VERSION=0.1.1 - - -PKG_CHECK_MODULES(APPLET, glib-2.0 >= $GLIB_REQUIRED_VERSION - gtk+-3.0 >= $GTK_REQUIRED_VERSION - indicator3-0.4 >= $INDICATOR_REQUIRED_VERSION - dbusmenu-gtk3-0.4 >= $DBUSMENUGTK_REQUIRED_VERSION) -AC_SUBST(APPLET_CFLAGS) -AC_SUBST(APPLET_LIBS) - - -PKG_CHECK_MODULES(SESSIONSERVICE, glib-2.0 >= $GLIB_REQUIRED_VERSION - dbusmenu-glib-0.4 >= $DBUSMENUGLIB_REQUIRED_VERSION - dbusmenu-gtk3-0.4 >= $DBUSMENUGTK_REQUIRED_VERSION - gio-unix-2.0 - indicator3-0.4 >= $INDICATOR_REQUIRED_VERSION) -AC_SUBST(SESSIONERVICE_CFLAGS) -AC_SUBST(SESSIONERVICE_LIBS) - -AC_SUBST(GUDEV_CFLAGS) -AC_SUBST(GUDEV_LIBS) - -########################### -# GTK Logout Helper -########################### - -AC_ARG_ENABLE([gtklogouthelper], - [AS_HELP_STRING([--enable-gtklogouthelper], [enable GTK Logout Helper])], - [], - [enable_gtklogouthelper=auto]) - -if test x"$enable_gtklogouthelper" != x"no" ; then - PKG_CHECK_MODULES([GTKLOGOUTHELPER], - [gtk+-3.0 >= $GTK_REQUIRED_VERSION], - [have_gtklogouthelper=yes], - [have_gtklogouthelper=no]) - if test x${have_gtklogouthelper} = xyes; then - AC_DEFINE(HAVE_GTKLOGOUTHELPER, 1, [Define to 1 to enable GTK Logout Helper]) - fi - if test x${enable_gtklogouthelper} = xyes && test x${have_gtklogouthelper} = xno; then - AC_MSG_ERROR([GTK Logout Helper configured but polkit-gobject not found]) - fi -else - have_gtklogouthelper=no -fi -AM_CONDITIONAL(BUILD_GTKLOGOUTHELPER, test x${have_gtklogouthelper} = xyes) - -AC_SUBST(GTKLOGOUTHELPER_CFLAGS) -AC_SUBST(GTKLOGOUTHELPER_LIBS) - -########################### -# Check to see if we're local -########################### - -with_localinstall="no" -AC_ARG_ENABLE(localinstall, AS_HELP_STRING([--enable-localinstall], [install all of the files localy instead of system directories (for distcheck)]), with_localinstall=$enableval, with_localinstall=no) - -########################### -# Indicator Info -########################### - -if test "x$with_localinstall" = "xyes"; then - INDICATORDIR="${libdir}/indicators/2/" - INDICATORICONSDIR="${datadir}/indicator-applet/icons/" -elif test "x$with_gtk" = x2; then - INDICATORDIR=`$PKG_CONFIG --variable=indicatordir indicator-0.4` - INDICATORICONSDIR=`$PKG_CONFIG --variable=iconsdir indicator-0.4` -else - INDICATORDIR=`$PKG_CONFIG --variable=indicatordir indicator3-0.4` - INDICATORICONSDIR=`$PKG_CONFIG --variable=iconsdir indicator3-0.4` -fi -AC_SUBST(INDICATORDIR) -AC_SUBST(INDICATORICONSDIR) - -########################### -# DBus Service Info -########################### - -if test "x$with_localinstall" = "xyes"; then - DBUSSERVICEDIR="${datadir}/dbus-1/services/" -else - DBUSSERVICEDIR=`$PKG_CONFIG --variable=session_bus_services_dir dbus-1` -fi -AC_SUBST(DBUSSERVICEDIR) - -########################### -# Google Test framework -########################### - -AC_ARG_ENABLE([tests], - [AS_HELP_STRING([--disable-tests], [Disable test scripts and tools (default=auto)])], - [enable_tests=${enableval}], - [enable_tests=auto]) -if test "x$enable_tests" != "xno"; then - m4_include([m4/gtest.m4]) - CHECK_GTEST - CHECK_XORG_GTEST - if test "x$enable_tests" = "xauto"; then - enable_tests=${have_gtest} - elif test "x$enable_tests" = "xyes" && test "x$have_gtest" != "xyes"; then - AC_MSG_ERROR([tests were requested but gtest is not installed.]) - fi - if test "x$enable_tests" = "xyes"; then - PKG_CHECK_MODULES([TEST_SERVICE],[glib-2.0 >= $GLIB_REQUIRED_VERSION - gio-2.0 >= $GIO_REQUIRED_VERSION], - [enable_tests="yes"], - [enable_tests="no"]) - fi -fi -AM_CONDITIONAL([BUILD_TESTS],[test "x$enable_tests" = "xyes"]) -AC_SUBST([TEST_SERVICE_CFLAGS]) -AC_SUBST([TEST_SERVICE_LIBS]) - -############################## -# Custom Junk -############################## - -AC_DEFUN([AC_DEFINE_PATH], [ - test "x$prefix" = xNONE && prefix="$ac_default_prefix" - test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' - ac_define_path=`eval echo [$]$2` - ac_define_path=`eval echo [$]ac_define_path` - $1="$ac_define_path" - AC_SUBST($1) - ifelse($3, , - AC_DEFINE_UNQUOTED($1, "$ac_define_path"), - AC_DEFINE_UNQUOTED($1, "$ac_define_path", $3)) -]) - -########################### -# Internationalization -########################### - -GETTEXT_PACKAGE=indicator-session -AC_SUBST(GETTEXT_PACKAGE) -AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [Name of the default get text domain]) -AC_DEFINE_PATH(GNOMELOCALEDIR, "${datadir}/locale", [locale directory]) - -AM_GLIB_GNU_GETTEXT - -########################### -# gcov coverage reporting -########################### - -m4_include([m4/gcov.m4]) -AC_TDD_GCOV -AM_CONDITIONAL([HAVE_GCOV], [test "x$ac_cv_check_gcov" = xyes]) -AM_CONDITIONAL([HAVE_LCOV], [test "x$ac_cv_check_lcov" = xyes]) -AM_CONDITIONAL([HAVE_GCOVR], [test "x$ac_cv_check_gcovr" = xyes]) -AC_SUBST(COVERAGE_CFLAGS) -AC_SUBST(COVERAGE_LDFLAGS) - -########################### -# Files -########################### - -AC_CONFIG_FILES([ -Makefile -src/Makefile -data/Makefile -data/icons/Makefile -data/icons/16x16/Makefile -data/icons/16x16/actions/Makefile -data/icons/16x16/status/Makefile -data/icons/22x22/Makefile -data/icons/22x22/actions/Makefile -data/icons/22x22/status/Makefile -data/icons/24x24/Makefile -data/icons/24x24/actions/Makefile -data/icons/24x24/status/Makefile -data/icons/32x32/Makefile -data/icons/32x32/actions/Makefile -data/icons/32x32/status/Makefile -data/icons/scalable/Makefile -data/icons/scalable/actions/Makefile -data/icons/scalable/status/Makefile -data/extra-sessions/Makefile -tests/Makefile -tests/indicator-session.service -po/Makefile.in -]) - -AC_OUTPUT - -########################### -# Results -########################### - -AC_MSG_NOTICE([ - -SUS Indicator Configuration: - - Prefix: $prefix - Indicator Dir: $INDICATORDIR - Logout Helper: $have_gtklogouthelper - Unit Tests: $enable_tests - Coverage reporting: $use_gcov -]) diff --git a/m4/gcov.m4 b/m4/gcov.m4 deleted file mode 100644 index 3163584..0000000 --- a/m4/gcov.m4 +++ /dev/null @@ -1,86 +0,0 @@ -# Checks for existence of coverage tools: -# * gcov -# * lcov -# * genhtml -# * gcovr -# -# Sets ac_cv_check_gcov to yes if tooling is present -# and reports the executables to the variables LCOV, GCOVR and GENHTML. -AC_DEFUN([AC_TDD_GCOV], -[ - AC_ARG_ENABLE(gcov, - AS_HELP_STRING([--enable-gcov], - [enable coverage testing with gcov]), - [use_gcov=$enableval], [use_gcov=no]) - - if test "x$use_gcov" = "xyes"; then - # we need gcc: - if test "$GCC" != "yes"; then - AC_MSG_ERROR([GCC is required for --enable-gcov]) - fi - - # Check if ccache is being used - AC_CHECK_PROG(SHTOOL, shtool, shtool) - case `$SHTOOL path $CC` in - *ccache*[)] gcc_ccache=yes;; - *[)] gcc_ccache=no;; - esac - - if test "$gcc_ccache" = "yes" && (test -z "$CCACHE_DISABLE" || test "$CCACHE_DISABLE" != "1"); then - AC_MSG_ERROR([ccache must be disabled when --enable-gcov option is used. You can disable ccache by setting environment variable CCACHE_DISABLE=1.]) - fi - - lcov_version_list="1.6 1.7 1.8 1.9" - AC_CHECK_PROG(LCOV, lcov, lcov) - AC_CHECK_PROG(GENHTML, genhtml, genhtml) - - if test "$LCOV"; then - AC_CACHE_CHECK([for lcov version], glib_cv_lcov_version, [ - glib_cv_lcov_version=invalid - lcov_version=`$LCOV -v 2>/dev/null | $SED -e 's/^.* //'` - for lcov_check_version in $lcov_version_list; do - if test "$lcov_version" = "$lcov_check_version"; then - glib_cv_lcov_version="$lcov_check_version (ok)" - fi - done - ]) - else - lcov_msg="To enable code coverage reporting you must have one of the following lcov versions installed: $lcov_version_list" - AC_MSG_ERROR([$lcov_msg]) - fi - - case $glib_cv_lcov_version in - ""|invalid[)] - lcov_msg="You must have one of the following versions of lcov: $lcov_version_list (found: $lcov_version)." - AC_MSG_ERROR([$lcov_msg]) - LCOV="exit 0;" - ;; - esac - - if test -z "$GENHTML"; then - AC_MSG_ERROR([Could not find genhtml from the lcov package]) - fi - - ac_cv_check_gcov=yes - ac_cv_check_lcov=yes - - # Remove all optimization flags from CFLAGS - changequote({,}) - CFLAGS=`echo "$CFLAGS" | $SED -e 's/-O[0-9]*//g'` - changequote([,]) - - # Add the special gcc flags - COVERAGE_CFLAGS="-O0 -fprofile-arcs -ftest-coverage" - COVERAGE_CXXFLAGS="-O0 -fprofile-arcs -ftest-coverage" - COVERAGE_LDFLAGS="-lgcov" - - # Check availability of gcovr - AC_CHECK_PROG(GCOVR, gcovr, gcovr) - if test -z "$GCOVR"; then - ac_cv_check_gcovr=no - else - ac_cv_check_gcovr=yes - fi - -fi -]) # AC_TDD_GCOV diff --git a/m4/gtest.m4 b/m4/gtest.m4 deleted file mode 100644 index 2de334c..0000000 --- a/m4/gtest.m4 +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright (C) 2012 Canonical, Ltd. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice (including the next -# paragraph) shall be included in all copies or substantial portions of the -# Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -# Checks whether the gtest source is available on the system. Allows for -# adjusting the include and source path. Sets have_gtest=yes if the source is -# present. Sets GTEST_CPPFLAGS and GTEST_SOURCE to the preprocessor flags and -# source location respectively. -AC_DEFUN([CHECK_GTEST], -[ - AC_ARG_WITH([gtest-include-path], - [AS_HELP_STRING([--with-gtest-include-path], - [location of the Google test headers])], - [GTEST_CPPFLAGS="-I$withval"]) - - AC_ARG_WITH([gtest-source-path], - [AS_HELP_STRING([--with-gtest-source-path], - [location of the Google test sources, defaults to /usr/src/gtest])], - [GTEST_SOURCE="$withval"], - [GTEST_SOURCE="/usr/src/gtest"]) - - GTEST_CPPFLAGS="$GTEST_CPPFLAGS -I$GTEST_SOURCE" - - AC_LANG_PUSH([C++]) - - tmp_CPPFLAGS="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $GTEST_CPPFLAGS" - - AC_CHECK_HEADER([gtest/gtest.h]) - - CPPFLAGS="$tmp_CPPFLAGS" - - AC_LANG_POP - - AC_CHECK_FILES([$GTEST_SOURCE/src/gtest-all.cc] - [$GTEST_SOURCE/src/gtest_main.cc], - [have_gtest_source=yes], - [have_gtest_source=no]) - - AS_IF([test "x$ac_cv_header_gtest_gtest_h" = xyes -a \ - "x$have_gtest_source" = xyes], - [have_gtest=yes] - [AC_SUBST(GTEST_CPPFLAGS)] - [AC_SUBST(GTEST_SOURCE)], - [have_gtest=no]) -]) # CHECK_GTEST diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..efa704c --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,19 @@ +add_subdirectory (backend-dbus) + +add_library (libindicatorsessionservice STATIC + actions.c + actions.h + guest.c + guest.h + service.c + service.h + users.c + users.h) +set_target_properties (libindicatorsessionservice PROPERTIES COMPILE_FLAGS " -g ${CC_WARNING_ARGS} ${GCOV_FLAGS}") + +include_directories(${SERVICE_INCLUDE_DIRS}) +link_directories(${SERVICE_LIBRARY_DIRS}) + +add_executable (indicator-session-service main.c) +target_link_libraries (indicator-session-service libindicatorsessionservice backenddbus ${SERVICE_LIBRARIES} ${GCOV_LIBS}) + diff --git a/src/Makefile.am b/src/Makefile.am deleted file mode 100644 index bcc8652..0000000 --- a/src/Makefile.am +++ /dev/null @@ -1,207 +0,0 @@ -CLEANFILES = -EXTRA_DIST = - -libexec_PROGRAMS = \ - indicator-session-service - -if BUILD_GTKLOGOUTHELPER -libexec_PROGRAMS += \ - gtk-logout-helper -endif - -################### -# Indicator Stuff -################### - -CLEANFILES += .libs/*.gcda .libs/*.gcno *.gcda *.gcno - -sessionlibdir = $(INDICATORDIR) -sessionlib_LTLIBRARIES = libsession.la -libsession_la_SOURCES = \ - indicator-session.c \ - gen-session-dbus.xml.h \ - shared-names.h \ - user-widget.c \ - user-widget.h -libsession_la_CFLAGS = \ - $(APPLET_CFLAGS) \ - $(COVERAGE_CFLAGS) \ - -Wall -Wunused \ - -DG_LOG_DOMAIN=\"Indicator-Session\" -libsession_la_LIBADD = $(APPLET_LIBS) -libsession_la_LDFLAGS = \ - $(COVERAGE_LDFLAGS) \ - -module -avoid-version - -dbus_display_manager_sources = \ - dbus-display-manager.c \ - dbus-display-manager.h - -$(dbus_display_manager_sources): display-manager.xml - $(AM_V_GEN) gdbus-codegen \ - --interface-prefix org.freedesktop \ - --generate-c-code dbus-display-manager \ - $^ - -dbus_consolekit_manager_sources = \ - dbus-consolekit-manager.c \ - dbus-consolekit-manager.h - -$(dbus_consolekit_manager_sources): org.freedesktop.ConsoleKit.Manager.xml - $(AM_V_GEN) gdbus-codegen \ - --interface-prefix org.freedesktop \ - --generate-c-code dbus-consolekit-manager \ - $^ - -dbus_consolekit_seat_sources = \ - dbus-consolekit-seat.c \ - dbus-consolekit-seat.h - -$(dbus_consolekit_seat_sources): org.freedesktop.ConsoleKit.Seat.xml - $(AM_V_GEN) gdbus-codegen \ - --interface-prefix org.freedesktop \ - --generate-c-code dbus-consolekit-seat \ - $^ - -dbus_consolekit_session_sources = \ - dbus-consolekit-session.c \ - dbus-consolekit-session.h - -$(dbus_consolekit_session_sources): org.freedesktop.ConsoleKit.Session.xml - $(AM_V_GEN) gdbus-codegen \ - --interface-prefix org.freedesktop \ - --generate-c-code dbus-consolekit-session \ - $^ - -dbus_accounts_sources = \ - dbus-accounts.c \ - dbus-accounts.h - -$(dbus_accounts_sources): org.freedesktop.Accounts.xml - $(AM_V_GEN) gdbus-codegen \ - --interface-prefix org.freedesktop \ - --generate-c-code dbus-accounts \ - $^ - -dbus_user_sources = \ - dbus-user.c \ - dbus-user.h - -$(dbus_user_sources): org.freedesktop.Accounts.User.xml - $(AM_V_GEN) gdbus-codegen \ - --interface-prefix org.freedesktop \ - --generate-c-code dbus-user \ - $^ - -dbus_upower_sources = \ - dbus-upower.c \ - dbus-upower.h - -$(dbus_upower_sources): upower.xml - $(AM_V_GEN) gdbus-codegen \ - --interface-prefix org.freedesktop \ - --generate-c-code dbus-upower \ - --c-namespace DBus \ - $^ - -gen-%.xml.c: %.xml - @echo "Building $@ from $<" - @echo "const char * _$(subst -,_,$(subst .,_,$(basename $(notdir $<)))) = " > $@ - @sed -e "s:\":\\\\\":g" -e s:^:\": -e s:\$$:\\\\n\": $< >> $@ - @echo ";" >> $@ - -gen-%.xml.h: %.xml - @echo "Building $@ from $<" - @echo "extern const char * _$(subst -,_,$(subst .,_,$(basename $(notdir $<))));" > $@ - -################# -# Session Stuff -################# - -indicator_session_service_SOURCES = \ - $(dbus_accounts_sources) \ - $(dbus_consolekit_manager_sources) \ - $(dbus_consolekit_seat_sources) \ - $(dbus_consolekit_session_sources) \ - $(dbus_display_manager_sources) \ - $(dbus_upower_sources) \ - $(dbus_user_sources) \ - session-service.c \ - session-dbus.c \ - session-dbus.h \ - gen-session-dbus.xml.c \ - users-service-dbus.h \ - users-service-dbus.c \ - session-menu-mgr.h \ - session-menu-mgr.c \ - online-accounts-mgr.c \ - online-accounts-mgr.h - -indicator_session_service_CFLAGS = \ - $(SESSIONSERVICE_CFLAGS) \ - $(GCONF_CFLAGS) \ - -DLIBEXECDIR=\"$(libexecdir)\" \ - -Wall \ - -DG_LOG_DOMAIN=\"Indicator-Session\" \ - $(COVERAGE_CFLAGS) -indicator_session_service_LDADD = \ - $(SESSIONSERVICE_LIBS) \ - $(GCONF_LIBS) -indicator_session_service_LDFLAGS = \ - $(COVERAGE_LDFLAGS) - -################# -# GTK Logout Stuff -################# - -if BUILD_GTKLOGOUTHELPER -gtk_logout_helper_SOURCES = \ - $(dbus_consolekit_manager_sources) \ - gtk-logout-helper.c \ - dialog.c \ - dialog.h - -gtk_logout_helper_CFLAGS = \ - $(SESSIONSERVICE_CFLAGS) \ - $(GTKLOGOUTHELPER_CFLAGS) \ - $(GCONF_CFLAGS) \ - $(COVERAGE_CFLAGS) \ - -Wall \ - -DINDICATOR_ICONS_DIR="\"$(INDICATORICONSDIR)\"" - -gtk_logout_helper_LDADD = \ - $(SESSIONSERVICE_LIBS) \ - $(GTKLOGOUTHELPER_LIBS) \ - $(GCONF_LIBS) - -gtk_logout_helper_LDFLAGS = \ - $(COVERAGE_LDFLAGS) -endif - - -############### -# Other Stuff -############### - -BUILT_SOURCES = \ - $(dbus_accounts_sources) \ - $(dbus_consolekit_manager_sources) \ - $(dbus_consolekit_seat_sources) \ - $(dbus_consolekit_session_sources) \ - $(dbus_display_manager_sources) \ - $(dbus_upower_sources) \ - $(dbus_user_sources) \ - gen-session-dbus.xml.c \ - gen-session-dbus.xml.h - -EXTRA_DIST += \ - display-manager.xml \ - org.freedesktop.Accounts.User.xml \ - org.freedesktop.Accounts.xml \ - org.freedesktop.ConsoleKit.Manager.xml \ - org.freedesktop.ConsoleKit.Seat.xml \ - org.freedesktop.ConsoleKit.Session.xml \ - session-dbus.xml \ - upower.xml - -CLEANFILES += $(BUILT_SOURCES) diff --git a/src/actions.c b/src/actions.c new file mode 100644 index 0000000..788f418 --- /dev/null +++ b/src/actions.c @@ -0,0 +1,383 @@ + +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include "actions.h" + +/*** +**** GObject Boilerplate +***/ + +G_DEFINE_TYPE (IndicatorSessionActions, indicator_session_actions, G_TYPE_OBJECT) + +enum +{ + PROP_0, + PROP_CAN_SWITCH, + PROP_CAN_HIBERNATE, + PROP_CAN_SUSPEND, + PROP_CAN_LOCK, + PROP_CAN_LOGOUT, + PROP_CAN_PROMPT, + PROP_HAS_ONLINE_ACCOUNT_ERROR, + PROP_LAST +}; + +static GParamSpec *properties[PROP_LAST]; + +static void +my_get_property (GObject * o, + guint property_id, + GValue * value, + GParamSpec * pspec) +{ + IndicatorSessionActions * self = INDICATOR_SESSION_ACTIONS (o); + + switch (property_id) + { + case PROP_CAN_SWITCH: + g_value_set_boolean (value, indicator_session_actions_can_switch (self)); + break; + + case PROP_CAN_HIBERNATE: + g_value_set_boolean (value, indicator_session_actions_can_hibernate (self)); + break; + + case PROP_CAN_SUSPEND: + g_value_set_boolean (value, indicator_session_actions_can_suspend (self)); + break; + + case PROP_CAN_LOCK: + g_value_set_boolean (value, indicator_session_actions_can_lock (self)); + break; + + case PROP_CAN_LOGOUT: + g_value_set_boolean (value, indicator_session_actions_can_logout (self)); + break; + + case PROP_CAN_PROMPT: + g_value_set_boolean (value, indicator_session_actions_can_prompt (self)); + break; + + case PROP_HAS_ONLINE_ACCOUNT_ERROR: + g_value_set_boolean (value, indicator_session_actions_has_online_account_error (self)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec); + } +} + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_actions_class_init (IndicatorSessionActionsClass * klass) +{ + GObjectClass * object_class; + const GParamFlags flags = G_PARAM_READABLE | G_PARAM_STATIC_STRINGS; + + object_class = G_OBJECT_CLASS (klass); + object_class->get_property = my_get_property; + + klass->can_lock = NULL; + klass->can_logout = NULL; + klass->can_switch = NULL; + klass->can_suspend = NULL; + klass->can_hibernate = NULL; + klass->has_online_account_error = NULL; + klass->logout = NULL; + klass->suspend = NULL; + klass->hibernate = NULL; + klass->restart = NULL; + klass->shutdown = NULL; + klass->switch_to_screensaver = NULL; + klass->switch_to_greeter = NULL; + klass->switch_to_guest = NULL; + klass->switch_to_username = NULL; + + /* properties */ + + properties[PROP_0] = NULL; + + properties[PROP_CAN_SWITCH] = + g_param_spec_boolean (INDICATOR_SESSION_ACTIONS_PROP_CAN_SWITCH, + "Can Switch Sessions", + "Whether or not the system services allow session switching", + TRUE, flags); + + properties[PROP_CAN_HIBERNATE] = + g_param_spec_boolean (INDICATOR_SESSION_ACTIONS_PROP_CAN_HIBERNATE, + "Can Hibernate", + "Whether or not the system services allow the user to hibernate", + TRUE, flags); + + properties[PROP_CAN_SUSPEND] = + g_param_spec_boolean (INDICATOR_SESSION_ACTIONS_PROP_CAN_SUSPEND, + "Can Suspend", + "Whether or not the system services allow the user to suspend", + TRUE, flags); + + properties[PROP_CAN_LOCK] = + g_param_spec_boolean (INDICATOR_SESSION_ACTIONS_PROP_CAN_LOCK, + "Can Lock", + "Whether or not the system services allow the user to lock the screen", + TRUE, flags); + + properties[PROP_CAN_LOGOUT] = + g_param_spec_boolean (INDICATOR_SESSION_ACTIONS_PROP_CAN_LOGOUT, + "Can Logout", + "Whether or not the system services allow the user to logout", + TRUE, flags); + + properties[PROP_CAN_PROMPT] = + g_param_spec_boolean (INDICATOR_SESSION_ACTIONS_PROP_CAN_PROMPT, + "Can Show End Session Dialog", + "Whether or not we can show an End Session dialog", + TRUE, flags); + + properties[PROP_HAS_ONLINE_ACCOUNT_ERROR] = + g_param_spec_boolean (INDICATOR_SESSION_ACTIONS_PROP_HAS_ONLINE_ACCOUNT_ERROR, + "Has Online Account Error", + "Whether or not an online account setting requires attention from the user", + FALSE, flags); + + g_object_class_install_properties (object_class, PROP_LAST, properties); +} + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_actions_init (IndicatorSessionActions * self G_GNUC_UNUSED) +{ +} + +/*** +**** +***/ + +gboolean +indicator_session_actions_can_lock (IndicatorSessionActions * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_ACTIONS (self), FALSE); + + return INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->can_lock (self); +} + +gboolean +indicator_session_actions_can_logout (IndicatorSessionActions * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_ACTIONS (self), FALSE); + + return INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->can_logout (self); +} + +gboolean +indicator_session_actions_can_switch (IndicatorSessionActions * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_ACTIONS (self), FALSE); + + return INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->can_switch (self); +} + +gboolean +indicator_session_actions_can_suspend (IndicatorSessionActions * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_ACTIONS (self), FALSE); + + return INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->can_suspend (self); +} + +gboolean +indicator_session_actions_can_hibernate (IndicatorSessionActions * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_ACTIONS (self), FALSE); + + return INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->can_hibernate (self); +} + +gboolean +indicator_session_actions_can_prompt (IndicatorSessionActions * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_ACTIONS (self), FALSE); + + return INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->can_prompt (self); +} + +gboolean +indicator_session_actions_has_online_account_error (IndicatorSessionActions * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_ACTIONS (self), FALSE); + + return INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->has_online_account_error (self); +} + +/*** +**** +***/ + +void +indicator_session_actions_settings (IndicatorSessionActions * self) +{ + g_return_if_fail (INDICATOR_IS_SESSION_ACTIONS (self)); + + INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->settings (self); +} + +void +indicator_session_actions_logout (IndicatorSessionActions * self) +{ + g_return_if_fail (INDICATOR_IS_SESSION_ACTIONS (self)); + + INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->logout (self); +} + +void +indicator_session_actions_shutdown (IndicatorSessionActions * self) +{ + g_return_if_fail (INDICATOR_IS_SESSION_ACTIONS (self)); + + INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->shutdown (self); +} + +void +indicator_session_actions_help (IndicatorSessionActions * self) +{ + g_return_if_fail (INDICATOR_IS_SESSION_ACTIONS (self)); + + INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->help (self); +} + +void +indicator_session_actions_about (IndicatorSessionActions * self) +{ + g_return_if_fail (INDICATOR_IS_SESSION_ACTIONS (self)); + + INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->about (self); +} + +void +indicator_session_actions_restart (IndicatorSessionActions * self) +{ + g_return_if_fail (INDICATOR_IS_SESSION_ACTIONS (self)); + + INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->restart (self); +} + +void +indicator_session_actions_suspend (IndicatorSessionActions * self) +{ + g_return_if_fail (INDICATOR_IS_SESSION_ACTIONS (self)); + + INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->suspend (self); +} + +void +indicator_session_actions_hibernate (IndicatorSessionActions * self) +{ + g_return_if_fail (INDICATOR_IS_SESSION_ACTIONS (self)); + + INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->hibernate (self); +} + +void +indicator_session_actions_switch_to_screensaver (IndicatorSessionActions * self) +{ + g_return_if_fail (INDICATOR_IS_SESSION_ACTIONS (self)); + + INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->switch_to_screensaver (self); +} + +void +indicator_session_actions_switch_to_greeter (IndicatorSessionActions * self) +{ + g_return_if_fail (INDICATOR_IS_SESSION_ACTIONS (self)); + + INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->switch_to_greeter (self); +} + +void +indicator_session_actions_switch_to_guest (IndicatorSessionActions * self) +{ + g_return_if_fail (INDICATOR_IS_SESSION_ACTIONS (self)); + + INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->switch_to_guest (self); +} + +void +indicator_session_actions_switch_to_username (IndicatorSessionActions * self, + const gchar * username) +{ + g_return_if_fail (INDICATOR_IS_SESSION_ACTIONS (self)); + + INDICATOR_SESSION_ACTIONS_GET_CLASS (self)->switch_to_username (self, username); +} + +/*** +**** +***/ + +static void +notify_func (IndicatorSessionActions * self, int prop) +{ + g_return_if_fail (INDICATOR_IS_SESSION_ACTIONS (self)); + + g_debug ("%s %s emitting '%s' prop notify", G_STRLOC, G_STRFUNC, properties[prop]->name); + + g_object_notify_by_pspec (G_OBJECT(self), properties[prop]); +} + +void +indicator_session_actions_notify_can_lock (IndicatorSessionActions * self) +{ + notify_func (self, PROP_CAN_LOCK); +} + +void +indicator_session_actions_notify_can_logout (IndicatorSessionActions * self) +{ + notify_func (self, PROP_CAN_LOGOUT); +} + +void +indicator_session_actions_notify_can_switch (IndicatorSessionActions * self) +{ + notify_func (self, PROP_CAN_SWITCH); +} + +void +indicator_session_actions_notify_can_suspend (IndicatorSessionActions * self) +{ + notify_func (self, PROP_CAN_SUSPEND); +} + +void +indicator_session_actions_notify_can_hibernate (IndicatorSessionActions * self) +{ + notify_func (self, PROP_CAN_HIBERNATE); +} + +void +indicator_session_actions_notify_can_prompt (IndicatorSessionActions * self) +{ + notify_func (self, PROP_CAN_PROMPT); +} + +void +indicator_session_actions_notify_has_online_account_error (IndicatorSessionActions * self) +{ + notify_func (self, PROP_HAS_ONLINE_ACCOUNT_ERROR); +} diff --git a/src/actions.h b/src/actions.h new file mode 100644 index 0000000..e0d0ec5 --- /dev/null +++ b/src/actions.h @@ -0,0 +1,129 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#ifndef __INDICATOR_SESSION_ACTIONS_H__ +#define __INDICATOR_SESSION_ACTIONS_H__ + +#include +#include + +G_BEGIN_DECLS + +/* standard GObject macros */ +#define INDICATOR_TYPE_SESSION_ACTIONS (indicator_session_actions_get_type()) +#define INDICATOR_SESSION_ACTIONS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_SESSION_ACTIONS, IndicatorSessionActions)) +#define INDICATOR_SESSION_ACTIONS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_SESSION_ACTIONS, IndicatorSessionActionsClass)) +#define INDICATOR_SESSION_ACTIONS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), INDICATOR_TYPE_SESSION_ACTIONS, IndicatorSessionActionsClass)) +#define INDICATOR_IS_SESSION_ACTIONS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_SESSION_ACTIONS)) + +typedef struct _IndicatorSessionActions IndicatorSessionActions; +typedef struct _IndicatorSessionActionsClass IndicatorSessionActionsClass; + +/* property keys */ +#define INDICATOR_SESSION_ACTIONS_PROP_CAN_LOCK "can-lock" +#define INDICATOR_SESSION_ACTIONS_PROP_CAN_LOGOUT "can-logout" +#define INDICATOR_SESSION_ACTIONS_PROP_CAN_SWITCH "can-switch" +#define INDICATOR_SESSION_ACTIONS_PROP_CAN_SUSPEND "can-suspend" +#define INDICATOR_SESSION_ACTIONS_PROP_CAN_HIBERNATE "can-hibernate" +#define INDICATOR_SESSION_ACTIONS_PROP_CAN_PROMPT "can-show-end-session-dialog" +#define INDICATOR_SESSION_ACTIONS_PROP_HAS_ONLINE_ACCOUNT_ERROR "has-online-account-error" + +/** + * A base class for invoking and getting state information on system actions. + * Use backend.h's get_backend() to get an instance. + */ +struct _IndicatorSessionActions +{ + /*< private >*/ + GObject parent; +}; + +struct _IndicatorSessionActionsClass +{ + GObjectClass parent_class; + + /* pure virtual functions */ + + gboolean (*can_lock) (IndicatorSessionActions * self); + gboolean (*can_logout) (IndicatorSessionActions * self); + gboolean (*can_switch) (IndicatorSessionActions * self); + gboolean (*can_suspend) (IndicatorSessionActions * self); + gboolean (*can_hibernate) (IndicatorSessionActions * self); + gboolean (*can_prompt) (IndicatorSessionActions * self); + gboolean (*has_online_account_error) (IndicatorSessionActions * self); + + void (*suspend) (IndicatorSessionActions * self); + void (*hibernate) (IndicatorSessionActions * self); + void (*logout) (IndicatorSessionActions * self); + void (*restart) (IndicatorSessionActions * self); + void (*shutdown) (IndicatorSessionActions * self); + void (*help) (IndicatorSessionActions * self); + void (*about) (IndicatorSessionActions * self); + void (*settings) (IndicatorSessionActions * self); + + void (*switch_to_greeter) (IndicatorSessionActions * self); + void (*switch_to_screensaver) (IndicatorSessionActions * self); + void (*switch_to_guest) (IndicatorSessionActions * self); + void (*switch_to_username) (IndicatorSessionActions * self, + const gchar * username); +}; + +/*** +**** +***/ + +GType indicator_session_actions_get_type (void); + +gboolean indicator_session_actions_can_lock (IndicatorSessionActions * self); +gboolean indicator_session_actions_can_logout (IndicatorSessionActions * self); +gboolean indicator_session_actions_can_switch (IndicatorSessionActions * self); +gboolean indicator_session_actions_can_suspend (IndicatorSessionActions * self); +gboolean indicator_session_actions_can_hibernate (IndicatorSessionActions * self); +gboolean indicator_session_actions_can_prompt (IndicatorSessionActions * self); +gboolean indicator_session_actions_has_online_account_error (IndicatorSessionActions * self); + + +void indicator_session_actions_notify_can_lock (IndicatorSessionActions * self); +void indicator_session_actions_notify_can_logout (IndicatorSessionActions * self); +void indicator_session_actions_notify_can_switch (IndicatorSessionActions * self); +void indicator_session_actions_notify_can_suspend (IndicatorSessionActions * self); +void indicator_session_actions_notify_can_hibernate (IndicatorSessionActions * self); +void indicator_session_actions_notify_can_prompt (IndicatorSessionActions * self); +void indicator_session_actions_notify_has_online_account_error (IndicatorSessionActions * self); + +void indicator_session_actions_lock (IndicatorSessionActions * self); +void indicator_session_actions_suspend (IndicatorSessionActions * self); +void indicator_session_actions_hibernate (IndicatorSessionActions * self); +void indicator_session_actions_logout (IndicatorSessionActions * self); +void indicator_session_actions_restart (IndicatorSessionActions * self); +void indicator_session_actions_shutdown (IndicatorSessionActions * self); + +void indicator_session_actions_help (IndicatorSessionActions * self); +void indicator_session_actions_about (IndicatorSessionActions * self); +void indicator_session_actions_settings (IndicatorSessionActions * self); + +void indicator_session_actions_switch_to_screensaver (IndicatorSessionActions * self); +void indicator_session_actions_switch_to_greeter (IndicatorSessionActions * self); +void indicator_session_actions_switch_to_guest (IndicatorSessionActions * self); +void indicator_session_actions_switch_to_username (IndicatorSessionActions * self, + const gchar * username); + +G_END_DECLS + +#endif /* __INDICATOR_SESSION_ACTIONS_H__ */ diff --git a/src/backend-dbus/CMakeLists.txt b/src/backend-dbus/CMakeLists.txt new file mode 100644 index 0000000..a477cfe --- /dev/null +++ b/src/backend-dbus/CMakeLists.txt @@ -0,0 +1,86 @@ +# autogenerate source code files for our DBus proxies +function(gdbus_codegen XML_FILE INTERFACE_PREFIX SOURCE_PREFIX) + + set (SRC_C, ${SOURCE_PREFIX}.c) + set (SRC_H, ${SOURCE_PREFIX}.h) + + # check for the app + find_program (GDBUS_CODEGEN_EXECUTABLE NAMES gdbus-codegen DOC "gdbus-codegen executable") + if(NOT GDBUS_CODEGEN_EXECUTABLE) + message(FATAL_ERROR "Executable gdbus-codegen not found") + endif() + + # generate the code + add_custom_command ( + OUTPUT ${SOURCE_PREFIX}.c ${SOURCE_PREFIX}.h + COMMAND gdbus-codegen ARGS --interface-prefix ${INTERFACE_PREFIX} --generate-c-code ${SOURCE_PREFIX} ${CMAKE_CURRENT_SOURCE_DIR}/${XML_FILE} + DEPENDS ${XML_FILE}) + + # update our variables + set_property (DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${SRC_C}) + set_property (DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${SRC_H}) + set_property (SOURCE ${SRC_C} ${SRC_H} PROPERTY GENERATED) + + # cleanup + unset (SRC_C) + unset (SRC_H) + +endfunction(gdbus_codegen) +gdbus_codegen ("display-manager.xml" "org.freedesktop" "dbus-display-manager") +gdbus_codegen ("com.canonical.indicators.webcredentials.xml" "com.canonical.indicators" "dbus-webcredentials") +gdbus_codegen ("org.freedesktop.Accounts.xml" "org.freedesktop" "dbus-accounts") +gdbus_codegen ("org.freedesktop.Accounts.User.xml" "org.freedesktop" "dbus-user") +gdbus_codegen ("org.freedesktop.ConsoleKit.Manager.xml" "org.freedesktop" "dbus-consolekit-manager") +gdbus_codegen ("org.freedesktop.ConsoleKit.Seat.xml" "org.freedesktop" "dbus-consolekit-seat") +gdbus_codegen ("org.freedesktop.ConsoleKit.Session.xml" "org.freedesktop" "dbus-consolekit-session") +gdbus_codegen ("org.gnome.ScreenSaver.xml" "org" "gnome-screen-saver") +gdbus_codegen ("org.gnome.SessionManager.xml" "org" "gnome-session-manager") +gdbus_codegen ("org.gnome.SessionManager.EndSessionDialog.xml" "org.gnome.SessionManager" "dbus-end-session-dialog") +gdbus_codegen ("upower.xml" "org.freedesktop" "dbus-upower") + +# add warnings/coverage info on handwritten files +# but not the autogenerated ones... +set_source_files_properties (actions.c + backend-dbus.c + guest.c + users.c + utils.c + PROPERTIES COMPILE_FLAGS " -g ${CC_WARNING_ARGS} ${GCOV_FLAGS}") + +# add the bin dir to our include path s.t. our code can find the autogenerated header files +include_directories (${CMAKE_CURRENT_BINARY_DIR} ${SERVICE_INCLUDE_DIRS}) + +add_library (backenddbus STATIC + gnome-screen-saver.c + gnome-screen-saver.h + gnome-session-manager.c + gnome-session-manager.h + dbus-display-manager.c + dbus-display-manager.h + dbus-consolekit-manager.c + dbus-consolekit-manager.h + dbus-consolekit-seat.c + dbus-consolekit-seat.h + dbus-consolekit-session.c + dbus-consolekit-session.h + dbus-accounts.c + dbus-accounts.h + dbus-upower.c + dbus-upower.h + dbus-user.c + dbus-user.h + dbus-webcredentials.c + dbus-webcredentials.h + dbus-end-session-dialog.c + dbus-end-session-dialog.h + actions.c + actions.h + backend-dbus.c + backend-dbus.h + guest.c + guest.h + users.c + users.h + utils.c + utils.h) + diff --git a/src/backend-dbus/actions.c b/src/backend-dbus/actions.c new file mode 100644 index 0000000..8994710 --- /dev/null +++ b/src/backend-dbus/actions.c @@ -0,0 +1,730 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include + +#include "dbus-end-session-dialog.h" +#include "dbus-upower.h" +#include "dbus-webcredentials.h" +#include "gnome-screen-saver.h" +#include "gnome-session-manager.h" + +#include "actions.h" + +enum +{ + END_SESSION_TYPE_LOGOUT = 0, + END_SESSION_TYPE_SHUTDOWN, + END_SESSION_TYPE_REBOOT +}; + +struct _IndicatorSessionActionsDbusPriv +{ + GCancellable * cancellable; + + GSettings * lockdown_settings; + UPower * upower; + GnomeScreenSaver * screen_saver; + GnomeSessionManager * session_manager; + ConsoleKitManager * ck_manager; + ConsoleKitSeat * ck_seat; + DisplayManagerSeat * dm_seat; + Webcredentials * webcredentials; + EndSessionDialog * end_session_dialog; + + gboolean suspend_allowed; + gboolean hibernate_allowed; + gboolean seat_allows_activation; +}; + +typedef IndicatorSessionActionsDbusPriv priv_t; + +G_DEFINE_TYPE (IndicatorSessionActionsDbus, + indicator_session_actions_dbus, + INDICATOR_TYPE_SESSION_ACTIONS) + +/*** +**** +***/ + +static void +log_and_clear_error (GError ** err, const char * loc, const char * func) +{ + if (*err) + { + g_warning ("%s %s: %s", loc, func, (*err)->message); + g_clear_error (err); + } +} + +static void +on_can_activate_sessions (GObject * o, GAsyncResult * res, gpointer gself) +{ + GError * err; + gboolean can_activate_sessions; + + err = NULL; + can_activate_sessions = FALSE; + console_kit_seat_call_can_activate_sessions_finish (CONSOLE_KIT_SEAT(o), + &can_activate_sessions, + res, + &err); + if (err == NULL) + { + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(gself)->priv; + p->seat_allows_activation = can_activate_sessions; + } + + log_and_clear_error (&err, G_STRLOC, G_STRFUNC); +} + +static void +set_ck_seat (IndicatorSessionActionsDbus * self, ConsoleKitSeat * seat) +{ + priv_t * p = self->priv; + + g_clear_object (&p->ck_seat); + + if (seat != NULL) + { + p->ck_seat = g_object_ref (seat); + + console_kit_seat_call_can_activate_sessions (seat, + p->cancellable, + on_can_activate_sessions, + self); + } +} + +/*** +**** +***/ + +static void +set_dm_seat (IndicatorSessionActionsDbus * self, DisplayManagerSeat * seat) +{ + priv_t * p = self->priv; + + if (p->dm_seat != NULL) + { + g_signal_handlers_disconnect_by_data (p->dm_seat, self); + g_clear_object (&p->dm_seat); + } + + if (seat != NULL) + { + p->dm_seat = g_object_ref (seat); + /*g_signal_connect (seat, "notify::has-actions-account", G_CALLBACK(on_notify_has_actions_account), self);*/ + } +} + +static void +on_screensaver_proxy_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself) +{ + GError * err; + GnomeScreenSaver * ss; + + err = NULL; + ss = gnome_screen_saver_proxy_new_for_bus_finish (res, &err); + if (err == NULL) + { + INDICATOR_SESSION_ACTIONS_DBUS(gself)->priv->screen_saver = ss; + } + + log_and_clear_error (&err, G_STRLOC, G_STRFUNC); +} + +static void +on_suspend_allowed_ready (GObject * o, GAsyncResult * res, gpointer gself) +{ + GError * err; + gboolean allowed = FALSE; + + err = NULL; + upower_call_suspend_allowed_finish (UPOWER(o), &allowed, res, &err); + if (err == NULL) + { + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(gself)->priv; + + if (p->suspend_allowed != allowed) + { + p->suspend_allowed = allowed; + indicator_session_actions_notify_can_suspend (gself); + } + } + + log_and_clear_error (&err, G_STRLOC, G_STRFUNC); +} + +static void +on_hibernate_allowed_ready (GObject * o, GAsyncResult * res, gpointer gself) +{ + GError * err; + gboolean allowed = FALSE; + + err = NULL; + upower_call_hibernate_allowed_finish (UPOWER(o), &allowed, res, &err); + if (err == NULL) + { + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(gself)->priv; + + if (p->hibernate_allowed != allowed) + { + p->hibernate_allowed = allowed; + indicator_session_actions_notify_can_hibernate (gself); + } + } + + log_and_clear_error (&err, G_STRLOC, G_STRFUNC); +} + +static void +on_upower_proxy_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself) +{ + GError * err; + UPower * upower; + + err = NULL; + upower = upower_proxy_new_for_bus_finish (res, &err); + if (err == NULL) + { + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(gself)->priv; + + p->upower = upower; + + g_signal_connect_swapped (upower, "notify::can-suspend", + G_CALLBACK(indicator_session_actions_notify_can_suspend), gself); + + g_signal_connect_swapped (upower, "notify::can-hibernate", + G_CALLBACK(indicator_session_actions_notify_can_hibernate), gself); + + upower_call_suspend_allowed (upower, p->cancellable, on_suspend_allowed_ready, gself); + + upower_call_hibernate_allowed (upower, p->cancellable, on_hibernate_allowed_ready, gself); + } + + log_and_clear_error (&err, G_STRLOC, G_STRFUNC); +} + +static void +on_session_manager_proxy_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself) +{ + GError * err; + GnomeSessionManager * sm; + + err = NULL; + sm = gnome_session_manager_proxy_new_for_bus_finish (res, &err); + if (err == NULL) + { + INDICATOR_SESSION_ACTIONS_DBUS(gself)->priv->session_manager = sm; + } + + log_and_clear_error (&err, G_STRLOC, G_STRFUNC); +} + +static void +on_webcredentials_proxy_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself) +{ + GError * err; + Webcredentials * webcredentials; + + err = NULL; + webcredentials = webcredentials_proxy_new_for_bus_finish (res, &err); + if (err == NULL) + { + INDICATOR_SESSION_ACTIONS_DBUS(gself)->priv->webcredentials = webcredentials; + + g_signal_connect_swapped (webcredentials, "notify::error-status", + G_CALLBACK(indicator_session_actions_notify_has_online_account_error), gself); + } + + log_and_clear_error (&err, G_STRLOC, G_STRFUNC); +} + +static void +on_end_session_dialog_proxy_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself) +{ + GError * err; + EndSessionDialog * end_session_dialog; + + err = NULL; + end_session_dialog = end_session_dialog_proxy_new_for_bus_finish (res, &err); + if (err == NULL) + { + INDICATOR_SESSION_ACTIONS_DBUS(gself)->priv->end_session_dialog = end_session_dialog; + + indicator_session_actions_notify_can_prompt (INDICATOR_SESSION_ACTIONS(gself)); + } + + log_and_clear_error (&err, G_STRLOC, G_STRFUNC); +} + +/*** +**** Virtual Functions +***/ + +static gboolean +my_can_lock (IndicatorSessionActions * self) +{ + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + return !g_settings_get_boolean (p->lockdown_settings, "disable-lock-screen"); +} + +static gboolean +my_can_logout (IndicatorSessionActions * self) +{ + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + return !g_settings_get_boolean (p->lockdown_settings, "disable-log-out"); +} + +static gboolean +my_can_switch (IndicatorSessionActions * self) +{ + const priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + return p->seat_allows_activation + && !g_settings_get_boolean (p->lockdown_settings, "disable-user-switching"); +} + +static gboolean +my_can_suspend (IndicatorSessionActions * self) +{ + const priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + return p && p->upower && p->suspend_allowed && upower_get_can_suspend (p->upower); +} + +static gboolean +my_can_hibernate (IndicatorSessionActions * self) +{ + const priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + return p && p->upower && p->hibernate_allowed && upower_get_can_hibernate (p->upower); +} + +static gboolean +my_can_prompt (IndicatorSessionActions * self) +{ + const priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + return (p != NULL) + && (p->end_session_dialog != NULL) + && (g_dbus_proxy_get_name_owner (G_DBUS_PROXY(p->end_session_dialog)) != NULL); +} + +static gboolean +my_has_online_account_error (IndicatorSessionActions * self) +{ + const priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + return p && (p->webcredentials) && (webcredentials_get_error_status (p->webcredentials)); +} + +static void +my_suspend (IndicatorSessionActions * self) +{ + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + g_return_if_fail (p->upower != NULL); + + upower_call_suspend (p->upower, p->cancellable, NULL, NULL); +} + +static void +my_hibernate (IndicatorSessionActions * self) +{ + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + g_return_if_fail (p->upower != NULL); + + upower_call_hibernate (p->upower, p->cancellable, NULL, NULL); +} + +/*** +**** End Session Dialog +***/ + +static void +logout_now (IndicatorSessionActions * self, gboolean try_to_prompt) +{ + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + const int type = try_to_prompt ? 0 : 1; + + g_return_if_fail (p->session_manager != NULL); + + gnome_session_manager_call_logout (p->session_manager, + type, + p->cancellable, + NULL, + NULL); +} + +static void +logout_now_with_prompt (IndicatorSessionActions * self) +{ + logout_now (self, TRUE); +} + +static void +logout_now_quietly (IndicatorSessionActions * self) +{ + logout_now (self, FALSE); +} + +static void +restart_now (IndicatorSessionActions * self) +{ + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + g_return_if_fail (p->ck_manager != NULL); + + console_kit_manager_call_restart (p->ck_manager, p->cancellable, NULL, NULL); +} + +static void +shutdown_now (IndicatorSessionActions * self) +{ + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + g_return_if_fail (p->ck_manager != NULL); + + console_kit_manager_call_stop (p->ck_manager, p->cancellable, NULL, NULL); +} + +static void +stop_listening_to_dialog (IndicatorSessionActionsDbus * self) +{ + g_signal_handlers_disconnect_by_data (self->priv->end_session_dialog, self); +} +static void +on_end_session_dialog_canceled (IndicatorSessionActionsDbus * self) +{ + stop_listening_to_dialog (self); +} +static void +on_end_session_dialog_closed (IndicatorSessionActionsDbus * self) +{ + stop_listening_to_dialog (self); +} + +static void +on_open_end_session_dialog_ready (GObject * o, + GAsyncResult * res, + gpointer gself G_GNUC_UNUSED) +{ + GError * err = NULL; + end_session_dialog_call_open_finish (END_SESSION_DIALOG(o), res, &err); + log_and_clear_error (&err, G_STRLOC, G_STRFUNC); +} + +static void +show_end_session_dialog (IndicatorSessionActionsDbus * self, int type) +{ + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + gpointer o = p->end_session_dialog; + const char * inhibitor_paths[] = { NULL }; + + g_assert (o != NULL); + + g_signal_connect_swapped (o, "confirmed-logout", G_CALLBACK(logout_now_quietly), self); + g_signal_connect_swapped (o, "confirmed-reboot", G_CALLBACK(restart_now), self); + g_signal_connect_swapped (o, "confirmed-shutdown", G_CALLBACK(shutdown_now), self); + g_signal_connect_swapped (o, "canceled", G_CALLBACK(on_end_session_dialog_canceled), self); + g_signal_connect_swapped (o, "closed", G_CALLBACK(on_end_session_dialog_closed), self); + + end_session_dialog_call_open (p->end_session_dialog, type, 0, 0, inhibitor_paths, + p->cancellable, + on_open_end_session_dialog_ready, + self); +} + +static void +my_logout (IndicatorSessionActions * self) +{ + if (my_can_prompt (self)) + show_end_session_dialog (INDICATOR_SESSION_ACTIONS_DBUS(self), END_SESSION_TYPE_LOGOUT); + else + logout_now_with_prompt (self); +} + + +static void +my_restart (IndicatorSessionActions * self) +{ + if (my_can_prompt (self)) + show_end_session_dialog (INDICATOR_SESSION_ACTIONS_DBUS(self), END_SESSION_TYPE_REBOOT); + else + restart_now (self); +} + +static void +my_shutdown (IndicatorSessionActions * self) +{ + /* NB: TYPE_REBOOT instead of TYPE_SHUTDOWN because + the latter adds lock & logout options in Unity... */ + if (my_can_prompt (self)) + show_end_session_dialog (INDICATOR_SESSION_ACTIONS_DBUS(self), END_SESSION_TYPE_REBOOT); + else + shutdown_now (self); +} + +/*** +**** +***/ + +static void +run_outside_app (const char * cmd) +{ + GError * err = NULL; + g_debug ("%s calling \"%s\"", G_STRFUNC, cmd); + g_spawn_command_line_async (cmd, &err); + log_and_clear_error (&err, G_STRLOC, G_STRFUNC); +} + +static void +my_help (IndicatorSessionActions * self G_GNUC_UNUSED) +{ + run_outside_app ("yelp"); +} + +static void +my_settings (IndicatorSessionActions * self G_GNUC_UNUSED) +{ + run_outside_app ("gnome-control-center"); +} + +static void +my_about (IndicatorSessionActions * self G_GNUC_UNUSED) +{ + run_outside_app ("gnome-control-center info"); +} + +/*** +**** +***/ + +static void +my_switch_to_screensaver (IndicatorSessionActions * self) +{ + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + g_return_if_fail (p->screen_saver != NULL); + + gnome_screen_saver_call_lock (p->screen_saver, p->cancellable, NULL, NULL); +} + +static void +my_switch_to_greeter (IndicatorSessionActions * self) +{ + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + g_return_if_fail (p->dm_seat != NULL); + + display_manager_seat_call_switch_to_greeter (p->dm_seat, p->cancellable, + NULL, NULL); +} + +static void +my_switch_to_guest (IndicatorSessionActions * self) +{ + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + g_return_if_fail (p->dm_seat != NULL); + + display_manager_seat_call_switch_to_guest (p->dm_seat, "", + p->cancellable, + NULL, NULL); +} + +static void +my_switch_to_username (IndicatorSessionActions * self, const char * username) +{ + priv_t * p = INDICATOR_SESSION_ACTIONS_DBUS(self)->priv; + + g_return_if_fail (p->dm_seat != NULL); + + display_manager_seat_call_switch_to_user (p->dm_seat, username, "", + p->cancellable, + NULL, NULL); +} + +static void +my_dispose (GObject * o) +{ + IndicatorSessionActionsDbus * self = INDICATOR_SESSION_ACTIONS_DBUS (o); + priv_t * p = self->priv; + + if (p->cancellable != NULL) + { + g_cancellable_cancel (p->cancellable); + g_clear_object (&p->cancellable); + } + + g_clear_object (&p->lockdown_settings); + g_clear_object (&p->ck_manager); + g_clear_object (&p->upower); + g_clear_object (&p->screen_saver); + g_clear_object (&p->session_manager); + g_clear_object (&p->webcredentials); + g_clear_object (&p->end_session_dialog); + set_dm_seat (self, NULL); + set_ck_seat (self, NULL); + + G_OBJECT_CLASS (indicator_session_actions_dbus_parent_class)->dispose (o); +} + +static void +my_finalize (GObject * o) +{ + /*IndicatorSessionActionsDbus * u = INDICATOR_SESSION_ACTIONS_DBUS (o);*/ + + G_OBJECT_CLASS (indicator_session_actions_dbus_parent_class)->finalize (o); +} + +/*** +**** GObject Boilerplate +***/ + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_actions_dbus_class_init (IndicatorSessionActionsDbusClass * klass) +{ + GObjectClass * object_class; + IndicatorSessionActionsClass * actions_class; + + object_class = G_OBJECT_CLASS (klass); + object_class->dispose = my_dispose; + object_class->finalize = my_finalize; + + actions_class = INDICATOR_SESSION_ACTIONS_CLASS (klass); + actions_class->can_lock = my_can_lock; + actions_class->can_logout = my_can_logout; + actions_class->can_switch = my_can_switch; + actions_class->can_suspend = my_can_suspend; + actions_class->can_hibernate = my_can_hibernate; + actions_class->can_prompt = my_can_prompt; + actions_class->has_online_account_error = my_has_online_account_error; + actions_class->logout = my_logout; + actions_class->suspend = my_suspend; + actions_class->hibernate = my_hibernate; + actions_class->restart = my_restart; + actions_class->shutdown = my_shutdown; + actions_class->settings = my_settings; + actions_class->help = my_help; + actions_class->about = my_about; + actions_class->switch_to_screensaver = my_switch_to_screensaver; + actions_class->switch_to_greeter = my_switch_to_greeter; + actions_class->switch_to_guest = my_switch_to_guest; + actions_class->switch_to_username = my_switch_to_username; + + g_type_class_add_private (klass, sizeof (IndicatorSessionActionsDbusPriv)); +} + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_actions_dbus_init (IndicatorSessionActionsDbus * self) +{ + priv_t * p; + GSettings * s; + + p = G_TYPE_INSTANCE_GET_PRIVATE (self, + INDICATOR_TYPE_SESSION_ACTIONS_DBUS, + IndicatorSessionActionsDbusPriv); + p->cancellable = g_cancellable_new (); + p->seat_allows_activation = TRUE; + self->priv = p; + + s = g_settings_new ("org.gnome.desktop.lockdown"); + g_signal_connect_swapped (s, "changed::disable-lock-screen", + G_CALLBACK(indicator_session_actions_notify_can_lock), self); + g_signal_connect_swapped (s, "changed::disable-log-out", + G_CALLBACK(indicator_session_actions_notify_can_logout), self); + g_signal_connect_swapped (s, "changed::disable-user-switching", + G_CALLBACK(indicator_session_actions_notify_can_switch), self); + p->lockdown_settings = s; + + gnome_screen_saver_proxy_new_for_bus (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + "org.gnome.ScreenSaver", + "/org/gnome/ScreenSaver", + p->cancellable, + on_screensaver_proxy_ready, + self); + + upower_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, + "org.freedesktop.UPower", + "/org/freedesktop/UPower", + p->cancellable, + on_upower_proxy_ready, + self); + + gnome_session_manager_proxy_new_for_bus (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + "org.gnome.SessionManager", + "/org/gnome/SessionManager", + p->cancellable, + on_session_manager_proxy_ready, + self); + + webcredentials_proxy_new_for_bus (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + "com.canonical.indicators.webcredentials", + "/com/canonical/indicators/webcredentials", + p->cancellable, + on_webcredentials_proxy_ready, + self); + + end_session_dialog_proxy_new_for_bus (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + "com.canonical.Unity", + "/org/gnome/SessionManager/EndSessionDialog", + p->cancellable, + on_end_session_dialog_proxy_ready, + self); +} + +/*** +**** Public +***/ + +IndicatorSessionActions * +indicator_session_actions_dbus_new (void) +{ + gpointer o = g_object_new (INDICATOR_TYPE_SESSION_ACTIONS_DBUS, NULL); + + return INDICATOR_SESSION_ACTIONS (o); +} + +void +indicator_session_actions_dbus_set_proxies (IndicatorSessionActionsDbus * self, + ConsoleKitManager * ck_manager, + DisplayManagerSeat * dm_seat, + ConsoleKitSeat * ck_seat) +{ + g_return_if_fail (INDICATOR_IS_SESSION_ACTIONS_DBUS(self)); + + self->priv->ck_manager = g_object_ref (ck_manager); + + set_dm_seat (self, dm_seat); + + set_ck_seat (self, ck_seat); +} diff --git a/src/backend-dbus/actions.h b/src/backend-dbus/actions.h new file mode 100644 index 0000000..997dd73 --- /dev/null +++ b/src/backend-dbus/actions.h @@ -0,0 +1,73 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#ifndef __INDICATOR_SESSION_ACTIONS_DBUS_H__ +#define __INDICATOR_SESSION_ACTIONS_DBUS_H__ + +#include +#include + +#include "../actions.h" /* parent class */ +#include "dbus-accounts.h" +#include "dbus-consolekit-manager.h" +#include "dbus-consolekit-seat.h" +#include "dbus-consolekit-session.h" +#include "dbus-display-manager.h" + + +G_BEGIN_DECLS + +#define INDICATOR_TYPE_SESSION_ACTIONS_DBUS (indicator_session_actions_dbus_get_type()) +#define INDICATOR_SESSION_ACTIONS_DBUS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_SESSION_ACTIONS_DBUS, IndicatorSessionActionsDbus)) +#define INDICATOR_SESSION_ACTIONS_DBUS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_SESSION_ACTIONS_DBUS, IndicatorSessionActionsDbusClass)) +#define INDICATOR_IS_SESSION_ACTIONS_DBUS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_SESSION_ACTIONS_DBUS)) + +typedef struct _IndicatorSessionActionsDbus IndicatorSessionActionsDbus; +typedef struct _IndicatorSessionActionsDbusPriv IndicatorSessionActionsDbusPriv; +typedef struct _IndicatorSessionActionsDbusClass IndicatorSessionActionsDbusClass; + +/** + * An implementation of IndicatorSessionActions that gets its user information + * from org.freedesktop.ConsoleKit and org.freedesktop.Accounts over DBus. + */ +struct _IndicatorSessionActionsDbus +{ + /*< private >*/ + IndicatorSessionActions parent; + IndicatorSessionActionsDbusPriv * priv; +}; + +struct _IndicatorSessionActionsDbusClass +{ + IndicatorSessionActionsClass parent_class; +}; + +GType indicator_session_actions_dbus_get_type (void); + +IndicatorSessionActions * indicator_session_actions_dbus_new (void); + +void indicator_session_actions_dbus_set_proxies (IndicatorSessionActionsDbus * self, + ConsoleKitManager * ck_manager, + DisplayManagerSeat * dm_seat, + ConsoleKitSeat * ck_seat); + + +G_END_DECLS + +#endif /* __INDICATOR_SESSION_ACTIONS_DBUS_H__ */ diff --git a/src/backend-dbus/backend-dbus.c b/src/backend-dbus/backend-dbus.c new file mode 100644 index 0000000..ea8f0ec --- /dev/null +++ b/src/backend-dbus/backend-dbus.c @@ -0,0 +1,117 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include "actions.h" +#include "backend-dbus.h" +#include "guest.h" +#include "users.h" +#include "utils.h" + +struct dbus_world_data +{ + GCancellable * cancellable; + IndicatorSessionActionsDbus * actions; + IndicatorSessionUsersDbus * users; + IndicatorSessionGuestDbus * guest; +}; + +static void +on_proxies_ready (ConsoleKitManager * ck_manager, + Accounts * account_manager, + DisplayManagerSeat * dm_seat, + ConsoleKitSeat * ck_seat, + ConsoleKitSession * ck_session, + AccountsUser * active_user G_GNUC_UNUSED, + const GError * error, + gpointer gdata) +{ + struct dbus_world_data * data = gdata; + + if (error == NULL) + { + if (data->actions != NULL) + indicator_session_actions_dbus_set_proxies (data->actions, + ck_manager, + dm_seat, + ck_seat); + + if (data->users != NULL) + indicator_session_users_dbus_set_proxies (data->users, + account_manager, + dm_seat, + ck_seat); + + if (data->guest != NULL) + indicator_session_guest_dbus_set_proxies (data->guest, + account_manager, + dm_seat, + ck_seat, + ck_session); + } + + g_free (data); +} + +/*** +**** +***/ + +void +backend_get (GCancellable * cancellable, + IndicatorSessionActions ** setme_actions, + IndicatorSessionUsers ** setme_users, + IndicatorSessionGuest ** setme_guest) +{ + struct dbus_world_data * data; + + data = g_new0 (struct dbus_world_data, 1); + + if (setme_actions != NULL) + { + IndicatorSessionActions * actions; + actions = indicator_session_actions_dbus_new (); + data->actions = INDICATOR_SESSION_ACTIONS_DBUS (actions); + + *setme_actions = actions; + } + + if (setme_users != NULL) + { + IndicatorSessionUsers * users; + users = indicator_session_users_dbus_new (); + data->users = INDICATOR_SESSION_USERS_DBUS (users); + + *setme_users = users; + } + + if (setme_guest != NULL) + { + IndicatorSessionGuest * guest; + guest = indicator_session_guest_dbus_new (); + data->guest = INDICATOR_SESSION_GUEST_DBUS (guest); + + *setme_guest = guest; + } + + data->cancellable = g_object_ref (cancellable); + + indicator_session_util_get_session_proxies (on_proxies_ready, + data->cancellable, + data); +} diff --git a/src/backend-dbus/backend-dbus.h b/src/backend-dbus/backend-dbus.h new file mode 100644 index 0000000..daf6ac3 --- /dev/null +++ b/src/backend-dbus/backend-dbus.h @@ -0,0 +1,38 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#ifndef __INDICATOR_SESSION_BACKEND_DESKTOP_H__ +#define __INDICATOR_SESSION_BACKEND_DESKTOP_H__ + +#include /* GCancellable */ + +#include "../actions.h" +#include "../guest.h" +#include "../users.h" + +G_BEGIN_DECLS + +void backend_get (GCancellable * cancellable, + IndicatorSessionActions ** setme_actions, + IndicatorSessionUsers ** setme_users, + IndicatorSessionGuest ** setme_guest); + +G_END_DECLS + +#endif diff --git a/src/backend-dbus/com.canonical.indicators.webcredentials.xml b/src/backend-dbus/com.canonical.indicators.webcredentials.xml new file mode 100644 index 0000000..d215081 --- /dev/null +++ b/src/backend-dbus/com.canonical.indicators.webcredentials.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/backend-dbus/display-manager.xml b/src/backend-dbus/display-manager.xml new file mode 100644 index 0000000..07b5f29 --- /dev/null +++ b/src/backend-dbus/display-manager.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/backend-dbus/guest.c b/src/backend-dbus/guest.c new file mode 100644 index 0000000..516ba00 --- /dev/null +++ b/src/backend-dbus/guest.c @@ -0,0 +1,570 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include + +#include "dbus-accounts.h" +#include "dbus-display-manager.h" +#include "dbus-user.h" +#include "dbus-consolekit-seat.h" +#include "dbus-consolekit-manager.h" +#include "dbus-consolekit-session.h" + +#include "guest.h" + +struct _IndicatorSessionGuestDbusPriv +{ + GCancellable * cancellable; + + Accounts * accounts; + AccountsUser * guest; + DisplayManagerSeat * display_manager_seat; + + ConsoleKitSeat * seat; + ConsoleKitSession * active_session; + guint active_uid; + + gboolean guest_is_active; + gboolean guest_is_allowed; +}; + +typedef IndicatorSessionGuestDbusPriv priv_t; + +G_DEFINE_TYPE (IndicatorSessionGuestDbus, + indicator_session_guest_dbus, + INDICATOR_TYPE_SESSION_GUEST) + +/*** +**** +***/ + +static void +check_for_active_guest (IndicatorSessionGuestDbus * self) +{ + gboolean guest_is_active; + priv_t * p = self->priv; + + guest_is_active = (p->active_uid) + && (p->guest != NULL) + && (p->active_uid == accounts_user_get_uid (p->guest)); + + if (p->guest_is_active != guest_is_active) + { + p->guest_is_active = guest_is_active; + + indicator_session_guest_notify_active (INDICATOR_SESSION_GUEST(self)); + } +} + +static void +set_active_uid (IndicatorSessionGuestDbus * self, guint uid) +{ + self->priv->active_uid = uid; + + check_for_active_guest (self); +} + +static void +on_active_uid_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself) +{ + guint uid; + GError * err; + IndicatorSessionGuestDbus * self; + g_debug ("%s %s", G_STRLOC, G_STRFUNC); + + uid = 0; + err = NULL; + self = INDICATOR_SESSION_GUEST_DBUS (gself); + console_kit_session_call_get_unix_user_finish (self->priv->active_session, &uid, res, &err); + + if (err != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); + } + else + { + set_active_uid (self, uid); + } +} + + +static void +set_active_session (IndicatorSessionGuestDbus * self, + ConsoleKitSession * session) +{ + priv_t * p = self->priv; + + if (p->active_session != NULL) + { + g_debug ("%s %s active_session refcount is %d before we unref", G_STRLOC, G_STRFUNC, G_OBJECT(self->priv->active_session)->ref_count); + + g_clear_object (&p->active_session); + } + + if (session != NULL) + { + p->active_session = g_object_ref (session); + + console_kit_session_call_get_unix_user (session, + p->cancellable, + on_active_uid_ready, + self); + } +} + +static void +on_active_session_proxy_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself) +{ + GError * err; + ConsoleKitSession * session; + + err = NULL; + session = console_kit_session_proxy_new_finish (res, &err); + + if (err != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + } + else + { + set_active_session (gself, session); + } + + g_clear_object (&session); +} + + +static void +on_active_session_changed (ConsoleKitSeat * seat G_GNUC_UNUSED, + const gchar * ssid, + IndicatorSessionGuestDbus * self) +{ + console_kit_session_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, + "org.freedesktop.ConsoleKit", + ssid, + self->priv->cancellable, + on_active_session_proxy_ready, + self); +} + +static void +set_seat (IndicatorSessionGuestDbus * self, + ConsoleKitSeat * seat) +{ + priv_t * p = self->priv; + + if (p->seat != NULL) + { +g_debug ("%s %s guest-dbus disconnecting from %p", G_STRLOC, G_STRFUNC, (void*)p->seat); + g_signal_handlers_disconnect_by_data (p->seat, self); +g_debug ("%s %s seat refcount is %d before our unref", G_STRLOC, G_STRFUNC, G_OBJECT(p->seat)->ref_count); + + g_clear_object (&p->seat); + } + + if (seat != NULL) + { + p->seat = g_object_ref (seat); +g_debug ("%s %s guest-dbus connecting to %p", G_STRLOC, G_STRFUNC, (void*)p->seat); + + g_signal_connect (seat, "active-session-changed", + G_CALLBACK(on_active_session_changed), self); + } +} + +/*** +**** +***/ + +static void +set_guest (IndicatorSessionGuestDbus * self, + AccountsUser * guest) +{ + priv_t * p = self->priv; + + if (p->guest != NULL) + { + g_debug ("%s %s guest refcount is %d before we unref", G_STRLOC, G_STRFUNC, G_OBJECT(p->guest)->ref_count); + + g_clear_object (&p->guest); + } + + if (guest != NULL) + { + p->guest = g_object_ref (guest); + } + + g_debug ("%s %s guest proxy is now %p", G_STRLOC, G_STRFUNC, (void*)guest); + indicator_session_guest_notify_logged_in (INDICATOR_SESSION_GUEST(self)); + + check_for_active_guest (self); +} + +static void +on_user_deleted (IndicatorSessionGuestDbus * self, + const gchar * path) +{ + AccountsUser * guest = self->priv->guest; + g_debug ("%s %s %s", G_STRLOC, G_STRFUNC, path); + + if (guest != NULL) + if (!g_strcmp0 (path, g_dbus_proxy_get_object_path (G_DBUS_PROXY(guest)))) + set_guest (self, NULL); +} + +static gboolean +is_guest (AccountsUser * user) +{ + /* a guest will look like this: + username:[guest-jjbEVV] realname:[Guest] system:[1] */ + return IS_ACCOUNTS_USER(user) + && accounts_user_get_system_account (user) + && !g_ascii_strcasecmp (accounts_user_get_real_name(user), "Guest"); +} + +static void +on_user_proxy_ready (GObject * o G_GNUC_UNUSED, + GAsyncResult * res, + gpointer self) +{ + GError * err; + AccountsUser * user; + + err = NULL; + user = accounts_user_proxy_new_for_bus_finish (res, &err); + + if (err != NULL) + { + g_warning ("%s: %s", G_STRFUNC, err->message); + g_error_free (err); + } + else if (is_guest (user)) + { + g_debug ("%s %s got guest", G_STRLOC, G_STRFUNC); + set_guest (INDICATOR_SESSION_GUEST_DBUS(self), user); + } + + g_clear_object (&user); +} + +static void +create_user_proxy_for_path (IndicatorSessionGuestDbus * self, + const char * path) +{ + const char * name = "org.freedesktop.Accounts"; + const GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES; + g_debug ("%s %s creating proxy for %s", G_STRLOC, G_STRFUNC, path); + + accounts_user_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + flags, name, path, + self->priv->cancellable, + on_user_proxy_ready, self); +} + +static void +on_user_list_ready (GObject * o, GAsyncResult * res, gpointer gself) +{ + GError * err; + gchar ** paths; + + err = NULL; + paths = NULL; + accounts_call_list_cached_users_finish (ACCOUNTS(o), &paths, res, &err); + if (err != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); + } + else + { + int i; + + for (i=0; paths && paths[i]; ++i) + create_user_proxy_for_path (gself, paths[i]); + + g_strfreev (paths); + } +} + +static void +set_account_manager (IndicatorSessionGuestDbus * self, + Accounts * a) +{ + g_debug ("%s %s setting account manager to %p", G_STRLOC, G_STRFUNC, (void*)a); + + if (self->priv->accounts != NULL) + { +g_debug ("%s %s guest-dbus disconnecting from %p", G_STRLOC, G_STRFUNC, (void*)self->priv->accounts); + g_signal_handlers_disconnect_by_data (self->priv->accounts, self); +g_debug ("%s %s account manager refcount is %d before our unref", G_STRLOC, G_STRFUNC, G_OBJECT(self->priv->accounts)->ref_count); + g_clear_object (&self->priv->accounts); + } + + if (a != NULL) + { + self->priv->accounts = g_object_ref (a); + +g_debug ("%s %s guest-dbus connecting to %p", G_STRLOC, G_STRFUNC, (void*)self->priv->accounts); + g_signal_connect_swapped (a, "user-added", + G_CALLBACK(create_user_proxy_for_path), self); + + g_signal_connect_swapped (a, "user-deleted", + G_CALLBACK(on_user_deleted), self); + + accounts_call_list_cached_users (a, + self->priv->cancellable, + on_user_list_ready, + self); + } +} + +static void +set_guest_is_allowed (IndicatorSessionGuestDbus * self, gboolean guest_is_allowed) +{ + priv_t * p = self->priv; + g_debug ("%s %s guest_is_allowed: %d", G_STRLOC, G_STRFUNC, (int)guest_is_allowed); + + if (p->guest_is_allowed != guest_is_allowed) + { + p->guest_is_allowed = guest_is_allowed; + + indicator_session_guest_notify_allowed (INDICATOR_SESSION_GUEST (self)); + } +} + +static void +on_notify_has_guest_account (GObject * seat, GParamSpec * pspec G_GNUC_UNUSED, gpointer gself) +{ + set_guest_is_allowed (INDICATOR_SESSION_GUEST_DBUS (gself), + display_manager_seat_get_has_guest_account (DISPLAY_MANAGER_SEAT(seat))); +} + +static void +set_display_manager_seat (IndicatorSessionGuestDbus * self, DisplayManagerSeat * seat) +{ + priv_t * p = self->priv; + + if (p->display_manager_seat != NULL) + { + g_signal_handlers_disconnect_by_data (p->display_manager_seat, self); + g_debug ("%s %s before we unref, dm seat's refcount is %d", G_STRLOC, G_STRFUNC, G_OBJECT(p->display_manager_seat)->ref_count); + g_clear_object (&p->display_manager_seat); + } + + if (seat != NULL) + { + p->display_manager_seat = g_object_ref (seat); + + g_signal_connect (seat, "notify::has-guest-account", G_CALLBACK(on_notify_has_guest_account), self); + + on_notify_has_guest_account (G_OBJECT(seat), NULL, self); + } +} + +#if 0 +static void +on_display_manager_seat_proxy_ready (GObject * o, GAsyncResult * res, gpointer gself) +{ + GError * err; + DisplayManagerSeat * seat; + g_debug ("%s %s", G_STRLOC, G_STRFUNC); + + err = NULL; + seat = display_manager_seat_proxy_new_for_bus_finish (res, &err); + if (err != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); + } + else + { + set_display_manager_seat (INDICATOR_SESSION_GUEST_DBUS(gself), seat); + } + + g_clear_object (&seat); +} +#endif + +static void +on_switch_to_guest_done (GObject * o, GAsyncResult * res, gpointer unused G_GNUC_UNUSED) +{ + GError * err; + g_debug ("%s %s", G_STRLOC, G_STRFUNC); + + err = NULL; + display_manager_seat_call_switch_to_guest_finish (DISPLAY_MANAGER_SEAT(o), res, &err); + if (err != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); + } +} + +/*** +**** Virtual Functions +***/ + +static void +my_dispose (GObject * o) +{ + IndicatorSessionGuestDbus * self = INDICATOR_SESSION_GUEST_DBUS (o); + + if (self->priv->cancellable != NULL) + { + g_cancellable_cancel (self->priv->cancellable); + g_clear_object (&self->priv->cancellable); + } + + set_seat (self, NULL); + set_active_session (self, NULL); + set_account_manager (self, NULL); + set_display_manager_seat (self, NULL); + g_clear_object (&self->priv->guest); + + G_OBJECT_CLASS (indicator_session_guest_dbus_parent_class)->dispose (o); +} + +static void +my_finalize (GObject * o) +{ + /*IndicatorSessionGuestDbus * u = INDICATOR_SESSION_GUEST_DBUS (o);*/ + + G_OBJECT_CLASS (indicator_session_guest_dbus_parent_class)->finalize (o); +} + +static gboolean +my_is_allowed (IndicatorSessionGuest * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_GUEST_DBUS(self), FALSE); + + return INDICATOR_SESSION_GUEST_DBUS(self)->priv->guest_is_allowed; +} + +static gboolean +my_is_logged_in (IndicatorSessionGuest * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_GUEST_DBUS(self), FALSE); + + return INDICATOR_SESSION_GUEST_DBUS(self)->priv->guest != NULL; +} + +static gboolean +my_is_active (IndicatorSessionGuest * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_GUEST_DBUS(self), FALSE); + + return INDICATOR_SESSION_GUEST_DBUS(self)->priv->guest_is_active; +} + +static void +my_switch_to_guest (IndicatorSessionGuest * self) +{ + priv_t * p; + g_debug ("%s %s", G_STRLOC, G_STRFUNC); + + g_return_if_fail (INDICATOR_IS_SESSION_GUEST_DBUS(self)); + + p = INDICATOR_SESSION_GUEST_DBUS(self)->priv; + + if (p->display_manager_seat != NULL) + { + display_manager_seat_call_switch_to_guest (p->display_manager_seat, + "", + p->cancellable, + on_switch_to_guest_done, + self); + } +} + +/*** +**** GObject Boilerplate +***/ + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_guest_dbus_class_init (IndicatorSessionGuestDbusClass * klass) +{ + GObjectClass * object_class; + IndicatorSessionGuestClass * guest_class; + + object_class = G_OBJECT_CLASS (klass); + object_class->dispose = my_dispose; + object_class->finalize = my_finalize; + + guest_class = INDICATOR_SESSION_GUEST_CLASS (klass); + guest_class->is_allowed = my_is_allowed; + guest_class->is_logged_in = my_is_logged_in; + guest_class->is_active = my_is_active; + guest_class->switch_to_guest = my_switch_to_guest; + + g_type_class_add_private (klass, sizeof (IndicatorSessionGuestDbusPriv)); +} + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_guest_dbus_init (IndicatorSessionGuestDbus * self) +{ + priv_t * p; + + p = G_TYPE_INSTANCE_GET_PRIVATE (self, + INDICATOR_TYPE_SESSION_GUEST_DBUS, + IndicatorSessionGuestDbusPriv); + p->cancellable = g_cancellable_new (); + self->priv = p; + +#if 0 + display_manager_seat_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, + "org.freedesktop.DisplayManager", + g_getenv ("XDG_SEAT_PATH"), + self->priv->cancellable, + on_display_manager_seat_proxy_ready, + self); +#endif +} + +/*** +**** Public +***/ + +IndicatorSessionGuest * +indicator_session_guest_dbus_new (void) +{ + gpointer o = g_object_new (INDICATOR_TYPE_SESSION_GUEST_DBUS, NULL); + + return INDICATOR_SESSION_GUEST (o); +} + +void +indicator_session_guest_dbus_set_proxies (IndicatorSessionGuestDbus * self, + Accounts * accounts, + DisplayManagerSeat * dm_seat, + ConsoleKitSeat * seat, + ConsoleKitSession * session) +{ + g_return_if_fail (INDICATOR_IS_SESSION_GUEST_DBUS(self)); + g_debug ("%s %s accounts %p seat %p session %p", G_STRLOC, G_STRFUNC, (void*)accounts, (void*)seat, (void*)session); + + set_account_manager (self, accounts); + set_display_manager_seat (self, dm_seat); + set_seat (self, seat); + set_active_session (self, session); +} diff --git a/src/backend-dbus/guest.h b/src/backend-dbus/guest.h new file mode 100644 index 0000000..03b6b28 --- /dev/null +++ b/src/backend-dbus/guest.h @@ -0,0 +1,72 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#ifndef __GUEST_DBUS_H__ +#define __GUEST_DBUS_H__ + +#include +#include + +#include "../guest.h" /* parent class */ +#include "dbus-accounts.h" +#include "dbus-consolekit-seat.h" +#include "dbus-consolekit-session.h" +#include "dbus-display-manager.h" + + +G_BEGIN_DECLS + +#define INDICATOR_TYPE_SESSION_GUEST_DBUS (indicator_session_guest_dbus_get_type()) +#define INDICATOR_SESSION_GUEST_DBUS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_SESSION_GUEST_DBUS, IndicatorSessionGuestDbus)) +#define INDICATOR_SESSION_GUEST_DBUS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_SESSION_GUEST_DBUS, IndicatorSessionGuestDbusClass)) +#define INDICATOR_IS_SESSION_GUEST_DBUS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_SESSION_GUEST_DBUS)) + +typedef struct _IndicatorSessionGuestDbus IndicatorSessionGuestDbus; +typedef struct _IndicatorSessionGuestDbusPriv IndicatorSessionGuestDbusPriv; +typedef struct _IndicatorSessionGuestDbusClass IndicatorSessionGuestDbusClass; + +/** + * An implementation of IndicatorSessionGuest that gets its user information + * from org.freedesktop.ConsoleKit and org.freedesktop.Accounts over DBus. + */ +struct _IndicatorSessionGuestDbus +{ + /*< private >*/ + IndicatorSessionGuest parent; + IndicatorSessionGuestDbusPriv * priv; +}; + +struct _IndicatorSessionGuestDbusClass +{ + IndicatorSessionGuestClass parent_class; +}; + +GType indicator_session_guest_dbus_get_type (void); + +IndicatorSessionGuest * indicator_session_guest_dbus_new (void); + +void indicator_session_guest_dbus_set_proxies (IndicatorSessionGuestDbus *, + Accounts *, + DisplayManagerSeat *, + ConsoleKitSeat *, + ConsoleKitSession *); + +G_END_DECLS + +#endif diff --git a/src/backend-dbus/org.freedesktop.Accounts.User.xml b/src/backend-dbus/org.freedesktop.Accounts.User.xml new file mode 100644 index 0000000..53f54d4 --- /dev/null +++ b/src/backend-dbus/org.freedesktop.Accounts.User.xml @@ -0,0 +1,744 @@ + + + + + + + + + + + The new username. + + + + + + + Sets the users username. Note that it is usually not allowed + to have multiple users with the same username. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.user-administration + To change the username of any user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new name, typically in the form "Firstname Lastname". + + + + + + + Sets the users real name. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change his own name + + + org.freedesktop.accounts.user-administration + To change the name of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new email address. + + + + + + + Sets the users email address. + + + Note that setting an email address in the AccountsService is + not the same as configuring a mail client. Mail clients might + default to email address that is configured here, though. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change his own email address + + + org.freedesktop.accounts.user-administration + To change the email address of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new language, as a locale specification like "de_DE.UTF-8". + + + + + + + Sets the users language. + + + The expectation is that display managers will start the + users session with this locale. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change his own language + + + org.freedesktop.accounts.user-administration + To change the language of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + + The new xsession to start (e.g. "gnome") + + + + + + + Sets the users x session. + + + The expectation is that display managers will log the user in to this + specified session, if available. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change his own language + + + org.freedesktop.accounts.user-administration + To change the language of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new location as a freeform string. + + + + + + + Sets the users location. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change his own location + + + org.freedesktop.accounts.user-administration + To change the location of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new homedir as an absolute path. + + + + + + + Sets the users home directory. + + + Note that changing the users home directory moves all the content + from the old location to the new one, and is potentially an + expensive operation. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.user-administration + To change the home directory of a user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new user shell. + + + + + + + Sets the users shell. + + + Note that setting the shell to a non-allowed program may + prevent the user from logging in. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.user-administration + To change the shell of a user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The absolute filename of a png file to use as the users icon. + + + + + + + Sets the users icon. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change his own icon + + + org.freedesktop.accounts.user-administration + To change the icon of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + Whether to lock or unlock the users account. + + + + + + + Locks or unlocks a users account. + + + Locking an account prevents the user from logging in. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.user-administration + To lock or unlock user accounts + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new account type, encoded as an integer: + + + 0 + Standard user + + + 1 + Administrator + + + + + + + + + Changes the users account type. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.user-administration + To change an account type + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new password mode, encoded as an integer: + + + 0 + Regular password + + + 1 + Password must be set at next login + + + 2 + No password + + + + + + + + + Changes the users password mode. + + + Note that changing the password mode has the side-effect of + unlocking the account. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.user-administration + To change a users password mode + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The crypted password. + + + + + + + The password hint. + + + + + + + Sets a new password for this user. + + + Note that setting a password has the side-effect of + unlocking the account. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.user-administration + To change the password of a user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + Whether to enable automatic login for this user. + + + + + + + Enables or disables automatic login for a user. + + + Note that usually only one user can have automatic login + enabled, so turning it on for a user will disable it for + the previously configured autologin user. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.set-login-option + To change the login screen configuration + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + The uid of the user. + + + + + + + + + + The username of the user. + + + + + + + + + + The users real name. + + + + + + + + + + The users account type, encoded as an integer: + + + 0 + Standard user + + + 1 + Administrator + + + + + + + + + + + + The users home directory. + + + + + + + + + + The users shell. + + + + + + + + + + The email address. + + + + + + + + + + The users language, as a locale specification like "de_DE.UTF-8". + + + + + + + + + + The users x session. + + + + + + + + + + The users location. + + + + + + + + + + How often the user has logged in. + + + + + + + + + + The filename of a png file containing the users icon. + + + + + + + + + + Whether the users account is locked. + + + + + + + + + + The password mode for the user account, encoded as an integer: + + + 0 + Regular password + + + 1 + Password must be set at next login + + + 2 + No password + + + + + + + + + + + + The password hint for the user. + + + + + + + + + + Whether automatic login is enabled for the user. + + + + + + + + + + Whether this is a 'system' account, like 'root' or 'nobody'. + System accounts should normally not appear in lists of + users, and ListCachedUsers will not include such accounts. + + + + + + + + + + Emitted when the user is changed. + + + + + + + diff --git a/src/backend-dbus/org.freedesktop.Accounts.xml b/src/backend-dbus/org.freedesktop.Accounts.xml new file mode 100644 index 0000000..9c19761 --- /dev/null +++ b/src/backend-dbus/org.freedesktop.Accounts.xml @@ -0,0 +1,194 @@ + + + + + + + + + + Object paths of cached users + + + + + + Lists users which have logged into the system locally before. + This is not meant to return an exhaustive list of all users. + It is possible for FindUserByName() + to return a user that's not on the list. + + + + + + + + + The uid to look up + + + Object path of user + + + + + + Finds a user by uid. + + + + if no user with the given uid exists + + + + + + + + The username to look up + + + Object path of user + + + + + + Finds a user by its username. + + + + if no user with the given username exists + + + + + + + + The username for the new user + + + + The real name for the new user + + + Object path of the new user + + + + The account type, encoded as an integer + + + + + + Creates a new user account. + + + The accountType argument can take the following values: + + + + 0 + Standard user + + + 1 + Administrator + + + 2 + Supervised user + + + + + The caller needs the org.freedesktop.accounts.user-administration PolicyKit authorization. + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + The uid to delete + + + Whether to remove the users files + + + + + + Deletes a user account. + + + + The caller needs the org.freedesktop.accounts.user-administration PolicyKit authorization. + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + Object path of the user that was added. + + + + + Emitted when a user is added. + + + + + + + + Object path of the user that was deleted. + + + + + Emitted when a user is deleted. + + + + + + + + Object path of the user that was changed. + + + + + Emitted when a user is changed. + + + + + + + + + + The version of the running daemon. + + + + + + + diff --git a/src/backend-dbus/org.freedesktop.ConsoleKit.Manager.xml b/src/backend-dbus/org.freedesktop.ConsoleKit.Manager.xml new file mode 100644 index 0000000..f903b55 --- /dev/null +++ b/src/backend-dbus/org.freedesktop.ConsoleKit.Manager.xml @@ -0,0 +1,353 @@ + + + + + + + + + This method initiates a request to restart (ie. reboot) the computer system. + + + + + + + + + + + + + + This method initiates a request to stop (ie. shutdown) the computer system. + + + + + + + + + + + + + + The secret cookie that is used to identify the new session + + + + + This method requests that a new Session + be created for the calling process. The properties of this new Session are set automatically + from information collected about the calling process. + + This new session exists until the calling process disconnects from the system bus or + calls CloseSession(). + + It is the responsibility of the calling process to set the environment variable + XDG_SESSION_COOKIE to the value of the returned cookie. This cookie should only + be made available to child processes of the caller so that they may be identified + as members of this session. + + See this simple example: + + DBusError error; + DBusMessage *message; + DBusMessage *reply; + + message = dbus_message_new_method_call ("org.freedesktop.ConsoleKit", + "/org/freedesktop/ConsoleKit/Manager", + "org.freedesktop.ConsoleKit.Manager", + "OpenSession"); + if (message == NULL) { + goto out; + } + + dbus_error_init (&error); + reply = dbus_connection_send_with_reply_and_block (connector->connection, + message, + -1, + &error); + if (reply == NULL) { + goto out; + } + + dbus_error_init (&error); + if (! dbus_message_get_args (reply, + &error, + DBUS_TYPE_STRING, &cookie, + DBUS_TYPE_INVALID)) { + goto out; + } + + + + OpenSessionWithParameters() + + + + + + + An array of sets of property names and values + + + + + The secret cookie that is used to identify the new session + + + + + This method requests that a new Session + be created for the calling process. The properties of this new Session are from the + parameters provided. + + This new session exists until the calling process disconnects from the system bus or + calls CloseSession(). + + It is the responsibility of the calling process to set the environment variable + XDG_SESSION_COOKIE to the value of the returned cookie. This cookie should only + be made available to child processes of the caller so that they may be identified + as members of this session. + + See the Session properties for a list of valid parameters. + + org.freedesktop.ConsoleKit.Session + This method is restricted to privileged users by D-Bus policy. + + + + + + + The secret cookie that is used to identify the session + + + + + Whether the session was successfully closed + + + + + This method is used to close the session identified by the supplied cookie. + + The session can only be closed by the same process that opened the session. + + + + + + + + + an array of Seat IDs + + + + + This gets a list of all the Seats + that are currently present on the system. + Each Seat ID is an D-Bus object path for the object that implements the + Seat interface. + + org.freedesktop.ConsoleKit.Seat + + + + + + + an array of Session IDs + + + + + This gets a list of all the Sessions + that are currently present on the system. + Each Session ID is an D-Bus object path for the object that implements the + Session interface. + + org.freedesktop.ConsoleKit.Session + + + + + + + + The secret cookie that is used to identify the session + + + + + The object identifier for the current session + + + + + Returns the session ID that is associated with the specified cookie. + + + + + + + + + The POSIX process ID + + + + + The object identifier for the current session + + + + + Attempts to determine the session ID for the specified + POSIX process ID (pid). + + + + + + + + + The object identifier for the current session + + + + + Attempts to determine the session ID that the caller belongs to. + + See this example of using dbus-send: + + dbus-send --system --dest=org.freedesktop.ConsoleKit \ + --type=method_call --print-reply --reply-timeout=2000 \ + /org/freedesktop/ConsoleKit/Manager \ + org.freedesktop.ConsoleKit.Manager.GetCurrentSession + + + + + + + + + POSIX User identification + + + + + an array of Session IDs + + + + + This gets a list of all the Sessions + that are currently open for the specified user. + Each Session ID is an D-Bus object path for the object that implements the + Session interface. + + + + + + + + User identification + + + + + an array of Session IDs + + + + + This gets a list of all the Sessions + that are currently open for the specified user. + Each Session ID is an D-Bus object path for the object that implements the + Session interface. + + + + + + + + + The value of the system-idle-hint + + + + + Returns TRUE if the idle-hint + property of every open session is TRUE or if there are no open sessions. + + + + + + + + An ISO 8601 format date-type string + + + + + Returns an ISO 8601 date-time string that corresponds to + the time of the last change of the system-idle-hint. + + + + + + + + + The Seat ID for the added seat + + + + + Emitted when a Seat has been added to the system. + + + + + + + + The Seat ID for the removed seat + + + + + Emitted when a Seat has been removed from the system. + + + + + + + + The value of the system-idle-hint + + + + + Emitted when the value of the system-idle-hint has changed. + + + + + + diff --git a/src/backend-dbus/org.freedesktop.ConsoleKit.Seat.xml b/src/backend-dbus/org.freedesktop.ConsoleKit.Seat.xml new file mode 100644 index 0000000..58c2ce7 --- /dev/null +++ b/src/backend-dbus/org.freedesktop.ConsoleKit.Seat.xml @@ -0,0 +1,164 @@ + + + + + + + A seat is a collection of sessions and a set of hardware (usually at +least a keyboard and mouse). Only one session may be active on a +seat at a time. + + + + + + + Seat ID + + + + + Returns the ID for Seat. + + + + + + + + an array of Session IDs + + + + + This gets a list of all the Sessions + that are currently attached to this seat. + Each Session ID is an D-Bus object path for the object that implements the + Session interface. + + + + + + + + an array of devices + + + + + This gets a list of all the devices + that are currently associated with this seat. + Each device is an D-Bus structure that represents + the device type and the device id. + + + + + + + + + Session ID + + + + + Gets the Session ID that is currently active on this Seat. + Returns NULL if there is no active session. + + + + + + + + TRUE if seat supports session activation + + + + Used to determine whether the seat supports session activation. + + + + + + + + + Session ID + + + + + Attempt to activate the specified session. In most + cases, if successful, this will cause the session to + become visible and take control of the hardware that is + associated with this seat. + + Activate() + + + + + + + Session ID + + + + + Emitted when the active session has changed. + + + + + + + Session ID + + + + + Emitted when a session has been added to the seat. + + + + + + + Session ID + + + + + Emitted when a session has been removed from the seat. + + + + + + + Device structure + + + + + Emitted when a device has been associated with the seat. + + + + + + + Device structure + + + + + Emitted when a device has been dissociated from the seat. + + + + + diff --git a/src/backend-dbus/org.freedesktop.ConsoleKit.Session.xml b/src/backend-dbus/org.freedesktop.ConsoleKit.Session.xml new file mode 100644 index 0000000..b6e1cdb --- /dev/null +++ b/src/backend-dbus/org.freedesktop.ConsoleKit.Session.xml @@ -0,0 +1,435 @@ + + + + + + + Session objects represent and store information + related to a user session. + + The properties associated with the Session + specifically refer to the properties of the "session leader". + + + + + + + Session ID + + + + Returns the ID for Session. + + + + + + + Seat ID + + + + Returns the ID for the Seat the Session is + attached to. + + org.freedesktop.ConsoleKit.Seat + + + + + + Session type + + + + + Returns the type of the session. + Warning: we haven't yet defined the allowed values for this property. + It is probably best to avoid this until we do. + + + session-type + + + + + + User ID + + + + Returns the user that the session belongs to. + + + user + + + + + + POSIX User ID + + + + Returns the POSIX user ID that the session belongs to. + + unix-user + + + + + + The value of the X11 display + + + + Returns the value of the X11 DISPLAY for this session + if one is present. + + x11-display + + + + + + The value of the X11 display device + + + + Returns the value of the display device (aka TTY) that the + X11 display for the session is connected to. If there is no x11-display set then this value + is undefined. + + x11-display-device + + + + + + The value of the display device + + + + Returns the value of the display device (aka TTY) that the + session is connected to. + + display-device + + + + + + The remote host name + + + + Returns the value of the remote host name for the session. + + + remote-host-name + + + + + + The value of the native system login session ID + + + + Returns the value of the login session ID that the + underlying system uses to enforce session boundaries. If there is no login session ID + set then this value is an empty string. + + + + + + + TRUE if the session is active, otherwise FALSE + + + + Returns whether the session is active on the Seat that + it is attached to. + If the session is not attached to a seat this value is undefined. + + + active + + + + + + TRUE if the session is local, otherwise FALSE + + + + Returns whether the session is local + FIXME: we need to come up with a concrete definition for this value. + It was originally used as a way to identify XDMCP sessions that originate + from a remote system. + + + is-local + + + + + + An ISO 8601 format date-type string + + + + + Returns an ISO 8601 date-time string that corresponds to + the time that the session was opened. + + + + + + + + + + Attempt to activate the this session. In most + cases, if successful, this will cause the session to + become visible and become active on the seat that it + is attached to. + + Seat.ActivateSession() + + + + + + + This will cause a Lock + signal to be emitted for this session. + + + This method is restricted to privileged users by D-Bus policy. + Lock signal + + + + + + + This will cause an Unlock + signal to be emitted for this session. + + This can be used by login managers to unlock a session before it is + re-activated during fast-user-switching. + + + This method is restricted to privileged users by D-Bus policy. + Unlock signal + + + + + + + The value of the idle-hint + + + + + Gets the value of the idle-hint + property. + + + idle-hint + + + + + + An ISO 8601 format date-type string + + + + + Returns an ISO 8601 date-time string that corresponds to + the time of the last change of the idle-hint. + + + + + + + + + boolean value to set the idle-hint to + + + + + This may be used by the session to indicate that + it is idle. + + Use of this method is restricted to the user + that owns the session. + + + + + + + + TRUE if the session is active, otherwise FALSE + + + + + Emitted when the active property has changed. + + + + + + + the new value of idle-hint + + + + + Emitted when the idle-hint property has changed. + + + + + + + Emitted in response to a call to the Lock() method. + It is intended that the screensaver for the session should lock the screen in response to this signal. + + + + + + + Emitted in response to a call to the Unlock() method. + It is intended that the screensaver for the session should unlock the screen in response to this signal. + + + + + + + + The user assigned to the session. + + + + + + + The user assigned to the session. + + + + + + + + The type of the session. + Warning: we haven't yet defined the allowed values for this property. + It is probably best to avoid this until we do. + + + + + + + + The remote host name for the session. + + This will be set in situations where the session is + opened and controlled from a remote system. + + For example, this value will be set when the + session is created from an SSH or XDMCP connection. + + + + + + + + The display device (aka TTY) that the + session is connected to. + + + + + + + + Value of the X11 DISPLAY for this session + if one is present. + + + + + + + + + The display device (aka TTY) that the X11 display for the + session is connected to. If there is no x11-display set then + this value is undefined. + + + + + + + + + Whether the session is active on the Seat that + it is attached to. + If the session is not attached to a seat this value is undefined. + + + + + + + + + Whether the session is local + FIXME: we need to come up with a concrete definition for this value. + It was originally used as a way to identify XDMCP sessions that originate + from a remote system. + + + + + + + + + This is a hint used to indicate that the session may be idle. + + + For sessions with a x11-display set (ie. graphical + sessions), it is up to each session to delegate the + responsibility for updating this value. Typically, the + screensaver will set this. + + However, for non-graphical sessions with a display-device set + the Session object itself will periodically update this value based + on the activity detected on the display-device itself. + + + This should not be considered authoritative. + + + + + + + diff --git a/src/backend-dbus/org.gnome.ScreenSaver.xml b/src/backend-dbus/org.gnome.ScreenSaver.xml new file mode 100644 index 0000000..c21fdc5 --- /dev/null +++ b/src/backend-dbus/org.gnome.ScreenSaver.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/src/backend-dbus/org.gnome.SessionManager.EndSessionDialog.xml b/src/backend-dbus/org.gnome.SessionManager.EndSessionDialog.xml new file mode 100644 index 0000000..5392de0 --- /dev/null +++ b/src/backend-dbus/org.gnome.SessionManager.EndSessionDialog.xml @@ -0,0 +1,53 @@ + + + + + + + + + The type of dialog to show. + 0 for logout, 1 for shutdown, 2 for restart. + + + + + + + Timestamp of the user-initiated event which triggered + the call, or 0 if the call was not triggered by an event. + + + + + + + The number of seconds which the dialog should stay open + before automatic action is taken. + + + + + + + The object paths of all inhibitors that are registered + for the action. + + + + + + This function opens a dialog which asks the user for confirmation + of a logout, poweroff or reboot action. The dialog has a timeout + after which the action is automatically taken, and it should show + the inhibitors to the user. + + + + + + + + + + diff --git a/src/backend-dbus/org.gnome.SessionManager.xml b/src/backend-dbus/org.gnome.SessionManager.xml new file mode 100644 index 0000000..eb69180 --- /dev/null +++ b/src/backend-dbus/org.gnome.SessionManager.xml @@ -0,0 +1,451 @@ + + + + + + + + + + + The variable name + + + + + The value + + + + + Adds the variable name to the application launch environment with the specified value. May only be used during the Session Manager initialization phase. + + + + + + + + The locale category + + + + + The value + + + + + Reads the current state of the specific locale category. + + + + + + + + The error message + + + + + Whether the error should be treated as fatal + + + + + May be used by applications launched during the Session Manager initialization phase to indicate there was a problem. + + + + + + + + + + + The application identifier + + + + + Client startup identifier + + + + + The object path of the newly registered client + + + + + Register the caller as a Session Management client. + + + + + + + + + The object path of the client + + + + + Unregister the specified client from Session Management. + + + + + + + + + The application identifier + + + + + The toplevel X window identifier + + + + + The reason for the inhibit + + + + + Flags that specify what should be inhibited + + + + + The cookie + + + + + Proactively indicates that the calling application is performing an action that should not be interrupted and sets a reason to be displayed to the user when an interruption is about to take placea. + + + Applications should invoke this method when they begin an operation that + should not be interrupted, such as creating a CD or DVD. The types of actions + that may be blocked are specified by the flags parameter. When the application + completes the operation it should call Uninhibit() + or disconnect from the session bus. + + + Applications should not expect that they will always be able to block the + action. In most cases, users will be given the option to force the action + to take place. + + + Reasons should be short and to the point. + + + The flags parameter must include at least one of the following: + + + 1 + Inhibit logging out + + + 2 + Inhibit user switching + + + 4 + Inhibit suspending the session or computer + + + 8 + Inhibit the session being marked as idle + + + 16 + Inhibit auto-mounting removable media for the session + + + Values for flags may be bitwise or'ed together. + + + The returned cookie is used to uniquely identify this request. It should be used + as an argument to Uninhibit() in + order to remove the request. + + + + + + + + + + The cookie + + + + + Cancel a previous call to Inhibit() identified by the cookie. + + + + + + + + Flags that spefify what should be inhibited + + + + + Returns TRUE if any of the operations in the bitfield flags are inhibited + + + + + Determine if operation(s) specified by the flags + are currently inhibited. Flags are same as those accepted + by the + Inhibit() + method. + + + + + + + + an array of client IDs + + + + + This gets a list of all the Clients + that are currently known to the session manager. + Each Client ID is an D-Bus object path for the object that implements the + Client interface. + + org.gnome.SessionManager.Client + + + + + + + an array of inhibitor IDs + + + + + This gets a list of all the Inhibitors + that are currently known to the session manager. + Each Inhibitor ID is an D-Bus object path for the object that implements the + Inhibitor interface. + + org.gnome.SessionManager.Inhibitor + + + + + + + + The autostart condition string + + + + + True if condition is handled, false otherwise + + + + + Allows the caller to determine whether the session manager is + handling changes to the specified autostart condition. + + + + + + + + Request a shutdown dialog. + + + + + + + + Request a reboot dialog. + + + + + + + + True if shutdown is available to the user, false otherwise + + + + + Allows the caller to determine whether or not it's okay to show + a shutdown option in the UI + + + + + + + + The type of logout that is being requested + + + + + Request a logout dialog + + Allowed values for the mode parameter are: + + + 0 + Normal. + + + 1 + No confirmation inferface should be shown. + + + 2 + Forcefully logout. No confirmation will be shown and any inhibitors will be ignored. + + + Values for flags may be bitwise or'ed together. + + + + + + + + + True if the session has entered the Running phase, false otherwise + + + + + Allows the caller to determine whether the session manager + has entered the Running phase, in case the client missed the + SessionRunning signal. + + + + + + + + + + The object path for the added client + + + + + Emitted when a client has been added to the session manager. + + + + + + + + The object path for the removed client + + + + + Emitted when a client has been removed from the session manager. + + + + + + + + + The object path for the added inhibitor + + + + + Emitted when an inhibitor has been added to the session manager. + + + + + + + + The object path for the removed inhibitor + + + + + Emitted when an inhibitor has been removed from the session manager. + + + + + + + + + Indicates the session has entered the Running phase. + + + + + + + + Indicates the session is about to end. + + + + + + + + + + The name of the session that has been loaded. + + + + + + + + If true, the session is currently in the + foreground and available for user input. + + + + + + + + A bitmask of flags to indicate which actions + are inhibited. See the Inhibit() function's description + for a list of possible values. + + + + + + diff --git a/src/backend-dbus/session-dbus.xml b/src/backend-dbus/session-dbus.xml new file mode 100644 index 0000000..96e9837 --- /dev/null +++ b/src/backend-dbus/session-dbus.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/backend-dbus/upower.xml b/src/backend-dbus/upower.xml new file mode 100644 index 0000000..18d5fbd --- /dev/null +++ b/src/backend-dbus/upower.xml @@ -0,0 +1,309 @@ + + + + + + + + The DeviceKit-power service is available via the system message + bus. To access the service, use + the org.freedesktop.UPower interface on + the /org/freedesktop/UPower object on + the D-Bus system bus service with the well-known + name org.freedesktop.UPower. + + + + +$ dbus-send --print-reply \ + --system \ + --dest=org.freedesktop.UPower \ + /org/freedesktop/UPower \ + org.freedesktop.UPower.EnumerateDevices + +method return sender=:1.386 -> dest=:1.451 reply_serial=2 + array [ + object path "/org/freedesktop/UPower/devices/line_power_AC" + object path "/org/freedesktop/UPower/devices/battery_BAT0" + ] + + + + + + + + + + + + An array of object paths for devices. + + + + + + Enumerate all power objects on the system. + + + + + + + + + + Object path of device that was added. + + + + + + Emitted when a device is added. + + + + + + + + + + Object path of device that was removed. + + + + + + Emitted when a device is removed. + + + + + + + + + + Object path of device that was changed. + + + + + + Emitted when a device changed. + + + + + + + + + + + + Emitted when one or more properties on the object changes. + + + + + + + + + + + + This signal is sent when the session is about to be suspended or + hibernated. + Session and system programs have one second to do anything required + before the sleep action is taken (such as sending out Avahi or + Jabber messages). + + + + + + + + + + + + This signal is sent when the session has just returned from + Suspend() or Hibernate(). + Session and system programs can then do anything required (such as + sending out Avahi or Jabber messages). + + + + + + + + + + + + + This method tells UPower that the Suspend() or Hibernate() method + is about to be called. + This allows UPower to emit the Suspending signal whilst + session activities are happening that have to be done before the + suspend process is started. + + + This method would typically be called by the session power + management daemon, before it locks the screen and waits for the + screen to fade to black. + The session power management component would then call Suspend() or + Hibernate() when these syncronous tasks have completed. + + + If this method is not called than nothing bad will happen and + Suspend() or Hibernate() will block for the required second. + + + + + + + + + + + + + Suspends the computer into a low power state. + System state is not preserved if the power is lost. + + + If AboutToRequestSleep() has not been called then UPower will send + the Sleeping() signal and block for one second. + + + If AboutToRequestSleep() has been called less than one second + before this method is called then UPower will block for the + remaining time to complete one second of delay. + + + + + + + + + + + TRUE if allowed, otherwise FALSE + + + + + Check if the caller has (or can get) the PolicyKit privilege to call + Suspend. + + + + + + + + + + + + + Hibernates the computer into a low power state. + System state is preserved if the power is lost. + + + If AboutToRequestSleep() has not been called then UPower will send + the Sleeping() signal and block for one second. + + + If AboutToRequestSleep() has been called less than one second + before this method is called then UPower will block for the + remaining time to complete one second of delay. + + + + + + + + + + + TRUE if allowed, otherwise FALSE + + + + + Check if the caller has (or can get) the PolicyKit privilege to call + Hibernate. + + + + + + + + + + Version of the running daemon, e.g. 002. + + + + + + Whether the system is able to suspend. + + + + + + Whether the system is able to hibernate. + + + + + + Indicates whether the system is running on battery power. + This property is provided for convenience. + + + + + + Indicates whether the system is running on battery power and if the battery is critically low. + This property is provided for convenience. + + + + + + + + Indicates if the laptop lid is closed where the display cannot be seen. + + + + + + + + + + If the system has a lid device. + + + + + + + + diff --git a/src/backend-dbus/users.c b/src/backend-dbus/users.c new file mode 100644 index 0000000..4798d33 --- /dev/null +++ b/src/backend-dbus/users.c @@ -0,0 +1,810 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include "dbus-accounts.h" +#include "dbus-consolekit-seat.h" +#include "dbus-consolekit-session.h" +#include "dbus-consolekit-manager.h" +#include "dbus-user.h" + +#include "users.h" + +struct _IndicatorSessionUsersDbusPriv +{ + char * active_session_id; + + Accounts * accounts; + + DisplayManagerSeat * dm_seat; + + ConsoleKitSeat * seat_proxy; + + /* user's dbus object path -> AccountsUser* */ + GHashTable * path_to_user; + + /* uint32 user-id --> user's dbus object path */ + GHashTable * uid_to_user_path; + + /* uint32 user-id --> hashset of ssid strings */ + GHashTable * uid_to_sessions; + + /* ssid string --> uint32 user-id */ + GHashTable * session_to_uid; + + GCancellable * cancellable; +}; + +typedef IndicatorSessionUsersDbusPriv priv_t; + +G_DEFINE_TYPE (IndicatorSessionUsersDbus, + indicator_session_users_dbus, + INDICATOR_TYPE_SESSION_USERS) + +/*** +**** +***/ + +static void create_user_proxy_for_path (IndicatorSessionUsersDbus * self, + const char * path); + +static void create_session_proxy_for_ssid (IndicatorSessionUsersDbus * self, + const char * ssid); + +static void +emit_user_changed_for_path (IndicatorSessionUsersDbus * self, const char * path) +{ + AccountsUser * user = g_hash_table_lookup (self->priv->path_to_user, path); + + if (user && !accounts_user_get_system_account (user)) + indicator_session_users_changed (INDICATOR_SESSION_USERS(self), path); +} + +static void +emit_user_changed_for_uid (IndicatorSessionUsersDbus * self, guint uid) +{ + const char * path; + + if ((path = g_hash_table_lookup (self->priv->uid_to_user_path, GUINT_TO_POINTER(uid)))) + emit_user_changed_for_path (self, path); +} + +/*** +**** ACCOUNT MANAGER / USER TRACKING +***/ + +/* called when a user proxy gets the 'Changed' signal */ +static void +on_user_changed (AccountsUser * user, gpointer gself) +{ + /* Accounts.User doesn't update properties in the standard way, + * so create a new proxy to pull in the new properties. + * The older proxy is freed when it's removed from our path_to_user hash */ + const char * path = g_dbus_proxy_get_object_path (G_DBUS_PROXY(user)); + create_user_proxy_for_path (gself, path); +} + +static void +track_user (IndicatorSessionUsersDbus * self, + AccountsUser * user) +{ + priv_t * p; + const char * path; + gboolean already_had_user; + + p = self->priv; + + path = g_dbus_proxy_get_object_path (G_DBUS_PROXY(user)); + already_had_user = g_hash_table_contains (p->path_to_user, path); + + g_signal_connect (user, "changed", G_CALLBACK(on_user_changed), self); + g_hash_table_insert (p->path_to_user, g_strdup(path), user); + + if (already_had_user) + { + emit_user_changed_for_path (self, path); + } + else + { + const guint uid = (guint) accounts_user_get_uid (user); + + g_hash_table_insert (p->uid_to_user_path, + GUINT_TO_POINTER(uid), + g_strdup(path)); + + if (!accounts_user_get_system_account (user)) + indicator_session_users_added (INDICATOR_SESSION_USERS(self), path); + } +} + +static void +untrack_user (IndicatorSessionUsersDbus * self, + const gchar * path) +{ + g_hash_table_remove (self->priv->path_to_user, path); + + indicator_session_users_removed (INDICATOR_SESSION_USERS(self), path); +} + + +static void +on_user_proxy_ready (GObject * o G_GNUC_UNUSED, + GAsyncResult * res, + gpointer self) +{ + GError * err; + AccountsUser * user; + + err = NULL; + user = accounts_user_proxy_new_for_bus_finish (res, &err); + if (err != NULL) + { + g_warning ("%s: %s", G_STRFUNC, err->message); + g_error_free (err); + } + else + { + track_user (self, user); + } +} + +static void +create_user_proxy_for_path (IndicatorSessionUsersDbus * self, + const char * path) +{ + const char * name = "org.freedesktop.Accounts"; + const GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES; + + accounts_user_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + flags, name, path, + self->priv->cancellable, + on_user_proxy_ready, self); +} + +static void +on_user_list_ready (GObject * o, GAsyncResult * res, gpointer gself) +{ + GError * err; + gchar ** paths; + + err = NULL; + paths = NULL; + accounts_call_list_cached_users_finish (ACCOUNTS(o), &paths, res, &err); + if (err != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); + } + else + { + int i; + + for (i=0; paths && paths[i]; ++i) + create_user_proxy_for_path (gself, paths[i]); + + g_strfreev (paths); + } +} + +static void +set_account_manager (IndicatorSessionUsersDbus * self, Accounts * a) +{ + priv_t * p = self->priv; + + if (p->accounts != NULL) + { + g_signal_handlers_disconnect_by_data (p->accounts, self); + g_clear_object (&p->accounts); + } + + if (a != NULL) + { + p->accounts = g_object_ref (a); + + accounts_call_list_cached_users (a, + self->priv->cancellable, + on_user_list_ready, + self); + + g_signal_connect_swapped (a, "user-added", + G_CALLBACK(create_user_proxy_for_path), self); + + g_signal_connect_swapped (a, "user-deleted", + G_CALLBACK(untrack_user), self); + } +} + +#if 0 +static void +create_accounts_proxy (IndicatorSessionUsersDbus * self) +{ + const char * name = "org.freedesktop.Accounts"; + const char * path = "/org/freedesktop/Accounts"; + GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES; + + accounts_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + flags, name, path, + self->priv->cancellable, + on_accounts_proxy_ready, self); +} +#endif + +/** + * SEAT / SESSION TRACKING + * + * There are two simple goals here: + * + * 1. Keep track of how many GUI sessions each user has + * so that we can set the 'is_logged_in' flag correctly + * + * 2. Also track which is the current session, + * so that we can compare it to those GUI sessions to + * set the 'is_current_session' flag correctly. + * + * Now that you know the goals, these steps may make more sense: + * + * 1. create a ConsoleKitManager proxy + * 2. ask it for the current session + * 3. create a corresponding Session proxy + * 4. ask that Session proxy for its seat + * 5. create a corresponding Seat proxy + * 6. connect to that seat's session-added / session-removed signals + * 7. ask the seat for a list of its current sessions + * 8. create corresponding Session proxies + * 9. of them, look for the GUI sessions by checking their X11 properties + * 10. for each GUI session, get the corresponding uid + * 11. use the information to update our uid <--> GUI sessions tables + */ + +static void +track_session (IndicatorSessionUsersDbus * self, + const char * ssid, + guint uid) +{ + gpointer uid_key; + GHashTable * sessions; + + uid_key = GUINT_TO_POINTER (uid); + sessions = g_hash_table_lookup (self->priv->uid_to_sessions, uid_key); + if (sessions == NULL) + { + sessions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + g_hash_table_insert (self->priv->uid_to_sessions, uid_key, sessions); + } + + g_hash_table_add (sessions, g_strdup (ssid)); + g_hash_table_insert (self->priv->session_to_uid, g_strdup(ssid), uid_key); + + g_debug ("%s %s now tracking ssid:%s uid:%u. uid has %u tracked ssids.", + G_STRLOC, G_STRFUNC, ssid, uid, g_hash_table_size (sessions)); + + emit_user_changed_for_uid (self, uid); +} + +static void +untrack_session (IndicatorSessionUsersDbus * self, + const char * ssid) +{ + gpointer uidptr; + priv_t * p = self->priv; + + if (g_hash_table_lookup_extended (p->session_to_uid, ssid, NULL, &uidptr)) + { + const guint uid = GPOINTER_TO_UINT (uidptr); + GHashTable * sessions = g_hash_table_lookup (p->uid_to_sessions, uidptr); + + g_hash_table_remove (p->session_to_uid, ssid); + g_hash_table_remove (sessions, ssid); + g_debug ("%s %s not tracking ssid:%s uid:%u. uid has %u tracked ssids.", + G_STRLOC, G_STRFUNC, ssid, uid, + sessions ? g_hash_table_size (sessions) : 0); + + emit_user_changed_for_uid (self, uid); + } +} + +static void +on_session_proxy_uid_ready (GObject * o, + GAsyncResult * res, + gpointer gself) +{ + guint uid; + GError * err; + ConsoleKitSession * session = CONSOLE_KIT_SESSION (o); + + uid = 0; + err = NULL; + console_kit_session_call_get_unix_user_finish (session, &uid, res, &err); + if (err != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); + } + else if (uid) + { + const char * path = g_dbus_proxy_get_object_path (G_DBUS_PROXY(session)); + track_session (gself, path, uid); + } + + g_object_unref (o); +} + +static void +on_session_x11_display_ready (GObject * o, + GAsyncResult * res, + gpointer gself) +{ + priv_t * p; + GError * err; + gchar * gui; + ConsoleKitSession * session; + + p = INDICATOR_SESSION_USERS_DBUS(gself)->priv; + + err = NULL; + gui = NULL; + session = CONSOLE_KIT_SESSION (o); + console_kit_session_call_get_x11_display_finish (session, &gui, res, &err); + if (err != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); + } + else + { + gboolean is_gui_session; + + is_gui_session = gui && *gui; + + if (!is_gui_session) + g_clear_object (&session); + else + console_kit_session_call_get_unix_user (session, + p->cancellable, + on_session_proxy_uid_ready, + gself); + + g_free (gui); + } +} + +static void +on_session_proxy_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself) +{ + GError * err; + ConsoleKitSession * session; + + err = NULL; + session = console_kit_session_proxy_new_finish (res, &err); + if (err != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); + } + else if (session != NULL) + { + priv_t * p = INDICATOR_SESSION_USERS_DBUS(gself)->priv; + + console_kit_session_call_get_x11_display (session, + p->cancellable, + on_session_x11_display_ready, + gself); + } +} + +static void +create_session_proxy_for_ssid (IndicatorSessionUsersDbus * self, + const char * ssid) +{ + const char * name = "org.freedesktop.ConsoleKit"; + GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES; + + console_kit_session_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + flags, name, ssid, + self->priv->cancellable, + on_session_proxy_ready, self); +} + +static void +on_session_list_ready (GObject * o, GAsyncResult * res, gpointer gself) +{ + GError * err; + gchar ** sessions; + + err = NULL; + sessions = NULL; + console_kit_seat_call_get_sessions_finish (CONSOLE_KIT_SEAT(o), + &sessions, res, &err); + if (err != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); + } + else + { + int i; + + for (i=0; sessions && sessions[i]; i++) + create_session_proxy_for_ssid (gself, sessions[i]); + + g_strfreev (sessions); + } +} + +static inline guint +get_uid_for_session (IndicatorSessionUsersDbus * self, const char * ssid) +{ + guint uid = 0; + gpointer value; + + if (ssid != NULL) + if ((value = g_hash_table_lookup (self->priv->session_to_uid, ssid))) + uid = GPOINTER_TO_UINT (value); + + return uid; +} + +/* it's a live session if username is 'ubuntu' and uid is 999 */ +static gboolean +is_live_ssid (IndicatorSessionUsersDbus * self, const char * ssid) +{ + priv_t * p; + guint uid; + + p = INDICATOR_SESSION_USERS_DBUS (self)->priv; + uid = get_uid_for_session (self, ssid); + + if (uid == 999) + { + const char * path; + AccountsUser * user = NULL; + + if ((path = g_hash_table_lookup (p->uid_to_user_path, GUINT_TO_POINTER (uid)))) + user = g_hash_table_lookup (p->path_to_user, path); + + return (user != NULL) && !g_strcmp0 (accounts_user_get_user_name(user), "ubuntu"); + } + + return FALSE; +} + + +static void +set_active_session (IndicatorSessionUsersDbus * self, const char * ssid) +{ + priv_t * p = self->priv; + const guint old_uid = get_uid_for_session (self, p->active_session_id); + const guint new_uid = get_uid_for_session (self, ssid); + const gboolean old_live = is_live_ssid (self, p->active_session_id); + const gboolean new_live = is_live_ssid (self, ssid); + + g_debug ("%s %s changing active_session_id from '%s' to '%s'", + G_STRLOC, G_STRFUNC, p->active_session_id, ssid); + g_free (p->active_session_id); + p->active_session_id = g_strdup (ssid); + + if (old_uid != new_uid) + { + emit_user_changed_for_uid (self, old_uid); + emit_user_changed_for_uid (self, new_uid); + } + + if (old_live != new_live) + { + indicator_session_users_notify_is_live_session (INDICATOR_SESSION_USERS(self)); + } +} + +static void +on_seat_active_session_ready (GObject * o, GAsyncResult * res, gpointer gself) +{ + GError * err; + gchar * ssid; + ConsoleKitSeat * seat; + + err = NULL; + ssid = NULL; + seat = CONSOLE_KIT_SEAT (o); + console_kit_seat_call_get_active_session_finish (seat, &ssid, res, &err); + if (err != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, err->message); + g_error_free (err); + } + else if (ssid != NULL) + { + set_active_session (INDICATOR_SESSION_USERS_DBUS(gself), ssid); + g_free (ssid); + } +} + +static void +set_seat (IndicatorSessionUsersDbus * self, ConsoleKitSeat * seat) +{ + priv_t * p = self->priv; + + if (p->seat_proxy != NULL) + { + g_signal_handlers_disconnect_by_data (p->seat_proxy, self); + g_clear_object (&p->seat_proxy); + } + + if (seat != NULL) + { + p->seat_proxy = g_object_ref (seat); + + /* ask the seat for a list of all the sessions */ + console_kit_seat_call_get_sessions (seat, + p->cancellable, + on_session_list_ready, + self); + + /* ask the seat for the name of the active session */ + console_kit_seat_call_get_active_session (p->seat_proxy, + p->cancellable, + on_seat_active_session_ready, + self); + + /* listen for session changes in this seat */ + g_signal_connect_swapped (seat, "session-added", + G_CALLBACK(create_session_proxy_for_ssid),self); + g_signal_connect_swapped (seat, "session-removed", + G_CALLBACK(untrack_session), self); + g_signal_connect_swapped (seat, "active-session-changed", + G_CALLBACK(set_active_session), self); + } +} + +/*** +**** +***/ + +static void +set_dm_seat (IndicatorSessionUsersDbus * self, DisplayManagerSeat * dm_seat) +{ + priv_t * p = self->priv; + + g_clear_object (&p->dm_seat); + + if (dm_seat != NULL) + p->dm_seat = g_object_ref (dm_seat); +} + +static void +activate_username (IndicatorSessionUsersDbus * self, const char * username) +{ + priv_t * p = self->priv; + const char * session = ""; + + g_return_if_fail (p->dm_seat != NULL); + + display_manager_seat_call_switch_to_user (p->dm_seat, username, session, + p->cancellable, NULL, NULL); +} + +/*** +**** +***/ + +static void +my_dispose (GObject * o) +{ + IndicatorSessionUsersDbus * self = INDICATOR_SESSION_USERS_DBUS (o); + priv_t * p = self->priv; + + if (p->cancellable) + { + g_cancellable_cancel (p->cancellable); + g_clear_object (&p->cancellable); + } + + set_seat (self, NULL); + set_dm_seat (self, NULL); + set_account_manager (self, NULL); + + g_clear_pointer (&p->path_to_user, g_hash_table_destroy); + g_clear_pointer (&p->session_to_uid, g_hash_table_destroy); + g_clear_pointer (&p->uid_to_sessions, g_hash_table_destroy); + g_clear_pointer (&p->uid_to_user_path, g_hash_table_destroy); + + G_OBJECT_CLASS (indicator_session_users_dbus_parent_class)->dispose (o); +} + +static void +my_finalize (GObject * o) +{ + IndicatorSessionUsersDbus * u = INDICATOR_SESSION_USERS_DBUS (o); + + g_free (u->priv->active_session_id); + + G_OBJECT_CLASS (indicator_session_users_dbus_parent_class)->finalize (o); +} + +static void +my_activate_user (IndicatorSessionUsers * users, const char * key) +{ + priv_t * p; + const char * username = 0; + + p = INDICATOR_SESSION_USERS_DBUS (users)->priv; + if (p != 0) + { + AccountsUser * au = g_hash_table_lookup (p->path_to_user, key); + + if (au != NULL) + username = accounts_user_get_user_name (au); + } + + if (username != 0) + activate_username (INDICATOR_SESSION_USERS_DBUS(users), username); + else + g_warning ("%s %s can't find user for '%s'", G_STRLOC, G_STRFUNC, key); +} + +static gboolean +my_is_live_session (IndicatorSessionUsers * users) +{ + IndicatorSessionUsersDbus * self = INDICATOR_SESSION_USERS_DBUS(users); + + return is_live_ssid (self, self->priv->active_session_id); +} + +static GStrv +my_get_keys (IndicatorSessionUsers * users) +{ + int i; + priv_t * p; + gchar ** keys; + GHashTableIter iter; + gpointer path; + gpointer user; + + g_return_val_if_fail (INDICATOR_IS_SESSION_USERS_DBUS(users), NULL); + p = INDICATOR_SESSION_USERS_DBUS (users)->priv; + + i = 0; + keys = g_new (gchar*, g_hash_table_size(p->path_to_user)+1); + g_hash_table_iter_init (&iter, p->path_to_user); + while (g_hash_table_iter_next (&iter, &path, &user)) + if (!accounts_user_get_system_account (user)) + keys[i++] = g_strdup (path); + keys[i] = NULL; + + return keys; +} + +static IndicatorSessionUser * +my_get_user (IndicatorSessionUsers * users, const gchar * key) +{ + priv_t * p; + AccountsUser * au; + IndicatorSessionUser * ret = NULL; + + p = INDICATOR_SESSION_USERS_DBUS (users)->priv; + + au = g_hash_table_lookup (p->path_to_user, key); + if (au && !accounts_user_get_system_account(au)) + { + const guint uid = (guint) accounts_user_get_uid (au); + GHashTable * s; + + ret = g_new0 (IndicatorSessionUser, 1); + + s = g_hash_table_lookup (p->uid_to_sessions, GUINT_TO_POINTER(uid)); + if (s == NULL) + { + ret->is_logged_in = FALSE; + ret->is_current_user = FALSE; + } + else + { + ret->is_logged_in = g_hash_table_size (s) > 0; + ret->is_current_user = g_hash_table_contains (s, p->active_session_id); + } + + ret->uid = uid; + ret->user_name = g_strdup (accounts_user_get_user_name (au)); + ret->real_name = g_strdup (accounts_user_get_real_name (au)); + ret->icon_file = g_strdup (accounts_user_get_icon_file (au)); + ret->login_frequency = accounts_user_get_login_frequency (au); + } + + return ret; +} + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_users_dbus_class_init (IndicatorSessionUsersDbusClass * klass) +{ + GObjectClass * object_class; + IndicatorSessionUsersClass * users_class; + + object_class = G_OBJECT_CLASS (klass); + object_class->dispose = my_dispose; + object_class->finalize = my_finalize; + + users_class = INDICATOR_SESSION_USERS_CLASS (klass); + users_class->is_live_session = my_is_live_session; + users_class->get_keys = my_get_keys; + users_class->get_user = my_get_user; + users_class->activate_user = my_activate_user; + + g_type_class_add_private (klass, sizeof (IndicatorSessionUsersDbusPriv)); +} + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_users_dbus_init (IndicatorSessionUsersDbus * self) +{ + priv_t * p; + + p = G_TYPE_INSTANCE_GET_PRIVATE (self, + INDICATOR_TYPE_SESSION_USERS_DBUS, + IndicatorSessionUsersDbusPriv); + self->priv = p; + p->cancellable = g_cancellable_new (); + + p->path_to_user = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_object_unref); + + p->uid_to_user_path = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, g_free); + + p->session_to_uid = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, NULL); + + p->uid_to_sessions = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, + (GDestroyNotify)g_hash_table_destroy); + +#if 0 + console_kit_manager_proxy_new_for_bus ( + G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, + "org.freedesktop.ConsoleKit", + "/org/freedesktop/ConsoleKit/Manager", + p->cancellable, + on_console_kit_manager_proxy_ready, + self); +#endif +} + +/*** +**** Public +***/ + +IndicatorSessionUsers * +indicator_session_users_dbus_new (void) +{ + gpointer o = g_object_new (INDICATOR_TYPE_SESSION_USERS_DBUS, NULL); + + return INDICATOR_SESSION_USERS (o); +} + +void +indicator_session_users_dbus_set_proxies (IndicatorSessionUsersDbus * self, + Accounts * accounts, + DisplayManagerSeat * dm_seat, + ConsoleKitSeat * seat) +{ + g_return_if_fail (INDICATOR_IS_SESSION_USERS_DBUS (self)); + + set_account_manager (self, accounts); + set_seat (self, seat); + set_dm_seat (self, dm_seat); +} diff --git a/src/backend-dbus/users.h b/src/backend-dbus/users.h new file mode 100644 index 0000000..ff1e0ad --- /dev/null +++ b/src/backend-dbus/users.h @@ -0,0 +1,71 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#ifndef __USERS_DBUS_H__ +#define __USERS_DBUS_H__ + +#include +#include + +#include "../users.h" /* parent class */ +#include "dbus-accounts.h" +#include "dbus-consolekit-seat.h" +#include "dbus-display-manager.h" + +G_BEGIN_DECLS + +#define INDICATOR_TYPE_SESSION_USERS_DBUS (indicator_session_users_dbus_get_type()) +#define INDICATOR_SESSION_USERS_DBUS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_SESSION_USERS_DBUS, IndicatorSessionUsersDbus)) +#define INDICATOR_SESSION_USERS_DBUS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_SESSION_USERS_DBUS, IndicatorSessionUsersDbusClass)) +#define INDICATOR_IS_SESSION_USERS_DBUS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_SESSION_USERS_DBUS)) + +typedef struct _IndicatorSessionUsersDbus IndicatorSessionUsersDbus; +typedef struct _IndicatorSessionUsersDbusPriv IndicatorSessionUsersDbusPriv; +typedef struct _IndicatorSessionUsersDbusClass IndicatorSessionUsersDbusClass; + +/** + * An implementation of IndicatorSessionUsers that gets its user information + * from org.freedesktop.ConsoleKit and org.freedesktop.Accounts over DBus. + */ +struct _IndicatorSessionUsersDbus +{ + /*< private >*/ + IndicatorSessionUsers parent; + IndicatorSessionUsersDbusPriv * priv; +}; + +struct _IndicatorSessionUsersDbusClass +{ + IndicatorSessionUsersClass parent_class; +}; + +GType indicator_session_users_dbus_get_type (void); + +IndicatorSessionUsers * indicator_session_users_dbus_new (void); + +void indicator_session_users_dbus_set_proxies (IndicatorSessionUsersDbus *, + Accounts *, + DisplayManagerSeat *, + ConsoleKitSeat *); + + + +G_END_DECLS + +#endif diff --git a/src/backend-dbus/utils.c b/src/backend-dbus/utils.c new file mode 100644 index 0000000..86a5e5a --- /dev/null +++ b/src/backend-dbus/utils.c @@ -0,0 +1,399 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include "utils.h" + +/*** +**** indicator_session_util_get_session_proxies() +***/ + +struct session_proxy_data +{ + ConsoleKitManager * ck_manager; + Accounts * account_manager; + DisplayManagerSeat * dm_seat; + + ConsoleKitSeat * current_seat; + ConsoleKitSession * current_session; + AccountsUser * active_user; + + GCancellable * cancellable; + GError * error; + int pending; + + indicator_session_util_session_proxies_func callback; + gpointer user_data; +}; + +static void +session_proxy_data_free (struct session_proxy_data * data) +{ + g_clear_object (&data->ck_manager); + g_clear_object (&data->account_manager); + g_clear_object (&data->dm_seat); + + g_clear_object (&data->current_seat); + g_clear_object (&data->current_session); + g_clear_object (&data->active_user); + + g_clear_object (&data->cancellable); + g_clear_error (&data->error); + + g_free (data); +} + +static void +finish_callback (struct session_proxy_data * data) +{ + g_assert (data != NULL); + g_debug ("%s %s: pending is %d", G_STRLOC, G_STRFUNC, (data->pending-1)); + + if (!--data->pending) + { + data->callback (data->ck_manager, + data->account_manager, + data->dm_seat, + data->current_seat, + data->current_session, + data->active_user, + data->error, + data->user_data); + + session_proxy_data_free (data); + } +} + +static void +on_user_proxy_ready (GObject * o G_GNUC_UNUSED, + GAsyncResult * res, + gpointer gdata) +{ + struct session_proxy_data * data = gdata; + g_debug ("%s %s", G_STRLOC, G_STRFUNC); + + data->active_user = accounts_user_proxy_new_for_bus_finish (res, &data->error); + + if (data->error != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, data->error->message); + } + else + { + g_debug ("%s %s user proxy is %p", G_STRLOC, G_STRFUNC, (void*)data->active_user); + } + + finish_callback (data); +} + +static void +on_user_path_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gdata) +{ + char * path = NULL; + struct session_proxy_data * data = gdata; + g_debug ("%s %s", G_STRLOC, G_STRFUNC); + + accounts_call_find_user_by_id_finish (data->account_manager, &path, res, &data->error); + + if (data->error != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, data->error->message); + } + else if (path != NULL) + { + g_debug ("%s %s user path is %s", G_STRLOC, G_STRFUNC, path); + ++data->pending; + accounts_user_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, + "org.freedesktop.Accounts", + path, + data->cancellable, + on_user_proxy_ready, + data); + } + + finish_callback (data); + g_free (path); +} + +static void +on_uid_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gdata) +{ + guint uid = 0; + struct session_proxy_data * data = gdata; + g_debug ("%s %s", G_STRLOC, G_STRFUNC); + + console_kit_session_call_get_unix_user_finish (data->current_session, &uid, res, &data->error); + if (data->error != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, data->error->message); + } + else if (uid) + { + g_debug ("%s %s uid is %u", G_STRLOC, G_STRFUNC, uid); + ++data->pending; + accounts_call_find_user_by_id (data->account_manager, + uid, + data->cancellable, + on_user_path_ready, + data); + } + + finish_callback (data); +} + +static void +on_seat_proxy_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gdata) +{ + struct session_proxy_data * data = gdata; + g_debug ("%s %s", G_STRLOC, G_STRFUNC); + + data->current_seat = console_kit_seat_proxy_new_for_bus_finish (res, &data->error); + + if (data->error != NULL) + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, data->error->message); + + finish_callback (data); +} + +static void +on_sid_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gdata) +{ + char * sid = NULL; + struct session_proxy_data * data = gdata; + g_debug ("%s %s", G_STRLOC, G_STRFUNC); + + console_kit_session_call_get_seat_id_finish (data->current_session, &sid, res, &data->error); + + if (data->error != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, data->error->message); + } + else if (sid != NULL) + { + g_debug ("%s %s sid is %s", G_STRLOC, G_STRFUNC, sid); + ++data->pending; + console_kit_seat_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, + "org.freedesktop.ConsoleKit", + sid, + data->cancellable, + on_seat_proxy_ready, + data); + } + + finish_callback (data); + g_free (sid); +} + +static void +on_session_proxy_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gdata) +{ + struct session_proxy_data * data = gdata; + g_debug ("%s %s", G_STRLOC, G_STRFUNC); + + data->current_session = console_kit_session_proxy_new_finish (res, &data->error); + if (data->error != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, data->error->message); + } + else + { + ++data->pending; + console_kit_session_call_get_seat_id (data->current_session, + data->cancellable, + on_sid_ready, + data); + + ++data->pending; + console_kit_session_call_get_unix_user (data->current_session, + data->cancellable, + on_uid_ready, + data); + } + + finish_callback (data); +} + +static void +on_current_session_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gdata) +{ + char * ssid = NULL; + struct session_proxy_data * data = gdata; + g_debug ("%s %s", G_STRLOC, G_STRFUNC); + + ssid = NULL; + console_kit_manager_call_get_current_session_finish (data->ck_manager, + &ssid, res, + &data->error); + if (data->error != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, data->error->message); + } + else if (ssid) + { + g_debug ("%s %s ssid is %s", G_STRLOC, G_STRFUNC, ssid); + data->pending++; + console_kit_session_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, + "org.freedesktop.ConsoleKit", + ssid, + data->cancellable, + on_session_proxy_ready, + data); + + } + + finish_callback (data); + g_free (ssid); +} + +static void +on_display_manager_seat_proxy_ready (GObject * o G_GNUC_UNUSED, + GAsyncResult * res, + gpointer gdata) +{ + DisplayManagerSeat * seat; + struct session_proxy_data * data = gdata; + + seat = display_manager_seat_proxy_new_for_bus_finish (res, &data->error); + + if (data->error != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, data->error->message); + } + else if (seat != NULL) + { + data->dm_seat = g_object_ref (seat); + } + + finish_callback (data); + g_clear_object (&seat); +} + +static void +on_console_kit_manager_proxy_ready (GObject * o G_GNUC_UNUSED, + GAsyncResult * res, + gpointer gdata) +{ + ConsoleKitManager * mgr; + struct session_proxy_data * data = gdata; + g_debug ("%s %s", G_STRLOC, G_STRFUNC); + + if (data->error == NULL) + { + mgr = console_kit_manager_proxy_new_for_bus_finish (res, &data->error); + g_debug ("%s %s mgr is %p, err is %p", G_STRLOC, G_STRFUNC, (void*)mgr, (void*)data->error); + + if (data->error != NULL) + { + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, data->error->message); + } + else + { + data->ck_manager = mgr; + + data->pending++; + console_kit_manager_call_get_current_session (mgr, + data->cancellable, + on_current_session_ready, + data); + + } + } + + finish_callback (data); +} + +static void +on_accounts_proxy_ready (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gdata) +{ + struct session_proxy_data * data = gdata; + g_debug ("%s %s", G_STRLOC, G_STRFUNC); + + if (data->error == NULL) + { + data->account_manager = accounts_proxy_new_for_bus_finish (res, &data->error); + + if (data->error != NULL) + g_warning ("%s %s: %s", G_STRLOC, G_STRFUNC, data->error->message); + } + + finish_callback (data); +} + +/** + * Getting all the proxies we want is kind of a pain -- + * especially without blocking (ie, using _sync() funcs) -- + * so it's farmed out to this wrapper utility. + * + * 1. in this func, start getting the ConsoleKit and Accounts proxies + * 2. when the accounts proxy is ready, stash it in data.account_manager + * 3. when the ck manager proxy is ready, stash it in data.ck_manager and + * ask it for the current session's ssid + * 4. when the ssid is ready, start getting a proxy for it + * 5. when the session's proxy is ready, stash it in data.current_session + * and ask it for both the current seat's sid and the active user's uid + * 6. When the current seat's sid is ready, start getting a proxy for it + * 7. When the current seat's proxy is ready, stash it in data.current_seat + * 8. when the active user's uid is ready, ask data.account_manager for the path + * 9. when the user path is ready, start getting an Accounts.User proxy for it + * 10. when the Accounts.User proxy is read, stash it in data.active_user + * + * When everything is done, or if there's an error, invoke the data.callback + */ +void +indicator_session_util_get_session_proxies ( + indicator_session_util_session_proxies_func func, + GCancellable * cancellable, + gpointer user_data) +{ + struct session_proxy_data * data; + + data = g_new0 (struct session_proxy_data, 1); + data->callback = func; + data->user_data = user_data; + data->cancellable = g_object_ref (cancellable); + + data->pending++; + accounts_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, + "org.freedesktop.Accounts", + "/org/freedesktop/Accounts", + data->cancellable, + on_accounts_proxy_ready, data); + + data->pending++; + console_kit_manager_proxy_new_for_bus ( + G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, + "org.freedesktop.ConsoleKit", + "/org/freedesktop/ConsoleKit/Manager", + data->cancellable, + on_console_kit_manager_proxy_ready, data); + + data->pending++; + display_manager_seat_proxy_new_for_bus ( + G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, + "org.freedesktop.DisplayManager", + g_getenv ("XDG_SEAT_PATH"), + data->cancellable, + on_display_manager_seat_proxy_ready, data); + +} diff --git a/src/backend-dbus/utils.h b/src/backend-dbus/utils.h new file mode 100644 index 0000000..b4f26c3 --- /dev/null +++ b/src/backend-dbus/utils.h @@ -0,0 +1,53 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#ifndef __DBUS_UTILS_H__ +#define __DBUS_UTILS_H__ + +#include +#include + +#include "dbus-accounts.h" +#include "dbus-display-manager.h" +#include "dbus-user.h" +#include "dbus-consolekit-seat.h" +#include "dbus-consolekit-session.h" +#include "dbus-consolekit-manager.h" + +typedef void (*indicator_session_util_session_proxies_func)( + ConsoleKitManager * ck_manager, + Accounts * account_manager, + DisplayManagerSeat * dm_seat, + ConsoleKitSeat * current_ck_seat, + ConsoleKitSession * current_ck_session, + AccountsUser * active_user, + const GError * error, + gpointer user_data); + +/** + * Both users-dbus and guest-dbus need some of these proxies. + * Getting them all involves a lot of steps, so instead of repeating + * ourselves, the common dbus steps are extracted to this func. + */ +void indicator_session_util_get_session_proxies ( + indicator_session_util_session_proxies_func func, + GCancellable * cancellable, + gpointer user_data); + +#endif diff --git a/src/backend.h b/src/backend.h new file mode 100644 index 0000000..2df215d --- /dev/null +++ b/src/backend.h @@ -0,0 +1,47 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#ifndef __INDICATOR_SESSION_BACKEND_H__ +#define __INDICATOR_SESSION_BACKEND_H__ + +#include /* GCancellable */ + +#include "actions.h" +#include "guest.h" +#include "users.h" + +G_BEGIN_DECLS + +/** + * Gets instances of the backend abstract base classes. + * These are how IndicatorSystemService knows what's happening on the system. + * + * This function isn't defined in libindicatorsessionservice. + * Instead, one of two implementations is statically linked at build time: + * one for production in libbackenddbus (in src/backend-dbus/) or + * one for testing in libbackendmock (in tests/). + */ +void backend_get (GCancellable * cancellable, + IndicatorSessionActions ** setme_actions, + IndicatorSessionUsers ** setme_users, + IndicatorSessionGuest ** setme_guest); + +G_END_DECLS + +#endif diff --git a/src/dialog.c b/src/dialog.c deleted file mode 100644 index eb91f57..0000000 --- a/src/dialog.c +++ /dev/null @@ -1,248 +0,0 @@ -/* -A dialog to ask the user about the various logout options that -are available. - -Copyright 2010 Canonical Ltd. - -Authors: - Ted Gould - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include "dbus-consolekit-manager.h" -#include "dialog.h" - -/* Strings */ - -static const gchar * title_strings[LOGOUT_DIALOG_TYPE_CNT] = { - /* LOGOUT_DIALOG_LOGOUT, */ NC_("title", "Log Out"), - /* LOGOUT_DIALOG_RESTART, */ NC_("title", "Restart"), - /* LOGOUT_DIALOG_SHUTDOWN, */ NC_("title", "Shut Down") -}; - -static const gchar * body_strings[LOGOUT_DIALOG_TYPE_CNT] = { - /* LOGOUT_DIALOG_LOGOUT, */ N_("Are you sure you want to close all programs and log out of the computer?"), - /* LOGOUT_DIALOG_RESTART, */ N_("Are you sure you want to close all programs and restart the computer?"), - /* LOGOUT_DIALOG_SHUTDOWN, */ N_("Are you sure you want to close all programs and shut down the computer?") -}; - -static const gchar * button_strings[LOGOUT_DIALOG_TYPE_CNT] = { - /* LOGOUT_DIALOG_LOGOUT, */ NC_("button", "Log Out"), - /* LOGOUT_DIALOG_RESTART, */ NC_("button", "Restart"), - /* LOGOUT_DIALOG_SHUTDOWN, */ NC_("button", "Shut Down") -}; - -/* TRANSLATORS: These strings have an ellipsis so that the user knows - they are also going to get a password dialog to do the action. */ -static const gchar * button_auth_strings[LOGOUT_DIALOG_TYPE_CNT] = { - /* LOGOUT_DIALOG_LOGOUT, */ NC_("button auth", "Log Out"), - /* LOGOUT_DIALOG_RESTART, */ NC_("button auth", "Restart…"), - /* LOGOUT_DIALOG_SHUTDOWN, */ NC_("button auth", "Shut Down…") -}; - -/* TRANSLATORS: This button appears on the logout dialog when - there are updates that require restart. It will do a restart - in place of a log out. */ -static const gchar * restart_updates = N_("Restart Instead"); -static const gchar * restart_auth = N_("Restart Instead…"); -static const gchar * body_logout_update = N_("Some software updates won’t apply until the computer next restarts."); - -static const gchar * icon_strings[LOGOUT_DIALOG_TYPE_CNT] = { - /* LOGOUT_DIALOG_LOGOUT, */ "system-log-out", - /* LOGOUT_DIALOG_RESTART, */ "system-restart", - /* LOGOUT_DIALOG_SHUTDOWN, */ "system-shutdown" -}; - - - -typedef struct _LogoutDialogPrivate LogoutDialogPrivate; -struct _LogoutDialogPrivate { - guint type; -}; - -#define LOGOUT_DIALOG_GET_PRIVATE(o) \ -(G_TYPE_INSTANCE_GET_PRIVATE ((o), LOGOUT_DIALOG_TYPE, LogoutDialogPrivate)) - -static void logout_dialog_class_init (LogoutDialogClass *klass); -static void logout_dialog_init (LogoutDialog *self); -static void logout_dialog_dispose (GObject *object); -static void logout_dialog_finalize (GObject *object); - -G_DEFINE_TYPE (LogoutDialog, logout_dialog, GTK_TYPE_MESSAGE_DIALOG); - -static void -logout_dialog_class_init (LogoutDialogClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (LogoutDialogPrivate)); - - object_class->dispose = logout_dialog_dispose; - object_class->finalize = logout_dialog_finalize; - - return; -} - -static void -logout_dialog_init (LogoutDialog *self) -{ - - return; -} - -static void -logout_dialog_dispose (GObject *object) -{ - - - G_OBJECT_CLASS (logout_dialog_parent_class)->dispose (object); - return; -} - -static void -logout_dialog_finalize (GObject *object) -{ - - - G_OBJECT_CLASS (logout_dialog_parent_class)->finalize (object); - return; -} - -/* Checks for updates that would signal that a restart is - required for them to apply */ -static gboolean -check_restart_required (void) -{ - return g_file_test("/var/run/reboot-required", G_FILE_TEST_EXISTS); -} - -/* Checks with console kit to see if we can do what we want */ -static gboolean -ck_check_allowed (LogoutDialogType type) -{ - gboolean allowed = TRUE; - - ConsoleKitManager * ck_proxy = console_kit_manager_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - "org.freedesktop.ConsoleKit", - "/org/freedesktop/ConsoleKit/Manager", - NULL, - NULL); - if (ck_proxy != NULL) - { - switch (type) { - case LOGOUT_DIALOG_TYPE_RESTART: - console_kit_manager_call_can_restart_sync (ck_proxy, &allowed, NULL, NULL); - break; - case LOGOUT_DIALOG_TYPE_SHUTDOWN: - console_kit_manager_call_can_stop_sync (ck_proxy, &allowed, NULL, NULL); - break; - default: - break; - } - - g_object_unref(ck_proxy); - } - - return allowed; -} - -LogoutDialog * -logout_dialog_new (LogoutDialogType type) -{ - GtkWidget * image = gtk_image_new_from_icon_name(icon_strings[type], GTK_ICON_SIZE_DIALOG); - gtk_widget_show(image); - - LogoutDialog * dialog = LOGOUT_DIALOG(g_object_new(LOGOUT_DIALOG_TYPE, - /* Window */ - "icon-name", icon_strings[type], - "modal", TRUE, - "resizable", FALSE, - "title", g_dpgettext2 (NULL, "title", title_strings[type]), - "window-position", GTK_WIN_POS_CENTER_ALWAYS, - /* Message Dialog */ - "buttons", GTK_BUTTONS_NONE, - "image", image, - "message-type", GTK_MESSAGE_OTHER, - "text", _(body_strings[type]), - NULL)); - - gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE); - - gboolean allowed = FALSE; - if (type == LOGOUT_DIALOG_TYPE_LOG_OUT) { - allowed = ck_check_allowed(LOGOUT_DIALOG_TYPE_RESTART); - } else { - allowed = ck_check_allowed(type); - } - - gboolean restart_required = FALSE; - if (type == LOGOUT_DIALOG_TYPE_LOG_OUT) { - restart_required = check_restart_required(); - } - - const gchar * button_text; - if (allowed) { - button_text = g_dpgettext2 (NULL, "button", button_strings[type]); - } else { - button_text = g_dpgettext2 (NULL, "button auth", button_auth_strings[type]); - } - - if (restart_required) { - const gchar * restart_req; - if (allowed) { - restart_req = restart_updates; - } else { - restart_req = restart_auth; - } - - g_object_set(dialog, "secondary-text", _(body_logout_update), NULL); - - gtk_dialog_add_buttons(GTK_DIALOG(dialog), - _(restart_req), GTK_RESPONSE_HELP, - _("Cancel"), GTK_RESPONSE_CANCEL, - button_text, GTK_RESPONSE_OK, - NULL); - } else { - gtk_dialog_add_buttons(GTK_DIALOG(dialog), - _("Cancel"), GTK_RESPONSE_CANCEL, - button_text, GTK_RESPONSE_OK, - NULL); - } - - gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK); - - /* The following is a workaround to fix an issue in GtkMessageDialog - in which the user can tab through the text in addition to - the buttons. */ - GtkWidget *message_area = gtk_message_dialog_get_message_area(GTK_MESSAGE_DIALOG(dialog)); - GList *children = gtk_container_get_children(GTK_CONTAINER(message_area)); - GList *l; - - for (l = children; l != NULL; l = g_list_next (l)) - { - GtkWidget *child = l->data; - gtk_widget_set_can_focus(child, FALSE); - } - - g_list_free (children); - - return dialog; -} diff --git a/src/dialog.h b/src/dialog.h deleted file mode 100644 index 18a55a7..0000000 --- a/src/dialog.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -A dialog to ask the user about the various logout options that -are available. - -Copyright 2010 Canonical Ltd. - -Authors: - Ted Gould - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . -*/ - -#ifndef __LOGOUT_DIALOG_H__ -#define __LOGOUT_DIALOG_H__ - -#include -#include - -#include - -G_BEGIN_DECLS - -#define LOGOUT_DIALOG_TYPE (logout_dialog_get_type ()) -#define LOGOUT_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LOGOUT_DIALOG_TYPE, LogoutDialog)) -#define LOGOUT_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), LOGOUT_DIALOG_TYPE, LogoutDialogClass)) -#define IS_LOGOUT_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LOGOUT_DIALOG_TYPE)) -#define IS_LOGOUT_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), LOGOUT_DIALOG_TYPE)) -#define LOGOUT_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), LOGOUT_DIALOG_TYPE, LogoutDialogClass)) - -typedef enum _LogoutDialogType LogoutDialogType; -enum _LogoutDialogType { - LOGOUT_DIALOG_TYPE_LOG_OUT, - LOGOUT_DIALOG_TYPE_RESTART, - LOGOUT_DIALOG_TYPE_SHUTDOWN, - LOGOUT_DIALOG_TYPE_CNT -}; - -typedef struct _LogoutDialog LogoutDialog; -typedef struct _LogoutDialogClass LogoutDialogClass; - -struct _LogoutDialogClass { - GtkMessageDialogClass parent_class; -}; - -struct _LogoutDialog { - GtkMessageDialog parent; -}; - -GType logout_dialog_get_type (void); -LogoutDialog * logout_dialog_new (LogoutDialogType type); - -G_END_DECLS - -#endif diff --git a/src/display-manager.xml b/src/display-manager.xml deleted file mode 100644 index 07b5f29..0000000 --- a/src/display-manager.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/gtk-logout-helper.c b/src/gtk-logout-helper.c deleted file mode 100644 index 55db630..0000000 --- a/src/gtk-logout-helper.c +++ /dev/null @@ -1,266 +0,0 @@ -/* -A small wrapper utility to load indicators and put them as menu items -into the gnome-panel using it's applet interface. - -Copyright 2009 Canonical Ltd. - -Authors: - Ted Gould - Christoph Korn - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . -*/ - -#include "config.h" - -#include -#include -#include /* textdomain(), bindtextdomain() */ -#include -#include "dialog.h" -#include "shared-names.h" - -static GVariant * -call_console_kit (const gchar *method, GVariant *parameters, GError **error) -{ - GDBusConnection * bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, error); - if (!bus) - { - g_variant_unref (parameters); - return NULL; - } - - GVariant *result = g_dbus_connection_call_sync(bus, - "org.freedesktop.ConsoleKit", - "/org/freedesktop/ConsoleKit/Manager", - "org.freedesktop.ConsoleKit.Manager", - method, - parameters, - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - error); - g_object_unref (bus); - - return result; -} - -static void -consolekit_fallback (LogoutDialogType action) -{ - GError * error = NULL; - GVariant *result = NULL; - - g_debug("Falling back to using ConsoleKit for action"); - - switch (action) { - case LOGOUT_DIALOG_TYPE_LOG_OUT: - g_warning("Unable to fallback to ConsoleKit for logout as it's a session issue. We need some sort of session handler."); - break; - case LOGOUT_DIALOG_TYPE_SHUTDOWN: - g_debug("Telling ConsoleKit to 'Stop'"); - result = call_console_kit ("Stop", g_variant_new ("()"), &error); - break; - case LOGOUT_DIALOG_TYPE_RESTART: - g_debug("Telling ConsoleKit to 'Restart'"); - result = call_console_kit ("Restart", g_variant_new ("()"), &error); - break; - default: - g_warning("Unknown action"); - break; - } - - if (!result) { - if (error != NULL) { - g_warning ("ConsoleKit action failed: %s", error->message); - } else { - g_warning ("ConsoleKit action failed: unknown error"); - } - - consolekit_fallback(action); - } - else - g_variant_unref (result); - g_clear_error (&error); - - return; -} - -static GVariant * -call_gnome_session (const gchar *method, GVariant *parameters, GError **error) -{ - GDBusConnection * bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, error); - if (!bus) - { - g_variant_unref (parameters); - return NULL; - } - - GVariant *result = g_dbus_connection_call_sync(bus, - "org.gnome.SessionManager", - "/org/gnome/SessionManager", - "org.gnome.SessionManager", - method, - parameters, - NULL, - G_DBUS_CALL_FLAGS_NONE, - G_MAXINT, - NULL, - error); - g_object_unref (bus); - - return result; -} - -static void -session_action (LogoutDialogType action) -{ - GError * error = NULL; - GVariant *result = NULL; - - if (action == LOGOUT_DIALOG_TYPE_LOG_OUT) { - g_debug("Asking Session manager to 'Logout'"); - result = call_gnome_session ("Logout", g_variant_new ("(u)", 1), &error); - } else if (action == LOGOUT_DIALOG_TYPE_SHUTDOWN) { - g_debug("Asking Session manager to 'RequestShutdown'"); - result = call_gnome_session ("RequestShutdown", g_variant_new ("()"), &error); - } else if (action == LOGOUT_DIALOG_TYPE_RESTART) { - g_debug("Asking Session manager to 'RequestReboot'"); - result = call_gnome_session ("RequestReboot", g_variant_new ("()"), &error); - } else { - g_warning ("Unknown session action"); - } - - if (!result) { - if (error != NULL) { - g_warning ("SessionManager action failed: %s", error->message); - } else { - g_warning ("SessionManager action failed: unknown error"); - } - - consolekit_fallback(action); - } - else - g_variant_unref (result); - g_clear_error (&error); - - return; -} - -static LogoutDialogType type = LOGOUT_DIALOG_TYPE_LOG_OUT; - -static gboolean -option_logout (const gchar * arg, const gchar * value, gpointer data, GError * error) -{ - type = LOGOUT_DIALOG_TYPE_LOG_OUT; - g_debug("Dialog type: logout"); - return TRUE; -} - -static gboolean -option_shutdown (const gchar * arg, const gchar * value, gpointer data, GError * error) -{ - type = LOGOUT_DIALOG_TYPE_SHUTDOWN; - g_debug("Dialog type: shutdown"); - return TRUE; -} - -static gboolean -option_restart (const gchar * arg, const gchar * value, gpointer data, GError * error) -{ - type = LOGOUT_DIALOG_TYPE_RESTART; - g_debug("Dialog type: restart"); - return TRUE; -} - -static GOptionEntry options[] = { - {"logout", 'l', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, option_logout, "Log out of the current session", NULL}, - {"shutdown", 's', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, option_shutdown, "Switch off the entire system", NULL}, - {"restart", 'r', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, option_restart, "Restart the system", NULL}, - - {NULL} -}; - -static gboolean -suppress_confirmations (void) -{ - GSettings * s = g_settings_new (SESSION_SCHEMA); - const gboolean suppress = g_settings_get_boolean (s, SUPPRESS_KEY); - g_clear_object (&s); - return suppress; -} - - - -int -main (int argc, char * argv[]) -{ - gtk_init(&argc, &argv); - - /* Setting up i18n and gettext. Apparently, we need - all of these. */ - setlocale (LC_ALL, ""); - bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); - textdomain (GETTEXT_PACKAGE); - - GError * error = NULL; - GOptionContext * context = g_option_context_new(" - logout of the current session"); - g_option_context_add_main_entries(context, options, "gtk-logout-helper"); - g_option_context_add_group(context, gtk_get_option_group(TRUE)); - g_option_context_set_help_enabled(context, TRUE); - - if (!g_option_context_parse(context, &argc, &argv, &error)) { - g_debug("Option parsing failed: %s", error->message); - g_error_free(error); - return 1; - } - - /* Init some theme/icon stuff */ - gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), - INDICATOR_ICONS_DIR); - - GtkWidget * dialog = NULL; - if (!suppress_confirmations()) { - g_debug("Showing dialog to ask for user confirmation"); - dialog = GTK_WIDGET(logout_dialog_new(type)); - } - - if (dialog != NULL) { - GtkResponseType response = gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_hide(dialog); - - if (response == GTK_RESPONSE_OK) { - g_debug("Dialog return response: 'okay'"); - } else if (response == GTK_RESPONSE_HELP) { - g_debug("Dialog return response: 'help'"); - } else { - g_debug("Dialog return response: %d", response); - } - - if (response == GTK_RESPONSE_HELP) { - type = LOGOUT_DIALOG_TYPE_RESTART; - response = GTK_RESPONSE_OK; - } - - if (response != GTK_RESPONSE_OK) { - g_debug("Final response was not okay, quiting"); - return 0; - } - } - - session_action(type); - g_debug("Finished action, quiting"); - - return 0; -} diff --git a/src/guest.c b/src/guest.c new file mode 100644 index 0000000..bcbd384 --- /dev/null +++ b/src/guest.c @@ -0,0 +1,190 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include "guest.h" + +G_DEFINE_TYPE (IndicatorSessionGuest, + indicator_session_guest, + G_TYPE_OBJECT) + +enum +{ + PROP_0, + PROP_ALLOWED, + PROP_LOGGED_IN, + PROP_ACTIVE, + PROP_LAST +}; + +static GParamSpec *properties[PROP_LAST]; + +static void +my_get_property (GObject * o, + guint property_id, + GValue * value, + GParamSpec * pspec) +{ + IndicatorSessionGuest * self = INDICATOR_SESSION_GUEST (o); + + switch (property_id) + { + case PROP_ALLOWED: + g_value_set_boolean (value, indicator_session_guest_is_allowed (self)); + break; + + case PROP_LOGGED_IN: + g_value_set_boolean (value, indicator_session_guest_is_logged_in (self)); + break; + + case PROP_ACTIVE: + g_value_set_boolean (value, indicator_session_guest_is_active (self)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec); + } +} + +static void +my_dispose (GObject *object) +{ + G_OBJECT_CLASS (indicator_session_guest_parent_class)->dispose (object); +} + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_guest_class_init (IndicatorSessionGuestClass * klass) +{ + GObjectClass * object_class; + const GParamFlags flags = G_PARAM_READABLE | G_PARAM_STATIC_STRINGS; + + object_class = G_OBJECT_CLASS (klass); + object_class->get_property = my_get_property; + object_class->dispose = my_dispose; + + klass->is_allowed = NULL; + klass->is_logged_in = NULL; + klass->is_active = NULL; + klass->switch_to_guest = NULL; + + properties[PROP_0] = NULL; + + properties[PROP_ALLOWED] = + g_param_spec_boolean (INDICATOR_SESSION_GUEST_PROPERTY_ALLOWED, + "Is Allowed", + "Whether or not a Guest user is allowed", + FALSE, flags); + + properties[PROP_LOGGED_IN] = + g_param_spec_boolean (INDICATOR_SESSION_GUEST_PROPERTY_LOGGED_IN, + "Is Logged In", + "Whether or not the Guest account is logged in", + FALSE, flags); + + properties[PROP_ACTIVE] = + g_param_spec_boolean (INDICATOR_SESSION_GUEST_PROPERTY_ACTIVE, + "Is Active", + "If the Guest account has the current session", + FALSE, flags); + + g_object_class_install_properties (object_class, PROP_LAST, properties); +} + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_guest_init (IndicatorSessionGuest *self G_GNUC_UNUSED) +{ +} + +/*** +**** +***/ + +gboolean +indicator_session_guest_is_active (IndicatorSessionGuest * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_GUEST (self), FALSE); + + return INDICATOR_SESSION_GUEST_GET_CLASS (self)->is_active (self); +} + +gboolean +indicator_session_guest_is_allowed (IndicatorSessionGuest * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_GUEST (self), FALSE); + + return INDICATOR_SESSION_GUEST_GET_CLASS (self)->is_allowed (self); +} + +gboolean +indicator_session_guest_is_logged_in (IndicatorSessionGuest * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_GUEST (self), FALSE); + + return INDICATOR_SESSION_GUEST_GET_CLASS (self)->is_logged_in (self); +} + +/*** +**** +***/ +static void +notify_func (IndicatorSessionGuest * self, int prop) +{ + g_return_if_fail (INDICATOR_IS_SESSION_GUEST (self)); + + g_debug ("%s %s emitting '%s' prop notify", G_STRLOC, G_STRFUNC, properties[prop]->name); + + g_object_notify_by_pspec (G_OBJECT(self), properties[prop]); +} + +void +indicator_session_guest_notify_active (IndicatorSessionGuest * self) +{ + notify_func (self, PROP_ACTIVE); +} + +void +indicator_session_guest_notify_allowed (IndicatorSessionGuest * self) +{ + notify_func (self, PROP_ALLOWED); +} + +void +indicator_session_guest_notify_logged_in (IndicatorSessionGuest * self) +{ + notify_func (self, PROP_LOGGED_IN); +} + +/*** +**** +***/ + +void +indicator_session_guest_switch_to_guest (IndicatorSessionGuest * self) +{ + gboolean allowed; + + g_return_if_fail (INDICATOR_IS_SESSION_GUEST (self)); + + g_object_get (self, INDICATOR_SESSION_GUEST_PROPERTY_ALLOWED, &allowed, NULL); + g_return_if_fail (allowed); + + INDICATOR_SESSION_GUEST_GET_CLASS (self)->switch_to_guest (self); +} + diff --git a/src/guest.h b/src/guest.h new file mode 100644 index 0000000..30947d5 --- /dev/null +++ b/src/guest.h @@ -0,0 +1,82 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#ifndef __GUEST_H__ +#define __GUEST_H__ + +#include +#include + +G_BEGIN_DECLS + +#define INDICATOR_TYPE_SESSION_GUEST (indicator_session_guest_get_type()) +#define INDICATOR_SESSION_GUEST(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_SESSION_GUEST, IndicatorSessionGuest)) +#define INDICATOR_SESSION_GUEST_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_SESSION_GUEST, IndicatorSessionGuestClass)) +#define INDICATOR_SESSION_GUEST_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), INDICATOR_TYPE_SESSION_GUEST, IndicatorSessionGuestClass)) +#define INDICATOR_IS_SESSION_GUEST(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_SESSION_GUEST)) + +typedef struct _IndicatorSessionGuest IndicatorSessionGuest; +typedef struct _IndicatorSessionGuestClass IndicatorSessionGuestClass; + +GType indicator_session_guest_get_type (void); + +/** + * A base class for getting state information about the system's guest user. + * Use backend.h's get_backend() to get an instance. + */ +struct _IndicatorSessionGuest +{ + /*< private >*/ + GObject parent; +}; + +/* properties */ +#define INDICATOR_SESSION_GUEST_PROPERTY_ALLOWED "guest-is-allowed" +#define INDICATOR_SESSION_GUEST_PROPERTY_LOGGED_IN "guest-is-logged-in" +#define INDICATOR_SESSION_GUEST_PROPERTY_ACTIVE "guest-is-active-session" + +struct _IndicatorSessionGuestClass +{ + GObjectClass parent_class; + + /* virtual functions */ + gboolean (* is_allowed) (IndicatorSessionGuest * self); + gboolean (* is_logged_in) (IndicatorSessionGuest * self); + gboolean (* is_active) (IndicatorSessionGuest * self); + void (* switch_to_guest) (IndicatorSessionGuest * self); +}; + +gboolean indicator_session_guest_is_allowed (IndicatorSessionGuest * self); +gboolean indicator_session_guest_is_logged_in (IndicatorSessionGuest * self); +gboolean indicator_session_guest_is_active (IndicatorSessionGuest * self); + +void indicator_session_guest_switch_to_guest (IndicatorSessionGuest * self); + +/** + * Emit 'notify' signals for the corresponding properties. + * These functions should only be called by IndicatorSessionGuest implementations. + */ +void indicator_session_guest_notify_allowed (IndicatorSessionGuest * self); +void indicator_session_guest_notify_logged_in (IndicatorSessionGuest * self); +void indicator_session_guest_notify_active (IndicatorSessionGuest * self); + + +G_END_DECLS + +#endif diff --git a/src/indicator-session.c b/src/indicator-session.c deleted file mode 100644 index 431292e..0000000 --- a/src/indicator-session.c +++ /dev/null @@ -1,495 +0,0 @@ -/* -A small wrapper utility to load indicators and put them as menu items -into the gnome-panel using its applet interface. - -Copyright 2009 Canonical Ltd. - -Authors: - Ted Gould - Conor Curran - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include "shared-names.h" -#include "user-widget.h" - -#define INDICATOR_SESSION_TYPE (indicator_session_get_type ()) -#define INDICATOR_SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_SESSION_TYPE, IndicatorSession)) -#define INDICATOR_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), INDICATOR_SESSION_TYPE, IndicatorSessionClass)) -#define IS_INDICATOR_SESSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INDICATOR_SESSION_TYPE)) -#define IS_INDICATOR_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), INDICATOR_SESSION_TYPE)) -#define INDICATOR_SESSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), INDICATOR_SESSION_TYPE, IndicatorSessionClass)) - -typedef struct _IndicatorSession IndicatorSession; -typedef struct _IndicatorSessionClass IndicatorSessionClass; - -struct _IndicatorSessionClass -{ - IndicatorObjectClass parent_class; -}; - -struct _IndicatorSession -{ - IndicatorObject parent; - IndicatorServiceManager * service; - IndicatorObjectEntry entry; - GCancellable * service_proxy_cancel; - GDBusProxy * service_proxy; - GSettings * settings; - DbusmenuClient * menu_client; - GtkIconTheme * icon_theme; -}; - -GType indicator_session_get_type (void); - -/* Indicator stuff */ -INDICATOR_SET_VERSION -INDICATOR_SET_TYPE(INDICATOR_SESSION_TYPE) - -/* Prototypes */ -static gboolean new_user_item (DbusmenuMenuitem * newitem, - DbusmenuMenuitem * parent, - DbusmenuClient * client, - gpointer user_data); -static void on_menu_layout_updated (DbusmenuClient * client, IndicatorSession * session); -static void indicator_session_update_icon_callback (GtkWidget * widget, gpointer callback_data); -static void indicator_session_update_icon_and_a11y (IndicatorSession * self); -static void indicator_session_update_users_label (IndicatorSession* self, - const gchar* name); -static void service_connection_cb (IndicatorServiceManager * sm, gboolean connected, gpointer user_data); -static void receive_signal (GDBusProxy * proxy, gchar * sender_name, gchar * signal_name, GVariant * parameters, gpointer user_data); -static void service_proxy_cb (GObject * object, GAsyncResult * res, gpointer user_data); -static void user_real_name_get_cb (GObject * obj, GAsyncResult * res, gpointer user_data); - -static void indicator_session_class_init (IndicatorSessionClass *klass); -static void indicator_session_init (IndicatorSession *self); -static void indicator_session_dispose (GObject *object); -static void indicator_session_finalize (GObject *object); -static GList* indicator_session_get_entries (IndicatorObject* obj); -static guint indicator_session_get_location (IndicatorObject * io, - IndicatorObjectEntry * entry); - -G_DEFINE_TYPE (IndicatorSession, indicator_session, INDICATOR_OBJECT_TYPE); - -static void -indicator_session_class_init (IndicatorSessionClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->dispose = indicator_session_dispose; - object_class->finalize = indicator_session_finalize; - - IndicatorObjectClass * io_class = INDICATOR_OBJECT_CLASS(klass); - io_class->get_entries = indicator_session_get_entries; - io_class->get_location = indicator_session_get_location; - return; -} - -static void -indicator_session_init (IndicatorSession *self) -{ - self->settings = g_settings_new ("com.canonical.indicator.session"); - - /* Now let's fire these guys up. */ - self->service = indicator_service_manager_new_version(INDICATOR_SESSION_DBUS_NAME, - INDICATOR_SESSION_DBUS_VERSION); - g_signal_connect (G_OBJECT(self->service), - INDICATOR_SERVICE_MANAGER_SIGNAL_CONNECTION_CHANGE, - G_CALLBACK(service_connection_cb), self); - - self->entry.name_hint = PACKAGE; - self->entry.label = GTK_LABEL (gtk_label_new ("User Name")); - self->entry.image = GTK_IMAGE (gtk_image_new()); - self->entry.menu = GTK_MENU (dbusmenu_gtkmenu_new(INDICATOR_SESSION_DBUS_NAME, - INDICATOR_SESSION_DBUS_OBJECT)); - /* We need to check if the current icon theme has the hard coded icons. - * If not, we'll fall back to a standard icon */ - self->icon_theme = gtk_icon_theme_get_default(); - g_signal_connect(G_OBJECT(self->icon_theme), - "changed", - G_CALLBACK(indicator_session_update_icon_callback), self); - - indicator_session_update_icon_and_a11y (self); - g_settings_bind (self->settings, "show-real-name-on-panel", - self->entry.label, "visible", - G_SETTINGS_BIND_GET); - - /* show-real-name-on-panel affects the a11y string */ - g_signal_connect_swapped (self->settings, - "notify::show-real-name-on-panel", - G_CALLBACK(indicator_session_update_icon_and_a11y), - self); - - gtk_widget_show (GTK_WIDGET(self->entry.menu)); - gtk_widget_show (GTK_WIDGET(self->entry.image)); - g_object_ref_sink (self->entry.menu); - g_object_ref_sink (self->entry.image); - - // set up the handlers - self->menu_client = DBUSMENU_CLIENT(dbusmenu_gtkmenu_get_client(DBUSMENU_GTKMENU(self->entry.menu))); - g_signal_connect (self->menu_client, "layout-updated", - G_CALLBACK(on_menu_layout_updated), self); - - dbusmenu_client_add_type_handler (self->menu_client, - USER_ITEM_TYPE, - new_user_item); - dbusmenu_gtkclient_set_accel_group (DBUSMENU_GTKCLIENT(self->menu_client), - gtk_accel_group_new()); -} - -static void -indicator_session_dispose (GObject *object) -{ - IndicatorSession * self = INDICATOR_SESSION(object); - - g_clear_object (&self->settings); - g_clear_object (&self->service); - g_clear_object (&self->service_proxy); - - if (self->service_proxy_cancel != NULL) - { - g_cancellable_cancel(self->service_proxy_cancel); - g_clear_object (&self->service_proxy_cancel); - } - - g_clear_object (&self->entry.menu); - - G_OBJECT_CLASS (indicator_session_parent_class)->dispose (object); -} - -static void -indicator_session_finalize (GObject *object) -{ - - G_OBJECT_CLASS (indicator_session_parent_class)->finalize (object); - return; -} - -static GList* -indicator_session_get_entries (IndicatorObject* obj) -{ - g_return_val_if_fail(IS_INDICATOR_SESSION(obj), NULL); - - IndicatorSession* self = INDICATOR_SESSION (obj); - return g_list_append (NULL, &self->entry); -} - -static guint -indicator_session_get_location (IndicatorObject * io, - IndicatorObjectEntry * entry) -{ - return 0; -} - -/* callback for the service manager state of being */ -static void -service_connection_cb (IndicatorServiceManager * sm, gboolean connected, gpointer user_data) -{ - IndicatorSession * self = INDICATOR_SESSION (user_data); - - if (connected) { - if (self->service_proxy != NULL){ - // Its a reconnect ! - // Fetch synchronisation data and return (proxy is still legit) - g_dbus_proxy_call (self->service_proxy, - "GetUserRealName", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - user_real_name_get_cb, - user_data); - return; - } - - self->service_proxy_cancel = g_cancellable_new(); - g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, - G_DBUS_PROXY_FLAGS_NONE, - NULL, - INDICATOR_SESSION_DBUS_NAME, - INDICATOR_SESSION_SERVICE_DBUS_OBJECT, - INDICATOR_SESSION_SERVICE_DBUS_IFACE, - self->service_proxy_cancel, - service_proxy_cb, - self); - } - return; -} - - -static void -service_proxy_cb (GObject * object, GAsyncResult * res, gpointer user_data) -{ - GError * error = NULL; - - IndicatorSession * self = INDICATOR_SESSION(user_data); - g_return_if_fail(self != NULL); - - GDBusProxy * proxy = g_dbus_proxy_new_for_bus_finish(res, &error); - - g_clear_object (&self->service_proxy_cancel); - - if (error != NULL) { - g_warning("Could not grab DBus proxy for %s: %s", INDICATOR_SESSION_DBUS_NAME, error->message); - g_error_free(error); - return; - } - - /* Okay, we're good to grab the proxy at this point, we're - sure that it's ours. */ - self->service_proxy = proxy; - - g_signal_connect(proxy, "g-signal", G_CALLBACK(receive_signal), self); - - // Fetch the user's real name for the user entry label - g_dbus_proxy_call (self->service_proxy, - "GetUserRealName", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - user_real_name_get_cb, - user_data); - return; -} - - -static gboolean -new_user_item (DbusmenuMenuitem * newitem, - DbusmenuMenuitem * parent, - DbusmenuClient * client, - gpointer user_data) -{ - g_return_val_if_fail (DBUSMENU_IS_MENUITEM(newitem), FALSE); - g_return_val_if_fail (DBUSMENU_IS_GTKCLIENT(client), FALSE); - - GtkWidget * user_item = user_widget_new (newitem); - - GtkMenuItem *user_widget = GTK_MENU_ITEM(user_item); - - dbusmenu_gtkclient_newitem_base (DBUSMENU_GTKCLIENT(client), - newitem, - user_widget, - parent); - - g_debug ("%s (\"%s\")", __func__, - dbusmenu_menuitem_property_get (newitem, - USER_ITEM_PROP_NAME)); - return TRUE; -} - -static void -user_real_name_get_cb (GObject * obj, GAsyncResult * res, gpointer user_data) -{ - IndicatorSession * self = INDICATOR_SESSION(user_data); - - GError * error = NULL; - GVariant * result = g_dbus_proxy_call_finish(self->service_proxy, res, &error); - - if (error != NULL) - { - g_warning ("Unable to complete real name dbus query: %s", error->message); - g_clear_error (&error); - } - else - { - const gchar * username = NULL; - g_variant_get (result, "(&s)", &username); - indicator_session_update_users_label (self, username); - g_variant_unref (result); - } -} - -/* Receives all signals from the service, routed to the appropriate functions */ -static void -receive_signal (GDBusProxy * proxy, - gchar * sender_name, - gchar * signal_name, - GVariant * parameters, - gpointer user_data) -{ - IndicatorSession * self = INDICATOR_SESSION(user_data); - - if (!g_strcmp0(signal_name, "UserRealNameUpdated")) - { - const gchar * username = NULL; - g_variant_get (parameters, "(&s)", &username); - indicator_session_update_users_label (self, username); - } -} - -static void -indicator_session_update_users_label (IndicatorSession * self, - const gchar * name) -{ - gtk_label_set_text (self->entry.label, name ? name : ""); -} - -/*** -**** Disposition -***/ - -enum -{ - DISPOSITION_NORMAL, - DISPOSITION_INFO, - DISPOSITION_WARNING, - DISPOSITION_ALERT -}; - -static void -indicator_session_update_a11y_from_disposition (IndicatorSession * indicator, - int disposition) -{ - gchar * a11y; - const gchar * username = gtk_label_get_text (indicator->entry.label); - const gboolean need_attn = disposition != DISPOSITION_NORMAL; - const gboolean show_name = g_settings_get_boolean (indicator->settings, - "show-real-name-on-panel"); - - if (show_name && need_attn) - /* Translators: the name of the menu ("System"), followed by the user's name, - followed by a hint that an item in this menu requires an action from the user */ - a11y = g_strdup_printf (_("System %s (Attention Required)"), username); - else if (show_name) - /* Translators: the name of the menu ("System"), followed by the user's name */ - a11y = g_strdup_printf (_("System %s"), username); - else if (need_attn) - a11y = g_strdup (_("System (Attention Required)")); - else - a11y = g_strdup (_("System")); - - g_debug (G_STRLOC" setting a11y to \"%s\"", a11y); - g_clear_pointer (&indicator->entry.accessible_desc, g_free); - indicator->entry.accessible_desc = a11y; - g_signal_emit (indicator, - INDICATOR_OBJECT_SIGNAL_ACCESSIBLE_DESC_UPDATE_ID, - 0, - &indicator->entry); -} - -static void -indicator_session_update_icon_from_disposition (IndicatorSession * indicator, - int disposition) -{ - const gchar * icon; - - if (disposition == DISPOSITION_NORMAL) - icon = ICON_DEFAULT; - else if (disposition == DISPOSITION_INFO) - icon = ICON_INFO; - else - icon = ICON_ALERT; - - if (gtk_icon_theme_has_icon (indicator->icon_theme, icon) == FALSE) - icon = "gtk-missing-image"; - - g_debug (G_STRLOC" setting icon to \"%s\"", icon); - gtk_image_set_from_icon_name (GTK_IMAGE(indicator->entry.image), - icon, - GTK_ICON_SIZE_BUTTON); -} - -static int -calculate_disposition (IndicatorSession * indicator) -{ - GList * l; - DbusmenuMenuitem * root = dbusmenu_client_get_root (indicator->menu_client); - GList * children = dbusmenu_menuitem_get_children (root); - int ret = DISPOSITION_NORMAL; - - for (l=children; l!=NULL; l=l->next) - { - int val; - const gchar * key = DBUSMENU_MENUITEM_PROP_DISPOSITION; - const gchar * val_str = dbusmenu_menuitem_property_get (l->data, key); - - if (!g_strcmp0 (val_str, DBUSMENU_MENUITEM_DISPOSITION_ALERT)) - val = DISPOSITION_ALERT; - else if (!g_strcmp0 (val_str, DBUSMENU_MENUITEM_DISPOSITION_WARNING)) - val = DISPOSITION_WARNING; - else if (!g_strcmp0 (val_str, DBUSMENU_MENUITEM_DISPOSITION_INFORMATIVE)) - val = DISPOSITION_INFO; - else - val = DISPOSITION_NORMAL; - - if (ret < val) - ret = val; - } - - return ret; -} - -static void -indicator_session_update_icon_callback (GtkWidget * widget, gpointer callback_data) -{ - indicator_session_update_icon_and_a11y ((IndicatorSession *)callback_data); -} - -static void -indicator_session_update_icon_and_a11y (IndicatorSession * indicator) -{ - const int disposition = calculate_disposition (indicator); - indicator_session_update_a11y_from_disposition (indicator, disposition); - indicator_session_update_icon_from_disposition (indicator, disposition); -} - -static void -on_menuitem_property_changed (DbusmenuMenuitem * mi, - gchar * property, - GValue * value, - gpointer indicator) -{ - if (!g_strcmp0 (property, DBUSMENU_MENUITEM_PROP_DISPOSITION)) - indicator_session_update_icon_and_a11y (indicator); -} - -static void -on_menu_layout_updated (DbusmenuClient * client, IndicatorSession * session) -{ - GList * l; - DbusmenuMenuitem * root = dbusmenu_client_get_root (client); - GList * children = dbusmenu_menuitem_get_children (root); - static GQuark tag = 0; - - if (G_UNLIKELY (tag == 0)) - { - tag = g_quark_from_static_string ("x-tagged-by-indicator-session"); - } - - for (l=children; l!=NULL; l=l->next) - { - if (g_object_get_qdata (l->data, tag) == NULL) - { - g_object_set_qdata (l->data, tag, GINT_TO_POINTER(1)); - g_signal_connect (l->data, "property-changed", G_CALLBACK(on_menuitem_property_changed), session); - } - } -} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..ff5997b --- /dev/null +++ b/src/main.c @@ -0,0 +1,87 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include +#include /* exit() */ + +#include +#include + +#include "service.h" + +/*** +**** +***/ + +static gboolean replace = FALSE; + +static void +parse_command_line (int * argc, char *** argv) +{ + GError * error; + GOptionContext * option_context; + + static GOptionEntry entries[] = + { + { "replace", 'r', 0, G_OPTION_ARG_NONE, &replace, "Replace the currently-running service", NULL }, + { NULL } + }; + + error = NULL; + option_context = g_option_context_new ("- indicator-session service"); + g_option_context_add_main_entries (option_context, entries, GETTEXT_PACKAGE); + if (!g_option_context_parse (option_context, argc, argv, &error)) + { + g_print ("option parsing failed: %s\n", error->message); + g_error_free (error); + exit (EXIT_FAILURE); + } + + g_option_context_free (option_context); +} + +/*** +**** +***/ + +int +main (int argc, char ** argv) +{ + GMainLoop * loop; + IndicatorSessionService * service; + + signal (SIGPIPE, SIG_IGN); + + /* boilerplate i18n */ + setlocale (LC_ALL, ""); + bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); + textdomain (GETTEXT_PACKAGE); + + parse_command_line (&argc, &argv); + + /* run */ + service = indicator_session_service_new (replace); + loop = g_main_loop_new (NULL, FALSE); + g_main_loop_run (loop); + + /* cleanup */ + g_clear_object (&service); + g_main_loop_unref (loop); + return 0; +} diff --git a/src/online-accounts-mgr.c b/src/online-accounts-mgr.c deleted file mode 100644 index 4abba00..0000000 --- a/src/online-accounts-mgr.c +++ /dev/null @@ -1,166 +0,0 @@ -/* -Copyright 2012 Canonical Ltd. - -Authors: - Alberto Mardegan - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . -*/ - -#include -#include - -#include "online-accounts-mgr.h" - -#include - -struct _OnlineAccountsMgr -{ - GObject parent_instance; - GDBusProxy *proxy; - DbusmenuMenuitem *menu_item; -}; - -#define ONLINE_ACCOUNTS_OBJECT_PATH "/com/canonical/indicators/webcredentials" -#define ONLINE_ACCOUNTS_BUS_NAME "com.canonical.indicators.webcredentials" -#define ONLINE_ACCOUNTS_INTERFACE ONLINE_ACCOUNTS_BUS_NAME - -G_DEFINE_TYPE (OnlineAccountsMgr, online_accounts_mgr, G_TYPE_OBJECT); - -static void -update_disposition (OnlineAccountsMgr *self, GVariant *error_status_prop) -{ - gboolean error_status; - - error_status = g_variant_get_boolean (error_status_prop); - dbusmenu_menuitem_property_set (self->menu_item, - DBUSMENU_MENUITEM_PROP_DISPOSITION, - error_status ? - DBUSMENU_MENUITEM_DISPOSITION_ALERT : - DBUSMENU_MENUITEM_DISPOSITION_NORMAL); -} - -static void -on_properties_changed (GDBusProxy *proxy, - GVariant *changed_properties, - GStrv invalidated_properties, - OnlineAccountsMgr *self) -{ - if (g_variant_n_children (changed_properties) > 0) { - GVariantIter *iter; - const gchar *key; - GVariant *value; - - g_variant_get (changed_properties, "a{sv}", &iter); - while (g_variant_iter_loop (iter, "{&sv}", &key, &value)) { - if (g_strcmp0 (key, "ErrorStatus") == 0) { - update_disposition (self, value); - } - } - g_variant_iter_free (iter); - } -} - -static void -on_menu_item_activated (DbusmenuMenuitem *menu_item, - guint timestamp, - OnlineAccountsMgr *self) -{ - GError *error = NULL; - - if (!g_spawn_command_line_async("gnome-control-center credentials", &error)) - { - g_warning("Unable to show control center: %s", error->message); - g_error_free(error); - } -} - -static void -online_accounts_mgr_init (OnlineAccountsMgr *self) -{ - GError *error = NULL; - GVariant *error_status_prop; - - self->menu_item = dbusmenu_menuitem_new (); - dbusmenu_menuitem_property_set (self->menu_item, - DBUSMENU_MENUITEM_PROP_TYPE, - DBUSMENU_CLIENT_TYPES_DEFAULT); - dbusmenu_menuitem_property_set (self->menu_item, - DBUSMENU_MENUITEM_PROP_LABEL, - _("Online Accounts\342\200\246")); - g_signal_connect (self->menu_item, - DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK (on_menu_item_activated), - self); - - self->proxy = - g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, - G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, - NULL, - ONLINE_ACCOUNTS_BUS_NAME, - ONLINE_ACCOUNTS_OBJECT_PATH, - ONLINE_ACCOUNTS_INTERFACE, - NULL, - &error); - if (G_UNLIKELY (error != NULL)) { - g_warning ("Couldn't create online_accounts proxy: %s", error->message); - g_clear_error (&error); - return; - } - - g_signal_connect (self->proxy, "g-properties-changed", - G_CALLBACK (on_properties_changed), self); - - error_status_prop = - g_dbus_proxy_get_cached_property (self->proxy, "ErrorStatus"); - if (error_status_prop != NULL) { - update_disposition (self, error_status_prop); - g_variant_unref (error_status_prop); - } -} - -static void -online_accounts_mgr_dispose (GObject *object) -{ - OnlineAccountsMgr *self = ONLINE_ACCOUNTS_MGR (object); - - if (self->proxy != NULL) { - g_object_unref (self->proxy); - self->proxy = NULL; - } - - if (self->menu_item != NULL) { - g_object_unref (self->menu_item); - self->menu_item = NULL; - } - - G_OBJECT_CLASS (online_accounts_mgr_parent_class)->dispose (object); -} - -static void -online_accounts_mgr_class_init (OnlineAccountsMgrClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - object_class->dispose = online_accounts_mgr_dispose; -} - -OnlineAccountsMgr *online_accounts_mgr_new () -{ - return g_object_new (ONLINE_ACCOUNTS_TYPE_MGR, NULL); -} - -DbusmenuMenuitem *online_accounts_mgr_get_menu_item (OnlineAccountsMgr *self) -{ - g_return_val_if_fail (ONLINE_ACCOUNTS_IS_MGR (self), NULL); - return self->menu_item; -} diff --git a/src/online-accounts-mgr.h b/src/online-accounts-mgr.h deleted file mode 100644 index 16c0461..0000000 --- a/src/online-accounts-mgr.h +++ /dev/null @@ -1,50 +0,0 @@ -/* -Copyright 2012 Canonical Ltd. - -Authors: - Alberto Mardegan - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . -*/ - -#ifndef _ONLINE_ACCOUNTS_MGR_H_ -#define _ONLINE_ACCOUNTS_MGR_H_ - -#include -#include - -G_BEGIN_DECLS - -#define ONLINE_ACCOUNTS_TYPE_MGR (online_accounts_mgr_get_type ()) -#define ONLINE_ACCOUNTS_MGR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ONLINE_ACCOUNTS_TYPE_MGR, OnlineAccountsMgr)) -#define ONLINE_ACCOUNTS_MGR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ONLINE_ACCOUNTS_TYPE_MGR, OnlineAccountsMgrClass)) -#define ONLINE_ACCOUNTS_IS_MGR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ONLINE_ACCOUNTS_TYPE_MGR)) -#define ONLINE_ACCOUNTS_IS_MGR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ONLINE_ACCOUNTS_TYPE_MGR)) -#define ONLINE_ACCOUNTS_MGR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ONLINE_ACCOUNTS_TYPE_MGR, OnlineAccountsMgrClass)) - -typedef struct _OnlineAccountsMgrClass OnlineAccountsMgrClass; -typedef struct _OnlineAccountsMgr OnlineAccountsMgr; - -struct _OnlineAccountsMgrClass -{ - GObjectClass parent_class; -}; - -GType online_accounts_mgr_get_type (void) G_GNUC_CONST; -OnlineAccountsMgr *online_accounts_mgr_new (void); - -DbusmenuMenuitem *online_accounts_mgr_get_menu_item (OnlineAccountsMgr *self); - -G_END_DECLS - -#endif /* _ONLINE_ACCOUNTS_MGR_H_ */ diff --git a/src/org.freedesktop.Accounts.User.xml b/src/org.freedesktop.Accounts.User.xml deleted file mode 100644 index 53f54d4..0000000 --- a/src/org.freedesktop.Accounts.User.xml +++ /dev/null @@ -1,744 +0,0 @@ - - - - - - - - - - - The new username. - - - - - - - Sets the users username. Note that it is usually not allowed - to have multiple users with the same username. - - - - The caller needs one of the following PolicyKit authorizations: - - - org.freedesktop.accounts.user-administration - To change the username of any user - - - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - - - The new name, typically in the form "Firstname Lastname". - - - - - - - Sets the users real name. - - - - The caller needs one of the following PolicyKit authorizations: - - - org.freedesktop.accounts.change-own-user-data - To change his own name - - - org.freedesktop.accounts.user-administration - To change the name of another user - - - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - - - The new email address. - - - - - - - Sets the users email address. - - - Note that setting an email address in the AccountsService is - not the same as configuring a mail client. Mail clients might - default to email address that is configured here, though. - - - - The caller needs one of the following PolicyKit authorizations: - - - org.freedesktop.accounts.change-own-user-data - To change his own email address - - - org.freedesktop.accounts.user-administration - To change the email address of another user - - - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - - - The new language, as a locale specification like "de_DE.UTF-8". - - - - - - - Sets the users language. - - - The expectation is that display managers will start the - users session with this locale. - - - - The caller needs one of the following PolicyKit authorizations: - - - org.freedesktop.accounts.change-own-user-data - To change his own language - - - org.freedesktop.accounts.user-administration - To change the language of another user - - - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - - - - The new xsession to start (e.g. "gnome") - - - - - - - Sets the users x session. - - - The expectation is that display managers will log the user in to this - specified session, if available. - - - - The caller needs one of the following PolicyKit authorizations: - - - org.freedesktop.accounts.change-own-user-data - To change his own language - - - org.freedesktop.accounts.user-administration - To change the language of another user - - - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - - - The new location as a freeform string. - - - - - - - Sets the users location. - - - - The caller needs one of the following PolicyKit authorizations: - - - org.freedesktop.accounts.change-own-user-data - To change his own location - - - org.freedesktop.accounts.user-administration - To change the location of another user - - - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - - - The new homedir as an absolute path. - - - - - - - Sets the users home directory. - - - Note that changing the users home directory moves all the content - from the old location to the new one, and is potentially an - expensive operation. - - - - The caller needs one of the following PolicyKit authorizations: - - - org.freedesktop.accounts.user-administration - To change the home directory of a user - - - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - - - The new user shell. - - - - - - - Sets the users shell. - - - Note that setting the shell to a non-allowed program may - prevent the user from logging in. - - - - The caller needs one of the following PolicyKit authorizations: - - - org.freedesktop.accounts.user-administration - To change the shell of a user - - - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - - - The absolute filename of a png file to use as the users icon. - - - - - - - Sets the users icon. - - - - The caller needs one of the following PolicyKit authorizations: - - - org.freedesktop.accounts.change-own-user-data - To change his own icon - - - org.freedesktop.accounts.user-administration - To change the icon of another user - - - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - - - Whether to lock or unlock the users account. - - - - - - - Locks or unlocks a users account. - - - Locking an account prevents the user from logging in. - - - - The caller needs one of the following PolicyKit authorizations: - - - org.freedesktop.accounts.user-administration - To lock or unlock user accounts - - - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - - - The new account type, encoded as an integer: - - - 0 - Standard user - - - 1 - Administrator - - - - - - - - - Changes the users account type. - - - - The caller needs one of the following PolicyKit authorizations: - - - org.freedesktop.accounts.user-administration - To change an account type - - - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - - - The new password mode, encoded as an integer: - - - 0 - Regular password - - - 1 - Password must be set at next login - - - 2 - No password - - - - - - - - - Changes the users password mode. - - - Note that changing the password mode has the side-effect of - unlocking the account. - - - - The caller needs one of the following PolicyKit authorizations: - - - org.freedesktop.accounts.user-administration - To change a users password mode - - - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - - - The crypted password. - - - - - - - The password hint. - - - - - - - Sets a new password for this user. - - - Note that setting a password has the side-effect of - unlocking the account. - - - - The caller needs one of the following PolicyKit authorizations: - - - org.freedesktop.accounts.user-administration - To change the password of a user - - - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - - - Whether to enable automatic login for this user. - - - - - - - Enables or disables automatic login for a user. - - - Note that usually only one user can have automatic login - enabled, so turning it on for a user will disable it for - the previously configured autologin user. - - - - The caller needs one of the following PolicyKit authorizations: - - - org.freedesktop.accounts.set-login-option - To change the login screen configuration - - - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - - The uid of the user. - - - - - - - - - - The username of the user. - - - - - - - - - - The users real name. - - - - - - - - - - The users account type, encoded as an integer: - - - 0 - Standard user - - - 1 - Administrator - - - - - - - - - - - - The users home directory. - - - - - - - - - - The users shell. - - - - - - - - - - The email address. - - - - - - - - - - The users language, as a locale specification like "de_DE.UTF-8". - - - - - - - - - - The users x session. - - - - - - - - - - The users location. - - - - - - - - - - How often the user has logged in. - - - - - - - - - - The filename of a png file containing the users icon. - - - - - - - - - - Whether the users account is locked. - - - - - - - - - - The password mode for the user account, encoded as an integer: - - - 0 - Regular password - - - 1 - Password must be set at next login - - - 2 - No password - - - - - - - - - - - - The password hint for the user. - - - - - - - - - - Whether automatic login is enabled for the user. - - - - - - - - - - Whether this is a 'system' account, like 'root' or 'nobody'. - System accounts should normally not appear in lists of - users, and ListCachedUsers will not include such accounts. - - - - - - - - - - Emitted when the user is changed. - - - - - - - diff --git a/src/org.freedesktop.Accounts.xml b/src/org.freedesktop.Accounts.xml deleted file mode 100644 index 9c19761..0000000 --- a/src/org.freedesktop.Accounts.xml +++ /dev/null @@ -1,194 +0,0 @@ - - - - - - - - - - Object paths of cached users - - - - - - Lists users which have logged into the system locally before. - This is not meant to return an exhaustive list of all users. - It is possible for FindUserByName() - to return a user that's not on the list. - - - - - - - - - The uid to look up - - - Object path of user - - - - - - Finds a user by uid. - - - - if no user with the given uid exists - - - - - - - - The username to look up - - - Object path of user - - - - - - Finds a user by its username. - - - - if no user with the given username exists - - - - - - - - The username for the new user - - - - The real name for the new user - - - Object path of the new user - - - - The account type, encoded as an integer - - - - - - Creates a new user account. - - - The accountType argument can take the following values: - - - - 0 - Standard user - - - 1 - Administrator - - - 2 - Supervised user - - - - - The caller needs the org.freedesktop.accounts.user-administration PolicyKit authorization. - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - The uid to delete - - - Whether to remove the users files - - - - - - Deletes a user account. - - - - The caller needs the org.freedesktop.accounts.user-administration PolicyKit authorization. - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - Object path of the user that was added. - - - - - Emitted when a user is added. - - - - - - - - Object path of the user that was deleted. - - - - - Emitted when a user is deleted. - - - - - - - - Object path of the user that was changed. - - - - - Emitted when a user is changed. - - - - - - - - - - The version of the running daemon. - - - - - - - diff --git a/src/org.freedesktop.ConsoleKit.Manager.xml b/src/org.freedesktop.ConsoleKit.Manager.xml deleted file mode 100644 index f903b55..0000000 --- a/src/org.freedesktop.ConsoleKit.Manager.xml +++ /dev/null @@ -1,353 +0,0 @@ - - - - - - - - - This method initiates a request to restart (ie. reboot) the computer system. - - - - - - - - - - - - - - This method initiates a request to stop (ie. shutdown) the computer system. - - - - - - - - - - - - - - The secret cookie that is used to identify the new session - - - - - This method requests that a new Session - be created for the calling process. The properties of this new Session are set automatically - from information collected about the calling process. - - This new session exists until the calling process disconnects from the system bus or - calls CloseSession(). - - It is the responsibility of the calling process to set the environment variable - XDG_SESSION_COOKIE to the value of the returned cookie. This cookie should only - be made available to child processes of the caller so that they may be identified - as members of this session. - - See this simple example: - - DBusError error; - DBusMessage *message; - DBusMessage *reply; - - message = dbus_message_new_method_call ("org.freedesktop.ConsoleKit", - "/org/freedesktop/ConsoleKit/Manager", - "org.freedesktop.ConsoleKit.Manager", - "OpenSession"); - if (message == NULL) { - goto out; - } - - dbus_error_init (&error); - reply = dbus_connection_send_with_reply_and_block (connector->connection, - message, - -1, - &error); - if (reply == NULL) { - goto out; - } - - dbus_error_init (&error); - if (! dbus_message_get_args (reply, - &error, - DBUS_TYPE_STRING, &cookie, - DBUS_TYPE_INVALID)) { - goto out; - } - - - - OpenSessionWithParameters() - - - - - - - An array of sets of property names and values - - - - - The secret cookie that is used to identify the new session - - - - - This method requests that a new Session - be created for the calling process. The properties of this new Session are from the - parameters provided. - - This new session exists until the calling process disconnects from the system bus or - calls CloseSession(). - - It is the responsibility of the calling process to set the environment variable - XDG_SESSION_COOKIE to the value of the returned cookie. This cookie should only - be made available to child processes of the caller so that they may be identified - as members of this session. - - See the Session properties for a list of valid parameters. - - org.freedesktop.ConsoleKit.Session - This method is restricted to privileged users by D-Bus policy. - - - - - - - The secret cookie that is used to identify the session - - - - - Whether the session was successfully closed - - - - - This method is used to close the session identified by the supplied cookie. - - The session can only be closed by the same process that opened the session. - - - - - - - - - an array of Seat IDs - - - - - This gets a list of all the Seats - that are currently present on the system. - Each Seat ID is an D-Bus object path for the object that implements the - Seat interface. - - org.freedesktop.ConsoleKit.Seat - - - - - - - an array of Session IDs - - - - - This gets a list of all the Sessions - that are currently present on the system. - Each Session ID is an D-Bus object path for the object that implements the - Session interface. - - org.freedesktop.ConsoleKit.Session - - - - - - - - The secret cookie that is used to identify the session - - - - - The object identifier for the current session - - - - - Returns the session ID that is associated with the specified cookie. - - - - - - - - - The POSIX process ID - - - - - The object identifier for the current session - - - - - Attempts to determine the session ID for the specified - POSIX process ID (pid). - - - - - - - - - The object identifier for the current session - - - - - Attempts to determine the session ID that the caller belongs to. - - See this example of using dbus-send: - - dbus-send --system --dest=org.freedesktop.ConsoleKit \ - --type=method_call --print-reply --reply-timeout=2000 \ - /org/freedesktop/ConsoleKit/Manager \ - org.freedesktop.ConsoleKit.Manager.GetCurrentSession - - - - - - - - - POSIX User identification - - - - - an array of Session IDs - - - - - This gets a list of all the Sessions - that are currently open for the specified user. - Each Session ID is an D-Bus object path for the object that implements the - Session interface. - - - - - - - - User identification - - - - - an array of Session IDs - - - - - This gets a list of all the Sessions - that are currently open for the specified user. - Each Session ID is an D-Bus object path for the object that implements the - Session interface. - - - - - - - - - The value of the system-idle-hint - - - - - Returns TRUE if the idle-hint - property of every open session is TRUE or if there are no open sessions. - - - - - - - - An ISO 8601 format date-type string - - - - - Returns an ISO 8601 date-time string that corresponds to - the time of the last change of the system-idle-hint. - - - - - - - - - The Seat ID for the added seat - - - - - Emitted when a Seat has been added to the system. - - - - - - - - The Seat ID for the removed seat - - - - - Emitted when a Seat has been removed from the system. - - - - - - - - The value of the system-idle-hint - - - - - Emitted when the value of the system-idle-hint has changed. - - - - - - diff --git a/src/org.freedesktop.ConsoleKit.Seat.xml b/src/org.freedesktop.ConsoleKit.Seat.xml deleted file mode 100644 index 58c2ce7..0000000 --- a/src/org.freedesktop.ConsoleKit.Seat.xml +++ /dev/null @@ -1,164 +0,0 @@ - - - - - - - A seat is a collection of sessions and a set of hardware (usually at -least a keyboard and mouse). Only one session may be active on a -seat at a time. - - - - - - - Seat ID - - - - - Returns the ID for Seat. - - - - - - - - an array of Session IDs - - - - - This gets a list of all the Sessions - that are currently attached to this seat. - Each Session ID is an D-Bus object path for the object that implements the - Session interface. - - - - - - - - an array of devices - - - - - This gets a list of all the devices - that are currently associated with this seat. - Each device is an D-Bus structure that represents - the device type and the device id. - - - - - - - - - Session ID - - - - - Gets the Session ID that is currently active on this Seat. - Returns NULL if there is no active session. - - - - - - - - TRUE if seat supports session activation - - - - Used to determine whether the seat supports session activation. - - - - - - - - - Session ID - - - - - Attempt to activate the specified session. In most - cases, if successful, this will cause the session to - become visible and take control of the hardware that is - associated with this seat. - - Activate() - - - - - - - Session ID - - - - - Emitted when the active session has changed. - - - - - - - Session ID - - - - - Emitted when a session has been added to the seat. - - - - - - - Session ID - - - - - Emitted when a session has been removed from the seat. - - - - - - - Device structure - - - - - Emitted when a device has been associated with the seat. - - - - - - - Device structure - - - - - Emitted when a device has been dissociated from the seat. - - - - - diff --git a/src/org.freedesktop.ConsoleKit.Session.xml b/src/org.freedesktop.ConsoleKit.Session.xml deleted file mode 100644 index b6e1cdb..0000000 --- a/src/org.freedesktop.ConsoleKit.Session.xml +++ /dev/null @@ -1,435 +0,0 @@ - - - - - - - Session objects represent and store information - related to a user session. - - The properties associated with the Session - specifically refer to the properties of the "session leader". - - - - - - - Session ID - - - - Returns the ID for Session. - - - - - - - Seat ID - - - - Returns the ID for the Seat the Session is - attached to. - - org.freedesktop.ConsoleKit.Seat - - - - - - Session type - - - - - Returns the type of the session. - Warning: we haven't yet defined the allowed values for this property. - It is probably best to avoid this until we do. - - - session-type - - - - - - User ID - - - - Returns the user that the session belongs to. - - - user - - - - - - POSIX User ID - - - - Returns the POSIX user ID that the session belongs to. - - unix-user - - - - - - The value of the X11 display - - - - Returns the value of the X11 DISPLAY for this session - if one is present. - - x11-display - - - - - - The value of the X11 display device - - - - Returns the value of the display device (aka TTY) that the - X11 display for the session is connected to. If there is no x11-display set then this value - is undefined. - - x11-display-device - - - - - - The value of the display device - - - - Returns the value of the display device (aka TTY) that the - session is connected to. - - display-device - - - - - - The remote host name - - - - Returns the value of the remote host name for the session. - - - remote-host-name - - - - - - The value of the native system login session ID - - - - Returns the value of the login session ID that the - underlying system uses to enforce session boundaries. If there is no login session ID - set then this value is an empty string. - - - - - - - TRUE if the session is active, otherwise FALSE - - - - Returns whether the session is active on the Seat that - it is attached to. - If the session is not attached to a seat this value is undefined. - - - active - - - - - - TRUE if the session is local, otherwise FALSE - - - - Returns whether the session is local - FIXME: we need to come up with a concrete definition for this value. - It was originally used as a way to identify XDMCP sessions that originate - from a remote system. - - - is-local - - - - - - An ISO 8601 format date-type string - - - - - Returns an ISO 8601 date-time string that corresponds to - the time that the session was opened. - - - - - - - - - - Attempt to activate the this session. In most - cases, if successful, this will cause the session to - become visible and become active on the seat that it - is attached to. - - Seat.ActivateSession() - - - - - - - This will cause a Lock - signal to be emitted for this session. - - - This method is restricted to privileged users by D-Bus policy. - Lock signal - - - - - - - This will cause an Unlock - signal to be emitted for this session. - - This can be used by login managers to unlock a session before it is - re-activated during fast-user-switching. - - - This method is restricted to privileged users by D-Bus policy. - Unlock signal - - - - - - - The value of the idle-hint - - - - - Gets the value of the idle-hint - property. - - - idle-hint - - - - - - An ISO 8601 format date-type string - - - - - Returns an ISO 8601 date-time string that corresponds to - the time of the last change of the idle-hint. - - - - - - - - - boolean value to set the idle-hint to - - - - - This may be used by the session to indicate that - it is idle. - - Use of this method is restricted to the user - that owns the session. - - - - - - - - TRUE if the session is active, otherwise FALSE - - - - - Emitted when the active property has changed. - - - - - - - the new value of idle-hint - - - - - Emitted when the idle-hint property has changed. - - - - - - - Emitted in response to a call to the Lock() method. - It is intended that the screensaver for the session should lock the screen in response to this signal. - - - - - - - Emitted in response to a call to the Unlock() method. - It is intended that the screensaver for the session should unlock the screen in response to this signal. - - - - - - - - The user assigned to the session. - - - - - - - The user assigned to the session. - - - - - - - - The type of the session. - Warning: we haven't yet defined the allowed values for this property. - It is probably best to avoid this until we do. - - - - - - - - The remote host name for the session. - - This will be set in situations where the session is - opened and controlled from a remote system. - - For example, this value will be set when the - session is created from an SSH or XDMCP connection. - - - - - - - - The display device (aka TTY) that the - session is connected to. - - - - - - - - Value of the X11 DISPLAY for this session - if one is present. - - - - - - - - - The display device (aka TTY) that the X11 display for the - session is connected to. If there is no x11-display set then - this value is undefined. - - - - - - - - - Whether the session is active on the Seat that - it is attached to. - If the session is not attached to a seat this value is undefined. - - - - - - - - - Whether the session is local - FIXME: we need to come up with a concrete definition for this value. - It was originally used as a way to identify XDMCP sessions that originate - from a remote system. - - - - - - - - - This is a hint used to indicate that the session may be idle. - - - For sessions with a x11-display set (ie. graphical - sessions), it is up to each session to delegate the - responsibility for updating this value. Typically, the - screensaver will set this. - - However, for non-graphical sessions with a display-device set - the Session object itself will periodically update this value based - on the activity detected on the display-device itself. - - - This should not be considered authoritative. - - - - - - - diff --git a/src/service.c b/src/service.c new file mode 100644 index 0000000..1345681 --- /dev/null +++ b/src/service.c @@ -0,0 +1,1192 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include + +#include +#include + +#include "backend.h" +#include "service.h" + +/* FIXME: remove -test */ +#define BUS_NAME "com.canonical.indicator.session-test" +#define BUS_PATH "/com/canonical/indicator/session" + +#define ICON_DEFAULT "system-devices-panel" +#define ICON_INFO "system-devices-panel-information" +#define ICON_ALERT "system-devices-panel-alert" + +G_DEFINE_TYPE (IndicatorSessionService, + indicator_session_service, + G_TYPE_OBJECT) + +enum +{ + PROP_0, + PROP_REPLACE, + PROP_MAX_USERS, + PROP_LAST +}; + +static GParamSpec * properties[PROP_LAST]; + +enum +{ + SECTION_HEADER = (1<<0), + SECTION_ADMIN = (1<<1), + SECTION_SETTINGS = (1<<2), + SECTION_SWITCH = (1<<3), + SECTION_SESSION = (1<<4) +}; + +enum +{ + FORM_DESKTOP, + FORM_GREETER, + N_FORMS +}; + +static const char * const menu_names[N_FORMS] = +{ + "desktop", + "desktop_greeter" +}; + +struct FormMenuInfo +{ + /* the root level -- the header is the only child of this */ + GMenu * menu; + + /* parent of the sections. This is the header's submenu */ + GMenu * submenu; + + guint export_id; +}; + +struct _IndicatorSessionServicePrivate +{ + guint own_id; + guint max_users; + IndicatorSessionUsers * backend_users; + IndicatorSessionGuest * backend_guest; + IndicatorSessionActions * backend_actions; + GSettings * indicator_settings; + GSettings * keybinding_settings; + GSimpleActionGroup * actions; + guint actions_export_id; + struct FormMenuInfo menus[N_FORMS]; + GSimpleAction * header_action; + GSimpleAction * user_switcher_action; + GSimpleAction * guest_switcher_action; + GHashTable * users; + guint rebuild_id; + int rebuild_flags; + GDBusConnection * conn; + + gboolean replace; +}; + +typedef IndicatorSessionServicePrivate priv_t; + +static const char * get_current_real_name (IndicatorSessionService * self); + +/*** +**** +***/ + +static void rebuild_now (IndicatorSessionService * self, int section); +static void rebuild_soon (IndicatorSessionService * self, int section); + +static inline void +rebuild_header_soon (IndicatorSessionService * self) +{ + rebuild_soon (self, SECTION_HEADER); +} +static inline void +rebuild_switch_section_soon (IndicatorSessionService * self) +{ + rebuild_soon (self, SECTION_SWITCH); +} +static inline void +rebuild_session_section_soon (IndicatorSessionService * self) +{ + rebuild_soon (self, SECTION_SESSION); +} +static inline void +rebuild_settings_section_soon (IndicatorSessionService * self) +{ + rebuild_soon (self, SECTION_SETTINGS); +} + +/*** +**** +***/ + +static void +update_header_action (IndicatorSessionService * self) +{ + gchar * a11y; + gboolean need_attn; + gboolean show_name; + GVariant * variant; + const gchar * real_name; + const gchar * label; + const gchar * iconstr; + const priv_t * const p = self->priv; + + g_return_if_fail (p->header_action != NULL); + + if (indicator_session_actions_has_online_account_error (p->backend_actions)) + { + need_attn = TRUE; + iconstr = ICON_ALERT; + } + else + { + need_attn = FALSE; + iconstr = ICON_DEFAULT; + } + + show_name = g_settings_get_boolean (p->indicator_settings, + "show-real-name-on-panel"); + + real_name = get_current_real_name (self); + label = show_name && real_name ? real_name : ""; + + if (*label && need_attn) + { + /* Translators: the name of the menu ("System"), then the user's name, + then a hint that something in this menu requires user attention */ + a11y = g_strdup_printf (_("System, %s (Attention Required)"), real_name); + } + else if (*label) + { + /* Translators: the name of the menu ("System"), then the user's name */ + a11y = g_strdup_printf (_("System, %s"), label); + } + else if (need_attn) + { + a11y = g_strdup (_("System (Attention Required)")); + } + else + { + a11y = g_strdup (_("System")); + } + + variant = g_variant_new ("(sssb)", label, iconstr, a11y, TRUE); + g_simple_action_set_state (p->header_action, variant); + g_free (a11y); +} + +/*** +**** USERS +***/ + +static GMenuModel * create_switch_section (IndicatorSessionService * self); + +static void +add_user (IndicatorSessionService * self, const gchar * key) +{ + IndicatorSessionUser * u; + + /* update our user table */ + u = indicator_session_users_get_user (self->priv->backend_users, key); + g_hash_table_insert (self->priv->users, g_strdup(key), u); + + /* enqueue rebuilds for the affected sections */ + rebuild_switch_section_soon (self); + if (u->is_current_user) + rebuild_header_soon (self); +} + +static void +on_user_added (IndicatorSessionUsers * backend_users G_GNUC_UNUSED, + const char * key, + gpointer gself) +{ + add_user (INDICATOR_SESSION_SERVICE(gself), key); +} + +static void +on_user_changed (IndicatorSessionUsers * backend_users G_GNUC_UNUSED, + const char * key, + gpointer gself) +{ + add_user (INDICATOR_SESSION_SERVICE(gself), key); +} + +static void +on_user_removed (IndicatorSessionUsers * backend_users G_GNUC_UNUSED, + const char * key, + gpointer gself) +{ + IndicatorSessionService * self = INDICATOR_SESSION_SERVICE (gself); + g_return_if_fail (self != NULL); + + /* update our user table */ + g_hash_table_remove (self->priv->users, key); + + /* enqueue rebuilds for the affected sections */ + rebuild_switch_section_soon (self); +} + +static const char * +get_current_real_name (IndicatorSessionService * self) +{ + GHashTableIter iter; + gpointer key, value; + + /* is it the guest? */ + if (indicator_session_guest_is_active (self->priv->backend_guest)) + return _("Guest"); + + /* is it a user? */ + g_hash_table_iter_init (&iter, self->priv->users); + while (g_hash_table_iter_next (&iter, &key, &value)) + { + IndicatorSessionUser * user = value; + if (user->is_current_user) + return user->real_name; + } + + return ""; +} + +/*** +**** +***/ + +static GMenuModel * +create_admin_section (void) +{ + GMenu * menu; + GMenuItem * item; + + menu = g_menu_new (); + + item = g_menu_item_new (_("About This Computer"), "indicator.about"); + g_menu_append_item (menu, item); + g_object_unref (G_OBJECT(item)); + + item = g_menu_item_new (_("Ubuntu Help"), "indicator.help"); + g_menu_append_item (menu, item); + g_object_unref (G_OBJECT(item)); + + return G_MENU_MODEL (menu); +} + +static GMenuModel * +create_settings_section (IndicatorSessionService * self) +{ + GMenu * menu; + GMenuItem * item; + priv_t * p = self->priv; + + menu = g_menu_new (); + + item = g_menu_item_new (_("System Settings\342\200\246"), "indicator.settings"); + g_menu_append_item (menu, item); + g_object_unref (G_OBJECT(item)); + + if (indicator_session_actions_has_online_account_error (p->backend_actions)) + { + item = g_menu_item_new (_("Online Accounts\342\200\246"), "indicator.online-accounts"); + g_menu_append_item (menu, item); + g_object_unref (G_OBJECT(item)); + } + + return G_MENU_MODEL (menu); +} + +/** + * The switch-to-guest action's state is a dictionary with these entries: + * - "is-active" (boolean) + * - "is-logged-in" (boolean) + */ +static GVariant * +create_guest_switcher_state (IndicatorSessionService * self) +{ + GVariant * val; + GVariantBuilder * b; + IndicatorSessionGuest * const g = self->priv->backend_guest; + + b = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + val = g_variant_new_boolean (indicator_session_guest_is_active (g)); + g_variant_builder_add (b, "{sv}", "is-active", val); + val = g_variant_new_boolean (indicator_session_guest_is_logged_in (g)); + g_variant_builder_add (b, "{sv}", "is-logged-in", val); + return g_variant_builder_end (b); +} + +/** + * The switch-to-user action's state is a dictionary with these entries: + * - "active-user" (username string) + * - "logged-in-users" (array of username strings) + */ +static GVariant * +create_user_switcher_state (IndicatorSessionService * self) +{ + GVariantBuilder * a; + GVariantBuilder * b; + GVariant * val; + GHashTableIter ht_iter; + gpointer ht_key, ht_value; + const char * current_user; + + current_user = ""; + a = g_variant_builder_new (G_VARIANT_TYPE("as")); + g_hash_table_iter_init (&ht_iter, self->priv->users); + while (g_hash_table_iter_next (&ht_iter, &ht_key, &ht_value)) + { + const IndicatorSessionUser * u = ht_value; + + if (u->is_current_user) + current_user = u->user_name; + + if (u->is_logged_in) + g_variant_builder_add (a, "s", u->user_name); + } + + b = g_variant_builder_new (G_VARIANT_TYPE("a{sv}")); + val = g_variant_new_string (current_user); + g_variant_builder_add (b, "{sv}", "active-user", val); + val = g_variant_builder_end (a); + g_variant_builder_add (b, "{sv}", "logged-in-users", val); + return g_variant_builder_end (b); +} + +static void +update_switch_actions (IndicatorSessionService * self) +{ + g_simple_action_set_state (self->priv->guest_switcher_action, + create_guest_switcher_state (self)); + + g_simple_action_set_state (self->priv->user_switcher_action, + create_user_switcher_state (self)); +} + +static gboolean +use_ellipsis (IndicatorSessionService * self) +{ + /* does the backend support confirmation prompts? */ + if (!indicator_session_actions_can_prompt (self->priv->backend_actions)) + return FALSE; + + /* has the user disabled prompts? */ + if (g_settings_get_boolean (self->priv->indicator_settings, + "suppress-logout-restart-shutdown")) + return FALSE; + + return TRUE; +} + +/* lower index == more useful. + When there are too many users for the menu, + we use this to decide which to cull. */ +static int +compare_users_by_usefulness (gconstpointer ga, gconstpointer gb) +{ + const IndicatorSessionUser * a = *(const IndicatorSessionUser**)ga; + const IndicatorSessionUser * b = *(const IndicatorSessionUser**)gb; + + if (a->is_current_user != b->is_current_user) + return a->is_current_user ? -1 : 1; + + if (a->is_logged_in != b->is_logged_in) + return a->is_logged_in ? -1 : 1; + + if (a->login_frequency != b->login_frequency) + return a->login_frequency > b->login_frequency ? -1 : 1; + + return 0; +} + +/* sorting them for display in the menu */ +static int +compare_users_by_label (gconstpointer ga, gconstpointer gb) +{ + int i; + const IndicatorSessionUser * a = *(const IndicatorSessionUser**)ga; + const IndicatorSessionUser * b = *(const IndicatorSessionUser**)gb; + + if ((i = g_strcmp0 (a->real_name, b->real_name))) + return i; + + return g_strcmp0 (a->user_name, b->user_name); +} + +static GMenuModel * +create_switch_section (IndicatorSessionService * self) +{ + gchar * str; + GMenu * menu; + GMenuItem * item; + guint i; + gpointer guser; + GHashTableIter iter; + GPtrArray * users; + const priv_t * const p = self->priv; + const gboolean ellipsis = use_ellipsis (self); + + menu = g_menu_new (); + + /* lockswitch */ + if (indicator_session_users_is_live_session (p->backend_users)) + { + const char * action = "indicator.switch-to-screensaver"; + item = g_menu_item_new (_("Start Screen Saver"), action); + } + else if (indicator_session_guest_is_active (p->backend_guest)) + { + const char * action = "indicator.switch-to-greeter"; + item = g_menu_item_new (ellipsis ? _("Switch Account\342\200\246") + : _("Switch Account"), action); + } + else if (g_hash_table_size (p->users) == 1) + { + const char * action = "indicator.switch-to-greeter"; + item = g_menu_item_new (ellipsis ? _("Lock\342\200\246") + : _("Lock"), action); + } + else + { + const char * action = "indicator.switch-to-greeter"; + item = g_menu_item_new (ellipsis ? _("Lock/Switch Account\342\200\246") + : _("Lock/Switch Account"), action); + } + str = g_settings_get_string (p->keybinding_settings, "screensaver"); + g_menu_item_set_attribute (item, "accel", "s", str); + g_free (str); + g_menu_append_item (menu, item); + g_object_unref (G_OBJECT(item)); + + if (indicator_session_guest_is_allowed (p->backend_guest)) + { + item = g_menu_item_new (_("Guest Session"), "indicator.switch-to-guest"); + g_menu_append_item (menu, item); + g_object_unref (G_OBJECT(item)); + } + + /* build an array of all the users we know of */ + users = g_ptr_array_new (); + g_hash_table_iter_init (&iter, p->users); + while (g_hash_table_iter_next (&iter, NULL, &guser)) + g_ptr_array_add (users, guser); + + /* if there are too many users, cull out the less interesting ones */ + if (users->len > p->max_users) + { + g_ptr_array_sort (users, compare_users_by_usefulness); + g_ptr_array_set_size (users, p->max_users); + } + + /* sort the users by name */ + g_ptr_array_sort (users, compare_users_by_label); + + /* add the users */ + for (i=0; ilen; ++i) + { + const IndicatorSessionUser * u = g_ptr_array_index (users, i); + item = g_menu_item_new (u->real_name, NULL); + g_menu_item_set_action_and_target (item, "indicator.switch-to-user", "s", u->user_name); + g_menu_append_item (menu, item); + g_object_unref (G_OBJECT(item)); + } + + /* cleanup */ + g_ptr_array_free (users, TRUE); + return G_MENU_MODEL (menu); +} + +static GMenuModel * +create_session_section (IndicatorSessionService * self) +{ + GMenu * menu; + GMenuItem * item; + const priv_t * const p = self->priv; + GSettings * const s = p->indicator_settings; + const gboolean ellipsis = use_ellipsis (self); + + menu = g_menu_new (); + + if (indicator_session_actions_can_logout (p->backend_actions) && !g_settings_get_boolean (s, "suppress-logout-menuitem")) + { + item = g_menu_item_new (ellipsis ? _("Log Out\342\200\246") + : _("Log Out"), "indicator.logout"); + g_menu_append_item (menu, item); + g_object_unref (G_OBJECT(item)); + } + + if (indicator_session_actions_can_suspend (p->backend_actions)) + { + item = g_menu_item_new (_("Suspend"), "indicator.suspend"); + g_menu_append_item (menu, item); + g_object_unref (G_OBJECT(item)); + } + + if (indicator_session_actions_can_hibernate (p->backend_actions)) + { + item = g_menu_item_new (_("Hibernate"), "indicator.hibernate"); + g_menu_append_item (menu, item); + g_object_unref (G_OBJECT(item)); + } + + if (!g_settings_get_boolean (s, "suppress-restart-menuitem")) + { + item = g_menu_item_new (ellipsis ? _("Restart\342\200\246") + : _("Restart"), "indicator.restart"); + g_menu_append_item (menu, item); + g_object_unref (G_OBJECT(item)); + } + + if (!g_settings_get_boolean (s, "suppress-shutdown-menuitem")) + { + item = g_menu_item_new (ellipsis ? _("Shutdown\342\200\246") + : _("Shutdown"), "indicator.shutdown"); + g_menu_append_item (menu, item); + g_object_unref (G_OBJECT(item)); + } + + return G_MENU_MODEL (menu); +} + +static void +create_menu (IndicatorSessionService * self, int form_factor) +{ + GMenu * menu; + GMenu * submenu; + GMenuItem * header; + GMenuModel * sections[16]; + int i; + int n = 0; + + g_assert (0<=form_factor && form_factorpriv->menus[form_factor].menu == NULL); + + if (form_factor == FORM_DESKTOP) + { + sections[n++] = create_admin_section (); + sections[n++] = create_settings_section (self); + sections[n++] = create_switch_section (self); + sections[n++] = create_session_section (self); + } + else if (form_factor == FORM_GREETER) + { + sections[n++] = create_session_section (self); + } + + /* add sections to the submenu */ + submenu = g_menu_new (); + for (i=0; ipriv->menus[form_factor].menu = menu; + self->priv->menus[form_factor].submenu = submenu; +} + +/*** +**** GActions +***/ + +static IndicatorSessionActions * +get_backend_actions (gpointer gself) +{ + return INDICATOR_SESSION_SERVICE(gself)->priv->backend_actions; +} + +static void +on_about_activated (GSimpleAction * a G_GNUC_UNUSED, + GVariant * param G_GNUC_UNUSED, + gpointer gself) +{ + indicator_session_actions_about (get_backend_actions(gself)); +} + +static void +on_help_activated (GSimpleAction * a G_GNUC_UNUSED, + GVariant * param G_GNUC_UNUSED, + gpointer gself) +{ + indicator_session_actions_help (get_backend_actions(gself)); +} + +static void +on_settings_activated (GSimpleAction * a G_GNUC_UNUSED, + GVariant * param G_GNUC_UNUSED, + gpointer gself) +{ + indicator_session_actions_settings (get_backend_actions(gself)); +} + +static void +on_logout_activated (GSimpleAction * a G_GNUC_UNUSED, + GVariant * param G_GNUC_UNUSED, + gpointer gself) +{ + indicator_session_actions_logout (get_backend_actions(gself)); +} + +static void +on_suspend_activated (GSimpleAction * a G_GNUC_UNUSED, + GVariant * param G_GNUC_UNUSED, + gpointer gself) +{ + indicator_session_actions_suspend (get_backend_actions(gself)); +} + +static void +on_hibernate_activated (GSimpleAction * a G_GNUC_UNUSED, + GVariant * param G_GNUC_UNUSED, + gpointer gself) +{ + indicator_session_actions_hibernate (get_backend_actions(gself)); +} + +static void +on_restart_activated (GSimpleAction * action G_GNUC_UNUSED, + GVariant * param G_GNUC_UNUSED, + gpointer gself) +{ + indicator_session_actions_restart (get_backend_actions(gself)); +} + +static void +on_shutdown_activated (GSimpleAction * a G_GNUC_UNUSED, + GVariant * param G_GNUC_UNUSED, + gpointer gself) +{ + indicator_session_actions_shutdown (get_backend_actions(gself)); +} + +static void +on_guest_activated (GSimpleAction * a G_GNUC_UNUSED, + GVariant * param G_GNUC_UNUSED, + gpointer gself) +{ + indicator_session_actions_switch_to_guest (get_backend_actions(gself)); +} + +static void +on_screensaver_activated (GSimpleAction * a G_GNUC_UNUSED, + GVariant * param G_GNUC_UNUSED, + gpointer gself) +{ + indicator_session_actions_switch_to_screensaver (get_backend_actions(gself)); +} + +static void +on_greeter_activated (GSimpleAction * a G_GNUC_UNUSED, + GVariant * param G_GNUC_UNUSED, + gpointer gself) +{ + indicator_session_actions_switch_to_greeter (get_backend_actions(gself)); +} + +static void +on_user_activated (GSimpleAction * a G_GNUC_UNUSED, + GVariant * param, + gpointer gself) +{ + const char * username = g_variant_get_string (param, NULL); + indicator_session_actions_switch_to_username (get_backend_actions(gself), + username); +} + +static void +init_gactions (IndicatorSessionService * self) +{ + GVariant * v; + GSimpleAction * a; + priv_t * p = self->priv; + + GActionEntry entries[] = { + { "about", on_about_activated }, + { "help", on_help_activated }, + { "settings", on_settings_activated }, + { "logout", on_logout_activated }, + { "suspend", on_suspend_activated }, + { "hibernate", on_hibernate_activated }, + { "restart", on_restart_activated }, + { "shutdown", on_shutdown_activated }, + { "switch-to-screensaver", on_screensaver_activated }, + { "switch-to-greeter", on_greeter_activated } + }; + + p->actions = g_simple_action_group_new (); + + g_action_map_add_action_entries (G_ACTION_MAP(p->actions), + entries, + G_N_ELEMENTS(entries), + self); + + /* add switch-to-guest action */ + v = create_guest_switcher_state (self); + a = g_simple_action_new_stateful ("switch-to-guest", NULL, v); + g_signal_connect (a, "activate", G_CALLBACK(on_guest_activated), self); + g_simple_action_group_insert (p->actions, G_ACTION(a)); + p->guest_switcher_action = a; + + /* add switch-to-user action... parameter is the uesrname */ + v = create_user_switcher_state (self); + a = g_simple_action_new_stateful ("switch-to-user", G_VARIANT_TYPE_STRING, v); + g_signal_connect (a, "activate", G_CALLBACK(on_user_activated), self); + g_simple_action_group_insert (p->actions, G_ACTION(a)); + p->user_switcher_action = a; + + /* add the header action */ + v = g_variant_new ("(sssb)", "label", ICON_DEFAULT, "a11y", TRUE); + a = g_simple_action_new_stateful ("_header", NULL, v); + g_simple_action_group_insert (p->actions, G_ACTION(a)); + p->header_action = a; + + rebuild_now (self, SECTION_HEADER); +} + +/*** +**** +***/ + +static void +replace_section (GMenu * parent, int pos, GMenuModel * new_section) +{ + g_menu_remove (parent, pos); + g_menu_insert_section (parent, pos, NULL, new_section); + g_object_unref (G_OBJECT(new_section)); +} + +static void +rebuild_now (IndicatorSessionService * self, int sections) +{ + priv_t * p = self->priv; + struct FormMenuInfo * desktop = &p->menus[FORM_DESKTOP]; + struct FormMenuInfo * greeter = &p->menus[FORM_GREETER]; + + if (sections & SECTION_HEADER) + { + update_header_action (self); + } + + if (sections & SECTION_ADMIN) + { + replace_section (desktop->submenu, 0, create_admin_section()); + } + + if (sections & SECTION_SETTINGS) + { + replace_section (desktop->submenu, 1, create_settings_section(self)); + } + + if (sections & SECTION_SWITCH) + { + replace_section (desktop->submenu, 2, create_switch_section(self)); + update_switch_actions (self); + } + + if (sections & SECTION_SESSION) + { + replace_section (desktop->submenu, 3, create_session_section(self)); + replace_section (greeter->submenu, 0, create_session_section(self)); + } +} + +static int +rebuild_timeout_func (IndicatorSessionService * self) +{ + priv_t * p = self->priv; + rebuild_now (self, p->rebuild_flags); + p->rebuild_flags = 0; + p->rebuild_id = 0; + return G_SOURCE_REMOVE; +} + +static void +rebuild_soon (IndicatorSessionService * self, int section) +{ + priv_t * p = self->priv; + + p->rebuild_flags |= section; + + if (p->rebuild_id == 0) + { + static const int REBUILD_INTERVAL_MSEC = 500; + + p->rebuild_id = g_timeout_add (REBUILD_INTERVAL_MSEC, + (GSourceFunc)rebuild_timeout_func, + self); + } +} + +/*** +**** GDBus +***/ + +static void +on_bus_acquired (GDBusConnection * connection, + const gchar * name, + gpointer gself) +{ + int i; + guint id; + GError * err = NULL; + IndicatorSessionService * self = INDICATOR_SESSION_SERVICE(gself); + priv_t * p = self->priv; + + g_debug ("bus acquired: %s", name); + + p->conn = g_object_ref (G_OBJECT (connection)); + + /* export the actions */ + if ((id = g_dbus_connection_export_action_group (connection, + BUS_PATH, + G_ACTION_GROUP (p->actions), + &err))) + { + p->actions_export_id = id; + } + else + { + g_warning ("cannot export action group: %s", err->message); + g_clear_error (&err); + } + + /* export the menus */ + for (i=0; imenus[i]; + + if (menu->menu == NULL) + create_menu (self, i); + + if ((id = g_dbus_connection_export_menu_model (connection, + path, + G_MENU_MODEL (menu->menu), + &err))) + { + menu->export_id = id; + } + else + { + g_warning ("cannot export %s menu: %s", menu_names[i], err->message); + g_clear_error (&err); + } + + g_free (path); + } +} + +static void +unexport (IndicatorSessionService * self) +{ + int i; + priv_t * p = self->priv; + + /* unexport the menus */ + for (i=0; ipriv->menus[i].export_id; + + if (*id) + { + g_dbus_connection_unexport_menu_model (p->conn, *id); + *id = 0; + } + } + + /* unexport the actions */ + if (p->actions_export_id) + { + g_dbus_connection_unexport_action_group (p->conn, p->actions_export_id); + p->actions_export_id = 0; + } +} + +static void +on_name_lost (GDBusConnection * connection G_GNUC_UNUSED, + const gchar * name, + gpointer gself) +{ + g_debug ("%s %s name lost %s", G_STRLOC, G_STRFUNC, name); + + unexport (INDICATOR_SESSION_SERVICE (gself)); +} + +/*** +**** +***/ + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_service_init (IndicatorSessionService * self) +{ + int i; + GStrv keys; + priv_t * p; + gpointer gp; + + /* init our priv pointer */ + p = G_TYPE_INSTANCE_GET_PRIVATE (self, + INDICATOR_TYPE_SESSION_SERVICE, + IndicatorSessionServicePrivate); + p->indicator_settings = g_settings_new ("com.canonical.indicator.session"); + p->keybinding_settings = g_settings_new ("org.gnome.settings-daemon.plugins.media-keys"); + self->priv = p; + + /* init the backend objects */ + backend_get (g_cancellable_new (), &p->backend_actions, + &p->backend_users, + &p->backend_guest); + + /* init our key-to-User table */ + p->users = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + (GDestroyNotify)indicator_session_user_free); + keys = indicator_session_users_get_keys (p->backend_users); + for (i=0; keys && keys[i]; ++i) + add_user (self, keys[i]); + g_strfreev (keys); + + init_gactions (self); + + /* watch for changes in backend_users */ + gp = p->backend_users; + g_signal_connect (gp, INDICATOR_SESSION_USERS_SIGNAL_USER_ADDED, + G_CALLBACK(on_user_added), self); + g_signal_connect (gp, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, + G_CALLBACK(on_user_changed), self); + g_signal_connect (gp, INDICATOR_SESSION_USERS_SIGNAL_USER_REMOVED, + G_CALLBACK(on_user_removed), self); + g_signal_connect_swapped (gp, "notify::is-live-session", + G_CALLBACK(rebuild_switch_section_soon), self); + + /* watch for changes in backend_guest */ + gp = p->backend_guest; + g_signal_connect_swapped (gp, "notify::guest-is-active-session", + G_CALLBACK(rebuild_header_soon), self); + g_signal_connect_swapped (gp, "notify", + G_CALLBACK(rebuild_switch_section_soon), self); + + /* watch for updates in backend_actions */ + gp = p->backend_actions; + g_signal_connect_swapped (gp, "notify", + G_CALLBACK(rebuild_switch_section_soon), self); + g_signal_connect_swapped (gp, "notify", + G_CALLBACK(rebuild_session_section_soon), self); + g_signal_connect_swapped (gp, "notify::has-online-account-error", + G_CALLBACK(rebuild_header_soon), self); + g_signal_connect_swapped (gp, "notify::has-online-account-error", + G_CALLBACK(rebuild_settings_section_soon), self); + + /* watch for changes in the indicator's settings */ + gp = p->indicator_settings; + g_signal_connect_swapped (gp, "changed::suppress-logout-restart-shutdown", + G_CALLBACK(rebuild_switch_section_soon), self); + g_signal_connect_swapped (gp, "changed::suppress-logout-restart-shutdown", + G_CALLBACK(rebuild_session_section_soon), self); + g_signal_connect_swapped (gp, "changed::suppress-logout-menuitem", + G_CALLBACK(rebuild_session_section_soon), self); + g_signal_connect_swapped (gp, "changed::suppress-restart-menuitem", + G_CALLBACK(rebuild_session_section_soon), self); + g_signal_connect_swapped (gp, "changed::suppress-shutdown-menuitem", + G_CALLBACK(rebuild_session_section_soon), self); + g_signal_connect_swapped (gp, "changed::show-real-name-on-panel", + G_CALLBACK(rebuild_header_soon), self); + + /* watch for changes to the lock keybinding */ + gp = p->keybinding_settings; + g_signal_connect_swapped (gp, "changed::screensaver", + G_CALLBACK(rebuild_switch_section_soon), self); +} + +static void +my_constructed (GObject * o) +{ + GBusNameOwnerFlags owner_flags; + IndicatorSessionService * self = INDICATOR_SESSION_SERVICE(o); + + /* own the name in constructed() instead of init() so that + we'll know the value of the 'replace' property */ + owner_flags = G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT; + if (self->priv->replace) + owner_flags |= G_BUS_NAME_OWNER_FLAGS_REPLACE; + + self->priv->own_id = g_bus_own_name (G_BUS_TYPE_SESSION, + BUS_NAME, + owner_flags, + on_bus_acquired, + NULL, + on_name_lost, + self, + NULL); +} + +/*** +**** GObject plumbing: properties +***/ + +static void +my_get_property (GObject * o, + guint property_id, + GValue * value, + GParamSpec * pspec) +{ + IndicatorSessionService * self = INDICATOR_SESSION_SERVICE (o); + + switch (property_id) + { + case PROP_REPLACE: + g_value_set_boolean (value, self->priv->replace); + break; + + case PROP_MAX_USERS: + g_value_set_uint (value, self->priv->max_users); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec); + } +} + +static void +my_set_property (GObject * o, + guint property_id, + const GValue * value G_GNUC_UNUSED, + GParamSpec * pspec) +{ + IndicatorSessionService * self = INDICATOR_SESSION_SERVICE (o); + + switch (property_id) + { + case PROP_REPLACE: + self->priv->replace = g_value_get_boolean (value); + break; + + case PROP_MAX_USERS: + self->priv->max_users = g_value_get_uint (value); + rebuild_switch_section_soon (self); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec); + } +} + +/*** +**** GObject plumbing: life cycle +***/ + +static void +my_dispose (GObject * o) +{ + int i; + IndicatorSessionService * self = INDICATOR_SESSION_SERVICE(o); + priv_t * p = self->priv; + + unexport (self); + + if (p->rebuild_id) + { + g_source_remove (p->rebuild_id); + p->rebuild_id = 0; + } + + if (p->own_id) + { + g_bus_unown_name (p->own_id); + p->own_id = 0; + } + + g_clear_pointer (&p->users, g_hash_table_destroy); + g_clear_object (&p->backend_users); + g_clear_object (&p->backend_guest); + g_clear_object (&p->backend_actions); + g_clear_object (&p->indicator_settings); + g_clear_object (&p->keybinding_settings); + g_clear_object (&p->actions); + + for (i=0; imenus[i].menu); + + g_clear_object (&p->header_action); + g_clear_object (&p->user_switcher_action); + g_clear_object (&p->guest_switcher_action); + g_clear_object (&p->conn); + + G_OBJECT_CLASS (indicator_session_service_parent_class)->dispose (o); +} + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_service_class_init (IndicatorSessionServiceClass * klass) +{ + GObjectClass * object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = my_dispose; + object_class->constructed = my_constructed; + object_class->get_property = my_get_property; + object_class->set_property = my_set_property; + + g_type_class_add_private (klass, sizeof (IndicatorSessionServicePrivate)); + + properties[PROP_0] = NULL; + + properties[PROP_REPLACE] = g_param_spec_boolean ("replace", + "Replace Service", + "Replace existing service", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + + properties[PROP_MAX_USERS] = g_param_spec_uint ("max-users", + "Max Users", + "Max visible users", + 0, INT_MAX, 12, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, PROP_LAST, properties); +} + +IndicatorSessionService * +indicator_session_service_new (gboolean replace) +{ + GObject * o = g_object_new (INDICATOR_TYPE_SESSION_SERVICE, + "replace", replace, + NULL); + + return INDICATOR_SESSION_SERVICE (o); +} diff --git a/src/service.h b/src/service.h new file mode 100644 index 0000000..2a78855 --- /dev/null +++ b/src/service.h @@ -0,0 +1,64 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#ifndef __INDICATOR_SESSION_SERVICE_H__ +#define __INDICATOR_SESSION_SERVICE_H__ + +#include +#include + +G_BEGIN_DECLS + +/* standard GObject macros */ +#define INDICATOR_TYPE_SESSION_SERVICE (indicator_session_service_get_type()) +#define INDICATOR_SESSION_SERVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_SESSION_SERVICE, IndicatorSessionService)) +#define INDICATOR_SESSION_SERVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_SESSION_SERVICE, IndicatorSessionServiceClass)) +#define INDICATOR_SESSION_SERVICE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), INDICATOR_TYPE_SESSION_SERVICE, IndicatorSessionServiceClass)) +#define INDICATOR_IS_SESSION_SERVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_SESSION_SERVICE)) + +typedef struct _IndicatorSessionService IndicatorSessionService; +typedef struct _IndicatorSessionServiceClass IndicatorSessionServiceClass; +typedef struct _IndicatorSessionServicePrivate IndicatorSessionServicePrivate; + +/** + * The Indicator Session Service. + */ +struct _IndicatorSessionService +{ + /*< private >*/ + GObject parent; + IndicatorSessionServicePrivate * priv; +}; + +struct _IndicatorSessionServiceClass +{ + GObjectClass parent_class; +}; + +/*** +**** +***/ + +GType indicator_session_service_get_type (void); + +IndicatorSessionService * indicator_session_service_new (gboolean replace); + +G_END_DECLS + +#endif /* __INDICATOR_SESSION_SERVICE_H__ */ diff --git a/src/session-dbus.c b/src/session-dbus.c deleted file mode 100644 index 4ece444..0000000 --- a/src/session-dbus.c +++ /dev/null @@ -1,282 +0,0 @@ -/* -The Dbus object on the bus for the indicator. - -Copyright 2010 Canonical Ltd. - -Authors: - Ted Gould - Conor Curran - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include "session-dbus.h" -#include "shared-names.h" - -static GVariant * get_users_real_name (SessionDbus * service); -static void bus_get_cb (GObject * object, GAsyncResult * res, gpointer user_data); -static void bus_method_call (GDBusConnection * connection, const gchar * sender, const gchar * path, const gchar * interface, const gchar * method, GVariant * params, GDBusMethodInvocation * invocation, gpointer user_data); - -#include "gen-session-dbus.xml.h" - -typedef struct _SessionDbusPrivate SessionDbusPrivate; -struct _SessionDbusPrivate { - gchar * name; - GDBusConnection * bus; - GCancellable * bus_cancel; - guint dbus_registration; -}; - -/* GDBus Stuff */ -static GDBusNodeInfo * node_info = NULL; -static GDBusInterfaceInfo * interface_info = NULL; -static GDBusInterfaceVTable interface_table = { - method_call: bus_method_call, - get_property: NULL, /* No properties */ - set_property: NULL /* No properties */ -}; - -#define SESSION_DBUS_GET_PRIVATE(o) \ -(G_TYPE_INSTANCE_GET_PRIVATE ((o), SESSION_DBUS_TYPE, SessionDbusPrivate)) - -static void session_dbus_class_init (SessionDbusClass *klass); -static void session_dbus_init (SessionDbus *self); -static void session_dbus_dispose (GObject *object); -static void session_dbus_finalize (GObject *object); - -G_DEFINE_TYPE (SessionDbus, session_dbus, G_TYPE_OBJECT); - -static void -session_dbus_class_init (SessionDbusClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (SessionDbusPrivate)); - - object_class->dispose = session_dbus_dispose; - object_class->finalize = session_dbus_finalize; - - /* Setting up the DBus interfaces */ - if (node_info == NULL) { - GError * error = NULL; - - node_info = g_dbus_node_info_new_for_xml(_session_dbus, &error); - if (error != NULL) { - g_error("Unable to parse Session Service Interface description: %s", error->message); - g_error_free(error); - } - } - - if (interface_info == NULL) { - interface_info = g_dbus_node_info_lookup_interface(node_info, INDICATOR_SESSION_SERVICE_DBUS_IFACE); - - if (interface_info == NULL) { - g_error("Unable to find interface '" INDICATOR_SESSION_SERVICE_DBUS_IFACE "'"); - } - } - - return; -} - -static void -session_dbus_init (SessionDbus *self) -{ - SessionDbusPrivate * priv = SESSION_DBUS_GET_PRIVATE(self); - - priv->name = NULL; - priv->bus = NULL; - priv->bus_cancel = NULL; - priv->dbus_registration = 0; - - priv->bus_cancel = g_cancellable_new(); - g_bus_get(G_BUS_TYPE_SESSION, - priv->bus_cancel, - bus_get_cb, - self); - - return; -} - -static void -bus_get_cb (GObject * object, GAsyncResult * res, gpointer user_data) -{ - GError * error = NULL; - GDBusConnection * connection = g_bus_get_finish(res, &error); - - if (error != NULL) { - g_error("OMG! Unable to get a connection to DBus: %s", error->message); - g_error_free(error); - return; - } - - SessionDbusPrivate * priv = SESSION_DBUS_GET_PRIVATE(user_data); - - g_warn_if_fail(priv->bus == NULL); - priv->bus = connection; - - if (priv->bus_cancel != NULL) { - g_object_unref(priv->bus_cancel); - priv->bus_cancel = NULL; - } - - /* Now register our object on our new connection */ - priv->dbus_registration = g_dbus_connection_register_object(priv->bus, - INDICATOR_SESSION_SERVICE_DBUS_OBJECT, - interface_info, - &interface_table, - user_data, - NULL, - &error); - - if (error != NULL) { - g_error("Unable to register the object to DBus: %s", error->message); - g_error_free(error); - return; - } - - return; -} - -/* A method has been called from our dbus inteface. Figure out what it - is and dispatch it. */ -static void -bus_method_call (GDBusConnection * connection, const gchar * sender, - const gchar * path, const gchar * interface, - const gchar * method, GVariant * params, - GDBusMethodInvocation * invocation, gpointer user_data) -{ - SessionDbus * service = SESSION_DBUS (user_data); - - GVariant * retval = NULL; - - if (g_strcmp0(method, "GetUserRealName") == 0) { - retval = get_users_real_name (service); - } - else { - g_warning("Calling method '%s' on the indicator service and it's unknown", method); - } - g_dbus_method_invocation_return_value(invocation, retval); - return; -} - -static void -session_dbus_dispose (GObject *object) -{ - SessionDbusPrivate * priv = SESSION_DBUS_GET_PRIVATE(object); - - if (priv->dbus_registration != 0) { - g_dbus_connection_unregister_object(priv->bus, priv->dbus_registration); - /* Don't care if it fails, there's nothing we can do */ - priv->dbus_registration = 0; - } - - if (priv->bus != NULL) { - g_object_unref(priv->bus); - priv->bus = NULL; - } - - if (priv->bus_cancel != NULL) { - g_cancellable_cancel(priv->bus_cancel); - g_object_unref(priv->bus_cancel); - priv->bus_cancel = NULL; - } - - G_OBJECT_CLASS (session_dbus_parent_class)->dispose (object); - return; -} - -static void -session_dbus_finalize (GObject *object) -{ - SessionDbusPrivate * priv = SESSION_DBUS_GET_PRIVATE(object); - - g_clear_pointer (&priv->name, g_free); - - G_OBJECT_CLASS (session_dbus_parent_class)->finalize (object); - return; -} - -static GVariant * -get_users_real_name (SessionDbus * service) -{ - SessionDbusPrivate * priv = SESSION_DBUS_GET_PRIVATE(service); - return g_variant_new ("(s)", priv->name ? priv->name : ""); -} - -SessionDbus * -session_dbus_new (void) -{ - return SESSION_DBUS(g_object_new(SESSION_DBUS_TYPE, NULL)); -} - -void -session_dbus_set_name (SessionDbus * session, const gchar * name) -{ -} - -void -session_dbus_set_users_real_name (SessionDbus * session, const gchar * name) -{ - SessionDbusPrivate * priv = SESSION_DBUS_GET_PRIVATE(session); - GError * error = NULL; - - g_free (priv->name); - priv->name = g_strdup(name); - - if (priv->bus != NULL) { - g_dbus_connection_emit_signal (priv->bus, - NULL, - INDICATOR_SESSION_SERVICE_DBUS_OBJECT, - INDICATOR_SESSION_SERVICE_DBUS_IFACE, - "UserRealNameUpdated", - g_variant_new ("(s)", priv->name, NULL), - &error); - - if (error != NULL) { - g_warning("Unable to send UserRealNameUpdated signal: %s", error->message); - g_error_free(error); - return; - } - } - return; -} - -void session_dbus_restart_required (SessionDbus* session) -{ - SessionDbusPrivate * priv = SESSION_DBUS_GET_PRIVATE(session); - GError * error = NULL; - - if (priv->bus != NULL) { - g_debug("About to send RebootRequired signal"); - - g_dbus_connection_emit_signal (priv->bus, - NULL, - INDICATOR_SESSION_SERVICE_DBUS_OBJECT, - INDICATOR_SESSION_SERVICE_DBUS_IFACE, - "RestartRequired", - NULL, - &error); - - if (error != NULL) { - g_warning("Unable to send reboot-required signal: %s", error->message); - g_error_free(error); - } - } - -} diff --git a/src/session-dbus.h b/src/session-dbus.h deleted file mode 100644 index 7520f06..0000000 --- a/src/session-dbus.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -The Dbus object on the bus for the indicator. - -Copyright 2010 Canonical Ltd. - -Authors: - Ted Gould - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . -*/ - -#ifndef __SESSION_DBUS_H__ -#define __SESSION_DBUS_H__ - -#include -#include - -G_BEGIN_DECLS - -#define SESSION_DBUS_TYPE (session_dbus_get_type ()) -#define SESSION_DBUS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SESSION_DBUS_TYPE, SessionDbus)) -#define SESSION_DBUS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SESSION_DBUS_TYPE, SessionDbusClass)) -#define IS_SESSION_DBUS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SESSION_DBUS_TYPE)) -#define IS_SESSION_DBUS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SESSION_DBUS_TYPE)) -#define SESSION_DBUS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SESSION_DBUS_TYPE, SessionDbusClass)) - -typedef struct _SessionDbus SessionDbus; -typedef struct _SessionDbusClass SessionDbusClass; - -struct _SessionDbusClass { - GObjectClass parent_class; - void (*icon_updated) (SessionDbus * session, gchar * icon, gpointer user_data); -}; - -struct _SessionDbus { - GObject parent; -}; - -GType session_dbus_get_type (void); -SessionDbus * session_dbus_new (void); -void session_dbus_set_name (SessionDbus * session, const gchar * name); -void session_dbus_set_users_real_name (SessionDbus * session, const gchar * name); -void session_dbus_restart_required (SessionDbus* session); -G_END_DECLS - -#endif diff --git a/src/session-dbus.xml b/src/session-dbus.xml deleted file mode 100644 index 96e9837..0000000 --- a/src/session-dbus.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/src/session-menu-mgr.c b/src/session-menu-mgr.c deleted file mode 100644 index b618135..0000000 --- a/src/session-menu-mgr.c +++ /dev/null @@ -1,1226 +0,0 @@ -/* -Copyright 2011 Canonical Ltd. - -Authors: - Charles Kerr - Conor Curran - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . -*/ - -#include "config.h" - -#include -#include /* geteuid(), getpwuid() */ - -#include -#include - -#include -#include - -#include "dbus-upower.h" -#include "session-menu-mgr.h" -#include "shared-names.h" -#include "users-service-dbus.h" -#include "online-accounts-mgr.h" - -#define DEBUG_SHOW_ALL FALSE - -#define UPOWER_ADDRESS "org.freedesktop.UPower" -#define UPOWER_PATH "/org/freedesktop/UPower" - -#define CMD_HELP "yelp" -#define CMD_INFO "gnome-control-center info" -#define CMD_SYSTEM_SETTINGS "gnome-control-center" -#ifdef HAVE_GTKLOGOUTHELPER - #define HAVE_RESTART_CMD TRUE - #define CMD_RESTART LIBEXECDIR"/gtk-logout-helper --restart" - #define CMD_LOGOUT LIBEXECDIR"/gtk-logout-helper --logout" - #define CMD_SHUTDOWN LIBEXECDIR"/gtk-logout-helper --shutdown" -#else - #define HAVE_RESTART_CMD FALSE /* hmm, no gnome-session-quit --restart? */ - #define CMD_RESTART "" - #define CMD_LOGOUT "gnome-session-quit --logout" - #define CMD_SHUTDOWN "gnome-session-quit --power-off" -#endif - -/** - * Which switch menuitem to show -- based on lockdown settings, - * greeter mode, number of users in the system, and so on. - * See get_switcher_mode() - */ -typedef enum -{ - SWITCHER_MODE_SCREENSAVER, - SWITCHER_MODE_LOCK, - SWITCHER_MODE_SWITCH, - SWITCHER_MODE_SWITCH_OR_LOCK, - SWITCHER_MODE_NONE -} -SwitcherMode; - -/** - * Creates and manages the menumodel and associated actions for the - * session menu described at . - * - * This is a pretty straightforward class: it creates the menumodel - * and listens for events that can affect the model's properties. - * - * Simple event sources, such as GSettings and a UPower DBus proxy, - * are handled here. More involved event sources are delegated to the - * UsersServiceDBus facade class. - */ -struct _SessionMenuMgr -{ - GObject parent_instance; - - DbusmenuMenuitem * top_mi; - DbusmenuMenuitem * screensaver_mi; - DbusmenuMenuitem * lock_mi; - DbusmenuMenuitem * lock_switch_mi; - DbusmenuMenuitem * guest_mi; - DbusmenuMenuitem * online_accounts_mi; - DbusmenuMenuitem * logout_mi; - DbusmenuMenuitem * suspend_mi; - DbusmenuMenuitem * hibernate_mi; - DbusmenuMenuitem * restart_mi; - DbusmenuMenuitem * shutdown_mi; - - GSList * user_menuitems; - gint user_menuitem_index; - - GSettings * lockdown_settings; - GSettings * indicator_settings; - GSettings * keybinding_settings; - - /* cached settings taken from the upower proxy */ - gboolean can_hibernate; - gboolean can_suspend; - gboolean allow_hibernate; - gboolean allow_suspend; - - gboolean greeter_mode; - - GCancellable * cancellable; - DBusUPower * upower_proxy; - SessionDbus * session_dbus; - UsersServiceDbus * users_dbus_facade; - OnlineAccountsMgr * online_accounts_mgr; -}; - -static SwitcherMode get_switcher_mode (SessionMenuMgr *); - -static void init_upower_proxy (SessionMenuMgr *); - -static void update_screensaver_shortcut (SessionMenuMgr *); -static void update_user_menuitems (SessionMenuMgr *); -static void update_session_menuitems (SessionMenuMgr *); -static void update_confirmation_labels (SessionMenuMgr *); - -static void action_func_lock (SessionMenuMgr *); -static void action_func_suspend (SessionMenuMgr *); -static void action_func_hibernate (SessionMenuMgr *); -static void action_func_switch_to_lockscreen (SessionMenuMgr *); -static void action_func_switch_to_greeter (SessionMenuMgr *); -static void action_func_switch_to_guest (SessionMenuMgr *); -static void action_func_switch_to_user (AccountsUser *); -static void action_func_spawn_async (const char * cmd); - -static gboolean is_this_guest_session (void); -static gboolean is_this_live_session (void); - -static void on_guest_logged_in_changed (UsersServiceDbus *, - SessionMenuMgr *); - -static void on_user_logged_in_changed (UsersServiceDbus *, - AccountsUser *, - SessionMenuMgr *); - -/** -*** GObject init / dispose -**/ - -G_DEFINE_TYPE (SessionMenuMgr, session_menu_mgr, G_TYPE_OBJECT); - -static void -session_menu_mgr_init (SessionMenuMgr *mgr) -{ - mgr->top_mi = dbusmenu_menuitem_new (); - - /* Lockdown settings */ - GSettings * s = g_settings_new ("org.gnome.desktop.lockdown"); - g_signal_connect_swapped (s, "changed::disable-log-out", - G_CALLBACK(update_session_menuitems), mgr); - g_signal_connect_swapped (s, "changed::disable-lock-screen", - G_CALLBACK(update_user_menuitems), mgr); - g_signal_connect_swapped (s, "changed::disable-user-switching", - G_CALLBACK(update_user_menuitems), mgr); - mgr->lockdown_settings = s; - - /* Indicator settings */ - s = g_settings_new ("com.canonical.indicator.session"); - g_signal_connect_swapped (s, "changed::suppress-logout-restart-shutdown", - G_CALLBACK(update_confirmation_labels), mgr); - g_signal_connect_swapped (s, "changed::suppress-logout-menuitem", - G_CALLBACK(update_session_menuitems), mgr); - g_signal_connect_swapped (s, "changed::suppress-restart-menuitem", - G_CALLBACK(update_session_menuitems), mgr); - g_signal_connect_swapped (s, "changed::suppress-shutdown-menuitem", - G_CALLBACK(update_session_menuitems), mgr); - mgr->indicator_settings = s; - - /* Keybinding settings */ - s = g_settings_new ("org.gnome.settings-daemon.plugins.media-keys"); - g_signal_connect_swapped (s, "changed::screensaver", - G_CALLBACK(update_screensaver_shortcut), mgr); - mgr->keybinding_settings = s; - - /* listen for user events */ - mgr->users_dbus_facade = g_object_new (USERS_SERVICE_DBUS_TYPE, NULL); - g_signal_connect_swapped (mgr->users_dbus_facade, "user-list-changed", - G_CALLBACK (update_user_menuitems), mgr); - g_signal_connect (mgr->users_dbus_facade, "user-logged-in-changed", - G_CALLBACK(on_user_logged_in_changed), mgr); - g_signal_connect (mgr->users_dbus_facade, "guest-logged-in-changed", - G_CALLBACK(on_guest_logged_in_changed), mgr); - - init_upower_proxy (mgr); - - /* Online accounts menu item */ - mgr->online_accounts_mgr = online_accounts_mgr_new (); -} - -static void -session_menu_mgr_dispose (GObject *object) -{ - SessionMenuMgr * mgr = SESSION_MENU_MGR (object); - - if (mgr->cancellable != NULL) - { - g_cancellable_cancel (mgr->cancellable); - g_clear_object (&mgr->cancellable); - } - - g_clear_object (&mgr->indicator_settings); - g_clear_object (&mgr->lockdown_settings); - g_clear_object (&mgr->keybinding_settings); - g_clear_object (&mgr->upower_proxy); - g_clear_object (&mgr->users_dbus_facade); - g_clear_object (&mgr->top_mi); - g_clear_object (&mgr->session_dbus); - g_clear_object (&mgr->online_accounts_mgr); - - g_slist_free (mgr->user_menuitems); - mgr->user_menuitems = NULL; - - G_OBJECT_CLASS (session_menu_mgr_parent_class)->dispose (object); -} - -static void -session_menu_mgr_class_init (SessionMenuMgrClass * klass) -{ - GObjectClass* object_class = G_OBJECT_CLASS (klass); - object_class->dispose = session_menu_mgr_dispose; -} - -/*** -**** UPower Proxy: -**** -**** 1. While bootstrapping, we invoke the AllowSuspend and AllowHibernate -**** methods to find out whether or not those features are allowed. -**** 2. While bootstrapping, we get the CanSuspend and CanHibernate properties -**** and also listen for property changes. -**** 3. These four values are used to set suspend and hibernate's visibility. -**** -***/ - -static void -on_upower_properties_changed (SessionMenuMgr * mgr) -{ - gboolean need_refresh = FALSE; - - if (mgr->upower_proxy != NULL) - { - gboolean b; - - /* suspend */ - b = dbus_upower_get_can_suspend (mgr->upower_proxy); - if (mgr->can_suspend != b) - { - mgr->can_suspend = b; - need_refresh = TRUE; - } - - /* hibernate */ - b = dbus_upower_get_can_hibernate (mgr->upower_proxy); - if (mgr->can_hibernate != b) - { - mgr->can_hibernate = b; - need_refresh = TRUE; - } - } - - if (need_refresh) - { - update_session_menuitems (mgr); - } -} - -static void -init_upower_proxy (SessionMenuMgr * mgr) -{ - /* default values */ - mgr->can_suspend = TRUE; - mgr->can_hibernate = TRUE; - mgr->allow_suspend = TRUE; - mgr->allow_hibernate = TRUE; - - mgr->cancellable = g_cancellable_new (); - - GError * error = NULL; - mgr->upower_proxy = dbus_upower_proxy_new_for_bus_sync ( - G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - UPOWER_ADDRESS, - UPOWER_PATH, - NULL, - &error); - if (error != NULL) - { - g_warning ("Error creating upower proxy: %s", error->message); - g_clear_error (&error); - } - else - { - dbus_upower_call_suspend_allowed_sync (mgr->upower_proxy, - &mgr->allow_suspend, - NULL, - &error); - if (error != NULL) - { - g_warning ("%s: %s", G_STRFUNC, error->message); - g_clear_error (&error); - } - - dbus_upower_call_hibernate_allowed_sync (mgr->upower_proxy, - &mgr->allow_hibernate, - NULL, - &error); - if (error != NULL) - { - g_warning ("%s: %s", G_STRFUNC, error->message); - g_clear_error (&error); - } - - g_signal_connect_swapped (mgr->upower_proxy, "changed", - G_CALLBACK(on_upower_properties_changed), mgr); - } -} - -/*** -**** Menuitem Helpers -***/ - -static inline void -mi_set_label (DbusmenuMenuitem * mi, const char * str) -{ - dbusmenu_menuitem_property_set (mi, DBUSMENU_MENUITEM_PROP_LABEL, str); -} - -static inline void -mi_set_type (DbusmenuMenuitem * mi, const char * str) -{ - dbusmenu_menuitem_property_set (mi, DBUSMENU_MENUITEM_PROP_TYPE, str); -} - -static inline void -mi_set_visible (DbusmenuMenuitem * mi, gboolean b) -{ - dbusmenu_menuitem_property_set_bool (mi, DBUSMENU_MENUITEM_PROP_VISIBLE, - b || DEBUG_SHOW_ALL); -} - -static inline void -mi_set_logged_in (DbusmenuMenuitem * mi, gboolean b) -{ - dbusmenu_menuitem_property_set_bool (mi, USER_ITEM_PROP_LOGGED_IN, b); -} - -static DbusmenuMenuitem* -mi_new_separator (void) -{ - DbusmenuMenuitem * mi = dbusmenu_menuitem_new (); - mi_set_type (mi, DBUSMENU_CLIENT_TYPES_SEPARATOR); - return mi; -} - -static DbusmenuMenuitem* -mi_new (const char * label) -{ - DbusmenuMenuitem * mi = dbusmenu_menuitem_new (); - mi_set_label (mi, label); - return mi; -} - -static void -check_online_accounts_status (SessionMenuMgr * mgr, DbusmenuMenuitem * mi) -{ - const gchar *disposition; - gboolean on_alert; - - disposition = - dbusmenu_menuitem_property_get (mi, DBUSMENU_MENUITEM_PROP_DISPOSITION); - on_alert = g_strcmp0 (disposition, DBUSMENU_MENUITEM_DISPOSITION_ALERT) == 0; - - mi_set_visible (mi, on_alert); -} - -static void -on_online_accounts_changed (SessionMenuMgr * mgr, const gchar * property, - GVariant *value, DbusmenuMenuitem *mi) -{ - if (g_strcmp0 (property, DBUSMENU_MENUITEM_PROP_DISPOSITION) == 0) - { - check_online_accounts_status(mgr, mi); - } -} - -/*** -**** Admin Menuitems -**** -***/ - -static void -build_admin_menuitems (SessionMenuMgr * mgr) -{ - if (!mgr->greeter_mode) - { - DbusmenuMenuitem * mi; - const gboolean show_settings = !mgr->greeter_mode; - - mi = mi_new (_("About This Computer")); - dbusmenu_menuitem_child_append (mgr->top_mi, mi); - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK(action_func_spawn_async), CMD_INFO); - - mi = mi_new (_("Ubuntu Help")); - dbusmenu_menuitem_child_append (mgr->top_mi, mi); - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK(action_func_spawn_async), CMD_HELP); - - mi = mi_new_separator (); - mi_set_visible (mi, show_settings); - dbusmenu_menuitem_child_append (mgr->top_mi, mi); - - mi = mi_new (_("System Settings\342\200\246")); - mi_set_visible (mi, show_settings); - dbusmenu_menuitem_child_append (mgr->top_mi, mi); - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK(action_func_spawn_async), - CMD_SYSTEM_SETTINGS); - - mi = mgr->online_accounts_mi = - online_accounts_mgr_get_menu_item (mgr->online_accounts_mgr); - dbusmenu_menuitem_child_append (mgr->top_mi, mi); - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, - G_CALLBACK(on_online_accounts_changed), - mgr); - check_online_accounts_status (mgr, mi); - - mi = mi_new_separator (); - dbusmenu_menuitem_child_append (mgr->top_mi, mi); - } -} - -/*** -**** Session Menuitems -**** -***/ - -static void -update_session_menuitems (SessionMenuMgr * mgr) -{ - gboolean v; - GSettings * s = mgr->indicator_settings; - - v = !mgr->greeter_mode - && !is_this_live_session() - && !g_settings_get_boolean (mgr->lockdown_settings, "disable-log-out") - && !g_settings_get_boolean (s, "suppress-logout-menuitem"); - mi_set_visible (mgr->logout_mi, v); - - v = mgr->can_suspend - && mgr->allow_suspend; - mi_set_visible (mgr->suspend_mi, v); - - v = mgr->can_hibernate - && mgr->allow_hibernate; - mi_set_visible (mgr->hibernate_mi, v); - - v = HAVE_RESTART_CMD - && !g_settings_get_boolean (s, "suppress-restart-menuitem"); - mi_set_visible (mgr->restart_mi, v); - - v = !g_settings_get_boolean (s, "suppress-shutdown-menuitem"); - mi_set_visible (mgr->shutdown_mi, v); -} - -/* Update the ellipses when the confirmation setting changes. - * - * : - * "Label the menu item with a trailing ellipsis ("...") only if the - * command requires further input from the user before it can be performed." - */ -static void -update_confirmation_labels (SessionMenuMgr * mgr) -{ - const gboolean confirm_needed = !g_settings_get_boolean ( - mgr->indicator_settings, - "suppress-logout-restart-shutdown"); - - mi_set_label (mgr->logout_mi, confirm_needed ? _("Log Out\342\200\246") - : _("Log Out")); - - mi_set_label (mgr->shutdown_mi, confirm_needed ? _("Shut Down\342\200\246") - : _("Shut Down")); - - mi_set_label (mgr->restart_mi, confirm_needed ? _("Restart\342\200\246") - : _("Restart")); -} - -static void -build_session_menuitems (SessionMenuMgr* mgr) -{ - DbusmenuMenuitem * mi; - - mi = mgr->logout_mi = mi_new (_("Log Out\342\200\246")); - dbusmenu_menuitem_child_append (mgr->top_mi, mi); - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK(action_func_spawn_async), CMD_LOGOUT); - - mi = mgr->suspend_mi = mi_new (_("Suspend")); - dbusmenu_menuitem_child_append (mgr->top_mi, mi); - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK(action_func_suspend), mgr); - - mi = mgr->hibernate_mi = mi_new (_("Hibernate")); - dbusmenu_menuitem_child_append (mgr->top_mi, mi); - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK(action_func_hibernate), mgr); - - mi = mgr->restart_mi = mi_new (_("Restart\342\200\246")); - dbusmenu_menuitem_child_append (mgr->top_mi, mi); - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK(action_func_spawn_async), CMD_RESTART); - - mi = mgr->shutdown_mi = mi_new (_("Shut Down\342\200\246")); - dbusmenu_menuitem_child_append (mgr->top_mi, mi); - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK(action_func_spawn_async), CMD_SHUTDOWN); - - update_confirmation_labels (mgr); - update_session_menuitems (mgr); -} - -/**** -***** User Menuitems -***** https://wiki.ubuntu.com/SystemMenu#Account-switching_items -****/ - -/* Local extensions to AccountsUser */ - -static GQuark -get_menuitem_quark (void) -{ - static GQuark q = 0; - - if (G_UNLIKELY(!q)) - { - q = g_quark_from_static_string ("menuitem"); - } - - return q; -} - -static DbusmenuMenuitem* -user_get_menuitem (AccountsUser * user) -{ - return g_object_get_qdata (G_OBJECT(user), get_menuitem_quark()); -} - -static void -user_clear_menuitem (AccountsUser * user) -{ - g_object_steal_qdata (G_OBJECT(user), get_menuitem_quark()); -} - -static void -user_set_menuitem (AccountsUser * user, DbusmenuMenuitem * mi) -{ - g_object_set_qdata (G_OBJECT(user), get_menuitem_quark(), mi); - - g_object_weak_ref (G_OBJECT(mi), (GWeakNotify)user_clear_menuitem, user); -} - -/***/ - -static GQuark -get_mgr_quark (void) -{ - static GQuark q = 0; - - if (G_UNLIKELY(!q)) - { - q = g_quark_from_static_string ("session-menu-mgr"); - } - - return q; -} - -static SessionMenuMgr* -user_get_mgr (AccountsUser * user) -{ - return g_object_get_qdata (G_OBJECT(user), get_mgr_quark()); -} - -static void -user_set_mgr (AccountsUser * user, SessionMenuMgr * mgr) -{ - g_object_set_qdata (G_OBJECT(user), get_mgr_quark(), mgr); -} - -/***/ - -static GQuark -get_collision_quark (void) -{ - static GQuark q = 0; - - if (G_UNLIKELY(!q)) - { - q = g_quark_from_static_string ("name-collision"); - } - - return q; -} - -static gboolean -user_has_name_collision (AccountsUser * u) -{ - return g_object_get_qdata (G_OBJECT(u), get_collision_quark()) != NULL; -} - -static void -user_set_name_collision (AccountsUser * u, gboolean b) -{ - g_object_set_qdata (G_OBJECT(u), get_collision_quark(), GINT_TO_POINTER(b)); -} - -/*** -**** -***/ - -static void -on_guest_logged_in_changed (UsersServiceDbus * usd, - SessionMenuMgr * mgr) -{ - if (mgr->guest_mi != NULL) - { - mi_set_logged_in (mgr->guest_mi, - users_service_dbus_is_guest_logged_in (usd)); - } -} - -/* When a user's login state changes, - update the corresponding menuitem's LOGGED_IN property */ -static void -on_user_logged_in_changed (UsersServiceDbus * usd, - AccountsUser * user, - SessionMenuMgr * mgr) -{ - DbusmenuMenuitem * mi = user_get_menuitem (user); - - if (mi != NULL) - { - mi_set_logged_in (mi, users_service_dbus_is_user_logged_in (usd, user)); - } -} - -static void -update_screensaver_shortcut (SessionMenuMgr * mgr) -{ - gchar * s = g_settings_get_string (mgr->keybinding_settings, "screensaver"); - g_debug ("%s Screensaver shortcut changed to: '%s'", G_STRLOC, s); - - if (mgr->lock_mi != NULL) - { - dbusmenu_menuitem_property_set_shortcut_string (mgr->lock_mi, s); - } - - if (mgr->lock_switch_mi != NULL) - { - dbusmenu_menuitem_property_set_shortcut_string (mgr->lock_switch_mi, s); - } - - if (mgr->screensaver_mi != NULL) - { - dbusmenu_menuitem_property_set_shortcut_string (mgr->screensaver_mi, s); - } - - g_free (s); -} - -static void -update_user_menuitem_icon (DbusmenuMenuitem * mi, AccountsUser * user) -{ - const gchar * str = accounts_user_get_icon_file (user); - - if (!str || !*str) - { - str = USER_ITEM_ICON_DEFAULT; - } - - dbusmenu_menuitem_property_set (mi, USER_ITEM_PROP_ICON, str); -} - -static void -update_user_menuitem_name (DbusmenuMenuitem * mi, AccountsUser * user) -{ - GString * gstr = g_string_new (accounts_user_get_real_name (user)); - - if (user_has_name_collision (user)) - g_string_append_printf (gstr, " (%s)", accounts_user_get_user_name(user)); - - if (!gstr->len) - g_string_assign (gstr, accounts_user_get_user_name(user)); - - dbusmenu_menuitem_property_set (mi, USER_ITEM_PROP_NAME, gstr->str); - g_string_free (gstr, TRUE); -} - -static void -on_user_property_changed (AccountsUser * user, - GParamSpec * pspec, - DbusmenuMenuitem * mi) -{ - static const char * interned_icon_file = NULL; - static const char * interned_real_name = NULL; - static const char * interned_user_name = NULL; - - if (G_UNLIKELY (interned_icon_file == NULL)) - { - interned_icon_file = g_intern_static_string ("icon-file"); - interned_user_name = g_intern_static_string ("user-name"); - interned_real_name = g_intern_static_string ("real-name"); - } - - if (pspec->name == interned_icon_file) - { - update_user_menuitem_icon (mi, user); - } - else if ((pspec->name == interned_real_name) - || (pspec->name == interned_user_name)) - { - /* name changing can affect other menuitems too by invalidating - the sort order or name collision flags... so let's rebuild */ - update_user_menuitems (user_get_mgr (user)); - } -} - -typedef struct -{ - gpointer instance; - gulong handler_id; -} -SignalHandlerData; - -/* when a user menuitem is destroyed, - it should stop listening for its UserAccount's property changes */ -static void -on_user_menuitem_destroyed (SignalHandlerData * data) -{ - g_signal_handler_disconnect (data->instance, data->handler_id); - g_free (data); -} - -static DbusmenuMenuitem* -user_menuitem_new (AccountsUser * user, SessionMenuMgr * mgr) -{ - DbusmenuMenuitem * mi = dbusmenu_menuitem_new (); - mi_set_type (mi, USER_ITEM_TYPE); - - /* set the name & icon and listen for property changes */ - update_user_menuitem_name (mi, user); - update_user_menuitem_icon (mi, user); - SignalHandlerData * hd = g_new0 (SignalHandlerData, 1); - hd->instance = user; - hd->handler_id = g_signal_connect (user, "notify", - G_CALLBACK(on_user_property_changed), mi); - g_object_weak_ref (G_OBJECT(mi), (GWeakNotify)on_user_menuitem_destroyed, hd); - - /* set the logged-in property */ - mi_set_logged_in (mi, - users_service_dbus_is_user_logged_in (mgr->users_dbus_facade, user)); - - /* set the is-current-user property */ - const gboolean is_current_user = - !g_strcmp0 (g_get_user_name(), accounts_user_get_user_name(user)); - - dbusmenu_menuitem_property_set_bool (mi, - USER_ITEM_PROP_IS_CURRENT_USER, - is_current_user); - - /* set the switch-to-user action */ - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK (action_func_switch_to_user), user); - - /* give this AccountsUser a hook back to this menuitem */ - user_set_menuitem (user, mi); - user_set_mgr (user, mgr); - - return mi; -} - -/* for sorting AccountsUsers from most to least frequently used */ -static gint -compare_users_by_login_frequency (gconstpointer a, gconstpointer b) -{ - const guint64 a_freq = accounts_user_get_login_frequency (ACCOUNTS_USER(a)); - const guint64 b_freq = accounts_user_get_login_frequency (ACCOUNTS_USER(b)); - if (a_freq > b_freq) return -1; - if (a_freq < b_freq) return 1; - return 0; -} - -/* for sorting AccountsUsers alphabetically */ -static gint -compare_users_by_username (gconstpointer ga, gconstpointer gb) -{ - AccountsUser * a = ACCOUNTS_USER(ga); - AccountsUser * b = ACCOUNTS_USER(gb); - - const int ret = g_strcmp0 (accounts_user_get_real_name (a), - accounts_user_get_real_name (b)); - - if (!ret) /* names are the same, so both have a name collision */ - { - user_set_name_collision (a, TRUE); - user_set_name_collision (b, TRUE); - } - - return ret; -} - -static gboolean -is_user_switching_allowed (SessionMenuMgr * mgr) -{ - /* maybe it's locked down */ - if (g_settings_get_boolean (mgr->lockdown_settings, "disable-user-switching")) - { - return FALSE; - } - - /* maybe the seat doesn't support activation */ - if (!users_service_dbus_can_activate_session (mgr->users_dbus_facade)) - { - return FALSE; - } - - return TRUE; -} - -static void -build_user_menuitems (SessionMenuMgr * mgr) -{ - g_return_if_fail (!mgr->greeter_mode); - - DbusmenuMenuitem * mi; - GSList * items = NULL; - gint pos = mgr->user_menuitem_index; - const char * current_real_name = NULL; - - /** - *** Start Screen Saver - *** Switch Account... - *** Lock - *** Lock / Switch Account... - **/ - - const SwitcherMode mode = get_switcher_mode (mgr); - - mi = mgr->screensaver_mi = mi_new (_("Start Screen Saver")); - mi_set_visible (mi, mode == SWITCHER_MODE_SCREENSAVER); - dbusmenu_menuitem_child_add_position (mgr->top_mi, mi, pos++); - items = g_slist_prepend (items, mi); - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK (action_func_lock), mgr); - - mi = mi_new (_("Switch User Account\342\200\246")); - mi_set_visible (mi, mode == SWITCHER_MODE_SWITCH); - dbusmenu_menuitem_child_add_position (mgr->top_mi, mi, pos++); - items = g_slist_prepend (items, mi); - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK (action_func_switch_to_greeter), mgr); - - mi = mgr->lock_mi = mi_new (_("Lock")); - mi_set_visible (mi, mode == SWITCHER_MODE_LOCK); - dbusmenu_menuitem_child_add_position (mgr->top_mi, mi, pos++); - items = g_slist_prepend (items, mi); - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK (action_func_switch_to_lockscreen), mgr); - - mi = mgr->lock_switch_mi = mi_new (_("Lock/Switch Account\342\200\246")); - mi_set_visible (mi, mode == SWITCHER_MODE_SWITCH_OR_LOCK); - dbusmenu_menuitem_child_add_position (mgr->top_mi, mi, pos++); - items = g_slist_prepend (items, mi); - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK (action_func_switch_to_lockscreen), mgr); - - const gboolean is_guest = is_this_guest_session (); - const gboolean guest_allowed = - users_service_dbus_guest_session_enabled (mgr->users_dbus_facade); - mi = mgr->guest_mi = dbusmenu_menuitem_new (); - mi_set_type (mi, USER_ITEM_TYPE); - mi_set_visible (mi, !is_guest && guest_allowed); - dbusmenu_menuitem_property_set (mi, USER_ITEM_PROP_NAME, _("Guest Session")); - dbusmenu_menuitem_child_add_position (mgr->top_mi, mi, pos++); - on_guest_logged_in_changed (mgr->users_dbus_facade, mgr); - items = g_slist_prepend (items, mi); - g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK (action_func_switch_to_guest), mgr); - - if (guest_allowed && is_guest) - { - current_real_name = _("Guest"); - } - - /*** - **** Users - ***/ - - /* if we can switch to another user account, show them here */ - const char * const username = g_get_user_name(); - GList * users = users_service_dbus_get_user_list (mgr->users_dbus_facade); - - /* since we're building (or rebuilding) from scratch, - clear the name collision flags */ - GList * u; - for (u=users; u!=NULL; u=u->next) - { - AccountsUser * user = ACCOUNTS_USER(u->data); - - user_set_name_collision (user, FALSE); - - if (!g_strcmp0 (username, accounts_user_get_user_name(user))) - { - current_real_name = accounts_user_get_real_name (user); - } - } - - if (is_user_switching_allowed (mgr)) - { - /* pick the most frequently used accounts */ - const int MAX_USERS = 12; /* this limit comes from the spec */ - if (g_list_length(users) > MAX_USERS) - { - users = g_list_sort (users, compare_users_by_login_frequency); - GList * last = g_list_nth (users, MAX_USERS-1); - GList * remainder = last->next; - last->next = NULL; - remainder->prev = NULL; - g_list_free (remainder); - } - - /* Sort the users by name for display */ - users = g_list_sort (users, compare_users_by_username); - - /* Create menuitems for them */ - int i; - for (i=0, u=users; inext, i++) - { - AccountsUser * user = u->data; - DbusmenuMenuitem * mi = user_menuitem_new (user, mgr); - dbusmenu_menuitem_child_add_position (mgr->top_mi, mi, pos++); - items = g_slist_prepend (items, mi); - } - } - - g_list_free (users); - - /* separator */ - if (mode != SWITCHER_MODE_SCREENSAVER && !is_guest && guest_allowed) - { - mi = mi_new_separator (); - dbusmenu_menuitem_child_add_position (mgr->top_mi, mi, pos++); - items = g_slist_prepend (items, mi); - } - - if (current_real_name != NULL) - { - session_dbus_set_users_real_name (mgr->session_dbus, - current_real_name); - } - - update_screensaver_shortcut (mgr); - mgr->user_menuitems = items; -} - -static void -update_user_menuitems (SessionMenuMgr * mgr) -{ - /* remove any previous user menuitems */ - GSList * l; - for (l=mgr->user_menuitems; l!=NULL; l=l->next) - { - dbusmenu_menuitem_child_delete (mgr->top_mi, l->data); - } - g_slist_free (mgr->user_menuitems); - mgr->user_menuitems = NULL; - - /* add fresh user menuitems */ - if (!mgr->greeter_mode) - { - build_user_menuitems (mgr); - } -} - -/*** -**** Actions! -***/ - -static void -action_func_spawn_async (const char * cmd) -{ - GError * error = NULL; - - g_debug ("%s calling \"%s\"", G_STRFUNC, cmd); - g_spawn_command_line_async (cmd, &error); - - if (error != NULL) - { - g_warning ("Unable to execute \"%s\": %s", cmd, error->message); - g_clear_error (&error); - } -} - -/* Calling "Lock" locks the screen & goes to black. - Calling "SimulateUserActivity" afterwards shows the Lock Screen. */ -static void -lock_helper (SessionMenuMgr * mgr, gboolean show_lock_screen) -{ - if (!g_settings_get_boolean (mgr->lockdown_settings, "disable-lock-screen")) - { - GError * error = NULL; - GDBusProxy * proxy = g_dbus_proxy_new_for_bus_sync ( - G_BUS_TYPE_SESSION, - G_DBUS_PROXY_FLAGS_NONE, - NULL, - "org.gnome.ScreenSaver", - "/org/gnome/ScreenSaver", - "org.gnome.ScreenSaver", - NULL, - &error); - - if (error == NULL) - { - g_dbus_proxy_call_sync (proxy, "Lock", - NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, - &error); - } - - if ((error == NULL) && show_lock_screen) - { - g_dbus_proxy_call_sync (proxy, "SimulateUserActivity", - NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, - &error); - } - - if (error != NULL) - { - g_warning ("Error locking screen: %s", error->message); - } - - g_clear_object (&proxy); - g_clear_error (&error); - } -} - -static void -action_func_lock (SessionMenuMgr * mgr) -{ - lock_helper (mgr, FALSE); -} - -static void -action_func_switch_to_lockscreen (SessionMenuMgr * mgr) -{ - lock_helper (mgr, TRUE); -} - -static void -action_func_switch_to_greeter (SessionMenuMgr * mgr) -{ - action_func_lock (mgr); - users_service_dbus_show_greeter (mgr->users_dbus_facade); -} - -static void -action_func_switch_to_user (AccountsUser * user) -{ - SessionMenuMgr * mgr = user_get_mgr (user); - - g_return_if_fail (mgr != NULL); - - if (g_strcmp0 (g_get_user_name(), accounts_user_get_user_name(user)) != 0) - { - action_func_lock (mgr); - users_service_dbus_activate_user_session (mgr->users_dbus_facade, user); - } -} - -static void -action_func_switch_to_guest (SessionMenuMgr * mgr) -{ - action_func_lock (mgr); - users_service_dbus_activate_guest_session (mgr->users_dbus_facade); -} - -static void -action_func_suspend (SessionMenuMgr * mgr) -{ - GError * error = NULL; - - dbus_upower_call_suspend_sync (mgr->upower_proxy, - mgr->cancellable, - &error); - - if (error != NULL) - { - g_warning ("%s: %s", G_STRFUNC, error->message); - g_clear_error (&error); - } -} - -static void -action_func_hibernate (SessionMenuMgr * mgr) -{ - GError * error = NULL; - - dbus_upower_call_hibernate_sync (mgr->upower_proxy, - mgr->cancellable, - &error); - - if (error != NULL) - { - g_warning ("%s: %s", G_STRFUNC, error->message); - g_clear_error (&error); - } -} - -/*** -**** -***/ - -static gboolean -is_this_guest_session (void) -{ - /* FIXME: this test has been here awhile and seems to work, - but seems brittle to me */ - return geteuid() < 500; -} - -static gboolean -is_this_live_session (void) -{ - const struct passwd * const pw = getpwuid (geteuid()); - return (pw->pw_uid==999) && !g_strcmp0("ubuntu",pw->pw_name); -} - -static SwitcherMode -get_switcher_mode (SessionMenuMgr * mgr) -{ - SwitcherMode mode; - - const gboolean can_lock = !g_settings_get_boolean (mgr->lockdown_settings, - "disable-lock-screen"); - const gboolean can_switch = is_user_switching_allowed (mgr); - - if (!can_lock && !can_switch) /* hmm, quite an extreme lockdown */ - { - mode = SWITCHER_MODE_NONE; - } - else if (is_this_live_session()) /* live sessions can't lock or switch */ - { - mode = SWITCHER_MODE_SCREENSAVER; - } - else if (!can_switch) /* switching's locked down */ - { - mode = SWITCHER_MODE_LOCK; - } - else if (is_this_guest_session ()) /* guest sessions can't lock */ - { - mode = SWITCHER_MODE_SWITCH; - } - else /* both locking & switching are allowed */ - { - GList * l = users_service_dbus_get_user_list (mgr->users_dbus_facade); - const size_t user_count = g_list_length (l); - g_list_free (l); - - /* only show switch mode if we have users to switch to */ - mode = user_count > (is_this_guest_session() ? 0 : 1) - ? SWITCHER_MODE_SWITCH_OR_LOCK - : SWITCHER_MODE_LOCK; - } - - return mode; -} - - -/*** -**** -***/ - -SessionMenuMgr* -session_menu_mgr_new (SessionDbus * session_dbus, - gboolean greeter_mode) -{ - SessionMenuMgr* mgr = g_object_new (SESSION_TYPE_MENU_MGR, NULL); - mgr->greeter_mode = greeter_mode; - mgr->session_dbus = g_object_ref (session_dbus); - build_admin_menuitems (mgr); - const guint n = g_list_length (dbusmenu_menuitem_get_children (mgr->top_mi)); - mgr->user_menuitem_index = n; - update_user_menuitems (mgr); - build_session_menuitems (mgr); - - /* After we have the session menu items built we can look to - align them with UPower */ - on_upower_properties_changed (mgr); - - return mgr; -} - -/** - * session_menu_mgr_get_menu: - * - * Returns: (transfer none): the manager's menu. - */ -DbusmenuMenuitem * -session_menu_mgr_get_menu (SessionMenuMgr * mgr) -{ - g_return_val_if_fail (IS_SESSION_MENU_MGR(mgr), NULL); - - return mgr->top_mi; -} diff --git a/src/session-menu-mgr.h b/src/session-menu-mgr.h deleted file mode 100644 index 5a173e1..0000000 --- a/src/session-menu-mgr.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -Copyright 2011 Canonical Ltd. - -Authors: - Conor Curran - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . -*/ - - -#ifndef _SESSION_MENU_MGR_H_ -#define _SESSION_MENU_MGR_H_ - -#include - -#include "session-dbus.h" - -G_BEGIN_DECLS - -#define SESSION_TYPE_MENU_MGR (session_menu_mgr_get_type ()) -#define SESSION_MENU_MGR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SESSION_TYPE_MENU_MGR, SessionMenuMgr)) -#define SESSION_MENU_MGR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SESSION_TYPE_MENU_MGR, SessionMenuMgrClass)) -#define IS_SESSION_MENU_MGR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SESSION_TYPE_MENU_MGR)) -#define IS_SESSION_MENU_MGR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SESSION_TYPE_MENU_MGR)) -#define SESSION_MENU_MGR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SESSION_TYPE_MENU_MGR, SessionMenuMgrClass)) - -typedef struct _SessionMenuMgrClass SessionMenuMgrClass; -typedef struct _SessionMenuMgr SessionMenuMgr; - -struct _SessionMenuMgrClass -{ - GObjectClass parent_class; -}; - -GType session_menu_mgr_get_type (void) G_GNUC_CONST; - -SessionMenuMgr* session_menu_mgr_new (SessionDbus * session_dbus, - gboolean greeter_mode); - -DbusmenuMenuitem* session_menu_mgr_get_menu (SessionMenuMgr * mgr); - - -G_END_DECLS - -#endif /* _SESSION_MENU_MGR_H_ */ diff --git a/src/session-service.c b/src/session-service.c deleted file mode 100644 index 13438d3..0000000 --- a/src/session-service.c +++ /dev/null @@ -1,96 +0,0 @@ -/* -A small wrapper utility to load indicators and put them as menu items -into the gnome-panel using it's applet interface. - -Copyright 2009 Canonical Ltd. - -Authors: - Ted Gould - Christoph Korn - Cody Russell - Conor Curran - Charles Kerr - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . -*/ - -#include "config.h" - -#include -#include - -#include -#include -#include - -#include - -#include - -#include - -#include "session-dbus.h" -#include "session-menu-mgr.h" -#include "shared-names.h" -#include "users-service-dbus.h" - -static SessionDbus * session_dbus = NULL; -static GMainLoop * mainloop = NULL; - - -/* When the service interface starts to shutdown, - we should follow it. */ -void -service_shutdown (IndicatorService * service, gpointer user_data) -{ - if (mainloop != NULL) - { - g_debug ("Service shutdown"); - g_main_loop_quit (mainloop); - } -} - -static inline gboolean -is_greeter_mode (void) -{ - return !g_strcmp0 (g_getenv ("INDICATOR_GREETER_MODE"), "1"); -} - -/* Main, is well, main. It brings everything up and throws - us into the mainloop of no return. */ -int -main (int argc, char ** argv) -{ - /* Setting up i18n and gettext. - Apparently we need all of these. */ - setlocale (LC_ALL, ""); - bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); - textdomain (GETTEXT_PACKAGE); - - IndicatorService * service = indicator_service_new_version (INDICATOR_SESSION_DBUS_NAME, - INDICATOR_SESSION_DBUS_VERSION); - g_signal_connect (G_OBJECT(service), INDICATOR_SERVICE_SIGNAL_SHUTDOWN, - G_CALLBACK(service_shutdown), NULL); - - session_dbus = session_dbus_new(); - - SessionMenuMgr * menu_mgr = session_menu_mgr_new (session_dbus, is_greeter_mode()); - DbusmenuServer* server = dbusmenu_server_new (INDICATOR_SESSION_DBUS_OBJECT); - dbusmenu_server_set_root (server, session_menu_mgr_get_menu (menu_mgr)); - - mainloop = g_main_loop_new(NULL, FALSE); - g_main_loop_run(mainloop); - - return 0; -} - diff --git a/src/shared-names.h b/src/shared-names.h deleted file mode 100644 index c08f98a..0000000 --- a/src/shared-names.h +++ /dev/null @@ -1,52 +0,0 @@ -/* -A small wrapper utility to load indicators and put them as menu items -into the gnome-panel using it's applet interface. - -Copyright 2009 Canonical Ltd. - -Authors: - Ted Gould - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . -*/ - -#ifndef __DBUS_SHARED_NAMES_H__ -#define __DBUS_SHARED_NAMES_H__ - -#define INDICATOR_SESSION_DBUS_NAME "com.canonical.indicator.session" -#define INDICATOR_SESSION_DBUS_OBJECT "/com/canonical/indicator/session/menu" -#define INDICATOR_SESSION_DBUS_VERSION 0 - -#define INDICATOR_SESSION_SERVICE_DBUS_OBJECT "/com/canonical/indicator/session/service" -#define INDICATOR_SESSION_SERVICE_DBUS_IFACE "com.canonical.indicator.session.service" -#define USER_ITEM_TYPE "x-canonical-user-item" -#define USER_ITEM_PROP_NAME "user-item-name" -#define USER_ITEM_PROP_LOGGED_IN "user-item-logged-in" -#define USER_ITEM_PROP_IS_CURRENT_USER "user-item-is-current-user" -#define USER_ITEM_PROP_ICON "user-item-icon-path" -#define USER_ITEM_ICON_DEFAULT "avatar-default" - -#define ICON_DEFAULT "system-devices-panel" -#define ICON_INFO "system-devices-panel-information" -#define ICON_ALERT "system-devices-panel-alert" - -/* the session indicator's settings */ -#define SESSION_SCHEMA "com.canonical.indicator.session" -#define SUPPRESS_KEY "suppress-logout-restart-shutdown" -#define LOGOUT_KEY "suppress-logout-menuitem" -#define RESTART_KEY "suppress-restart-menuitem" -#define SHUTDOWN_KEY "suppress-shutdown-menuitem" -#define SHOW_USER_MENU "user-show-menu" - - -#endif /* __DBUS_SHARED_NAMES_H__ */ diff --git a/src/upower.xml b/src/upower.xml deleted file mode 100644 index 18d5fbd..0000000 --- a/src/upower.xml +++ /dev/null @@ -1,309 +0,0 @@ - - - - - - - - The DeviceKit-power service is available via the system message - bus. To access the service, use - the org.freedesktop.UPower interface on - the /org/freedesktop/UPower object on - the D-Bus system bus service with the well-known - name org.freedesktop.UPower. - - - - -$ dbus-send --print-reply \ - --system \ - --dest=org.freedesktop.UPower \ - /org/freedesktop/UPower \ - org.freedesktop.UPower.EnumerateDevices - -method return sender=:1.386 -> dest=:1.451 reply_serial=2 - array [ - object path "/org/freedesktop/UPower/devices/line_power_AC" - object path "/org/freedesktop/UPower/devices/battery_BAT0" - ] - - - - - - - - - - - - An array of object paths for devices. - - - - - - Enumerate all power objects on the system. - - - - - - - - - - Object path of device that was added. - - - - - - Emitted when a device is added. - - - - - - - - - - Object path of device that was removed. - - - - - - Emitted when a device is removed. - - - - - - - - - - Object path of device that was changed. - - - - - - Emitted when a device changed. - - - - - - - - - - - - Emitted when one or more properties on the object changes. - - - - - - - - - - - - This signal is sent when the session is about to be suspended or - hibernated. - Session and system programs have one second to do anything required - before the sleep action is taken (such as sending out Avahi or - Jabber messages). - - - - - - - - - - - - This signal is sent when the session has just returned from - Suspend() or Hibernate(). - Session and system programs can then do anything required (such as - sending out Avahi or Jabber messages). - - - - - - - - - - - - - This method tells UPower that the Suspend() or Hibernate() method - is about to be called. - This allows UPower to emit the Suspending signal whilst - session activities are happening that have to be done before the - suspend process is started. - - - This method would typically be called by the session power - management daemon, before it locks the screen and waits for the - screen to fade to black. - The session power management component would then call Suspend() or - Hibernate() when these syncronous tasks have completed. - - - If this method is not called than nothing bad will happen and - Suspend() or Hibernate() will block for the required second. - - - - - - - - - - - - - Suspends the computer into a low power state. - System state is not preserved if the power is lost. - - - If AboutToRequestSleep() has not been called then UPower will send - the Sleeping() signal and block for one second. - - - If AboutToRequestSleep() has been called less than one second - before this method is called then UPower will block for the - remaining time to complete one second of delay. - - - - - - - - - - - TRUE if allowed, otherwise FALSE - - - - - Check if the caller has (or can get) the PolicyKit privilege to call - Suspend. - - - - - - - - - - - - - Hibernates the computer into a low power state. - System state is preserved if the power is lost. - - - If AboutToRequestSleep() has not been called then UPower will send - the Sleeping() signal and block for one second. - - - If AboutToRequestSleep() has been called less than one second - before this method is called then UPower will block for the - remaining time to complete one second of delay. - - - - - - - - - - - TRUE if allowed, otherwise FALSE - - - - - Check if the caller has (or can get) the PolicyKit privilege to call - Hibernate. - - - - - - - - - - Version of the running daemon, e.g. 002. - - - - - - Whether the system is able to suspend. - - - - - - Whether the system is able to hibernate. - - - - - - Indicates whether the system is running on battery power. - This property is provided for convenience. - - - - - - Indicates whether the system is running on battery power and if the battery is critically low. - This property is provided for convenience. - - - - - - - - Indicates if the laptop lid is closed where the display cannot be seen. - - - - - - - - - - If the system has a lid device. - - - - - - - - diff --git a/src/user-widget.c b/src/user-widget.c deleted file mode 100644 index 79b87b0..0000000 --- a/src/user-widget.c +++ /dev/null @@ -1,292 +0,0 @@ -/* -Copyright 2011 Canonical Ltd. - -Authors: - Conor Curran - Mirco Müller - Charles Kerr - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . -*/ - -#ifdef HAVE_CONFIG_H - #include "config.h" -#endif - -#include - -#include - -#include "shared-names.h" -#include "user-widget.h" - - -typedef struct _UserWidgetPrivate UserWidgetPrivate; - -struct _UserWidgetPrivate -{ - DbusmenuMenuitem* twin_item; - GtkWidget* user_image; - GtkWidget* user_name; - GtkWidget* container; - GtkWidget* tick_icon; - gboolean logged_in; - gboolean sessions_active; -}; - -#define USER_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), USER_WIDGET_TYPE, UserWidgetPrivate)) - -/* Prototypes */ -static void user_widget_class_init (UserWidgetClass *klass); -static void user_widget_init (UserWidget *self); -static void user_widget_dispose (GObject *object); -static void user_widget_finalize (GObject *object); - -static void user_widget_set_twin_item (UserWidget* self, - DbusmenuMenuitem* twin_item); - -static gboolean user_widget_primitive_draw_cb_gtk_3 (GtkWidget *image, - cairo_t* cr, - gpointer user_data); - -G_DEFINE_TYPE (UserWidget, user_widget, GTK_TYPE_MENU_ITEM); - -static void -user_widget_class_init (UserWidgetClass *klass) -{ - GObjectClass * gobject_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (UserWidgetPrivate)); - - gobject_class->dispose = user_widget_dispose; - gobject_class->finalize = user_widget_finalize; -} - -static void -user_widget_init (UserWidget *self) -{ - self->priv = USER_WIDGET_GET_PRIVATE(self); - - UserWidgetPrivate * priv = self->priv; - - priv->user_image = NULL; - priv->user_name = NULL; - priv->logged_in = FALSE; - priv->sessions_active = FALSE; - priv->container = NULL; - priv->tick_icon = NULL; - - // Create the UI elements. - priv->user_image = gtk_image_new (); - gtk_misc_set_alignment(GTK_MISC(priv->user_image), 0.0, 0.0); - - priv->user_name = gtk_label_new (NULL); - - priv->container = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4); - - priv->tick_icon = gtk_image_new_from_icon_name ("account-logged-in", - GTK_ICON_SIZE_MENU); - gtk_misc_set_alignment(GTK_MISC(priv->tick_icon), 1.0, 0.5); - - // Pack it together - gtk_box_pack_start (GTK_BOX (priv->container), - priv->user_image, - FALSE, - FALSE, - 0); - gtk_box_pack_start (GTK_BOX (priv->container), - priv->user_name, - FALSE, - FALSE, - 3); - gtk_box_pack_end (GTK_BOX(priv->container), - priv->tick_icon, - FALSE, - FALSE, 5); - - gtk_widget_show_all (priv->container); - gtk_container_add (GTK_CONTAINER (self), priv->container); - gtk_widget_show_all (priv->tick_icon); - gtk_widget_set_no_show_all (priv->tick_icon, TRUE); - gtk_widget_hide (priv->tick_icon); - - - // Fetch the drawing context. - g_signal_connect_after (GTK_WIDGET(self), "draw", - G_CALLBACK(user_widget_primitive_draw_cb_gtk_3), - GTK_WIDGET(self)); -} - -static void -user_widget_dispose (GObject *object) -{ - G_OBJECT_CLASS (user_widget_parent_class)->dispose (object); -} - -// TODO tidy up image and name -static void -user_widget_finalize (GObject *object) -{ - G_OBJECT_CLASS (user_widget_parent_class)->finalize (object); -} - - -/*****************************************************************/ - -// TODO handle drawing of green check mark -static gboolean -user_widget_primitive_draw_cb_gtk_3 (GtkWidget *widget, - cairo_t* cr, - gpointer user_data) -{ - g_return_val_if_fail(IS_USER_WIDGET(user_data), FALSE); - UserWidget* meta = USER_WIDGET(user_data); - UserWidgetPrivate * priv = USER_WIDGET_GET_PRIVATE(meta); - - // Draw dot only when user is the current user. - if (dbusmenu_menuitem_property_get_bool (priv->twin_item, USER_ITEM_PROP_IS_CURRENT_USER)) - { - gdouble x, y; - GtkStyle * style = gtk_widget_get_style (widget); - - GtkAllocation allocation; - gtk_widget_get_allocation (widget, &allocation); - x = allocation.x + 13; - y = allocation.height / 2; - - cairo_arc (cr, x, y, 3.0, 0.0, 2 * G_PI); - - cairo_set_source_rgb (cr, style->fg[gtk_widget_get_state(widget)].red/65535.0, - style->fg[gtk_widget_get_state(widget)].green/65535.0, - style->fg[gtk_widget_get_state(widget)].blue/65535.0); - cairo_fill (cr); - } - - return FALSE; -} - -/*** -**** -***/ - -static void -update_icon (UserWidget * self, DbusmenuMenuitem * mi) -{ - gboolean updated = FALSE; - GtkImage * image = GTK_IMAGE(self->priv->user_image); - - /* first try the menuitem's icon property */ - const gchar * icon_name = dbusmenu_menuitem_property_get (mi, USER_ITEM_PROP_ICON); - if (icon_name != NULL) - { - int width = 18; /* arbitrary default values */ - int height = 18; - GError * err = NULL; - GdkPixbuf * pixbuf = NULL; - - /* load the image */ - gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &width, &height); - pixbuf = gdk_pixbuf_new_from_file_at_size (icon_name, width, height, &err); - if (err == NULL) - { - gtk_image_set_from_pixbuf (image, pixbuf); - g_object_unref (pixbuf); - updated = TRUE; - } - else - { - g_warning ("Couldn't load the image \"%s\": %s", icon_name, err->message); - g_clear_error (&err); - } - } - - /* as a fallback, use the default user icon */ - if (!updated) - { - gtk_image_set_from_icon_name (image, - USER_ITEM_ICON_DEFAULT, - GTK_ICON_SIZE_MENU); - } -} - -static void -update_logged_in (UserWidget * self, DbusmenuMenuitem * mi) -{ - const gboolean b = dbusmenu_menuitem_property_get_bool (mi, USER_ITEM_PROP_LOGGED_IN); - - g_debug ("User \"%s\" %s active sessions", - dbusmenu_menuitem_property_get (mi, USER_ITEM_PROP_NAME), - b ? "has" : "doesn't have"); - - gtk_widget_set_visible (self->priv->tick_icon, b); -} - -static void -update_name (UserWidget * self, DbusmenuMenuitem * mi) -{ - gtk_label_set_label (GTK_LABEL(self->priv->user_name), - dbusmenu_menuitem_property_get (mi, USER_ITEM_PROP_NAME)); -} - -static void -user_widget_property_update (DbusmenuMenuitem * mi, - const gchar * property, - GVariant * value, - UserWidget * self) -{ - g_return_if_fail (IS_USER_WIDGET (self)); - - if (!g_strcmp0 (property, USER_ITEM_PROP_LOGGED_IN)) - { - update_logged_in (self, mi); - } - else if (!g_strcmp0 (property, USER_ITEM_PROP_ICON)) - { - update_icon (self, mi); - } - else if (!g_strcmp0 (property, USER_ITEM_PROP_NAME)) - { - update_name (self, mi); - } - else - { - g_debug ("%s FIXME: unhandled property change %s", G_STRFUNC, property); - } -} - -static void -user_widget_set_twin_item (UserWidget * self, DbusmenuMenuitem * mi) -{ - self->priv->twin_item = mi; - - update_icon (self, mi); - update_name (self, mi); - update_logged_in (self, mi); - - g_signal_connect (G_OBJECT(mi), "property-changed", - G_CALLBACK(user_widget_property_update), self); -} - - /** - * user_widget_new: - * @item: the #DbusmenuMenuitem this widget will render. - * - * Returns: (transfer full): a new #UserWidget. - **/ -GtkWidget* -user_widget_new (DbusmenuMenuitem *item) -{ - GtkWidget* widget = g_object_new(USER_WIDGET_TYPE, NULL); - user_widget_set_twin_item ( USER_WIDGET(widget), item ); - return widget; -} diff --git a/src/user-widget.h b/src/user-widget.h deleted file mode 100644 index 0953e6c..0000000 --- a/src/user-widget.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -Copyright 2011 Canonical Ltd. - -Authors: - Conor Curran - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . -*/ -#ifndef __USER_WIDGET_H__ -#define __USER_WIDGET_H__ - -#include -#include - -G_BEGIN_DECLS - -#define USER_WIDGET_TYPE (user_widget_get_type ()) -#define USER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), USER_WIDGET_TYPE, UserWidget)) -#define USER_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), USER_WIDGET_TYPE, UserWidgetClass)) -#define IS_USER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), USER_WIDGET_TYPE)) -#define IS_USER_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), USER_WIDGET_TYPE)) -#define USER_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), USER_WIDGET_TYPE, UserWidgetClass)) - -typedef struct _UserWidget UserWidget; -typedef struct _UserWidgetClass UserWidgetClass; -typedef struct _UserWidgetPrivate UserWidgetPrivate; - -struct _UserWidgetClass -{ - GtkMenuItemClass parent_class; -}; - -struct _UserWidget -{ - /*< private >*/ - GtkMenuItem parent; - UserWidgetPrivate * priv; -}; - -GType user_widget_get_type (void) G_GNUC_CONST; -GtkWidget* user_widget_new(DbusmenuMenuitem *twin_item); - -G_END_DECLS - -#endif diff --git a/src/users-service-dbus.c b/src/users-service-dbus.c deleted file mode 100644 index f12f47c..0000000 --- a/src/users-service-dbus.c +++ /dev/null @@ -1,1044 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */ -/* - * Copyright 2009 Canonical Ltd. - * - * Authors: - * Cody Russell - * Charles Kerr - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . - */ - -#ifdef HAVE_CONFIG_H - #include "config.h" -#endif - -#include - -#include - -#include /* getpwuid() */ - -#include "dbus-accounts.h" -#include "dbus-consolekit-manager.h" -#include "dbus-consolekit-seat.h" -#include "dbus-consolekit-session.h" -#include "dbus-display-manager.h" -#include "dbus-user.h" -#include "shared-names.h" -#include "users-service-dbus.h" - -#define CK_ADDR "org.freedesktop.ConsoleKit" -#define CK_SESSION_IFACE "org.freedesktop.ConsoleKit.Session" - -/** -*** -**/ - -static void update_user_list (UsersServiceDbus * self); - -static gchar* get_seat (UsersServiceDbus * service); - -static void on_user_added (Accounts * o, - const gchar * user_object_path, - UsersServiceDbus * service); - -static void on_user_deleted (Accounts * o, - const gchar * user_object_path, - UsersServiceDbus * service); - -static void on_session_added (ConsoleKitSeat * seat, - const gchar * ssid, - UsersServiceDbus * service); - -static void on_session_removed (ConsoleKitSeat * seat, - const gchar * ssid, - UsersServiceDbus * service); - -static void on_session_list (ConsoleKitSeat * seat, - GAsyncResult * result, - UsersServiceDbus * service); - -/*** -**** Priv Struct -***/ - -struct _UsersServiceDbusPrivate -{ - gchar * seat; - gchar * guest_ssid; - - /* ssid -> AccountsUser lookup */ - GHashTable * sessions; - - /* user object path -> AccountsUser lookup */ - GHashTable * users; - - GCancellable * cancellable; - ConsoleKitSeat * seat_proxy; - ConsoleKitManager * ck_manager_proxy; - Accounts * accounts_proxy; -}; - -/*** -**** GObject -***/ - -enum -{ - USER_LIST_CHANGED, - USER_LOGGED_IN_CHANGED, - GUEST_LOGGED_IN_CHANGED, - N_SIGNALS -}; - -static guint signals[N_SIGNALS] = { 0 }; - -G_DEFINE_TYPE (UsersServiceDbus, users_service_dbus, G_TYPE_OBJECT); - -static void -users_service_dbus_dispose (GObject *object) -{ - UsersServiceDbusPrivate * priv = USERS_SERVICE_DBUS(object)->priv; - - g_clear_object (&priv->accounts_proxy); - g_clear_object (&priv->seat_proxy); - g_clear_object (&priv->ck_manager_proxy); - - if (priv->cancellable != NULL) - { - g_cancellable_cancel (priv->cancellable); - g_clear_object (&priv->cancellable); - } - - if (priv->users != NULL) - { - g_hash_table_destroy (priv->users); - priv->users = NULL; - } - - if (priv->sessions != NULL) - { - g_hash_table_destroy (priv->sessions); - priv->sessions = NULL; - } - - G_OBJECT_CLASS (users_service_dbus_parent_class)->dispose (object); -} - -static void -users_service_dbus_finalize (GObject *object) -{ - UsersServiceDbusPrivate * priv = USERS_SERVICE_DBUS(object)->priv; - - g_free (priv->guest_ssid); - g_free (priv->seat); - - G_OBJECT_CLASS (users_service_dbus_parent_class)->finalize (object); -} - -static void -users_service_dbus_class_init (UsersServiceDbusClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (object_class, sizeof (UsersServiceDbusPrivate)); - - object_class->dispose = users_service_dbus_dispose; - object_class->finalize = users_service_dbus_finalize; - - signals[USER_LIST_CHANGED] = g_signal_new ( - "user-list-changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (UsersServiceDbusClass, user_list_changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - signals[USER_LOGGED_IN_CHANGED] = g_signal_new ( - "user-logged-in-changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (UsersServiceDbusClass, user_logged_in_changed), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); - - signals[GUEST_LOGGED_IN_CHANGED] = g_signal_new ( - "guest-logged-in-changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (UsersServiceDbusClass, guest_logged_in_changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); -} - -static void -users_service_dbus_init (UsersServiceDbus *self) -{ - GError * error = NULL; - - self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, - USERS_SERVICE_DBUS_TYPE, - UsersServiceDbusPrivate); - - UsersServiceDbusPrivate * p = self->priv; - - p->cancellable = g_cancellable_new (); - - /* ssid -> AccountsUser */ - p->sessions = g_hash_table_new_full (g_str_hash, - g_str_equal, - g_free, - g_object_unref); - - /* user object path -> AccountsUser */ - p->users = g_hash_table_new_full (g_str_hash, - g_str_equal, - g_free, - g_object_unref); - - /** - *** create the consolekit manager proxy... - **/ - - p->ck_manager_proxy = console_kit_manager_proxy_new_for_bus_sync ( - G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - "org.freedesktop.ConsoleKit", - "/org/freedesktop/ConsoleKit/Manager", - NULL, - &error); - if (error != NULL) - { - g_warning ("%s: %s", G_STRLOC, error->message); - g_clear_error (&error); - } - - p->seat = get_seat (self); - - /** - *** create the consolekit seat proxy... - **/ - - if (p->seat != NULL) - { - ConsoleKitSeat * proxy = console_kit_seat_proxy_new_for_bus_sync ( - G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - "org.freedesktop.ConsoleKit", - p->seat, - NULL, - &error); - - if (error != NULL) - { - g_warning ("Failed to connect to the ConsoleKit seat: %s", error->message); - g_clear_error (&error); - } - else - { - g_signal_connect (proxy, "session-added", - G_CALLBACK (on_session_added), self); - g_signal_connect (proxy, "session-removed", - G_CALLBACK (on_session_removed), self); - console_kit_seat_call_get_sessions (proxy, p->cancellable, - (GAsyncReadyCallback)on_session_list, self); - p->seat_proxy = proxy; - } - } - - /** - *** create the accounts manager proxy... - **/ - - Accounts * proxy = accounts_proxy_new_for_bus_sync ( - G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - "org.freedesktop.Accounts", - "/org/freedesktop/Accounts", - NULL, - &error); - if (error != NULL) - { - g_warning ("%s: %s", G_STRFUNC, error->message); - g_clear_error (&error); - } - else - { - g_signal_connect (proxy, "user-added", G_CALLBACK(on_user_added), self); - g_signal_connect (proxy, "user-deleted", G_CALLBACK(on_user_deleted), self); - p->accounts_proxy = proxy; - update_user_list (self); - } -} - -/*** -**** -***/ - -static void -emit_user_list_changed (UsersServiceDbus * self) -{ - g_signal_emit (self, signals[USER_LIST_CHANGED], 0); -} - -static void -emit_user_login_changed (UsersServiceDbus * self, AccountsUser * user) -{ - g_signal_emit (self, signals[USER_LOGGED_IN_CHANGED], 0, user); -} - -static void -emit_guest_login_changed (UsersServiceDbus * self) -{ - g_signal_emit (self, signals[GUEST_LOGGED_IN_CHANGED], 0); -} - -/*** -**** -***/ - -static ConsoleKitSession* -create_consolekit_session_proxy (const char * ssid) -{ - GError * error = NULL; - - ConsoleKitSession * p = console_kit_session_proxy_new_for_bus_sync ( - G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - CK_ADDR, - ssid, - NULL, - &error); - if (error != NULL) - { - g_warning ("%s: %s", G_STRLOC, error->message); - g_error_free (error); - } - - return p; -} - -static gchar * -get_seat_from_session_proxy (ConsoleKitSession * session_proxy) -{ - gchar * seat = NULL; - - GError * error = NULL; - console_kit_session_call_get_seat_id_sync (session_proxy, - &seat, - NULL, - &error); - if (error != NULL) - { - g_debug ("%s: %s", G_STRLOC, error->message); - g_error_free (error); - } - - return seat; -} - -static gchar * -get_seat (UsersServiceDbus *service) -{ - gchar * seat = NULL; - gchar * ssid = NULL; - GError * error = NULL; - UsersServiceDbusPrivate * priv = service->priv; - - console_kit_manager_call_get_current_session_sync (priv->ck_manager_proxy, - &ssid, - NULL, - &error); - - if (error != NULL) - { - g_debug ("%s: %s", G_STRLOC, error->message); - g_error_free (error); - } - else - { - ConsoleKitSession * session = create_consolekit_session_proxy (ssid); - - if (session != NULL) - { - seat = get_seat_from_session_proxy (session); - g_object_unref (session); - } - } - - return seat; -} - -/*** -**** AccountsUser add-ons for tracking sessions -***/ - -static GHashTable* -user_get_sessions_hashset (AccountsUser * user) -{ - static GQuark q = 0; - - if (G_UNLIKELY(!q)) - { - q = g_quark_from_static_string ("sessions"); - } - - GObject * o = G_OBJECT (user); - GHashTable * h = g_object_get_qdata (o, q); - if (h == NULL) - { - h = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - g_object_set_qdata_full (o, q, h, (GDestroyNotify)g_hash_table_destroy); - } - - return h; -} - -static void -user_add_session (AccountsUser * user, const char * ssid) -{ - g_hash_table_add (user_get_sessions_hashset(user), g_strdup(ssid)); -} - -static void -user_remove_session (AccountsUser * user, const char * ssid) -{ - g_hash_table_remove (user_get_sessions_hashset(user), ssid); -} - -static guint -user_count_sessions (AccountsUser * user) -{ - return g_hash_table_size (user_get_sessions_hashset(user)); -} - -/*** -**** Users -***/ - -/* adds this user session to the user's and service's session tables */ -static void -add_user_session (UsersServiceDbus * service, - AccountsUser * user, - const gchar * ssid) -{ - ConsoleKitSession * session_proxy = create_consolekit_session_proxy (ssid); - if (session_proxy != NULL) - { - UsersServiceDbusPrivate * priv = service->priv; - gchar * seat = get_seat_from_session_proxy (session_proxy); - - /* is this session in our seat? */ - if (seat && priv->seat && !g_strcmp0 (seat, priv->seat)) - { - /* does this session have a display? */ - gchar * display = NULL; - console_kit_session_call_get_x11_display_sync (session_proxy, - &display, - NULL, NULL); - const gboolean has_display = display && *display; - g_free (display); - - if (has_display) - { - const gchar * username = accounts_user_get_user_name (user); - g_debug ("%s adding %s's session '%s' to our tables", - G_STRLOC, username, ssid); - - g_hash_table_insert (priv->sessions, - g_strdup (ssid), - g_object_ref (user)); - - user_add_session (user, ssid); - } - } - - g_free (seat); - g_object_unref (session_proxy); - } -} - -/* calls add_user_session() for each of this user's sessions */ -static void -add_user_sessions (UsersServiceDbus *self, AccountsUser * user) -{ - const guint64 uid = accounts_user_get_uid (user); - const char * username = accounts_user_get_user_name (user); - g_debug ("%s adding %s (%i)", G_STRLOC, username, (int)uid); - - GError * error = NULL; - gchar ** sessions = NULL; - console_kit_manager_call_get_sessions_for_unix_user_sync ( - self->priv->ck_manager_proxy, - uid, - &sessions, - NULL, - &error); - - if (error != NULL) - { - g_debug ("%s: %s", G_STRLOC, error->message); - g_error_free (error); - } - else if (sessions != NULL) - { - int i; - - for (i=0; sessions[i]; i++) - { - const char * const ssid = sessions[i]; - g_debug ("%s adding %s's session %s", G_STRLOC, username, ssid); - add_user_session (self, user, ssid); - } - - g_strfreev (sessions); - } -} - -/* returns true if this property is one we use */ -static gboolean -is_interesting_user_property (const char * key) -{ - return !g_strcmp0 (key, "IconFile") - || !g_strcmp0 (key, "LoginFrequency") - || !g_strcmp0 (key, "RealName") - || !g_strcmp0 (key, "Uid") - || !g_strcmp0 (key, "UserName"); -} - -static void -sync_user_properties (GDBusProxy * source, GDBusProxy * target) -{ - gchar ** keys = g_dbus_proxy_get_cached_property_names (source); - - if (keys != NULL) - { - int i; - GVariantBuilder builder; - gboolean changed = FALSE; - g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); - - for (i=0; keys[i]; i++) - { - const gchar * const key = keys[i]; - - if (is_interesting_user_property (key)) - { - GVariant * oldval = g_dbus_proxy_get_cached_property (target, key); - GVariant * newval = g_dbus_proxy_get_cached_property (source, key); - - /* all the properties we're interested in are - basic types safe for g_variant_compare()... */ - g_assert (g_variant_type_is_basic(g_variant_get_type(newval))); - - if (g_variant_compare (oldval, newval)) - { - changed = TRUE; - g_dbus_proxy_set_cached_property (target, key, newval); - g_variant_builder_add (&builder, "{sv}", key, newval); - } - - g_variant_unref (newval); - g_variant_unref (oldval); - } - } - - if (changed) - { - g_signal_emit_by_name (target, "g-properties-changed", g_variant_builder_end(&builder), keys); - } - - g_variant_builder_clear (&builder); - g_strfreev (keys); - } -} - -/** - * The AccountsUserProxy's properties aren't being updated automatically - * for some reason... the only update we get is the 'changed' signal. - * This function is a workaround to update our User object's properties. - */ -static void -on_user_changed (AccountsUser * user, UsersServiceDbus * service) -{ - AccountsUser * tmp = accounts_user_proxy_new_for_bus_sync ( - G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - "org.freedesktop.Accounts", - g_dbus_proxy_get_object_path (G_DBUS_PROXY(user)), - NULL, - NULL); - if (tmp != NULL) - { - sync_user_properties (G_DBUS_PROXY(tmp), G_DBUS_PROXY(user)); - g_object_unref (tmp); - } -} - -static void -add_user_from_object_path (UsersServiceDbus * self, - const char * user_object_path) -{ - GError * error = NULL; - - AccountsUser * user = accounts_user_proxy_new_for_bus_sync ( - G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - "org.freedesktop.Accounts", - user_object_path, - NULL, - &error); - - if (error != NULL) - { - g_warning ("%s: %s", G_STRLOC, error->message); - g_clear_error (&error); - } - else - { - AccountsUser * prev = g_hash_table_lookup (self->priv->users, user_object_path); - - if (prev != NULL) /* we've already got this user... sync its properties */ - { - sync_user_properties (G_DBUS_PROXY(user), G_DBUS_PROXY(prev)); - g_object_unref (user); - user = prev; - } - else /* ooo, we got a new user */ - { - g_signal_connect (user, "changed", G_CALLBACK(on_user_changed), self); - g_hash_table_insert (self->priv->users, g_strdup(user_object_path), user); - } - - add_user_sessions (self, user); - } -} - - -/* asks org.freedesktop.Accounts for a list of users and - * calls add_user_from_object_path() on each of those users */ -static void -update_user_list (UsersServiceDbus *self) -{ - g_return_if_fail(IS_USERS_SERVICE_DBUS(self)); - - GError * error = NULL; - char ** object_paths = NULL; - UsersServiceDbusPrivate * priv = self->priv; - - accounts_call_list_cached_users_sync (priv->accounts_proxy, - &object_paths, - NULL, - &error); - - if (error != NULL) - { - g_warning ("%s: %s", G_STRFUNC, error->message); - g_clear_error (&error); - } - else if (object_paths != NULL) - { - gint i; - - for (i=0; object_paths[i] != NULL; ++i) - { - add_user_from_object_path (self, object_paths[i]); - } - - emit_user_list_changed (self); - - g_strfreev (object_paths); - } - - g_debug ("%s finished updating the user list", G_STRLOC); -} - -static void -on_user_added (Accounts * o G_GNUC_UNUSED, - const gchar * user_path G_GNUC_UNUSED, - UsersServiceDbus * service) -{ - /* We see a new user but we might not want to list it -- - for example, lightdm shows up when we switch to the greeter. - So instead of adding the user directly here, let's ask - org.freedesktop.Accounts for a fresh list of users - because it filters out special cases. */ - update_user_list (service); -} - -static void -on_user_deleted (Accounts * o G_GNUC_UNUSED, - const gchar * user_path, - UsersServiceDbus * service) -{ - AccountsUser * user = g_hash_table_lookup (service->priv->users, user_path); - - if (user != NULL) - { - GObject * o = g_object_ref (G_OBJECT(user)); - g_hash_table_remove (service->priv->users, user_path); - emit_user_list_changed (service); - g_object_unref (o); - } -} - -static AccountsUser * -find_user_from_username (UsersServiceDbus * self, - const gchar * username) -{ - AccountsUser * match = NULL; - - g_return_val_if_fail (IS_USERS_SERVICE_DBUS(self), match); - - gpointer user; - GHashTableIter iter; - g_hash_table_iter_init (&iter, self->priv->users); - while (!match && g_hash_table_iter_next (&iter, NULL, &user)) - { - if (!g_strcmp0 (username, accounts_user_get_user_name (user))) - { - match = user; - } - } - - return match; -} - -/*** -**** Sessions -***/ - -static void -on_session_removed (ConsoleKitSeat * seat_proxy, - const gchar * ssid, - UsersServiceDbus * service) -{ - g_return_if_fail (IS_USERS_SERVICE_DBUS (service)); - - UsersServiceDbusPrivate * priv = service->priv; - g_debug ("%s %s() session removed %s", G_STRLOC, G_STRFUNC, ssid); - - if (!g_strcmp0 (ssid, priv->guest_ssid)) - { - g_debug ("%s removing guest session %s", G_STRLOC, ssid); - g_clear_pointer (&priv->guest_ssid, g_free); - emit_guest_login_changed (service); - } - else - { - AccountsUser * user = g_hash_table_lookup (priv->sessions, ssid); - if (user == NULL) - { - g_debug ("%s we're not tracking ssid %s", G_STRLOC, ssid); - } - else - { - GObject * o = g_object_ref (G_OBJECT(user)); - g_hash_table_remove (service->priv->users, ssid); - user_remove_session (user, ssid); - emit_user_login_changed (service, user); - g_object_unref (o); - } - } -} - -static gchar* -get_unix_username_from_ssid (UsersServiceDbus * self, - const gchar * ssid) -{ - gchar * username = NULL; - - ConsoleKitSession * session_proxy = create_consolekit_session_proxy (ssid); - if (session_proxy != NULL) - { - guint uid = 0; - GError * error = NULL; - console_kit_session_call_get_unix_user_sync (session_proxy, - &uid, - NULL, &error); - if (error != NULL) - { - g_warning ("%s: %s", G_STRLOC, error->message); - g_clear_error (&error); - } - else - { - errno = 0; - const struct passwd * pwent = getpwuid (uid); - if (pwent == NULL) - { - g_warning ("Failed to lookup user id %d: %s", (int)uid, g_strerror(errno)); - } - else - { - username = g_strdup (pwent->pw_name); - } - } - - g_object_unref (session_proxy); - } - - return username; -} - -static gboolean -is_guest_username (const char * username) -{ - if (!g_strcmp0 (username, "guest")) - return TRUE; - - if (username && g_str_has_prefix (username, "guest-")) - return TRUE; - - return FALSE; -} - -/* If the new session belongs to 'guest', update our guest_ssid. - Otherwise, call add_user_session() to update our session tables */ -static void -on_session_added (ConsoleKitSeat * seat_proxy G_GNUC_UNUSED, - const gchar * ssid, - UsersServiceDbus * service) -{ - g_return_if_fail (IS_USERS_SERVICE_DBUS(service)); - - gchar * username = get_unix_username_from_ssid (service, ssid); - g_debug ("%s %s() username %s has new session %s", G_STRLOC, G_STRFUNC, username, ssid); - - if (is_guest_username (username)) - { - /* handle guest as a special case -- it's not in the GDM - user tables and there isn't be an AccountsUser for it */ - g_debug("Found guest session: %s", ssid); - g_free (service->priv->guest_ssid); - service->priv->guest_ssid = g_strdup (ssid); - emit_guest_login_changed (service); - } - else - { - AccountsUser * user = find_user_from_username (service, username); - - if (user != NULL) - { - add_user_session (service, user, ssid); - emit_user_login_changed (service, user); - } - } - - g_free (username); -} - -/* Receives a list of sessions and calls on_session_added() for each of them */ -static void -on_session_list (ConsoleKitSeat * seat_proxy, - GAsyncResult * result, - UsersServiceDbus * self) -{ - GError * error = NULL; - gchar ** sessions = NULL; - g_debug ("%s bootstrapping the session list", G_STRLOC); - - console_kit_seat_call_get_sessions_finish (seat_proxy, - &sessions, - result, - &error); - - if (error != NULL) - { - g_debug ("%s: %s", G_STRLOC, error->message); - g_error_free (error); - } - else if (sessions != NULL) - { - int i; - - for (i=0; sessions[i]; i++) - { - g_debug ("%s adding initial session '%s'", G_STRLOC, sessions[i]); - on_session_added (seat_proxy, sessions[i], self); - } - - g_strfreev (sessions); - } - - g_debug ("%s done bootstrapping the session list", G_STRLOC); -} - -static DisplayManagerSeat * -create_display_proxy (UsersServiceDbus * self) -{ - const gchar * const seat = g_getenv ("XDG_SEAT_PATH"); - g_debug ("%s creating a DisplayManager proxy for seat %s", G_STRLOC, seat); - - GError * error = NULL; - DisplayManagerSeat * p = display_manager_seat_proxy_new_for_bus_sync ( - G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - "org.freedesktop.DisplayManager", - seat, - NULL, - &error); - - if (error != NULL) - { - g_warning ("%s: %s", G_STRLOC, error->message); - g_error_free (error); - } - - return p; -} - -/*** -**** Public API -***/ - -/** - * users_service_dbus_get_user_list: - * - * Returns: (transfer container): a list of AccountsUser objects - */ -GList * -users_service_dbus_get_user_list (UsersServiceDbus * self) -{ - g_return_val_if_fail(IS_USERS_SERVICE_DBUS(self), NULL); - - return g_hash_table_get_values (self->priv->users); -} - -/** - * users_service_dbus_show_greeter: - * - * Ask the Display Mnaager to switch to the greeter screen. - */ -void -users_service_dbus_show_greeter (UsersServiceDbus * self) -{ - DisplayManagerSeat * dp; - - g_return_if_fail (IS_USERS_SERVICE_DBUS(self)); - - dp = create_display_proxy (self); - if (dp != NULL) - { - display_manager_seat_call_switch_to_greeter_sync (dp, NULL, NULL); - g_clear_object (&dp); - } -} - -/** - * users_service_dbus_activate_guest_session: - * - * Activates the guest account. - */ -void -users_service_dbus_activate_guest_session (UsersServiceDbus * self) -{ - DisplayManagerSeat * dp; - - g_return_if_fail (IS_USERS_SERVICE_DBUS(self)); - - dp = create_display_proxy (self); - if (dp != NULL) - { - display_manager_seat_call_switch_to_guest_sync (dp, "", NULL, NULL); - g_clear_object (&dp); - } -} - -/** - * users_service_dbus_activate_user_session: - * - * Activates a specific user. - */ -void -users_service_dbus_activate_user_session (UsersServiceDbus * self, - AccountsUser * user) -{ - DisplayManagerSeat * dp; - - g_return_if_fail (IS_USERS_SERVICE_DBUS(self)); - - dp = create_display_proxy (self); - if (dp != NULL) - { - const char * const username = accounts_user_get_user_name (user); - display_manager_seat_call_switch_to_user_sync (dp, username, "", NULL, NULL); - g_clear_object (&dp); - } -} - -/** - * users_service_dbus_guest_session_enabled: - * - * Tells whether or not guest sessions are allowed. - */ -gboolean -users_service_dbus_guest_session_enabled (UsersServiceDbus * self) -{ - DisplayManagerSeat * dp; - gboolean enabled = FALSE; - - g_return_val_if_fail (IS_USERS_SERVICE_DBUS(self), enabled); - - dp = create_display_proxy (self); - if (dp != NULL) - { - enabled = display_manager_seat_get_has_guest_account (dp); - g_clear_object (&dp); - } - - return enabled; -} - -gboolean -users_service_dbus_can_activate_session (UsersServiceDbus * self) -{ - gboolean can_activate = FALSE; - - g_return_val_if_fail (IS_USERS_SERVICE_DBUS(self), can_activate); - - GError * error = NULL; - console_kit_seat_call_can_activate_sessions_sync (self->priv->seat_proxy, - &can_activate, - NULL, - &error); - if (error != NULL) - { - g_warning ("%s: %s", G_STRLOC, error->message); - g_error_free (error); - } - - return can_activate; -} - -gboolean -users_service_dbus_is_guest_logged_in (UsersServiceDbus * self) -{ - g_return_val_if_fail (IS_USERS_SERVICE_DBUS(self), FALSE); - - return self->priv->guest_ssid != NULL; -} - -gboolean -users_service_dbus_is_user_logged_in (UsersServiceDbus * self, - AccountsUser * user) -{ - g_return_val_if_fail (IS_USERS_SERVICE_DBUS(self), FALSE); - g_return_val_if_fail (IS_ACCOUNTS_USER(user), FALSE); - - return user_count_sessions (user) > 0; -} diff --git a/src/users-service-dbus.h b/src/users-service-dbus.h deleted file mode 100644 index 0f082c3..0000000 --- a/src/users-service-dbus.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2009 Canonical Ltd. - * - * Authors: - * Cody Russell - * Charles Kerr - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . - */ - -#ifndef __USERS_SERVICE_DBUS_H__ -#define __USERS_SERVICE_DBUS_H__ - -#include -#include - -#include "dbus-user.h" /* for AccountsUser */ - -G_BEGIN_DECLS - -#define USERS_SERVICE_DBUS_TYPE (users_service_dbus_get_type ()) -#define USERS_SERVICE_DBUS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), USERS_SERVICE_DBUS_TYPE, UsersServiceDbus)) -#define IS_USERS_SERVICE_DBUS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), USERS_SERVICE_DBUS_TYPE)) - -typedef struct _UsersServiceDbus UsersServiceDbus; -typedef struct _UsersServiceDbusClass UsersServiceDbusClass; -typedef struct _UsersServiceDbusPrivate UsersServiceDbusPrivate; - -/** - * A facade class which interacts with multiple DBus services to - * track info which is useful to the interactor's user menu: - * - * 1. A list of users to add to the user menu. - * - * Each user is an AccountsUser object, which is a GDBusProxy - * to an org.freedesktop.Accounts.User object. - * - * We initially build this list by calling org.freedesktop.Accounts' - * GetCachedUsers method. We also monitor o.f.Accounts' UserAdded - * and UserDeleted and update the list accordingly. - * - * 2. Track which users currently have X sessions. - * This is used for the menuitems' USER_ITEM_PROP_LOGGED_IN property. - * - * We initially build this list by calling org.freedesktop.ConsoleKit.Seat's - * GetDevices method. We also monitor the seat for SessionAdded and - * SessionRemoved and update the list accordingly. - * - * 3. Provide an API for user switching and guest sessions. - * These are typically pass-through functions to GDBusProxies. - * - */ -struct _UsersServiceDbus -{ - /*< private >*/ - GObject parent; - UsersServiceDbusPrivate * priv; -}; - -struct _UsersServiceDbusClass -{ - GObjectClass parent_class; - - /* Signals */ - void (* user_list_changed) (UsersServiceDbus*, gpointer); - void (* user_logged_in_changed) (UsersServiceDbus*, AccountsUser*, gpointer); - void (* guest_logged_in_changed) (UsersServiceDbus*, gpointer); -}; - -GType users_service_dbus_get_type (void) G_GNUC_CONST; - -GList * users_service_dbus_get_user_list (UsersServiceDbus * self); - -gboolean users_service_dbus_is_guest_logged_in (UsersServiceDbus * self); -gboolean users_service_dbus_is_user_logged_in (UsersServiceDbus * self, - AccountsUser * user); - -void users_service_dbus_show_greeter (UsersServiceDbus * self); -gboolean users_service_dbus_guest_session_enabled (UsersServiceDbus * self); -gboolean users_service_dbus_can_activate_session (UsersServiceDbus * self); -void users_service_dbus_activate_guest_session (UsersServiceDbus * self); -void users_service_dbus_activate_user_session (UsersServiceDbus * self, - AccountsUser * user); - -G_END_DECLS - -#endif diff --git a/src/users.c b/src/users.c new file mode 100644 index 0000000..4b9c0ad --- /dev/null +++ b/src/users.c @@ -0,0 +1,198 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include "users.h" + +/* signals enum */ +enum +{ + USER_ADDED, + USER_REMOVED, + USER_CHANGED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE (IndicatorSessionUsers, indicator_session_users, G_TYPE_OBJECT) + +enum +{ + PROP_0, + PROP_IS_LIVE_SESSION, + PROP_LAST +}; + +static GParamSpec *properties[PROP_LAST]; + +static void +my_get_property (GObject * o, + guint property_id, + GValue * value, + GParamSpec * pspec) +{ + IndicatorSessionUsers * self = INDICATOR_SESSION_USERS (o); + + switch (property_id) + { + case PROP_IS_LIVE_SESSION: + g_value_set_boolean (value, indicator_session_users_is_live_session (self)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (o, property_id, pspec); + } +} + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_users_class_init (IndicatorSessionUsersClass * klass) +{ + GObjectClass * object_class; + const GParamFlags flags = G_PARAM_READABLE | G_PARAM_STATIC_STRINGS; + + object_class = G_OBJECT_CLASS (klass); + object_class->get_property = my_get_property; + + signals[USER_ADDED] = g_signal_new (INDICATOR_SESSION_USERS_SIGNAL_USER_ADDED, + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (IndicatorSessionUsersClass, user_added), + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); + + signals[USER_REMOVED] = g_signal_new (INDICATOR_SESSION_USERS_SIGNAL_USER_REMOVED, + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (IndicatorSessionUsersClass, user_removed), + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); + + signals[USER_CHANGED] = g_signal_new (INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (IndicatorSessionUsersClass, user_changed), + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); + + + properties[PROP_IS_LIVE_SESSION] = + g_param_spec_boolean (INDICATOR_SESSION_USERS_PROP_IS_LIVE_SESSION, + "Is Live Session", + "Whether or this is a 'live session', such as booting from a live CD", + FALSE, flags); + + g_object_class_install_properties (object_class, PROP_LAST, properties); + +} + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_users_init (IndicatorSessionUsers * self G_GNUC_UNUSED) +{ +} + +/*** +**** Virtual Functions +***/ + +GStrv +indicator_session_users_get_keys (IndicatorSessionUsers * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_USERS (self), NULL); + + return INDICATOR_SESSION_USERS_GET_CLASS (self)->get_keys (self); +} + +IndicatorSessionUser * +indicator_session_users_get_user (IndicatorSessionUsers * self, + const char * key) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_USERS (self), NULL); + + return INDICATOR_SESSION_USERS_GET_CLASS (self)->get_user (self, key); +} + +void +indicator_session_users_activate_user (IndicatorSessionUsers * self, + const char * key) +{ + g_return_if_fail (INDICATOR_IS_SESSION_USERS (self)); + + INDICATOR_SESSION_USERS_GET_CLASS (self)->activate_user (self, key); +} + +gboolean +indicator_session_users_is_live_session (IndicatorSessionUsers * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_USERS (self), FALSE); + + return INDICATOR_SESSION_USERS_GET_CLASS (self)->is_live_session (self); +} + +void +indicator_session_user_free (IndicatorSessionUser * user) +{ + g_return_if_fail (user != NULL); + + g_free (user->real_name); + g_free (user->user_name); + g_free (user->icon_file); + g_free (user); +} + +/*** +**** Signal Convenience +***/ + +void +indicator_session_users_added (IndicatorSessionUsers * self, const char * key) +{ + g_return_if_fail (INDICATOR_IS_SESSION_USERS (self)); + + g_signal_emit (self, signals[USER_ADDED], 0, key); +} + +void +indicator_session_users_removed (IndicatorSessionUsers * self, const char * key) +{ + g_return_if_fail (INDICATOR_IS_SESSION_USERS (self)); + + g_signal_emit (self, signals[USER_REMOVED], 0, key); +} + +void +indicator_session_users_changed (IndicatorSessionUsers * self, const char * key) +{ + g_return_if_fail (INDICATOR_IS_SESSION_USERS (self)); + + g_signal_emit (self, signals[USER_CHANGED], 0, key); +} + +void +indicator_session_users_notify_is_live_session (IndicatorSessionUsers * self) +{ + g_return_if_fail (INDICATOR_IS_SESSION_USERS (self)); + + g_object_notify_by_pspec (G_OBJECT(self), properties[PROP_IS_LIVE_SESSION]); +} + diff --git a/src/users.h b/src/users.h new file mode 100644 index 0000000..31ee39e --- /dev/null +++ b/src/users.h @@ -0,0 +1,146 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#ifndef __USERS_H__ +#define __USERS_H__ + +#include +#include + +G_BEGIN_DECLS + +#define INDICATOR_TYPE_SESSION_USERS (indicator_session_users_get_type()) +#define INDICATOR_SESSION_USERS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_SESSION_USERS, IndicatorSessionUsers)) +#define INDICATOR_SESSION_USERS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_SESSION_USERS, IndicatorSessionUsersClass)) +#define INDICATOR_SESSION_USERS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), INDICATOR_TYPE_SESSION_USERS, IndicatorSessionUsersClass)) +#define INDICATOR_IS_SESSION_USERS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_SESSION_USERS)) + + +typedef struct _IndicatorSessionUser IndicatorSessionUser; +typedef struct _IndicatorSessionUsers IndicatorSessionUsers; +typedef struct _IndicatorSessionUsersClass IndicatorSessionUsersClass; + +/** + * A base class for monitoring the system's users and active sessions. + * Use backend.h's get_backend() to get an instance. + */ +struct _IndicatorSessionUsers +{ + /*< private >*/ + GObject parent; +}; + +struct _IndicatorSessionUser +{ + gboolean is_current_user; + gboolean is_logged_in; + guint uid; + guint64 login_frequency; + gchar * user_name; + gchar * real_name; + gchar * icon_file; +}; + +/* signal keys */ +#define INDICATOR_SESSION_USERS_SIGNAL_USER_ADDED "user-added" +#define INDICATOR_SESSION_USERS_SIGNAL_USER_REMOVED "user-removed" +#define INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED "user-changed" + +/* property keys */ +#define INDICATOR_SESSION_USERS_PROP_IS_LIVE_SESSION "is-live-session" + +struct _IndicatorSessionUsersClass +{ + GObjectClass parent_class; + + /* signals */ + + void (* user_added) (IndicatorSessionUsers * self, + const gchar * key); + + void (* user_removed) (IndicatorSessionUsers * self, + const gchar * key); + + void (* user_changed) (IndicatorSessionUsers * self, + const gchar * key); + + + /* pure virtual functions */ + + gboolean (* is_live_session) (IndicatorSessionUsers * self); + + + GStrv (* get_keys) (IndicatorSessionUsers * self); + + IndicatorSessionUser * (* get_user) (IndicatorSessionUsers * self, + const gchar * key); + + void ( * activate_user) (IndicatorSessionUsers * self, + const gchar * key); +}; + +/*** +**** +***/ + +GType indicator_session_users_get_type (void); + +/* emits the "user-added" signal */ +void indicator_session_users_added (IndicatorSessionUsers * self, + const gchar * key); + +/* emits the "user-removed" signal */ +void indicator_session_users_removed (IndicatorSessionUsers * self, + const gchar * key); + +/* emits the "user-changed" signal */ +void indicator_session_users_changed (IndicatorSessionUsers * self, + const gchar * key); + +/* notify listeners of a change to the 'is-live-session' property */ +void indicator_session_users_notify_is_live_session (IndicatorSessionUsers * self); + + + +/*** +**** +***/ + +gboolean indicator_session_users_is_live_session (IndicatorSessionUsers * users); + +/* get a list of user keys */ +GStrv indicator_session_users_get_keys (IndicatorSessionUsers * users); + +/* get information about a particular user. + call indicator_session_user_free() when done with the returned struct. */ +IndicatorSessionUser * +indicator_session_users_get_user (IndicatorSessionUsers * users, + const gchar * key); + +/* frees a IndicatorSessionUser struct */ +void indicator_session_user_free (IndicatorSessionUser * user); + +/* activate to a different session */ +void indicator_session_users_activate_user (IndicatorSessionUsers * self, + const char * key); + + +G_END_DECLS + +#endif diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..45ab69f --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,53 @@ +# build the necessary schemas +set_directory_properties (PROPERTIES + ADDITIONAL_MAKE_CLEAN_FILES gschemas.compiled) +set_source_files_properties (gschemas.compiled GENERATED) + +# GSettings: +# compile the schemas our tests use (indicator-session's, lockdown, media-keys) +# into a gschemas.compiled file in this directory, and help the tests to find +# that file by setting -DSCHEMA_DIR +set (SCHEMA_DIR ${CMAKE_CURRENT_BINARY_DIR}) +add_definitions(-DSCHEMA_DIR="${SCHEMA_DIR}") +execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} gio-2.0 --variable glib_compile_schemas + OUTPUT_VARIABLE COMPILE_SCHEMA_EXECUTABLE + OUTPUT_STRIP_TRAILING_WHITESPACE) +add_custom_command (OUTPUT gschemas.compiled + DEPENDS ${CMAKE_BINARY_DIR}/data/com.canonical.indicator.session.gschema.xml + ${CMAKE_SOURCE_DIR}/tests/com.canonical.indicator.session.backendmock.gschema.xml + ${CMAKE_SOURCE_DIR}/tests/org.gnome.desktop.lockdown.gschema.xml + ${CMAKE_SOURCE_DIR}/tests/org.gnome.settings-daemon.plugins.media-keys.gschema.xml + COMMAND cp -f ${CMAKE_BINARY_DIR}/data/*gschema.xml ${SCHEMA_DIR} + COMMAND cp -f ${CMAKE_SOURCE_DIR}/tests/*gschema.xml ${SCHEMA_DIR} + COMMAND ${COMPILE_SCHEMA_EXECUTABLE} ${SCHEMA_DIR}) + +# DBus Activation +configure_file (indicator-session.service.in indicator-session.service) +add_definitions(-DINDICATOR_SERVICE_DIR="${CMAKE_CURRENT_BINARY_DIR}") + +# look for hearder in our src dir, and also in the directories where we autogenerate files... +include_directories (${CMAKE_SOURCE_DIR}/src) +include_directories (${CMAKE_CURRENT_BINARY_DIR} ${SERVICE_INCLUDE_DIRS}) + +# backendmock +add_library (backendmock STATIC + backend-mock-actions.c + backend-mock-actions.h + backend-mock.c + backend-mock.h + backend-mock-guest.c + backend-mock-guest.h + backend-mock-users.c + backend-mock-users.h) +set_target_properties (backendmock PROPERTIES COMPILE_FLAGS " ${CC_WARNING_ARGS}") + +# test-service +add_executable (test-service + test-service.cc + gschemas.compiled) +set_target_properties (test-service PROPERTIES COMPILE_FLAGS " ${CC_WARNING_ARGS}") +add_test (test-service test-service) +add_dependencies (test-service libindicatorsessionservice backendmock) +target_link_libraries (test-service libindicatorsessionservice backendmock gtest ${SERVICE_LIBRARIES} ${GTEST_LIBS}) + +add_subdirectory (backend-dbus) diff --git a/tests/Makefile.am b/tests/Makefile.am deleted file mode 100644 index 071f684..0000000 --- a/tests/Makefile.am +++ /dev/null @@ -1,51 +0,0 @@ -TESTS = -CLEANFILES = -BUILT_SOURCES = -check_PROGRAMS = - -integrationcheckdir = . -integrationcheck_PROGRAMS = - -### -### -### - -# stock UMB tests on user-visible strings -include $(srcdir)/Makefile.am.strings - -check_LIBRARIES = libgtest.a -nodist_libgtest_a_SOURCES = \ - $(GTEST_SOURCE)/gtest-all.cc \ - $(GTEST_SOURCE)/gtest_main.cc - -AM_CPPFLAGS = $(GTEST_CPPFLAGS) -I${top_srcdir}/src -Wall -Werror -AM_CXXFLAGS = $(GTEST_CXXFLAGS) - -### -### -### - -BUILT_SOURCES += gschemas.compiled -CLEANFILES += gschemas.compiled -gschemas.compiled: Makefile - $(AM_V_at) cp -f $(top_builddir)/data/*gschema.xml . - $(AM_V_GEN) $(GLIB_COMPILE_SCHEMAS) --targetdir=. . - - -integrationcheck: - ./test-service - -integrationcheck_PROGRAMS += test-service -test_service_SOURCES = test-service.cc -test_service_LDADD = \ - $(TEST_SERVICE_LIBS) \ - $(XORG_GTEST_LDFLAGS) \ - libgtest.a -test_service_CPPFLAGS = \ - -DSCHEMA_DIR="\"$(top_builddir)/tests/\"" \ - -DINDICATOR_SERVICE_DIR="\"$(abs_builddir)\"" \ - -DINDICATOR_SERVICE_PATH="\"$(top_builddir)/src/indicator-session-service\"" \ - $(TEST_SERVICE_CFLAGS) \ - $(AM_CPPFLAGS) - - diff --git a/tests/Makefile.am.strings b/tests/Makefile.am.strings deleted file mode 100644 index 26a23a8..0000000 --- a/tests/Makefile.am.strings +++ /dev/null @@ -1,38 +0,0 @@ -TESTS += \ - test-ellipsis \ - test-space-ellipsis \ - test-ascii-quotes - -##### -# Tests for there being proper ellipsis instead of three periods in a row -##### -test-ellipsis: $(top_srcdir)/po - @echo "#!/bin/bash" > $@ - @echo "(cd $(top_srcdir)/po && make $(GETTEXT_PACKAGE).pot)" >> $@ - @echo "grep -c -e \"^msgid.*\.\.\.\\\"\" $(top_srcdir)/po/$(GETTEXT_PACKAGE).pot > /dev/null && echo \"Ellipsis found in user visible strings\" >&2 && exit 1" >> $@ - @echo "exit 0" >> $@ - @chmod +x $@ - -##### -# Tests for there being a space before an ellipsis -##### -test-space-ellipsis: $(top_srcdir)/po - @echo "#!/bin/bash" > $@ - @echo "(cd $(top_srcdir)/po && make $(GETTEXT_PACKAGE).pot)" >> $@ - @echo "grep -c -e \"^msgid.* …\\\"\" $(top_srcdir)/po/$(GETTEXT_PACKAGE).pot > /dev/null && echo \"Space before ellipsis found in user visible strings\" >&2 && exit 1" >> $@ - @echo "exit 0" >> $@ - @chmod +x $@ - -##### -# Tests for ASCII quote types -##### -test-ascii-quotes: $(top_srcdir)/po - @echo "#!/bin/bash" > $@ - @echo "(cd $(top_srcdir)/po && make $(GETTEXT_PACKAGE).pot)" >> $@ - @echo "grep -c -e \"^msgid \\\".*'.*\\\"\" $(top_srcdir)/po/$(GETTEXT_PACKAGE).pot > /dev/null && echo \"ASCII apostrophy found in user visible strings\" >&2 && exit 1" >> $@ - @echo "grep -c -e \"^msgid \\\".*\\\".*\\\"\" $(top_srcdir)/po/$(GETTEXT_PACKAGE).pot > /dev/null && echo \"ASCII quote found in user visible strings\" >&2 && exit 1" >> $@ - @echo "grep -c -e \"^msgid \\\".*\\\`.*\\\"\" $(top_srcdir)/po/$(GETTEXT_PACKAGE).pot > /dev/null && echo \"ASCII backtick found in user visible strings\" >&2 && exit 1" >> $@ - @echo "exit 0" >> $@ - @chmod +x $@ - -CLEANFILES += $(TESTS) diff --git a/tests/backend-dbus/CMakeLists.txt b/tests/backend-dbus/CMakeLists.txt new file mode 100644 index 0000000..7cd7030 --- /dev/null +++ b/tests/backend-dbus/CMakeLists.txt @@ -0,0 +1,62 @@ +# build libgtest +add_library (gtest STATIC + ${GTEST_SOURCE_DIR}/gtest-all.cc + ${GTEST_SOURCE_DIR}/gtest_main.cc) +set_target_properties (gtest PROPERTIES INCLUDE_DIRECTORIES + ${GTEST_INCLUDE_DIR}) + +# build desktopmock +add_library (desktopmock STATIC + mock-accounts.cc + mock-accounts.h + mock-consolekit-manager.cc + mock-consolekit-manager.h + mock-consolekit-seat.cc + mock-consolekit-seat.h + mock-consolekit-session.cc + mock-consolekit-session.h + mock-display-manager-seat.cc + mock-display-manager-seat.h + mock-end-session-dialog.cc + mock-end-session-dialog.h + mock-object.cc + mock-object.h + mock-screen-saver.cc + mock-screen-saver.h + mock-session-manager.cc + mock-session-manager.h + mock-upower.cc + mock-upower.h + mock-user.cc + mock-user.h + mock-webcredentials.cc + mock-webcredentials.h) + +include_directories (${SERVICE_INCLUDE_DIRS}) +include_directories (${CMAKE_SOURCE_DIR}/src) +include_directories (${CMAKE_BINARY_DIR}/src) +include_directories (${CMAKE_SOURCE_DIR}/tests) + +# test the Actions class +add_executable (test-actions + test-actions.cc) +add_test (test-actions test-actions) +set_tests_properties (test-actions PROPERTIES COMPILE_FLAGS "${SERVICE_CFLAGS}") +target_link_libraries (test-actions desktopmock backenddbus libindicatorsessionservice gtest ${SERVICE_LDFLAGS} ${GTEST_LIBS} ${GCOV_LIBS}) + +# test the Guest class +add_executable (test-guest + test-guest.cc) +add_test (test-guest test-guest) +set_tests_properties (test-guest PROPERTIES COMPILE_FLAGS "${SERVICE_CFLAGS}") +target_link_libraries (test-guest desktopmock backenddbus libindicatorsessionservice gtest ${SERVICE_LDFLAGS} ${GTEST_LIBS} ${GCOV_LIBS}) + +# test the Users class +add_executable (test-users + test-users.cc) +add_test (test-users test-users) +set_tests_properties (test-users PROPERTIES COMPILE_FLAGS "${SERVICE_CFLAGS}") +target_link_libraries (test-users desktopmock backenddbus libindicatorsessionservice gtest ${SERVICE_LDFLAGS} ${GTEST_LIBS} ${GCOV_LIBS}) + + + diff --git a/tests/backend-dbus/gtest-mock-dbus-fixture.h b/tests/backend-dbus/gtest-mock-dbus-fixture.h new file mode 100644 index 0000000..5c4e312 --- /dev/null +++ b/tests/backend-dbus/gtest-mock-dbus-fixture.h @@ -0,0 +1,130 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include "gtest-dbus-fixture.h" + +#include "mock-accounts.h" +#include "mock-consolekit-manager.h" +#include "mock-consolekit-seat.h" +#include "mock-consolekit-session.h" +#include "mock-display-manager-seat.h" +#include "mock-end-session-dialog.h" +#include "mock-screen-saver.h" +#include "mock-session-manager.h" +#include "mock-upower.h" +#include "mock-user.h" +#include "mock-webcredentials.h" + +/*** +**** +***/ + +class GTestMockDBusFixture: public GTestDBusFixture +{ + private: + + typedef GTestDBusFixture super; + + protected: + + MockScreenSaver * screen_saver; + MockSessionManager * session_manager; + MockDisplayManagerSeat * dm_seat; + MockAccounts * accounts; + MockConsoleKitSession * ck_session; + MockConsoleKitSeat * ck_seat; + MockConsoleKitManager * ck_manager; + MockUPower * upower; + MockEndSessionDialog * end_session_dialog; + MockWebcredentials * webcredentials; + + protected: + + virtual void SetUp () + { + super :: SetUp (); + + webcredentials = new MockWebcredentials (loop, conn); + end_session_dialog = new MockEndSessionDialog (loop, conn); + session_manager = new MockSessionManager (loop, conn); + screen_saver = new MockScreenSaver (loop, conn); + upower = new MockUPower (loop, conn); + dm_seat = new MockDisplayManagerSeat (loop, conn); + g_setenv ("XDG_SEAT_PATH", dm_seat->path(), TRUE); + dm_seat->set_guest_allowed (false); + accounts = build_accounts_mock (); + ck_manager = new MockConsoleKitManager (loop, conn); + ck_seat = new MockConsoleKitSeat (loop, conn, true); + MockUser * user = accounts->find_by_username ("msmith"); + ck_session = ck_seat->add_session_by_user (user); + ck_manager->add_seat (ck_seat); + dm_seat->set_consolekit_seat (ck_seat); + dm_seat->switch_to_user (user->username()); + ASSERT_EQ (ck_session, ck_manager->current_session()); + } + + protected: + + virtual void TearDown () + { + delete accounts; + delete ck_manager; + delete dm_seat; + delete upower; + delete screen_saver; + delete session_manager; + delete end_session_dialog; + delete webcredentials; + + super :: TearDown (); + } + + private: + + MockAccounts * build_accounts_mock () + { + struct { + guint64 login_frequency; + const gchar * user_name; + const gchar * real_name; + } users[] = { + { 134, "whartnell", "First Doctor" }, + { 119, "ptroughton", "Second Doctor" }, + { 128, "jpertwee", "Third Doctor" }, + { 172, "tbaker", "Fourth Doctor" }, + { 69, "pdavison", "Fifth Doctor" }, + { 31, "cbaker", "Sixth Doctor" }, + { 42, "smccoy", "Seventh Doctor" }, + { 1, "pmcgann", "Eigth Doctor" }, + { 13, "ceccleston", "Ninth Doctor" }, + { 47, "dtennant", "Tenth Doctor" }, + { 34, "msmith", "Eleventh Doctor" }, + { 1, "rhurndall", "First Doctor" } + }; + + MockAccounts * a = new MockAccounts (loop, conn); + for (int i=0, n=G_N_ELEMENTS(users); iadd_user (new MockUser (loop, conn, + users[i].user_name, + users[i].real_name, + users[i].login_frequency)); + return a; + } +}; + diff --git a/tests/backend-dbus/mock-accounts.cc b/tests/backend-dbus/mock-accounts.cc new file mode 100644 index 0000000..2a0e7e7 --- /dev/null +++ b/tests/backend-dbus/mock-accounts.cc @@ -0,0 +1,156 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include "mock-accounts.h" +#include "mock-user.h" + +namespace +{ + const char * const DBUS_ACCOUNTS_NAME = "org.freedesktop.Accounts"; + + const char * const DBUS_ACCOUNTS_PATH = "/org/freedesktop/Accounts"; +} + +/*** +**** +***/ + +void +MockAccounts :: add_user (MockUser * user) +{ + g_assert (my_users.count(user) == 0); + + my_users.insert (user); + my_uid_to_user[user->uid()] = user; + my_path_to_user[user->path()] = user; + my_username_to_user[user->username()] = user; + + accounts_emit_user_added (my_skeleton, user->path()); +} + +void +MockAccounts :: remove_user (MockUser * user) +{ + g_assert (my_users.count(user) == 1); + + my_users.erase (user); + my_uid_to_user.erase (user->uid()); + my_path_to_user.erase (user->path()); + my_username_to_user.erase (user->username()); + + accounts_emit_user_deleted (my_skeleton, user->path()); +} + +MockUser * +MockAccounts :: find_by_uid (guint64 uid) +{ + const uid_to_user_t::iterator it (my_uid_to_user.find(uid)); + + if (it != my_uid_to_user.end()) + return it->second; + + g_warn_if_reached (); + return 0; +} + +MockUser * +MockAccounts :: find_by_path (const char * path) +{ + const path_to_user_t::iterator it (my_path_to_user.find(path)); + + if (it != my_path_to_user.end()) + return it->second; + + g_warn_if_reached (); + return 0; +} + +MockUser * +MockAccounts :: find_by_username (const char * username) +{ + const username_to_user_t::iterator it (my_username_to_user.find(username)); + + if (it != my_path_to_user.end()) + return it->second; + + g_warn_if_reached (); + return 0; +} + +/*** +**** +***/ + +gboolean +MockAccounts :: on_find_user_by_id_static (Accounts * a, + GDBusMethodInvocation * invocation, + guint64 uid, + gpointer gself) +{ + MockUser * user = static_cast(gself)->find_by_uid (uid); + accounts_complete_find_user_by_id (a, invocation, user ? user->path() : ""); + return true; +} + +gboolean +MockAccounts :: on_list_cached_users_static (Accounts * a, + GDBusMethodInvocation * invocation, + gpointer gself) +{ + int i; + const char ** paths; + const users_t& users = static_cast(gself)->my_users; + + i = 0; + paths = g_new0 (const char*, users.size() + 1); + for (users_t::iterator it(users.begin()), + end(users.end()); it!=end; ++it) + paths[i++] = (*it)->path(); + accounts_complete_list_cached_users (a, invocation, paths); + g_free (paths); + + return true; +} + +/*** +**** +***/ + +MockAccounts :: MockAccounts (GMainLoop * loop, + GDBusConnection * bus_connection): + MockObject (loop, bus_connection, DBUS_ACCOUNTS_NAME, DBUS_ACCOUNTS_PATH), + my_skeleton (accounts_skeleton_new ()) +{ + g_signal_connect (my_skeleton, "handle-list-cached-users", + G_CALLBACK(on_list_cached_users_static), this); + g_signal_connect (my_skeleton, "handle-find-user-by-id", + G_CALLBACK(on_find_user_by_id_static), this); + + set_skeleton (G_DBUS_INTERFACE_SKELETON(my_skeleton)); +} + +MockAccounts :: ~MockAccounts () +{ + for (users_t::iterator it(my_users.begin()), + end(my_users.end()); it!=end; ++it) + delete *it; + + g_signal_handlers_disconnect_by_data (my_skeleton, this); + g_clear_object (&my_skeleton); +} diff --git a/tests/backend-dbus/mock-accounts.h b/tests/backend-dbus/mock-accounts.h new file mode 100644 index 0000000..95da102 --- /dev/null +++ b/tests/backend-dbus/mock-accounts.h @@ -0,0 +1,74 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#ifndef MOCK_ACCOUNTS_H +#define MOCK_ACCOUNTS_H + +#include +#include +#include +#include "mock-object.h" +#include "backend-dbus/dbus-accounts.h" // struct Accounts + +class MockUser; + +class MockAccounts: public MockObject +{ + public: + + MockAccounts (GMainLoop * loop, + GDBusConnection * bus_connection); + virtual ~MockAccounts (); + + void add_user (MockUser * user); + void remove_user (MockUser * user); + size_t size() const { return my_users.size(); } + MockUser * find_by_uid (guint64 uid); + MockUser * find_by_path (const char * path); + MockUser * find_by_username (const char * username); + + private: + + Accounts * my_skeleton; + + typedef std::set users_t; + users_t my_users; + + typedef std::map uid_to_user_t; + uid_to_user_t my_uid_to_user; + + typedef std::map path_to_user_t; + path_to_user_t my_path_to_user; + + typedef std::map username_to_user_t; + username_to_user_t my_username_to_user; + + private: + + static gboolean on_find_user_by_id_static (Accounts *, + GDBusMethodInvocation *, + guint64, + gpointer); + + static gboolean on_list_cached_users_static (Accounts *, + GDBusMethodInvocation *, + gpointer); +}; + +#endif // #ifndef MOCK_ACCOUNTS_H diff --git a/tests/backend-dbus/mock-consolekit-manager.cc b/tests/backend-dbus/mock-consolekit-manager.cc new file mode 100644 index 0000000..40f9bf9 --- /dev/null +++ b/tests/backend-dbus/mock-consolekit-manager.cc @@ -0,0 +1,156 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include "mock-consolekit-manager.h" +#include "mock-consolekit-seat.h" +#include "mock-consolekit-session.h" + +namespace +{ + const char * CONSOLEKIT_MANAGER_NAME = "org.freedesktop.ConsoleKit"; + + const char * CONSOLEKIT_MANAGER_PATH = "/org/freedesktop/ConsoleKit/Manager"; + + void on_active_session_changed (ConsoleKitSeat * o G_GNUC_UNUSED, + const gchar * new_ssid, + gpointer ssid) + { + *static_cast(ssid) = new_ssid; + } +} + +/*** +**** +***/ + +gboolean +MockConsoleKitManager :: on_get_current_session (ConsoleKitManager * m, + GDBusMethodInvocation * inv, + gpointer gself) +{ + MockConsoleKitManager * self = static_cast(gself); + const std::string& ssid = self->my_current_ssid; + console_kit_manager_complete_get_current_session (m, inv, ssid.c_str()); + return true; +} + +gboolean +MockConsoleKitManager :: on_get_seats (ConsoleKitManager * m, + GDBusMethodInvocation * inv, + gpointer gself) +{ + int i; + char ** sids; + const seats_t& seats = static_cast(gself)->my_seats; + + i = 0; + sids = g_new0 (char*, seats.size()+1); + for (seats_t::const_iterator it(seats.begin()), + end(seats.end()); it!=end; ++it) + sids[i++] = (char*) (*it)->path(); + console_kit_manager_complete_get_seats (m, inv, sids); + g_strfreev (sids); + + return true; +} + +gboolean +MockConsoleKitManager :: handle_restart (ConsoleKitManager * ckm, + GDBusMethodInvocation * inv, + gpointer gself) +{ + static_cast(gself)->my_last_action = Restart; + console_kit_manager_complete_restart (ckm, inv); + return true; +} + +gboolean +MockConsoleKitManager :: handle_stop (ConsoleKitManager * ckm, + GDBusMethodInvocation * inv, + gpointer gself) +{ + static_cast(gself)->my_last_action = Shutdown; + console_kit_manager_complete_stop (ckm, inv); + return true; +} + +/*** +**** +***/ + +MockConsoleKitSession * +MockConsoleKitManager :: current_session () +{ + MockConsoleKitSession * ret = 0; + + for (seats_t::iterator it(my_seats.begin()), + end(my_seats.end()); it!=end; ++it) + if ((ret = (*it)->find (my_current_ssid.c_str()))) + break; + + return ret; +} + +void +MockConsoleKitManager :: add_seat (MockConsoleKitSeat * seat) +{ + g_assert (my_seats.count(seat) == 0); + + my_seats.insert (seat); + + console_kit_manager_emit_seat_added (my_skeleton, seat->sid()); + + g_signal_connect (seat->skeleton(), "active-session-changed", + G_CALLBACK(on_active_session_changed), &my_current_ssid); +} + +/*** +**** +***/ + +MockConsoleKitManager :: MockConsoleKitManager (GMainLoop * loop, + GDBusConnection * conn): + MockObject (loop, conn, CONSOLEKIT_MANAGER_NAME, CONSOLEKIT_MANAGER_PATH), + my_skeleton (console_kit_manager_skeleton_new ()), + my_last_action (None) +{ + g_signal_connect (my_skeleton, "handle-get-current-session", + G_CALLBACK(on_get_current_session), this); + g_signal_connect (my_skeleton, "handle-get-seats", + G_CALLBACK(on_get_seats), this); + g_signal_connect (my_skeleton, "handle-stop", + G_CALLBACK(handle_stop), this); + g_signal_connect (my_skeleton, "handle-restart", + G_CALLBACK(handle_restart), this); + + set_skeleton (G_DBUS_INTERFACE_SKELETON(my_skeleton)); +} + +MockConsoleKitManager :: ~MockConsoleKitManager () +{ + for (seats_t::iterator it(my_seats.begin()); it!=my_seats.end(); ++it) + { + MockConsoleKitSeat * seat = *it; + g_signal_handlers_disconnect_by_data (seat->skeleton(), &my_current_ssid); + delete seat; + } + + g_signal_handlers_disconnect_by_data (my_skeleton, this); + g_clear_object (&my_skeleton); +} diff --git a/tests/backend-dbus/mock-consolekit-manager.h b/tests/backend-dbus/mock-consolekit-manager.h new file mode 100644 index 0000000..c5942b2 --- /dev/null +++ b/tests/backend-dbus/mock-consolekit-manager.h @@ -0,0 +1,77 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#ifndef MOCK_CONSOLEKIT_MANAGER_H +#define MOCK_CONSOLEKIT_MANAGER_H + +#include +#include +#include "mock-object.h" +#include "backend-dbus/dbus-consolekit-manager.h" + +class MockConsoleKitSession; +class MockConsoleKitSeat; + +class MockConsoleKitManager: public MockObject +{ + public: + + MockConsoleKitManager (GMainLoop * loop, + GDBusConnection * bus_connection); + virtual ~MockConsoleKitManager (); + + void add_seat (MockConsoleKitSeat * seat); + + MockConsoleKitSession * current_session (); + + public: + + enum Action { None, Shutdown, Restart }; + + Action last_action () const { return my_last_action; } + + void clear_last_action () { my_last_action = None; } + + private: + + typedef std::set seats_t; + seats_t my_seats; + + ConsoleKitManager * my_skeleton; + + std::string my_current_ssid; + + Action my_last_action; + + static gboolean on_get_current_session (ConsoleKitManager *, + GDBusMethodInvocation *, + gpointer ); + static gboolean on_get_seats (ConsoleKitManager *, + GDBusMethodInvocation *, + gpointer ); + static gboolean handle_restart (ConsoleKitManager *, + GDBusMethodInvocation *, + gpointer); + static gboolean handle_stop (ConsoleKitManager *, + GDBusMethodInvocation *, + gpointer); + +}; + +#endif // #ifndef MOCK_CONSOLEKIT_MANAGER_H diff --git a/tests/backend-dbus/mock-consolekit-seat.cc b/tests/backend-dbus/mock-consolekit-seat.cc new file mode 100644 index 0000000..ce1fbad --- /dev/null +++ b/tests/backend-dbus/mock-consolekit-seat.cc @@ -0,0 +1,220 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include "mock-consolekit-seat.h" + +#include "mock-object.h" +#include "mock-consolekit-session.h" +#include "mock-user.h" + +namespace +{ + const char * CONSOLEKIT_BUS_NAME = "org.freedesktop.ConsoleKit"; + + std::string next_unique_sid () + { + static int id = 1; + + char * tmp; + std::string ret; + + tmp = g_strdup_printf ("/org/freedesktop/ConsoleKit/Seat%d", id++); + ret = tmp; + g_free (tmp); + return ret; + } +} + +/*** +**** +***/ + +void +MockConsoleKitSeat :: activate_session (MockConsoleKitSession * session) +{ + g_assert (my_sessions.count(session) == 1); + + const char * ssid = session->ssid (); + if (my_active_ssid != ssid) + { + my_active_ssid = ssid; + console_kit_seat_emit_active_session_changed (my_skeleton, ssid); + } +} + +void +MockConsoleKitSeat :: switch_to_guest () +{ + for (sessions_t::iterator it(my_sessions.begin()), + end(my_sessions.end()); it!=end; ++it) + { + MockConsoleKitSession * session (*it); + + if (session->user()->is_guest()) + { + activate_session (*it); + return; + } + } + + g_warn_if_reached (); +} + +void +MockConsoleKitSeat :: switch_to_user (const char * username) +{ + for (sessions_t::iterator it(my_sessions.begin()), + end(my_sessions.end()); it!=end; ++it) + { + MockConsoleKitSession * session (*it); + + if (!g_strcmp0 (username, session->user()->username())) + { + activate_session (*it); + return; + } + } + + g_warn_if_reached (); +} + +/*** +**** +***/ + +MockConsoleKitSession * +MockConsoleKitSeat :: add_session_by_user (MockUser * mu) +{ + g_assert (mu != 0); + + MockConsoleKitSession * session; + + session = new MockConsoleKitSession (my_loop, my_bus_connection); + session->set_user (mu); + add_session (session); + return session; +} + +void +MockConsoleKitSeat :: add_session (MockConsoleKitSession * session) +{ + g_assert (my_sessions.count(session) == 0); + + my_sessions.insert (session); + session->set_sid (path()); + console_kit_seat_emit_session_added (my_skeleton, session->ssid()); +} + +void +MockConsoleKitSeat :: remove_session (MockConsoleKitSession * session) +{ + g_assert (my_sessions.count(session) == 1); + + my_sessions.erase (session); + session->set_sid (""); + console_kit_seat_emit_session_removed (my_skeleton, session->ssid()); +} + +/*** +**** Handlers +***/ + +gboolean +MockConsoleKitSeat :: on_can_activate_sessions (ConsoleKitSeat * cks, + GDBusMethodInvocation * inv, + gpointer gself) +{ + bool b = static_cast(gself)->my_can_activate_sessions; + console_kit_seat_complete_can_activate_sessions (cks, inv, b); + return true; +} + +gboolean +MockConsoleKitSeat :: on_get_active_session (ConsoleKitSeat * cks, + GDBusMethodInvocation * invoke, + gpointer gself) +{ + std::string ssid = static_cast(gself)->my_active_ssid; + console_kit_seat_complete_get_active_session (cks, invoke, ssid.c_str()); + return true; +} + +gboolean +MockConsoleKitSeat :: on_get_sessions (ConsoleKitSeat * cks, + GDBusMethodInvocation * inv, + gpointer gself) +{ + int i; + const char ** paths; + sessions_t& sessions = static_cast(gself)->my_sessions; + + i = 0; + paths = g_new0 (const char*, sessions.size() + 1); + for (sessions_t::iterator it(sessions.begin()), + end(sessions.end()); it!=end; ++it) + paths[i++] = (*it)->path(); + + g_debug ("returning a list of %d sessions", i); + console_kit_seat_complete_get_sessions (cks, inv, paths); + g_free (paths); + + return true; +} + +MockConsoleKitSession * +MockConsoleKitSeat :: find (const char * ssid) +{ + for (sessions_t::iterator it(my_sessions.begin()), + end(my_sessions.end()); it!=end; ++it) + if (!g_strcmp0 ((*it)->path(), ssid)) + return *it; + + return 0; +} + +/*** +**** Life Cycle +***/ + +MockConsoleKitSeat :: MockConsoleKitSeat (GMainLoop * loop, + GDBusConnection * bus_connection, + bool can_activate_sessions): + MockObject (loop, bus_connection, CONSOLEKIT_BUS_NAME, next_unique_sid()), + my_skeleton (console_kit_seat_skeleton_new ()), + my_can_activate_sessions (can_activate_sessions) +{ + g_signal_connect (my_skeleton, "handle-get-active-session", + G_CALLBACK(on_get_active_session), this); + g_signal_connect (my_skeleton, "handle-get-sessions", + G_CALLBACK(on_get_sessions), this); + g_signal_connect (my_skeleton, "handle-can-activate-sessions", + G_CALLBACK(on_can_activate_sessions), this); + + set_skeleton (G_DBUS_INTERFACE_SKELETON(my_skeleton)); +} + +MockConsoleKitSeat :: ~MockConsoleKitSeat () +{ + for (sessions_t::iterator it(my_sessions.begin()), + end(my_sessions.end()); it!=end; ++it) + delete *it; + + g_signal_handlers_disconnect_by_data (my_skeleton, this); + g_clear_object (&my_skeleton); +} diff --git a/tests/backend-dbus/mock-consolekit-seat.h b/tests/backend-dbus/mock-consolekit-seat.h new file mode 100644 index 0000000..aa52276 --- /dev/null +++ b/tests/backend-dbus/mock-consolekit-seat.h @@ -0,0 +1,75 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#ifndef MOCK_CONSOLEKIT_SEAT_H +#define MOCK_CONSOLEKIT_SEAT_H + +#include +#include +#include "backend-dbus/dbus-consolekit-seat.h" +#include "mock-object.h" + +class MockUser; +class MockConsoleKitSession; + +class MockConsoleKitSeat: public MockObject +{ + public: + + MockConsoleKitSeat (GMainLoop * loop, + GDBusConnection * bus_connection, + bool can_activate_sessions); + virtual ~MockConsoleKitSeat (); + + const char * sid() { return path(); } + MockConsoleKitSession * add_session_by_user (MockUser * user); + void add_session (MockConsoleKitSession * session); + void remove_session (MockConsoleKitSession * session); + void activate_session (MockConsoleKitSession * session); + void switch_to_guest (); + void switch_to_user (const char * username); + bool can_activate_sessions () const { return my_can_activate_sessions; } + MockConsoleKitSession * find (const char * ssid); + + private: + + static gboolean on_get_active_session (ConsoleKitSeat * cks, + GDBusMethodInvocation * inv, + gpointer gself); + static gboolean on_get_sessions (ConsoleKitSeat * cks, + GDBusMethodInvocation * inv, + gpointer gself); + static gboolean on_can_activate_sessions (ConsoleKitSeat * cks, + GDBusMethodInvocation * inv, + gpointer gself); + + + private: + + ConsoleKitSeat * my_skeleton; + + std::string my_active_ssid; + + typedef std::set sessions_t; + sessions_t my_sessions; + bool my_can_activate_sessions; + +}; + +#endif // #ifndef MOCK_CONSOLEKIT_SEAT_H diff --git a/tests/backend-dbus/mock-consolekit-session.cc b/tests/backend-dbus/mock-consolekit-session.cc new file mode 100644 index 0000000..2f39411 --- /dev/null +++ b/tests/backend-dbus/mock-consolekit-session.cc @@ -0,0 +1,113 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include "mock-consolekit-session.h" +#include "mock-user.h" + +namespace +{ + const char * const DEFAULT_X11_DISPLAY = ":0:0"; + + const char * const CONSOLEKIT_NAME = "org.freedesktop.ConsoleKit"; + + std::string next_unique_ssid () + { + static int id = 333; // arbitrary + + char * tmp; + std::string ret; + + tmp = g_strdup_printf ("/org/freedesktop/ConsoleKit/Session%d", id++); + ret = tmp; + g_free (tmp); + return ret; + } +} + +void +MockConsoleKitSession :: set_user (MockUser * user) +{ + my_user = user; +} + +/*** +**** +***/ + +gboolean +MockConsoleKitSession :: on_get_seat_id_static (ConsoleKitSession * cks, + GDBusMethodInvocation * inv, + gpointer gself) +{ + const std::string& sid = static_cast(gself)->my_sid; + g_debug ("%s %s returning seat id of %s", G_STRLOC, G_STRFUNC, sid.c_str()); + console_kit_session_complete_get_seat_id (cks, inv, sid.c_str()); + return true; +} + +gboolean +MockConsoleKitSession :: on_get_unix_user_static (ConsoleKitSession * cks, + GDBusMethodInvocation * inv, + gpointer gself) +{ + MockUser * user = static_cast(gself)->my_user; + g_debug ("%s %s returning uid of %u", G_STRLOC, G_STRFUNC, user->uid()); + console_kit_session_complete_get_unix_user (cks, inv, user->uid()); + return true; +} + +gboolean +MockConsoleKitSession :: on_get_x11_display (ConsoleKitSession * cks, + GDBusMethodInvocation * inv, + gpointer gself) +{ + MockConsoleKitSession * self = static_cast(gself); + const char * x11 = self->x11_display(); + g_debug ("%s %s returning x11 display '%s'", G_STRLOC, G_STRFUNC, x11); + console_kit_session_complete_get_x11_display (cks, inv, x11); + return true; +} + +/*** +**** +***/ + +MockConsoleKitSession :: MockConsoleKitSession (GMainLoop * loop, + GDBusConnection * conn): + MockObject (loop, conn, CONSOLEKIT_NAME, next_unique_ssid ()), + my_skeleton (console_kit_session_skeleton_new ()), + my_x11_display (DEFAULT_X11_DISPLAY), + my_user (0) +{ + g_signal_connect (my_skeleton, "handle-get-seat-id", + G_CALLBACK(on_get_seat_id_static), this); + g_signal_connect (my_skeleton, "handle-get-unix-user", + G_CALLBACK(on_get_unix_user_static), this); + g_signal_connect (my_skeleton, "handle-get-x11-display", + G_CALLBACK(on_get_x11_display), this); + + set_skeleton (G_DBUS_INTERFACE_SKELETON(my_skeleton)); +} + +MockConsoleKitSession :: ~MockConsoleKitSession () +{ + const int n = g_signal_handlers_disconnect_by_data (my_skeleton, this); + g_assert (n == 3); + g_clear_object (&my_skeleton); +} diff --git a/tests/backend-dbus/mock-consolekit-session.h b/tests/backend-dbus/mock-consolekit-session.h new file mode 100644 index 0000000..7759f72 --- /dev/null +++ b/tests/backend-dbus/mock-consolekit-session.h @@ -0,0 +1,65 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#ifndef MOCK_CONSOLEKIT_SESSION_H +#define MOCK_CONSOLEKIT_SESSION_H + +#include +#include "mock-object.h" +#include "backend-dbus/dbus-consolekit-session.h" + +class MockUser; + +class MockConsoleKitSession: public MockObject +{ + public: + + MockConsoleKitSession (GMainLoop * loop, + GDBusConnection * bus_connection); + virtual ~MockConsoleKitSession (); + + MockUser * user () { return my_user; } + void set_user (MockUser * user); + const char * ssid () { return path(); } + void set_sid (const std::string& sid) { my_sid = sid; } + const char * x11_display() { return my_x11_display.c_str(); } + void set_x11_display (const std::string& x) { my_x11_display = x; } + + private: + + static gboolean on_get_seat_id_static (ConsoleKitSession *, + GDBusMethodInvocation *, + gpointer); + static gboolean on_get_unix_user_static (ConsoleKitSession *, + GDBusMethodInvocation *, + gpointer); + static gboolean on_get_x11_display (ConsoleKitSession *, + GDBusMethodInvocation *, + gpointer); + + + private: + + ConsoleKitSession * my_skeleton; + std::string my_sid; + std::string my_x11_display; + MockUser * my_user; +}; + +#endif // #ifndef MOCK_CONSOLEKIT_SESSION_H diff --git a/tests/backend-dbus/mock-display-manager-seat.cc b/tests/backend-dbus/mock-display-manager-seat.cc new file mode 100644 index 0000000..9f30ae1 --- /dev/null +++ b/tests/backend-dbus/mock-display-manager-seat.cc @@ -0,0 +1,140 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include "mock-display-manager-seat.h" +#include "mock-consolekit-seat.h" + +namespace +{ + const char * const DISPLAY_MANAGER_NAME = "org.freedesktop.DisplayManager"; + + std::string + next_unique_path () + { + static int id = 12; // arbitrary; doesn't matter + + char * tmp; + std::string ret; + + tmp = g_strdup_printf ("/org/freedesktop/DisplayManager/Seat%d", id++); + ret = tmp; + g_free (tmp); + return ret; + } +} + +/*** +**** +***/ + +void +MockDisplayManagerSeat :: switch_to_greeter () +{ + my_last_action = GREETER; +} + +gboolean +MockDisplayManagerSeat :: handle_switch_to_greeter (DisplayManagerSeat * o, + GDBusMethodInvocation * inv, + gpointer gself) +{ + static_cast(gself)->switch_to_greeter (); + display_manager_seat_complete_switch_to_greeter (o, inv); + return true; +} + +void +MockDisplayManagerSeat :: set_guest_allowed (bool b) +{ + display_manager_seat_set_has_guest_account (my_skeleton, b); +} + +gboolean +MockDisplayManagerSeat :: handle_switch_to_guest (DisplayManagerSeat * o, + GDBusMethodInvocation * inv, + const gchar * session_name G_GNUC_UNUSED, + gpointer gself) +{ + static_cast(gself)->switch_to_guest (); + display_manager_seat_complete_switch_to_guest (o, inv); + return true; +} + +void +MockDisplayManagerSeat :: switch_to_guest () +{ + g_assert (my_ck_seat != 0); + + my_last_action = GUEST; + my_ck_seat->switch_to_guest (); +} + +gboolean +MockDisplayManagerSeat :: handle_switch_to_user (DisplayManagerSeat * o, + GDBusMethodInvocation * inv, + const gchar * username, + const gchar * session_name G_GNUC_UNUSED, + gpointer gself) +{ + static_cast(gself)->switch_to_user (username); + display_manager_seat_complete_switch_to_user (o, inv); + return true; +} + +void +MockDisplayManagerSeat :: switch_to_user (const char * username) +{ + g_assert (my_ck_seat != 0); + + my_last_action = USER; + my_ck_seat->switch_to_user (username); +} + +void +MockDisplayManagerSeat :: set_consolekit_seat (MockConsoleKitSeat * seat) +{ + my_ck_seat = seat; +} + +/*** +**** +***/ + +MockDisplayManagerSeat :: MockDisplayManagerSeat (GMainLoop * loop, + GDBusConnection * connection): + MockObject (loop, connection, DISPLAY_MANAGER_NAME, next_unique_path()), + my_skeleton (display_manager_seat_skeleton_new ()), + my_ck_seat (0), + my_last_action (NONE) +{ + g_signal_connect (my_skeleton, "handle-switch-to-guest", + G_CALLBACK(handle_switch_to_guest), this); + g_signal_connect (my_skeleton, "handle-switch-to-user", + G_CALLBACK(handle_switch_to_user), this); + g_signal_connect (my_skeleton, "handle-switch-to-greeter", + G_CALLBACK(handle_switch_to_greeter), this); + + set_skeleton (G_DBUS_INTERFACE_SKELETON(my_skeleton)); +} + +MockDisplayManagerSeat :: ~MockDisplayManagerSeat () +{ + g_signal_handlers_disconnect_by_data (my_skeleton, this); + g_clear_object (&my_skeleton); +} diff --git a/tests/backend-dbus/mock-display-manager-seat.h b/tests/backend-dbus/mock-display-manager-seat.h new file mode 100644 index 0000000..b0ea415 --- /dev/null +++ b/tests/backend-dbus/mock-display-manager-seat.h @@ -0,0 +1,72 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#ifndef MOCK_DISPLAY_MANAGER_SEAT_H +#define MOCK_DISPLAY_MANAGER_SEAT_H + +#include "mock-object.h" // parent class +#include "backend-dbus/dbus-display-manager.h" + +class MockConsoleKitSeat; + +class MockDisplayManagerSeat: public MockObject +{ + public: + + MockDisplayManagerSeat (GMainLoop * loop, + GDBusConnection * bus_connection); + virtual ~MockDisplayManagerSeat (); + + void set_guest_allowed (bool b); + + void set_consolekit_seat (MockConsoleKitSeat * ck_seat); + + void switch_to_guest (); + + void switch_to_greeter (); + + void switch_to_user (const char * username); + + public: + + enum Action { NONE, GUEST, GREETER, USER }; + + Action last_action () const { return my_last_action; } + + private: + + static gboolean handle_switch_to_greeter (DisplayManagerSeat *o, + GDBusMethodInvocation *inv, + gpointer gself); + static gboolean handle_switch_to_guest (DisplayManagerSeat *o, + GDBusMethodInvocation *inv, + const gchar *session_name, + gpointer gself); + static gboolean handle_switch_to_user (DisplayManagerSeat * o, + GDBusMethodInvocation * inv, + const gchar * username, + const gchar * session_name, + gpointer gself); + + DisplayManagerSeat * my_skeleton; + MockConsoleKitSeat * my_ck_seat; + Action my_last_action; +}; + +#endif // #ifndef MOCK_DISPLAY_MANAGER_SEAT_H diff --git a/tests/backend-dbus/mock-end-session-dialog.cc b/tests/backend-dbus/mock-end-session-dialog.cc new file mode 100644 index 0000000..e289a83 --- /dev/null +++ b/tests/backend-dbus/mock-end-session-dialog.cc @@ -0,0 +1,89 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include "mock-end-session-dialog.h" + +#if 0 +gboolean +MockEndSessionDialog :: handle_lock (GnomeScreenSaver * ss, + GDBusMethodInvocation * inv, + gpointer gself) +{ + static_cast(gself)->my_last_action = Lock; + gnome_screen_saver_complete_lock (ss, inv); + return true; +} + +gboolean +MockEndSessionDialog :: handle_simulate_user_activity (GnomeScreenSaver * ss, + GDBusMethodInvocation * inv, + gpointer gself) +{ + static_cast(gself)->my_last_action = UserActivity; + gnome_screen_saver_complete_simulate_user_activity (ss, inv); + return true; +} +#endif + +gboolean +MockEndSessionDialog :: handle_open (EndSessionDialog * object, + GDBusMethodInvocation * invocation, + guint arg_type, + guint arg_timestamp, + guint arg_seconds_to_stay_open, + const gchar * const * inhibitor_paths, + gpointer gself) +{ + static_cast(gself)->my_isOpen = true; + end_session_dialog_complete_open (object, invocation); + return true; +} + +/*** +**** +***/ + +namespace +{ + const char * const MY_NAME = "com.canonical.Unity"; + const char * const MY_PATH = "/org/gnome/SessionManager/EndSessionDialog"; +} + +MockEndSessionDialog :: MockEndSessionDialog (GMainLoop * loop, + GDBusConnection * bus_connection): + MockObject (loop, bus_connection, MY_NAME, MY_PATH), + my_isOpen (false), + my_skeleton (end_session_dialog_skeleton_new ()) +{ + g_signal_connect (my_skeleton, "handle-open", + G_CALLBACK(handle_open), this); +#if 0 + g_signal_connect (my_skeleton, "handle-lock", + G_CALLBACK(handle_lock), this); + g_signal_connect (my_skeleton, "handle-simulate-user-activity", + G_CALLBACK(handle_simulate_user_activity), this); +#endif + + set_skeleton (G_DBUS_INTERFACE_SKELETON(my_skeleton)); +} + +MockEndSessionDialog :: ~MockEndSessionDialog () +{ + g_clear_object (&my_skeleton); +} diff --git a/tests/backend-dbus/mock-end-session-dialog.h b/tests/backend-dbus/mock-end-session-dialog.h new file mode 100644 index 0000000..468715c --- /dev/null +++ b/tests/backend-dbus/mock-end-session-dialog.h @@ -0,0 +1,67 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#ifndef MOCK_END_SESSION_DIALOG_H +#define MOCK_END_SESSION_DIALOG_H + +#include "mock-object.h" // parent class +#include "backend-dbus/dbus-end-session-dialog.h" // EndSessionDialog + +class MockEndSessionDialog: public MockObject +{ + public: + + MockEndSessionDialog (GMainLoop * loop, + GDBusConnection * bus_connection); + virtual ~MockEndSessionDialog (); + + bool is_open () const { return my_isOpen; } + + void cancel () { my_isOpen = false; end_session_dialog_emit_canceled (my_skeleton); } + void confirm_logout () { my_isOpen = false; end_session_dialog_emit_confirmed_logout (my_skeleton); } + void confirm_reboot () { my_isOpen = false; end_session_dialog_emit_confirmed_reboot (my_skeleton); } + void confirm_shutdown () { my_isOpen = false; end_session_dialog_emit_confirmed_shutdown (my_skeleton); } + void close () { my_isOpen = false; end_session_dialog_emit_closed (my_skeleton); } + + private: + + EndSessionDialog * my_skeleton; + + bool my_isOpen; + + static gboolean handle_open (EndSessionDialog *, + GDBusMethodInvocation *, + guint, + guint, + guint, + const gchar * const *, + gpointer); + + +#if 0 + static gboolean handle_lock (GnomeScreenSaver *, + GDBusMethodInvocation *, + gpointer); + static gboolean handle_simulate_user_activity (GnomeScreenSaver *, + GDBusMethodInvocation *, + gpointer); +#endif +}; + +#endif diff --git a/tests/backend-dbus/mock-object.cc b/tests/backend-dbus/mock-object.cc new file mode 100644 index 0000000..af9330b --- /dev/null +++ b/tests/backend-dbus/mock-object.cc @@ -0,0 +1,122 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include +#include + +#include "mock-object.h" + +namespace +{ + const int TIMEOUT_SECONDS = 5; + + gboolean on_timeout_reached (gpointer loop) + { + g_main_loop_quit (static_cast(loop)); + return G_SOURCE_REMOVE; + } + + void on_name_acquired (GDBusConnection * connection G_GNUC_UNUSED, + const char * name G_GNUC_UNUSED, + gpointer loop) + { + //g_debug ("name '%s' acquired", name); + g_main_loop_quit (static_cast(loop)); + } + + void on_name_lost (GDBusConnection * connection G_GNUC_UNUSED, + const char * name G_GNUC_UNUSED, + gpointer loop) + { + //g_debug ("name '%s' lost", name); + g_main_loop_quit (static_cast(loop)); + } +} + +void +MockObject :: set_skeleton (GDBusInterfaceSkeleton * skeleton) +{ + g_assert (skeleton != NULL); + g_assert (my_skeleton == NULL); + g_assert (g_variant_is_object_path (my_object_path.c_str())); + g_assert (my_owner_id == 0); + + my_skeleton = G_DBUS_INTERFACE_SKELETON (g_object_ref (skeleton)); + + GError * err = NULL; + g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON(my_skeleton), + my_bus_connection, + my_object_path.c_str(), + &err); + g_assert_no_error (err); + + my_owner_id = g_bus_own_name_on_connection (my_bus_connection, + my_object_name.c_str(), + G_BUS_NAME_OWNER_FLAGS_NONE, + on_name_acquired, + on_name_lost, + my_loop, + NULL); + + // wait for the name to be acquired or timeout, whichever comes first + const guint timeout_id = g_timeout_add_seconds (TIMEOUT_SECONDS, + on_timeout_reached, + my_loop); + g_main_loop_run (my_loop); + g_assert (g_main_context_find_source_by_id (NULL, timeout_id) != NULL); + g_source_remove (timeout_id); +} + +/*** +**** +***/ + +MockObject :: MockObject (GMainLoop * loop, + GDBusConnection * bus_connection, + const std::string & object_name, + const std::string & object_path): + my_owner_id (0), + my_loop (g_main_loop_ref (loop)), + my_bus_connection (G_DBUS_CONNECTION (g_object_ref (bus_connection))), + my_object_name (object_name), + my_object_path (object_path), + my_skeleton (0) +{ +} + +MockObject :: ~MockObject () +{ + g_main_loop_unref (my_loop); + + if (my_owner_id != 0) + { + g_bus_unown_name (my_owner_id); + + my_owner_id = 0; + } + + if (my_skeleton) + { + g_dbus_interface_skeleton_unexport (my_skeleton); + + g_clear_object (&my_skeleton); + } + + g_clear_object (&my_bus_connection); +} diff --git a/tests/backend-dbus/mock-object.h b/tests/backend-dbus/mock-object.h new file mode 100644 index 0000000..8dc7070 --- /dev/null +++ b/tests/backend-dbus/mock-object.h @@ -0,0 +1,62 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#ifndef MOCK_OBJECT_H +#define MOCK_OBJECT_H + +#include + +#include +#include + +class MockObject +{ + public: + + MockObject (GMainLoop * loop, + GDBusConnection * bus_connection, + const std::string & object_name, + const std::string & object_path); + + virtual ~MockObject (); + + const char * name() const { return my_object_name.c_str(); } + const char * path() const { return my_object_path.c_str(); } + + GDBusInterfaceSkeleton * skeleton() { return my_skeleton; } + + protected: + + guint my_owner_id; + GMainLoop * my_loop; + GDBusConnection * my_bus_connection; + const std::string my_object_name; + const std::string my_object_path; + GDBusInterfaceSkeleton * my_skeleton; + + void set_skeleton (GDBusInterfaceSkeleton * skeleton); + + private: + // safeguard to make sure we don't copy-by-value... + // this object's holding a handful of pointers + MockObject (const MockObject& rhs); + MockObject& operator= (const MockObject& rhs); +}; + +#endif diff --git a/tests/backend-dbus/mock-screen-saver.cc b/tests/backend-dbus/mock-screen-saver.cc new file mode 100644 index 0000000..1d3bb11 --- /dev/null +++ b/tests/backend-dbus/mock-screen-saver.cc @@ -0,0 +1,71 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include "mock-screen-saver.h" + + +gboolean +MockScreenSaver :: handle_lock (GnomeScreenSaver * ss, + GDBusMethodInvocation * inv, + gpointer gself) +{ + static_cast(gself)->my_last_action = Lock; + gnome_screen_saver_complete_lock (ss, inv); + return true; +} + +gboolean +MockScreenSaver :: handle_simulate_user_activity (GnomeScreenSaver * ss, + GDBusMethodInvocation * inv, + gpointer gself) +{ + static_cast(gself)->my_last_action = UserActivity; + gnome_screen_saver_complete_simulate_user_activity (ss, inv); + return true; +} + +/*** +**** +***/ + +namespace +{ + const char * const SCREENSAVER_NAME = "org.gnome.ScreenSaver"; + const char * const SCREENSAVER_PATH = "/org/gnome/ScreenSaver"; + +} + +MockScreenSaver :: MockScreenSaver (GMainLoop * loop, + GDBusConnection * bus_connection): + MockObject (loop, bus_connection, SCREENSAVER_NAME, SCREENSAVER_PATH), + my_skeleton (gnome_screen_saver_skeleton_new ()), + my_last_action (None) +{ + g_signal_connect (my_skeleton, "handle-lock", + G_CALLBACK(handle_lock), this); + g_signal_connect (my_skeleton, "handle-simulate-user-activity", + G_CALLBACK(handle_simulate_user_activity), this); + + set_skeleton (G_DBUS_INTERFACE_SKELETON(my_skeleton)); +} + +MockScreenSaver :: ~MockScreenSaver () +{ + g_clear_object (&my_skeleton); +} diff --git a/tests/backend-dbus/mock-screen-saver.h b/tests/backend-dbus/mock-screen-saver.h new file mode 100644 index 0000000..c57a4c6 --- /dev/null +++ b/tests/backend-dbus/mock-screen-saver.h @@ -0,0 +1,53 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#ifndef MOCK_SCREENSAVER_H +#define MOCK_SCREENSAVER_H + +#include "mock-object.h" // parent class +#include "backend-dbus/gnome-screen-saver.h" // GnomeScreenSaver + +class MockScreenSaver: public MockObject +{ + public: + + MockScreenSaver (GMainLoop * loop, + GDBusConnection * bus_connection); + virtual ~MockScreenSaver (); + + public: + + enum Action { None, Lock, UserActivity }; + Action last_action () { return my_last_action; } + + private: + + GnomeScreenSaver * my_skeleton; + Action my_last_action; + + static gboolean handle_lock (GnomeScreenSaver *, + GDBusMethodInvocation *, + gpointer); + static gboolean handle_simulate_user_activity (GnomeScreenSaver *, + GDBusMethodInvocation *, + gpointer); + +}; + +#endif diff --git a/tests/backend-dbus/mock-session-manager.cc b/tests/backend-dbus/mock-session-manager.cc new file mode 100644 index 0000000..7a4ce87 --- /dev/null +++ b/tests/backend-dbus/mock-session-manager.cc @@ -0,0 +1,66 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include "mock-session-manager.h" + +gboolean +MockSessionManager :: handle_logout (GnomeSessionManager * gsm, + GDBusMethodInvocation * inv, + guint arg, + gpointer gself) +{ + Action action; + switch (arg) { + case 0: action = LogoutNormal; break; + case 1: action = LogoutQuiet; break; + case 2: action = LogoutForce; break; + default: action = None; break; + } + static_cast(gself)->my_last_action = action; + gnome_session_manager_complete_logout (gsm, inv); + return true; +} + + /*** +**** +***/ + +namespace +{ + const char * const SESSION_MANAGER_NAME = "org.gnome.SessionManager"; + const char * const SESSION_MANAGER_PATH = "/org/gnome/SessionManager"; + +} + +MockSessionManager :: MockSessionManager (GMainLoop * loop, + GDBusConnection * bus_connection): + MockObject (loop, bus_connection, SESSION_MANAGER_NAME, SESSION_MANAGER_PATH), + my_skeleton (gnome_session_manager_skeleton_new ()), + my_last_action (None) +{ + g_signal_connect (my_skeleton, "handle-logout", + G_CALLBACK(handle_logout), this); + + set_skeleton (G_DBUS_INTERFACE_SKELETON(my_skeleton)); +} + +MockSessionManager :: ~MockSessionManager () +{ + g_clear_object (&my_skeleton); +} diff --git a/tests/backend-dbus/mock-session-manager.h b/tests/backend-dbus/mock-session-manager.h new file mode 100644 index 0000000..6a21277 --- /dev/null +++ b/tests/backend-dbus/mock-session-manager.h @@ -0,0 +1,50 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#ifndef MOCK_SESSION_MANAGER_H +#define MOCK_SESSION_MANAGER_H + +#include "mock-object.h" // parent class +#include "backend-dbus/gnome-session-manager.h" // GnomeSessionManager + +class MockSessionManager: public MockObject +{ + public: + + MockSessionManager (GMainLoop * loop, + GDBusConnection * bus_connection); + virtual ~MockSessionManager (); + + public: + + enum Action { None, LogoutNormal, LogoutQuiet, LogoutForce }; + Action last_action () { return my_last_action; } + + private: + + GnomeSessionManager * my_skeleton; + Action my_last_action; + + static gboolean handle_logout (GnomeSessionManager *, + GDBusMethodInvocation *, + guint, + gpointer); +}; + +#endif diff --git a/tests/backend-dbus/mock-upower.cc b/tests/backend-dbus/mock-upower.cc new file mode 100644 index 0000000..65757b3 --- /dev/null +++ b/tests/backend-dbus/mock-upower.cc @@ -0,0 +1,103 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include "mock-upower.h" + + +gboolean +MockUPower :: handle_suspend (UPower * upower, + GDBusMethodInvocation * inv, + gpointer gself) +{ + static_cast(gself)->my_last_action = Suspend; + upower_complete_suspend (upower, inv); + return true; +} + +gboolean +MockUPower :: handle_hibernate (UPower * upower, + GDBusMethodInvocation * inv, + gpointer gself) +{ + static_cast(gself)->my_last_action = Hibernate; + upower_complete_hibernate (upower, inv); + return true; +} + +gboolean +MockUPower :: handle_suspend_allowed (UPower * upower, + GDBusMethodInvocation * inv, + gpointer gself) +{ + const bool allowed = static_cast(gself)->my_can_suspend; + upower_complete_suspend_allowed (upower, inv, allowed); + return true; +} + +gboolean +MockUPower :: handle_hibernate_allowed (UPower * upower, + GDBusMethodInvocation * inv, + gpointer gself) +{ + const bool allowed = static_cast(gself)->my_can_hibernate; + upower_complete_hibernate_allowed (upower, inv, allowed); + return true; +} + +/*** +**** +***/ + +namespace +{ + const char * const UPOWER_NAME = "org.freedesktop.UPower"; + const char * const UPOWER_PATH = "/org/freedesktop/UPower"; + +} + +MockUPower :: MockUPower (GMainLoop * loop, + GDBusConnection * bus_connection): + MockObject (loop, bus_connection, UPOWER_NAME, UPOWER_PATH), + my_skeleton (upower_skeleton_new ()), + my_can_suspend (true), + my_can_hibernate (true), + my_suspend_allowed (true), + my_hibernate_allowed (true), + my_last_action (None) +{ + //set_can_hibernate (false); + //set_can_suspend (true); + + g_signal_connect (my_skeleton, "handle-suspend", + G_CALLBACK(handle_suspend), this); + g_signal_connect (my_skeleton, "handle-suspend-allowed", + G_CALLBACK(handle_suspend_allowed), this); + + g_signal_connect (my_skeleton, "handle-hibernate", + G_CALLBACK(handle_hibernate), this); + g_signal_connect (my_skeleton, "handle-hibernate-allowed", + G_CALLBACK(handle_hibernate_allowed), this); + + set_skeleton (G_DBUS_INTERFACE_SKELETON(my_skeleton)); +} + +MockUPower :: ~MockUPower () +{ + g_clear_object (&my_skeleton); +} diff --git a/tests/backend-dbus/mock-upower.h b/tests/backend-dbus/mock-upower.h new file mode 100644 index 0000000..351d0f7 --- /dev/null +++ b/tests/backend-dbus/mock-upower.h @@ -0,0 +1,72 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#ifndef MOCK_UPOWER_H +#define MOCK_UPOWER_H + +#include "mock-object.h" // parent class +#include "backend-dbus/dbus-upower.h" // UPower + +class MockUPower: public MockObject +{ + public: + + MockUPower (GMainLoop * loop, + GDBusConnection * bus_connection); + virtual ~MockUPower (); + + void set_can_suspend (bool b) { upower_set_can_suspend (my_skeleton, b); } + void set_can_hibernate (bool b) { upower_set_can_hibernate (my_skeleton, b); } + + bool suspend_allowed () const { return my_suspend_allowed; } + bool hibernate_allowed () const { return my_suspend_allowed; } + bool can_suspend () const { return upower_get_can_suspend (my_skeleton); } + bool can_hibernate () const { return upower_get_can_hibernate (my_skeleton); } + + public: + + enum Action { None, Suspend, Hibernate }; + Action last_action () { return my_last_action; } + + private: + + UPower * my_skeleton; + bool my_can_suspend; + bool my_can_hibernate; + bool my_suspend_allowed; + bool my_hibernate_allowed; + Action my_last_action; + + static gboolean handle_suspend_allowed (UPower *, + GDBusMethodInvocation *, + gpointer); + static gboolean handle_suspend (UPower *, + GDBusMethodInvocation *, + gpointer); + + static gboolean handle_hibernate_allowed (UPower *, + GDBusMethodInvocation *, + gpointer); + static gboolean handle_hibernate (UPower *, + GDBusMethodInvocation *, + gpointer); + +}; + +#endif diff --git a/tests/backend-dbus/mock-user.cc b/tests/backend-dbus/mock-user.cc new file mode 100644 index 0000000..abf2e21 --- /dev/null +++ b/tests/backend-dbus/mock-user.cc @@ -0,0 +1,131 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include "mock-user.h" + +/*** +**** +***/ + +const char * +MockUser :: username () const +{ + return accounts_user_get_user_name (my_skeleton); +} + +const char * +MockUser :: realname () const +{ + return accounts_user_get_real_name (my_skeleton); +} + +void +MockUser :: set_realname (const char * realname) +{ + accounts_user_set_real_name (my_skeleton, realname); + accounts_user_emit_changed (my_skeleton); +} + +guint +MockUser :: uid () const +{ + return accounts_user_get_uid (my_skeleton); +} + +guint64 +MockUser :: login_frequency () const +{ + return accounts_user_get_login_frequency (my_skeleton); +} + +#if 0 +bool +MockUser :: system_account() const +{ + return accounts_user_get_system_account (my_skeleton); +} +#endif + +void +MockUser :: set_system_account (gboolean b) +{ + accounts_user_set_system_account (my_skeleton, b); +} + +bool +MockUser :: is_guest () const +{ + // a guest will look like this: + // username:[guest-jjbEVV] realname:[Guest] system:[1] + return accounts_user_get_system_account (my_skeleton) + && !g_ascii_strcasecmp (accounts_user_get_real_name(my_skeleton), "Guest"); +} + +/*** +**** +***/ + +namespace +{ + const char * const DBUS_ACCOUNTS_NAME = "org.freedesktop.Accounts"; + + static guint next_uid = 1000; + + std::string path_for_uid (guint uid) + { + char * tmp; + std::string ret; + const char * const DBUS_ACCOUNTS_PATH = "/org/freedesktop/Accounts"; + tmp = g_strdup_printf ("%s/User%u", DBUS_ACCOUNTS_PATH, uid); + ret = tmp; + g_free (tmp); + return ret; + } +} + +guint +MockUser :: get_next_uid () +{ + return next_uid++; +} + + +MockUser :: MockUser (GMainLoop * loop, + GDBusConnection * bus_connection, + const char * userName, + const char * realName, + guint64 login_frequency, + guint uid_): + MockObject (loop, bus_connection, DBUS_ACCOUNTS_NAME, path_for_uid(uid_)), + my_skeleton (accounts_user_skeleton_new ()) +{ + accounts_user_set_uid (my_skeleton, uid_); + accounts_user_set_user_name (my_skeleton, userName); + accounts_user_set_real_name (my_skeleton, realName); + accounts_user_set_login_frequency (my_skeleton, login_frequency); + accounts_user_set_system_account (my_skeleton, false); + + set_skeleton (G_DBUS_INTERFACE_SKELETON(my_skeleton)); +} + +MockUser :: ~MockUser () +{ + g_signal_handlers_disconnect_by_data (my_skeleton, this); + g_clear_object (&my_skeleton); +} diff --git a/tests/backend-dbus/mock-user.h b/tests/backend-dbus/mock-user.h new file mode 100644 index 0000000..c1d3d0f --- /dev/null +++ b/tests/backend-dbus/mock-user.h @@ -0,0 +1,57 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#ifndef MOCK_USER_H +#define MOCK_USER_H + +#include "mock-object.h" // parent class +#include "backend-dbus/dbus-user.h" // AccountsUser + +class MockUser: public MockObject +{ + protected: + + static guint get_next_uid (); + + public: + + MockUser (GMainLoop * loop, + GDBusConnection * bus_connection, + const char * userName, + const char * realName, + guint64 login_frequency, + guint uid = get_next_uid()); + virtual ~MockUser (); + + const char * username () const; + const char * realname () const; + void set_realname (const char *); + guint uid () const; + guint64 login_frequency () const; + //bool system_account() const; + + bool is_guest() const; + void set_system_account (gboolean b); + + private: + + AccountsUser * my_skeleton; +}; + +#endif diff --git a/tests/backend-dbus/mock-webcredentials.cc b/tests/backend-dbus/mock-webcredentials.cc new file mode 100644 index 0000000..44fa8ac --- /dev/null +++ b/tests/backend-dbus/mock-webcredentials.cc @@ -0,0 +1,54 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include "mock-webcredentials.h" + +namespace +{ + const char * const MY_NAME = "com.canonical.indicators.webcredentials"; + const char * const MY_PATH = "/com/canonical/indicators/webcredentials"; +} + +MockWebcredentials :: MockWebcredentials (GMainLoop * loop, + GDBusConnection * bus_connection): + MockObject (loop, bus_connection, MY_NAME, MY_PATH), + my_skeleton (webcredentials_skeleton_new ()) +{ + //set_can_hibernate (false); + //set_can_suspend (true); + +#if 0 + g_signal_connect (my_skeleton, "handle-suspend", + G_CALLBACK(handle_suspend), this); + g_signal_connect (my_skeleton, "handle-suspend-allowed", + G_CALLBACK(handle_suspend_allowed), this); + + g_signal_connect (my_skeleton, "handle-hibernate", + G_CALLBACK(handle_hibernate), this); + g_signal_connect (my_skeleton, "handle-hibernate-allowed", + G_CALLBACK(handle_hibernate_allowed), this); +#endif + + set_skeleton (G_DBUS_INTERFACE_SKELETON(my_skeleton)); +} + +MockWebcredentials :: ~MockWebcredentials () +{ + g_clear_object (&my_skeleton); +} diff --git a/tests/backend-dbus/mock-webcredentials.h b/tests/backend-dbus/mock-webcredentials.h new file mode 100644 index 0000000..212ca76 --- /dev/null +++ b/tests/backend-dbus/mock-webcredentials.h @@ -0,0 +1,42 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#ifndef MOCK_WEBCREDENTIALS_H +#define MOCK_WEBCREDENTIALS_H + +#include "mock-object.h" // parent class +#include "backend-dbus/dbus-webcredentials.h" // Webcredentials + +class MockWebcredentials: public MockObject +{ + public: + + MockWebcredentials (GMainLoop * loop, + GDBusConnection * bus_connection); + virtual ~MockWebcredentials (); + + bool has_error () const { return webcredentials_get_error_status (my_skeleton); } + bool set_error (bool b) const { webcredentials_set_error_status (my_skeleton, b); } + + private: + + Webcredentials * my_skeleton; +}; + +#endif diff --git a/tests/backend-dbus/test-actions.cc b/tests/backend-dbus/test-actions.cc new file mode 100644 index 0000000..f79c913 --- /dev/null +++ b/tests/backend-dbus/test-actions.cc @@ -0,0 +1,454 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include "gtest-mock-dbus-fixture.h" + +#include "backend.h" +#include "backend-dbus/backend-dbus.h" + +/*** +**** +***/ + +class Actions: public GTestMockDBusFixture +{ + private: + + typedef GTestMockDBusFixture super; + + protected: + + GCancellable * cancellable; + IndicatorSessionActions * actions; + + virtual void SetUp () + { + super :: SetUp (); + + // init 'actions' + cancellable = g_cancellable_new (); + actions = 0; + backend_get (cancellable, &actions, NULL, NULL); + g_assert (actions != 0); + wait_msec (100); + } + + virtual void TearDown () + { + g_cancellable_cancel (cancellable); + g_clear_object (&cancellable); + g_clear_object (&actions); + + super :: TearDown (); + } +}; + +/*** +**** +***/ + +TEST_F (Actions, HelloWorld) +{ + ASSERT_TRUE (true); +} + +namespace +{ + static gboolean toggle_can_switch (gpointer settings) + { + const char * key = "disable-user-switching"; + gboolean b = g_settings_get_boolean (G_SETTINGS(settings), key); + g_settings_set_boolean (G_SETTINGS(settings), key, !b); + return G_SOURCE_REMOVE; + } +} + +TEST_F (Actions, CanSwitch) +{ + const char * schema_id = "org.gnome.desktop.lockdown"; + const char * settings_key = "disable-user-switching"; + GSettings * s = g_settings_new (schema_id); + + for (int i=0; i<3; ++i) + { + bool b; + gboolean b2; + + b = ck_seat->can_activate_sessions() && !g_settings_get_boolean (s, settings_key); + ASSERT_EQ (b, indicator_session_actions_can_switch (actions)); + g_object_get (actions, INDICATOR_SESSION_ACTIONS_PROP_CAN_SWITCH, &b2, NULL); + ASSERT_EQ (b, b2); + + g_idle_add (toggle_can_switch, s); + wait_for_signal (actions, "notify::" INDICATOR_SESSION_ACTIONS_PROP_CAN_SWITCH); + } + + g_object_unref (s); +} + +namespace +{ + static gboolean toggle_can_lock (gpointer settings) + { + const char * key = "disable-lock-screen"; + gboolean b = g_settings_get_boolean (G_SETTINGS(settings), key); + g_settings_set_boolean (G_SETTINGS(settings), key, !b); + return G_SOURCE_REMOVE; + } +} + +TEST_F (Actions, CanLock) +{ + const char * schema_id = "org.gnome.desktop.lockdown"; + const char * settings_key = "disable-lock-screen"; + GSettings * s = g_settings_new (schema_id); + + for (int i=0; i<3; ++i) + { + bool b; + gboolean b2; + + b = g_settings_get_boolean (s, settings_key); + ASSERT_EQ (b, !indicator_session_actions_can_lock (actions)); + g_object_get (actions, INDICATOR_SESSION_ACTIONS_PROP_CAN_LOCK, &b2, NULL); + ASSERT_EQ (b, !b2); + + g_idle_add (toggle_can_lock, s); + wait_for_signal (actions, "notify::" INDICATOR_SESSION_ACTIONS_PROP_CAN_LOCK); + } + + g_object_unref (s); +} + +namespace +{ + static gboolean toggle_can_logout (gpointer settings) + { + const char * key = "disable-log-out"; + gboolean b = g_settings_get_boolean (G_SETTINGS(settings), key); + g_settings_set_boolean (G_SETTINGS(settings), key, !b); + return G_SOURCE_REMOVE; + } +} + +TEST_F (Actions, CanLogout) +{ + const char * schema_id = "org.gnome.desktop.lockdown"; + const char * settings_key = "disable-log-out"; + GSettings * s = g_settings_new (schema_id); + + for (int i=0; i<3; ++i) + { + bool b; + gboolean b2; + + b = g_settings_get_boolean (s, settings_key); + ASSERT_EQ (b, !indicator_session_actions_can_logout (actions)); + g_object_get (actions, INDICATOR_SESSION_ACTIONS_PROP_CAN_LOGOUT, &b2, NULL); + ASSERT_EQ (b, !b2); + + g_idle_add (toggle_can_logout, s); + wait_for_signal (actions, "notify::" INDICATOR_SESSION_ACTIONS_PROP_CAN_LOGOUT); + } + + g_object_unref (s); +} + +TEST_F (Actions, CanSuspend) +{ + bool b; + bool can; + bool allowed; + gboolean b2; + + can = upower->can_suspend (); + allowed = upower->suspend_allowed (); + b = can && allowed; + + ASSERT_EQ (b, indicator_session_actions_can_suspend (actions)); + g_object_get (actions, INDICATOR_SESSION_ACTIONS_PROP_CAN_SUSPEND, &b2, NULL); + ASSERT_EQ (b, b2); + + for (int i=0; i<2; ++i) + { + can = !can; + b = can && allowed; + + upower->set_can_suspend (can); + wait_for_signal (actions, "notify::" INDICATOR_SESSION_ACTIONS_PROP_CAN_SUSPEND); + ASSERT_EQ (b, indicator_session_actions_can_suspend (actions)); + g_object_get (actions, INDICATOR_SESSION_ACTIONS_PROP_CAN_SUSPEND, &b2, NULL); + ASSERT_EQ (b, b2); + } +} + +TEST_F (Actions, CanHibernate) +{ + bool b; + bool can; + bool allowed; + gboolean b2; + + can = upower->can_hibernate (); + allowed = upower->hibernate_allowed (); + b = can && allowed; + + ASSERT_EQ (b, indicator_session_actions_can_hibernate (actions)); + g_object_get (actions, INDICATOR_SESSION_ACTIONS_PROP_CAN_HIBERNATE, &b2, NULL); + ASSERT_EQ (b, b2); + +#if 0 + for (int i=0; i<2; ++i) + { + b = !b; + upower->set_can_hibernate (b); + wait_for_signal (actions, "notify::" INDICATOR_SESSION_ACTIONS_PROP_CAN_HIBERNATE); + ASSERT_EQ (b, indicator_session_actions_can_hibernate (actions)); + g_object_get (actions, INDICATOR_SESSION_ACTIONS_PROP_CAN_HIBERNATE, &b2, NULL); + ASSERT_EQ (b, b2); + } +#endif +} + +TEST_F (Actions, Restart) +{ + ASSERT_EQ (MockConsoleKitManager::None, ck_manager->last_action()); + + // confirm that user is prompted + // and that no action is taken when the user cancels the dialog + indicator_session_actions_restart (actions); + wait_msec (50); + ASSERT_TRUE (end_session_dialog->is_open()); + end_session_dialog->cancel(); + wait_msec (50); + ASSERT_EQ (MockConsoleKitManager::None, ck_manager->last_action()); + + // confirm that user is prompted + // and that no action is taken when the user cancels the dialog + indicator_session_actions_restart (actions); + wait_msec (50); + ASSERT_TRUE (end_session_dialog->is_open ()); + end_session_dialog->confirm_reboot (); + wait_msec (100); + ASSERT_EQ (MockConsoleKitManager::Restart, ck_manager->last_action()); + + // confirm that we try to restart w/o prompting + // if the EndSessionDialog isn't available + delete end_session_dialog; + end_session_dialog = 0; + ck_manager->clear_last_action (); + ASSERT_EQ (MockConsoleKitManager::None, ck_manager->last_action()); + wait_msec (50); + indicator_session_actions_restart (actions); + wait_msec (50); + ASSERT_EQ (MockConsoleKitManager::Restart, ck_manager->last_action()); +} + +TEST_F (Actions, Shutdown) +{ + ASSERT_EQ (MockConsoleKitManager::None, ck_manager->last_action()); + + // confirm that user is prompted + // and that no action is taken when the user cancels the dialog + indicator_session_actions_shutdown (actions); + wait_msec (50); + ASSERT_TRUE (end_session_dialog->is_open()); + end_session_dialog->cancel(); + wait_msec (50); + ASSERT_EQ (MockConsoleKitManager::None, ck_manager->last_action()); + + // confirm that user is prompted + // and that no action is taken when the user cancels the dialog + indicator_session_actions_shutdown (actions); + wait_msec (50); + ASSERT_TRUE (end_session_dialog->is_open ()); + end_session_dialog->confirm_shutdown (); + wait_msec (100); + ASSERT_EQ (MockConsoleKitManager::Shutdown, ck_manager->last_action()); + + // confirm that we try to shutdown w/o prompting + // if the EndSessionDialog isn't available + delete end_session_dialog; + end_session_dialog = 0; + ck_manager->clear_last_action (); + wait_msec (50); + indicator_session_actions_shutdown (actions); + wait_msec (50); + ASSERT_EQ (MockConsoleKitManager::Shutdown, ck_manager->last_action()); +} + +TEST_F (Actions, Logout) +{ + ASSERT_EQ (MockConsoleKitManager::None, ck_manager->last_action()); + + // confirm that user is prompted + // and that no action is taken when the user cancels the dialog + indicator_session_actions_logout (actions); + wait_msec (50); + ASSERT_TRUE (end_session_dialog->is_open()); + end_session_dialog->cancel(); + wait_msec (50); + ASSERT_EQ (MockSessionManager::None, session_manager->last_action ()); + + // confirm that user is prompted + // and that no action is taken when the user cancels the dialog + indicator_session_actions_shutdown (actions); + wait_msec (50); + ASSERT_TRUE (end_session_dialog->is_open ()); + end_session_dialog->confirm_logout (); + wait_msec (100); + ASSERT_EQ (MockSessionManager::LogoutQuiet, session_manager->last_action ()); + + // confirm that we try to call SessionManager::LogoutNormal + // if the EndSessionDialog isn't available + delete end_session_dialog; + end_session_dialog = 0; + wait_msec (50); + indicator_session_actions_logout (actions); + wait_msec (50); + ASSERT_EQ (MockSessionManager::LogoutNormal, session_manager->last_action ()); +} + +TEST_F (Actions, Suspend) +{ + ASSERT_EQ (MockUPower::None, upower->last_action()); + indicator_session_actions_suspend (actions); + wait_msec (50); + ASSERT_EQ (MockUPower::Suspend, upower->last_action()); +} + +TEST_F (Actions, Hibernate) +{ + ASSERT_EQ (MockUPower::None, upower->last_action()); + indicator_session_actions_hibernate (actions); + wait_msec (50); + ASSERT_EQ (MockUPower::Hibernate, upower->last_action()); +} + +TEST_F (Actions, SwitchToScreensaver) +{ + ASSERT_EQ (MockScreenSaver::None, screen_saver->last_action()); + indicator_session_actions_switch_to_screensaver (actions); + wait_msec (50); + ASSERT_EQ (MockScreenSaver::Lock, screen_saver->last_action()); +} + +TEST_F (Actions, SwitchToGreeter) +{ + ASSERT_NE (MockDisplayManagerSeat::GREETER, dm_seat->last_action()); + indicator_session_actions_switch_to_greeter (actions); + wait_msec (50); + ASSERT_EQ (MockDisplayManagerSeat::GREETER, dm_seat->last_action()); +} + +TEST_F (Actions, SwitchToGuest) +{ + // allow guests + dm_seat->set_guest_allowed (true); + MockUser * guest_user; + MockConsoleKitSession * guest_ck_session; + + // set up a guest + guest_user = new MockUser (loop, conn, "guest-zzbEVV", "Guest", 10); + guest_user->set_system_account (true); + accounts->add_user (guest_user); + guest_ck_session = ck_seat->add_session_by_user (guest_user); + + // try to switch to guest + indicator_session_actions_switch_to_guest (actions); + wait_for_signal (ck_seat->skeleton(), "active-session-changed"); + ASSERT_EQ (guest_ck_session, ck_manager->current_session()); + wait_msec (50); +} + +TEST_F (Actions, SwitchToUsername) +{ + const char * const dr1_username = "whartnell"; + const char * const dr2_username = "ptroughton"; + MockUser * dr1_user; + MockUser * dr2_user; + MockConsoleKitSession * dr1_session; + MockConsoleKitSession * dr2_session; + + dr1_user = accounts->find_by_username (dr1_username); + dr1_session = ck_seat->add_session_by_user (dr1_user); + + dr2_user = accounts->find_by_username (dr2_username); + dr2_session = ck_seat->add_session_by_user (dr2_user); + + indicator_session_actions_switch_to_username (actions, dr1_username); + wait_for_signal (ck_seat->skeleton(), "active-session-changed"); + ASSERT_EQ (dr1_session, ck_manager->current_session()); + wait_msec (50); + + indicator_session_actions_switch_to_username (actions, dr2_username); + wait_for_signal (ck_seat->skeleton(), "active-session-changed"); + ASSERT_EQ (dr2_session, ck_manager->current_session()); + wait_msec (50); + + indicator_session_actions_switch_to_username (actions, dr1_username); + wait_for_signal (ck_seat->skeleton(), "active-session-changed"); + ASSERT_EQ (dr1_session, ck_manager->current_session()); + wait_msec (50); +} + +TEST_F (Actions, HasOnlineAccountError) +{ + bool b; + gboolean gb; + + b = webcredentials->has_error (); + ASSERT_EQ (b, indicator_session_actions_has_online_account_error (actions)); + g_object_get (actions, INDICATOR_SESSION_ACTIONS_PROP_HAS_ONLINE_ACCOUNT_ERROR, &gb, NULL); + ASSERT_EQ (b, gb); + + b = !b; + webcredentials->set_error (b); + wait_msec (50); + ASSERT_EQ (b, indicator_session_actions_has_online_account_error (actions)); + g_object_get (actions, INDICATOR_SESSION_ACTIONS_PROP_HAS_ONLINE_ACCOUNT_ERROR, &gb, NULL); + ASSERT_EQ (b, gb); + + b = !b; + webcredentials->set_error (b); + wait_msec (50); + ASSERT_EQ (b, indicator_session_actions_has_online_account_error (actions)); + g_object_get (actions, INDICATOR_SESSION_ACTIONS_PROP_HAS_ONLINE_ACCOUNT_ERROR, &gb, NULL); + ASSERT_EQ (b, gb); +} + +TEST_F (Actions, CanPrompt) +{ + gboolean b; + + ASSERT_TRUE (indicator_session_actions_can_prompt (actions)); + + delete end_session_dialog; + end_session_dialog = 0; + wait_msec (50); + ASSERT_FALSE (indicator_session_actions_can_prompt (actions)); + g_object_get (actions, INDICATOR_SESSION_ACTIONS_PROP_CAN_PROMPT, &b, NULL); + ASSERT_FALSE (b); + + end_session_dialog = new MockEndSessionDialog (loop, conn); + wait_msec (50); + ASSERT_TRUE (indicator_session_actions_can_prompt (actions)); + g_object_get (actions, INDICATOR_SESSION_ACTIONS_PROP_CAN_PROMPT, &b, NULL); + ASSERT_TRUE (b); +} diff --git a/tests/backend-dbus/test-guest.cc b/tests/backend-dbus/test-guest.cc new file mode 100644 index 0000000..db55dd1 --- /dev/null +++ b/tests/backend-dbus/test-guest.cc @@ -0,0 +1,192 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include "gtest-mock-dbus-fixture.h" + +#include "backend.h" +#include "backend-dbus/backend-dbus.h" + +/*** +**** +***/ + +class Guest: public GTestMockDBusFixture +{ + private: + + typedef GTestMockDBusFixture super; + + protected: + + GCancellable * cancellable; + IndicatorSessionGuest * guest; + + virtual void SetUp () + { + super :: SetUp (); + + // get the guest-dbus + cancellable = g_cancellable_new (); + guest = 0; + backend_get (cancellable, NULL, NULL, &guest); + wait_msec (100); + + // test the default state + ASSERT_TRUE (guest != 0); + ASSERT_FALSE (indicator_session_guest_is_allowed (guest)); + ASSERT_FALSE (indicator_session_guest_is_logged_in (guest)); + ASSERT_FALSE (indicator_session_guest_is_active (guest)); + } + + virtual void TearDown () + { + g_cancellable_cancel (cancellable); + g_clear_object (&cancellable); + g_clear_object (&guest); + + super :: TearDown (); + } + + protected: + + void add_mock_guest (MockUser *& guest_user, + MockConsoleKitSession *& guest_session) + { + guest_user = new MockUser (loop, conn, "guest-jjbEVV", "Guest", 10); + guest_user->set_system_account (true); + accounts->add_user (guest_user); + guest_session = new MockConsoleKitSession (loop, conn); + guest_session->set_user (guest_user); + ck_seat->add_session (guest_session); + } +}; + +/** + * Confirms that the Fixture's SetUp() and TearDown() work + */ +TEST_F (Guest, HelloWorld) +{ + ASSERT_TRUE (true); +} + +/** + * Toggle in the DM whether or not guests are allowed. + * Confirm that "guest" reflects the changes. + */ +TEST_F (Guest, Allowed) +{ + dm_seat->set_guest_allowed (true); + wait_for_signal (guest, "notify::guest-is-allowed"); + ASSERT_TRUE (indicator_session_guest_is_allowed (guest)); + ASSERT_FALSE (indicator_session_guest_is_logged_in (guest)); + ASSERT_FALSE (indicator_session_guest_is_active (guest)); + + dm_seat->set_guest_allowed (false); + wait_for_signal (guest, "notify::guest-is-allowed"); + ASSERT_FALSE (indicator_session_guest_is_allowed (guest)); + ASSERT_FALSE (indicator_session_guest_is_logged_in (guest)); + ASSERT_FALSE (indicator_session_guest_is_active (guest)); +} + +/** + * Have a guest user log in & out. + * Confirm that "guest" reflects the changes. + */ +TEST_F (Guest, Login) +{ + gboolean b; + + dm_seat->set_guest_allowed (true); + + // Log a Guest in + // And confirm that guest's is_login changes to true + MockUser * guest_user; + MockConsoleKitSession * guest_session; + add_mock_guest (guest_user, guest_session); + wait_for_signal (guest, "notify::guest-is-logged-in"); + ASSERT_TRUE (indicator_session_guest_is_allowed (guest)); + ASSERT_TRUE (indicator_session_guest_is_logged_in (guest)); + g_object_get (guest, INDICATOR_SESSION_GUEST_PROPERTY_LOGGED_IN, &b,NULL); + ASSERT_TRUE (b); + ASSERT_FALSE (indicator_session_guest_is_active (guest)); + + // Log the Guest User out + // and confirm that guest's is_login changes to false + ck_seat->remove_session (guest_session); + accounts->remove_user (guest_user); + delete guest_user; + delete guest_session; + wait_for_signal (guest, "notify::guest-is-logged-in"); + ASSERT_TRUE (indicator_session_guest_is_allowed (guest)); + ASSERT_FALSE (indicator_session_guest_is_logged_in (guest)); + g_object_get (guest, INDICATOR_SESSION_GUEST_PROPERTY_LOGGED_IN, &b,NULL); + ASSERT_FALSE (b); + ASSERT_FALSE (indicator_session_guest_is_active (guest)); +} + +/** + * Activate a Guest session, then activate a different session. + * Confirm that "guest" reflects the changes. + */ +TEST_F (Guest, Active) +{ + gboolean b; + + dm_seat->set_guest_allowed (true); + MockUser * guest_user; + MockConsoleKitSession * guest_session; + add_mock_guest (guest_user, guest_session); + + // Activate the guest session + // and confirm that guest's is_active changes to true + ck_seat->activate_session (guest_session); + wait_for_signal (guest, "notify::guest-is-active-session"); + ASSERT_TRUE (indicator_session_guest_is_allowed (guest)); + ASSERT_TRUE (indicator_session_guest_is_logged_in (guest)); + ASSERT_TRUE (indicator_session_guest_is_active (guest)); + g_object_get (guest, INDICATOR_SESSION_GUEST_PROPERTY_ACTIVE, &b,NULL); + ASSERT_TRUE (b); + + // Activate a non-guest session + // and confirm that guest's is_active changes to false + ck_seat->activate_session (ck_session); + wait_for_signal (guest, "notify::guest-is-active-session"); + ASSERT_TRUE (indicator_session_guest_is_allowed (guest)); + ASSERT_TRUE (indicator_session_guest_is_logged_in (guest)); + ASSERT_FALSE (indicator_session_guest_is_active (guest)); + g_object_get (guest, INDICATOR_SESSION_GUEST_PROPERTY_ACTIVE, &b,NULL); + ASSERT_FALSE (b); +} + +/** + * Activate a guest session using the "guest" API. + * Confirm that the guest session gets activated on the bus. + */ +TEST_F (Guest, Activate) +{ + dm_seat->set_guest_allowed (true); + MockUser * guest_user; + MockConsoleKitSession * guest_session; + add_mock_guest (guest_user, guest_session); + + indicator_session_guest_switch_to_guest (guest); + wait_for_signal (ck_seat->skeleton(), "active-session-changed"); + ASSERT_EQ (guest_session, ck_manager->current_session()); + wait_msec (50); +} diff --git a/tests/backend-dbus/test-users.cc b/tests/backend-dbus/test-users.cc new file mode 100644 index 0000000..bd0547d --- /dev/null +++ b/tests/backend-dbus/test-users.cc @@ -0,0 +1,377 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include "gtest-mock-dbus-fixture.h" + +#include "backend.h" +#include "backend-dbus/backend-dbus.h" + +/*** +**** +***/ + +class Users: public GTestMockDBusFixture +{ + private: + + typedef GTestMockDBusFixture super; + + protected: + + GCancellable * cancellable; + IndicatorSessionUsers * users; + + virtual void SetUp () + { + super :: SetUp (); + + init_event_keys (0); + + // init 'users' + cancellable = g_cancellable_new (); + users = 0; + backend_get (cancellable, NULL, &users, NULL); + g_assert (users != 0); + wait_msec (100); + } + + virtual void TearDown () + { + g_cancellable_cancel (cancellable); + g_clear_object (&cancellable); + g_clear_object (&users); + + super :: TearDown (); + } + + protected: + + void compare_user (const IndicatorSessionUser * isu, + MockUser * mu, + bool is_logged_in, + bool is_current_user) + { + ASSERT_TRUE (isu != 0); + ASSERT_TRUE (mu != 0); + + ASSERT_EQ (mu->uid(), isu->uid); + ASSERT_EQ (mu->login_frequency(), isu->login_frequency); + ASSERT_STREQ (mu->username(), isu->user_name); + ASSERT_STREQ (mu->realname(), isu->real_name); + ASSERT_EQ (is_logged_in, isu->is_logged_in); + ASSERT_EQ (is_current_user, isu->is_current_user); + // FIXME: test icon file? + } + + void compare_user (const std::string & key, + MockUser * mu, + bool is_logged_in, + bool is_current_user) + { + IndicatorSessionUser * isu; + isu = indicator_session_users_get_user (users, key.c_str()); + compare_user (isu, mu, is_logged_in, is_current_user); + indicator_session_user_free (isu); + } + + private: + + void init_event_keys (size_t n) + { + expected_event_count = n; + event_keys.clear(); + } + + static gboolean + wait_for_signals__timeout (gpointer name) + { + g_error ("%s: timed out waiting for signal '%s'", G_STRLOC, (char*)name); + return G_SOURCE_REMOVE; + } + + static void + wait_for_signals__event (IndicatorSessionUser * u G_GNUC_UNUSED, + const char * key, + gpointer gself) + { + Users * self = static_cast(gself); + + self->event_keys.push_back (key); + + if (self->event_keys.size() == self->expected_event_count) + g_main_loop_quit (self->loop); + } + + protected: + + std::vector event_keys; + size_t expected_event_count; + + void wait_for_signals (gpointer o, const gchar * name, size_t n) + { + const int timeout_seconds = 5; // arbitrary + + init_event_keys (n); + + guint handler_id = g_signal_connect (o, name, + G_CALLBACK(wait_for_signals__event), + this); + gulong timeout_id = g_timeout_add_seconds (timeout_seconds, + wait_for_signals__timeout, + (gpointer)name); + g_main_loop_run (loop); + g_source_remove (timeout_id); + g_signal_handler_disconnect (o, handler_id); + } +}; + +/*** +**** +***/ + +/** + * Confirm that the fixture's SetUp() and TearDown() work + */ +TEST_F (Users, HelloWorld) +{ + ASSERT_TRUE (true); +} + + +/** + * Confirm that 'users' can get the cached users from our Mock Accounts + */ +TEST_F (Users, InitialUsers) +{ + const guint logged_in_uid = ck_session->user()->uid(); + GStrv keys = indicator_session_users_get_keys (users); + + ASSERT_EQ (12, g_strv_length (keys)); + + for (int i=0; keys && keys[i]; ++i) + { + MockUser * mu = accounts->find_by_path (keys[i]); + const bool is_logged_in = mu->uid() == logged_in_uid; + const bool is_current_user = mu->uid() == logged_in_uid; + compare_user (keys[i], mu, is_logged_in, is_current_user); + } + + g_strfreev (keys); +} + +/** + * Confirm that 'users' can tell when a new user is added + */ +TEST_F (Users, UserAdded) +{ + MockUser * mu; + + mu = new MockUser (loop, conn, "pcushing", "Peter Cushing", 2); + accounts->add_user (mu); + ASSERT_EQ (0, event_keys.size()); + wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_ADDED, 1); + ASSERT_EQ (1, event_keys.size()); + ASSERT_STREQ (mu->path(), event_keys[0].c_str()); + + compare_user (event_keys[0], mu, false, false); +} + +/** + * Confirm that 'users' can tell when a user is removed + */ +TEST_F (Users, UserRemoved) +{ + MockUser * mu; + + mu = accounts->find_by_username ("pdavison"); + accounts->remove_user (mu); + ASSERT_EQ (0, event_keys.size()); + wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_REMOVED, 1); + ASSERT_EQ (1, event_keys.size()); + ASSERT_STREQ (mu->path(), event_keys[0].c_str()); + + GStrv keys = indicator_session_users_get_keys (users); + ASSERT_EQ (11, g_strv_length (keys)); + g_strfreev (keys); + + ASSERT_TRUE (indicator_session_users_get_user (users, mu->path()) == NULL); + + delete mu; +} + +/** + * Confirm that 'users' notices when a user's real name changes + */ +TEST_F (Users, RealnameChanged) +{ + MockUser * mu; + + mu = accounts->find_by_username ("pdavison"); + const char * const realname = "Peter M. G. Moffett"; + mu->set_realname (realname); + ASSERT_NE (mu->realname(), realname); + ASSERT_STREQ (mu->realname(), realname); + wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 1); + ASSERT_EQ (1, event_keys.size()); + ASSERT_STREQ (mu->path(), event_keys[0].c_str()); + compare_user (mu->path(), mu, false, false); +} + +/** + * Confirm that 'users' notices when users log in and out + */ +TEST_F (Users, LogInLogOut) +{ + // The fist doctor logs in. + // Confirm that 'users' notices. + MockUser * mu = accounts->find_by_username ("whartnell"); + compare_user (mu->path(), mu, false, false); + MockConsoleKitSession * session = ck_seat->add_session_by_user (mu); + wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 1); + ASSERT_STREQ (mu->path(), event_keys[0].c_str()); + compare_user (mu->path(), mu, true, false); + + // The fist doctor logs out. + // Confirm that 'users' notices. + ck_seat->remove_session (session); + wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 1); + ASSERT_EQ (1, event_keys.size()); + ASSERT_STREQ (mu->path(), event_keys[0].c_str()); + compare_user (event_keys[0], mu, false, false); + + delete session; +} + +/** + * Confirm that 'users' notices when the active session changes + */ +TEST_F (Users, ActivateSession) +{ + // The fist doctor logs in. + // Confirm that 'users' notices. + MockUser * mu = accounts->find_by_username ("whartnell"); + compare_user (mu->path(), mu, false, false); + MockConsoleKitSession * session = ck_seat->add_session_by_user (mu); + wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 1); + ASSERT_STREQ (mu->path(), event_keys[0].c_str()); + compare_user (mu->path(), mu, true, false); + + // activate the first doctor's session. + // confirm that 'users' sees he's active and that ck_session isn't. + // this should come in the form of two 'user-changed' events + ck_seat->activate_session (session); + wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 2); + ASSERT_EQ (2, event_keys.size()); + compare_user (event_keys[0], ck_session->user(), true, false); + compare_user (event_keys[1], mu, true, true); + + // switch back to the previous + // confirm that 'users' sees it's active and the first doctor's session isn't + // this should come in the form of two 'user-changed' events + ck_seat->activate_session (ck_session); + wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 2); + ASSERT_EQ (2, event_keys.size()); + compare_user (event_keys[0], mu, true, false); + compare_user (event_keys[1], ck_session->user(), true, true); +} + +/** + * Confirm that we can change the active session via users' API. + * This is nearly the same as ActivateSession but uses users' API + */ +TEST_F (Users, ActivateUser) +{ + // The fist doctor logs in. + // Confirm that 'users' notices. + MockUser * mu = accounts->find_by_username ("whartnell"); + compare_user (mu->path(), mu, false, false); + MockConsoleKitSession * session = ck_seat->add_session_by_user (mu); + wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 1); + ASSERT_STREQ (mu->path(), event_keys[0].c_str()); + compare_user (mu->path(), mu, true, false); + + // activate the first doctor's session. + // confirm that 'users' sees he's active and that ck_session isn't. + // this should come in the form of two 'user-changed' events + indicator_session_users_activate_user (users, mu->path()); + ck_seat->activate_session (session); + wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 2); + ASSERT_EQ (2, event_keys.size()); + compare_user (event_keys[0], ck_session->user(), true, false); + compare_user (event_keys[1], mu, true, true); + + // switch back to the previous + // confirm that 'users' sees it's active and the first doctor's session isn't + // this should come in the form of two 'user-changed' events + indicator_session_users_activate_user (users, ck_session->user()->path()); + ck_seat->activate_session (ck_session); + wait_for_signals (users, INDICATOR_SESSION_USERS_SIGNAL_USER_CHANGED, 2); + ASSERT_EQ (2, event_keys.size()); + compare_user (event_keys[0], mu, true, false); + compare_user (event_keys[1], ck_session->user(), true, true); +} + +/** + * Confirm that adding a Guest doesn't show up in the users list + */ +TEST_F (Users, UnwantedGuest) +{ + GStrv keys; + + keys = indicator_session_users_get_keys (users); + const size_t n = g_strv_length (keys); + g_strfreev (keys); + + MockUser * mu = new MockUser (loop, conn, "guest-jjbEVV", "Guest", 1); + mu->set_system_account (true); + accounts->add_user (mu); + wait_msec (50); + + keys = indicator_session_users_get_keys (users); + ASSERT_EQ (n, g_strv_length (keys)); + g_strfreev (keys); +} + + +/** + * Confirm that we can detect live sessions + */ +TEST_F (Users, LiveSession) +{ + gboolean b; + + // not initially a live session + ASSERT_FALSE (indicator_session_users_is_live_session (users)); + g_object_get (users, INDICATOR_SESSION_USERS_PROP_IS_LIVE_SESSION, &b, NULL); + ASSERT_FALSE (b); + + // now add the criteria for a live session + MockUser * live_user = new MockUser (loop, conn, "ubuntu", "Ubuntu", 1, 999); + live_user->set_system_account (true); + accounts->add_user (live_user); + MockConsoleKitSession * session = ck_seat->add_session_by_user (live_user); + wait_msec (100); + ck_seat->activate_session (session); + wait_for_signal (users, "notify::"INDICATOR_SESSION_USERS_PROP_IS_LIVE_SESSION); + + // confirm the backend thinks it's a live session + ASSERT_TRUE (indicator_session_users_is_live_session (users)); + g_object_get (users, INDICATOR_SESSION_USERS_PROP_IS_LIVE_SESSION, &b, NULL); + ASSERT_TRUE (b); +} diff --git a/tests/backend-mock-actions.c b/tests/backend-mock-actions.c new file mode 100644 index 0000000..121c7ba --- /dev/null +++ b/tests/backend-mock-actions.c @@ -0,0 +1,229 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include +#include + +#include "backend-mock.h" +#include "backend-mock-actions.h" + +G_DEFINE_TYPE (IndicatorSessionActionsMock, + indicator_session_actions_mock, + INDICATOR_TYPE_SESSION_ACTIONS) + +/*** +**** Virtual Functions +***/ + +static gboolean +my_can_lock (IndicatorSessionActions * self G_GNUC_UNUSED) +{ + return g_settings_get_boolean (mock_settings, "can-lock"); +} + +static gboolean +my_can_logout (IndicatorSessionActions * self G_GNUC_UNUSED) +{ + return g_settings_get_boolean (mock_settings, "can-logout"); +} + +static gboolean +my_can_switch (IndicatorSessionActions * self G_GNUC_UNUSED) +{ + return g_settings_get_boolean (mock_settings, "can-switch-sessions"); +} + +static gboolean +my_can_suspend (IndicatorSessionActions * self G_GNUC_UNUSED) +{ + return g_settings_get_boolean (mock_settings, "can-suspend"); +} + +static gboolean +my_can_hibernate (IndicatorSessionActions * self G_GNUC_UNUSED) +{ + return g_settings_get_boolean (mock_settings, "can-hibernate"); +} + +static void +my_logout (IndicatorSessionActions * self G_GNUC_UNUSED) +{ + g_settings_set_string (mock_settings, "last-command", "logout"); +} + +static void +my_suspend (IndicatorSessionActions * self G_GNUC_UNUSED) +{ + g_settings_set_string (mock_settings, "last-command", "suspend"); +} + +static void +my_hibernate (IndicatorSessionActions * self G_GNUC_UNUSED) +{ + g_settings_set_string (mock_settings, "last-command", "hibernate"); +} + +static void +my_restart (IndicatorSessionActions * self G_GNUC_UNUSED) +{ + g_settings_set_string (mock_settings, "last-command", "restart"); +} + +static void +my_shutdown (IndicatorSessionActions * self G_GNUC_UNUSED) +{ + g_settings_set_string (mock_settings, "last-command", "shutdown"); +} + +static void +my_switch_to_screensaver (IndicatorSessionActions * self G_GNUC_UNUSED) +{ + g_settings_set_string (mock_settings, "last-command", "switch-to-screensaver"); +} + +static void +my_switch_to_greeter (IndicatorSessionActions * self G_GNUC_UNUSED) +{ + g_settings_set_string (mock_settings, "last-command", "switch-to-greeter"); +} + +static void +my_switch_to_guest (IndicatorSessionActions * self G_GNUC_UNUSED) +{ + g_settings_set_string (mock_settings, "last-command", "switch-to-guest"); +} + +static void +my_switch_to_username (IndicatorSessionActions * self G_GNUC_UNUSED, + const char * username) +{ + gchar * str = g_strdup_printf ("switch-to-user::%s", username); + g_settings_set_string (mock_settings, "last-command", str); +} + +static void +my_help (IndicatorSessionActions * self G_GNUC_UNUSED) +{ + g_settings_set_string (mock_settings, "last-command", "help"); +} + +static void +my_about (IndicatorSessionActions * self G_GNUC_UNUSED) +{ + g_settings_set_string (mock_settings, "last-command", "about"); +} + +static void +my_settings (IndicatorSessionActions * self G_GNUC_UNUSED) +{ + g_settings_set_string (mock_settings, "last-command", "settings"); +} + +static gboolean +my_can_prompt (IndicatorSessionActions * self G_GNUC_UNUSED) +{ + return g_settings_get_boolean (mock_settings, "can-prompt"); +} + +static gboolean +my_has_online_account_error (IndicatorSessionActions * self G_GNUC_UNUSED) +{ + return g_settings_get_boolean (mock_settings, "has-online-account-error"); +} + +static void +my_dispose (GObject * o) +{ + G_OBJECT_CLASS (indicator_session_actions_mock_parent_class)->dispose (o); +} + +static void +my_finalize (GObject * o) +{ + G_OBJECT_CLASS (indicator_session_actions_mock_parent_class)->finalize (o); +} + +/*** +**** GObject Boilerplate +***/ + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_actions_mock_class_init (IndicatorSessionActionsMockClass * klass) +{ + GObjectClass * object_class; + IndicatorSessionActionsClass * actions_class; + + object_class = G_OBJECT_CLASS (klass); + object_class->dispose = my_dispose; + object_class->finalize = my_finalize; + + actions_class = INDICATOR_SESSION_ACTIONS_CLASS (klass); + actions_class->can_lock = my_can_lock; + actions_class->can_logout = my_can_logout; + actions_class->can_switch = my_can_switch; + actions_class->can_suspend = my_can_suspend; + actions_class->can_hibernate = my_can_hibernate; + actions_class->can_prompt = my_can_prompt; + actions_class->has_online_account_error = my_has_online_account_error; + actions_class->logout = my_logout; + actions_class->suspend = my_suspend; + actions_class->hibernate = my_hibernate; + actions_class->restart = my_restart; + actions_class->shutdown = my_shutdown; + actions_class->settings = my_settings; + actions_class->help = my_help; + actions_class->about = my_about; + actions_class->switch_to_screensaver = my_switch_to_screensaver; + actions_class->switch_to_greeter = my_switch_to_greeter; + actions_class->switch_to_guest = my_switch_to_guest; + actions_class->switch_to_username = my_switch_to_username; +} + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_actions_mock_init (IndicatorSessionActionsMock * self) +{ + g_signal_connect_swapped (mock_settings, "changed::can-lock", + G_CALLBACK(indicator_session_actions_notify_can_lock), self); + g_signal_connect_swapped (mock_settings, "changed::can-logout", + G_CALLBACK(indicator_session_actions_notify_can_logout), self); + g_signal_connect_swapped (mock_settings, "changed::can-switch-sessions", + G_CALLBACK(indicator_session_actions_notify_can_switch), self); + g_signal_connect_swapped (mock_settings, "changed::can-suspend", + G_CALLBACK(indicator_session_actions_notify_can_suspend), self); + g_signal_connect_swapped (mock_settings, "changed::can-hibernate", + G_CALLBACK(indicator_session_actions_notify_can_hibernate), self); + g_signal_connect_swapped (mock_settings, "changed::can-prompt", + G_CALLBACK(indicator_session_actions_notify_can_prompt), self); + g_signal_connect_swapped (mock_settings, "changed::has-online-account-error", + G_CALLBACK(indicator_session_actions_notify_has_online_account_error), self); +} + +/*** +**** Public +***/ + +IndicatorSessionActions * +indicator_session_actions_mock_new (void) +{ + gpointer o = g_object_new (INDICATOR_TYPE_SESSION_ACTIONS_MOCK, NULL); + + return INDICATOR_SESSION_ACTIONS (o); +} diff --git a/tests/backend-mock-actions.h b/tests/backend-mock-actions.h new file mode 100644 index 0000000..bd9ed47 --- /dev/null +++ b/tests/backend-mock-actions.h @@ -0,0 +1,61 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#ifndef __INDICATOR_SESSION_ACTIONS_MOCK_H__ +#define __INDICATOR_SESSION_ACTIONS_MOCK_H__ + +#include +#include + +#include "actions.h" /* parent class */ + +G_BEGIN_DECLS + +#define INDICATOR_TYPE_SESSION_ACTIONS_MOCK (indicator_session_actions_mock_get_type()) +#define INDICATOR_SESSION_ACTIONS_MOCK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_SESSION_ACTIONS_MOCK, IndicatorSessionActionsMock)) +#define INDICATOR_SESSION_ACTIONS_MOCK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_SESSION_ACTIONS_MOCK, IndicatorSessionActionsMockClass)) +#define INDICATOR_IS_SESSION_ACTIONS_MOCK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_SESSION_ACTIONS_MOCK)) + +typedef struct _IndicatorSessionActionsMock IndicatorSessionActionsMock; +typedef struct _IndicatorSessionActionsMockPriv IndicatorSessionActionsMockPriv; +typedef struct _IndicatorSessionActionsMockClass IndicatorSessionActionsMockClass; + +/** + * An implementation of IndicatorSessionActions that gets its user information + * from org.freedesktop.ConsoleKit and org.freedesktop.Accounts over DBus. + */ +struct _IndicatorSessionActionsMock +{ + /*< private >*/ + IndicatorSessionActions parent; + IndicatorSessionActionsMockPriv * priv; +}; + +struct _IndicatorSessionActionsMockClass +{ + IndicatorSessionActionsClass parent_class; +}; + +GType indicator_session_actions_mock_get_type (void); + +IndicatorSessionActions * indicator_session_actions_mock_new (void); + +G_END_DECLS + +#endif /* __INDICATOR_SESSION_ACTIONS_MOCK_H__ */ diff --git a/tests/backend-mock-guest.c b/tests/backend-mock-guest.c new file mode 100644 index 0000000..0428783 --- /dev/null +++ b/tests/backend-mock-guest.c @@ -0,0 +1,129 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include + +#include "backend-mock-guest.h" + +struct _IndicatorSessionGuestMockPriv +{ + gboolean guest_is_active; + gboolean guest_is_logged_in; + gboolean guest_is_allowed; +}; + +typedef IndicatorSessionGuestMockPriv priv_t; + +G_DEFINE_TYPE (IndicatorSessionGuestMock, + indicator_session_guest_mock, + INDICATOR_TYPE_SESSION_GUEST) + +/*** +**** Virtual Functions +***/ + +static void +my_dispose (GObject * o) +{ + G_OBJECT_CLASS (indicator_session_guest_mock_parent_class)->dispose (o); +} + +static void +my_finalize (GObject * o) +{ + G_OBJECT_CLASS (indicator_session_guest_mock_parent_class)->finalize (o); +} + +static gboolean +my_is_allowed (IndicatorSessionGuest * self) +{ + return INDICATOR_SESSION_GUEST_MOCK(self)->priv->guest_is_allowed; +} + +static gboolean +my_is_logged_in (IndicatorSessionGuest * self) +{ + g_return_val_if_fail (INDICATOR_IS_SESSION_GUEST_MOCK(self), FALSE); + + return INDICATOR_SESSION_GUEST_MOCK(self)->priv->guest_is_logged_in; +} + +static gboolean +my_is_active (IndicatorSessionGuest * self) +{ + return INDICATOR_SESSION_GUEST_MOCK(self)->priv->guest_is_active; +} + +static void +my_switch_to_guest (IndicatorSessionGuest * self) +{ + g_message ("%s %s FIXME", G_STRLOC, G_STRFUNC); +} + +/*** +**** GObject Boilerplate +***/ + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_guest_mock_class_init (IndicatorSessionGuestMockClass * klass) +{ + GObjectClass * object_class; + IndicatorSessionGuestClass * guest_class; + + object_class = G_OBJECT_CLASS (klass); + object_class->dispose = my_dispose; + object_class->finalize = my_finalize; + + guest_class = INDICATOR_SESSION_GUEST_CLASS (klass); + guest_class->is_allowed = my_is_allowed; + guest_class->is_logged_in = my_is_logged_in; + guest_class->is_active = my_is_active; + guest_class->switch_to_guest = my_switch_to_guest; + + g_type_class_add_private (klass, sizeof (IndicatorSessionGuestMockPriv)); +} + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_guest_mock_init (IndicatorSessionGuestMock * self) +{ + priv_t * p; + + p = G_TYPE_INSTANCE_GET_PRIVATE (self, + INDICATOR_TYPE_SESSION_GUEST_MOCK, + IndicatorSessionGuestMockPriv); + self->priv = p; + + p->guest_is_allowed = TRUE; + p->guest_is_active = FALSE; + p->guest_is_logged_in = FALSE; +} + +/*** +**** Public +***/ + +IndicatorSessionGuest * +indicator_session_guest_mock_new (void) +{ + gpointer o = g_object_new (INDICATOR_TYPE_SESSION_GUEST_MOCK, NULL); + + return INDICATOR_SESSION_GUEST (o); +} diff --git a/tests/backend-mock-guest.h b/tests/backend-mock-guest.h new file mode 100644 index 0000000..db6ce86 --- /dev/null +++ b/tests/backend-mock-guest.h @@ -0,0 +1,61 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#ifndef __GUEST_MOCK_H__ +#define __GUEST_MOCK_H__ + +#include +#include + +#include "guest.h" /* parent class */ + +G_BEGIN_DECLS + +#define INDICATOR_TYPE_SESSION_GUEST_MOCK (indicator_session_guest_mock_get_type()) +#define INDICATOR_SESSION_GUEST_MOCK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_SESSION_GUEST_MOCK, IndicatorSessionGuestMock)) +#define INDICATOR_SESSION_GUEST_MOCK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_SESSION_GUEST_MOCK, IndicatorSessionGuestMockClass)) +#define INDICATOR_IS_SESSION_GUEST_MOCK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_SESSION_GUEST_MOCK)) + +typedef struct _IndicatorSessionGuestMock IndicatorSessionGuestMock; +typedef struct _IndicatorSessionGuestMockPriv IndicatorSessionGuestMockPriv; +typedef struct _IndicatorSessionGuestMockClass IndicatorSessionGuestMockClass; + +/** + * An implementation of IndicatorSessionGuest that gets its user information + * from org.freedesktop.ConsoleKit and org.freedesktop.Accounts over DBus. + */ +struct _IndicatorSessionGuestMock +{ + /*< private >*/ + IndicatorSessionGuest parent; + IndicatorSessionGuestMockPriv * priv; +}; + +struct _IndicatorSessionGuestMockClass +{ + IndicatorSessionGuestClass parent_class; +}; + +GType indicator_session_guest_mock_get_type (void); + +IndicatorSessionGuest * indicator_session_guest_mock_new (void); + +G_END_DECLS + +#endif diff --git a/tests/backend-mock-users.c b/tests/backend-mock-users.c new file mode 100644 index 0000000..d9ab5a8 --- /dev/null +++ b/tests/backend-mock-users.c @@ -0,0 +1,189 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include "backend-mock.h" +#include "backend-mock-users.h" + +struct _IndicatorSessionUsersMockPriv +{ + GHashTable * users; +}; + +typedef IndicatorSessionUsersMockPriv priv_t; + +G_DEFINE_TYPE (IndicatorSessionUsersMock, + indicator_session_users_mock, + INDICATOR_TYPE_SESSION_USERS) + +/*** +**** +***/ + +static void +my_dispose (GObject * o) +{ + G_OBJECT_CLASS (indicator_session_users_mock_parent_class)->dispose (o); +} + +static void +my_finalize (GObject * o) +{ + priv_t * p = INDICATOR_SESSION_USERS_MOCK (o)->priv; + + g_hash_table_destroy (p->users); + + G_OBJECT_CLASS (indicator_session_users_mock_parent_class)->finalize (o); +} + +static gboolean +my_is_live_session (IndicatorSessionUsers * users G_GNUC_UNUSED) +{ + return g_settings_get_boolean (mock_settings, "is-live-session"); +} + +static void +my_activate_user (IndicatorSessionUsers * users, const char * key) +{ + g_message ("%s %s users %p key %s FIXME", G_STRLOC, G_STRFUNC, (void*)users, key); +} + +static GStrv +my_get_keys (IndicatorSessionUsers * users) +{ + int i; + priv_t * p; + gchar ** keys; + GHashTableIter iter; + gpointer key; + + g_return_val_if_fail (INDICATOR_IS_SESSION_USERS_MOCK(users), NULL); + p = INDICATOR_SESSION_USERS_MOCK (users)->priv; + + i = 0; + keys = g_new (gchar*, g_hash_table_size(p->users)+1); + g_hash_table_iter_init (&iter, p->users); + while (g_hash_table_iter_next (&iter, &key, NULL)) + keys[i++] = g_strdup (key); + keys[i] = NULL; + + return keys; +} + +static IndicatorSessionUser * +my_get_user (IndicatorSessionUsers * self, const gchar * key) +{ + priv_t * p; + const IndicatorSessionUser * src; + IndicatorSessionUser * ret = NULL; + + g_return_val_if_fail (INDICATOR_IS_SESSION_USERS_MOCK(self), NULL); + p = INDICATOR_SESSION_USERS_MOCK (self)->priv; + + if ((src = g_hash_table_lookup (p->users, key))) + { + ret = g_new0 (IndicatorSessionUser, 1); + ret->is_current_user = src->is_current_user; + ret->is_logged_in = src->is_logged_in; + ret->uid = src->uid; + ret->login_frequency = src->login_frequency; + ret->user_name = g_strdup (src->user_name); + ret->real_name = g_strdup (src->real_name); + ret->icon_file = g_strdup (src->icon_file); + } + + return ret; +} + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_users_mock_class_init (IndicatorSessionUsersMockClass * klass) +{ + GObjectClass * object_class; + IndicatorSessionUsersClass * users_class; + + object_class = G_OBJECT_CLASS (klass); + object_class->dispose = my_dispose; + object_class->finalize = my_finalize; + + users_class = INDICATOR_SESSION_USERS_CLASS (klass); + users_class->is_live_session = my_is_live_session; + users_class->get_keys = my_get_keys; + users_class->get_user = my_get_user; + users_class->activate_user = my_activate_user; + + g_type_class_add_private (klass, sizeof (IndicatorSessionUsersMockPriv)); +} + +static void +/* cppcheck-suppress unusedFunction */ +indicator_session_users_mock_init (IndicatorSessionUsersMock * self) +{ + priv_t * p; + + p = G_TYPE_INSTANCE_GET_PRIVATE (self, + INDICATOR_TYPE_SESSION_USERS_MOCK, + IndicatorSessionUsersMockPriv); + self->priv = p; + + p->users = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + (GDestroyNotify)indicator_session_user_free); + + g_signal_connect_swapped (mock_settings, "changed::is-live-session", + G_CALLBACK(indicator_session_users_notify_is_live_session), self); +} + +/*** +**** Public +***/ + +IndicatorSessionUsers * +indicator_session_users_mock_new (void) +{ + gpointer o = g_object_new (INDICATOR_TYPE_SESSION_USERS_MOCK, NULL); + + return INDICATOR_SESSION_USERS (o); +} + + +void +indicator_session_users_mock_add_user (IndicatorSessionUsersMock * self, + const char * key, + IndicatorSessionUser * user) +{ + g_return_if_fail (INDICATOR_IS_SESSION_USERS_MOCK (self)); + g_return_if_fail (key && *key); + g_return_if_fail (user != NULL); + + g_hash_table_insert (self->priv->users, g_strdup(key), user); + indicator_session_users_added (INDICATOR_SESSION_USERS (self), key); +} + +void +indicator_session_users_mock_remove_user (IndicatorSessionUsersMock * self, + const char * key) +{ + g_return_if_fail (INDICATOR_IS_SESSION_USERS_MOCK (self)); + g_return_if_fail (key && *key); + + g_hash_table_remove (self->priv->users, key); + indicator_session_users_removed (INDICATOR_SESSION_USERS (self), key); +} + diff --git a/tests/backend-mock-users.h b/tests/backend-mock-users.h new file mode 100644 index 0000000..c7e11d3 --- /dev/null +++ b/tests/backend-mock-users.h @@ -0,0 +1,70 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#ifndef __USERS_MOCK_H__ +#define __USERS_MOCK_H__ + +#include +#include + +#include "users.h" /* parent class */ + +G_BEGIN_DECLS + +#define INDICATOR_TYPE_SESSION_USERS_MOCK (indicator_session_users_mock_get_type()) +#define INDICATOR_SESSION_USERS_MOCK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_SESSION_USERS_MOCK, IndicatorSessionUsersMock)) +#define INDICATOR_SESSION_USERS_MOCK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_SESSION_USERS_MOCK, IndicatorSessionUsersMockClass)) +#define INDICATOR_IS_SESSION_USERS_MOCK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_SESSION_USERS_MOCK)) + +typedef struct _IndicatorSessionUsersMock IndicatorSessionUsersMock; +typedef struct _IndicatorSessionUsersMockPriv IndicatorSessionUsersMockPriv; +typedef struct _IndicatorSessionUsersMockClass IndicatorSessionUsersMockClass; + +/** + * An implementation of IndicatorSessionUsers that gets its user information + * from org.freedesktop.ConsoleKit and org.freedesktop.Accounts over DBus. + */ +struct _IndicatorSessionUsersMock +{ + /*< private >*/ + IndicatorSessionUsers parent; + IndicatorSessionUsersMockPriv * priv; +}; + +struct _IndicatorSessionUsersMockClass +{ + IndicatorSessionUsersClass parent_class; +}; + +GType indicator_session_users_mock_get_type (void); + +IndicatorSessionUsers * indicator_session_users_mock_new (void); + +void indicator_session_users_mock_add_user (IndicatorSessionUsersMock * self, + const char * key, + IndicatorSessionUser * user); + +void indicator_session_users_mock_remove_user (IndicatorSessionUsersMock * self, + const char * key); + + + +G_END_DECLS + +#endif diff --git a/tests/backend-mock.c b/tests/backend-mock.c new file mode 100644 index 0000000..48d7de4 --- /dev/null +++ b/tests/backend-mock.c @@ -0,0 +1,44 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include "backend-mock.h" +#include "backend-mock-actions.h" +#include "backend-mock-guest.h" +#include "backend-mock-users.h" + +GSettings * mock_settings = NULL; +IndicatorSessionActions * mock_actions = NULL; +IndicatorSessionUsers * mock_users = NULL; +IndicatorSessionGuest * mock_guest = NULL; + +void +backend_get (GCancellable * cancellable G_GNUC_UNUSED, + IndicatorSessionActions ** setme_actions, + IndicatorSessionUsers ** setme_users, + IndicatorSessionGuest ** setme_guest) +{ + if (setme_actions != NULL) + *setme_actions = g_object_ref (mock_actions); + + if (setme_users != NULL) + *setme_users = g_object_ref (mock_users); + + if (setme_guest != NULL) + *setme_guest = g_object_ref (mock_guest); +} diff --git a/tests/backend-mock.h b/tests/backend-mock.h new file mode 100644 index 0000000..d80a185 --- /dev/null +++ b/tests/backend-mock.h @@ -0,0 +1,38 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#ifndef __BACKEND_MOCK_H__ +#define __BACKEND_MOCK_H__ + +#include /* GCancellable */ + +#include "actions.h" +#include "guest.h" +#include "users.h" + +G_BEGIN_DECLS + +extern GSettings * mock_settings; +extern IndicatorSessionActions * mock_actions; +extern IndicatorSessionUsers * mock_users; +extern IndicatorSessionGuest * mock_guest; + +G_END_DECLS + +#endif diff --git a/tests/com.canonical.indicator.session.backendmock.gschema.xml b/tests/com.canonical.indicator.session.backendmock.gschema.xml new file mode 100644 index 0000000..34479df --- /dev/null +++ b/tests/com.canonical.indicator.session.backendmock.gschema.xml @@ -0,0 +1,41 @@ + + + + + '' + The last command activated + + + false + Has online account error + + + true + Is hibernation allowed? + + + true + Is suspending allowed? + + + true + Is logging out allowed? + + + true + Is locking the session allowed? + + + true + Is switching sessions allowed? + + + true + Do we have a way of prompting for confirmation? + + + false + Is this a session running on a live CD? + + + diff --git a/tests/com.canonical.indicator.session.gschema.xml b/tests/com.canonical.indicator.session.gschema.xml new file mode 100644 index 0000000..76b2be3 --- /dev/null +++ b/tests/com.canonical.indicator.session.gschema.xml @@ -0,0 +1,32 @@ + + + + + false + Suppress the dialog to confirm logout, restart and shutdown action + Whether or not to show confirmation dialogs for logout, restart and shutdown actions. + + + false + Remove the Log Out item from the session menu + Makes it so that the logout button doesn’t show in the session menu. + + + false + Remove the Restart item from the session menu + Makes it so that the restart button doesn’t show in the session menu. + + + false + Remove the shutdown item from the session menu + Makes it so that the shutdown button doesn’t show in the session menu. + + + false + Determine the visibility of the User's real name on the panel + Allow for the Removal of the users name from the panel + + + + + \ No newline at end of file diff --git a/tests/gtest-dbus-fixture.h b/tests/gtest-dbus-fixture.h new file mode 100644 index 0000000..e6cd9c7 --- /dev/null +++ b/tests/gtest-dbus-fixture.h @@ -0,0 +1,134 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + */ + +#include +#include + +#include + +/*** +**** +***/ + +class GTestDBusFixture : public ::testing::Test +{ + private: + + static void + on_bus_opened (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself) + { + GTestDBusFixture * self = static_cast(gself); + + GError * err = 0; + self->conn = g_bus_get_finish (res, &err); + g_assert_no_error (err); + + g_main_loop_quit (self->loop); + } + + static void + on_bus_closed (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself) + { + GTestDBusFixture * self = static_cast(gself); + + GError * err = 0; + g_dbus_connection_close_finish (self->conn, res, &err); + g_assert_no_error (err); + + g_main_loop_quit (self->loop); + } + + static gboolean + wait_for_signal__timeout (gpointer name) + { + g_error ("%s: timed out waiting for signal '%s'", G_STRLOC, (char*)name); + return G_SOURCE_REMOVE; + } + + protected: + + virtual void SetUp () + { + conn = 0; + test_dbus = 0; + loop = 0; + + g_setenv ("GSETTINGS_SCHEMA_DIR", SCHEMA_DIR, TRUE); + g_setenv ("GSETTINGS_BACKEND", "memory", TRUE); + g_debug ("SCHEMA_DIR is %s", SCHEMA_DIR); + + // pull up a test dbus + loop = g_main_loop_new (NULL, FALSE); + test_dbus = g_test_dbus_new (G_TEST_DBUS_NONE); + g_test_dbus_add_service_dir (test_dbus, INDICATOR_SERVICE_DIR); + g_debug ("INDICATOR_SERVICE_DIR is %s", INDICATOR_SERVICE_DIR); + g_test_dbus_up (test_dbus); + const char * address; + address = g_test_dbus_get_bus_address (test_dbus); + g_setenv ("DBUS_SYSTEM_BUS_ADDRESS", address, TRUE); + g_debug ("test_dbus's address is %s", address); + + // wait for the GDBusConnection before returning + g_bus_get (G_BUS_TYPE_SYSTEM, NULL, on_bus_opened, this); + g_main_loop_run (loop); + } + + virtual void TearDown() + { + // close the bus connection + g_dbus_connection_close (conn, NULL, on_bus_closed, this); + g_main_loop_run (loop); + g_clear_object (&conn); + + // tear down the test dbus + g_test_dbus_down (test_dbus); + g_clear_object (&test_dbus); + + g_clear_pointer (&loop, g_main_loop_unref); + } + + /* convenience func to loop while waiting for a GObject's signal */ + void wait_for_signal (gpointer o, const gchar * signal) + { + const int timeout_seconds = 5; // arbitrary + + // wait for the signal or for timeout, whichever comes first + guint handler_id = g_signal_connect_swapped (o, signal, + G_CALLBACK(g_main_loop_quit), + loop); + gulong timeout_id = g_timeout_add_seconds (timeout_seconds, + wait_for_signal__timeout, + loop); + g_main_loop_run (loop); + g_source_remove (timeout_id); + g_signal_handler_disconnect (o, handler_id); + } + + /* convenience func to loop for N msec */ + void wait_msec (int msec) + { + guint id = g_timeout_add (msec, (GSourceFunc)g_main_loop_quit, loop); + g_main_loop_run (loop); + g_source_remove (id); + } + + GMainLoop * loop; + GTestDBus * test_dbus; + GDBusConnection * conn; +}; diff --git a/tests/indicator-session.service.in b/tests/indicator-session.service.in index 80aab0d..fb3798a 100644 --- a/tests/indicator-session.service.in +++ b/tests/indicator-session.service.in @@ -1,3 +1,3 @@ [D-BUS Service] -Name=com.canonical.indicator.session -Exec=@abs_top_builddir@/src/indicator-session-service +Name=com.canonical.indicator.session-test +Exec=${CMAKE_BINARY_DIR}/src/indicator-session-service --mock diff --git a/tests/test-service.cc b/tests/test-service.cc index b1ca5bc..058fc3d 100644 --- a/tests/test-service.cc +++ b/tests/test-service.cc @@ -17,70 +17,329 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include -#include -#include - -#include - -#include "shared-names.h" +#include "gtest-dbus-fixture.h" +#include "service.h" +#include "backend-mock.h" +#include "backend-mock-users.h" +#include "backend-mock-guest.h" +#include "backend-mock-actions.h" /*** **** ***/ -#define INDICATOR_SERVICE_OBJECT_PATH "/org/ayatana/indicator/service" -#define INDICATOR_SERVICE_INTERFACE_NAME "org.ayatana.indicator.service" +#if 0 +namespace +{ + void + dump_menu_model (GMenuModel * model, int depth) + { + GString * indent = g_string_new_len (" ", (depth*4)); + const int n = g_menu_model_get_n_items (model); + g_message ("%s depth[%d] menu model[%p] has %d items", indent->str, depth, (void*)model, n); + + for (int i=0; istr, depth, (void*)model, i, name, str); + g_free (str); + g_variant_unref (attribute_value); + } + g_clear_object (&attribute_iter); + + GMenuLinkIter * link_iter = g_menu_model_iterate_item_links (model, i); + while (g_menu_link_iter_get_next (link_iter, &name, &link_value)) + { + g_message ("%s depth[%d] menu model[%p] item[%d] attribute key[%s] model[%p]", indent->str, depth, (void*)model, i, name, (void*)link_value); + dump_menu_model (link_value, depth+1); + g_object_unref (link_value); + } + g_clear_object (&link_iter); + } + g_string_free (indent, TRUE); + } +} +#endif -class ClientTest : public ::testing::Test + +/* cppcheck-suppress noConstructor */ +class ServiceTest: public GTestDBusFixture { + typedef GTestDBusFixture super; + + enum { TIME_LIMIT_SEC = 10 }; + + private: + + static void on_name_appeared (GDBusConnection * connection G_GNUC_UNUSED, + const gchar * name G_GNUC_UNUSED, + const gchar * name_owner G_GNUC_UNUSED, + gpointer gself) + { + g_main_loop_quit (static_cast(gself)->loop); + } + + GSList * menu_references; + + bool any_item_changed; + + static void on_items_changed (GMenuModel * model G_GNUC_UNUSED, + gint position G_GNUC_UNUSED, + gint removed G_GNUC_UNUSED, + gint added G_GNUC_UNUSED, + gpointer any_item_changed) + { + *((gboolean*)any_item_changed) = true; + } + + protected: + + void activate_subtree (GMenuModel * model) + { + // query the GDBusMenuModel for information to activate it + int n = g_menu_model_get_n_items (model); + if (!n) + { + // give the model a moment to populate its info + wait_msec (100); + n = g_menu_model_get_n_items (model); + } + + // keep a ref so that it stays activated + menu_references = g_slist_prepend (menu_references, g_object_ref(model)); + + g_signal_connect (model, "items-changed", G_CALLBACK(on_items_changed), &any_item_changed); + + // recurse + for (int i=0; i= TIME_LIMIT_SEC; + } + + void wait_for_has_action (const char * name) + { + while (!g_action_group_has_action (G_ACTION_GROUP(action_group), name) && !times_up()) + wait_msec (50); + + ASSERT_FALSE (times_up()); + ASSERT_TRUE (g_action_group_has_action (G_ACTION_GROUP(action_group), name)); + } - virtual void SetUp() + void wait_for_menu_resync (void) { - test_dbus = NULL; - session_bus = NULL; - main_loop = NULL; + any_item_changed = false; + while (!times_up() && !any_item_changed) + wait_msec (50); + sync_menu (); + } + + protected: + + void check_last_command_is (const char * expected) + { + char * str = g_settings_get_string (mock_settings, "last-command"); + ASSERT_STREQ (expected, str); + g_free (str); + } - static bool first_run = true; - if (first_run) + void test_simple_action (const char * action_name) + { + wait_for_has_action (action_name); + + g_action_group_activate_action (G_ACTION_GROUP (action_group), action_name, NULL); + wait_for_signal (mock_settings, "changed::last-command"); + check_last_command_is (action_name); + } + + protected: + + bool find_menu_item_for_action (const char * action_key, GMenuModel ** setme, int * item_index) + { + bool success = false; + + for (GSList * l=menu_references; !success && (l!=NULL); l=l->next) { - g_setenv ("INDICATOR_SERVICE_SHUTDOWN_TIMEOUT", "1000", TRUE); - g_unsetenv ("INDICATOR_ALLOW_NO_WATCHERS"); - g_unsetenv ("INDICATOR_SERVICE_REPLACE_MODE"); - g_setenv ("GSETTINGS_SCHEMA_DIR", SCHEMA_DIR, TRUE); - g_setenv ("GSETTINGS_BACKEND", "memory", TRUE); - first_run = false; + GMenuModel * mm = G_MENU_MODEL (l->data); + const int n = g_menu_model_get_n_items (mm); + + for (int i=0; !success && iref_count); + if (expected_a11y != NULL) + ASSERT_STREQ (expected_a11y, a11y); + + // the session menu is always visible... + ASSERT_TRUE (visible); + + g_variant_unref (variant); } - // undo SetUp - virtual void TearDown() + void check_label (const char * expected_label, GMenuModel * model, int pos) { - g_clear_object (&session_bus); - g_debug (G_STRLOC" tearing down the bus"); - g_test_dbus_down (test_dbus); - g_clear_object (&test_dbus); - g_clear_pointer (&main_loop, g_main_loop_unref); + char * label = NULL; + ASSERT_TRUE (g_menu_model_get_item_attribute (model, pos, G_MENU_ATTRIBUTE_LABEL, "s", &label)); + ASSERT_STREQ (expected_label, label); + g_free (label); } }; @@ -88,58 +347,438 @@ class ClientTest : public ::testing::Test **** ***/ +#if 0 +TEST_F (ServiceTest, HelloWorld) +{ + ASSERT_TRUE (true); +} +#endif + +TEST_F (ServiceTest, About) +{ + test_simple_action ("about"); +} + +TEST_F (ServiceTest, Help) +{ + test_simple_action ("help"); +} + +TEST_F (ServiceTest, Hibernate) +{ + test_simple_action ("hibernate"); +} + +TEST_F (ServiceTest, Settings) +{ + test_simple_action ("settings"); +} + +TEST_F (ServiceTest, Logout) +{ + test_simple_action ("logout"); +} + +TEST_F (ServiceTest, Shutdown) +{ + test_simple_action ("shutdown"); +} + +TEST_F (ServiceTest, Restart) +{ + test_simple_action ("restart"); +} + +TEST_F (ServiceTest, SwitchToScreensaver) +{ + test_simple_action ("switch-to-screensaver"); +} + +TEST_F (ServiceTest, SwitchToGuest) +{ + test_simple_action ("switch-to-guest"); +} + +TEST_F (ServiceTest, SwitchToGreeter) +{ + test_simple_action ("switch-to-greeter"); +} + +TEST_F (ServiceTest, Suspend) +{ + test_simple_action ("suspend"); +} + +#if 0 +namespace +{ + gboolean + find_menu_item_for_action (GMenuModel * top, const char * action_key, GMenuModel ** setme, int * item_index) + { + gboolean success = FALSE; + const int n = g_menu_model_get_n_items (top); + + for (int i=0; !success && imessage); - g_clear_error (&error); - } - - name = NULL; - g_variant_get (result, "(&s)", &name); - ASSERT_STREQ (g_get_real_name(), name); - g_clear_pointer (&result, g_variant_unref); - - // call IndicatorService's Shutdown() method for a clean exit - result = g_dbus_connection_call_sync (session_bus, - INDICATOR_SESSION_DBUS_NAME, - "/org/ayatana/indicator/service", - "org.ayatana.indicator.service", - "Shutdown", NULL, - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, NULL, NULL); - g_clear_pointer (&result, g_variant_unref); +TEST_F (ServiceTest, DefaultMenuItems) +{ + ASSERT_TRUE (find_menu_item_for_action ("indicator.about", NULL, NULL)); + ASSERT_TRUE (find_menu_item_for_action ("indicator.help", NULL, NULL)); + ASSERT_TRUE (find_menu_item_for_action ("indicator.settings", NULL, NULL)); + ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-greeter", NULL, NULL)); + ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-guest", NULL, NULL)); + ASSERT_TRUE (find_menu_item_for_action ("indicator.logout", NULL, NULL)); + ASSERT_TRUE (find_menu_item_for_action ("indicator.suspend", NULL, NULL)); + ASSERT_TRUE (find_menu_item_for_action ("indicator.hibernate", NULL, NULL)); + ASSERT_TRUE (find_menu_item_for_action ("indicator.restart", NULL, NULL)); + ASSERT_TRUE (find_menu_item_for_action ("indicator.shutdown", NULL, NULL)); +} + +TEST_F (ServiceTest, OnlineAccountError) +{ + bool err; + int pos = -1; + GMenuModel * model = 0; + const char * const error_key = "has-online-account-error"; + + // check the initial default header state + check_header ("", "system-devices-panel", "System"); + + // check that the menuitems' existence matches the error flag + err = g_settings_get_boolean (mock_settings, error_key); + ASSERT_FALSE (err); + ASSERT_EQ (err, find_menu_item_for_action ("indicator.online-accounts", &model, &pos)); + g_clear_object (&model); + + // now toggle the error flag + err = !err; + g_settings_set_boolean (mock_settings, error_key, err); + + // wait for the _header action and error menuitem to update + wait_for_menu_resync (); + + // check that the menuitems' existence matches the error flag + ASSERT_TRUE (g_settings_get_boolean (mock_settings, error_key)); + ASSERT_TRUE (find_menu_item_for_action ("indicator.online-accounts", &model, &pos)); + g_clear_object (&model); + + // check that the header's icon and a11y adjusted to the error state + check_header ("", "system-devices-panel-alert", "System (Attention Required)"); + + // cleanup + g_settings_reset (mock_settings, error_key); +} + +namespace +{ + gboolean set_live_session_to_true (gpointer unused G_GNUC_UNUSED) + { + const char * const live_session_key = "is-live-session"; + g_settings_set_boolean (mock_settings, live_session_key, true); + return G_SOURCE_REMOVE; + } +} + +TEST_F (ServiceTest, LiveSession) +{ + gboolean b; + const char * const live_session_key = "is-live-session"; + + // default BackendMock is not a live session + ASSERT_FALSE (g_settings_get_boolean (mock_settings, live_session_key)); + g_object_get (mock_users, INDICATOR_SESSION_USERS_PROP_IS_LIVE_SESSION, &b, NULL); + ASSERT_FALSE (b); + + // confirm that we can see live sessions + g_idle_add (set_live_session_to_true, NULL); + wait_for_signal (mock_users, "notify::" INDICATOR_SESSION_USERS_PROP_IS_LIVE_SESSION); + ASSERT_TRUE (g_settings_get_boolean (mock_settings, live_session_key)); + wait_msec (50); + g_object_get (mock_users, INDICATOR_SESSION_USERS_PROP_IS_LIVE_SESSION, &b, NULL); + ASSERT_TRUE (b); + + // cleanup + g_settings_reset (mock_settings, live_session_key); +} + + +TEST_F (ServiceTest, User) +{ + const char * const error_key = "has-online-account-error"; + const char * const show_name_key = "show-real-name-on-panel"; + + const struct { + guint64 login_frequency; + const gchar * user_name; + const gchar * real_name; + } account_info[] = { + { 134, "whartnell", "First Doctor" }, + { 119, "ptroughton", "Second Doctor" }, + { 128, "jpertwee", "Third Doctor" }, + { 172, "tbaker", "Fourth Doctor" }, + { 69, "pdavison", "Fifth Doctor" }, + { 31, "cbaker", "Sixth Doctor" }, + { 42, "smccoy", "Seventh Doctor" }, + { 1, "pmcgann", "Eigth Doctor" }, + { 13, "ceccleston", "Ninth Doctor" }, + { 47, "dtennant", "Tenth Doctor" }, + { 34, "msmith", "Eleventh Doctor" }, + { 1, "rhurndall", "First Doctor" } + }; + + // Find the switcher menu model. + // In BackendMock's default setup, it will only two menuitems: greeter & guest + int pos = 0; + GMenuModel * switch_menu = 0; + ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-greeter", &switch_menu, &pos)); + ASSERT_EQ (0, pos); + ASSERT_EQ (2, g_menu_model_get_n_items (switch_menu)); + g_clear_object (&switch_menu); + + // now add some users + IndicatorSessionUser * users[12]; + for (int i=0; i<12; ++i) + users[i] = 0; + for (int i=0; i<5; ++i) + { + IndicatorSessionUser * u = g_new0 (IndicatorSessionUser, 1); + u->is_current_user = false; + u->is_logged_in = false; + u->uid = 101 + i; + u->login_frequency = account_info[i].login_frequency; + u->user_name = g_strdup (account_info[i].user_name); + u->real_name = g_strdup (account_info[i].real_name); + indicator_session_users_mock_add_user (INDICATOR_SESSION_USERS_MOCK(mock_users), u->user_name, u); + users[i] = u; + } + + wait_for_menu_resync (); + + // now there should be 7 menuitems: greeter + guest + the five doctors + ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-greeter", &switch_menu, &pos)); + ASSERT_EQ (0, pos); + ASSERT_EQ (7, g_menu_model_get_n_items (switch_menu)); + // confirm that the doctor names are sorted + check_label ("Fifth Doctor", switch_menu, 2); + check_label ("First Doctor", switch_menu, 3); + check_label ("Fourth Doctor", switch_menu, 4); + check_label ("Second Doctor", switch_menu, 5); + check_label ("Third Doctor", switch_menu, 6); + g_clear_object (&switch_menu); + + // now remove a couple of 'em + indicator_session_users_mock_remove_user (INDICATOR_SESSION_USERS_MOCK(mock_users), account_info[3].user_name); + indicator_session_users_mock_remove_user (INDICATOR_SESSION_USERS_MOCK(mock_users), account_info[4].user_name); + + wait_for_menu_resync (); + + // now there should be 5 menuitems: greeter + guest + the three doctors + ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-greeter", &switch_menu, &pos)); + ASSERT_EQ (0, pos); + ASSERT_EQ (5, g_menu_model_get_n_items (switch_menu)); + // confirm that the doctor names are sorted + check_label ("First Doctor", switch_menu, 2); + check_label ("Second Doctor", switch_menu, 3); + check_label ("Third Doctor", switch_menu, 4); + g_clear_object (&switch_menu); + + // now let's have the third one be the current user + users[2]->is_current_user = true; + users[2]->is_logged_in = true; + indicator_session_users_changed (mock_users, users[2]->user_name); + + wait_for_menu_resync (); + + // now there should be 5 menuitems: greeter + guest + the three doctors + ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-greeter", &switch_menu, &pos)); + ASSERT_EQ (0, pos); + ASSERT_EQ (5, g_menu_model_get_n_items (switch_menu)); + g_clear_object (&switch_menu); + + // oh hey, while we've got an active user let's check the header + ASSERT_FALSE (g_settings_get_boolean (indicator_settings, show_name_key)); + ASSERT_FALSE (g_settings_get_boolean (mock_settings, error_key)); + check_header ("", "system-devices-panel", "System"); + g_settings_set_boolean (indicator_settings, show_name_key, true); + wait_for_signal (action_group, "action-state-changed"); + check_header ("Third Doctor", "system-devices-panel", "System, Third Doctor"); + g_settings_set_boolean (mock_settings, error_key, true); + wait_for_signal (action_group, "action-state-changed"); + check_header ("Third Doctor", "system-devices-panel-alert", "System, Third Doctor (Attention Required)"); + g_settings_reset (mock_settings, error_key); + g_settings_reset (indicator_settings, show_name_key); + wait_for_menu_resync (); + + // try setting the max user count to 2... + // since troughton has the fewest logins, he should get culled + g_object_set (service, "max-users", 2, NULL); + guint max_users; + g_object_get (service, "max-users", &max_users, NULL); + ASSERT_EQ (2, max_users); + wait_for_menu_resync (); + ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-greeter", &switch_menu, &pos)); + ASSERT_EQ (0, pos); + ASSERT_EQ (4, g_menu_model_get_n_items (switch_menu)); + check_label ("First Doctor", switch_menu, 2); + check_label ("Third Doctor", switch_menu, 3); + g_clear_object (&switch_menu); + + // add some more, test sorting and culling. + // add in all the doctors, but only show 7, and make msmith the current session + g_object_set (service, "max-users", 7, NULL); + g_object_get (service, "max-users", &max_users, NULL); + ASSERT_EQ (7, max_users); + for (int i=3; i<12; ++i) + { + IndicatorSessionUser * u = g_new0 (IndicatorSessionUser, 1); + u->is_current_user = false; + u->is_logged_in = false; + u->uid = 101 + i; + u->login_frequency = account_info[i].login_frequency; + u->user_name = g_strdup (account_info[i].user_name); + u->real_name = g_strdup (account_info[i].real_name); + indicator_session_users_mock_add_user (INDICATOR_SESSION_USERS_MOCK(mock_users), u->user_name, u); + users[i] = u; + } + users[2]->is_current_user = false; + indicator_session_users_changed (mock_users, users[2]->user_name); + users[10]->is_current_user = true; + users[10]->is_logged_in = true; + indicator_session_users_changed (mock_users, users[10]->user_name); + wait_for_menu_resync (); + ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-greeter", &switch_menu, &pos)); + ASSERT_EQ (0, pos); + ASSERT_EQ (9, g_menu_model_get_n_items (switch_menu)); + check_label ("Eleventh Doctor", switch_menu, 2); + check_label ("Fifth Doctor", switch_menu, 3); + check_label ("First Doctor", switch_menu, 4); + check_label ("Fourth Doctor", switch_menu, 5); + check_label ("Second Doctor", switch_menu, 6); + check_label ("Tenth Doctor", switch_menu, 7); + check_label ("Third Doctor", switch_menu, 8); + g_clear_object (&switch_menu); + + // now switch to one of the doctors + g_action_group_activate_action (G_ACTION_GROUP(action_group), + "switch-to-user", + g_variant_new_string("tbaker")); + wait_for_signal (mock_settings, "changed::last-command"); + check_last_command_is ("switch-to-user::tbaker"); } diff --git a/trim-lcov.py b/trim-lcov.py new file mode 100755 index 0000000..78613d3 --- /dev/null +++ b/trim-lcov.py @@ -0,0 +1,53 @@ +#!/usr/bin/python + +# This script removes branch and/or line coverage data for lines that +# contain a particular substring. +# +# In the interest of "fairness" it removes all branch or coverage data +# when a match is found -- not just negative data. It is therefore +# likely that running this script will actually reduce the total number +# of lines and branches that are marked as covered (in absolute terms). +# +# This script intentionally avoids checking for errors. Any exceptions +# will trigger make to fail. +# +# Author: Ryan Lortie + +import sys + +line_suppress = ['g_assert_not_reached'] +branch_suppress = ['g_assert', 'g_return_if_fail', 'g_clear_object', 'g_clear_pointer', 'g_return_val_if_fail', 'G_DEFINE_TYPE'] + +def check_suppress(suppressions, source, data): + line, _, rest = data.partition(',') + line = int(line) - 1 + + assert line < len(source) + + for suppression in suppressions: + if suppression in source[line]: + return True + + return False + +source = [] +for line in sys.stdin: + line = line[:-1] + + keyword, _, rest = line.partition(':') + + # Source file + if keyword == 'SF': + source = file(rest).readlines() + + # Branch coverage data + elif keyword == 'BRDA': + if check_suppress(branch_suppress, source, rest): + continue + + # Line coverage data + elif keyword == 'DA': + if check_suppress(line_suppress, source, rest): + continue + + print line -- cgit v1.2.3