Example #1
0
 def set_gnome_input_sources(self, input_sources):
     self.debug(
         "Setting org.gnome.desktop.input-sources sources to %r",
         input_sources,
     )
     gsettings.set_list("org.gnome.desktop.input-sources", "sources",
                        input_sources)
Example #2
0
def set_indicator_keymaps(lang):
    import libxml2
    from gi.repository import Xkl, GdkX11
    # GdkX11.x11_get_default_xdisplay() segfaults if Gtk hasn't been
    # imported; possibly finer-grained than this, but anything using this
    # will already have imported Gtk anyway ...
    from gi.repository import Gtk
    from ubiquity import gsettings

    # pacify pyflakes
    Gtk

    xpath = "//iso_639_3_entry[@part1_code='%s']"
    gsettings_key = ['org.gnome.libgnomekbd.keyboard', 'layouts']
    lang = lang.split('_')[0]
    variants = []

    # Map inspired from that of gfxboot-theme-ubuntu that's itself
    # based on console-setup's. This one has been restricted to
    # language => keyboard layout not locale => keyboard layout as
    # we don't actually know the exact locale
    default_keymap = {
        'ar': 'ara',
        'bs': 'ba',
        'de': 'de',
        'el': 'gr',
        'en': 'us',
        'eo': 'epo',
        'fr': 'fr_oss',
        'gu': 'in_guj',
        'hi': 'in',
        'hr': 'hr',
        'hy': 'am',
        'ka': 'ge',
        'kn': 'in_kan',
        'lo': 'la',
        'ml': 'in_mal',
        'pa': 'in_guru',
        'sr': 'rs',
        'sv': 'se',
        'ta': 'in_tam',
        'te': 'in_tel',
        'zh': 'cn',
    }

    def item_str(s):
        '''Convert a zero-terminated byte array to a proper str'''
        i = s.find(b'\x00')
        return s[:i].decode()

    def process_variant(*args):
        if hasattr(args[2], 'name'):
            variants.append('%s\t%s' %
                            (item_str(args[1].name), item_str(args[2].name)))
        else:
            variants.append(item_str(args[1].name))

    def restrict_list(variants):
        new_variants = []

        # Start by looking by an explicit default layout in the keymap
        if lang in default_keymap:
            if default_keymap[lang] in variants:
                variants.remove(default_keymap[lang])
                new_variants.append(default_keymap[lang])
            else:
                tab_keymap = default_keymap[lang].replace('_', '\t')
                if tab_keymap in variants:
                    variants.remove(tab_keymap)
                    new_variants.append(tab_keymap)

        # Prioritize the layout matching the language (if any)
        if lang in variants:
            variants.remove(lang)
            new_variants.append(lang)

        # Uniquify our list (just in case)
        variants = list(set(variants))

        if len(variants) > 4:
            # We have a problem, X only supports 4

            # Add as many entry as we can that are layouts without variant
            country_variants = sorted(
                [entry for entry in variants if '\t' not in entry])
            for entry in country_variants[:4 - len(new_variants)]:
                new_variants.append(entry)
                variants.remove(entry)

            if len(new_variants) < 4:
                # We can add some more
                simple_variants = sorted(
                    [entry for entry in variants if '_' not in entry])
                for entry in simple_variants[:4 - len(new_variants)]:
                    new_variants.append(entry)
                    variants.remove(entry)

            if len(new_variants) < 4:
                # Now just add anything left
                for entry in variants[:4 - len(new_variants)]:
                    new_variants.append(entry)
                    variants.remove(entry)
        else:
            new_variants += list(variants)

        # gsettings doesn't understand utf8
        new_variants = [str(variant) for variant in new_variants]

        return new_variants

    def call_setxkbmap(variants):
        kb_layouts = []
        kb_variants = []

        for entry in variants:
            fields = entry.split('\t')
            if len(fields) > 1:
                kb_layouts.append(fields[0])
                kb_variants.append(fields[1])
            else:
                kb_layouts.append(fields[0])
                kb_variants.append("")

        execute("setxkbmap", "-layout", ",".join(kb_layouts), "-variant",
                ",".join(kb_variants))

    fp = libxml2.parseFile('/usr/share/xml/iso-codes/iso_639_3.xml')
    context = fp.xpathNewContext()
    nodes = context.xpathEvalExpression(xpath % lang)
    display = GdkX11.x11_get_default_xdisplay()
    engine = Xkl.Engine.get_instance(display)
    if nodes:
        configreg = Xkl.ConfigRegistry.get_instance(engine)
        configreg.load(False)

        # Apparently part2_code doesn't always work (fails with French)
        for prop in ('part2_code', 'id', 'part1_code'):
            if nodes[0].hasProp(prop):
                code = nodes[0].prop(prop)
                configreg.foreach_language_variant(code, process_variant, None)
                if variants:
                    restricted_variants = restrict_list(variants)
                    call_setxkbmap(restricted_variants)
                    gsettings.set_list(gsettings_key[0], gsettings_key[1],
                                       restricted_variants)
                    break
        else:
            # Use the system default if no other keymaps can be determined.
            gsettings.set_list(gsettings_key[0], gsettings_key[1], [])

    engine.lock_group(0)
