From d5277646dbe9a88d32c42187c9c3701a7c57a469 Mon Sep 17 00:00:00 2001 From: Mike Gabriel Date: Thu, 26 Oct 2017 19:17:41 +0200 Subject: Fork from Ubuntu's indicator-keyboard. --- src/source.vala | 487 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 487 insertions(+) create mode 100644 src/source.vala (limited to 'src/source.vala') diff --git a/src/source.vala b/src/source.vala new file mode 100644 index 00000000..b7d7a971 --- /dev/null +++ b/src/source.vala @@ -0,0 +1,487 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: William Hua + */ + +public class Indicator.Keyboard.Source : Object { + + private static Gnome.XkbInfo? xkb_info; + private static IBus.Bus? ibus_bus; + private static Fcitx.InputMethod? fcitx_proxy; + + private string? xkb; + private string? ibus; + private string? fcitx; + + private string? _name; + private string? _short_name; + private string? _layout; + private string? _variant; + private Icon? _icon; + private uint _subscript; + private bool _show_subscript; + private bool _use_gtk; + + public string? name { + get { if (_name == null) { _name = _get_name (); } return _name; } + } + + public string? short_name { + get { if (_short_name == null) { _short_name = _get_short_name (); } return _short_name; } + } + + public string? layout { + get { if (_layout == null) { _layout = _get_layout (); } return _layout; } + } + + public string? variant { + get { if (_variant == null) { _variant = _get_variant (); } return _variant; } + } + + public Icon? icon { + get { if (_icon == null) { _icon = _get_icon (); } return _icon; } + set { _icon = value; } + } + + public uint subscript { + get { return _subscript; } + set { _subscript = value; icon = null; } + } + + public bool show_subscript { + get { return _show_subscript; } + set { _show_subscript = value; icon = null; } + } + + public bool use_gtk { + get { return _use_gtk; } + construct set { _use_gtk = value; icon = null; } + } + + public bool is_xkb { + get { return xkb != null; } + } + + public bool is_ibus { + get { return ibus != null; } + } + + public bool is_fcitx { + get { return fcitx != null; } + } + + public Source (Variant variant, bool use_gtk = false) { + Object (use_gtk: use_gtk); + + if (variant.is_of_type (new VariantType ("(ss)"))) { + unowned string type; + unowned string name; + + variant.get ("(&s&s)", out type, out name); + + if (type == "xkb") { + xkb = name; + } else if (type == "ibus") { + ibus = name; + } else if (type == "fcitx") { + fcitx = name; + } + } else if (variant.is_of_type (new VariantType ("a{ss}"))) { + foreach (var pair in variant) { + unowned string key; + unowned string value; + + ((!) pair).get ("{&s&s}", out key, out value); + + if (key == "xkb") { + xkb = value; + } else if (key == "ibus") { + ibus = value; + } else if (key == "fcitx") { + fcitx = value; + } + } + } + } + + private static Gnome.XkbInfo get_xkb_info () { + if (xkb_info == null) { + xkb_info = new Gnome.XkbInfo (); + } + + return (!) xkb_info; + } + + private static IBus.Bus get_ibus_bus () { + if (ibus_bus == null) { + IBus.init (); + ibus_bus = new IBus.Bus (); + } + + return (!) ibus_bus; + } + + private static Fcitx.InputMethod get_fcitx_proxy () throws Error { + if (fcitx_proxy == null) { + fcitx_proxy = new Fcitx.InputMethod (BusType.SESSION, DBusProxyFlags.NONE, 0); + } + + return (!) fcitx_proxy; + } + + private IBus.EngineDesc? get_engine () { + IBus.EngineDesc? engine = null; + + if (ibus != null) { + var names = new string[2]; + names[0] = (!) ibus; + + var engines = get_ibus_bus ().get_engines_by_names (names); + + if (engines.length > 0) { + engine = engines[0]; + } + } + + return engine; + } + + protected virtual string? _get_name () { + string? name = null; + + if (xkb != null) { + string? display_name = null; + string? layout = null; + + get_xkb_info ().get_layout_info ((!) xkb, out display_name, null, out layout, null); + + var has_display_name = display_name != null && ((!) display_name).get_char () != '\0'; + var has_layout = layout != null && ((!) layout).get_char () != '\0'; + + if (has_display_name) { + name = display_name; + } else if (has_layout) { + string? language = Xkl.get_language_name ((!) layout); + string? country = Xkl.get_country_name ((!) layout); + var has_language = language != null && ((!) language).get_char () != '\0'; + var has_country = country != null && ((!) country).get_char () != '\0'; + + if (has_language && has_country) { + name = @"$((!) language) ($((!) country))"; + } else if (has_language) { + name = language; + } else if (has_country) { + name = country; + } + } + + if (name == null || ((!) name).get_char () == '\0') { + name = xkb; + } + } else if (ibus != null) { + var engine = get_engine (); + + if (engine != null) { + string? language = ((!) engine).get_language (); + string? display_name = ((!) engine).get_longname (); + var has_language = language != null && ((!) language).get_char () != '\0'; + var has_display_name = display_name != null && ((!) display_name).get_char () != '\0'; + + if (has_language) { + language = Xkl.get_language_name ((!) language); + has_language = language != null && ((!) language).get_char () != '\0'; + } + + if (has_language && has_display_name) { + name = @"$((!) language) ($((!) display_name))"; + } else if (has_language) { + name = language; + } else if (has_display_name) { + name = display_name; + } + } + + if (name == null || ((!) name).get_char () == '\0') { + name = ibus; + } + } else if (fcitx != null) { + try { + var input_methods = get_fcitx_proxy ().get_imlist_nofree (); + + for (var i = 0; i < input_methods.length; i++) { + if (input_methods.get (i).unique_name == (!) fcitx) { + name = input_methods.get (i).name; + break; + } + } + } catch (Error error) { + warning ("error: %s", error.message); + } + + if (name == null || ((!) name).get_char () == '\0') { + name = fcitx; + } + } + + return name; + } + + protected virtual string? _get_short_name () { + string? short_name = null; + + if (xkb != null) { + get_xkb_info ().get_layout_info ((!) xkb, null, out short_name, null, null); + + if (short_name == null || ((!) short_name).get_char () == '\0') { + short_name = xkb; + } + } else if (ibus != null) { + var engine = get_engine (); + + if (engine != null) { + short_name = ((!) engine).get_name (); + } + + if (short_name == null || ((!) short_name).get_char () == '\0') { + short_name = ibus; + } + } else if (fcitx != null) { + try { + var input_methods = get_fcitx_proxy ().get_imlist_nofree (); + + for (var i = 0; i < input_methods.length; i++) { + if (input_methods.get (i).unique_name == (!) fcitx) { + short_name = input_methods.get (i).langcode; + break; + } + } + } catch (Error error) { + warning ("error: %s", error.message); + } + + if (short_name == null || ((!) short_name).get_char () == '\0') { + short_name = fcitx; + } + } + + return abbreviate (short_name); + } + + protected virtual string? _get_layout () { + string? layout = null; + + if (xkb != null) { + get_xkb_info ().get_layout_info ((!) xkb, null, null, out layout, null); + } + + var has_layout = layout != null && ((!) layout).get_char () != '\0'; + + if (!has_layout) { + var engine = get_engine (); + + if (engine != null) { + layout = ((!) engine).get_layout (); + } + } + + if (layout == null || ((!) layout).get_char () == '\0') { + layout = xkb; + } + + return layout; + } + + protected virtual string? _get_variant () { + string? variant = null; + + if (xkb != null) { + get_xkb_info ().get_layout_info ((!) xkb, null, null, null, out variant); + } + + var has_variant = variant != null && ((!) variant).get_char () != '\0'; + + if (!has_variant) { + var engine = get_engine (); + + if (engine != null) { + variant = ((!) engine).get_layout_variant (); + } + } + + if (variant == null || ((!) variant).get_char () == '\0') { + variant = null; + } + + return variant; + } + + private Gtk.StyleContext? get_style_context () { + Gtk.StyleContext? context = null; + + if (_use_gtk) { + Gdk.Screen? screen = Gdk.Screen.get_default (); + + if (screen != null) { + var style_context = new Gtk.StyleContext (); + style_context.set_screen ((!) screen); + + var path = new Gtk.WidgetPath (); + path.append_type (typeof (Gtk.MenuItem)); + style_context.set_path (path); + + context = style_context; + } + } + + return context; + } + + protected virtual Icon? create_icon () { + Icon? icon = null; + + var style = get_style_context (); + + if (style != null) { + const int W = 22; + const int H = 22; + const int w = 20; + const int h = 20; + const double R = 2.0; + const double TEXT_SIZE = 12.0; + const double SUBSCRIPT_SIZE = 8.0; + + Pango.FontDescription description; + var colour = ((!) style).get_color (Gtk.StateFlags.NORMAL); + colour = { 0.5, 0.5, 0.5, 1.0 }; + ((!) style).get (Gtk.StateFlags.NORMAL, Gtk.STYLE_PROPERTY_FONT, out description); + + var surface = new Cairo.ImageSurface (Cairo.Format.ARGB32, W, H); + var context = new Cairo.Context (surface); + + context.translate (0.5 * (W - w), 0.5 * (H - h)); + + context.new_sub_path (); + context.arc (R, R, R, Math.PI, -0.5 * Math.PI); + context.arc (w - R, R, R, -0.5 * Math.PI, 0); + context.arc (w - R, h - R, R, 0, 0.5 * Math.PI); + context.arc (R, h - R, R, 0.5 * Math.PI, Math.PI); + context.close_path (); + + context.set_source_rgba (colour.red, colour.green, colour.blue, colour.alpha); + context.fill (); + context.set_operator (Cairo.Operator.CLEAR); + + if (short_name != null) { + var text_layout = Pango.cairo_create_layout (context); + text_layout.set_alignment (Pango.Alignment.CENTER); + description.set_absolute_size (Pango.units_from_double (TEXT_SIZE)); + text_layout.set_font_description (description); + text_layout.set_text ((!) short_name, -1); + Pango.cairo_update_layout (context, text_layout); + int text_width; + int text_height; + text_layout.get_pixel_size (out text_width, out text_height); + + if (_show_subscript) { + var subscript_layout = Pango.cairo_create_layout (context); + subscript_layout.set_alignment (Pango.Alignment.CENTER); + description.set_absolute_size (Pango.units_from_double (SUBSCRIPT_SIZE)); + subscript_layout.set_font_description (description); + subscript_layout.set_text (@"$_subscript", -1); + Pango.cairo_update_layout (context, subscript_layout); + int subscript_width; + int subscript_height; + subscript_layout.get_pixel_size (out subscript_width, out subscript_height); + + context.save (); + context.translate ((w - (text_width + subscript_width)) / 2, (h - text_height) / 2); + Pango.cairo_layout_path (context, text_layout); + context.fill (); + context.restore (); + + context.save (); + context.translate ((w + (text_width - subscript_width)) / 2, (h + text_height) / 2 - subscript_height); + Pango.cairo_layout_path (context, subscript_layout); + context.fill (); + context.restore (); + } else { + context.save (); + context.translate ((w - text_width) / 2, (h - text_height) / 2); + Pango.cairo_layout_path (context, text_layout); + context.fill (); + context.restore (); + } + } + + var buffer = new ByteArray (); + + surface.write_to_png_stream ((data) => { + buffer.append (data); + return Cairo.Status.SUCCESS; + }); + + icon = new BytesIcon (ByteArray.free_to_bytes ((owned) buffer)); + } + + return icon; + } + + private Icon? _get_icon () { + Icon? icon = null; + + var engine = get_engine (); + + if (engine != null) { + string? icon_name = ((!) engine).get_icon (); + var has_icon_name = icon_name != null && ((!) icon_name).get_char () != '\0'; + + if (has_icon_name) { + try { + icon = Icon.new_for_string ((!) icon_name); + } catch (Error error) { + warning ("error: %s", error.message); + } + } + } + + if (icon == null && short_name != null) { + string icon_name; + + if (_show_subscript) { + icon_name = @"indicator-keyboard-$((!) short_name)-$_subscript"; + } else { + icon_name = @"indicator-keyboard-$((!) short_name)"; + } + + if (_use_gtk) { + var icon_theme = Gtk.IconTheme.get_default (); + Gtk.IconInfo? icon_info = icon_theme.lookup_icon (icon_name, 22, 0); + + if (icon_info != null) { + icon = new ThemedIcon (icon_name); + } + } else { + icon = new ThemedIcon (icon_name); + } + } + + if (icon == null) { + icon = create_icon (); + } + + return icon; + } +} -- cgit v1.2.3