diff --git a/autogen.sh b/autogen.sh index 1861f1b4..c4cea1a4 100755 --- a/autogen.sh +++ b/autogen.sh @@ -22,4 +22,4 @@ which gnome-autogen.sh || { touch $srcdir/ChangeLog } -ACLOCAL_FLAGS="$ACLOCAL_FLAGS -I m4" REQUIRED_AUTOMAKE_VERSION=1.10 CFLAGS="-Wall -Werror $CFLAGS" . gnome-autogen.sh +ACLOCAL_FLAGS="$ACLOCAL_FLAGS -I m4" REQUIRED_AUTOMAKE_VERSION=1.10 CFLAGS="-Wall $CFLAGS" . gnome-autogen.sh diff --git a/bus/ibusimpl.c b/bus/ibusimpl.c index 059d6602..d1242c85 100644 --- a/bus/ibusimpl.c +++ b/bus/ibusimpl.c @@ -48,7 +48,7 @@ struct _BusIBusImpl { /* a fake input context for global engine support */ BusInputContext *fake_context; - + /* a list of engines that are preloaded. */ GList *engine_list; /* a list of engines that are started by a user (without the --ibus command line flag.) */ @@ -65,10 +65,7 @@ struct _BusIBusImpl { BusInputContext *focused_context; BusPanelProxy *panel; - IBusConfig *config; - /* global hotkeys such as "trigger" and "next_engine_in_menu" */ - IBusHotkeyProfile *hotkey_profile; /* a default keymap of ibus-daemon (usually "us") which is used only when use_sys_layout is FALSE. */ IBusKeymap *keymap; @@ -131,36 +128,6 @@ static gboolean ibus_ibus_impl_service_set_property GVariant *value, GError **error); #endif -static void bus_ibus_impl_set_trigger (BusIBusImpl *ibus, - GVariant *value); -static void bus_ibus_impl_set_next_engine_in_menu - (BusIBusImpl *ibus, - GVariant *value); -static void bus_ibus_impl_set_previous_engine - (BusIBusImpl *ibus, - GVariant *value); -static void bus_ibus_impl_set_preload_engines - (BusIBusImpl *ibus, - GVariant *value); -static void bus_ibus_impl_set_use_sys_layout - (BusIBusImpl *ibus, - GVariant *value); -static void bus_ibus_impl_set_embed_preedit_text - (BusIBusImpl *ibus, - GVariant *value); -static void bus_ibus_impl_set_enable_by_default - (BusIBusImpl *ibus, - GVariant *value); -static void bus_ibus_impl_set_use_global_engine - (BusIBusImpl *ibus, - GVariant *value); -static void bus_ibus_impl_set_global_engine (BusIBusImpl *ibus, - BusEngineProxy *engine); -static void bus_ibus_impl_set_global_engine_by_name - (BusIBusImpl *ibus, - const gchar *name); -static void bus_ibus_impl_check_global_engine - (BusIBusImpl *ibus); static void bus_ibus_impl_registry_changed (BusIBusImpl *ibus); static void bus_ibus_impl_global_engine_changed (BusIBusImpl *ibus); @@ -168,15 +135,6 @@ static void bus_ibus_impl_set_context_engine_from_desc (BusIBusImpl *ibus, BusInputContext *context, IBusEngineDesc *desc); -static gchar *bus_ibus_impl_load_global_engine_name_from_config - (BusIBusImpl *ibus); -static void bus_ibus_impl_save_global_engine_name_to_config - (BusIBusImpl *ibus); - -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); static BusInputContext @@ -216,6 +174,10 @@ static const gchar introspection_xml[] = " \n" " \n" " \n" + " \n" + " \n" + " \n" + " \n" " \n" " \n" " \n" @@ -282,398 +244,6 @@ _panel_destroy_cb (BusPanelProxy *panel, g_object_unref (panel); } -static void -bus_ibus_impl_set_hotkey (BusIBusImpl *ibus, - GQuark hotkey, - GVariant *value) -{ - g_assert (BUS_IS_IBUS_IMPL (ibus)); - - ibus_hotkey_profile_remove_hotkey_by_event (ibus->hotkey_profile, hotkey); - - if (value == NULL) { - return; - } - - GVariantIter iter; - g_variant_iter_init (&iter, value); - const gchar *str = NULL; - while (g_variant_iter_loop (&iter,"&s", &str)) { - ibus_hotkey_profile_add_hotkey_from_string (ibus->hotkey_profile, - str, - hotkey); - } - -} - -/** - * bus_ibus_impl_set_trigger: - * - * A function to be called when "trigger" config is updated. If the value is NULL, the default trigger (Ctrl+space) is set. - */ -static void -bus_ibus_impl_set_trigger (BusIBusImpl *ibus, - GVariant *value) -{ - GQuark hotkey = g_quark_from_static_string ("trigger"); - if (value != NULL) { - bus_ibus_impl_set_hotkey (ibus, hotkey, value); - } -#ifndef OS_CHROMEOS - else { - /* set default trigger */ - ibus_hotkey_profile_remove_hotkey_by_event (ibus->hotkey_profile, hotkey); - ibus_hotkey_profile_add_hotkey (ibus->hotkey_profile, - IBUS_space, - IBUS_CONTROL_MASK, - hotkey); - } -#endif -} - -/** - * bus_ibus_impl_set_enable_unconditional: - * - * A function to be called when "enable_unconditional" config is updated. - */ -static void -bus_ibus_impl_set_enable_unconditional (BusIBusImpl *ibus, - GVariant *value) -{ - GQuark hotkey = g_quark_from_static_string ("enable-unconditional"); - bus_ibus_impl_set_hotkey (ibus, hotkey, value); -} - -/** - * bus_ibus_impl_set_disable_unconditional: - * - * A function to be called when "disable_unconditional" config is updated. - */ -static void -bus_ibus_impl_set_disable_unconditional (BusIBusImpl *ibus, - GVariant *value) -{ - GQuark hotkey = g_quark_from_static_string ("disable-unconditional"); - bus_ibus_impl_set_hotkey (ibus, hotkey, value); -} - -/** - * bus_ibus_impl_set_next_engine_in_menu: - * - * A function to be called when "next_engine_in_menu" config is updated. - */ -static void -bus_ibus_impl_set_next_engine_in_menu (BusIBusImpl *ibus, - GVariant *value) -{ - GQuark hotkey = g_quark_from_static_string ("next-engine-in-menu"); - bus_ibus_impl_set_hotkey (ibus, hotkey, value); -} - -/** - * bus_ibus_impl_set_previous_engine: - * - * A function to be called when "previous_engine" config is updated. - */ -static void -bus_ibus_impl_set_previous_engine (BusIBusImpl *ibus, - GVariant *value) -{ - GQuark hotkey = g_quark_from_static_string ("previous-engine"); - bus_ibus_impl_set_hotkey (ibus, hotkey, value); -} - -/** - * bus_ibus_impl_set_preload_engines: - * - * A function to be called when "preload_engines" config is updated. - */ -static void -bus_ibus_impl_set_preload_engines (BusIBusImpl *ibus, - GVariant *value) -{ - GList *engine_list = NULL; - - g_list_foreach (ibus->engine_list, (GFunc) g_object_unref, NULL); - g_list_free (ibus->engine_list); - - if (value != NULL && g_variant_classify (value) == G_VARIANT_CLASS_ARRAY) { - GVariantIter iter; - g_variant_iter_init (&iter, value); - const gchar *engine_name = NULL; - while (g_variant_iter_loop (&iter, "&s", &engine_name)) { - IBusEngineDesc *engine = bus_registry_find_engine_by_name (ibus->registry, engine_name); - if (engine == NULL || g_list_find (engine_list, engine) != NULL) - continue; - engine_list = g_list_append (engine_list, engine); - } - } - - g_list_foreach (engine_list, (GFunc) g_object_ref, NULL); - ibus->engine_list = engine_list; - - if (ibus->engine_list) { - BusComponent *component = bus_component_from_engine_desc ((IBusEngineDesc *) ibus->engine_list->data); - if (component && !bus_component_is_running (component)) { - bus_component_start (component, g_verbose); - } - } - - bus_ibus_impl_check_global_engine (ibus); - bus_ibus_impl_update_engines_hotkey_profile (ibus); -} - -/** - * bus_ibus_impl_set_use_sys_layout: - * - * A function to be called when "use_system_keyboard_layout" config is updated. - */ -static void -bus_ibus_impl_set_use_sys_layout (BusIBusImpl *ibus, - GVariant *value) -{ - if (value != NULL && g_variant_classify (value) == G_VARIANT_CLASS_BOOLEAN) { - ibus->use_sys_layout = g_variant_get_boolean (value); - } -} - -/** - * bus_ibus_impl_set_embed_preedit_text: - * - * A function to be called when "use_embed_preedit_text" config is updated. - */ -static void -bus_ibus_impl_set_embed_preedit_text (BusIBusImpl *ibus, - GVariant *value) -{ - if (value != NULL && g_variant_classify (value) == G_VARIANT_CLASS_BOOLEAN) { - ibus->embed_preedit_text = g_variant_get_boolean (value); - } -} - -/** - * bus_ibus_impl_set_enable_by_default: - * - * A function to be called when "enable_by_default" config is updated. - */ -static void -bus_ibus_impl_set_enable_by_default (BusIBusImpl *ibus, - GVariant *value) -{ - if (value != NULL && g_variant_classify (value) == G_VARIANT_CLASS_BOOLEAN) { - ibus->enable_by_default = g_variant_get_boolean (value); - } -} - -/** - * bus_ibus_impl_set_use_global_engine: - * - * A function to be called when "use_global_engine" config is updated. - */ -static void -bus_ibus_impl_set_use_global_engine (BusIBusImpl *ibus, - GVariant *value) -{ - if (value == NULL || g_variant_classify (value) != G_VARIANT_CLASS_BOOLEAN) - return; - - gboolean new_value = g_variant_get_boolean (value); - if (ibus->use_global_engine == new_value) - return; - - if (new_value) { - /* turn on use_global_engine option */ - ibus->use_global_engine = TRUE; - if (ibus->panel && ibus->focused_context == NULL) { - bus_panel_proxy_focus_in (ibus->panel, ibus->fake_context); - } - } - else { - /* turn off use_global_engine option */ - ibus->use_global_engine = FALSE; - - /* if fake context has the focus, we should focus out it */ - if (ibus->panel && ibus->focused_context == NULL) { - bus_panel_proxy_focus_out (ibus->panel, ibus->fake_context); - } - /* remove engine in fake context */ - bus_input_context_set_engine (ibus->fake_context, NULL); - } -} - -#ifndef OS_CHROMEOS -static gint -_engine_desc_cmp (IBusEngineDesc *desc1, - IBusEngineDesc *desc2) -{ - return - ((gint) ibus_engine_desc_get_rank (desc1)) + - ((gint) ibus_engine_desc_get_rank (desc2)); -} -#endif - -/** - * bus_ibus_impl_set_default_preload_engines: - * - * If the "preload_engines" config variable is not set yet, set the default value which is determined based on a current locale. - */ -static void -bus_ibus_impl_set_default_preload_engines (BusIBusImpl *ibus) -{ -#ifndef OS_CHROMEOS - g_assert (BUS_IS_IBUS_IMPL (ibus)); - - static gboolean done = FALSE; - - if (done || ibus->config == NULL) { - return; - } - - GVariant *variant = ibus_config_get_value (ibus->config, "general", "preload_engines"); - if (variant != NULL) { - done = TRUE; - g_variant_unref (variant); - return; - } - - done = TRUE; - - /* The setlocale call first checks LC_ALL. If it's not available, checks - * LC_CTYPE. If it's also not available, checks LANG. */ - gchar *lang = g_strdup (setlocale (LC_CTYPE, NULL)); - if (lang == NULL) { - return; - } - - gchar *p = index (lang, '.'); - if (p) { - *p = '\0'; - } - - GList *engines = bus_registry_get_engines_by_language (ibus->registry, lang); - if (engines == NULL) { - p = index (lang, '_'); - if (p) { - *p = '\0'; - engines = bus_registry_get_engines_by_language (ibus->registry, lang); - } - } - g_free (lang); - - /* sort engines by rank */ - engines = g_list_sort (engines, (GCompareFunc) _engine_desc_cmp); - - GVariantBuilder builder; - g_variant_builder_init (&builder, G_VARIANT_TYPE ("as")); - GList *list; - for (list = engines; list != NULL; list = list->next) { - IBusEngineDesc *desc = (IBusEngineDesc *) list->data; - /* ignore engines with rank <= 0 */ - if (ibus_engine_desc_get_rank (desc) > 0) - g_variant_builder_add (&builder, "s", ibus_engine_desc_get_name (desc)); - } - - GVariant *value = g_variant_builder_end (&builder); - if (value != NULL) { - if (g_variant_n_children (value) > 0) { - ibus_config_set_value (ibus->config, - "general", "preload_engines", value); - } else { - /* We don't update preload_engines with an empty string for safety. - * Just unref the floating value. */ - g_variant_unref (value); - } - } - g_list_free (engines); -#endif -} - -/* The list of config entries that are related to ibus-daemon. */ -const static struct { - gchar *section; - gchar *key; - void (*func) (BusIBusImpl *, GVariant *); -} bus_ibus_impl_config_items [] = { - { "general/hotkey", "trigger", bus_ibus_impl_set_trigger }, - { "general/hotkey", "enable_unconditional", bus_ibus_impl_set_enable_unconditional }, - { "general/hotkey", "disable_unconditional", bus_ibus_impl_set_disable_unconditional }, - { "general/hotkey", "next_engine_in_menu", bus_ibus_impl_set_next_engine_in_menu }, - { "general/hotkey", "previous_engine", bus_ibus_impl_set_previous_engine }, - { "general", "preload_engines", bus_ibus_impl_set_preload_engines }, - { "general", "use_system_keyboard_layout", bus_ibus_impl_set_use_sys_layout }, - { "general", "use_global_engine", bus_ibus_impl_set_use_global_engine }, - { "general", "embed_preedit_text", bus_ibus_impl_set_embed_preedit_text }, - { "general", "enable_by_default", bus_ibus_impl_set_enable_by_default }, -}; - -/** - * bus_ibus_impl_reload_config - * - * Read config entries (e.g. preload_engines) from the config daemon. - */ -static void -bus_ibus_impl_reload_config (BusIBusImpl *ibus) -{ - g_assert (BUS_IS_IBUS_IMPL (ibus)); - - gint i; - for (i = 0; i < G_N_ELEMENTS (bus_ibus_impl_config_items); i++) { - GVariant *variant = NULL; - if (ibus->config != NULL) - variant = ibus_config_get_value (ibus->config, - bus_ibus_impl_config_items[i].section, - bus_ibus_impl_config_items[i].key); - bus_ibus_impl_config_items[i].func (ibus, variant); /* variant could be NULL if the deamon is not ready yet. */ - if (variant) g_variant_unref (variant); - } -} - -/** - * _config_value_changed_cb: - * - * A callback function to be called when the "ValueChanged" D-Bus signal is sent from the config daemon. - */ -static void -_config_value_changed_cb (IBusConfig *config, - gchar *section, - gchar *key, - GVariant *value, - BusIBusImpl *ibus) -{ - g_assert (IBUS_IS_CONFIG (config)); - g_assert (section); - g_assert (key); - g_assert (value); - g_assert (BUS_IS_IBUS_IMPL (ibus)); - - gint i; - for (i = 0; i < G_N_ELEMENTS (bus_ibus_impl_config_items); i++) { - if (g_strcmp0 (bus_ibus_impl_config_items[i].section, section) == 0 && - g_strcmp0 (bus_ibus_impl_config_items[i].key, key) == 0) { - bus_ibus_impl_config_items[i].func (ibus, value); - break; - } - } -} - -/** - * _config_destroy_cb: - * - * A callback function which is called when (1) the connection to the config process is terminated, - * or (2) ibus_proxy_destroy (ibus->config); is called. See src/ibusproxy.c for details. - */ -static void -_config_destroy_cb (IBusConfig *config, - BusIBusImpl *ibus) -{ - g_assert (IBUS_IS_CONFIG (config)); - g_assert (BUS_IS_IBUS_IMPL (ibus)); - - g_assert (ibus->config == config); - - g_object_unref (ibus->config); - ibus->config = NULL; -} - static void _registry_changed_cb (BusRegistry *registry, BusIBusImpl *ibus) @@ -730,47 +300,6 @@ _dbus_name_owner_changed_cb (BusDBusImpl *dbus, } } } - else if (g_strcmp0 (name, IBUS_SERVICE_CONFIG) == 0) { - if (g_strcmp0 (new_name, "") != 0) { - /* a config process is started. */ - BusConnection *connection; - - if (ibus->config != NULL) { - ibus_proxy_destroy ((IBusProxy *) ibus->config); - /* config should be NULL after destroy. See _config_destroy_cb for details. */ - g_assert (ibus->config == NULL); - } - - /* get a connection between ibus-daemon and the config daemon. */ - connection = bus_dbus_impl_get_connection_by_name (BUS_DEFAULT_DBUS, new_name); - g_return_if_fail (connection != NULL); - - ibus->config = g_initable_new (IBUS_TYPE_CONFIG, - NULL, - NULL, - /* The following properties are necessary to initialize GDBusProxy object - * which is a parent of the config object. */ - "g-connection", bus_connection_get_dbus_connection (connection), - "g-flags", G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START | G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, - "g-interface-name", IBUS_INTERFACE_CONFIG, - "g-object-path", IBUS_PATH_CONFIG, - "g-default-timeout", g_gdbus_timeout, - NULL); - - g_signal_connect (ibus->config, - "value-changed", - G_CALLBACK (_config_value_changed_cb), - ibus); - - g_signal_connect (ibus->config, - "destroy", - G_CALLBACK (_config_destroy_cb), - ibus); - - bus_ibus_impl_set_default_preload_engines (ibus); - bus_ibus_impl_reload_config (ibus); - } - } bus_registry_name_owner_changed (ibus->registry, name, old_name, new_name); } @@ -808,8 +337,6 @@ bus_ibus_impl_init (BusIBusImpl *ibus) ibus->contexts = NULL; ibus->focused_context = NULL; ibus->panel = NULL; - ibus->config = NULL; - ibus->registry = bus_registry_new (); g_signal_connect (ibus->registry, @@ -824,13 +351,12 @@ bus_ibus_impl_init (BusIBusImpl *ibus) } #endif - ibus->hotkey_profile = ibus_hotkey_profile_new (); ibus->keymap = ibus_keymap_get ("us"); ibus->use_sys_layout = FALSE; ibus->embed_preedit_text = TRUE; - ibus->enable_by_default = FALSE; - ibus->use_global_engine = FALSE; + ibus->enable_by_default = TRUE; + ibus->use_global_engine = TRUE; ibus->global_engine_name = NULL; ibus->global_previous_engine_name = NULL; @@ -904,11 +430,6 @@ bus_ibus_impl_destroy (BusIBusImpl *ibus) ibus->factory_dict = NULL; } - if (ibus->hotkey_profile != NULL) { - g_object_unref (ibus->hotkey_profile); - ibus->hotkey_profile = NULL; - } - if (ibus->keymap != NULL) { g_object_unref (ibus->keymap); ibus->keymap = NULL; @@ -972,7 +493,6 @@ _find_engine_desc_by_name (BusIBusImpl *ibus, if (g_strcmp0 (ibus_engine_desc_get_name (desc), engine_name) == 0) return desc; } - return NULL; } @@ -999,180 +519,10 @@ static IBusEngineDesc * bus_ibus_impl_get_engine_desc (BusIBusImpl *ibus, const gchar *engine_name) { - IBusEngineDesc *desc = NULL; + g_return_val_if_fail (engine_name != NULL, NULL); + g_return_val_if_fail (engine_name[0] != '\0', NULL); - if (engine_name != NULL && engine_name[0] != '\0') { - /* request engine by name */ - desc = _find_engine_desc_by_name (ibus, engine_name); - if (desc == NULL) { - g_warning ("_context_request_engine_cb: Invalid engine '%s' is requested.", engine_name); - return NULL; - } - } - else { - /* Use global engine if possible. */ - if (ibus->use_global_engine) { - gchar *name = g_strdup (ibus->global_engine_name); - if (name == NULL) { - name = bus_ibus_impl_load_global_engine_name_from_config (ibus); - } - if (name) { - desc = _find_engine_desc_by_name (ibus, name); - g_free (name); - } - } - /* request default engine */ - if (!desc) { - if (ibus->register_engine_list) { - desc = (IBusEngineDesc *) ibus->register_engine_list->data; - } - else if (ibus->engine_list) { - desc = (IBusEngineDesc *) ibus->engine_list->data; - } - } - if (!desc) { - /* no engine is available. the user hasn't ran ibus-setup yet and - * the bus_ibus_impl_set_default_preload_engines() function could - * not find any default engines. another possiblity is that the - * user hasn't installed an engine yet? just give up. */ - g_warning ("No engine is available. Run ibus-setup first."); - return NULL; - } - } - - return desc; -} - -/** - * bus_ibus_impl_context_request_rotate_engine_in_menu: - * - * Process the "next_engine_in_menu" or "previous_engine" hotkey. - */ -static void -bus_ibus_impl_context_request_rotate_engine_in_menu (BusIBusImpl *ibus, - BusInputContext *context, - gboolean is_next) -{ - BusEngineProxy *engine; - IBusEngineDesc *desc; - IBusEngineDesc *next_desc = NULL; - GList *p = NULL; - - engine = bus_input_context_get_engine (context); - if (engine == NULL) { - desc = bus_ibus_impl_get_engine_desc (ibus, NULL); - if (desc != NULL) - bus_ibus_impl_set_context_engine_from_desc (ibus, - context, - desc); - return; - } - - desc = bus_engine_proxy_get_desc (engine); - - p = g_list_find (ibus->register_engine_list, desc); - if (p != NULL) { - if (is_next) { - p = p->next; - } else { - p = p->prev; - } - } - - /* Rotate register_engine_list and engine_list. */ - if (p == NULL && g_list_find (ibus->register_engine_list, desc) != NULL) { - if (is_next) { - p = ibus->engine_list; - } else { - p = g_list_last (ibus->engine_list); - } - } - - if (p == NULL) { - p = g_list_find (ibus->engine_list, desc); - if (p != NULL) { - if (is_next) { - p = p->next; - } else { - p = p->prev; - } - } - } - - /* Rerotate register_engine_list and engine_list. */ - if (p == NULL && g_list_find (ibus->engine_list, desc) != NULL) { - if (is_next) { - p = ibus->register_engine_list; - if (p == NULL) { - p = ibus->engine_list; - } - } else { - p = g_list_last (ibus->register_engine_list); - if (p == NULL) { - p = g_list_last (ibus->engine_list); - } - } - } - - if (p != NULL) { - next_desc = (IBusEngineDesc*) p->data; - } - else { - if (ibus->register_engine_list) { - next_desc = (IBusEngineDesc *) ibus->register_engine_list->data; - } - else if (ibus->engine_list) { - next_desc = (IBusEngineDesc *) ibus->engine_list->data; - } - } - - bus_ibus_impl_set_context_engine_from_desc (ibus, context, next_desc); -} - -/** - * bus_ibus_impl_context_request_previous_engine: - * - * Process the "previous_engine" hotkey. - */ -static void -bus_ibus_impl_context_request_previous_engine (BusIBusImpl *ibus, - BusInputContext *context) -{ - gchar *engine_name = NULL; - - if (!ibus->use_global_engine) { - engine_name = (gchar *) g_object_get_data (G_OBJECT (context), "previous-engine-name"); - } - else { - if (!ibus->global_previous_engine_name) { - ibus->global_previous_engine_name = bus_ibus_impl_load_global_previous_engine_name_from_config (ibus); - } - engine_name = ibus->global_previous_engine_name; - if (engine_name != NULL) { - /* If the previous engine is removed from the engine list or the - current engine and the previous engine are the same one, force - to pick a new one. */ - if (!_find_engine_desc_by_name (ibus, engine_name) || - g_strcmp0 (engine_name, ibus->global_engine_name) == 0) { - g_free (engine_name); - ibus->global_previous_engine_name = engine_name = NULL; - } - } - } - - if (!engine_name) { - bus_ibus_impl_context_request_rotate_engine_in_menu (ibus, context, - FALSE); - return; - } - - IBusEngineDesc *desc = NULL; - desc = bus_ibus_impl_get_engine_desc (ibus, engine_name); - if (desc != NULL) { - bus_ibus_impl_set_context_engine_from_desc (ibus, - context, - desc); - } + return bus_registry_find_engine_by_name (ibus->registry, engine_name); } static void @@ -1214,7 +564,8 @@ bus_ibus_impl_set_focused_context (BusIBusImpl *ibus, /* dettach engine from the focused context */ engine = bus_input_context_get_engine (ibus->focused_context); if (engine) { - is_enabled = bus_input_context_is_enabled (ibus->focused_context); + // is_enabled = bus_input_context_is_enabled (ibus->focused_context); + is_enabled = TRUE; g_object_ref (engine); bus_input_context_set_engine (ibus->focused_context, NULL); } @@ -1361,9 +712,6 @@ _context_engine_changed_cb (BusInputContext *context, g_free (ibus->global_previous_engine_name); ibus->global_previous_engine_name = ibus->global_engine_name; ibus->global_engine_name = g_strdup (name); - /* save changes */ - bus_ibus_impl_save_global_engine_name_to_config (ibus); - bus_ibus_impl_save_global_previous_engine_name_to_config (ibus); bus_ibus_impl_global_engine_changed (ibus); } } @@ -1443,30 +791,6 @@ _context_destroy_cb (BusInputContext *context, g_object_unref (context); } -/** - * _context_enabled_cb: - * - * A callback function to be called when the "enabled" signal is sent to the context. - */ -static void -_context_enabled_cb (BusInputContext *context, - BusIBusImpl *ibus) -{ - /* FIXME implement this. */ -} - -/** - * _context_disabled_cb: - * - * A callback function to be called when the "disabled" signal is sent to the context. - */ -static void -_context_disabled_cb (BusInputContext *context, - BusIBusImpl *ibus) -{ - /* FIXME implement this. */ -} - /** * bus_ibus_impl_create_input_context: * @client: A name of a client. e.g. "gtk-im" @@ -1493,8 +817,6 @@ bus_ibus_impl_create_input_context (BusIBusImpl *ibus, { "focus-in", G_CALLBACK (_context_focus_in_cb) }, { "focus-out", G_CALLBACK (_context_focus_out_cb) }, { "destroy", G_CALLBACK (_context_destroy_cb) }, - { "enabled", G_CALLBACK (_context_enabled_cb) }, - { "disabled", G_CALLBACK (_context_disabled_cb) }, }; gint i; @@ -1671,6 +993,37 @@ _ibus_list_engines (BusIBusImpl *ibus, g_dbus_method_invocation_return_value (invocation, g_variant_new ("(av)", &builder)); } +/** + * _ibus_get_engines_by_names: + * + * Implement the "GetEnginesByNames" method call of the org.freedesktop.IBus interface. + */ +static void +_ibus_get_engines_by_names (BusIBusImpl *ibus, + GVariant *parameters, + GDBusMethodInvocation *invocation) +{ + const gchar **names = NULL; + g_variant_get (parameters, "(^a&s)", &names); + + g_assert (names != NULL); + + gint i = 0; + GVariantBuilder builder; + g_variant_builder_init (&builder, G_VARIANT_TYPE ("av")); + while (names[i] != NULL) { + IBusEngineDesc *desc = bus_registry_find_engine_by_name ( + ibus->registry, names[i++]); + if (desc == NULL) + continue; + g_variant_builder_add ( + &builder, + "v", + ibus_serializable_serialize ((IBusSerializable *)desc)); + } + g_dbus_method_invocation_return_value (invocation, g_variant_new ("(av)", &builder)); +} + /** * _ibus_list_active_engines: * @@ -1863,7 +1216,7 @@ _ibus_set_global_engine (BusIBusImpl *ibus, const gchar *engine_name = NULL; g_variant_get (parameters, "(&s)", &engine_name); - IBusEngineDesc *desc = _find_engine_desc_by_name (ibus, engine_name); + IBusEngineDesc *desc = bus_ibus_impl_get_engine_desc(ibus, engine_name); if (desc == NULL) { g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, @@ -1906,7 +1259,7 @@ _ibus_is_global_engine_enabled (BusIBusImpl *ibus, if (context == NULL) break; - enabled = bus_input_context_is_enabled (context); + enabled = TRUE; } while (0); g_dbus_method_invocation_return_value (invocation, @@ -1946,6 +1299,7 @@ bus_ibus_impl_service_method_call (IBusService *service, { "CurrentInputContext", _ibus_current_input_context }, { "RegisterComponent", _ibus_register_component }, { "ListEngines", _ibus_list_engines }, + { "GetEnginesByNames", _ibus_get_engines_by_names }, { "ListActiveEngines", _ibus_list_active_engines }, { "Exit", _ibus_exit }, { "Ping", _ibus_ping }, @@ -1994,14 +1348,6 @@ bus_ibus_impl_lookup_factory (BusIBusImpl *ibus, return factory; } -IBusHotkeyProfile * -bus_ibus_impl_get_hotkey_profile (BusIBusImpl *ibus) -{ - g_assert (BUS_IS_IBUS_IMPL (ibus)); - - return ibus->hotkey_profile; -} - IBusKeymap * bus_ibus_impl_get_keymap (BusIBusImpl *ibus) { @@ -2064,207 +1410,9 @@ bus_ibus_impl_filter_keyboard_shortcuts (BusIBusImpl *ibus, guint prev_keyval, guint prev_modifiers) { - static GQuark trigger = 0; - static GQuark enable_unconditional = 0; - static GQuark disable_unconditional = 0; - static GQuark next = 0; - static GQuark previous = 0; - - GQuark event; - GList *engine_list; - - if (trigger == 0) { - trigger = g_quark_from_static_string ("trigger"); - enable_unconditional = g_quark_from_static_string ("enable-unconditional"); - disable_unconditional = g_quark_from_static_string ("disable-unconditional"); - next = g_quark_from_static_string ("next-engine-in-menu"); - previous = g_quark_from_static_string ("previous-engine"); - } - - /* 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); - if (enabled) { - bus_input_context_disable (context); - } - else { - bus_input_context_enable (context); - } - return TRUE; - } - if (event == enable_unconditional) { - gboolean enabled = bus_input_context_is_enabled (context); - if (!enabled) { - bus_input_context_enable (context); - } - return TRUE; - } - if (event == disable_unconditional) { - gboolean enabled = bus_input_context_is_enabled (context); - if (enabled) { - bus_input_context_disable (context); - } - return TRUE; - } - if (event == next) { - if (bus_input_context_is_enabled (context)) { - bus_ibus_impl_context_request_rotate_engine_in_menu (ibus, context, - TRUE); - } - else { - bus_input_context_enable (context); - } - return TRUE; - } - if (event == previous) { - if (bus_input_context_is_enabled (context)) { - bus_ibus_impl_context_request_previous_engine (ibus, context); - } - else { - bus_input_context_enable (context); - } - 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; } -/** - * bus_ibus_impl_load_global_engine_name_from_config: - * - * Retrieve the "global_engine" config from the config daemon. Return NULL if the daemon is not ready. - */ -static gchar* -bus_ibus_impl_load_global_engine_name_from_config (BusIBusImpl *ibus) -{ - g_assert (BUS_IS_IBUS_IMPL (ibus)); - if (ibus->config == NULL) { - /* the config component is not started yet. */ - return NULL; - } - g_assert (IBUS_IS_CONFIG (ibus->config)); - - GVariant *variant = ibus_config_get_value (ibus->config, "general", "global_engine"); - gchar *engine_name = NULL; - if (variant != NULL) { - engine_name = g_variant_dup_string (variant, NULL); - g_variant_unref (variant); - } - return engine_name; -} - -/** - * bus_ibus_impl_save_global_engine_name_to_config: - * - * Save the "global_engine" config value on the config daemon. No-op if the daemon is not ready. - */ -static void -bus_ibus_impl_save_global_engine_name_to_config (BusIBusImpl *ibus) -{ - g_assert (BUS_IS_IBUS_IMPL (ibus)); - - if (ibus->config && - ibus->use_global_engine && - ibus->global_engine_name) { - ibus_config_set_value (ibus->config, - "general", "global_engine", - g_variant_new_string (ibus->global_engine_name)); - } -} - -/** - * bus_ibus_impl_load_global_previous_engine_name_from_config: - * - * Retrieve the "global_previous_engine" config from the config daemon. Return NULL if the daemon is not ready. - */ -static gchar* -bus_ibus_impl_load_global_previous_engine_name_from_config (BusIBusImpl *ibus) -{ - g_assert (BUS_IS_IBUS_IMPL (ibus)); - if (ibus->config == NULL) { - /* the config component is not started yet. */ - return NULL; - } - g_assert (IBUS_IS_CONFIG (ibus->config)); - - GVariant *value = ibus_config_get_value (ibus->config, "general", "global_previous_engine"); - if (value == NULL) - return NULL; - gchar *engine_name = g_variant_dup_string (value, NULL); - g_variant_unref (value); - return engine_name; -} - -/** - * bus_ibus_impl_save_global_previous_engine_name_to_config: - * - * Save the "global_previous_engine" config value on the config daemon. No-op if the daemon is not ready. - */ -static void -bus_ibus_impl_save_global_previous_engine_name_to_config (BusIBusImpl *ibus) -{ - g_assert (BUS_IS_IBUS_IMPL (ibus)); - - if (ibus->config && - ibus->use_global_engine && - ibus->global_previous_engine_name) { - ibus_config_set_value (ibus->config, - "general", "global_previous_engine", - g_variant_new_string (ibus->global_previous_engine_name)); - } -} - /** * _add_engine_hotkey: * diff --git a/bus/ibusimpl.h b/bus/ibusimpl.h index 42edbf83..0b212bb9 100644 --- a/bus/ibusimpl.h +++ b/bus/ibusimpl.h @@ -50,8 +50,6 @@ #define BUS_DEFAULT_IBUS \ (bus_ibus_impl_get_default ()) -#define BUS_DEFAULT_HOTKEY_PROFILE \ - (bus_ibus_impl_get_hotkey_profile (BUS_DEFAULT_IBUS)) #define BUS_DEFAULT_KEYMAP \ (bus_ibus_impl_get_keymap (BUS_DEFAULT_IBUS)) #define BUS_DEFAULT_REGISTRY \ @@ -90,8 +88,6 @@ gboolean bus_ibus_impl_filter_keyboard_shortcuts /* accessors */ BusFactoryProxy *bus_ibus_impl_lookup_factory (BusIBusImpl *ibus, const gchar *path); -IBusHotkeyProfile - *bus_ibus_impl_get_hotkey_profile (BusIBusImpl *ibus); IBusKeymap *bus_ibus_impl_get_keymap (BusIBusImpl *ibus); BusRegistry *bus_ibus_impl_get_registry (BusIBusImpl *ibus); gboolean bus_ibus_impl_is_use_sys_layout (BusIBusImpl *ibus); diff --git a/bus/inputcontext.c b/bus/inputcontext.c index 3c81688f..55b601b4 100644 --- a/bus/inputcontext.c +++ b/bus/inputcontext.c @@ -53,7 +53,6 @@ struct _BusInputContext { gchar *client; gboolean has_focus; - gboolean enabled; /* client capabilities */ guint capabilities; @@ -96,6 +95,7 @@ struct _BusInputContextClass { IBusServiceClass parent; /* class members */ + IBusEngineDesc *default_engine_desc; }; enum { @@ -118,8 +118,6 @@ enum { CURSOR_DOWN_LOOKUP_TABLE, REGISTER_PROPERTIES, UPDATE_PROPERTY, - ENABLED, - DISABLED, ENGINE_CHANGED, REQUEST_ENGINE, LAST_SIGNAL, @@ -163,12 +161,6 @@ static gboolean bus_input_context_service_set_property GVariant *value, GError **error); */ -static gboolean bus_input_context_filter_keyboard_shortcuts - (BusInputContext *context, - guint keyval, - guint keycode, - guint modifiers); - static void bus_input_context_unset_engine (BusInputContext *context); static void bus_input_context_commit_text (BusInputContext *context, IBusText *text); @@ -247,11 +239,6 @@ static const gchar introspection_xml[] = " " " " " " - " " - " " - " " - " " - " " " " " " " " @@ -275,8 +262,6 @@ static const gchar introspection_xml[] = " " " " " " - " " - " " " " " " " " @@ -337,6 +322,16 @@ bus_input_context_class_init (BusInputContextClass *class) { IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (class); + class->default_engine_desc = ibus_engine_desc_new ("dummy", + "", + "", + "", + "", + "", + "ibus-engine", + ""); + g_object_ref_sink (class->default_engine_desc); + ibus_object_class->destroy = (IBusObjectDestroyFunc) bus_input_context_destroy; /* override the parent class's implementation. */ @@ -543,26 +538,6 @@ bus_input_context_class_init (BusInputContextClass *class) 1, IBUS_TYPE_PROPERTY); - context_signals[ENABLED] = - g_signal_new (I_("enabled"), - G_TYPE_FROM_CLASS (class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - bus_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - - context_signals[DISABLED] = - g_signal_new (I_("disabled"), - G_TYPE_FROM_CLASS (class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - bus_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - context_signals[ENGINE_CHANGED] = g_signal_new (I_("engine-changed"), G_TYPE_FROM_CLASS (class), @@ -732,17 +707,8 @@ _ic_process_key_event (BusInputContext *context, } } - if (G_LIKELY (context->has_focus)) { - gboolean retval = bus_input_context_filter_keyboard_shortcuts (context, keyval, keycode, modifiers); - /* If it is keyboard shortcut, reply TRUE to client */ - if (G_UNLIKELY (retval)) { - g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE)); - return; - } - } - /* ignore key events, if it is a fake input context */ - if (context->has_focus && context->enabled && context->engine && context->fake == FALSE) { + if (context->has_focus && context->engine && context->fake == FALSE) { bus_engine_proxy_process_key_event (context->engine, keyval, keycode, @@ -770,7 +736,7 @@ _ic_set_cursor_location (BusInputContext *context, g_variant_get (parameters, "(iiii)", &context->x, &context->y, &context->w, &context->h); - if (context->has_focus && context->enabled && context->engine) { + if (context->has_focus && context->engine) { bus_engine_proxy_set_cursor_location (context->engine, context->x, context->y, context->w, context->h); } @@ -792,7 +758,7 @@ _ic_process_hand_writing_event (BusInputContext *context, GDBusMethodInvocation *invocation) { /* do nothing if it is a fake input context */ - if (context->has_focus && context->enabled && + if (context->has_focus && context->engine && context->fake == FALSE) { bus_engine_proxy_process_hand_writing_event (context->engine, parameters); } @@ -808,7 +774,7 @@ _ic_cancel_hand_writing (BusInputContext *context, g_variant_get (parameters, "(u)", &n_strokes); /* do nothing if it is a fake input context */ - if (context->has_focus && context->enabled && + if (context->has_focus && context->engine && context->fake == FALSE) { bus_engine_proxy_cancel_hand_writing (context->engine, n_strokes); } @@ -865,7 +831,7 @@ _ic_reset (BusInputContext *context, GVariant *parameters, GDBusMethodInvocation *invocation) { - if (context->enabled && context->engine) { + if (context->engine) { bus_engine_proxy_reset (context->engine); } g_dbus_method_invocation_return_value (invocation, NULL); @@ -903,7 +869,7 @@ _ic_property_activate (BusInputContext *context, guint prop_state = 0; g_variant_get (parameters, "(&su)", &prop_name, &prop_state); - if (context->enabled && context->engine) { + if (context->engine) { bus_engine_proxy_property_activate (context->engine, prop_name, prop_state); } @@ -921,47 +887,6 @@ _ic_property_activate (BusInputContext *context, g_dbus_method_invocation_return_value (invocation, NULL); } -/** - * _ic_enable: - * - * Implement the "Enable" method call of the org.freedesktop.IBus.InputContext interface. - */ -static void -_ic_enable (BusInputContext *context, - GVariant *parameters, - GDBusMethodInvocation *invocation) -{ - bus_input_context_enable (context); - g_dbus_method_invocation_return_value (invocation, NULL); -} - -/** - * _ic_disable: - * - * Implement the "Disable" method call of the org.freedesktop.IBus.InputContext interface. - */ -static void -_ic_disable (BusInputContext *context, - GVariant *parameters, - GDBusMethodInvocation *invocation) -{ - bus_input_context_disable (context); - g_dbus_method_invocation_return_value (invocation, NULL); -} - -/** - * _ic_is_enabled: - * - * Implement the "IsEnabled" method call of the org.freedesktop.IBus.InputContext interface. - */ -static void -_ic_is_enabled (BusInputContext *context, - GVariant *parameters, - GDBusMethodInvocation *invocation) -{ - g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", context->enabled)); -} - static void _ic_set_engine_done (BusInputContext *context, GAsyncResult *res, @@ -1033,18 +958,13 @@ _ic_get_engine (BusInputContext *context, GVariant *parameters, GDBusMethodInvocation *invocation) { - if (context->engine) { - IBusEngineDesc *desc = bus_engine_proxy_get_desc (context->engine); - g_dbus_method_invocation_return_value (invocation, - g_variant_new ("(v)", ibus_serializable_serialize ((IBusSerializable *)desc))); - } - else { - g_dbus_method_invocation_return_error ( - invocation, - IBUS_ERROR, - IBUS_ERROR_NO_ENGINE, - "Input context does not have engine."); - } + IBusEngineDesc *desc = context->engine ? + bus_engine_proxy_get_desc (context->engine) : + BUS_INPUT_CONTEXT_GET_CLASS (context)->default_engine_desc; + + + g_dbus_method_invocation_return_value (invocation, + g_variant_new ("(v)", ibus_serializable_serialize ((IBusSerializable *)desc))); } /** @@ -1071,7 +991,7 @@ _ic_set_surrounding_text (BusInputContext *context, g_variant_unref (variant); if ((context->capabilities & IBUS_CAP_SURROUNDING_TEXT) && - context->has_focus && context->enabled && context->engine) { + context->has_focus && context->engine) { bus_engine_proxy_set_surrounding_text (context->engine, text, cursor_pos, @@ -1121,9 +1041,6 @@ bus_input_context_service_method_call (IBusService *service, { "Reset", _ic_reset }, { "SetCapabilities", _ic_set_capabilities }, { "PropertyActivate", _ic_property_activate }, - { "Enable", _ic_enable }, - { "Disable", _ic_disable }, - { "IsEnabled", _ic_is_enabled }, { "SetEngine", _ic_set_engine }, { "GetEngine", _ic_get_engine }, { "SetSurroundingText", _ic_set_surrounding_text}, @@ -1163,7 +1080,7 @@ bus_input_context_focus_in (BusInputContext *context) context->prev_keyval = IBUS_VoidSymbol; context->prev_modifiers = 0; - if (context->engine == NULL && context->enabled) { + if (context->engine == NULL) { /* request an engine, e.g. a global engine if the feature is enabled. */ IBusEngineDesc *desc = NULL; g_signal_emit (context, @@ -1181,7 +1098,7 @@ bus_input_context_focus_in (BusInputContext *context) } } - if (context->engine && context->enabled) { + if (context->engine) { bus_engine_proxy_focus_in (context->engine); bus_engine_proxy_enable (context->engine); bus_engine_proxy_set_capabilities (context->engine, context->capabilities); @@ -1190,7 +1107,7 @@ bus_input_context_focus_in (BusInputContext *context) if (context->capabilities & IBUS_CAP_FOCUS) { g_signal_emit (context, context_signals[FOCUS_IN], 0); - if (context->engine && context->enabled) { + if (context->engine) { /* if necessary, emit glib signals to the context object to update panel status. see the comment for PREEDIT_CONDITION * for details. */ if (context->preedit_visible && !PREEDIT_CONDITION) { @@ -1252,7 +1169,7 @@ bus_input_context_focus_out (BusInputContext *context) bus_input_context_update_lookup_table (context, lookup_table_empty, FALSE); bus_input_context_register_properties (context, props_empty); - if (context->engine && context->enabled) { + if (context->engine) { bus_engine_proxy_focus_out (context->engine); } @@ -1269,7 +1186,7 @@ bus_input_context_focus_out (BusInputContext *context) { \ g_assert (BUS_IS_INPUT_CONTEXT (context)); \ \ - if (context->has_focus && context->enabled && context->engine) { \ + if (context->has_focus && context->engine) { \ bus_engine_proxy_##name (context->engine); \ } \ } @@ -1289,7 +1206,7 @@ bus_input_context_candidate_clicked (BusInputContext *context, { g_assert (BUS_IS_INPUT_CONTEXT (context)); - if (context->enabled && context->engine) { + if (context->engine) { bus_engine_proxy_candidate_clicked (context->engine, index, button, @@ -1304,7 +1221,7 @@ bus_input_context_property_activate (BusInputContext *context, { g_assert (BUS_IS_INPUT_CONTEXT (context)); - if (context->enabled && context->engine) { + if (context->engine) { bus_engine_proxy_property_activate (context->engine, prop_name, prop_state); } } @@ -1315,9 +1232,6 @@ bus_input_context_commit_text (BusInputContext *context, { g_assert (BUS_IS_INPUT_CONTEXT (context)); - if (!context->enabled) - return; - if (text == text_empty || text == NULL) return; @@ -1829,9 +1743,6 @@ _engine_forward_key_event_cb (BusEngineProxy *engine, g_assert (context->engine == engine); - if (!context->enabled) - return; - bus_input_context_emit_signal (context, "ForwardKeyEvent", g_variant_new ("(uuu)", keyval, keycode, state), @@ -1854,9 +1765,6 @@ _engine_delete_surrounding_text_cb (BusEngineProxy *engine, g_assert (context->engine == engine); - if (!context->enabled) - return; - bus_input_context_emit_signal (context, "DeleteSurroundingText", g_variant_new ("(iu)", offset_from_cursor, nchars), @@ -1877,9 +1785,6 @@ _engine_require_surrounding_text_cb (BusEngineProxy *engine, g_assert (context->engine == engine); - if (!context->enabled) - return; - bus_input_context_emit_signal (context, "RequireSurroundingText", NULL, @@ -1905,9 +1810,6 @@ _engine_update_preedit_text_cb (BusEngineProxy *engine, g_assert (context->engine == engine); - if (!context->enabled) - return; - bus_input_context_update_preedit_text (context, text, cursor_pos, visible, mode); } @@ -1928,9 +1830,6 @@ _engine_update_auxiliary_text_cb (BusEngineProxy *engine, g_assert (context->engine == engine); - if (!context->enabled) - return; - bus_input_context_update_auxiliary_text (context, text, visible); } @@ -1951,9 +1850,6 @@ _engine_update_lookup_table_cb (BusEngineProxy *engine, g_assert (context->engine == engine); - if (!context->enabled) - return; - bus_input_context_update_lookup_table (context, table, visible); } @@ -1973,9 +1869,6 @@ _engine_register_properties_cb (BusEngineProxy *engine, g_assert (context->engine == engine); - if (!context->enabled) - return; - bus_input_context_register_properties (context, props); } @@ -1995,9 +1888,6 @@ _engine_update_property_cb (BusEngineProxy *engine, g_assert (context->engine == engine); - if (!context->enabled) - return; - bus_input_context_update_property (context, prop); } @@ -2011,9 +1901,6 @@ _engine_update_property_cb (BusEngineProxy *engine, \ g_assert (context->engine == engine); \ \ - if (!context->enabled) \ - return; \ - \ bus_input_context_##name (context); \ } @@ -2077,7 +1964,6 @@ bus_input_context_enable (BusInputContext *context) g_assert (BUS_IS_INPUT_CONTEXT (context)); if (!context->has_focus) { - context->enabled = TRUE; /* FIXME Do we need to emit "enabled" signal? */ return; } @@ -2101,20 +1987,10 @@ bus_input_context_enable (BusInputContext *context) if (context->engine == NULL) return; - context->enabled = TRUE; - bus_engine_proxy_focus_in (context->engine); bus_engine_proxy_enable (context->engine); bus_engine_proxy_set_capabilities (context->engine, context->capabilities); bus_engine_proxy_set_cursor_location (context->engine, context->x, context->y, context->w, context->h); - - bus_input_context_emit_signal (context, - "Enabled", - NULL, - NULL); - g_signal_emit (context, - context_signals[ENABLED], - 0); } void @@ -2131,24 +2007,6 @@ bus_input_context_disable (BusInputContext *context) bus_engine_proxy_focus_out (context->engine); bus_engine_proxy_disable (context->engine); } - - bus_input_context_emit_signal (context, - "Disabled", - NULL, - NULL); - g_signal_emit (context, - context_signals[DISABLED], - 0); - - context->enabled = FALSE; -} - -gboolean -bus_input_context_is_enabled (BusInputContext *context) -{ - g_assert (BUS_IS_INPUT_CONTEXT (context)); - - return context->enabled; } /* A list of signals (and their handler functions) that could be emit by the engine proxy object. */ @@ -2228,7 +2086,7 @@ bus_input_context_set_engine (BusInputContext *context, engine_signals[i].callback, context); } - if (context->has_focus && context->enabled) { + if (context->has_focus) { bus_engine_proxy_focus_in (context->engine); bus_engine_proxy_enable (context->engine); bus_engine_proxy_set_capabilities (context->engine, context->capabilities); @@ -2461,44 +2319,6 @@ bus_input_context_get_engine_desc (BusInputContext *context) return NULL; } -static gboolean -bus_input_context_filter_keyboard_shortcuts (BusInputContext *context, - guint keyval, - guint keycode, - guint modifiers) -{ - g_assert (BUS_IS_INPUT_CONTEXT (context)); - - gboolean retval = FALSE; - - if (context->filter_release){ - if (modifiers & IBUS_RELEASE_MASK) { - /* filter release key event */ - return TRUE; - } - else { - /* stop filter release key event */ - context->filter_release = FALSE; - } - } - - retval = bus_ibus_impl_filter_keyboard_shortcuts (BUS_DEFAULT_IBUS, - context, - keyval, - modifiers, - context->prev_keyval, - context->prev_modifiers); - context->prev_keyval = keyval; - context->prev_modifiers = modifiers; - - if (retval == TRUE) { - /* begin filter release key event */ - context->filter_release = TRUE; - } - - return retval; -} - guint bus_input_context_get_capabilities (BusInputContext *context) { diff --git a/bus/inputcontext.h b/bus/inputcontext.h index bc4e096e..b76d02de 100644 --- a/bus/inputcontext.h +++ b/bus/inputcontext.h @@ -91,12 +91,6 @@ void bus_input_context_enable (BusInputContext *con */ void bus_input_context_disable (BusInputContext *context); -/** - * bus_input_context_is_enabled: - * @returns: context->enabled. - */ -gboolean bus_input_context_is_enabled (BusInputContext *context); - /** * bus_input_context_page_up: * diff --git a/bus/panelproxy.c b/bus/panelproxy.c index 30059098..7bf13ab2 100644 --- a/bus/panelproxy.c +++ b/bus/panelproxy.c @@ -625,8 +625,6 @@ static const struct { { "register-properties", G_CALLBACK (_context_register_properties_cb) }, { "update-property", G_CALLBACK (_context_update_property_cb) }, - { "enabled", G_CALLBACK (_context_state_changed_cb) }, - { "disabled", G_CALLBACK (_context_state_changed_cb) }, { "engine-changed", G_CALLBACK (_context_state_changed_cb) }, { "destroy", G_CALLBACK (_context_destroy_cb) }, diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c index 72db581d..1fcd2b2c 100644 --- a/client/gtk2/ibusimcontext.c +++ b/client/gtk2/ibusimcontext.c @@ -47,8 +47,6 @@ struct _IBusIMContext { GtkIMContext *slave; GdkWindow *client_window; - /* enabled */ - gboolean enable; IBusInputContext *ibuscontext; /* preedit status */ @@ -271,7 +269,7 @@ _process_key_event_done (GObject *object, static void _request_surrounding_text (IBusIMContext *context) { - if (context && context->enable && + if (context && (context->caps & IBUS_CAP_SURROUNDING_TEXT) != 0 && context->ibuscontext != NULL && ibus_input_context_needs_surrounding_text (context->ibuscontext)) { @@ -566,9 +564,6 @@ ibus_im_context_init (GObject *obj) ibusimcontext->client_window = NULL; - // Init ibus status - ibusimcontext->enable = FALSE; - // Init preedit status ibusimcontext->preedit_string = NULL; ibusimcontext->preedit_attrs = NULL; @@ -840,36 +835,31 @@ ibus_im_context_get_preedit_string (GtkIMContext *context, IBusIMContext *ibusimcontext = IBUS_IM_CONTEXT (context); - if (ibusimcontext->enable) { - if (ibusimcontext->preedit_visible) { - if (str) { - *str = g_strdup (ibusimcontext->preedit_string ? ibusimcontext->preedit_string: ""); - } - - if (attrs) { - *attrs = ibusimcontext->preedit_attrs ? - pango_attr_list_ref (ibusimcontext->preedit_attrs): - pango_attr_list_new (); - } - - if (cursor_pos) { - *cursor_pos = ibusimcontext->preedit_cursor_pos; - } + if (ibusimcontext->preedit_visible) { + if (str) { + *str = g_strdup (ibusimcontext->preedit_string ? ibusimcontext->preedit_string: ""); } - else { - if (str) { - *str = g_strdup (""); - } - if (attrs) { - *attrs = pango_attr_list_new (); - } - if (cursor_pos) { - *cursor_pos = 0; - } + + if (attrs) { + *attrs = ibusimcontext->preedit_attrs ? + pango_attr_list_ref (ibusimcontext->preedit_attrs): + pango_attr_list_new (); + } + + if (cursor_pos) { + *cursor_pos = ibusimcontext->preedit_cursor_pos; } } else { - gtk_im_context_get_preedit_string (ibusimcontext->slave, str, attrs, cursor_pos); + if (str) { + *str = g_strdup (""); + } + if (attrs) { + *attrs = pango_attr_list_new (); + } + if (cursor_pos) { + *cursor_pos = 0; + } } IDEBUG ("str=%s", *str); } @@ -1040,7 +1030,7 @@ ibus_im_context_set_surrounding (GtkIMContext *context, IBusIMContext *ibusimcontext = IBUS_IM_CONTEXT (context); - if (ibusimcontext->enable && ibusimcontext->ibuscontext) { + if (ibusimcontext->ibuscontext) { IBusText *ibustext; guint cursor_pos; guint utf8_len; @@ -1399,36 +1389,6 @@ _ibus_context_hide_preedit_text_cb (IBusInputContext *ibuscontext, g_signal_emit (ibusimcontext, _signal_preedit_end_id, 0); } -static void -_ibus_context_enabled_cb (IBusInputContext *ibuscontext, - IBusIMContext *ibusimcontext) -{ - IDEBUG ("%s", __FUNCTION__); - - ibusimcontext->enable = TRUE; - - /* retrieve the initial surrounding-text (regardless of whether - * the current IBus engine needs surrounding-text) */ - _request_surrounding_text (ibusimcontext); -} - -static void -_ibus_context_disabled_cb (IBusInputContext *ibuscontext, - IBusIMContext *ibusimcontext) -{ - IDEBUG ("%s", __FUNCTION__); - ibusimcontext->enable = FALSE; - - /* clear preedit */ - ibusimcontext->preedit_visible = FALSE; - ibusimcontext->preedit_cursor_pos = 0; - g_free (ibusimcontext->preedit_string); - ibusimcontext->preedit_string = NULL; - - g_signal_emit (ibusimcontext, _signal_preedit_changed_id, 0); - g_signal_emit (ibusimcontext, _signal_preedit_end_id, 0); -} - static void _ibus_context_destroy_cb (IBusInputContext *ibuscontext, IBusIMContext *ibusimcontext) @@ -1439,8 +1399,6 @@ _ibus_context_destroy_cb (IBusInputContext *ibuscontext, g_object_unref (ibusimcontext->ibuscontext); ibusimcontext->ibuscontext = NULL; - ibusimcontext->enable = FALSE; - /* clear preedit */ ibusimcontext->preedit_visible = FALSE; ibusimcontext->preedit_cursor_pos = 0; @@ -1497,14 +1455,6 @@ _create_input_context_done (IBusBus *bus, "hide-preedit-text", G_CALLBACK (_ibus_context_hide_preedit_text_cb), ibusimcontext); - g_signal_connect (ibusimcontext->ibuscontext, - "enabled", - G_CALLBACK (_ibus_context_enabled_cb), - ibusimcontext); - g_signal_connect (ibusimcontext->ibuscontext, - "disabled", - G_CALLBACK (_ibus_context_disabled_cb), - ibusimcontext); g_signal_connect (ibusimcontext->ibuscontext, "destroy", G_CALLBACK (_ibus_context_destroy_cb), ibusimcontext); @@ -1549,10 +1499,6 @@ _slave_commit_cb (GtkIMContext *slave, gchar *string, IBusIMContext *ibusimcontext) { -#if 0 - if ((GtkIMContext *)context == CURRENT_CONTEXT && ibus_im_client_is_enabled (_client)) - return; -#endif g_signal_emit (ibusimcontext, _signal_commit_id, 0, string); } @@ -1560,7 +1506,7 @@ static void _slave_preedit_changed_cb (GtkIMContext *slave, IBusIMContext *ibusimcontext) { - if (ibusimcontext->enable && ibusimcontext->ibuscontext) { + if (ibusimcontext->ibuscontext) { return; } @@ -1571,7 +1517,7 @@ static void _slave_preedit_start_cb (GtkIMContext *slave, IBusIMContext *ibusimcontext) { - if (ibusimcontext->enable && ibusimcontext->ibuscontext) { + if (ibusimcontext->ibuscontext) { return; } @@ -1582,7 +1528,7 @@ static void _slave_preedit_end_cb (GtkIMContext *slave, IBusIMContext *ibusimcontext) { - if (ibusimcontext->enable && ibusimcontext->ibuscontext) { + if (ibusimcontext->ibuscontext) { return; } g_signal_emit (ibusimcontext, _signal_preedit_end_id, 0); @@ -1594,7 +1540,7 @@ _slave_retrieve_surrounding_cb (GtkIMContext *slave, { gboolean return_value; - if (ibusimcontext->enable && ibusimcontext->ibuscontext) { + if (ibusimcontext->ibuscontext) { return FALSE; } g_signal_emit (ibusimcontext, _signal_retrieve_surrounding_id, 0, @@ -1610,7 +1556,7 @@ _slave_delete_surrounding_cb (GtkIMContext *slave, { gboolean return_value; - if (ibusimcontext->enable && ibusimcontext->ibuscontext) { + if (ibusimcontext->ibuscontext) { return FALSE; } g_signal_emit (ibusimcontext, _signal_delete_surrounding_id, 0, offset_from_cursor, nchars, &return_value); diff --git a/configure.ac b/configure.ac index 94563978..53fac5ec 100644 --- a/configure.ac +++ b/configure.ac @@ -105,6 +105,7 @@ AC_SUBST(DATE_DISPLAY) AC_PROG_CC AM_PROG_CC_C_O AC_PROG_CC_STDC +AM_PROG_VALAC([0.14]) AC_PROG_INSTALL AC_PROG_MAKE_SET @@ -473,6 +474,7 @@ ui/Makefile ui/gtk/Makefile ui/gtk/ibus-ui-gtk ui/gtk/gtkpanel.xml.in +ui/gtk3/Makefile setup/Makefile setup/ibus-setup gconf/Makefile diff --git a/ibus/bus.py b/ibus/bus.py index a8a458d9..179fd4ea 100644 --- a/ibus/bus.py +++ b/ibus/bus.py @@ -137,6 +137,10 @@ class Bus(object.Object): def list_engines(self): engines = self.__ibus.ListEngines() return map(serializable.deserialize_object, engines) + + def get_engines_by_names(self, names): + engines = self.__ibus.GetEnginesByNames(names) + return map(serializable.deserialize_object, engines) def list_active_engines(self): engines = self.__ibus.ListActiveEngines() diff --git a/ibus/inputcontext.py b/ibus/inputcontext.py index 64a6ba23..a2989091 100644 --- a/ibus/inputcontext.py +++ b/ibus/inputcontext.py @@ -153,10 +153,6 @@ class InputContext(object.Object): self.__signal_matches.append(m) m = self.__context.connect_to_signal("RequireSurroundingText", self.__require_surrounding_text_cb) self.__signal_matches.append(m) - m = self.__context.connect_to_signal("Enabled", self.__enabled_cb) - self.__signal_matches.append(m) - m = self.__context.connect_to_signal("Disabled", self.__disabled_cb) - self.__signal_matches.append(m) m = self.__context.connect_to_signal("ForwardKeyEvent", lambda *args: self.emit("forward-key-event", *args)) self.__signal_matches.append(m) @@ -185,14 +181,6 @@ class InputContext(object.Object): m = self.__context.connect_to_signal("CursorDownLookupTable", lambda *args: self.emit("cursor-down-lookup-table")) self.__signal_matches.append(m) - def __enabled_cb(self, *args): - self.__needs_surrounding_text = False - self.emit("enabled") - - def __disabled_cb(self, *args): - self.__needs_surrounding_text = False - self.emit("disabled") - def __commit_text_cb(self, *args): text = serializable.deserialize_object(args[0]) self.emit("commit-text", text) @@ -253,15 +241,6 @@ class InputContext(object.Object): def reset(self): return self.__context.Reset() - def enable(self): - return self.__context.Enable() - - def disable(self): - return self.__context.Disable() - - def is_enabled(self): - return self.__context.IsEnabled() - def set_capabilities(self, caps): caps = dbus.UInt32(caps) return self.__context.SetCapabilities(caps) @@ -319,8 +298,6 @@ def test(): self.__context.connect("show-preedit-text", self.__show_preedit_text_cb) self.__context.connect("update-auxiliary-text", self.__update_auxiliary_text_cb) self.__context.connect("update-lookup-table", self.__update_lookup_table_cb) - self.__context.connect("enabled", self.__enabled_cb) - self.__context.connect("disabled", self.__disabled_cb) self.set_events(gtk.gdk.KEY_PRESS_MASK | gtk.gdk.KEY_RELEASE_MASK | gtk.gdk.FOCUS_CHANGE_MASK) @@ -350,14 +327,6 @@ def test(): def __update_lookup_table_cb(self, context, table, visible): print "update-lookup-table:", visible - def __enabled_cb(self, context): - print "enabled" - info = context.get_factory_info() - print "factory = %s" % info.name - - def __disabled_cb(self, context): - print "disabled" - def __key_press_event_cb(self, widget, event): self.__context.process_key_event(event.keyval, event.state) diff --git a/ibus/interface/iibus.py b/ibus/interface/iibus.py index 678d5179..99874c41 100644 --- a/ibus/interface/iibus.py +++ b/ibus/interface/iibus.py @@ -62,6 +62,9 @@ class IIBus(dbus.service.Object): @method(out_signature="av") def ListEngines(self, dbusconn): pass + + @method(in_signature="as", out_signature="av") + def GetEnginesByNames(self, names, dbusconn): pass @method(out_signature="av") def ListActiveEngines(self, dbusconn): pass diff --git a/ibus/interface/iinputcontext.py b/ibus/interface/iinputcontext.py index 06ce519b..62047919 100644 --- a/ibus/interface/iinputcontext.py +++ b/ibus/interface/iinputcontext.py @@ -61,15 +61,6 @@ class IInputContext(dbus.service.Object): @method() def Reset(self): pass - @method() - def Enable(self): pass - - @method() - def Disable(self): pass - - @method(out_signature="b") - def IsEnabled(self): pass - @method(in_signature="u") def SetCapabilities(self, caps): pass @@ -86,12 +77,6 @@ class IInputContext(dbus.service.Object): @signal(signature="v") def CommitText(self, text): pass - @signal() - def Enabled(self): pass - - @signal() - def Disabled(self): pass - @signal(signature="uuu") def ForwardKeyEvent(self, keyval, keycode, state): pass diff --git a/src/ibusbus.c b/src/ibusbus.c index 2607448b..61374417 100644 --- a/src/ibusbus.c +++ b/src/ibusbus.c @@ -1478,6 +1478,37 @@ ibus_bus_list_active_engines_async_finish (IBusBus *bus, return ibus_bus_list_engines_async_finish (bus, res, error); } +IBusEngineDesc ** +ibus_bus_get_engines_by_names (IBusBus *bus, + const gchar * const *names) +{ + g_return_val_if_fail (IBUS_IS_BUS (bus), NULL); + + GVariant *result; + result = ibus_bus_call_sync (bus, + IBUS_SERVICE_IBUS, + IBUS_PATH_IBUS, + IBUS_INTERFACE_IBUS, + "GetEnginesByNames", + g_variant_new("(^as)", names), + G_VARIANT_TYPE ("(av)")); + if (result == NULL) + return NULL; + + GArray *array = g_array_new (TRUE, TRUE, sizeof (IBusEngineDesc *)); + GVariantIter *iter = NULL; + g_variant_get (result, "(av)", &iter); + GVariant *var; + while (g_variant_iter_loop (iter, "v", &var)) { + IBusEngineDesc *desc = (IBusEngineDesc *) ibus_serializable_deserialize (var); + g_array_append_val (array, desc); + } + g_variant_iter_free (iter); + g_variant_unref (result); + + return (IBusEngineDesc **)g_array_free (array, FALSE); +} + static void _config_destroy_cb (IBusConfig *config, IBusBus *bus) diff --git a/src/ibusbus.h b/src/ibusbus.h index 7c4fdeed..abcf2c4b 100644 --- a/src/ibusbus.h +++ b/src/ibusbus.h @@ -710,6 +710,19 @@ GList *ibus_bus_list_active_engines_async_finish GAsyncResult *res, GError **error); +/** + * ibus_bus_get_engines_by_names: + * @bus: An #IBusBus. + * @names: A %NULL-terminated array of names. + * @returns: (transfer container) (element-type IBusEngineDesc): A %NULL-terminated array of engines. + * + * Get engines by given names synchronously. + * TODO(penghuang): add asynchronous version + */ +IBusEngineDesc ** + ibus_bus_get_engines_by_names + (IBusBus *bus, + const gchar * const *names); /** * ibus_bus_get_use_sys_layout: * @bus: An #IBusBus. diff --git a/src/ibusinputcontext.c b/src/ibusinputcontext.c index 54e30aea..fa8301b0 100644 --- a/src/ibusinputcontext.c +++ b/src/ibusinputcontext.c @@ -1009,45 +1009,6 @@ ibus_input_context_property_hide (IBusInputContext *context, ); } -void -ibus_input_context_is_enabled_async (IBusInputContext *context, - gint timeout_msec, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - g_assert (IBUS_IS_INPUT_CONTEXT (context)); - g_dbus_proxy_call ((GDBusProxy *) context, - "IsEnabled", /* method_name */ - NULL, /* parameters */ - G_DBUS_CALL_FLAGS_NONE, /* flags */ - timeout_msec, - cancellable, - callback, - user_data); -} - -gboolean -ibus_input_context_is_enabled_async_finish (IBusInputContext *context, - GAsyncResult *res, - GError **error) -{ - g_assert (IBUS_IS_INPUT_CONTEXT (context)); - g_assert (G_IS_ASYNC_RESULT (res)); - g_assert (error == NULL || *error == NULL); - - gboolean enabled = FALSE; - - GVariant *variant = g_dbus_proxy_call_finish ((GDBusProxy *) context, - res, error); - if (variant != NULL) { - g_variant_get (variant, "(b)", &enabled); - g_variant_unref (variant); - } - - return enabled; -} - void ibus_input_context_set_surrounding_text (IBusInputContext *context, IBusText *text, @@ -1096,34 +1057,6 @@ ibus_input_context_needs_surrounding_text (IBusInputContext *context) return priv->needs_surrounding_text; } -gboolean -ibus_input_context_is_enabled (IBusInputContext *context) -{ - g_assert (IBUS_IS_INPUT_CONTEXT (context)); - GVariant *result; - GError *error = NULL; - result = g_dbus_proxy_call_sync ((GDBusProxy *) context, - "IsEnabled", /* method_name */ - NULL, /* parameters */ - G_DBUS_CALL_FLAGS_NONE, /* flags */ - -1, /* timeout */ - NULL, /* cancellable */ - &error /* error */ - ); - - if (result == NULL) { - g_warning ("%s.IsEnabled: %s", IBUS_INTERFACE_INPUT_CONTEXT, error->message); - g_error_free (error); - return FALSE; - } - - gboolean retval = FALSE; - g_variant_get (result, "(b)", &retval); - g_variant_unref (result); - - return retval; -} - void ibus_input_context_get_engine_async (IBusInputContext *context, gint timeout_msec, @@ -1242,6 +1175,4 @@ DEFINE_FUNC(page_up, PageUp); DEFINE_FUNC(page_down, PageDown); DEFINE_FUNC(cursor_up, CursorUp); DEFINE_FUNC(cursor_down, CursorDown); -DEFINE_FUNC(enable, Enable); -DEFINE_FUNC(disable, Disable); #undef DEFINE_FUNC diff --git a/src/ibusinputcontext.h b/src/ibusinputcontext.h index f584de31..659732b1 100644 --- a/src/ibusinputcontext.h +++ b/src/ibusinputcontext.h @@ -371,73 +371,6 @@ void ibus_input_context_focus_out (IBusInputContext *context); */ void ibus_input_context_reset (IBusInputContext *context); -/** - * ibus_input_context_enable: - * @context: An IBusInputContext. - * - * Invoked when the IME is enabled, either by IME switch hotkey or select from the menu. - * An asynchronous IPC will be performed. - * - * see_also: #IBusEngine::enable - */ -void ibus_input_context_enable (IBusInputContext *context); - -/** - * ibus_input_context_disable: - * @context: An IBusInputContext. - * - * Invoked when the IME is disabled, either by IME switch hotkey or select from the menu. - * An asynchronous IPC will be performed. - * - * see_also: #IBusEngine::disable - */ -void ibus_input_context_disable (IBusInputContext *context); - - -/** - * ibus_input_context_is_enabled_async: - * @context: An #IBusInputContext. - * @timeout_msec: The timeout in milliseconds or -1 to use the default timeout. - * @cancellable: A #GCancellable or %NULL. - * @callback: A #GAsyncReadyCallback to call when the request is satisfied or %NULL - * if you don't care about the result of the method invocation. - * @user_data: The data to pass to callback. - * - * An asynchronous IPC will be performed. - */ -void ibus_input_context_is_enabled_async - (IBusInputContext *context, - gint timeout_msec, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -/** - * ibus_input_context_is_enabled_async_finish: - * @context: An #IBusInputContext. - * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to - * ibus_input_context_is_enabled_async(). - * @error: Return location for error or %NULL. - * @returns: %TRUE if the IME is enabled on the contextfor success; - * %FALSE otherwise or some errors happen and the @error will be set. - * - * Finishes an operation started with ibus_input_context_is_enabled_async(). - */ -gboolean ibus_input_context_is_enabled_async_finish - (IBusInputContext *context, - GAsyncResult *res, - GError **error); - -/** - * ibus_input_context_is_enabled: - * @context: An IBusInputContext. - * @returns: TRUE if the IME is enabled on the context. - * - * Returns TRUE if the IME is enabled on the context. - * A asynchronous IPC will be performed. - */ -gboolean ibus_input_context_is_enabled (IBusInputContext *context); - /** * ibus_input_context_get_engine_async: * @context: An #IBusInputContext. diff --git a/src/tests/ibus-inputcontext.c b/src/tests/ibus-inputcontext.c index 846e635d..9053ca02 100644 --- a/src/tests/ibus-inputcontext.c +++ b/src/tests/ibus-inputcontext.c @@ -56,10 +56,6 @@ call_basic_ipcs (IBusInputContext *context) ibus_input_context_set_capabilities (context, IBUS_CAP_FOCUS); ibus_input_context_property_activate (context, "dummy.prop.name", PROP_STATE_CHECKED); ibus_input_context_reset (context); - ibus_input_context_disable (context); - /* g_assert (ibus_input_context_is_enabled (context) == FALSE); */ /* see below. */ - ibus_input_context_enable (context); - /* g_assert (ibus_input_context_is_enabled (context) == TRUE); */ /* see below. */ /* When enable() is called, ibus-daemon may start a global (or preloaded, * or default) engine in an asynchrnous manner and return immediately. @@ -119,31 +115,6 @@ test_input_context (void) g_list_free (engines); } -static void -finish_is_enabled_async (GObject *source_object, - GAsyncResult *res, - gpointer user_data) -{ - IBusInputContext *context = IBUS_INPUT_CONTEXT (source_object); - GError *error = NULL; - gboolean result = ibus_input_context_is_enabled_async_finish (context, - res, - &error); - g_assert (result); - g_debug ("ibus_context_is_enabled_async_finish: OK"); - call_next_async_function (context); -} - -static void -start_is_enabled_async (IBusInputContext *context) -{ - ibus_input_context_is_enabled_async (context, - -1, /* timeout */ - NULL, /* cancellable */ - finish_is_enabled_async, - NULL); /* user_data */ -} - static void finish_get_engine_async (GObject *source_object, GAsyncResult *res, @@ -220,7 +191,6 @@ static void call_next_async_function (IBusInputContext *context) { static void (*async_functions[])(IBusInputContext *) = { - start_is_enabled_async, start_get_engine_async, start_process_key_event_async, }; diff --git a/ui/Makefile.am b/ui/Makefile.am index ba6d4ffb..b28e03f2 100644 --- a/ui/Makefile.am +++ b/ui/Makefile.am @@ -23,6 +23,7 @@ if ENABLE_PYTHON SUBDIRS = \ gtk \ + gtk3 \ $(NULL) endif diff --git a/ui/gtk/candidatepanel.py b/ui/gtk/candidatepanel.py index 462c7021..159b2bcf 100644 --- a/ui/gtk/candidatepanel.py +++ b/ui/gtk/candidatepanel.py @@ -202,7 +202,6 @@ class CandidatePanel(gtk.VBox): gdk.BUTTON_PRESS_MASK | \ gdk.BUTTON_RELEASE_MASK | \ gdk.BUTTON1_MOTION_MASK) - self.__begin_move = False self.__toplevel.connect("size-allocate", lambda w, a: self.__check_position()) self.__orientation = ibus.ORIENTATION_VERTICAL diff --git a/ui/gtk/languagebar.py b/ui/gtk/languagebar.py index c642d8f3..c3701a6e 100644 --- a/ui/gtk/languagebar.py +++ b/ui/gtk/languagebar.py @@ -354,7 +354,7 @@ class LanguageBar(gtk.Toolbar): self.__properties.append(item) menu.insert(item, 0) - about_label = _("About") + " - " + self.__im_name + about_label = _("About") + " - " + (self.__im_name or "") prop = ibus.Property(key=u"about", label=unicode(about_label), icon=unicode(gtk.STOCK_ABOUT), diff --git a/ui/gtk/panel.py b/ui/gtk/panel.py index f71a36da..42dde5d0 100644 --- a/ui/gtk/panel.py +++ b/ui/gtk/panel.py @@ -220,7 +220,7 @@ class Panel(ibus.PanelBase): def focus_in(self, ic): self.reset() self.__focus_ic = ibus.InputContext(self.__bus, ic) - enabled = self.__focus_ic.is_enabled() + enabled = True or self.__focus_ic.is_enabled() self.__language_bar.set_enabled(enabled) if not enabled: @@ -414,7 +414,11 @@ class Panel(ibus.PanelBase): # return menu def __create_im_menu(self): - engines = self.__bus.list_active_engines() + # FIXME + # engines = self.__bus.list_engines() + names = self.__config.get_value("general", "preload_engines", + ["xkb:us::eng", "xkb:us:intl:eng", "pinyin"]) + engines = self.__bus.get_engines_by_names(names) current_engine = \ (self.__focus_ic != None and self.__focus_ic.get_engine()) or \ (engines and engines[0]) or \ @@ -439,7 +443,7 @@ class Panel(ibus.PanelBase): item = gtk.ImageMenuItem(_("Turn off input method")) item.set_image(_icon.IconWidget("gtk-close", size[0])) item.connect("activate", self.__im_menu_item_activate_cb, None) - if self.__focus_ic == None or not self.__focus_ic.is_enabled(): + if self.__focus_ic == None: item.set_sensitive(False) menu.add(item) diff --git a/ui/gtk3/Makefile.am b/ui/gtk3/Makefile.am new file mode 100644 index 00000000..1483a911 --- /dev/null +++ b/ui/gtk3/Makefile.am @@ -0,0 +1,84 @@ +# vim:set noet ts=4: +# +# ibus - The Input Bus +# +# Copyright (c) 2007-2010 Peng Huang +# Copyright (c) 2007-2010 Red Hat, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place, Suite 330, +# Boston, MA 02111-1307 USA + +NULL = + +libibus = $(top_builddir)/src/libibus-@IBUS_API_VERSION@.la + +INCLUDES = \ + -I$(top_srcdir)/src \ + -I$(top_builddir)/src \ + $(NULL) + +AM_CFLAGS = \ + @GLIB2_CFLAGS@ \ + @GIO2_CFLAGS@ \ + @GTHREAD2_CFLAGS@ \ + @GTK3_CFLAGS@ \ + @X11_CFLAGS@ \ + -DG_LOG_DOMAIN=\"IBUS\" \ + -DPKGDATADIR=\"$(pkgdatadir)\" \ + -DLIBEXECDIR=\"$(libexecdir)\" \ + -DBINDIR=\"@bindir@\" \ + $(INCLUDES) \ + $(NULL) + +AM_LDADD = \ + @GOBJECT2_LIBS@ \ + @GLIB2_LIBS@ \ + @GIO2_LIBS@ \ + @GTHREAD2_LIBS@ \ + @GTK3_LIBS@ \ + @X11_LIBS@ \ + $(libibus) \ + $(NULL) + +AM_VALAFLAGS = \ + --vapidir=$(top_builddir)/bindings/vala \ + --pkg=gtk+-3.0 \ + --pkg=gdk-x11-3.0 \ + --pkg=ibus-1.0 \ + $(NULL) + +bin_PROGRAMS = ibus-ui-gtk3 + +ibus_ui_gtk3_SOURCES = \ + application.vala \ + candidatearea.vala \ + candidatepanel.vala \ + handle.vala \ + iconwidget.vala \ + keybindingmanager.vala \ + panel.vala \ + pango.vala \ + separator.vala \ + $(NULL) + +ibus_ui_gtk3_CFLAGS = \ + $(AM_CFLAGS) \ + $(NULL) + +ibus_ui_gtk3_LDADD = \ + $(AM_LDADD) \ + $(NULL) + +-include $(top_srcdir)/git.mk diff --git a/ui/gtk3/application.vala b/ui/gtk3/application.vala new file mode 100644 index 00000000..4e7a2a2a --- /dev/null +++ b/ui/gtk3/application.vala @@ -0,0 +1,109 @@ +/* vim:set et sts=4 sw=4: + * + * ibus - The Input Bus + * + * Copyright(c) 2011 Peng Huang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or(at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + */ + +using IBus; +using GLib; +using Gtk; + +class Application { + private IBus.Bus m_bus; + private Panel m_panel; + private KeybindingManager m_keybinding_manager; + + public Application(string[] argv) { + IBus.init(); + Gtk.init(ref argv); + + m_keybinding_manager = new KeybindingManager(); + m_bus = new IBus.Bus(); + m_panel = new Panel(m_bus); + + m_bus.connected.connect(bus_connected); + m_bus.disconnected.connect(bus_disconnected); + + if (m_bus.is_connected()) { + init(); + } + m_keybinding_manager.bind("V", hotkey_triggered); + } + + private void init() { + DBusConnection connection = m_bus.get_connection(); + connection.signal_subscribe("org.freedesktop.DBus", + "org.freedesktop.DBus", + "NameAcquired", + "/org/freedesktop/DBus", + "org.freedesktop.IBus.Panel", + DBusSignalFlags.NONE, + this.bus_name_acquired); + connection.signal_subscribe("org.freedesktop.DBus", + "org.freedesktop.DBus", + "NameLost", + "/org/freedesktop/DBus", + "org.freedesktop.IBus.Panel", + DBusSignalFlags.NONE, + this.bus_name_lost); + + m_bus.request_name("org.freedesktop.IBus.Panel", 2); + } + + public int run() { + Gtk.main(); + return 0; + } + + private void bus_name_acquired(DBusConnection connection, + string sender_name, + string object_path, + string interface_name, + string signal_name, + Variant parameters) { + debug("signal_name = %s", signal_name); + } + + private void bus_name_lost(DBusConnection connection, + string sender_name, + string object_path, + string interface_name, + string signal_name, + Variant parameters) { + debug("signal_name = %s", signal_name); + } + + private void bus_disconnected(IBus.Bus bus) { + debug("connection is lost."); + Gtk.main_quit(); + } + + private void bus_connected(IBus.Bus bus) { + init(); + } + + private void hotkey_triggered() { + debug("hotkey"); + } + + public static void main(string[] argv) { + Application app = new Application(argv); + app.run(); + } +} diff --git a/ui/gtk3/candidatearea.vala b/ui/gtk3/candidatearea.vala new file mode 100644 index 00000000..13ebf769 --- /dev/null +++ b/ui/gtk3/candidatearea.vala @@ -0,0 +1,252 @@ +/* vim:set et sts=4 sw=4: + * + * ibus - The Input Bus + * + * Copyright(c) 2011 Peng Huang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or(at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + */ + +using Gtk; +using IBus; +using Pango; + +class CandidateArea : Gtk.Box { + private bool m_vertical; + private Gtk.Label[] m_labels; + private Gtk.Label[] m_candidates; + private Gtk.Widget[] m_widgets; + + private IBus.Text[] m_ibus_candidates; + private uint m_focus_candidate; + private bool m_show_cursor; + + public signal void candidate_clicked(uint index, uint button, uint state); + public signal void page_up(); + public signal void page_down(); + public signal void cursor_up(); + public signal void cursor_down(); + + public CandidateArea(bool vertical) { + GLib.Object( + orientation: vertical ? Gtk.Orientation.VERTICAL : Gtk.Orientation.HORIZONTAL + ); + m_vertical = vertical; + recreate_ui(); + show_all(); + } + + public void set_vertical(bool vertical) { + if (m_vertical == vertical) + return; + m_vertical = vertical; + recreate_ui(); + + // Workaround a vala issue https://bugzilla.gnome.org/show_bug.cgi?id=661130 + set_candidates((owned)m_ibus_candidates, m_focus_candidate, m_show_cursor); + if (m_candidates.length > 0) + show_all(); + } + + public void set_labels(string[] labels) { + if (labels == null) { + const string labels[] = { + "1.", "2.", "3.", "4.", "5.", "6.", "7.", "8.", + "9.", "0.", "a.", "b.", "c.", "d.", "e.", "f." + }; + for (int i = 0 ; i < 16; i++) + m_labels[i].set_text(labels[i]); + } else { + int i = 0; + foreach (string label in labels) + m_labels[i].set_text(label); + } + } + + public void set_candidates(IBus.Text[] candidates, + uint focus_candidate = 0, + bool show_cursor = true) { + m_ibus_candidates = candidates; + m_focus_candidate = focus_candidate; + m_show_cursor = show_cursor; + + assert(candidates.length < 16); + for (int i = 0 ; i < 16 ; i++) { + Gtk.Label label = m_candidates[i]; + bool visible = false; + if (i < candidates.length) { + Pango.AttrList attrs = get_pango_attr_list_from_ibus_text(candidates[i]); + if (i == focus_candidate && show_cursor) { + Gtk.StyleContext context = m_candidates[i].get_style_context(); + Gdk.RGBA color = context.get_color(Gtk.StateFlags.SELECTED); + Pango.Attribute pango_attr = Pango.attr_foreground_new( + (uint16)(color.red * uint16.MAX), + (uint16)(color.green * uint16.MAX), + (uint16)(color.blue * uint16.MAX)); + pango_attr.start_index = 0; + pango_attr.end_index = candidates[i].get_text().length; + attrs.insert((owned)pango_attr); + + color = context.get_background_color(Gtk.StateFlags.SELECTED); + pango_attr = Pango.attr_background_new( + (uint16)(color.red * uint16.MAX), + (uint16)(color.green * uint16.MAX), + (uint16)(color.blue * uint16.MAX)); + pango_attr.start_index = 0; + pango_attr.end_index = candidates[i].get_text().length; + attrs.insert((owned)pango_attr); + } + label.set_text(candidates[i].get_text()); + label.set_attributes(attrs); + visible = true; + } else { + label.set_text(""); + label.set_attributes(new Pango.AttrList()); + } + if (m_vertical) { + m_widgets[i * 2].set_visible(visible); + m_widgets[i * 2 +1].set_visible(visible); + } else { + m_widgets[i].set_visible(visible); + } + } + } + + private void recreate_ui() { + foreach (Gtk.Widget w in get_children()) { + w.destroy(); + } + + const string labels[] = { + "1.", "2.", "3.", "4.", "5.", "6.", "7.", "8.", + "9.", "0.", "a.", "b.", "c.", "d.", "e.", "f." + }; + + Gtk.Button prev_button = new Gtk.Button(); + prev_button.clicked.connect((b) => page_up()); + prev_button.set_image(new Gtk.Image.from_icon_name(Gtk.Stock.GO_UP, Gtk.IconSize.MENU)); + prev_button.set_relief(Gtk.ReliefStyle.NONE); + + Gtk.Button next_button = new Gtk.Button(); + next_button.clicked.connect((b) => page_down()); + next_button.set_image(new Gtk.Image.from_icon_name(Gtk.Stock.GO_DOWN, Gtk.IconSize.MENU)); + next_button.set_relief(Gtk.ReliefStyle.NONE); + + if (m_vertical) { + // Add Candidates + Gtk.HBox candidates_hbox = new Gtk.HBox(false, 0); + pack_start(candidates_hbox, false, false, 0); + Gtk.VBox labels_vbox = new Gtk.VBox(true, 0); + Gtk.VBox candidates_vbox = new Gtk.VBox(true, 0); + candidates_hbox.pack_start(labels_vbox, false, false, 4); + candidates_hbox.pack_start(new VSeparator(), false, false, 0); + candidates_hbox.pack_start(candidates_vbox, true, true, 4); + + // Add HSeparator + pack_start(new HSeparator(), false, false, 0); + + // Add buttons + Gtk.HBox buttons_hbox = new Gtk.HBox(false, 0); + Gtk.Label state_label = new Gtk.Label(null); + state_label.set_size_request(20, -1); + buttons_hbox.pack_start(state_label, true, true, 0); + buttons_hbox.pack_start(prev_button, false, false, 0); + buttons_hbox.pack_start(next_button, false, false, 0); + pack_start(buttons_hbox, false, false, 0); + + m_labels = {}; + m_candidates = {}; + m_widgets = {}; + for (int i = 0; i < 16; i++) { + Gtk.Label label = new Gtk.Label(labels[i]); + label.set_alignment(0.0f, 0.5f); + label.show(); + m_labels += label; + + Gtk.Label candidate = new Gtk.Label("test"); + candidate.set_alignment(0.0f, 0.5f); + candidate.show(); + m_candidates += candidate; + + label.set_property("xpad", 8); + candidate.set_property("xpad", 8); + + // Make a copy of i to workaround a bug in vala. + // https://bugzilla.gnome.org/show_bug.cgi?id=628336 + int index = i; + Gtk.EventBox label_ebox = new Gtk.EventBox(); + label_ebox.set_no_show_all(true); + label_ebox.button_press_event.connect((w, e) => { + candidate_clicked(i, e.button, e.state); + return true; + }); + label_ebox.add(label); + labels_vbox.pack_start(label_ebox, false, false, 2); + m_widgets += label_ebox; + + Gtk.EventBox candidate_ebox = new Gtk.EventBox(); + candidate_ebox.set_no_show_all(true); + candidate_ebox.button_press_event.connect((w, e) => { + candidate_clicked(index, e.button, e.state); + return true; + }); + candidate_ebox.add(candidate); + candidates_vbox.pack_start(candidate_ebox, false, false, 2); + m_widgets += candidate_ebox; + } + } else { + Gtk.HBox hbox = new Gtk.HBox(false, 0); + add(hbox); + + m_labels = {}; + m_candidates = {}; + m_widgets = {}; + for (int i = 0; i < 16; i++) { + Gtk.Label label = new Gtk.Label(labels[i]); + label.set_alignment(0.0f, 0.5f); + label.show(); + m_labels += label; + + Gtk.Label candidate = new Gtk.Label("test"); + candidate.set_alignment(0.0f, 0.5f); + candidate.show(); + m_candidates += candidate; + + Gtk.HBox candidate_hbox = new Gtk.HBox(false, 0); + candidate_hbox.show(); + candidate_hbox.pack_start(label, false, false, 2); + candidate_hbox.pack_start(candidate, false, false, 2); + + // Make a copy of i to workaround a bug in vala. + // https://bugzilla.gnome.org/show_bug.cgi?id=628336 + int index = i; + Gtk.EventBox ebox = new Gtk.EventBox(); + ebox.set_no_show_all(true); + ebox.button_press_event.connect((w, e) => { + candidate_clicked(index, e.button, e.state); + return true; + }); + ebox.add(candidate_hbox); + hbox.pack_start(ebox, false, false, 4); + m_widgets += ebox; + } + hbox.pack_start(new VSeparator(), false, false, 0); + hbox.pack_start(prev_button, false, false, 0); + hbox.pack_start(next_button, false, false, 0); + } + } +} + diff --git a/ui/gtk3/candidatepanel.vala b/ui/gtk3/candidatepanel.vala new file mode 100644 index 00000000..b31913ef --- /dev/null +++ b/ui/gtk3/candidatepanel.vala @@ -0,0 +1,238 @@ +/* vim:set et sts=4 sw=4: + * + * ibus - The Input Bus + * + * Copyright(c) 2011 Peng Huang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or(at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + */ + +using Gtk; +using Pango; + +class CandidatePanel : Gtk.HBox{ + private bool m_vertical = true; + private Gtk.Window m_toplevel; + private Gtk.VBox m_vbox; + + private Gtk.Label m_preedit_label; + private Gtk.Label m_aux_label; + private CandidateArea m_candidate_area; + private HSeparator m_hseparator; + + private Gdk.Rectangle m_cursor_location; + + public signal void cursor_up(); + public signal void cursor_down(); + public signal void page_up(); + public signal void page_down(); + public signal void candidate_clicked(uint index, + uint button, + uint state); + + public CandidatePanel() { + // Call base class constructor + GLib.Object( + name : "IBusCandidate" + ); + + m_toplevel = new Gtk.Window(Gtk.WindowType.POPUP); + m_toplevel.add_events(Gdk.EventMask.BUTTON_PRESS_MASK); + m_toplevel.button_press_event.connect((w, e) => { + if (e.button != 1 || (e.state & Gdk.ModifierType.CONTROL_MASK) == 0) + return false; + set_vertical(!m_vertical); + return true; + }); + + m_vbox = new Gtk.VBox(false, 0); + Handle handle = new Handle(); + pack_start(handle, false, false, 0); + pack_start(m_vbox, false, false, 0); + + m_toplevel.add(this); + + create_ui(); + } + + public void set_vertical(bool vertical) { + if (m_vertical == vertical) + return; + m_vertical = vertical; + m_candidate_area.set_vertical(vertical); + } + + public void set_cursor_location(int x, int y, int width, int height) { + Gdk.Rectangle location = { x, y, width, height }; + if (m_cursor_location == location) + return; + m_cursor_location = location; + adjust_window_position(); + } + + public void set_labels(string[] labels) { + m_candidate_area.set_labels(labels); + } + + public void set_preedit_text(IBus.Text? text, uint cursor) { + if (text != null) { + m_preedit_label.set_text(text.get_text()); + m_preedit_label.show(); + } else { + m_preedit_label.set_text(""); + m_preedit_label.hide(); + } + update(); + } + + public void set_auxiliary_text(IBus.Text? text) { + if (text != null) { + m_aux_label.set_text(text.get_text()); + m_aux_label.show(); + } else { + m_aux_label.set_text(""); + m_aux_label.hide(); + } + update(); + } + + public void set_lookup_table(IBus.LookupTable? table) { + IBus.Text[] candidates = {}; + uint cursor_in_page = 0; + bool show_cursor = true; + + if (table != null) { + uint page_size = table.get_page_size(); + uint ncandidates = table.get_number_of_candidates(); + uint cursor = table.get_cursor_pos(); + cursor_in_page = table.get_cursor_in_page(); + show_cursor = table.is_cursor_visible(); + + uint page_start_pos = cursor / page_size * page_size; + uint page_end_pos = uint.min(page_start_pos + page_size, ncandidates); + for (uint i = page_start_pos; i < page_end_pos; i++) + candidates += table.get_candidate(i); + } + m_candidate_area.set_candidates(candidates, cursor_in_page, show_cursor); + if (candidates.length != 0) + m_candidate_area.show_all(); + else + m_candidate_area.hide(); + + update(); + } + + private void update() { + if (m_candidate_area.get_visible() || + m_preedit_label.get_visible() || + m_aux_label.get_visible()) + m_toplevel.show(); + else + m_toplevel.hide(); + + if (m_aux_label.get_visible() && + (m_candidate_area.get_visible() || m_preedit_label.get_visible())) + m_hseparator.show(); + else + m_hseparator.hide(); + } + + public override void get_preferred_width(out int minimum_width, out int natural_width) { + base.get_preferred_width(out minimum_width, out natural_width); + m_toplevel.resize(1, 1); + } + + public override void get_preferred_height(out int minimum_width, out int natural_width) { + base.get_preferred_height(out minimum_width, out natural_width); + m_toplevel.resize(1, 1); + } + + private void create_ui() { + m_preedit_label = new Gtk.Label(null); + m_preedit_label.set_size_request(20, -1); + m_preedit_label.set_alignment(0.0f, 0.5f); + m_preedit_label.set_padding(8, 0); + m_preedit_label.set_no_show_all(true); + + m_aux_label = new Gtk.Label(null); + m_aux_label.set_size_request(20, -1); + m_aux_label.set_alignment(0.0f, 0.5f); + m_aux_label.set_padding(8, 0); + m_aux_label.set_no_show_all(true); + + m_candidate_area = new CandidateArea(m_vertical); + m_candidate_area.candidate_clicked.connect((w, i, b, s) => candidate_clicked(i, b, s)); + m_candidate_area.page_up.connect((c) => page_up()); + m_candidate_area.page_down.connect((c) => page_down()); + m_candidate_area.cursor_up.connect((c) => cursor_up()); + m_candidate_area.cursor_down.connect((c) => cursor_down()); + m_candidate_area.show(); + + m_hseparator = new HSeparator(); + + pack_all_widgets(); + } + + private void pack_all_widgets() { + m_vbox.pack_start(m_preedit_label, false, false, 4); + m_vbox.pack_start(m_aux_label, false, false, 4); + m_vbox.pack_start(m_hseparator, false, false, 0); + m_vbox.pack_start(m_candidate_area, false, false, 0); + } + + public new void show() { + m_toplevel.show_all(); + } + + public new void hide() { + m_toplevel.hide(); + } + + private void move(int x, int y) { + m_toplevel.move(x, y); + } + + private void adjust_window_position() { + Gdk.Point cursor_right_bottom = { + m_cursor_location.x + m_cursor_location.width, + m_cursor_location.y + m_cursor_location.height + }; + + Gtk.Allocation allocation; + m_toplevel.get_allocation(out allocation); + Gdk.Point window_right_bottom = { + cursor_right_bottom.x + allocation.width, + cursor_right_bottom.y + allocation.height + }; + + Gdk.Window root = Gdk.get_default_root_window(); + int root_width = root.get_width(); + int root_height = root.get_height(); + + int x, y; + if (window_right_bottom.x > root_width) + x = root_width - allocation.width; + else + x = cursor_right_bottom.x; + + if (window_right_bottom.y > root_height) + y = m_cursor_location.y - allocation.height; + else + y = cursor_right_bottom.y; + + move(x, y); + } +} diff --git a/ui/gtk3/handle.vala b/ui/gtk3/handle.vala new file mode 100644 index 00000000..6738415f --- /dev/null +++ b/ui/gtk3/handle.vala @@ -0,0 +1,161 @@ +/* vim:set et sts=4 sw=4: + * + * ibus - The Input Bus + * + * Copyright(c) 2011 Peng Huang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or(at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + */ + +using Cairo; +using Gdk; +using Gtk; + +class Handle : Gtk.EventBox { + private bool m_move_begined; + private Gdk.Rectangle m_workarea; + private Gdk.Point m_press_pos; + + public signal void move_begin(); + public signal void move_end(); + + public Handle() { + set_size_request(6, -1); + Gdk.EventMask mask = Gdk.EventMask.EXPOSURE_MASK | + Gdk.EventMask.BUTTON_PRESS_MASK | + Gdk.EventMask.BUTTON_RELEASE_MASK | + Gdk.EventMask.BUTTON1_MOTION_MASK; + set_events(mask); + m_move_begined = false; + } + + public override void realize() { + base.realize(); + // get_window().set_cursor(new Gdk.Cursor(Gdk.CursorType.FLEUR)); + } + + public override bool button_press_event(Gdk.EventButton event) { + if (event.button != 1) + return false; + m_workarea = {0, 0, int.MAX, int.MAX}; + do { + Gdk.Window root = Gdk.get_default_root_window(); + Gdk.Atom property = Gdk.Atom.intern("_NET_CURRENT_DESKTOP", false); + Gdk.Atom type = Gdk.Atom.intern("CARDINAL", false); + Gdk.Atom actual_type; + int format; + uchar[] data; + bool result; + result = Gdk.property_get(root, + property, + type, + 0, long.MAX, + 0, + out actual_type, + out format, + out data); + if (!result || actual_type != type || format != 32 || data.length != 4) + break; + int index = data[0] | + data[1] << 8 | + data[2] << 16 | + data[3] << 24; + property = Gdk.Atom.intern("_NET_WORKAREA", false); + type = Gdk.Atom.intern("CARDINAL", false); + result = Gdk.property_get(root, + property, + type, + 0, long.MAX, + 0, + out actual_type, + out format, + out data); + if (!result || actual_type != type || format != 32 || data.length < (index + 1) * 16) + break; + int i = index * 4 * 4; + m_workarea.x = data[i] | + data[i + 1] << 8 | + data[i + 2] << 16 | + data[i + 3] << 24; + i += 4; + m_workarea.y = data[i] | + data[i + 1] << 8 | + data[i + 2] << 16 | + data[i + 3] << 24; + i += 4; + m_workarea.width = data[i] | + data[i + 1] << 8 | + data[i + 2] << 16 | + data[i + 3] << 24; + i += 4; + m_workarea.height = data[i] | + data[i + 1] << 8 | + data[i + 2] << 16 | + data[i + 3] << 24; + } while (false); + m_move_begined = true; + int x, y; + Gtk.Window toplevel = (Gtk.Window)get_toplevel(); + toplevel.get_position(out x, out y); + m_press_pos = { (int)event.x_root - x, (int)event.y_root - y }; + move_begin(); + return true; + } + + public override bool button_release_event(Gdk.EventButton event) { + if (event.button != 1) + return false; + m_move_begined = false; + m_press_pos = { 0, 0 }; + get_window().set_cursor(new Gdk.Cursor(Gdk.CursorType.LEFT_PTR)); + move_end(); + return true; + } + + public override bool motion_notify_event(Gdk.EventMotion event) { + if (!m_move_begined) + return false; + Gtk.Window toplevel = (Gtk.Window)get_toplevel(); + int x = (int)(event.x_root - m_press_pos.x); + int y = (int)(event.y_root - m_press_pos.y); + + if (x < m_workarea.x && x > m_workarea.x - 16) + x = m_workarea.x; + if (y < m_workarea.y && y > m_workarea.y - 16) + y = m_workarea.y; + int w, h; + toplevel.get_size(out w, out h); + if (x + w > m_workarea.x + m_workarea.width && + x + w < m_workarea.x + m_workarea.width + 16) + x = m_workarea.x + m_workarea.width - w; + if (y + h > m_workarea.y + m_workarea.height && + y + h < m_workarea.y + m_workarea.height + 16) + y = m_workarea.y + m_workarea.height - w; + toplevel.move(x, y); + return true; + } + + public override bool draw(Cairo.Context cr) { + if (Gtk.cairo_should_draw_window(cr, get_window())) { + Gtk.StyleContext context = get_style_context(); + Gtk.Allocation allocation; + get_allocation(out allocation); + Gtk.render_handle(context, cr, + allocation.x, allocation.y + (allocation.height - 40) / 2, allocation.width, 40.0); + } + return false; + } +} diff --git a/ui/gtk3/iconwidget.vala b/ui/gtk3/iconwidget.vala new file mode 100644 index 00000000..d73cb6be --- /dev/null +++ b/ui/gtk3/iconwidget.vala @@ -0,0 +1,56 @@ +/* vim:set et sts=4 sw=4: + * + * ibus - The Input Bus + * + * Copyright(c) 2011 Peng Huang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or(at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + */ + +using Gdk; +using GLib; +using Gtk; + +class IconWidget: Gtk.Image { + public IconWidget(string icon, int size) { + Gdk.Pixbuf pixbuf = null; + try { + if (icon[0] == '/') { + pixbuf = new Gdk.Pixbuf.from_file(icon); + } else { + var theme = Gtk.IconTheme.get_default(); + pixbuf = theme.load_icon(icon, size, 0); + } + } catch (GLib.Error e) { + try { + var theme = Gtk.IconTheme.get_default(); + pixbuf = theme.load_icon(Gtk.Stock.MISSING_IMAGE, size, 0); + } catch (GLib.Error e) {} + } + + if (pixbuf == null) + return; + float width = (float)pixbuf.get_width(); + float height = (float)pixbuf.get_height(); + float scale = size / (width > height ? width : height); + width *= scale; + height *= scale; + + pixbuf = pixbuf.scale_simple((int)width, (int)height, Gdk.InterpType.BILINEAR); + set_from_pixbuf(pixbuf); + show(); + } +} diff --git a/ui/gtk3/keybindingmanager.vala b/ui/gtk3/keybindingmanager.vala new file mode 100644 index 00000000..e9f46e4b --- /dev/null +++ b/ui/gtk3/keybindingmanager.vala @@ -0,0 +1,186 @@ +/* +valac --pkg gtk+-2.0 --pkg x11 --pkg gdk-x11-2.0 --pkg gee-1.0 keybinding-manager.vala +*/ + +/** + * This class is in charge to grab keybindings on the X11 display + * and filter X11-events and passing on such events to the registed + * handler methods. + * + * @author Oliver Sauder + */ + +using Gdk; +using GLib; +using Gtk; +using X; + +class KeybindingManager : GLib.Object +{ + /** + * list of binded keybindings + */ + private GLib.List bindings = new GLib.List(); + + /** + * locked modifiers used to grab all keys whatever lock key + * is pressed. + */ + private static uint[] lock_modifiers = { + 0, + Gdk.ModifierType.MOD2_MASK, // NUM_LOCK + Gdk.ModifierType.LOCK_MASK, // CAPS_LOCK + Gdk.ModifierType.MOD5_MASK, // SCROLL_LOCK + Gdk.ModifierType.MOD2_MASK|Gdk.ModifierType.LOCK_MASK, + Gdk.ModifierType.MOD2_MASK|Gdk.ModifierType.MOD5_MASK, + Gdk.ModifierType.LOCK_MASK|Gdk.ModifierType.MOD5_MASK, + Gdk.ModifierType.MOD2_MASK|Gdk.ModifierType.LOCK_MASK|Gdk.ModifierType.MOD5_MASK + }; + + /** + * Helper class to store keybinding + */ + private class Keybinding + { + public Keybinding(string accelerator, int keycode, + Gdk.ModifierType modifiers, KeybindingHandlerFunc handler) + { + this.accelerator = accelerator; + this.keycode = keycode; + this.modifiers = modifiers; + this.handler = handler; + } + + public string accelerator { get; set; } + public int keycode { get; set; } + public Gdk.ModifierType modifiers { get; set; } + public unowned KeybindingHandlerFunc handler { get; set; } + } + + /** + * Keybinding func needed to bind key to handler + * + * @param event passing on gdk event + */ + public delegate void KeybindingHandlerFunc(Gdk.Event event); + + public KeybindingManager() + { + // init filter to retrieve X.Events + Gdk.Window rootwin = Gdk.get_default_root_window(); + if(rootwin != null) { + rootwin.add_filter(event_filter); + } + } + + /** + * Bind accelerator to given handler + * + * @param accelerator accelerator parsable by Gtk.accelerator_parse + * @param handler handler called when given accelerator is pressed + */ + public void bind(string accelerator, KeybindingHandlerFunc handler) + { + debug("Binding key " + accelerator); + + // convert accelerator + uint keysym; + Gdk.ModifierType modifiers; + Gtk.accelerator_parse(accelerator, out keysym, out modifiers); + + unowned X.Display display = Gdk.x11_get_default_xdisplay(); + + int keycode = display.keysym_to_keycode(keysym); + + if(keycode != 0) { + // trap XErrors to avoid closing of application + // even when grabing of key fails + Gdk.error_trap_push(); + + // grab key finally + // also grab all keys which are combined with a lock key such NumLock + foreach(uint lock_modifier in lock_modifiers) { + display.grab_key(keycode, modifiers|lock_modifier, Gdk.x11_get_default_root_xwindow(), false, + X.GrabMode.Async, X.GrabMode.Async); + } + + // wait until all X request have been processed + Gdk.flush(); + + // store binding + Keybinding binding = new Keybinding(accelerator, keycode, modifiers, handler); + bindings.append(binding); + + debug("Successfully binded key " + accelerator); + } + } + + /** + * Unbind given accelerator. + * + * @param accelerator accelerator parsable by Gtk.accelerator_parse + */ + public void unbind(string accelerator) + { + debug("Unbinding key " + accelerator); + + unowned X.Display display = Gdk.x11_get_default_xdisplay(); + + // unbind all keys with given accelerator + GLib.List remove_bindings = new GLib.List(); + foreach(Keybinding binding in bindings) { + if(str_equal(accelerator, binding.accelerator)) { + foreach(uint lock_modifier in lock_modifiers) { + display.ungrab_key(binding.keycode, binding.modifiers | lock_modifier, Gdk.x11_get_default_root_xwindow()); + } + remove_bindings.append(binding); + } + } + + // remove unbinded keys + foreach(Keybinding binding in remove_bindings) + bindings.remove(binding); + } + + /** + * Event filter method needed to fetch X.Events + */ + public Gdk.FilterReturn event_filter(Gdk.XEvent gdk_xevent, Gdk.Event gdk_event) + { + Gdk.FilterReturn filter_return = Gdk.FilterReturn.CONTINUE; + + void* pointer = &gdk_xevent; + X.Event* xevent = (X.Event*) pointer; + + if(xevent->type == X.EventType.KeyPress) { + foreach(Keybinding binding in bindings) { + // remove NumLock, CapsLock and ScrollLock from key state + uint event_mods = xevent.xkey.state & ~ (lock_modifiers[7]); + if(xevent->xkey.keycode == binding.keycode && event_mods == binding.modifiers) { + // call all handlers with pressed key and modifiers + binding.handler(gdk_event); + } + } + } + + return filter_return; + } +} + +/* +public static int main (string[] args) +{ + Gtk.init (ref args); + + KeybindingManager manager = new KeybindingManager(); + manager.bind("V", test); + + Gtk.main (); + return 0; +} + +private static void test() +{ + debug("hotkey pressed"); +} +*/ diff --git a/ui/gtk3/panel.vala b/ui/gtk3/panel.vala new file mode 100644 index 00000000..dc63064c --- /dev/null +++ b/ui/gtk3/panel.vala @@ -0,0 +1,168 @@ +/* vim:set et sts=4 sw=4: + * + * ibus - The Input Bus + * + * Copyright(c) 2011 Peng Huang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or(at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + */ + +using IBus; +using GLib; +using Gtk; + +class Panel : IBus.PanelService { + private IBus.Bus m_bus; + private IBus.Config m_config; + // private IBus.PanelService m_service; + private Gtk.StatusIcon m_status_icon; + private Gtk.Menu m_ime_menu; + private IBus.EngineDesc[] m_engines; + private CandidatePanel m_candidate_panel; + private KeybindingManager m_keybinding_manager; + + public Panel(IBus.Bus bus) { + assert(bus.is_connected()); + // Chain up base class constructor + GLib.Object(connection : bus.get_connection(), + object_path : "/org/freedesktop/IBus/Panel"); + + m_bus = bus; + + m_config = bus.get_config(); + + // init ui + m_status_icon = new Gtk.StatusIcon(); + m_status_icon.set_name("ibus-ui-gtk"); + m_status_icon.set_title("IBus Panel"); + m_status_icon.popup_menu.connect(status_icon_popup_menu); + m_status_icon.activate.connect(status_icon_activate); + m_status_icon.set_from_icon_name("ibus-keyboard"); + + m_candidate_panel = new CandidatePanel(); + + m_candidate_panel.hide(); + m_candidate_panel.show(); + + update_engines(); + + m_keybinding_manager = new KeybindingManager(); + m_keybinding_manager.bind("space", (d) => { + // Switch to next engine + IBus.EngineDesc engine = m_bus.get_global_engine(); + int i; + for (i = 0; i < m_engines.length && engine != null; i++) { + if (m_engines[i].get_name() == engine.get_name()) + break; + } + i ++; + if (i >= m_engines.length) i = 0; + if (i >= m_engines.length) + return; + m_bus.set_global_engine(m_engines[i].get_name()); + }); + } + + private void update_engines() { + Variant variant = m_config.get_value("general", "preload_engines"); + if (variant != null) + m_engines = m_bus.get_engines_by_names(variant.get_strv()); + else + m_engines = m_bus.get_engines_by_names({"xkb:us:eng", "pinyin"}); + m_ime_menu = null; + } + + private void status_icon_popup_menu(Gtk.StatusIcon status_icon, + uint button, + uint activate_time) { + debug("popup-menu %u %u", button, activate_time); + } + + private void status_icon_activate(Gtk.StatusIcon status_icon) { + if (m_ime_menu == null) { + int width, height; + Gtk.icon_size_lookup(Gtk.IconSize.MENU, out width, out height); + m_ime_menu = new Gtk.Menu(); + foreach (var engine in m_engines) { + var lang = engine.get_language(); + var name = engine.get_name(); + var item = new Gtk.ImageMenuItem.with_label(lang + " - " + name); + if (engine.get_icon() != "") { + var icon = new IconWidget(engine.get_icon(), width); + item.set_image(icon); + } + // Make a copy of engine to workaround a bug in vala. + // https://bugzilla.gnome.org/show_bug.cgi?id=628336 + var e = engine; + item.activate.connect((i) => { + m_bus.set_global_engine(e.get_name()); + }); + m_ime_menu.add(item); + } + m_ime_menu.show_all(); + m_ime_menu.set_take_focus(false); + } + m_ime_menu.popup(null, + null, + m_status_icon.position_menu, + 0, + Gtk.get_current_event_time()); + } + + public override void set_cursor_location(int x, int y, int width, int height) { + m_candidate_panel.set_cursor_location(x, y, width, height); + } + + public override void focus_in(string input_context_path) { + debug("focus_in ic=%s", input_context_path); + } + + public override void focus_out(string input_context_path) { + debug("focus_out ic=%s", input_context_path); + } + + public override void update_preedit_text(IBus.Text text, + uint cursor_pos, + bool visible) { + if (visible) + m_candidate_panel.set_preedit_text(text, cursor_pos); + else + m_candidate_panel.set_preedit_text(null, 0); + } + + public override void hide_preedit_text() { + m_candidate_panel.set_preedit_text(null, 0); + } + + public override void update_auxiliary_text(IBus.Text text, + bool visible) { + m_candidate_panel.set_auxiliary_text(visible ? text : null); + } + + public override void hide_auxiliary_text() { + m_candidate_panel.set_auxiliary_text(null); + } + + public override void update_lookup_table(IBus.LookupTable table, + bool visible) { + m_candidate_panel.set_lookup_table(visible ? table : null); + } + + public override void hide_lookup_table() { + m_candidate_panel.set_lookup_table(null); + } +} + diff --git a/ui/gtk3/pango.vala b/ui/gtk3/pango.vala new file mode 100644 index 00000000..adcce439 --- /dev/null +++ b/ui/gtk3/pango.vala @@ -0,0 +1,84 @@ +/* vim:set et sts=4 sw=4: + * + * ibus - The Input Bus + * + * Copyright(c) 2011 Peng Huang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or(at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + */ + +using IBus; +using Pango; + +Pango.AttrList get_pango_attr_list_from_ibus_text(IBus.Text text) { + Pango.AttrList pango_attrs = new Pango.AttrList(); + unowned IBus.AttrList attrs = text.get_attributes(); + if (attrs == null) + return pango_attrs; + + unowned string str = text.get_text(); + long nchars = str.char_count(); + long[] offsets = new long[nchars + 1]; + for (int i = 0; i <= nchars; i++) + offsets[i] = str.index_of_nth_char(i); + + IBus.Attribute attr; + int i = 0; + while(true) { + attr = attrs.get(i++); + if (attr == null) + break; + long start_index = attr.start_index; + if (start_index <= 0) start_index = 0; + start_index = start_index <= nchars ? offsets[start_index] : offsets[-1]; + + long end_index = attr.end_index; + if (end_index <= 0) end_index = 0; + end_index = end_index <= nchars ? offsets[end_index] : offsets[-1]; + + Pango.Attribute pango_attr = null; + switch(attr.type) { + case IBus.AttrType.FOREGROUND: + { + uint16 r = (uint16)(attr.value & 0x00ff0000) >> 8; + uint16 g = (uint16)(attr.value & 0x0000ff00); + uint16 b = (uint16)(attr.value & 0x000000ff) << 8; + pango_attr = Pango.attr_foreground_new(r, g, b); + break; + } + case IBus.AttrType.BACKGROUND: + { + uint16 r = (uint16)(attr.value & 0x00ff0000) >> 8; + uint16 g = (uint16)(attr.value & 0x0000ff00); + uint16 b = (uint16)(attr.value & 0x000000ff) << 8; + pango_attr = Pango.attr_background_new(r, g, b); + break; + } + case IBus.AttrType.UNDERLINE: + { + pango_attr = Pango.attr_underline_new((Pango.Underline)attr.value); + break; + } + default: + continue; + } + pango_attr.start_index = (uint)start_index; + pango_attr.end_index = (uint)end_index; + // Transfer the ownership to pango_attrs + pango_attrs.insert((owned)pango_attr); + } + return pango_attrs; +} diff --git a/ui/gtk3/separator.vala b/ui/gtk3/separator.vala new file mode 100644 index 00000000..0917f4c2 --- /dev/null +++ b/ui/gtk3/separator.vala @@ -0,0 +1,39 @@ +/* vim:set et sts=4 sw=4: + * + * ibus - The Input Bus + * + * Copyright(c) 2011 Peng Huang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or(at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + */ + +using Gtk; + +class HSeparator : Gtk.HSeparator { + public HSeparator() { + GLib.Object( + margin : 2 + ); + } +} + +class VSeparator : Gtk.VSeparator { + public VSeparator() { + GLib.Object( + margin : 2 + ); + } +}