1 /* vim:set et sts=4 sw=4:
5 * Copyright(c) 2011 Peng Huang <shawn.p.huang@gmail.com>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or(at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this program; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20 * Boston, MA 02111-1307 USA
27 class Panel : IBus.PanelService {
28 private IBus.Bus m_bus;
29 private IBus.Config m_config;
30 private Gtk.StatusIcon m_status_icon;
31 private Gtk.Menu m_ime_menu;
32 private IBus.EngineDesc[] m_engines;
33 private CandidatePanel m_candidate_panel;
34 private Switcher m_switcher;
35 private PropertyManager m_property_manager;
36 private IBus.InputContext m_input_context;
38 public Panel(IBus.Bus bus) {
39 assert(bus.is_connected());
40 // Chain up base class constructor
41 GLib.Object(connection : bus.get_connection(),
42 object_path : "/org/freedesktop/IBus/Panel");
46 m_config = bus.get_config();
49 m_status_icon = new Gtk.StatusIcon();
50 m_status_icon.set_name("ibus-ui-gtk");
51 m_status_icon.set_title("IBus Panel");
52 m_status_icon.popup_menu.connect(status_icon_popup_menu);
53 m_status_icon.activate.connect(status_icon_activate);
54 m_status_icon.set_from_icon_name("ibus-keyboard");
56 m_candidate_panel = new CandidatePanel();
58 m_candidate_panel.hide();
59 m_candidate_panel.show();
63 m_switcher = new Switcher();
65 KeybindingManager.get_instance().bind("<Control>space", (e) => {
66 handle_engine_switch(e, false);
69 KeybindingManager.get_instance().bind("<Control><Shift>space", (e) => {
70 handle_engine_switch(e, true);
73 m_property_manager = new PropertyManager();
74 m_property_manager.property_activate.connect((k, s) => {
75 if (m_input_context != null)
76 m_input_context.property_activate(k, s);
80 private void switch_engine(int i) {
81 // debug("switch_engine i = %d", i);
82 assert(i >= 0 && i < m_engines.length);
88 // Move the target engine to the first place.
89 IBus.EngineDesc engine = m_engines[i];
90 for (int j = i; j > 0; j--) {
91 m_engines[j] = m_engines[j - 1];
93 m_engines[0] = engine;
95 if (!m_bus.set_global_engine(engine.get_name())) {
96 warning("Switch engine to %s failed.", engine.get_name());
100 string cmdline = "setxkbmap %s".printf(engine.get_layout());
102 if (!GLib.Process.spawn_command_line_sync(cmdline)) {
103 warning("Switch xkb layout to %s failed.",
104 engine.get_layout());
106 } catch (GLib.SpawnError e) {
107 warning("execute setxkblayout failed");
111 private void handle_engine_switch(Gdk.Event event, bool revert) {
112 if (!KeybindingManager.primary_modifier_still_pressed(event)) {
113 int i = revert ? m_engines.length - 1 : 1;
116 int i = revert ? m_engines.length - 1 : 1;
117 i = m_switcher.run(event, m_engines, i);
119 debug("switch cancelled");
121 assert(i < m_engines.length);
127 private void update_engines() {
128 Variant variant = m_config.get_value("general", "preload_engines");
129 string[] engine_names;
132 engine_names = variant.dup_strv();
134 engine_names = {"xkb:layout:us", "pinyin", "anthy"};
136 m_engines = m_bus.get_engines_by_names(engine_names);
139 private void status_icon_popup_menu(Gtk.StatusIcon status_icon,
141 uint activate_time) {
142 Gtk.Menu menu = m_property_manager.get_menu();
147 menu.set_take_focus(false);
151 m_status_icon.position_menu,
153 Gtk.get_current_event_time());
156 private void status_icon_activate(Gtk.StatusIcon status_icon) {
158 Gtk.icon_size_lookup(Gtk.IconSize.MENU, out width, out height);
159 if (m_ime_menu == null) {
160 m_ime_menu = new Gtk.Menu();
161 foreach (var engine in m_engines) {
162 var lang = engine.get_language();
163 var name = engine.get_name();
164 var item = new Gtk.ImageMenuItem.with_label(lang + " - " + name);
165 if (engine.get_icon() != "") {
166 var icon = new IconWidget(engine.get_icon(), width);
167 item.set_image(icon);
169 // Make a copy of engine to workaround a bug in vala.
170 // https://bugzilla.gnome.org/show_bug.cgi?id=628336
172 item.activate.connect((item) => {
173 for (int i = 0; i < m_engines.length; i++) {
174 if (e == m_engines[i]) {
180 m_ime_menu.add(item);
182 m_ime_menu.show_all();
183 m_ime_menu.set_take_focus(false);
185 m_ime_menu.popup(null,
187 m_status_icon.position_menu,
189 Gtk.get_current_event_time());
192 /* override virtual functions */
193 public override void set_cursor_location(int x, int y,
194 int width, int height) {
195 m_candidate_panel.set_cursor_location(x, y, width, height);
198 public override void focus_in(string input_context_path) {
200 GLib.Cancellable cancellable = null;
202 new IBus.InputContext(input_context_path,
203 m_bus.get_connection(),
205 } catch (GLib.Error e) {
210 public override void focus_out(string input_context_path) {
211 m_input_context = null;
214 public override void register_properties(IBus.PropList props) {
215 m_property_manager.set_properties(props);
218 public override void update_property(IBus.Property prop) {
219 m_property_manager.update_property(prop);
222 public override void update_preedit_text(IBus.Text text,
226 m_candidate_panel.set_preedit_text(text, cursor_pos);
228 m_candidate_panel.set_preedit_text(null, 0);
231 public override void hide_preedit_text() {
232 m_candidate_panel.set_preedit_text(null, 0);
235 public override void update_auxiliary_text(IBus.Text text,
237 m_candidate_panel.set_auxiliary_text(visible ? text : null);
240 public override void hide_auxiliary_text() {
241 m_candidate_panel.set_auxiliary_text(null);
244 public override void update_lookup_table(IBus.LookupTable table,
246 m_candidate_panel.set_lookup_table(visible ? table : null);
249 public override void hide_lookup_table() {
250 m_candidate_panel.set_lookup_table(null);