Example #3
0
def set_indicator_keymaps(lang):
    import xml.etree.cElementTree as ElementTree
    from gi.repository import Xkl, GdkX11
    # GdkX11.x11_get_default_xdisplay() segfaults if Gtk hasn't been
    # imported; possibly finer-grained than this, but anything using this
    # will already have imported Gtk anyway ...
    from gi.repository import Gtk
    from ubiquity import gsettings

    gsettings_key = ['org.gnome.libgnomekbd.keyboard', 'layouts']
    lang = lang.split('_')[0]
    variants = []

    # Map inspired from that of gfxboot-theme-ubuntu that's itself
    # based on console-setup's. This one has been restricted to
    # language => keyboard layout not locale => keyboard layout as
    # we don't actually know the exact locale
    default_keymap = {
        'ar': 'ara',
        'bs': 'ba',
        'de': 'de',
        'el': 'gr',
        'en': 'us',
        'eo': 'epo',
        'fr': 'fr_oss',
        'gu': 'in_guj',
        'hi': 'in',
        'hr': 'hr',
        'hy': 'am',
        'ka': 'ge',
        'kn': 'in_kan',
        'lo': 'la',
        'ml': 'in_mal',
        'pa': 'in_guru',
        'sr': 'rs',
        'sv': 'se',
        'ta': 'in_tam',
        'te': 'in_tel',
        'zh': 'cn',
    }

    def item_str(s):
        """ Convert a zero-terminated byte array to a proper str """
        i = s.find(b'\x00')
        return s[:i].decode()

    def process_variant(*args):
        if hasattr(args[2], 'name'):
            variants.append('{0}\t{1}'.format((item_str(args[1].name), item_str(args[2].name))))
        else:
            variants.append(item_str(args[1].name))

    def restrict_list(variants):
        new_variants = []

        # Start by looking by an explicit default layout in the keymap
        if lang in default_keymap:
            if default_keymap[lang] in variants:
                variants.remove(default_keymap[lang])
                new_variants.append(default_keymap[lang])
            else:
                tab_keymap = default_keymap[lang].replace('_', '\t')
                if tab_keymap in variants:
                    variants.remove(tab_keymap)
                    new_variants.append(tab_keymap)

        # Prioritize the layout matching the language (if any)
        if lang in variants:
            variants.remove(lang)
            new_variants.append(lang)

        # Uniquify our list (just in case)
        variants = list(set(variants))

        if len(variants) > 4:
            # We have a problem, X only supports 4

            # Add as many entry as we can that are layouts without variant
            country_variants = sorted(
                entry for entry in variants if '\t' not in entry)
            for entry in country_variants[:4 - len(new_variants)]:
                new_variants.append(entry)
                variants.remove(entry)

            if len(new_variants) < 4:
                # We can add some more
                simple_variants = sorted(
                    entry for entry in variants if '_' not in entry)
                for entry in simple_variants[:4 - len(new_variants)]:
                    new_variants.append(entry)
                    variants.remove(entry)

            if len(new_variants) < 4:
                # Now just add anything left
                for entry in variants[:4 - len(new_variants)]:
                    new_variants.append(entry)
                    variants.remove(entry)
        else:
            new_variants = new_variants + list(variants)

        # gsettings doesn't understand utf8
        new_variants = [str(variant) for variant in new_variants]

        return new_variants

    def call_setxkbmap(variants):
        kb_layouts = []
        kb_variants = []

        for entry in variants:
            fields = entry.split('\t')
            if len(fields) > 1:
                kb_layouts.append(fields[0])
                kb_variants.append(fields[1])
            else:
                kb_layouts.append(fields[0])
                kb_variants.append("")

        execute(
            "setxkbmap", "-layout", ",".join(kb_layouts),
            "-variant", ",".join(kb_variants))

    iso_639_3 = ElementTree.parse('/usr/share/xml/iso-codes/iso_639_3.xml')
    nodes = [element for element in iso_639_3.findall('iso_639_3_entry')
             if element.get('part1_code') == lang]
    display = GdkX11.x11_get_default_xdisplay()
    engine = Xkl.Engine.get_instance(display)
    if nodes:
        configreg = Xkl.ConfigRegistry.get_instance(engine)
        configreg.load(False)

        # Apparently part2_code doesn't always work (fails with French)
        for prop in ('part2_code', 'id', 'part1_code'):
            code = nodes[0].get(prop)
            if code is not None:
                configreg.foreach_language_variant(code, process_variant, None)
                if variants:
                    restricted_variants = restrict_list(variants)
                    call_setxkbmap(restricted_variants)
                    gsettings.set_list(
                        gsettings_key[0], gsettings_key[1],
                        restricted_variants)
                    break
        else:
            # Use the system default if no other keymaps can be determined.
            gsettings.set_list(gsettings_key[0], gsettings_key[1], [])

    engine.lock_group(0)
