[pitivi] Use Gtk.Application for power management



commit 9d8b194a7000450dcee615bd70f641e296930d44
Author: Alexandru Băluț <alexandru balut gmail com>
Date:   Mon Jan 2 01:11:03 2017 +0100

    Use Gtk.Application for power management
    
    Fixes https://phabricator.freedesktop.org/T3114
    
    Reviewed-by: Thibault Saunier <tsaunier gnome org>
    Differential Revision: https://phabricator.freedesktop.org/D1580

 pitivi/application.py     |   34 ++++++++
 pitivi/render.py          |   15 ++--
 pitivi/utils/system.py    |  185 +--------------------------------------------
 pitivi/viewer/viewer.py   |   27 +++----
 tests/test_application.py |   41 ++++++++++
 tests/test_system.py      |  119 +++--------------------------
 6 files changed, 106 insertions(+), 315 deletions(-)
---
diff --git a/pitivi/application.py b/pitivi/application.py
index 82831ef..f3309c8 100644
--- a/pitivi/application.py
+++ b/pitivi/application.py
@@ -84,6 +84,7 @@ class Pitivi(Gtk.Application, Loggable):
 
         self.gui = None
         self.__welcome_wizard = None
+        self.__inhibit_cookies = {}
 
         self._version_information = {}
 
@@ -387,3 +388,36 @@ class Pitivi(Gtk.Application, Loggable):
         # In the tests we do not want to create any gui
         if self.gui is not None:
             self.gui.showProjectStatus()
+
+    def simple_inhibit(self, reason, flags):
+        """Informs the session manager about actions to be inhibited.
+
+        Keeps track of the reasons received. A specific reason should always
+        be accompanied by the same flags. Calling the method a second time
+        with the same reason has no effect unless `simple_uninhibit` has been
+        called in the meanwhile.
+
+        Args:
+            reason (str): The reason for which to perform the inhibition.
+            flags (Gtk.ApplicationInhibitFlags): What should be inhibited.
+        """
+        if reason in self.__inhibit_cookies:
+            self.debug("Inhibit reason already active: %s", reason)
+            return
+        self.debug("Inhibiting %s for %s", flags, reason)
+        cookie = self.inhibit(self.gui, flags, reason)
+        self.__inhibit_cookies[reason] = cookie
+
+    def simple_uninhibit(self, reason):
+        """Informs the session manager that an inhibition is not needed anymore.
+
+        Args:
+            reason (str): The reason which is not valid anymore.
+        """
+        try:
+            cookie = self.__inhibit_cookies.pop(reason)
+        except KeyError:
+            self.debug("Inhibit reason not active: %s", reason)
+            return
+        self.debug("Uninhibiting %s", reason)
+        self.uninhibit(cookie)
diff --git a/pitivi/render.py b/pitivi/render.py
index 38d8d90..24ccec5 100644
--- a/pitivi/render.py
+++ b/pitivi/render.py
@@ -390,7 +390,6 @@ class RenderDialog(Loggable):
 
         self.app = app
         self.project = project
-        self.system = app.system
         self._pipeline = self.project.pipeline
 
         self.outfile = None
@@ -1060,16 +1059,16 @@ class RenderDialog(Loggable):
             self._showRenderErrorDialog(error, details)
 
         elif message.type == Gst.MessageType.STATE_CHANGED and self.progress:
-            prev, state, pending = message.parse_state_changed()
             if message.src == self._pipeline:
-                state_really_changed = pending == Gst.State.VOID_PENDING
-                if state_really_changed:
+                prev, state, pending = message.parse_state_changed()
+                if pending == Gst.State.VOID_PENDING:
+                    # State will not change further.
                     if state == Gst.State.PLAYING:
-                        self.debug(
-                            "Rendering started/resumed, inhibiting sleep")
-                        self.system.inhibitSleep(RenderDialog.INHIBIT_REASON)
+                        self.debug("Inhibiting sleep when rendering")
+                        self.app.simple_inhibit(RenderDialog.INHIBIT_REASON,
+                                                Gtk.ApplicationInhibitFlags.SUSPEND)
                     else:
