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