[PATCH] Use systemd-localed for writing out xorg conf file (#958714)

Vratislav Podzimek vpodzime at redhat.com
Mon May 6 16:02:59 UTC 2013


Also use its file to write out configuration to the target system instead of our
own file nobody reads. The systemd-localed's configuration file is read by Gnome
and hopefully the other desktop environments as well.

Signed-off-by: Vratislav Podzimek <vpodzime at redhat.com>
---
 pyanaconda/keyboard.py | 245 ++++++++++++++++++++++++++++++-------------------
 1 file changed, 153 insertions(+), 92 deletions(-)

diff --git a/pyanaconda/keyboard.py b/pyanaconda/keyboard.py
index be33314..004fa97 100755
--- a/pyanaconda/keyboard.py
+++ b/pyanaconda/keyboard.py
@@ -34,6 +34,8 @@ keymaps.
 
 import types
 import os
+import shutil
+
 from pyanaconda import iutil
 from pyanaconda.safe_dbus import dbus_call_safe_sync, dbus_get_property_safe_sync
 from pyanaconda.safe_dbus import DBUS_SYSTEM_BUS_ADDR
@@ -90,50 +92,6 @@ def _join_layout_variant(layout, variant=""):
     else:
         return layout
 
-def get_layouts_xorg_conf(keyboard):
-    """
-    Get the xorg.conf content setting up layouts in the ksdata.
-
-    :param keyboard: ksdata.keyboard object
-    :rtype: str
-
-    """
-
-    layouts = list()
-    variants = list()
-
-    for layout_variant in keyboard.x_layouts:
-        (layout, variant) = _parse_layout_variant(layout_variant)
-        layouts.append(layout)
-        variants.append(variant)
-
-    ret = "#This file was generated by the Anaconda installer\n"
-
-    #section header
-    ret += 'Section "InputClass"\n'\
-           '\tIdentifier\t"anaconda-keyboard"\n'\
-           '\tMatchIsKeyboard\t"on"\n'
-
-    #layouts
-    ret += '\tOption\t"XkbLayout"\t'
-    ret += '"' + ','.join(layouts) + '"\n'
-
-    #variants
-    if any(variants):
-        #write out this line only if some variants are specified
-        ret += '\tOption\t"XkbVariant"\t'
-        ret += '"' + ','.join(variants) + '"\n'
-
-    #switching
-    if any(keyboard.switch_options):
-        ret += '\tOption\t"XkbOptions"\t'
-        ret += '"' + ','.join(keyboard.switch_options) + '"\n'
-
-    #section footer
-    ret += 'EndSection\n'
-
-    return ret
-
 def populate_missing_items(keyboard):
     """
     Function that populates keyboard.vc_keymap and keyboard.x_layouts if
@@ -156,7 +114,7 @@ def populate_missing_items(keyboard):
         c_lay_var = localed.set_and_convert_keymap(keyboard.vc_keymap)
         keyboard.x_layouts.append(c_lay_var)
 
-def write_keyboard_config(keyboard, root, convert=True, weight=0):
+def write_keyboard_config(keyboard, root, convert=True):
     """
     Function that writes files with layouts configuration to
     $root/etc/X11/xorg.conf.d/01-anaconda-layouts.conf and
@@ -173,8 +131,9 @@ def write_keyboard_config(keyboard, root, convert=True, weight=0):
     if convert:
         populate_missing_items(keyboard)
 
-    xconf_dir = os.path.normpath(root + "/etc/X11/xorg.conf.d")
-    xconf_file = "%0.2d-anaconda-keyboard.conf" % weight
+    xconf_dir = "/etc/X11/xorg.conf.d"
+    xconf_file = "00-keyboard.conf"
+    xconf_file_path = os.path.normpath(xconf_dir + "/" + xconf_file)
 
     vcconf_dir = os.path.normpath(root + "/etc")
     vcconf_file = "vconsole.conf"
@@ -189,11 +148,30 @@ def write_keyboard_config(keyboard, root, convert=True, weight=0):
         errors.append("Cannot create directory xorg.conf.d")
 
     if keyboard.x_layouts:
-        try:
-            with open(os.path.join(xconf_dir, xconf_file), "w") as fobj:
-                fobj.write(get_layouts_xorg_conf(keyboard))
-        except IOError as ioerr:
-            errors.append("Cannot write X keyboard configuration file")
+        localed_wrapper = LocaledWrapper()
+
+        if root != "/":
+            # writing to a different root, we need to save these values, so that
+            # we can restore them when we have the file written out
+            layouts_variants = localed_wrapper.layouts_variants
+            options = localed_wrapper.options
+
+            # set systemd-localed's layouts, variants and switch options, which
+            # also generates a new conf file
+            localed_wrapper.set_layouts(keyboard.x_layouts,
+                                        keyboard.switch_options)
+
+            # copy the file to the chroot
+            shutil.copy2(xconf_file_path,
+                         os.path.normpath(root + "/" + xconf_file_path))
+
+            # restore the original values
+            localed_wrapper.set_layouts(layouts_variants,
+                                        options)
+        else:
+            # just let systemd-localed write out the conf file
+            localed_wrapper.set_layouts(keyboard.x_layouts,
+                                        keyboard.switch_options)
 
     if keyboard.vc_keymap:
         try:
@@ -289,9 +267,8 @@ def activate_keyboard(keyboard):
         if not keyboard.vc_keymap:
             keyboard.vc_keymap = c_keymap
 
-        # write out full configuration that will be loaded by X server
-        # (systemd-localed writes configuration with only one layout)
-        write_keyboard_config(keyboard, root="/", convert=False, weight=99)
+        # write out keyboard configuration for the X session
+        write_keyboard_config(keyboard, root="/", convert=False)
 
 def item_str(s):
     """Convert a zero-terminated byte array to a proper str"""
@@ -664,14 +641,63 @@ class LocaledWrapper(object):
                              Gio.DBusConnectionFlags.MESSAGE_BUS_CONNECTION,
                              None, None)
 
