Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial commit: implemented previewer with polkit auth

  • Loading branch information...
commit 3766bae5f4840a0d6741ee03e12ecc418a563b45 0 parents
@maksbotan authored
2  .gitignore
@@ -0,0 +1,2 @@
+*.swp
+*.pyc
161 plymouth-theme-preview
@@ -0,0 +1,161 @@
+#!/usr/bin/env
+
+# vim:ft=python
+
+import gtk, dbus
+
+def dbus_error_catcher(f):
+ def __wrapper(self, *a, **k):
+ try:
+ self._authorized = True
+ return f(self, *a, **k)
+ except dbus.DBusException as e:
+ if 'NotAuthorizedException' in e.get_dbus_name():
+ self.error("You are must authorize as root to configure plymouth", critical=True)
+ else:
+ self.error("Error ocquired while communicating helper", e.get_dbus_message())
+ self._authorized = False
+
+ return __wrapper
+
+
+class MainWindow():
+
+ _authorized = False
+ _theme = ''
+
+ def __init__(self):
+ self.window = gtk.Window()
+
+ vbox = gtk.VBox()
+ self.window.add(vbox)
+
+ self.current_theme_label = gtk.Label()
+ self.current_theme_label.set_markup("Current plymouth theme: ")
+ vbox.pack_start(self.current_theme_label, expand=False)
+
+ self.preview_controls = gtk.HBox()
+ self.preview_controls.pack_start(gtk.Label("Preview duration:"), False)
+ adj = gtk.Adjustment(value=5, lower=1, upper=1000, step_incr=1)
+ self.preview_duration = gtk.SpinButton(adj)
+ self.preview_duration.set_numeric(True)
+ self.preview_controls.pack_start(self.preview_duration)
+ vbox.pack_start(self.preview_controls, False)
+
+ self.g_themes_list = gtk.ListStore(int, str)
+ self.tree_view = gtk.TreeView(self.g_themes_list)
+ column = gtk.TreeViewColumn('Theme')
+ cell_renderer = gtk.CellRendererText()
+ column.pack_start(cell_renderer)
+ column.set_attributes(cell_renderer, text=1)
+ self.tree_view.append_column(column)
+ vbox.pack_start(self.tree_view)
+
+ self.controls = gtk.HBox()
+ self.preview_button = gtk.Button("Preview")
+ self.select_button = gtk.Button("Set as default")
+ self.controls.pack_start(self.preview_button, True, False)
+ self.controls.pack_start(self.select_button, True, False)
+ self.preview_button.connect('clicked', self.preview)
+ self.select_button.connect('clicked', self.select)
+ vbox.pack_start(self.controls, False)
+
+ self.window.connect('destroy', self.quit)
+
+
+ def start(self):
+ self.window.show_all()
+ self.init_dbus_object()
+
+ self.list_available_themes()
+ self.query_current_theme()
+
+
+ def quit(self, *args):
+ try:
+ if self.d_helper is not None and self._authorized:
+ self.d_helper.StopPlymouthd()
+ except dbus.DBusException as e:
+ pass
+ gtk.main_quit()
+
+
+ def init_dbus_object(self):
+ try:
+ bus = dbus.SystemBus()
+ helper_object = bus.get_object("ru.gentoo.plymouth_theme_preview_helper", "/PlymouthThemePreviewHelper")
+ self.d_helper = dbus.Interface(helper_object, "ru.gentoo.plymouth_theme_preview_helper")
+ except dbus.DBusException as e:
+ self.d_helper = None
+ self.error("D-Bus connection to helper cannot be established", e.get_dbus_message(), critical=True)
+
+
+ @dbus_error_catcher
+ def list_available_themes(self):
+ self.themes = self.d_helper.ListThemes()
+
+ self.g_themes_list.clear()
+ for i, theme in enumerate(self.themes):
+ self.g_themes_list.append([i, theme])
+
+ @dbus_error_catcher
+ def query_current_theme(self):
+ self._theme = self.d_helper.GetCurrentTheme()
+
+ index = self.themes.index(self._theme)
+ self.current_theme_label.set_markup("Current plymouth theme: <b>{0}</b>".format(self._theme))
+ self.tree_view.set_cursor(index)
+
+
+ @dbus_error_catcher
+ def preview(self, *args):
+ path, _ = self.tree_view.get_cursor()
+ if path is None:
+ return
+ theme = self.g_themes_list[path][1]
+ self.d_helper.StartPlymouthd()
+ if theme != self._theme:
+ self.d_helper.SelectTheme(theme)
+ self.d_helper.RunSimulation(self.preview_duration.get_value_as_int())
+ if theme != self._theme:
+ self.d_helper.SelectTheme(self._theme)
+ self.d_helper.StopPlymouthd()
+
+
+ @dbus_error_catcher
+ def select(self, *args):
+ path, _ = self.tree_view.get_cursor()
+ if path is None:
+ return
+ theme = self.g_themes_list[path][1]
+ if theme == self._theme:
+ return
+
+ self.d_helper.SelectTheme(theme)
+ self.query_current_theme()
+
+ def error(self, message, reason='', critical=False):
+ dialog = gtk.MessageDialog(
+ type=gtk.MESSAGE_ERROR,
+ buttons=gtk.BUTTONS_CLOSE,
+ message_format=message
+ )
+ if reason:
+ dialog.format_secondary_text(reason)
+ dialog.run()
+ dialog.destroy()
+
+ if critical:
+ self.tree_view.set_sensitive(False)
+ self.controls.set_sensitive(False)
+ self.preview_controls.set_sensitive(False)
+ self.current_theme_label.set_markup("<span foreground='red' weight='bold'>{0}</span>".format(message))
+
+
+if __name__ == '__main__':
+ main_window = MainWindow()
+ main_window.start()
+ try:
+ gtk.main()
+ except KeyboardInterrupt:
+ main_window.quit()
145 plymouth-theme-preview-helper
@@ -0,0 +1,145 @@
+#!/usr/bin/env python
+
+# vim:ft=python
+
+SERVICE_NAME="ru.gentoo.plymouth_theme_preview_helper"
+ACTION_NAME="ru.gentoo.plymouth_theme_preview.use_plymouthd"
+
+import gobject
+import dbus
+import dbus.service
+import dbus.mainloop.glib
+import slip.dbus.service
+import logging, logging.handlers
+import subprocess, time
+
+from functools import wraps
+
+class PlymouthException(dbus.DBusException):
+ _dbus_error_name = 'ru.gentoo.plymouth_theme_preview_helper.PlymouthException'
+
+def check_plymouthd_running(f):
+ @wraps(f)
+ def __wrapper(self, *args, **kwargs):
+ if not self._plymouthd_running:
+ self.StartPlymouthd()
+ return f(self, *args, **kwargs)
+
+ return __wrapper
+
+class PlymouthHelper(slip.dbus.service.Object):
+
+ _plymouthd_running = False
+
+ @slip.dbus.polkit.require_auth(ACTION_NAME)
+ @dbus.service.method(SERVICE_NAME, in_signature='', out_signature='')
+ def StartPlymouthd(self):
+ logger.debug("Starting plymouthd...")
+
+ if self._plymouthd_running:
+ return
+
+ subprocess.call(['/sbin/plymouthd'])
+ self._plymouthd_running = True
+
+
+ @slip.dbus.polkit.require_auth(ACTION_NAME)
+ @dbus.service.method(SERVICE_NAME, in_signature='', out_signature='')
+ def StopPlymouthd(self):
+ logger.debug("Stopping plymouthd...")
+
+ if not self._plymouthd_running:
+ return
+
+ result = subprocess.call(['plymouth', 'quit'])
+ if result != 0:
+ raise PlymouthException("'plymouth quit' exited with {}".format(result))
+
+ self._plymouthd_running = False
+
+
+ def ShowSplash(self):
+ result = subprocess.call(['plymouth', '--show-splash'])
+ if result != 0:
+ raise PlymouthException("'plymouth --show-splash' exited with {}".format(result))
+
+
+ def HideSplash(self):
+ result = subprocess.call(['plymouth', '--hide-splash'])
+ if result != 0:
+ raise PlymouthException("'plymouth --hide-splash' exited with {}".format(result))
+
+
+ @slip.dbus.polkit.require_auth(ACTION_NAME)
+ @dbus.service.method(SERVICE_NAME, in_signature='', out_signature='s')
+ def GetCurrentTheme(self):
+ logger.debug("Returning current plymouth theme...")
+
+ try:
+ theme = subprocess.check_output(['/usr/sbin/plymouth-set-default-theme'])
+ except subprocess.CalledProcessError as e:
+ raise PlymouthException("'plymouth-set-default-theme' exited with {}".format(e.returncode))
+ return theme.strip()
+
+
+ @slip.dbus.polkit.require_auth(ACTION_NAME)
+ @dbus.service.method(SERVICE_NAME, in_signature='', out_signature='as')
+ def ListThemes(self):
+ logger.debug("Listing plymouth themes...")
+
+ try:
+ themes = subprocess.check_output(['/usr/sbin/plymouth-set-default-theme', '--list'])
+ except subprocess.CalledProcessError as e:
+ raise PlymouthException("'plymouth-set-default-theme' exited with {}".format(e.returncode))
+ return themes.split()
+
+
+ @slip.dbus.polkit.require_auth(ACTION_NAME)
+ @dbus.service.method(SERVICE_NAME, in_signarute='s', out_signature='')
+ def SelectTheme(self, theme):
+ logger.debug("Setting plymouth theme to {}...".format(theme))
+
+ result = subprocess.call(['/usr/sbin/plymouth-set-default-theme', theme])
+ if result == 1:
+ raise PlymouthException("{} plymouth theme does not exist".format(theme))
+ elif result !=0:
+ raise PlymouthException("'plymouth-set-default-theme exited with {}".format(result))
+
+
+ @check_plymouthd_running
+ @slip.dbus.polkit.require_auth(ACTION_NAME)
+ @dbus.service.method(SERVICE_NAME, in_signarute='i', out_signature='')
+ def RunSimulation(self, duration):
+ logger.debug("Running simulation for {} seconds...".format(duration))
+
+ self.ShowSplash()
+ try:
+ subprocess.check_call(['plymouth', '--show-splash'])
+ for i in xrange(duration):
+ subprocess.check_call(['plymouth', '--update=test{}'.format(i)])
+ time.sleep(1)
+ except subprocess.CalledProcessError as e:
+ raise PlymouthException("Simulation failed with code {}".format(e.returncode))
+ finally:
+ self.HideSplash()
+
+
+if __name__ == '__main__':
+ logger = logging.getLogger('plymouth_theme_preview_helper')
+ logger.setLevel(logging.DEBUG)
+ syslog = logging.handlers.SysLogHandler('/dev/log')
+ formatter = logging.Formatter('%(name)s: %(levelname)s %(message)s')
+ syslog.setFormatter(formatter)
+ logger.addHandler(logging.StreamHandler())
+ logger.addHandler(syslog)
+
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+ bus = dbus.SystemBus()
+ name = dbus.service.BusName(SERVICE_NAME, bus)
+
+ object = PlymouthHelper(bus, '/PlymouthThemePreviewHelper')
+ mainloop = gobject.MainLoop()
+ slip.dbus.service.set_mainloop(mainloop)
+
+ logger.debug("Starting plymouth theme preview helper service")
+ mainloop.run()
14 ru.gentoo.plymouth_theme_preview.policy
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE policyconfig PUBLIC
+"-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
+"http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
+<policyconfig>
+ <action id="ru.gentoo.plymouth_theme_preview.use_plymouthd">
+ <description>Use Plymouth daemon</description>
+ <message>Authorization is required to run Plymouth daemon</message>
+ <defaults>
+ <allow_inactive>no</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ </action>
+</policyconfig>
17 ru.gentoo.plymouth_theme_preview_helper.conf
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE busconfig PUBLIC
+"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+ <!-- Only user root can own the helper -->
+ <policy user="root">
+ <allow own="ru.gentoo.plymouth_theme_preview_helper"/>
+ </policy>
+
+ <!-- Allow anyone to call into the service - we'll reject callers using PolicyKit -->
+ <policy context="default">
+ <allow send_interface="ru.gentoo.plymouth_theme_preview_helper"/>
+ <allow receive_sender="ru.gentoo.plymouth_theme_preview_helper"/>
+ <allow receive_interface="ru.gentoo.plymouth_theme_preview_helper"/>
+ </policy>
+</busconfig>
4 ru.gentoo.plymouth_theme_preview_helper.service
@@ -0,0 +1,4 @@
+[D-BUS Service]
+Name=ru.gentoo.plymouth_theme_preview_helper
+Exec=/usr/libexec/plymouth-theme-preview-helper
+User=root
17 setup.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+
+from distutils.core import setup
+
+setup(
+ name='plymouth-theme-preview',
+ version='0.1',
+ description='Previewer and configurator for Plymouth boot splash',
+ author='Maxim Koltsov',
+ author_email='maksbotan@gentoo.org',
+ scripts=['plymouth-theme-preview'],
+ data_files=[
+ ('/etc/dbus-1/system.d', ['ru.gentoo.plymouth_theme_preview_helper.conf']),
+ ('/usr/share/dbus-1/system-services/', ['ru.gentoo.plymouth_theme_preview_helper.service']),
+ ('/usr/share/polkit-1/actions/', ['ru.gentoo.plymouth_theme_preview.policy']),
+ ('/usr/libexec', ['plymouth-theme-preview-helper'])]
+)
Please sign in to comment.
Something went wrong with that request. Please try again.