[master][PATCH] Let users configure keyboard via anaconda in live installations (#1002533)

Vratislav Podzimek vpodzime at redhat.com
Thu Sep 5 11:59:30 UTC 2013


Setting up keyboard layouts for both the installation process and the installed
system is a complicated and confusing task. Because the default environments
don't show the layout indicator and have keyboard configuration hidden in some
menus, we may let users configure keyboard layouts via anaconda.

If somebody configures keyboard on their own and the anaconda's configuration
for the installed system is different, we should warn them and make them visit
the Keyboard spoke to confirm the configuration.

Signed-off-by: Vratislav Podzimek <vpodzime at redhat.com>
---
 pyanaconda/flags.py                  |  7 +++++--
 pyanaconda/keyboard.py               | 26 ++++++++++++++++++++++++++
 pyanaconda/ui/gui/spokes/keyboard.py | 21 ++++++++++++++-------
 pyanaconda/ui/gui/spokes/welcome.py  |  4 ++--
 4 files changed, 47 insertions(+), 11 deletions(-)

diff --git a/pyanaconda/flags.py b/pyanaconda/flags.py
index 07e5e95..e79f502 100644
--- a/pyanaconda/flags.py
+++ b/pyanaconda/flags.py
@@ -180,16 +180,19 @@ class BootArgs(OrderedDict):
                 result = False # XXX: should noarg=off -> True?
         return result
 
-def can_touch_runtime_system(msg):
+def can_touch_runtime_system(msg, ignore_live=False):
     """
     Guard that should be used before doing actions that modify runtime system.
 
     :param msg: message to be logged in case that runtime system cannot be touched
+    :type msg: str
+    :param ignore_live: whether to ignore liveCD installations (can touch liveCD system)
+    :type ignore_live: bool
     :rtype: bool
 
     """
 
-    if flags.livecdInstall:
+    if flags.livecdInstall and not ignore_live:
         log.info("Not doing '%s' in live installation", msg)
         return False
 
diff --git a/pyanaconda/keyboard.py b/pyanaconda/keyboard.py
index 24d10bb..934b701 100644
--- a/pyanaconda/keyboard.py
+++ b/pyanaconda/keyboard.py
@@ -500,6 +500,32 @@ class XklWrapper(object):
         self._switching_options.append(name)
         self.switch_to_show_str[name] = desc.encode("utf-8")
 
+    def get_current_layout(self):
+        """
+        Get current activated X layout and variant
+
+        :return: current activated X layout and variant (e.g. "cz (qwerty)")
+
+        """
+        # ported from the widgets/src/LayoutIndicator.c code
+
+        self._engine.start_listen(Xkl.EngineListenModes.TRACK_KEYBOARD_STATE)
+        state = self._engine.get_current_state()
+        cur_group = state.group
+        num_groups = self._engine.get_num_groups()
+
+        # BUG?: if the last layout in the list is activated and removed,
+        #       state.group may be equal to n_groups
+        if cur_group >= num_groups:
+            cur_group = num_groups - 1;
+
+        layout = self._rec.layouts[cur_group]
+        variant = self._rec.variants[cur_group]
+
+        self._engine.stop_listen(Xkl.EngineListenModes.TRACK_KEYBOARD_STATE)
+
+        return _join_layout_variant(layout, variant)
+
     def get_available_layouts(self):
         """A generator yielding layouts (no need to store them as a bunch)"""
 
diff --git a/pyanaconda/ui/gui/spokes/keyboard.py b/pyanaconda/ui/gui/spokes/keyboard.py
index 1e5cb3f..5782666 100644
--- a/pyanaconda/ui/gui/spokes/keyboard.py
+++ b/pyanaconda/ui/gui/spokes/keyboard.py
@@ -264,6 +264,7 @@ class KeyboardSpoke(NormalSpoke):
     def __init__(self, *args):
         NormalSpoke.__init__(self, *args)
         self._remove_last_attempt = False
+        self._confirmed = False
         self._xkl_wrapper = keyboard.XklWrapper.get_instance()
 
         self._upButton = self.builder.get_object("upButton")
@@ -272,18 +273,24 @@ class KeyboardSpoke(NormalSpoke):
         self._previewButton = self.builder.get_object("previewButton")
 
     def apply(self):
+        # the user has confirmed (seen) the configuration
+        self._confirmed = True
+
         # Clear and repopulate self.data with actual values
         self.data.keyboard.x_layouts = list()
         self.data.keyboard.seen = True
 
         for row in self._store:
             self.data.keyboard.x_layouts.append(row[0])
-        # FIXME:  Set the keyboard layout here, too.
 
     @property
     def completed(self):
         if flags.flags.automatedInstall and not self.data.keyboard.seen:
             return False
+        elif not self._confirmed and self._xkl_wrapper.get_current_layout() != self.data.keyboard.x_layouts[0]:
+            # the currently activated layout is a different one from the
+            # installed system's default
+            return False
         else:
             return True
 
@@ -296,7 +303,7 @@ class KeyboardSpoke(NormalSpoke):
         NormalSpoke.initialize(self)
 
         if flags.can_touch_runtime_system("hide runtime keyboard configuration "
-                                          "warning"):
+                                          "warning", ignore_live=True):
             self.builder.get_object("warningBox").hide()
 
         # We want to store layouts' names but show layouts as