Example #4
0
def set_indicator_keymaps(lang):
    import xml.etree.cElementTree as ElementTree
    from gi.repository import Xkl, GdkX11
    # GdkX11.x11_get_default_xdisplay() segfaults if Gtk hasn't been
    # imported; possibly finer-grained than this, but anything using this
    # will already have imported Gtk anyway ...
    from gi.repository import Gtk
    from ubiquity import gsettings

    # pacify pyflakes
    Gtk

    gsettings_key = ['org.gnome.libgnomekbd.keyboard', 'layouts']
    gsettings_sources = ('org.gnome.desktop.input-sources', 'sources')
    gsettings_options = ('org.gnome.desktop.input-sources', 'xkb-options')
    lang = lang.split('_')[0]
    variants = []

    # Map inspired from that of gfxboot-theme-ubuntu that's itself
    # based on console-setup's. This one has been restricted to
    # language => keyboard layout not locale => keyboard layout as
    # we don't actually know the exact locale
    default_keymap = {
        'ar': 'ara',
        'bs': 'ba',
        'de': 'de',
        'el': 'gr',
        'en': 'us',
        'eo': 'epo',
        'fr': 'fr_oss',
        'gu': 'in_guj',
        'hi': 'in',
        'hr': 'hr',
        'hy': 'am',
        'ka': 'ge',
        'kn': 'in_kan',
        'lo': 'la',
        'ml': 'in_mal',
        'pa': 'in_guru',
        'sr': 'rs',
        'sv': 'se',
        'ta': 'in_tam',
        'te': 'in_tel',
        'zh': 'cn',
    }

    def item_str(s):
        '''Convert a zero-terminated byte array to a proper str'''
        import array
        s = array.array('B', s).tobytes()
        i = s.find(b'\x00')
        return s[:i].decode()

    def process_variant(*args):
        if hasattr(args[2], 'name'):
            variants.append('%s\t%s' %
                            (item_str(args[1].name), item_str(args[2].name)))
        else:
            variants.append(item_str(args[1].name))

    def restrict_list(variants):
        new_variants = []

        # Start by looking by an explicit default layout in the keymap
        if lang in default_keymap:
            if default_keymap[lang] in variants:
                variants.remove(default_keymap[lang])
                new_variants.append(default_keymap[lang])
            else:
                tab_keymap = default_keymap[lang].replace('_', '\t')
                if tab_keymap in variants:
                    variants.remove(tab_keymap)
                    new_variants.append(tab_keymap)

        # Prioritize the layout matching the language (if any)
        if lang in variants:
            variants.remove(lang)
            new_variants.append(lang)

        # Uniquify our list (just in case)
        variants = list(set(variants))

        if len(variants) > 4:
            # We have a problem, X only supports 4

            # Add as many entry as we can that are layouts without variant
            country_variants = sorted(entry for entry in variants
                                      if '\t' not in entry)
            for entry in country_variants[:4 - len(new_variants)]:
                new_variants.append(entry)
                variants.remove(entry)

            if len(new_variants) < 4:
                # We can add some more
                simple_variants = sorted(entry for entry in variants
                                         if '_' not in entry)
                for entry in simple_variants[:4 - len(new_variants)]:
                    new_variants.append(entry)
                    variants.remove(entry)

            if len(new_variants) < 4:
                # Now just add anything left
                for entry in variants[:4 - len(new_variants)]:
                    new_variants.append(entry)
                    variants.remove(entry)
        else:
            new_variants += list(variants)

        # gsettings doesn't understand utf8
        new_variants = [str(variant) for variant in new_variants]

        return new_variants

    def call_setxkbmap(variants):
        kb_layouts = []
        kb_variants = []

        for entry in variants:
            fields = entry.split('\t')
            if len(fields) > 1:
                kb_layouts.append(fields[0])
                kb_variants.append(fields[1])
            else:
                kb_layouts.append(fields[0])
                kb_variants.append("")

        execute("setxkbmap", "-layout", ",".join(kb_layouts), "-variant",
                ",".join(kb_variants))

    iso_639 = ElementTree.parse('/usr/share/xml/iso-codes/iso_639.xml')
    nodes = [
        element for element in iso_639.findall('iso_639_entry')
        if element.get('iso_639_1_code') == lang
    ]
    display = GdkX11.x11_get_default_xdisplay()
    engine = Xkl.Engine.get_instance(display)
    if nodes:
        configreg = Xkl.ConfigRegistry.get_instance(engine)
        configreg.load(False)

        # Apparently iso_639_2B_code doesn't always work (fails with French)
        for prop in ('iso_639_2B_code', 'iso_639_2T_code', 'iso_639_1_code'):
            code = nodes[0].get(prop)
            if code is not None:
                configreg.foreach_language_variant(code, process_variant, None)
                if variants:
                    restricted_variants = restrict_list(variants)
                    call_setxkbmap(restricted_variants)
                    gsettings.set_list(gsettings_key[0], gsettings_key[1],
                                       restricted_variants)
                    break
        else:
            # Use the system default if no other keymaps can be determined.
            gsettings.set_list(gsettings_key[0], gsettings_key[1], [])

        # Gnome Shell only does keyboard layout conversion from old
        # gsettings_key once. Recently we started to launch keyboard plugin
        # during ubiquity-dm, hence if we change that key, we should purge the
        # state that gsd uses, to determine if it should run the
        # conversion. Which are a stamp file, and having the new key set.
        # Ideally, I think ubiquity should be more universal and set the new key
        # directly, instead of relying on gsd keeping the conversion code
        # around. But it's too late for 20.10 release.
        gsettings_stamp = os.path.join(
            '/home', os.getenv("SUDO_USER", os.getenv("USER", "root")),
            '.local/share/gnome-settings-daemon/input-sources-converted')
        if os.path.exists(gsettings_stamp):
            os.remove(gsettings_stamp)
        gsettings.unset(*gsettings_sources)
        gsettings.unset(*gsettings_options)

    engine.lock_group(0)
