[PATCH 1/2] Add and remove layouts from the X runtime configuration

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

 



When user adds/removes a layout, we want to add/remove it from the
X runtime configuration so that the change really happens.
---
 pyanaconda/ui/gui/spokes/keyboard.py |    4 +
 pyanaconda/ui/gui/spokes/welcome.py  |    1 +
 pyanaconda/xklavier.py               |  106 +++++++++++++++++++++++++++++++++-
 3 files changed, 109 insertions(+), 2 deletions(-)

diff --git a/pyanaconda/ui/gui/spokes/keyboard.py b/pyanaconda/ui/gui/spokes/keyboard.py
index 1223a63..6a04d6d 100644
--- a/pyanaconda/ui/gui/spokes/keyboard.py
+++ b/pyanaconda/ui/gui/spokes/keyboard.py
@@ -183,6 +183,7 @@ class KeyboardSpoke(NormalSpoke):
 
     def _addLayout(self, store, name):
         store.append([name])
+        self._xkl_wrapper.add_layout(name)
 
     # Signal handlers.
     def on_add_clicked(self, button):
@@ -222,6 +223,7 @@ class KeyboardSpoke(NormalSpoke):
             itr2 = store.iter_next(itr2)
             if itr2: #next one existing
                 selection.select_iter(itr2)
+                self._xkl_wrapper.remove_layout(store[itr][0])
                 store.remove(itr)
                 return
 
@@ -239,6 +241,8 @@ class KeyboardSpoke(NormalSpoke):
         while itr3 and (store[itr3][0] != store[itr][0]):
             itr2 = store.iter_next(itr2)
             itr3 = store.iter_next(itr3)
+
+        self._xkl_wrapper.remove_layout(store[itr][0])
         store.remove(itr)
         selection.select_iter(itr2)
 
diff --git a/pyanaconda/ui/gui/spokes/welcome.py b/pyanaconda/ui/gui/spokes/welcome.py
index 7e7444d..e4dd145 100644
--- a/pyanaconda/ui/gui/spokes/welcome.py
+++ b/pyanaconda/ui/gui/spokes/welcome.py
@@ -74,6 +74,7 @@ class WelcomeLanguageSpoke(StandaloneSpoke):
         for layout in new_layouts:
             if layout not in self.data.keyboard.layouts_list:
                 self.data.keyboard.layouts_list.append(layout)
+                self._xklwrapper.add_layout(layout)
 
         #TODO: better use GeoIP data once it is available
         if self.language.territory and not self.data.timezone.timezone:
diff --git a/pyanaconda/xklavier.py b/pyanaconda/xklavier.py
index 386dea2..3dad44f 100755
--- a/pyanaconda/xklavier.py
+++ b/pyanaconda/xklavier.py
@@ -50,6 +50,11 @@ class _Layout(object):
     def description(self):
         return self.desc
 