@@ -314,7 +321,7 @@ class KeyboardSpoke(NormalSpoke):
 
         self._layoutSwitchLabel = self.builder.get_object("layoutSwitchLabel")
 
-        if not flags.can_touch_runtime_system("test X layouts"):
+        if not flags.can_touch_runtime_system("test X layouts", ignore_live=True):
             # Disable area for testing layouts as we cannot make
             # it work without modifying runtime system
 
@@ -352,7 +359,7 @@ class KeyboardSpoke(NormalSpoke):
 
     def _addLayout(self, store, name):
         # first try to add the layout
-        if flags.can_touch_runtime_system("add runtime X layout"):
+        if flags.can_touch_runtime_system("add runtime X layout", ignore_live=True):
             self._xkl_wrapper.add_layout(name)
 
         # valid layout, append it to the store
@@ -365,7 +372,7 @@ class KeyboardSpoke(NormalSpoke):
 
         """
 
-        if flags.can_touch_runtime_system("remove runtime X layout"):
+        if flags.can_touch_runtime_system("remove runtime X layout", ignore_live=True):
             self._xkl_wrapper.remove_layout(store[itr][0])
         store.remove(itr)
 
@@ -449,7 +456,7 @@ class KeyboardSpoke(NormalSpoke):
             return
 
         store.swap(cur, prev)
-        if flags.can_touch_runtime_system("reorder runtime X layouts"):
+        if flags.can_touch_runtime_system("reorder runtime X layouts", ignore_live=True):
             self._flush_layouts_to_X()
 
         if not store.iter_previous(cur):
@@ -473,7 +480,7 @@ class KeyboardSpoke(NormalSpoke):
             return
 
         store.swap(cur, nxt)
-        if flags.can_touch_runtime_system("reorder runtime X layouts"):
+        if flags.can_touch_runtime_system("reorder runtime X layouts", ignore_live=True):
             self._flush_layouts_to_X()
 
         if activate_default:
diff --git a/pyanaconda/ui/gui/spokes/welcome.py b/pyanaconda/ui/gui/spokes/welcome.py
index 5bd8c8a..49f2c06 100644
--- a/pyanaconda/ui/gui/spokes/welcome.py
+++ b/pyanaconda/ui/gui/spokes/welcome.py
@@ -120,14 +120,14 @@ class WelcomeLanguageSpoke(StandaloneSpoke):
             new_layouts = ["us"]
 
         self.data.keyboard.x_layouts = new_layouts
-        if flags.can_touch_runtime_system("replace runtime X layouts"):
+        if flags.can_touch_runtime_system("replace runtime X layouts", ignore_live=True):
             self._xklwrapper.replace_layouts(new_layouts)
 
         if len(new_layouts) >= 2 and not self.data.keyboard.switch_options:
             #initialize layout switching if needed
             self.data.keyboard.switch_options = ["grp:alt_shift_toggle"]
 
-            if flags.can_touch_runtime_system("init layout switching"):
+            if flags.can_touch_runtime_system("init layout switching", ignore_live=True):
                 self._xklwrapper.set_switching_options(["grp:alt_shift_toggle"])
                 # activate the first (language-default) layout instead of the
                 # 'us' one
-- 
1.7.11.7



More information about the anaconda-patches mailing list