Skip to content

Commit

Permalink
Add missing support to localed for compositor
Browse files Browse the repository at this point in the history
The plan is to use systemd-localed to control compositor keyboard and
replace current `gk_keyboard_manager`. Most of the code is in place
already but we need to add a few missing ones.

The most problematic is missing support for next layout. The issue is
that localed service don't have support for selection, to resolve this
issue we will set the first in the list as selected.

However, it means that we have to keep what user has set from Anaconda
so we can find next candidate when switch to next layout is requested.
Keep the information when user set the layouts to the compositor.
  • Loading branch information
jkonecny12 committed Oct 9, 2024
1 parent 248341e commit d9ed3f7
Show file tree
Hide file tree
Showing 2 changed files with 324 additions and 3 deletions.
104 changes: 101 additions & 3 deletions pyanaconda/modules/localization/localed.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class LocaledWrapper(object):

def __init__(self):
self._localed_proxy = None
self._user_layouts_variants = []

if not conf.system.provides_system_bus:
log.debug("Not using localed service: "
Expand Down Expand Up @@ -77,6 +78,15 @@ def layouts_variants(self):

return [join_layout_variant(layout, variant) for layout, variant in zip(layouts, variants)]

@property
def current_layout_variant(self):
"""Get first (current) layout with variant.
:return: a list of "layout (variant)" or "layout" layout specifications
:rtype: list(str)
"""
return "" if not self.layouts_variants else self.layouts_variants[0]

@property
def options(self):
"""Get current X11 options.
Expand Down Expand Up @@ -125,7 +135,7 @@ def convert_keymap(self, keymap):
orig_layouts_variants = self.layouts_variants
orig_keymap = self.keymap
converted_layouts = self.set_and_convert_keymap(keymap)
self.set_layouts(orig_layouts_variants)
self._set_layouts(orig_layouts_variants)
self.set_keymap(orig_keymap)

return converted_layouts
Expand Down Expand Up @@ -155,13 +165,22 @@ def set_layouts(self, layouts_variants, options=None, convert=False):
(see set_and_convert_layouts)
:type convert: bool
"""
# store configuration from user
self._set_layouts(layouts_variants, options, convert)
log.debug("Storing layouts for compositor configured by user")
self._user_layouts_variants = layouts_variants

def _set_layouts(self, layouts_variants, options=None, convert=False):
if not self._localed_proxy:
return

layouts = []
variants = []
parsing_failed = False

log.debug("Setting system/compositor keyboard layouts: '%s' options: '%s' convert: '%s",
layouts_variants, options, convert)

for layout_variant in (nonempty for nonempty in layouts_variants if nonempty):
try:
(layout, variant) = parse_layout_variant(layout_variant)
Expand Down Expand Up @@ -198,7 +217,7 @@ def set_and_convert_layouts(self, layouts_variants):
:rtype: str
"""

self.set_layouts(layouts_variants, convert=True)
self._set_layouts(layouts_variants, convert=True)

return self.keymap

Expand All @@ -223,7 +242,86 @@ def convert_layouts(self, layouts_variants):
orig_layouts_variants = self.layouts_variants
orig_keymap = self.keymap
ret = self.set_and_convert_layouts(layouts_variants)
self.set_layouts(orig_layouts_variants)
self._set_layouts(orig_layouts_variants)
self.set_keymap(orig_keymap)

return ret

# TODO: rename to select_layout
def set_current_layout(self, layout_variant):
"""Set given layout as first (current) layout for compositor.
This will search for the given layout variant in the list and move it as first in the list.
:param layout_variant: The layout to set, with format "layout (variant)"
(e.g. "cz (qwerty)")
:type layout_variant: str
:return: If the keyboard layout was activated
:rtype: bool
"""
# ignore compositor layouts but force Anaconda configuration
layouts = self._user_layouts_variants

try:
new_layouts = self._shift_list(layouts, layout_variant)
self._set_layouts(new_layouts)
return True
except ValueError:
log.warning("Can't set layout: '%s' as first to the current set: %s",
layout_variant, layouts)
return False

@staticmethod
def _shift_list(source_layouts, value_to_first):
"""Helper method to reorder list of layouts and move one as first in the list.
We should preserve the ordering just shift items from start of the list to the
end in the same order.
When we want to set 2nd as first in this list:
["cz", "es", "us"]
The result should be:
["es", "us", "cz"]
So the compositor has the same next layout as Anaconda.
:raises: ValueError: if the list is small or the layout is not inside
"""
value_id = source_layouts.index(value_to_first)
new_list = source_layouts[value_id:len(source_layouts)] + source_layouts[0:value_id]
return new_list

def select_next_layout(self):
"""Select (make it first) next layout for compositor.
Find current compositor layout in the list of defined layouts and set next to it as
current (first) for compositor. We need to have user defined list because compositor
layouts will change with the selection. Store this list when user is setting configuration
to compositor. This list must not change ordering.
:param user_layouts: List of layouts selected by user in Anaconda.
:type user_layouts: [str]
:return: If switch was successful True otherwise False
:rtype: bool
"""
current_layout = self.current_layout_variant
layout_id = 0

if not self._user_layouts_variants:
log.error("Can't switch next layout - user defined keyboard layout is not present!")
return False

# find next layout
for i, v in enumerate(self._user_layouts_variants):
if v == current_layout:
layout_id = i + 1
layout_id %= len(self._user_layouts_variants)

try:
new_layouts = self._shift_list(self._user_layouts_variants,
self._user_layouts_variants[layout_id])
self._set_layouts(new_layouts)
return True
except ValueError:
log.warning("Can't set next keyboard layout %s", self._user_layouts_variants)
return False
Loading

0 comments on commit d9ed3f7

Please sign in to comment.