-                        self.system.uninhibitSleep(RenderDialog.INHIBIT_REASON)
+                        self.app.simple_uninhibit(RenderDialog.INHIBIT_REASON)
 
     def _updatePositionCb(self, unused_pipeline, position):
         """Updates the progress bar and triggers the update of the file size.
diff --git a/pitivi/utils/system.py b/pitivi/utils/system.py
index 2ef7adf..5fa9bc4 100644
--- a/pitivi/utils/system.py
+++ b/pitivi/utils/system.py
@@ -30,15 +30,10 @@ from pitivi.utils.loggable import Loggable
 class System(GObject.Object, Loggable):
     """A base class for systems in which Pitivi runs."""
 
-    __gsignals__ = {
-        'update-power-inhibition': (GObject.SIGNAL_RUN_LAST, None, ()),
-    }
-
     def __init__(self):
         GObject.Object.__init__(self)
         Loggable.__init__(self)
         self.log("new object %s", self)
-        self._reset()
 
         self._x11 = False
         try:
@@ -50,118 +45,6 @@ class System(GObject.Object, Loggable):
     def has_x11(self):
         return self._x11
 
-    def _reset(self):
-        self._screensaver_keys = []
-        self._sleep_keys = []
-
-    # generic functions
-    def _inhibit(self, list_, key):
-        assert key is not None
-        assert isinstance(key, str)
-        if key not in list_:
-            list_.append(key)
-            self.log("emitting 'update-power-inhibition'")
-            self.emit('update-power-inhibition')
-
-    def _uninhibit(self, list_, key):
-        if key is None:
-            if self._isInhibited(list_):
-                list_ = []
-                self.log("emitting 'update-power-inhibition'")
-                self.emit('update-power-inhibition')
-        else:
-            assert isinstance(key, str)
-            if key in list_:
-                list_.remove(key)
-                self.log("emitting 'update-power-inhibition'")
-                self.emit('update-power-inhibition')
-
-    def _isInhibited(self, list_, key=None):
-        if key is None:
-            if list_:
-                return True
-        elif key in list_:
-            return True
-
-        return False
-
-    # screensaver
-    def inhibitScreensaver(self, key):
-        """Increases the screensaver inhibitor count.
-
-        It is safe to call this method with a key that is already inhibited.
-
-        Args:
-            key (str): A unique translated string, giving the reason for
-                inhibiting sleep
-        """
-        self.info("Inhibiting the screensaver")
-        self._inhibit(self._screensaver_keys, key)
-
-    def uninhibitScreensaver(self, key):
-        """Decreases screensaver inhibitor count.
-
-        It is safe to call this method with a key that is not inhibited.
-
-        Args:
-            key (str): A unique translated string, giving the reason for
-                inhibiting sleep
-        """
-        self.info("Uninhibiting the screensaver")
-        self._uninhibit(self._screensaver_keys, key)
-
-    def screensaverIsInhibited(self, key=None):
-        """Checks whether inhibited."""
-        return self._isInhibited(self._screensaver_keys, key)
-
-    def getScreensaverInhibitors(self):
-        """Returns a comma separated string of screensaver inhibitor keys."""
-        return ", ".join(self._screensaver_keys)
-
-    def screensaverIsBlockable(self):
-        return False
-
-    # Sleep
-    def inhibitSleep(self, key):
-        """Increase the sleep inhibitor count.
-
-        It is safe to call this method with a key that is already inhibited.
-
-        Args:
-            key (str): A unique translated string, giving the reason for
-                inhibiting sleep
-        """
-        self.info("Inhibiting sleep")
-        self._inhibit(self._sleep_keys, key)
-
-    def uninhibitSleep(self, key):
-        """Decreases sleep inhibitor count.
-
-        It is safe to call this method with a key that is not inhibited.
-
-        Args:
-            key (str): A unique translated string, giving the reason for
-                inhibiting sleep
-        """
-        self.info("Uninhibiting sleep")
-        self._uninhibit(self._sleep_keys, key)
-
-    def sleepIsInhibited(self, key=None):
-        """Returns whether inhibited."""
-        return self._isInhibited(self._sleep_keys, key)
-
-    def getSleepInhibitors(self):
-        """Returns a comma separated strinsg of sleep inhibitor keys."""
-        return ", ".join(self._sleep_keys)
-
-    def sleepIsBlockable(self):
-        return False
-
-    # Other
-    def uninhibitAll(self):
-        self._reset()
-        self.emit('update-power-inhibition')
-
     def desktopMessage(self, title, message, unused_icon=None):
         """Sends a message to the desktop to be displayed to the user.
 
@@ -214,78 +97,12 @@ class FreedesktopOrgSystem(System):
         return None
 
 