+class XklWrapperError(Exception):
+    """Exception class for reporting libxklavier-related problems"""
+
+    pass
+
 class XklWrapper(object):
     """
     Class wrapping the libxklavier functionality
@@ -72,10 +77,29 @@ class XklWrapper(object):
     def __init__(self):
         #initialize Xkl-related stuff
         display = GdkX11.x11_get_default_xdisplay()
-        engine = Xkl.Engine.get_instance(display)
+        self._engine = Xkl.Engine.get_instance(display)
+
+        self._rec = Xkl.ConfigRec()
+        if not self._rec.get_from_server(self._engine):
+            raise XklWrapperError("Failed to get configuration from server")
+
+        #X is probably initialized to the 'us' layout without any variant and
+        #since we want to add layouts with variants we need the layouts and
+        #variants lists to have the same length. Add "" padding to variants.
+        #See docstring of the add_layout method for details.
+        diff = len(self._rec.layouts) - len(self._rec.variants)
+        if diff > 0:
+            self._rec.set_variants(self._rec.variants + (diff * [""]))
+            if not self._rec.activate(self._engine):
+                raise XklWrapperError("Failed to initialize layouts")
+
+        #initialize layout switching to Alt+Shift
+        self._rec.set_options(self._rec.options + ["grp:alt_shift_toggle"])
+        if not self._rec.activate(self._engine):
+            raise XklWrapperError("Cannot initialize layout switching")
 
         #needed also for Gkbd.KeyboardDrawingDialog
-        self.configreg = Xkl.ConfigRegistry.get_instance(engine)
+        self.configreg = Xkl.ConfigRegistry.get_instance(self._engine)
         self.configreg.load(False)
 
         self._language_keyboard_variants = dict()
@@ -134,3 +158,81 @@ class XklWrapper(object):
         #first layout (should exist for every language)
         return language_layouts[0].name
 
+    def _parse_layout_variant(self, layout):
+        """
+        Parse layout and variant from the string that may look like 'layout' or
+        'layout (variant)'.
+
+        @return: the (layout, variant) pair, where variant can be ""
+        @rtype: tuple
+
+        """
+
+        variant = ""
+
+        lbracket_idx = layout.find("(")
+        rbracket_idx = layout.rfind(")")
+        if lbracket_idx != -1:
+            variant = layout[(lbracket_idx + 1) : rbracket_idx]
+            layout = layout[:lbracket_idx].strip()
+
+        return (layout, variant)
+
+    def add_layout(self, layout):
+        """
+        Method that tries to add a given layout to the current X configuration.
+
+        The X layouts configuration is handled by two lists. A list of layouts
+        and a list of variants. Index-matching items in these lists (as if they
+        were zipped) are used for the construction of real layouts (e.g.
+        'cz (qwerty)').
+
+        @param layout: either 'layout' or 'layout (variant)'
+        @raise XklWrapperError: if the given layout cannot be added
+
+        """
+
+        #we can get 'layout' or 'layout (variant)'
+        (layout, variant) = self._parse_layout_variant(layout)
+
+        #do not add the same layout-variant combinanion multiple times
+        if (layout, variant) in zip(self._rec.layouts, self._rec.variants):
+            return
+
+        self._rec.set_layouts(self._rec.layouts + [layout])
+        self._rec.set_variants(self._rec.variants + [variant])
+
+        if not self._rec.activate(self._engine):
+            raise XklWrapperError("Failed to add layout '%s (%s)'" % (layout,
+                                                                      variant))
+
+    def remove_layout(self, layout):
+        """
+        Method that tries to remove a given layout from the current X
+        configuration.
+
+        See also the documentation for the add_layout method.
+
+        @param layout: either 'layout' or 'layout (variant)'
+        @raise XklWrapperError: if the given layout cannot be removed
+
+        """
+
+        #we can get 'layout' or 'layout (variant)'
+        (layout, variant) = self._parse_layout_variant(layout)
+
+        layouts_variants = zip(self._rec.layouts, self._rec.variants)
+
+        if not (layout, variant) in layouts_variants:
+            raise XklWrapperError("'%s (%s)' not in the list of added layouts")
+
+        idx = layouts_variants.index((layout, variant))
+        new_layouts = self._rec.layouts[:idx] + self._rec.layouts[(idx + 1):]
+        new_variants = self._rec.variants[:idx] + self._rec.variants[(idx + 1):]
+
+        self._rec.set_layouts(new_layouts)
+        self._rec.set_variants(new_variants)
+
+        if not self._rec.activate(self._engine):
+            raise XklWrapperError("Failed to remove layout '%s (%s)'" % (layout,
+                                                                       variant))
-- 
1.7.4.4

_______________________________________________
Anaconda-devel-list mailing list
Anaconda-devel-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/anaconda-devel-list


[Index of Archives]     [Kickstart]     [Fedora Users]     [Fedora Legacy List]     [Fedora Maintainers]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [Yosemite Photos]     [KDE Users]     [Fedora Tools]
  Powered by Linux