From cb93cab84beea2074502b04580d33e51587da83e Mon Sep 17 00:00:00 2001 From: fujiwarat Date: Thu, 9 Apr 2015 15:20:56 +0900 Subject: ibus-ui-gtk3: Support language icon in KDE5. TEST=ui/gtk3/ibus-ui-gtk3 Review URL: https://codereview.appspot.com/229740043 --- ui/gtk3/indicator.vala | 69 +++++++++++++++++++++++++++++++++++++++++++ ui/gtk3/notification-item.xml | 6 ++++ ui/gtk3/panel.vala | 53 ++++++++++++++++++++++++++------- 3 files changed, 117 insertions(+), 11 deletions(-) diff --git a/ui/gtk3/indicator.vala b/ui/gtk3/indicator.vala index 013b1c48..77a84ade 100644 --- a/ui/gtk3/indicator.vala +++ b/ui/gtk3/indicator.vala @@ -44,6 +44,7 @@ class Indicator : IBus.Service public string label_s { get; set; } public string label_guide_s { get; set; } public uint32 ordering_index { get; set; } + public GLib.Variant icon_vector { get; set; } public enum Category { APPLICATION_STATUS, @@ -234,6 +235,10 @@ class Indicator : IBus.Service return new GLib.Variant.string(this.icon_name); } + private GLib.Variant _get_icon_vector(GLib.DBusConnection connection) { + return this.icon_vector; + } + private GLib.Variant _get_icon_desc(GLib.DBusConnection connection) { return new GLib.Variant.string(this.icon_desc); } @@ -318,6 +323,8 @@ class Indicator : IBus.Service return _get_status(connection); if (property_name == "IconName") return _get_icon_name(connection); + if (property_name == "IconPixmap") + return _get_icon_vector(connection); if (property_name == "IconAccessibleDesc") return _get_icon_desc(connection); if (property_name == "AttentionIconName") @@ -359,6 +366,12 @@ class Indicator : IBus.Service if (this.status_s == status_s) return; this.status_s = status_s; + + /* This API does not require (this.connection != null) + * because service_get_property() can be called when + * this.connection emits the "NewStatus" signal or + * or m_proxy calls the "RegisterStatusNotifierItem" signal. + */ if (this.connection == null) return; try { @@ -377,6 +390,7 @@ class Indicator : IBus.Service bool changed = false; if (this.icon_name != icon_name) { this.icon_name = icon_name; + this.icon_vector = null; changed = true; } if (this.icon_desc != icon_desc) { @@ -385,6 +399,61 @@ class Indicator : IBus.Service } if (!changed) return; + + /* This API does not require (this.connection != null) + * because service_get_property() can be called when + * this.connection emits the "NewIcon" signal or + * or m_proxy calls the "RegisterStatusNotifierItem" signal. + */ + if (this.connection == null) + return; + try { + this.connection.emit_signal(null, + this.object_path, + NOTIFICATION_ITEM_DBUS_IFACE, + "NewIcon", + null); + } catch(GLib.Error e) { + warning("Unable to send signal for NewIcon: %s", e.message); + } + } + + public void set_cairo_image_surface_full(Cairo.ImageSurface image, + string? icon_desc) { + int width = image.get_width(); + int height = image.get_height(); + int stride = image.get_stride(); + unowned uint[] data = (uint[]) image.get_data(); + int length = stride * height / (int) sizeof(uint); + if (GLib.BYTE_ORDER == GLib.ByteOrder.LITTLE_ENDIAN) { + for (int i = 0; i < length; i++) + data[i] = data[i].to_big_endian(); + } + unowned uint8[] data8 = (uint8[]) data; + data8.length = stride * height; + GLib.Bytes bytes = new GLib.Bytes(data8); + GLib.Variant bs = + new GLib.Variant.from_bytes(GLib.VariantType.BYTESTRING, + bytes, + true); + GLib.VariantBuilder builder = new GLib.VariantBuilder( + new GLib.VariantType("a(iiay)")); + builder.open(new GLib.VariantType("(iiay)")); + builder.add("i", width); + builder.add("i", height); + builder.add_value(bs); + builder.close(); + this.icon_vector = new GLib.Variant("a(iiay)", builder); + this.icon_name = ""; + + if (this.icon_desc != icon_desc) + this.icon_desc = icon_desc; + + /* This API does not require (this.connection != null) + * because service_get_property() can be called when + * this.connection emits the "NewIcon" signal or + * or m_proxy calls the "RegisterStatusNotifierItem" signal. + */ if (this.connection == null) return; try { diff --git a/ui/gtk3/notification-item.xml b/ui/gtk3/notification-item.xml index aecb8d9b..6fde3d3e 100644 --- a/ui/gtk3/notification-item.xml +++ b/ui/gtk3/notification-item.xml @@ -7,6 +7,12 @@ + + + + diff --git a/ui/gtk3/panel.vala b/ui/gtk3/panel.vala index c77bd2f7..748ceb4e 100644 --- a/ui/gtk3/panel.vala +++ b/ui/gtk3/panel.vala @@ -72,6 +72,9 @@ class Panel : IBus.PanelService { private GLib.HashTable m_xkb_icon_pixbufs = new GLib.HashTable(GLib.str_hash, GLib.str_equal); + private GLib.HashTable m_xkb_icon_image = + new GLib.HashTable(GLib.str_hash, + GLib.str_equal); private Gdk.RGBA m_xkb_icon_rgba = Gdk.RGBA(){ red = 0.0, green = 0.0, blue = 0.0, alpha = 1.0 }; private XKBLayout m_xkblayout = new XKBLayout(); @@ -649,13 +652,17 @@ class Panel : IBus.PanelService { } else m_xkb_icon_rgba = rgba; - if (m_xkb_icon_pixbufs.size() > 0) { - m_xkb_icon_pixbufs.remove_all(); + if (m_icon_type == IconType.STATUS_ICON) { + if (m_xkb_icon_pixbufs.size() > 0) { + m_xkb_icon_pixbufs.remove_all(); - if (m_icon_type == IconType.STATUS_ICON) { if (m_status_icon != null && m_switcher != null) state_changed(); - } else if (m_icon_type == IconType.INDICATOR) { + } + } else if (m_icon_type == IconType.INDICATOR) { + if (m_xkb_icon_image.size() > 0) { + m_xkb_icon_image.remove_all(); + if (m_indicator != null && m_switcher != null) state_changed(); } @@ -962,13 +969,18 @@ class Panel : IBus.PanelService { Pango.cairo_show_layout(cr, layout); } - private Gdk.Pixbuf create_icon_pixbuf_with_string(string symbol) { - Gdk.Pixbuf pixbuf = m_xkb_icon_pixbufs[symbol]; + private Cairo.ImageSurface + create_cairo_image_surface_with_string(string symbol, bool cache) { + Cairo.ImageSurface image = null; - if (pixbuf != null) - return pixbuf; + if (cache) { + image = m_xkb_icon_image[symbol]; - var image = new Cairo.ImageSurface(Cairo.Format.ARGB32, 48, 48); + if (image != null) + return image; + } + + image = new Cairo.ImageSurface(Cairo.Format.ARGB32, 48, 48); var cr = new Cairo.Context(image); int width = image.get_width(); int height = image.get_height(); @@ -978,6 +990,23 @@ class Panel : IBus.PanelService { cr.paint(); cr.set_operator(Cairo.Operator.OVER); context_render_string(cr, symbol, width, height); + image.flush(); + + if (cache) + m_xkb_icon_image.insert(symbol, image); + + return image; + } + + private Gdk.Pixbuf create_icon_pixbuf_with_string(string symbol) { + Gdk.Pixbuf pixbuf = m_xkb_icon_pixbufs[symbol]; + + if (pixbuf != null) + return pixbuf; + + var image = create_cairo_image_surface_with_string(symbol, false); + int width = image.get_width(); + int height = image.get_height(); pixbuf = Gdk.pixbuf_get_from_surface(image, 0, 0, width, height); m_xkb_icon_pixbufs.insert(symbol, pixbuf); return pixbuf; @@ -1274,8 +1303,10 @@ class Panel : IBus.PanelService { m_status_icon.set_from_pixbuf(pixbuf); } else if (m_icon_type == IconType.INDICATOR) { - /* Appindicator does not support pixbuf. */ - m_indicator.set_icon_full(icon_name, ""); + Cairo.ImageSurface image = + create_cairo_image_surface_with_string(language, + true); + m_indicator.set_cairo_image_surface_full(image, ""); } } else { var theme = Gtk.IconTheme.get_default(); -- cgit v1.2.1