-# org.gnome.SessionManager flags
-INHIBIT_LOGOUT = 1
-INHIBIT_USER_SWITCHING = 2
-INHIBIT_SUSPEND = 4
-INHIBIT_SESSION_IDLE = 8
-
-COOKIE_NONE = 0
-COOKIE_SCREENSAVER = 1
-COOKIE_SLEEP = 2
-
-
 class GnomeSystem(FreedesktopOrgSystem):
+    """GNOME."""
 
     def __init__(self):
         FreedesktopOrgSystem.__init__(self)
 
-        import dbus
-        self.bus = dbus.Bus(dbus.Bus.TYPE_SESSION)
-
-        # connect to gnome sessionmanager
-        self.sessionmanager = self.bus.get_object('org.gnome.SessionManager',
-                                                  '/org/gnome/SessionManager')
-        self.session_iface = dbus.Interface(self.sessionmanager,
-                                            'org.gnome.SessionManager')
-        self.cookie = None
-        self.cookie_type = COOKIE_NONE
-
-        self.connect('update-power-inhibition', self._updatePowerInhibitionCb)
-
-    def _updatePowerInhibitionCb(self, unused_system):
-        # there are two states we want the program to be in, with regards to
-        # power saving, the screen saver is inhibited when the viewer is watched.
-        # or we inhibit sleep/powersaving when we are processing data
-        # we do things the way we do here because the viewer shows the the output
-        # of the render pipeline
-        self.log("updating power inhibitors")
-        toplevel_id = 0
-
-        # inhibit power saving if we are rendering, maybe downloading a video
-        if self.sleepIsInhibited():
-            if self.cookie_type != COOKIE_SLEEP:
-                new_cookie = self.session_iface.Inhibit(APPNAME, toplevel_id,
-                                                        self.getSleepInhibitors(), INHIBIT_SUSPEND | 
INHIBIT_LOGOUT)
-                if self.cookie is not None:
-                    self.session_iface.Uninhibit(self.cookie)
-                self.cookie = new_cookie
-                self.cookie_type = COOKIE_SLEEP
-                self.debug("sleep inhibited")
-            else:
-                self.debug("sleep already inhibited")
-        # inhibit screensaver if we are just watching the viewer
-        elif self.screensaverIsInhibited():
-            if self.cookie_type != COOKIE_SCREENSAVER:
-                new_cookie = self.session_iface.Inhibit(APPNAME, toplevel_id,
-                                                        self.getScreensaverInhibitors(), 
INHIBIT_SESSION_IDLE)
-                if self.cookie is not None:
-                    self.session_iface.Uninhibit(self.cookie)
-                self.cookie = new_cookie
-                self.cookie_type = COOKIE_SCREENSAVER
-                self.debug("screensaver inhibited")
-            else:
-                self.debug("screensaver already inhibited")
-        # unblock everything otherwise
-        else:
-            if self.cookie != COOKIE_NONE:
-                self.session_iface.Uninhibit(self.cookie)
-                self.cookie = None
-                self.cookie_type = COOKIE_NONE
-                self.debug("uninhibited")
-            else:
-                self.debug("already uninhibited")
-
 
 class DarwinSystem(System):
     """Apple OS X."""
diff --git a/pitivi/viewer/viewer.py b/pitivi/viewer/viewer.py
index 798ff66..40b814d 100644
--- a/pitivi/viewer/viewer.py
+++ b/pitivi/viewer/viewer.py
@@ -80,7 +80,6 @@ class ViewerContainer(Gtk.Box, Loggable):
         self.set_border_width(SPACING)
         self.app = app
         self.settings = app.settings
-        self.system = app.system
 
         Loggable.__init__(self)
         self.log("New ViewerContainer")
@@ -451,23 +450,23 @@ class ViewerContainer(Gtk.Box, Loggable):
 
     def _pipelineStateChangedCb(self, unused_pipeline, state, old_state):
         """Updates the widgets when the playback starts or stops."""
-        if int(state) == int(Gst.State.PLAYING):
+        if state == Gst.State.PLAYING:
             st = Gst.Structure.new_empty("play")
             self.app.write_action(st)
             self.playpause_button.setPause()
-            self.system.inhibitScreensaver(self.INHIBIT_REASON)
-        elif int(state) == int(Gst.State.PAUSED):
-            if old_state != int(Gst.State.PAUSED):
-                st = Gst.Structure.new_empty("pause")
-                if old_state == int(Gst.State.PLAYING):
-                    st.set_value("playback_time", float(self.pipeline.getPosition()) /
-                                 Gst.SECOND)
-                self.app.write_action(st)
-
-            self.playpause_button.setPlay()
-            self.system.uninhibitScreensaver(self.INHIBIT_REASON)
+            self.app.simple_inhibit(ViewerContainer.INHIBIT_REASON,
+                                    Gtk.ApplicationInhibitFlags.IDLE)
         else:
