[pitivi] Use Gtk.Application for power management
- From: Alexandru Băluț <alexbalut src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pitivi] Use Gtk.Application for power management
- Date: Wed, 4 Jan 2017 06:48:48 +0000 (UTC)
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]