Example #5
0
def set_indicator_keymaps(lang):
    import xml.etree.cElementTree as ElementTree
    from gi.repository import Xkl, GdkX11

    # GdkX11.x11_get_default_xdisplay() segfaults if Gtk hasn't been
    # imported; possibly finer-grained than this, but anything using this
    # will already have imported Gtk anyway ...
    from gi.repository import Gtk
    from ubiquity import gsettings

    # pacify pyflakes
    Gtk

    gsettings_key = ["org.gnome.libgnomekbd.keyboard", "layouts"]
    lang = lang.split("_")[0]
    variants = []

    # Map inspired from that of gfxboot-theme-ubuntu that's itself
    # based on console-setup's. This one has been restricted to
    # language => keyboard layout not locale => keyboard layout as
    # we don't actually know the exact locale
    default_keymap = {
        "ar": "ara",
        "bs": "ba",
        "de": "de",
        "el": "gr",
        "en": "us",
        "eo": "epo",
        "fr": "fr_oss",
        "gu": "in_guj",
        "hi": "in",
        "hr": "hr",
        "hy": "am",
        "ka": "ge",
        "kn": "in_kan",
        "lo": "la",
        "ml": "in_mal",
        "pa": "in_guru",
        "sr": "rs",
        "sv": "se",
        "ta": "in_tam",
        "te": "in_tel",
        "zh": "cn",
    }

    def item_str(s):
        """Convert a zero-terminated byte array to a proper str"""
        i = s.find(b"\x00")
        return s[:i].decode()

    def process_variant(*args):
        if hasattr(args[2], "name"):
            variants.append("%s\t%s" % (item_str(args[1].name), item_str(args[2].name)))
        else:
            variants.append(item_str(args[1].name))

    def restrict_list(variants):
        new_variants = []

        # Start by looking by an explicit default layout in the keymap
        if lang in default_keymap:
            if default_keymap[lang] in variants:
                variants.remove(default_keymap[lang])
                new_variants.append(default_keymap[lang])
            else:
                tab_keymap = default_keymap[lang].replace("_", "\t")
                if tab_keymap in variants:
                    variants.remove(tab_keymap)
                    new_variants.append(tab_keymap)

        # Prioritize the layout matching the language (if any)
        if lang in variants:
            variants.remove(lang)
            new_variants.append(lang)

        # Uniquify our list (just in case)
        variants = list(set(variants))

        if len(variants) > 4:
            # We have a problem, X only supports 4

            # Add as many entry as we can that are layouts without variant
            country_variants = sorted(entry for entry in variants if "\t" not in entry)
            for entry in country_variants[: 4 - len(new_variants)]:
                new_variants.append(entry)
                variants.remove(entry)

            if len(new_variants) < 4:
                # We can add some more
                simple_variants = sorted(entry for entry in variants if "_" not in entry)
                for entry in simple_variants[: 4 - len(new_variants)]:
                    new_variants.append(entry)
                    variants.remove(entry)

            if len(new_variants) < 4:
                # Now just add anything left
                for entry in variants[: 4 - len(new_variants)]:
                    new_variants.append(entry)
                    variants.remove(entry)
        else:
            new_variants += list(variants)

        # gsettings doesn't understand utf8
        new_variants = [str(variant) for variant in new_variants]

        return new_variants

    def call_setxkbmap(variants):
        kb_layouts = []
        kb_variants = []

        for entry in variants:
            fields = entry.split("\t")
            if len(fields) > 1:
                kb_layouts.append(fields[0])
                kb_variants.append(fields[1])
            else:
                kb_layouts.append(fields[0])
                kb_variants.append("")

        execute("setxkbmap", "-layout", ",".join(kb_layouts), "-variant", ",".join(kb_variants))

    iso_639_3 = ElementTree.parse("/usr/share/xml/iso-codes/iso_639_3.xml")
    nodes = [element for element in iso_639_3.findall("iso_639_3_entry") if element.get("part1_code") == lang]
    display = GdkX11.x11_get_default_xdisplay()
    engine = Xkl.Engine.get_instance(display)
    if nodes:
        configreg = Xkl.ConfigRegistry.get_instance(engine)
        configreg.load(False)

        # Apparently part2_code doesn't always work (fails with French)
        for prop in ("part2_code", "id", "part1_code"):
            code = nodes[0].get(prop)
            if code is not None:
                configreg.foreach_language_variant(code, process_variant, None)
                if variants:
                    restricted_variants = restrict_list(variants)
                    call_setxkbmap(restricted_variants)
                    gsettings.set_list(gsettings_key[0], gsettings_key[1], restricted_variants)
                    break
        else:
            # Use the system default if no other keymaps can be determined.
            gsettings.set_list(gsettings_key[0], gsettings_key[1], [])

    engine.lock_group(0)