-            self.system.uninhibitScreensaver(self.INHIBIT_REASON)
+            if state == Gst.State.PAUSED:
+                if old_state != Gst.State.PAUSED:
+                    st = Gst.Structure.new_empty("pause")
+                    if old_state == Gst.State.PLAYING:
+                        st.set_value("playback_time",
+                                     self.pipeline.getPosition() / Gst.SECOND)
+                    self.app.write_action(st)
+
+                self.playpause_button.setPlay()
+            self.app.simple_uninhibit(ViewerContainer.INHIBIT_REASON)
 
 
 class ViewerWidget(Gtk.AspectFrame, Loggable):
diff --git a/tests/test_application.py b/tests/test_application.py
index 4258996..b2e1e3a 100644
--- a/tests/test_application.py
+++ b/tests/test_application.py
@@ -67,3 +67,44 @@ class TestPitivi(common.TestCase):
         app = self.call_version_info_received("0.100000000=current")
         self.assertFalse(app.isLatest())
         self.assertEqual("0.100000000", app.getLatest())
+
+    def test_inhibition(self):
+        app = application.Pitivi()
+
+        # Check simple_inhibit.
+        with mock.patch.object(app, "inhibit") as inhibit_mock:
+            inhibit_mock.return_value = 1
+            app.simple_inhibit("reason1", "flags1")
+            inhibit_mock.return_value = 2
+            app.simple_inhibit("reason2", "flags2")
+            self.assertEqual(inhibit_mock.call_count, 2)
+
+            inhibit_mock.reset_mock()
+            app.simple_inhibit("reason1", "flags1.1")
+            self.assertFalse(inhibit_mock.called)
+
+        # Check simple_uninhibit.
+        with mock.patch.object(app, "uninhibit") as uninhibit_mock:
+            uninhibit_mock.reset_mock()
+            app.simple_uninhibit("reason1")
+            uninhibit_mock.assert_called_once_with(1)
+
+            uninhibit_mock.reset_mock()
+            app.simple_uninhibit("reason1")
+            self.assertFalse(uninhibit_mock.called)
+
+            uninhibit_mock.reset_mock()
+            app.simple_uninhibit("reason2")
+            uninhibit_mock.assert_called_once_with(2)
+
+            uninhibit_mock.reset_mock()
+            app.simple_uninhibit("reason2")
+            self.assertFalse(uninhibit_mock.called)
+
+            app.simple_uninhibit("reason3")
+            self.assertFalse(uninhibit_mock.called)
+
+        # Check again simple_inhibit.
+        with mock.patch.object(app, "inhibit") as inhibit_mock:
+            app.simple_inhibit("reason1", "flags1")
+            self.assertTrue(inhibit_mock.called)
diff --git a/tests/test_system.py b/tests/test_system.py
index a8e95d8..95e7b87 100644
--- a/tests/test_system.py
+++ b/tests/test_system.py
@@ -16,120 +16,21 @@
 # License along with this program; if not, write to the
 # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 # Boston, MA 02110-1301, USA.
+"""Tests for the utils.system module."""
+# pylint: disable=missing-docstring
 from unittest import TestCase
 
-from pitivi.utils.system import get_system
-from pitivi.utils.system import GnomeSystem
-from pitivi.utils.system import INHIBIT_LOGOUT
-from pitivi.utils.system import INHIBIT_SESSION_IDLE
-from pitivi.utils.system import INHIBIT_SUSPEND
-from pitivi.utils.system import INHIBIT_USER_SWITCHING
 from pitivi.utils.system import System
 
 
 class TestSystem(TestCase):
 
-    def setUp(self):
-        self.system = System()
-
     def testGetUniqueFilename(self):
