Index: bus/ibusimpl.c |
diff --git a/bus/ibusimpl.c b/bus/ibusimpl.c |
index ee5f9993206151781769da446ee1c64aa3daaf3d..01ec61c6fd88eb3ec535c85272a848a1b8a624f2 100644 |
--- a/bus/ibusimpl.c |
+++ b/bus/ibusimpl.c |
@@ -88,6 +88,10 @@ static void bus_ibus_impl_global_engine_changed |
static void _factory_destroy_cb (BusFactoryProxy *factory, |
BusIBusImpl *ibus); |
+static void bus_ibus_impl_set_context_engine_from_desc |
+ (BusIBusImpl *ibus, |
+ BusInputContext *context, |
+ IBusEngineDesc *engine_desc); |
static void bus_ibus_impl_set_context_engine(BusIBusImpl *ibus, |
BusInputContext *context, |
BusEngineProxy *engine); |
@@ -101,6 +105,8 @@ static gchar *bus_ibus_impl_load_global_previous_engine_name_from_config |
(BusIBusImpl *ibus); |
static void bus_ibus_impl_save_global_previous_engine_name_to_config |
(BusIBusImpl *ibus); |
+static void bus_ibus_impl_update_engines_hotkey_profile |
+ (BusIBusImpl *ibus); |
G_DEFINE_TYPE(BusIBusImpl, bus_ibus_impl, IBUS_TYPE_SERVICE) |
@@ -248,6 +254,8 @@ bus_ibus_impl_set_preload_engines (BusIBusImpl *ibus, |
ibus_component_start (component, g_verbose); |
} |
} |
+ |
+ bus_ibus_impl_update_engines_hotkey_profile (ibus); |
} |
static void |
@@ -606,6 +614,9 @@ bus_ibus_impl_init (BusIBusImpl *ibus) |
ibus->global_engine = NULL; |
ibus->global_previous_engine_name = NULL; |
+ ibus->engines_hotkey_profile = NULL; |
+ ibus->hotkey_to_engines_map = NULL; |
+ |
bus_ibus_impl_reload_config (ibus); |
g_signal_connect (BUS_DEFAULT_DBUS, |
@@ -682,6 +693,16 @@ bus_ibus_impl_destroy (BusIBusImpl *ibus) |
g_free (ibus->global_previous_engine_name); |
+ if (ibus->engines_hotkey_profile != NULL) { |
+ g_object_unref (ibus->engines_hotkey_profile); |
+ ibus->engines_hotkey_profile = NULL; |
+ } |
+ |
+ if (ibus->hotkey_to_engines_map) { |
+ g_hash_table_unref (ibus->hotkey_to_engines_map); |
+ ibus->hotkey_to_engines_map = NULL; |
+ } |
+ |
bus_server_quit (BUS_DEFAULT_SERVER); |
ibus_object_destroy ((IBusObject *) BUS_DEFAULT_SERVER); |
IBUS_OBJECT_CLASS(bus_ibus_impl_parent_class)->destroy (IBUS_OBJECT (ibus)); |
@@ -891,12 +912,7 @@ _context_request_engine_cb (BusInputContext *context, |
engine_desc = _find_engine_desc_by_name (ibus, engine_name); |
} |
- if (engine_desc != NULL) { |
- engine = bus_ibus_impl_create_engine (engine_desc); |
- if (engine != NULL) { |
- bus_ibus_impl_set_context_engine (ibus, context, engine); |
- } |
- } |
+ bus_ibus_impl_set_context_engine_from_desc (ibus, context, engine_desc); |
} |
static void |
@@ -939,12 +955,7 @@ bus_ibus_impl_context_request_next_engine_in_menu (BusIBusImpl *ibus, |
} |
} |
- if (next_desc != NULL) { |
- engine = bus_ibus_impl_create_engine (next_desc); |
- if (engine != NULL) { |
- bus_ibus_impl_set_context_engine (ibus, context, engine); |
- } |
- } |
+ bus_ibus_impl_set_context_engine_from_desc (ibus, context, next_desc); |
} |
static void |
@@ -1013,6 +1024,19 @@ bus_ibus_impl_set_global_engine (BusIBusImpl *ibus, |
} |
static void |
+bus_ibus_impl_set_context_engine_from_desc (BusIBusImpl *ibus, |
+ BusInputContext *context, |
+ IBusEngineDesc *engine_desc) |
+{ |
+ if (engine_desc != NULL) { |
+ BusEngineProxy *engine = bus_ibus_impl_create_engine (engine_desc); |
+ if (engine != NULL) { |
+ bus_ibus_impl_set_context_engine (ibus, context, engine); |
+ } |
+ } |
+} |
+ |
+static void |
bus_ibus_impl_set_context_engine (BusIBusImpl *ibus, |
BusInputContext *context, |
BusEngineProxy *engine) { |
@@ -1285,6 +1309,8 @@ _factory_destroy_cb (BusFactoryProxy *factory, |
} |
g_object_unref (factory); |
+ |
+ bus_ibus_impl_update_engines_hotkey_profile (ibus); |
} |
static void |
@@ -1344,6 +1370,8 @@ _ibus_register_component (BusIBusImpl *ibus, |
ibus->register_engine_list = g_list_concat (ibus->register_engine_list, engines); |
g_object_unref (component); |
+ bus_ibus_impl_update_engines_hotkey_profile (ibus); |
+ |
reply = ibus_message_new_method_return (message); |
return reply; |
} |
@@ -1781,18 +1809,22 @@ bus_ibus_impl_filter_keyboard_shortcuts (BusIBusImpl *ibus, |
static GQuark next = 0; |
static GQuark previous = 0; |
+ GQuark event; |
+ GList *engine_list; |
+ |
if (trigger == 0) { |
trigger = g_quark_from_static_string ("trigger"); |
next = g_quark_from_static_string ("next-engine-in-menu"); |
previous = g_quark_from_static_string ("previous-engine"); |
} |
- GQuark event = ibus_hotkey_profile_filter_key_event (ibus->hotkey_profile, |
- keyval, |
- modifiers, |
- prev_keyval, |
- prev_modifiers, |
- 0); |
+ /* Try global hotkeys first. */ |
+ event = ibus_hotkey_profile_filter_key_event (ibus->hotkey_profile, |
+ keyval, |
+ modifiers, |
+ prev_keyval, |
+ prev_modifiers, |
+ 0); |
if (event == trigger) { |
gboolean enabled = bus_input_context_is_enabled (context); |
@@ -1822,6 +1854,50 @@ bus_ibus_impl_filter_keyboard_shortcuts (BusIBusImpl *ibus, |
} |
return TRUE; |
} |
+ |
+ if (!ibus->engines_hotkey_profile || !ibus->hotkey_to_engines_map) { |
+ return FALSE; |
+ } |
+ |
+ /* Then try engines hotkeys. */ |
+ event = ibus_hotkey_profile_filter_key_event (ibus->engines_hotkey_profile, |
+ keyval, |
+ modifiers, |
+ prev_keyval, |
+ prev_modifiers, |
+ 0); |
+ if (event == 0) { |
+ return FALSE; |
+ } |
+ |
+ engine_list = g_hash_table_lookup (ibus->hotkey_to_engines_map, |
+ GUINT_TO_POINTER (event)); |
+ if (engine_list) { |
+ BusEngineProxy *current_engine = bus_input_context_get_engine (context); |
+ IBusEngineDesc *current_engine_desc = |
+ (current_engine ? bus_engine_proxy_get_desc (current_engine) : NULL); |
+ IBusEngineDesc *new_engine_desc = (IBusEngineDesc *) engine_list->data; |
+ |
+ g_assert (new_engine_desc); |
+ |
+ /* Find out what engine we should switch to. If the current engine has |
+ * the same hotkey, then we should switch to the next engine with the |
+ * same hotkey in the list. Otherwise, we just switch to the first |
+ * engine in the list. */ |
+ GList *p = engine_list; |
+ for (; p->next != NULL; p = p->next) { |
+ if (current_engine_desc == (IBusEngineDesc *) p->data) { |
+ new_engine_desc = (IBusEngineDesc *) p->next->data; |
+ break; |
+ } |
+ } |
+ |
+ if (current_engine_desc != new_engine_desc) { |
+ bus_ibus_impl_set_context_engine_from_desc (ibus, context, new_engine_desc); |
+ return TRUE; |
+ } |
+ } |
+ |
return FALSE; |
} |
@@ -1888,3 +1964,74 @@ bus_ibus_impl_save_global_previous_engine_name_to_config (BusIBusImpl *ibus) |
g_value_unset (&value); |
} |
} |
+ |
+static void |
+_add_engine_hotkey (IBusEngineDesc *engine, BusIBusImpl *ibus) |
+{ |
+ gchar **hotkey_list; |
+ gchar **p; |
+ gchar *hotkey; |
+ GList *engine_list; |
+ |
+ GQuark event; |
+ guint keyval; |
+ guint modifiers; |
+ |
+ if (!engine || !engine->hotkeys || !*engine->hotkeys) { |
+ return; |
+ } |
+ |
+ hotkey_list = g_strsplit_set (engine->hotkeys, ";,", 0); |
+ |
+ for (p = hotkey_list; p && *p; ++p) { |
+ hotkey = g_strstrip (*p); |
+ if (!*hotkey || !ibus_key_event_from_string (hotkey, &keyval, &modifiers)) { |
+ continue; |
+ } |
+ |
+ /* If the hotkey already exists, we won't need to add it again. */ |
+ event = ibus_hotkey_profile_lookup_hotkey (ibus->engines_hotkey_profile, |
+ keyval, modifiers); |
+ if (event == 0) { |
+ event = g_quark_from_string (hotkey); |
+ ibus_hotkey_profile_add_hotkey (ibus->engines_hotkey_profile, |
+ keyval, modifiers, event); |
+ } |
+ |
+ engine_list = g_hash_table_lookup (ibus->hotkey_to_engines_map, |
+ GUINT_TO_POINTER (event)); |
+ |
+ /* As we will rebuild the engines hotkey map whenever an engine was |
+ * added or removed, we don't need to hold a reference of the engine |
+ * here. */ |
+ engine_list = g_list_append (engine_list, engine); |
+ |
+ /* We need to steal the value before adding it back, otherwise it will |
+ * be destroyed. */ |
+ g_hash_table_steal (ibus->hotkey_to_engines_map, GUINT_TO_POINTER (event)); |
+ |
+ g_hash_table_insert (ibus->hotkey_to_engines_map, |
+ GUINT_TO_POINTER (event), engine_list); |
+ } |
+ |
+ g_strfreev (hotkey_list); |
+} |
+ |
+static void |
+bus_ibus_impl_update_engines_hotkey_profile (BusIBusImpl *ibus) |
+{ |
+ if (ibus->engines_hotkey_profile) { |
+ g_object_unref (ibus->engines_hotkey_profile); |
+ } |
+ |
+ if (ibus->hotkey_to_engines_map) { |
+ g_hash_table_unref (ibus->hotkey_to_engines_map); |
+ } |
+ |
+ ibus->engines_hotkey_profile = ibus_hotkey_profile_new(); |
+ ibus->hotkey_to_engines_map = |
+ g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_list_free); |
+ |
+ g_list_foreach (ibus->register_engine_list, (GFunc) _add_engine_hotkey, ibus); |
+ g_list_foreach (ibus->engine_list, (GFunc) _add_engine_hotkey, ibus); |
+} |