Example #6
0
def set_indicator_keymaps(lang):
    import xml.etree.cElementTree as ElementTree
    from gi.repository import Xkl, GdkX11
    # GdkX11.x11_get_default_xdisplay() segfaults if Gtk hasn't been
    # imported; possibly finer-grained than this, but anything using this
    # will already have imported Gtk anyway ...
    from gi.repository import Gtk
    from ubiquity import gsettings

    # pacify pyflakes
    Gtk

    gsettings_key = ['org.gnome.libgnomekbd.keyboard', 'layouts']
    lang = lang.split('_')[0]
    variants = []

    # Map inspired from that of gfxboot-theme-ubuntu that's itself
    # based on console-setup's. This one has been restricted to
    # language => keyboard layout not locale => keyboard layout as
    # we don't actually know the exact locale
    default_keymap = {
        'ar': 'ara',
        'bs': 'ba',
        'de': 'de',
        'el': 'gr',
        'en': 'us',
        'eo': 'epo',
        'fr': 'fr_oss',
        'gu': 'in_guj',
        'hi': 'in',
        'hr': 'hr',
        'hy': 'am',
        'ka': 'ge',
        'kn': 'in_kan',
        'lo': 'la',
        'ml': 'in_mal',
        'pa': 'in_guru',
        'sr': 'rs',
        'sv': 'se',
        'ta': 'in_tam',
        'te': 'in_tel',
        'zh': 'cn',
    }

    def item_str(s):
        '''Convert a zero-terminated byte array to a proper str'''
        import array
        s = array.array('B', s).tostring()
        i = s.find(b'\x00')
        return s[:i].decode()

    def process_variant(*args):
        if hasattr(args[2], 'name'):
            variants.append(
                '%s\t%s' % (item_str(args[1].name), item_str(args[2].name)))
        else:
            variants.append(item_str(args[1].name))

    def restrict_list(variants):
        new_variants = []

        # Start by looking by an explicit default layout in the keymap
        if lang in default_keymap:
            if default_keymap[lang] in variants:
                variants.remove(default_keymap[lang])
                new_variants.append(default_keymap[lang])
            else:
                tab_keymap = default_keymap[lang].replace('_', '\t')
                if tab_keymap in variants:
                    variants.remove(tab_keymap)
                    new_variants.append(tab_keymap)

        # Prioritize the layout matching the language (if any)
        if lang in variants:
            variants.remove(lang)
            new_variants.append(lang)

        # Uniquify our list (just in case)
        variants = list(set(variants))

        if len(variants) > 4:
            # We have a problem, X only supports 4

            # Add as many entry as we can that are layouts without variant
            country_variants = sorted(
                entry for entry in variants if '\t' not in entry)
            for entry in country_variants[:4 - len(new_variants)]:
                new_variants.append(entry)
                variants.remove(entry)

            if len(new_variants) < 4:
                # We can add some more
                simple_variants = sorted(
                    entry for entry in variants if '_' not in entry)
                for entry in simple_variants[:4 - len(new_variants)]:
                    new_variants.append(entry)
                    variants.remove(entry)

            if len(new_variants) < 4:
                # Now just add anything left
                for entry in variants[:4 - len(new_variants)]:
                    new_variants.append(entry)
                    variants.remove(entry)
        else:
            new_variants += list(variants)

        # gsettings doesn't understand utf8
        new_variants = [str(variant) for variant in new_variants]

        #Hack pt1 added for Bio-Linux to prefer gb keyboard over us
        if new_variants[0] == "us" and new_variants[2] == "gb" :
            new_variants[0] = str("gb")
            new_variants[2] = str("us")
        #end hack

        return new_variants

    def call_setxkbmap(variants):
        kb_layouts = []
        kb_variants = []

        for entry in variants:
            fields = entry.split('\t')
            if len(fields) > 1:
                kb_layouts.append(fields[0])
                kb_variants.append(fields[1])
            else:
                kb_layouts.append(fields[0])
                kb_variants.append("")

        execute(
            "setxkbmap", "-layout", ",".join(kb_layouts),
            "-variant", ",".join(kb_variants))

        #Hack pt2 added for Bio-Linux to actually make the keyboard settings stick
        #in 14.04.
        #It seems the upstream authors have attempted to get this fixed, but missed
        #the point that we need to preserve the DBUS address variable, which is lost
        #when Ubiquity gains root privileges.
        # os.environ['DBUS_SESSION_BUS_ADDRESS'] = "unix:abstract=/tmp/dbus-FaqRsE1MGY"
        #I tried signalling the keyboard indicator with "pkill -USR1", but that just
        #locks up the whole system.  Meh, so frickin fragile.  Hence this appalling
        #kludge instead.
        user = os.environ.get('PKEXEC_UID')
        user = '******' + user if user else '#999'

        try:
            if not os.environ.get('DBUS_SESSION_BUS_ADDRESS') :
                proc1 = subprocess.Popen('ps -p %i -o ppid=' % os.getppid(), shell=True, 
                                         stdout=subprocess.PIPE, )
                pppid = int(proc1.communicate()[0].rstrip())
                proc2 = subprocess.Popen('sudo -u "%s" cat /proc/%i/environ' % (user, pppid), 
                                         shell=True, stdout=subprocess.PIPE, )
                os.environ['DBUS_SESSION_BUS_ADDRESS'] = [ 
                       x for x in proc2.communicate()[0].decode().split('\0') 
                       if x.startswith("DBUS_SESSION_BUS_ADDRESS=") 
                       ][0][25:]
        except:
            os.environ['DBUS_SESSION_BUS_ADDRESS'] = 'none'

        subprocess.call(
          ['sudo', '-E', '-u', user, 'gsettings', 'set',
           "org.gnome.desktop.input-sources", "sources",
           repr( [('xkb', l+'+'+v if v else l) for l,v in zip(kb_layouts, kb_variants)] )
          ],
        preexec_fn=drop_all_privileges )
        #subprocess.call(['sudo', '-u', user, 'pkill', '-USR1', 'indicator-keybo'])
        #end hack 

    iso_639 = ElementTree.parse('/usr/share/xml/iso-codes/iso_639.xml')
    nodes = [element for element in iso_639.findall('iso_639_entry')
             if element.get('iso_639_1_code') == lang]
    display = GdkX11.x11_get_default_xdisplay()
    engine = Xkl.Engine.get_instance(display)
    if nodes:
        configreg = Xkl.ConfigRegistry.get_instance(engine)
        configreg.load(False)

        # Apparently iso_639_2B_code doesn't always work (fails with French)
        for prop in ('iso_639_2B_code', 'iso_639_2T_code', 'iso_639_1_code'):
            code = nodes[0].get(prop)
            if code is not None:
                configreg.foreach_language_variant(code, process_variant, None)
                if variants:
                    restricted_variants = restrict_list(variants)
                    call_setxkbmap(restricted_variants)
                    gsettings.set_list(
                        gsettings_key[0], gsettings_key[1],
                        restricted_variants)
                    break
        else:
            # Use the system default if no other keymaps can be determined.
            gsettings.set_list(gsettings_key[0], gsettings_key[1], [])

    engine.lock_group(0)