-        self.assertNotEqual(self.system.getUniqueFilename("a/b"),
-                            self.system.getUniqueFilename("a%47b"))
-        self.assertNotEqual(self.system.getUniqueFilename("a%b"),
-                            self.system.getUniqueFilename("a%37b"))
-        self.assertNotEqual(self.system.getUniqueFilename("a%/b"),
-                            self.system.getUniqueFilename("a%37%3747b"))
-        self.assertEqual("a b", self.system.getUniqueFilename("a b"))
-
-    def testScreensaverInhibit(self):
-        # check that we start of uninhibited
-        self.assertTrue(not self.system.screensaverIsInhibited())
-
-        # inhibit and check that we are
-        self.system.inhibitScreensaver("a")
-        self.assertTrue(self.system.screensaverIsInhibited())
-        # uninhibit and check that we are
-        self.system.uninhibitScreensaver("a")
-        self.assertTrue(not self.system.screensaverIsInhibited())
-
-        # check that adding/removing is consistent with multiple keys
-        for c in range(0, 5):
-            self.system.inhibitScreensaver(str(c))
-            self.assertTrue(self.system.screensaverIsInhibited(str(c)))
-
-        for c in range(0, 5):
-            self.system.uninhibitScreensaver(str(c))
-            self.assertTrue(not self.system.screensaverIsInhibited(str(c)))
-
-        self.assertTrue(not self.system.screensaverIsInhibited())
-
-    def testSleepInhibit(self):
-        # check that we start of uninhibited
-        self.assertTrue(not self.system.sleepIsInhibited())
-
-        # inhibit and check that we are
-        self.system.inhibitSleep("a")
-        self.assertTrue(self.system.sleepIsInhibited())
-        # uninhibit and check that we are
-        self.system.uninhibitSleep("a")
-        self.assertTrue(not self.system.sleepIsInhibited())
-
-        # check that adding/removing is consistent with multiple keys
-        for c in range(0, 5):
-            self.system.inhibitSleep(str(c))
-            self.assertTrue(self.system.sleepIsInhibited(str(c)))
-
-        for c in range(0, 5):
-            self.system.uninhibitSleep(str(c))
-            self.assertTrue(not self.system.sleepIsInhibited(str(c)))
-
-        self.assertTrue(not self.system.sleepIsInhibited())
-
-
-class TestGnomeSystem(TestCase):
-
-    def setUp(self):
-        self.system = get_system()
-
-    def testPowerInhibition(self):
-        if not isinstance(self.system, GnomeSystem):
-            # We can only test this on a Gnome system.
-            return
-
-        if self.system.session_iface.IsInhibited(
-                INHIBIT_LOGOUT | INHIBIT_USER_SWITCHING | INHIBIT_SUSPEND |
-                INHIBIT_SESSION_IDLE):
-            # Other programs are inhibiting, cannot test.
-            return
-
-        self.system.inhibitScreensaver('1')
-        self.assertTrue(self.system.session_iface.IsInhibited(
-            INHIBIT_SESSION_IDLE))
-
-        self.system.inhibitSleep('2')
-        # Screensaver should be able to turn off, but
-        self.assertFalse(self.system.session_iface.IsInhibited(
-            INHIBIT_SESSION_IDLE))
-        # suspend (sleep, suspend, shutdown) and logout should be inhibited.
-        # IsInhibited will return True if just one is inhibited, so we
-        # check both separately.
-        self.assertTrue(self.system.session_iface.IsInhibited(
-            INHIBIT_SUSPEND))
-        self.assertTrue(self.system.session_iface.IsInhibited(
-            INHIBIT_LOGOUT))
-
-        self.system.uninhibitSleep('2')
-        # Screensaver should now be blocked.
-        self.assertTrue(self.system.session_iface.IsInhibited(
-            INHIBIT_SESSION_IDLE))
-        # Suspend and logout should be unblocked.
-        self.assertFalse(self.system.session_iface.IsInhibited(
-            INHIBIT_SUSPEND))
-        self.assertFalse(self.system.session_iface.IsInhibited(
-            INHIBIT_LOGOUT))
-
-        self.system.uninhibitScreensaver('1')
-        # Now everything should be unblocked.
-        self.assertFalse(self.system.session_iface.IsInhibited(
-            INHIBIT_LOGOUT | INHIBIT_USER_SWITCHING | INHIBIT_SUSPEND |
-            INHIBIT_SESSION_IDLE))
+        system = System()
+        self.assertNotEqual(system.getUniqueFilename("a/b"),
+                            system.getUniqueFilename("a%47b"))
+        self.assertNotEqual(system.getUniqueFilename("a%b"),
+                            system.getUniqueFilename("a%37b"))
+        self.assertNotEqual(system.getUniqueFilename("a%/b"),
+                            system.getUniqueFilename("a%37%3747b"))
+        self.assertEqual("a b", system.getUniqueFilename("a b"))


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