-    def set_and_convert_keymap(self, keymap):
+    @property
+    def keymap(self):
+        keymap = dbus_get_property_safe_sync(LOCALED_SERVICE,
+                                             LOCALED_OBJECT_PATH,
+                                             LOCALED_IFACE,
+                                             "VConsoleKeymap",
+                                             self._connection)
+
+        # returned GVariant is unpacked to a tuple with a single element
+        return keymap[0]
+
+    @property
+    def layouts_variants(self):
+        layouts = dbus_get_property_safe_sync(LOCALED_SERVICE,
+                                              LOCALED_OBJECT_PATH,
+                                              LOCALED_IFACE,
+                                              "X11Layout",
+                                              self._connection)
+
+        variants = dbus_get_property_safe_sync(LOCALED_SERVICE,
+                                               LOCALED_OBJECT_PATH,
+                                               LOCALED_IFACE,
+                                               "X11Variant",
+                                               self._connection)
+
+        # returned GVariants are unpacked to tuples with single elements
+        # containing comma-separated values
+        layouts = layouts[0].split(",")
+        variants = variants[0].split(",")
+
+        # if there are more layouts than variants, empty strings should be appended
+        diff = len(layouts) - len(variants)
+        variants.extend(diff * [""])
+
+        # map can be used with multiple lists and works like zipWith (Haskell)
+        return map(_join_layout_variant, layouts, variants)
+
+    @property
+    def options(self):
+        options = dbus_get_property_safe_sync(LOCALED_SERVICE,
+                                              LOCALED_OBJECT_PATH,
+                                              LOCALED_IFACE,
+                                              "X11Options",
+                                              self._connection)
+
+        # returned GVariant is unpacked to a tuple with a single element
+        return options[0]
+
+    def set_keymap(self, keymap, convert=False):
         """
-        Method that sets VConsole keymap and returns X11 layout and
-        variant that (systemd-localed thinks) match given keymap best.
+        Method that sets VConsole keymap via systemd-localed's DBus API.
 
-        :return: string containing "layout (variant)" or "layout" if variant
-                 is missing
-        :rtype: string
+        :param keymap: VConsole keymap that should be set
+        :type keymap: str
+        :param convert: whether the keymap should be converted to a X11 layout
+                        (see set_and_convert_keymap)
+        :type convert: bool
 
         """
 
@@ -679,55 +705,90 @@ class LocaledWrapper(object):
         # where convert indicates whether the keymap should be converted
         # to X11 layout and user_interaction indicates whether PolicyKit
         # should ask for credentials or not