Example #7
0
def set_indicator_keymaps(lang):
    import xml.etree.cElementTree as ElementTree
    from gi.repository import Xkl, GdkX11
    # GdkX11.x11_get_default_xdisplay() segfaults if Gtk hasn't been
    # imported; possibly finer-grained than this, but anything using this
    # will already have imported Gtk anyway ...
    from gi.repository import Gtk
    from ubiquity import gsettings

    # pacify pyflakes
    Gtk

    gsettings_key = ['org.gnome.libgnomekbd.keyboard', 'layouts']
    lang = lang.split('_')[0]
    variants = []

    # Map inspired from that of gfxboot-theme-ubuntu that's itself
    # based on console-setup's. This one has been restricted to
    # language => keyboard layout not locale => keyboard layout as
    # we don't actually know the exact locale
    default_keymap = {
        'ar': 'ara',
        'bs': 'ba',
        'de': 'de',
        'el': 'gr',
        'en': 'us',
        'eo': 'epo',
        'fr': 'fr_oss',
        'gu': 'in_guj',
        'hi': 'in',
        'hr': 'hr',
        'hy': 'am',
        'ka': 'ge',
        'kn': 'in_kan',
        'lo': 'la',
        'ml': 'in_mal',
        'pa': 'in_guru',
        'sr': 'rs',
        'sv': 'se',
        'ta': 'in_tam',
        'te': 'in_tel',
        'zh': 'cn',
    }

    def item_str(s):
        '''Convert a zero-terminated byte array to a proper str'''
        import array
        s = array.array('B', s).tostring()
        i = s.find(b'\x00')
        return s[:i].decode()

    def process_variant(*args):
        if hasattr(args[2], 'name'):
            variants.append('%s\t%s' %
                            (item_str(args[1].name), item_str(args[2].name)))
        else:
            variants.append(item_str(args[1].name))

    def restrict_list(variants):
        new_variants = []

        # Start by looking by an explicit default layout in the keymap
        if lang in default_keymap:
            if default_keymap[lang] in variants:
                variants.remove(default_keymap[lang])
                new_variants.append(default_keymap[lang])
            else:
                tab_keymap = default_keymap[lang].replace('_', '\t')
                if tab_keymap in variants:
                    variants.remove(tab_keymap)
                    new_variants.append(tab_keymap)

        # Prioritize the layout matching the language (if any)
        if lang in variants:
            variants.remove(lang)
            new_variants.append(lang)

        # Uniquify our list (just in case)
        variants = list(set(variants))

        if len(variants) > 4:
            # We have a problem, X only supports 4

            # Add as many entry as we can that are layouts without variant
            country_variants = sorted(entry for entry in variants
                                      if '\t' not in entry)
            for entry in country_variants[:4 - len(new_variants)]:
                new_variants.append(entry)
                variants.remove(entry)

            if len(new_variants) < 4:
                # We can add some more
                simple_variants = sorted(entry for entry in variants
                                         if '_' not in entry)
                for entry in simple_variants[:4 - len(new_variants)]:
                    new_variants.append(entry)
                    variants.remove(entry)

            if len(new_variants) < 4:
                # Now just add anything left
                for entry in variants[:4 - len(new_variants)]:
                    new_variants.append(entry)
                    variants.remove(entry)
        else:
            new_variants += list(variants)

        # gsettings doesn't understand utf8
        new_variants = [str(variant) for variant in new_variants]

        #Hack pt1 added for Bio-Linux to prefer gb keyboard over us
        if new_variants[0] == "us" and new_variants[2] == "gb":
            new_variants[0] = str("gb")
            new_variants[2] = str("us")
        #end hack

        return new_variants

    def call_setxkbmap(variants):
        kb_layouts = []
        kb_variants = []

        for entry in variants:
            fields = entry.split('\t')
            if len(fields) > 1:
                kb_layouts.append(fields[0])
                kb_variants.append(fields[1])
            else:
                kb_layouts.append(fields[0])
                kb_variants.append("")

        execute("setxkbmap", "-layout", ",".join(kb_layouts), "-variant",
                ",".join(kb_variants))

        #Hack pt2 added for Bio-Linux to actually make the keyboard settings stick
        #in 14.04.
        #It seems the upstream authors have attempted to get this fixed, but missed
        #the point that we need to preserve the DBUS address variable, which is lost
        #when Ubiquity gains root privileges.
        # os.environ['DBUS_SESSION_BUS_ADDRESS'] = "unix:abstract=/tmp/dbus-FaqRsE1MGY"
        #I tried signalling the keyboard indicator with "pkill -USR1", but that just
        #locks up the whole system.  Meh, so frickin fragile.  Hence this appalling
        #kludge instead.
        user = os.environ.get('PKEXEC_UID')
        user = '******' + user if user else '#999'

        try:
            if not os.environ.get('DBUS_SESSION_BUS_ADDRESS'):
                proc1 = subprocess.Popen(
                    'ps -p %i -o ppid=' % os.getppid(),
                    shell=True,
                    stdout=subprocess.PIPE,
                )
                pppid = int(proc1.communicate()[0].rstrip())
                proc2 = subprocess.Popen(
                    'sudo -u "%s" cat /proc/%i/environ' % (user, pppid),
                    shell=True,
                    stdout=subprocess.PIPE,
                )
                os.environ['DBUS_SESSION_BUS_ADDRESS'] = [
                    x for x in proc2.communicate()[0].decode().split('\0')
                    if x.startswith("DBUS_SESSION_BUS_ADDRESS=")
                ][0][25:]
        except:
            os.environ['DBUS_SESSION_BUS_ADDRESS'] = 'none'

        subprocess.call([
            'sudo', '-E', '-u', user, 'gsettings', 'set',
            "org.gnome.desktop.input-sources", "sources",
            repr([('xkb', l + '+' + v if v else l)
                  for l, v in zip(kb_layouts, kb_variants)])
        ],
                        preexec_fn=drop_all_privileges)
        #subprocess.call(['sudo', '-u', user, 'pkill', '-USR1', 'indicator-keybo'])
        #end hack

    iso_639 = ElementTree.parse('/usr/share/xml/iso-codes/iso_639.xml')
    nodes = [
        element for element in iso_639.findall('iso_639_entry')
        if element.get('iso_639_1_code') == lang
    ]
    display = GdkX11.x11_get_default_xdisplay()
    engine = Xkl.Engine.get_instance(display)
    if nodes:
        configreg = Xkl.ConfigRegistry.get_instance(engine)
        configreg.load(False)

        # Apparently iso_639_2B_code doesn't always work (fails with French)
        for prop in ('iso_639_2B_code', 'iso_639_2T_code', 'iso_639_1_code'):
            code = nodes[0].get(prop)
            if code is not None:
                configreg.foreach_language_variant(code, process_variant, None)
                if variants:
                    restricted_variants = restrict_list(variants)
                    call_setxkbmap(restricted_variants)
                    gsettings.set_list(gsettings_key[0], gsettings_key[1],
                                       restricted_variants)
                    break
        else:
            # Use the system default if no other keymaps can be determined.
            gsettings.set_list(gsettings_key[0], gsettings_key[1], [])

    engine.lock_group(0)