-        args = GLib.Variant('(ssbb)', (keymap, "", True, False))
+        args = GLib.Variant('(ssbb)', (keymap, "", convert, False))
 
         dbus_call_safe_sync(LOCALED_SERVICE, LOCALED_OBJECT_PATH, LOCALED_IFACE,
                             "SetVConsoleKeyboard", args, self._connection)
 
-        layout = dbus_get_property_safe_sync(LOCALED_SERVICE,
-                                             LOCALED_OBJECT_PATH,
-                                             LOCALED_IFACE,
-                                             "X11Layout",
-                                             self._connection)
+    def set_and_convert_keymap(self, keymap):
+        """
+        Method that sets VConsole keymap and returns X11 layouts and
+        variants that (systemd-localed thinks) match given keymap best.
 
-        variant = dbus_get_property_safe_sync(LOCALED_SERVICE,
-                                              LOCALED_OBJECT_PATH,
-                                              LOCALED_IFACE,
-                                              "X11Variant",
-                                              self._connection)
+        :return: string containing comma-separated "layout (variant)" or
+                 "layout" layout specifications
+        :rtype: string
+
+        """
 
-        # returned GVariants are unpacked to a tuple with single element
-        layout = layout[0]
-        variant = variant[0]
+        self.set_keymap(keymap, convert=True)
 
-        return _join_layout_variant(layout, variant)
+        layouts_str, variants_str = self.layouts_variants
 
-    def set_and_convert_layout(self, layout_variant):
-        """
-        Method that sets X11 layout and variant (for later X sessions)
-        and returns VConsole keymap that (systemd-localed thinks) matches
-        given layout and variant best.
+        layouts = layouts_str.split(",")
+        variants = variants_str.split(",")
 
-        :return: a keymap matching layout and variant best
-        :rtype: string
+        # if there are less variants than layouts, empty strings need to be
+        # appended
+        diff = len(layouts) - len(variants)
+        variants = variants + diff * [""]
+
+        layouts_variants = []
+        layouts_variants.extend(map(_join_layout_variant, layouts, variants))
+
+        return ",".join(layouts_variants)
+
+    def set_layouts(self, layouts_variants, options=None, convert=False):
+        """
+        Method that sets X11 layouts and variants (for later X sessions) via
+        systemd-localed's DBus API.
+
+        :param layout_variant: list of 'layout (variant)' or 'layout'
+                               specifications of layouts and variants
+        :type layout_variant: list of strings
+        :param options: list of X11 options that should be set
+        :type options: list of strings
+        :param convert: whether the keymap should be converted to a X11 layout
+                        (see set_and_convert_keymap)
+        :type convert: bool
 
         """
 
-        (layout, variant) = _parse_layout_variant(layout_variant)
+        layouts = []
+        variants = []
+
+        for layout_variant in layouts_variants:
+            (layout, variant) = _parse_layout_variant(layout_variant)
+            layouts.append(layout)
+            variants.append(variant)
+
+        layouts_str = ",".join(layouts)
+        variants_str = ",".join(variants)
+        if options:
+            opts_str = ",".join(options)
+        else:
+            opts_str = ""
 
         # args: layout, model, variant, options, convert, user_interaction
         # where convert indicates whether the keymap should be converted
         # to X11 layout and user_interaction indicates whether PolicyKit
         # should ask for credentials or not
-        args = GLib.Variant("(ssssbb)", (layout, "", variant, "", True, False))
+        args = GLib.Variant("(ssssbb)", (layouts_str, "", variants_str, opts_str,
+                                         convert, False))
         dbus_call_safe_sync(LOCALED_SERVICE, LOCALED_OBJECT_PATH, LOCALED_IFACE,
                             "SetX11Keyboard", args, self._connection)
 
-        keymap = dbus_get_property_safe_sync(LOCALED_SERVICE,
-                                             LOCALED_OBJECT_PATH,
-                                             LOCALED_IFACE,
-                                             "VConsoleKeymap",
-                                             self._connection)
+    def set_and_convert_layout(self, layout_variant):
+        """
+        Method that sets X11 layout and variant (for later X sessions)
+        and returns VConsole keymap that (systemd-localed thinks) matches
+        given layout and variant best.
 
-        # returned GVariant is unpacked to a tuple with single element
-        return keymap[0]
+        :return: a keymap matching layout and variant best
+        :rtype: string
+
+        """
+
+        self.set_layouts([layout_variant], convert=True)
+
+        return self.keymap
-- 
1.7.11.7



More information about the anaconda-patches mailing list