9d6bb4f328
- Fixed Bug 673047 - abrt ibus_xkb_get_current_layout for non-XKB system Updated ibus-541492-xkb.patch
1439 lines
47 KiB
Diff
1439 lines
47 KiB
Diff
From 71689f16ab8d19045ed44f2609c90202a6bf5db7 Mon Sep 17 00:00:00 2001
|
|
From: fujiwarat <takao.fujiwara1@gmail.com>
|
|
Date: Fri, 4 Mar 2011 00:04:34 +0900
|
|
Subject: [PATCH] Implement APIs for another non-Python panel.
|
|
|
|
1. Support icon and prop_list = null in ibus_property_new with GIR.
|
|
2. Add getter methods in IBusText and IBusProperty since GJS cannot access
|
|
the members in C-Structure.
|
|
3. Add ibus_get_language_name() since GIR libxml2 does not provide the
|
|
useful APIs.
|
|
4. Implement flags in ibus_bus_request_name() to follow DBus
|
|
RequestName signal spec.
|
|
http://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-names
|
|
This is needed to terminate the current IBus panel.
|
|
E.g. IBus GTK panel is launched by ibus-daemon but another panel is
|
|
launched by gnome-shell.
|
|
5. Support IBUS_BUS_NAME_FLAG_ALLOW_REPLACEMENT in ui/gtk/main.py
|
|
6. Fix bus_component_set_factory() not to call
|
|
bus_component_factory_destroy_cb() twice.
|
|
7. Hide ibus_text_new_from_static_string() for GIR.
|
|
8. Add ibus_is_running_gnome_shell() for ibus-ui-gtk because
|
|
gnome-shell runs earlier than ibus-ui-gtk.
|
|
---
|
|
bus/component.c | 2 +-
|
|
bus/connection.c | 8 +
|
|
bus/connection.h | 12 +-
|
|
bus/dbusimpl.c | 480 +++++++++++++++++++++++++++++++++++++++++++--
|
|
bus/marshalers.list | 3 +-
|
|
ibus/common.py | 24 +++-
|
|
src/Makefile.am | 2 +
|
|
src/ibusbus.c | 6 +-
|
|
src/ibusbus.h | 8 +-
|
|
src/ibusproperty.c | 24 +++
|
|
src/ibusproperty.h | 85 ++++++++-
|
|
src/ibustext.c | 18 ++
|
|
src/ibustext.h | 29 +++-
|
|
src/ibustypes.h | 33 +++
|
|
src/ibusutil.c | 169 ++++++++++++++++
|
|
src/ibusutil.h | 39 ++++
|
|
ui/gtk/gtkpanel.xml.in.in | 2 +-
|
|
ui/gtk/main.py | 23 ++-
|
|
18 files changed, 928 insertions(+), 39 deletions(-)
|
|
create mode 100644 src/ibusutil.c
|
|
create mode 100644 src/ibusutil.h
|
|
|
|
diff --git a/bus/component.c b/bus/component.c
|
|
index c1ff85a..fdff9c3 100644
|
|
--- a/bus/component.c
|
|
+++ b/bus/component.c
|
|
@@ -256,7 +256,7 @@ bus_component_set_factory (BusComponent *component,
|
|
}
|
|
|
|
if (component->factory) {
|
|
- g_signal_handlers_disconnect_by_func (factory,
|
|
+ g_signal_handlers_disconnect_by_func (component->factory,
|
|
bus_component_factory_destroy_cb,
|
|
component);
|
|
g_object_unref (component->factory);
|
|
diff --git a/bus/connection.c b/bus/connection.c
|
|
index a3b4c9c..9e73213 100644
|
|
--- a/bus/connection.c
|
|
+++ b/bus/connection.c
|
|
@@ -204,6 +204,14 @@ bus_connection_remove_name (BusConnection *connection,
|
|
return FALSE;
|
|
}
|
|
|
|
+gboolean
|
|
+bus_connection_has_name (BusConnection *connection,
|
|
+ const gchar *name)
|
|
+{
|
|
+ GList *list = g_list_find_custom (connection->names, name, (GCompareFunc) g_strcmp0);
|
|
+ return list != NULL;
|
|
+}
|
|
+
|
|
GDBusConnection *
|
|
bus_connection_get_dbus_connection (BusConnection *connection)
|
|
{
|
|
diff --git a/bus/connection.h b/bus/connection.h
|
|
index df86036..2a34319 100644
|
|
--- a/bus/connection.h
|
|
+++ b/bus/connection.h
|
|
@@ -85,7 +85,7 @@ const gchar *bus_connection_add_name (BusConnection *connect
|
|
const gchar *name);
|
|
|
|
/**
|
|
- * bus_connection_add_name:
|
|
+ * bus_connection_remove_name:
|
|
* @name: a well-known name for the connection.
|
|
* @returns: TRUE on success.
|
|
*
|
|
@@ -95,6 +95,16 @@ gboolean bus_connection_remove_name (BusConnection *connect
|
|
const gchar *name);
|
|
|
|
/**
|
|
+ * bus_connection_has_name:
|
|
+ * @name: a well-known name for the connection.
|
|
+ * @returns: TRUE if found the name.
|
|
+ *
|
|
+ * Lookup the well-known name from the connection.
|
|
+ */
|
|
+gboolean bus_connection_has_name (BusConnection *connection,
|
|
+ const gchar *name);
|
|
+
|
|
+/**
|
|
* bus_connection_get_dbus_connection:
|
|
*
|
|
* Get the underlying GDBus connection.
|
|
diff --git a/bus/dbusimpl.c b/bus/dbusimpl.c
|
|
index 48dbd42..8002bac 100644
|
|
--- a/bus/dbusimpl.c
|
|
+++ b/bus/dbusimpl.c
|
|
@@ -27,6 +27,8 @@
|
|
|
|
enum {
|
|
NAME_OWNER_CHANGED,
|
|
+ NAME_LOST,
|
|
+ NAME_ACQUIRED,
|
|
LAST_SIGNAL,
|
|
};
|
|
|
|
@@ -68,6 +70,14 @@ struct _BusDBusImplClass {
|
|
gchar *name,
|
|
gchar *old_name,
|
|
gchar *new_name);
|
|
+
|
|
+ void (* name_lost) (BusDBusImpl *dbus,
|
|
+ BusConnection *connection,
|
|
+ gchar *name);
|
|
+
|
|
+ void (* name_acquired) (BusDBusImpl *dbus,
|
|
+ BusConnection *connection,
|
|
+ gchar *name);
|
|
};
|
|
|
|
typedef struct _BusDispatchData BusDispatchData;
|
|
@@ -76,6 +86,19 @@ struct _BusDispatchData {
|
|
BusConnection *skip_connection;
|
|
};
|
|
|
|
+typedef struct _BusNameService BusNameService;
|
|
+struct _BusNameService {
|
|
+ gchar *name;
|
|
+ GSList *owners;
|
|
+};
|
|
+
|
|
+typedef struct _BusConnectionOwner BusConnectionOwner;
|
|
+struct _BusConnectionOwner {
|
|
+ BusConnection *conn;
|
|
+
|
|
+ guint allow_replacement : 1;
|
|
+ guint do_not_queue : 1;
|
|
+};
|
|
|
|
/* functions prototype */
|
|
static void bus_dbus_impl_destroy (BusDBusImpl *dbus);
|
|
@@ -111,6 +134,14 @@ static void bus_dbus_impl_name_owner_changed
|
|
gchar *name,
|
|
gchar *old_name,
|
|
gchar *new_name);
|
|
+static void bus_dbus_impl_name_lost
|
|
+ (BusDBusImpl *dbus,
|
|
+ BusConnection *connection,
|
|
+ gchar *name);
|
|
+static void bus_dbus_impl_name_acquired
|
|
+ (BusDBusImpl *dbus,
|
|
+ BusConnection *connection,
|
|
+ gchar *name);
|
|
static void bus_dbus_impl_connection_destroy_cb
|
|
(BusConnection *connection,
|
|
BusDBusImpl *dbus);
|
|
@@ -205,6 +236,188 @@ static const gchar introspection_xml[] =
|
|
"</node>";
|
|
|
|
static void
|
|
+bus_connection_owner_set_flags (BusConnectionOwner *owner,
|
|
+ guint32 flags)
|
|
+{
|
|
+ owner->allow_replacement =
|
|
+ (flags & IBUS_BUS_NAME_FLAG_ALLOW_REPLACEMENT) != 0;
|
|
+
|
|
+ owner->do_not_queue =
|
|
+ (flags & IBUS_BUS_NAME_FLAG_DO_NOT_QUEUE) != 0;
|
|
+}
|
|
+
|
|
+static BusConnectionOwner *
|
|
+bus_connection_owner_new (BusConnection *connection,
|
|
+ guint32 flags)
|
|
+{
|
|
+ BusConnectionOwner *owner = NULL;
|
|
+
|
|
+ g_assert (connection != NULL);
|
|
+
|
|
+ owner = (BusConnectionOwner *) g_new0 (BusConnectionOwner, 1);
|
|
+ if (owner != NULL) {
|
|
+ owner->conn = g_object_ref (connection);
|
|
+ bus_connection_owner_set_flags (owner, flags);
|
|
+ }
|
|
+
|
|
+ return owner;
|
|
+}
|
|
+
|
|
+static void
|
|
+bus_connection_owner_free (BusConnectionOwner *owner)
|
|
+{
|
|
+ g_assert (owner != NULL);
|
|
+
|
|
+ g_object_unref (owner->conn);
|
|
+ owner->conn = NULL;
|
|
+ g_free (owner);
|
|
+}
|
|
+
|
|
+static GSList *
|
|
+_bus_name_service_find_owner_link (BusNameService *service,
|
|
+ BusConnection *connection)
|
|
+{
|
|
+ GSList *owners = service->owners;
|
|
+
|
|
+ while (owners) {
|
|
+ BusConnectionOwner *owner = (BusConnectionOwner *) owners->data;
|
|
+ if (owner->conn == connection) {
|
|
+ break;
|
|
+ }
|
|
+ owners = owners->next;
|
|
+ }
|
|
+
|
|
+ return owners;
|
|
+}
|
|
+
|
|
+static BusNameService *
|
|
+bus_name_service_new (const gchar *name)
|
|
+{
|
|
+ BusNameService *service = NULL;
|
|
+
|
|
+ g_assert (name != NULL);
|
|
+
|
|
+ service = g_new0 (BusNameService, 1);
|
|
+ if (service != NULL) {
|
|
+ service->name = g_strdup (name);
|
|
+ }
|
|
+
|
|
+ return service;
|
|
+}
|
|
+
|
|
+static void
|
|
+bus_name_service_free (BusNameService *service)
|
|
+{
|
|
+ GSList *list = NULL;
|
|
+
|
|
+ g_assert (service != NULL);
|
|
+
|
|
+ list = service->owners;
|
|
+
|
|
+ while (list) {
|
|
+ bus_connection_owner_free ((BusConnectionOwner *) list->data);
|
|
+ list->data = NULL;
|
|
+ list = list->next;
|
|
+ }
|
|
+ if (service->owners) {
|
|
+ g_slist_free (service->owners);
|
|
+ service->owners = NULL;
|
|
+ }
|
|
+ g_free (service->name);
|
|
+ service->name = NULL;
|
|
+ g_free (service);
|
|
+}
|
|
+
|
|
+static void
|
|
+bus_name_service_add_primary_owner (BusNameService *service,
|
|
+ BusConnectionOwner *owner,
|
|
+ BusDBusImpl *dbus)
|
|
+{
|
|
+ g_assert (service != NULL);
|
|
+
|
|
+ if (dbus) {
|
|
+ g_signal_emit (dbus,
|
|
+ dbus_signals[NAME_ACQUIRED],
|
|
+ 0,
|
|
+ g_object_ref (owner->conn),
|
|
+ service->name ? service->name : "");
|
|
+ }
|
|
+
|
|
+ service->owners = g_slist_prepend (service->owners, (gpointer) owner);
|
|
+}
|
|
+
|
|
+static BusConnectionOwner *
|
|
+bus_name_service_get_primary_owner (BusNameService *service)
|
|
+{
|
|
+ g_assert (service != NULL);
|
|
+
|
|
+ if (service->owners == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return (BusConnectionOwner *) service->owners->data;
|
|
+}
|
|
+
|
|
+static void
|
|
+bus_name_service_add_owner (BusNameService *service,
|
|
+ BusConnectionOwner *owner,
|
|
+ BusDBusImpl *dbus)
|
|
+{
|
|
+ g_assert (service != NULL);
|
|
+
|
|
+ if (dbus && service->owners == NULL) {
|
|
+ g_signal_emit (dbus,
|
|
+ dbus_signals[NAME_ACQUIRED],
|
|
+ 0,
|
|
+ g_object_ref (owner->conn),
|
|
+ service->name ? service->name : "");
|
|
+ }
|
|
+
|
|
+ service->owners = g_slist_append (service->owners, (gpointer) owner);
|
|
+}
|
|
+
|
|
+static void
|
|
+bus_name_service_remove_owner (BusNameService *service,
|
|
+ BusConnectionOwner *owner,
|
|
+ BusDBusImpl *dbus)
|
|
+{
|
|
+ GSList *owners;
|
|
+
|
|
+ g_assert (service != NULL);
|
|
+ g_assert (owner != NULL);
|
|
+
|
|
+ owners = _bus_name_service_find_owner_link (service, owner->conn);
|
|
+ if (owners == NULL) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (dbus &&
|
|
+ owners->data == bus_name_service_get_primary_owner (service)) {
|
|
+ g_signal_emit (dbus,
|
|
+ dbus_signals[NAME_LOST],
|
|
+ 0,
|
|
+ g_object_ref (owner->conn),
|
|
+ service->name ? service->name : "");
|
|
+ }
|
|
+
|
|
+ service->owners = g_slist_remove_link (service->owners, (gpointer) owners);
|
|
+}
|
|
+
|
|
+static gboolean
|
|
+bus_name_service_get_allow_replacement (BusNameService *service)
|
|
+{
|
|
+ BusConnectionOwner *owner = NULL;
|
|
+
|
|
+ g_assert (service != NULL);
|
|
+
|
|
+ owner = bus_name_service_get_primary_owner (service);
|
|
+ if (owner == NULL) {
|
|
+ return TRUE;
|
|
+ }
|
|
+ return owner->allow_replacement;
|
|
+}
|
|
+
|
|
+static void
|
|
bus_dbus_impl_class_init (BusDBusImplClass *class)
|
|
{
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
|
|
@@ -221,6 +434,12 @@ bus_dbus_impl_class_init (BusDBusImplClass *class)
|
|
/* register a handler of the name-owner-changed signal below. */
|
|
class->name_owner_changed = bus_dbus_impl_name_owner_changed;
|
|
|
|
+ /* register a handler of the name-lost signal below. */
|
|
+ class->name_lost = bus_dbus_impl_name_lost;
|
|
+
|
|
+ /* register a handler of the name-acquired signal below. */
|
|
+ class->name_acquired = bus_dbus_impl_name_acquired;
|
|
+
|
|
/* install signals */
|
|
dbus_signals[NAME_OWNER_CHANGED] =
|
|
g_signal_new (I_("name-owner-changed"),
|
|
@@ -234,13 +453,39 @@ bus_dbus_impl_class_init (BusDBusImplClass *class)
|
|
G_TYPE_STRING,
|
|
G_TYPE_STRING,
|
|
G_TYPE_STRING);
|
|
+
|
|
+ dbus_signals[NAME_LOST] =
|
|
+ g_signal_new (I_("name-lost"),
|
|
+ G_TYPE_FROM_CLASS (class),
|
|
+ G_SIGNAL_RUN_FIRST,
|
|
+ G_STRUCT_OFFSET (BusDBusImplClass, name_lost),
|
|
+ NULL, NULL,
|
|
+ bus_marshal_VOID__OBJECT_STRING,
|
|
+ G_TYPE_NONE,
|
|
+ 2,
|
|
+ BUS_TYPE_CONNECTION,
|
|
+ G_TYPE_STRING);
|
|
+
|
|
+ dbus_signals[NAME_ACQUIRED] =
|
|
+ g_signal_new (I_("name-acquired"),
|
|
+ G_TYPE_FROM_CLASS (class),
|
|
+ G_SIGNAL_RUN_FIRST,
|
|
+ G_STRUCT_OFFSET (BusDBusImplClass, name_acquired),
|
|
+ NULL, NULL,
|
|
+ bus_marshal_VOID__OBJECT_STRING,
|
|
+ G_TYPE_NONE,
|
|
+ 2,
|
|
+ BUS_TYPE_CONNECTION,
|
|
+ G_TYPE_STRING);
|
|
}
|
|
|
|
static void
|
|
bus_dbus_impl_init (BusDBusImpl *dbus)
|
|
{
|
|
dbus->unique_names = g_hash_table_new (g_str_hash, g_str_equal);
|
|
- dbus->names = g_hash_table_new (g_str_hash, g_str_equal);
|
|
+ dbus->names = g_hash_table_new_full (g_str_hash, g_str_equal,
|
|
+ (GDestroyNotify) g_free,
|
|
+ (GDestroyNotify) bus_name_service_free);
|
|
|
|
dbus->dispatch_lock = g_mutex_new ();
|
|
dbus->forward_lock = g_mutex_new ();
|
|
@@ -557,10 +802,15 @@ bus_dbus_impl_request_name (BusDBusImpl *dbus,
|
|
GVariant *parameters,
|
|
GDBusMethodInvocation *invocation)
|
|
{
|
|
- /* FIXME need to handle flags defined in:
|
|
- * http://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-names */
|
|
const gchar *name = NULL; // e.g. "org.freedesktop.IBus.Panel"
|
|
- guint flags = 0;
|
|
+ guint32 flags = 0;
|
|
+ guint32 retval = 0;
|
|
+ gchar *old_owner_name = NULL;
|
|
+ BusNameService *service = NULL;
|
|
+ BusConnectionOwner *primary_owner = NULL;
|
|
+ BusConnectionOwner *owner = NULL;
|
|
+ BusConnection *old_owner_conn = NULL;
|
|
+
|
|
g_variant_get (parameters, "(&su)", &name, &flags);
|
|
|
|
if (name == NULL ||
|
|
@@ -580,25 +830,82 @@ bus_dbus_impl_request_name (BusDBusImpl *dbus,
|
|
return;
|
|
}
|
|
|
|
- if (g_hash_table_lookup (dbus->names, name) != NULL) {
|
|
- g_dbus_method_invocation_return_error (invocation,
|
|
- G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
|
|
- "Service name '%s' already has an owner.", name);
|
|
- return;
|
|
+ service = (BusNameService *) g_hash_table_lookup (dbus->names, name);
|
|
+
|
|
+ if (service != NULL) {
|
|
+ primary_owner = bus_name_service_get_primary_owner (service);
|
|
+ if (primary_owner != NULL) {
|
|
+ old_owner_conn = primary_owner->conn;
|
|
+ } else {
|
|
+ old_owner_conn = NULL;
|
|
+ }
|
|
+ } else {
|
|
+ old_owner_conn = NULL;
|
|
}
|
|
|
|
- const guint retval = 1; /* DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER */
|
|
- g_dbus_method_invocation_return_value (invocation, g_variant_new ("(u)", retval));
|
|
- g_hash_table_insert (dbus->names,
|
|
- (gpointer) bus_connection_add_name (connection, name),
|
|
- connection);
|
|
+ if (old_owner_conn == NULL) {
|
|
+ retval = IBUS_BUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;
|
|
+ }
|
|
+ else if (old_owner_conn == connection) {
|
|
+ retval = IBUS_BUS_REQUEST_NAME_REPLY_ALREADY_OWNER;
|
|
+ goto out;
|
|
+ }
|
|
+ else if (((flags & IBUS_BUS_NAME_FLAG_DO_NOT_QUEUE) &&
|
|
+ !(bus_name_service_get_allow_replacement (service))) ||
|
|
+ ((flags & IBUS_BUS_NAME_FLAG_DO_NOT_QUEUE) &&
|
|
+ !(flags & IBUS_BUS_NAME_FLAG_REPLACE_EXISTING))) {
|
|
+ retval = IBUS_BUS_REQUEST_NAME_REPLY_EXISTS;
|
|
+ goto out;
|
|
+ }
|
|
+ else if (!(flags & IBUS_BUS_NAME_FLAG_DO_NOT_QUEUE) &&
|
|
+ (!(flags & IBUS_BUS_NAME_FLAG_REPLACE_EXISTING) ||
|
|
+ !(bus_name_service_get_allow_replacement (service)))) {
|
|
+ if (!bus_connection_has_name (connection, name)) {
|
|
+ bus_connection_add_name (connection, name);
|
|
+ }
|
|
+ owner = bus_connection_owner_new (connection, flags);
|
|
+ bus_name_service_add_owner (service, owner, dbus);
|
|
+ retval = IBUS_BUS_REQUEST_NAME_REPLY_IN_QUEUE;
|
|
+ goto out;
|
|
+ }
|
|
+ else {
|
|
+ if (!bus_connection_has_name (connection, name)) {
|
|
+ bus_connection_add_name (connection, name);
|
|
+ }
|
|
+ owner = bus_connection_owner_new (connection, flags);
|
|
+ old_owner_name = g_strdup (bus_connection_get_unique_name (primary_owner->conn));
|
|
+ bus_name_service_remove_owner (service, primary_owner, dbus);
|
|
+ bus_name_service_add_primary_owner (service, owner, dbus);
|
|
+ if (primary_owner->do_not_queue == 0) {
|
|
+ bus_name_service_add_owner (service, primary_owner, dbus);
|
|
+ } else {
|
|
+ if (bus_connection_has_name (primary_owner->conn, name)) {
|
|
+ bus_connection_remove_name (primary_owner->conn, name);
|
|
+ }
|
|
+ bus_connection_owner_free (primary_owner);
|
|
+ }
|
|
+ retval = IBUS_BUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;
|
|
+ }
|
|
+
|
|
+ if (service == NULL) {
|
|
+ service = bus_name_service_new (name);
|
|
+ owner = bus_connection_owner_new (connection, flags);
|
|
+ bus_name_service_add_owner (service, owner, dbus);
|
|
+ g_hash_table_insert (dbus->names,
|
|
+ (gpointer) g_strdup (bus_connection_add_name (connection, name)),
|
|
+ service);
|
|
+ }
|
|
|
|
g_signal_emit (dbus,
|
|
dbus_signals[NAME_OWNER_CHANGED],
|
|
0,
|
|
name,
|
|
- "",
|
|
+ old_owner_name ? old_owner_name : "",
|
|
bus_connection_get_unique_name (connection));
|
|
+ g_free (old_owner_name);
|
|
+
|
|
+out:
|
|
+ g_dbus_method_invocation_return_value (invocation, g_variant_new ("(u)", retval));
|
|
}
|
|
|
|
/**
|
|
@@ -682,6 +989,70 @@ bus_dbus_impl_name_owner_changed (BusDBusImpl *dbus,
|
|
}
|
|
|
|
/**
|
|
+ * bus_dbus_impl_name_lost:
|
|
+ *
|
|
+ * The function is called on name-lost signal, typically when g_signal_emit (dbus, NAME_LOST)
|
|
+ * is called, and broadcasts the signal to clients.
|
|
+ */
|
|
+static void
|
|
+bus_dbus_impl_name_lost (BusDBusImpl *dbus,
|
|
+ BusConnection *connection,
|
|
+ gchar *name)
|
|
+{
|
|
+ static guint32 serial = 0;
|
|
+
|
|
+ g_assert (BUS_IS_DBUS_IMPL (dbus));
|
|
+ g_assert (name != NULL);
|
|
+
|
|
+ GDBusMessage *message = g_dbus_message_new_signal ("/org/freedesktop/DBus",
|
|
+ "org.freedesktop.DBus",
|
|
+ "NameLost");
|
|
+ g_dbus_message_set_sender (message, "org.freedesktop.DBus");
|
|
+ g_dbus_message_set_destination (message, bus_connection_get_unique_name (connection));
|
|
+
|
|
+ /* set a non-zero serial to make libdbus happy */
|
|
+ g_dbus_message_set_serial (message, ++serial);
|
|
+ g_dbus_message_set_body (message,
|
|
+ g_variant_new ("(s)", name));
|
|
+
|
|
+ bus_dbus_impl_forward_message (dbus, connection, message);
|
|
+ g_object_unref (message);
|
|
+ g_object_unref (connection);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bus_dbus_impl_name_acquired:
|
|
+ *
|
|
+ * The function is called on name-acquired signal, typically when g_signal_emit (dbus, NAME_LOST)
|
|
+ * is called, and broadcasts the signal to clients.
|
|
+ */
|
|
+static void
|
|
+bus_dbus_impl_name_acquired (BusDBusImpl *dbus,
|
|
+ BusConnection *connection,
|
|
+ gchar *name)
|
|
+{
|
|
+ static guint32 serial = 0;
|
|
+
|
|
+ g_assert (BUS_IS_DBUS_IMPL (dbus));
|
|
+ g_assert (name != NULL);
|
|
+
|
|
+ GDBusMessage *message = g_dbus_message_new_signal ("/org/freedesktop/DBus",
|
|
+ "org.freedesktop.DBus",
|
|
+ "NameAcquired");
|
|
+ g_dbus_message_set_sender (message, "org.freedesktop.DBus");
|
|
+ g_dbus_message_set_destination (message, bus_connection_get_unique_name (connection));
|
|
+
|
|
+ /* set a non-zero serial to make libdbus happy */
|
|
+ g_dbus_message_set_serial (message, ++serial);
|
|
+ g_dbus_message_set_body (message,
|
|
+ g_variant_new ("(s)", name));
|
|
+
|
|
+ bus_dbus_impl_forward_message (dbus, connection, message);
|
|
+ g_object_unref (message);
|
|
+ g_object_unref (connection);
|
|
+}
|
|
+
|
|
+/**
|
|
* bus_dbus_impl_service_method_call:
|
|
*
|
|
* Handle a D-Bus method call from a client. This function overrides an implementation in src/ibusservice.c.
|
|
@@ -935,6 +1306,10 @@ bus_dbus_impl_connection_destroy_cb (BusConnection *connection,
|
|
BusDBusImpl *dbus)
|
|
{
|
|
const gchar *unique_name = bus_connection_get_unique_name (connection);
|
|
+ const GList *names = NULL;
|
|
+ BusNameService *service = NULL;
|
|
+ GSList *owners = NULL;
|
|
+
|
|
if (unique_name != NULL) {
|
|
g_hash_table_remove (dbus->unique_names, unique_name);
|
|
g_signal_emit (dbus,
|
|
@@ -945,16 +1320,71 @@ bus_dbus_impl_connection_destroy_cb (BusConnection *connection,
|
|
"");
|
|
}
|
|
|
|
- const GList *name = bus_connection_get_names (connection);
|
|
- while (name != NULL) {
|
|
- g_hash_table_remove (dbus->names, name->data);
|
|
+ /* service->owners is the queue of connections.
|
|
+ * If the connection is the primary owner and
|
|
+ * bus_name_service_remove_owner() is called, the owner is removed
|
|
+ * in the queue and the next owner will become the primary owner
|
|
+ * automatically because service->owners is just a GSList.
|
|
+ * If service->owners == NULL, it's good to remove the service in
|
|
+ * dbus->names.
|
|
+ * I suppose dbus->names are global queue for every connection and
|
|
+ * connection->names are private queue of the connection.
|
|
+ */
|
|
+ names = bus_connection_get_names (connection);
|
|
+ while (names != NULL) {
|
|
+ service = (BusNameService *) g_hash_table_lookup (dbus->names,
|
|
+ names->data);
|
|
+ if (service) {
|
|
+ owners = _bus_name_service_find_owner_link (service, connection);
|
|
+ if (owners) {
|
|
+ BusConnectionOwner *owner = owners->data;
|
|
+ bus_name_service_remove_owner (service, owner, dbus);
|
|
+ bus_connection_owner_free (owner);
|
|
+ }
|
|
+ if (service->owners == NULL) {
|
|
+ /* g_hash_table_remove() will call bus_name_service_free()
|
|
+ * due to g_hash_table_new_full() */
|
|
+ g_hash_table_remove (dbus->names, names->data);
|
|
+ service = NULL;
|
|
+ }
|
|
+ }
|
|
+ /* if service == NULL, the names->data should be removed in
|
|
+ * the connection by bus_connection_remove_name().
|
|
+ * But connection->names is GSList so it cannot be removed
|
|
+ * during this while loop because names->next would not
|
|
+ * become the wrong pointer here.
|
|
+ * the next while loop can call bus_connection_remove_name().
|
|
+ */
|
|
+
|
|
g_signal_emit (dbus,
|
|
dbus_signals[NAME_OWNER_CHANGED],
|
|
0,
|
|
- name->data,
|
|
+ names->data,
|
|
unique_name,
|
|
"");
|
|
- name = name->next;
|
|
+ names = names->next;
|
|
+ }
|
|
+
|
|
+ while ((names = bus_connection_get_names (connection)) != NULL) {
|
|
+ const gchar *name = NULL;
|
|
+ service = NULL;
|
|
+
|
|
+ while (names != NULL) {
|
|
+ name = (const gchar *) names->data;
|
|
+ service = (BusNameService *) g_hash_table_lookup (dbus->names,
|
|
+ name);
|
|
+ if (service == NULL) {
|
|
+ break;
|
|
+ }
|
|
+ names = names->next;
|
|
+ }
|
|
+ if (names == NULL) {
|
|
+ break;
|
|
+ }
|
|
+ if (name == NULL) {
|
|
+ break;
|
|
+ }
|
|
+ bus_connection_remove_name (connection, name);
|
|
}
|
|
|
|
dbus->connections = g_list_remove (dbus->connections, connection);
|
|
@@ -1004,7 +1434,15 @@ bus_dbus_impl_get_connection_by_name (BusDBusImpl *dbus,
|
|
return (BusConnection *) g_hash_table_lookup (dbus->unique_names, name);
|
|
}
|
|
else {
|
|
- return (BusConnection *) g_hash_table_lookup (dbus->names, name);
|
|
+ BusNameService *service;
|
|
+ BusConnectionOwner *owner;
|
|
+
|
|
+ service = (BusNameService *) g_hash_table_lookup (dbus->names, name);
|
|
+ if (service == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+ owner = bus_name_service_get_primary_owner (service);
|
|
+ return owner ? owner->conn : NULL;
|
|
}
|
|
}
|
|
|
|
diff --git a/bus/marshalers.list b/bus/marshalers.list
|
|
index 15bdf02..514d6ea 100644
|
|
--- a/bus/marshalers.list
|
|
+++ b/bus/marshalers.list
|
|
@@ -5,9 +5,10 @@ VOID:INT,UINT
|
|
VOID:UINT,UINT,UINT
|
|
VOID:INT,INT,INT,INT
|
|
VOID:STRING,INT
|
|
-VOID:OBJECT
|
|
VOID:STRING,STRING,STRING
|
|
+VOID:OBJECT
|
|
VOID:OBJECT,BOOLEAN
|
|
+VOID:OBJECT,STRING
|
|
VOID:OBJECT,UINT,BOOLEAN
|
|
VOID:OBJECT,UINT,BOOLEAN,UINT
|
|
BOOL:UINT,UINT,UINT
|
|
diff --git a/ibus/common.py b/ibus/common.py
|
|
index cbc8d56..614d782 100644
|
|
--- a/ibus/common.py
|
|
+++ b/ibus/common.py
|
|
@@ -35,6 +35,13 @@ __all__ = (
|
|
"ORIENTATION_SYSTEM",
|
|
"PRELOAD_ENGINE_MODE_USER",
|
|
"PRELOAD_ENGINE_MODE_LANG_RELATIVE",
|
|
+ "BUS_NAME_FLAG_ALLOW_REPLACEMENT",
|
|
+ "BUS_NAME_FLAG_REPLACE_EXISTING",
|
|
+ "BUS_NAME_FLAG_DO_NOT_QUEUE",
|
|
+ "BUS_REQUEST_NAME_REPLY_PRIMARY_OWNER",
|
|
+ "BUS_REQUEST_NAME_REPLY_IN_QUEUE",
|
|
+ "BUS_REQUEST_NAME_REPLY_EXISTS",
|
|
+ "BUS_REQUEST_NAME_REPLY_ALREADY_OWNER",
|
|
"default_reply_handler",
|
|
"default_error_handler",
|
|
"DEFAULT_ASYNC_HANDLERS",
|
|
@@ -47,7 +54,8 @@ __all__ = (
|
|
"main_quit",
|
|
"main_iteration",
|
|
"get_address",
|
|
- "get_socket_path"
|
|
+ "get_socket_path",
|
|
+ "is_running_gnome_shell",
|
|
)
|
|
|
|
import os
|
|
@@ -106,6 +114,9 @@ get_address.restype=ctypes.c_char_p
|
|
get_socket_path = libibus.ibus_get_socket_path
|
|
get_socket_path.restype=ctypes.c_char_p
|
|
|
|
+is_running_gnome_shell = libibus.ibus_is_running_gnome_shell
|
|
+is_running_gnome_shell.restype = ctypes.c_bool
|
|
+
|
|
# __session_id = os.getenv ("IBUS_SESSION_ID")
|
|
#
|
|
# IBUS_ADDR = "unix:path=/tmp/ibus-%s%s/ibus-%s-%s" % (__username,
|
|
@@ -138,6 +149,17 @@ ORIENTATION_SYSTEM = 2
|
|
PRELOAD_ENGINE_MODE_USER = 0
|
|
PRELOAD_ENGINE_MODE_LANG_RELATIVE = 1
|
|
|
|
+# define bus name flag
|
|
+BUS_NAME_FLAG_ALLOW_REPLACEMENT = (1 << 0)
|
|
+BUS_NAME_FLAG_REPLACE_EXISTING = (1 << 1)
|
|
+BUS_NAME_FLAG_DO_NOT_QUEUE = (1 << 2)
|
|
+
|
|
+# define bus request name reply
|
|
+BUS_REQUEST_NAME_REPLY_PRIMARY_OWNER = 1
|
|
+BUS_REQUEST_NAME_REPLY_IN_QUEUE = 2
|
|
+BUS_REQUEST_NAME_REPLY_EXISTS = 3
|
|
+BUS_REQUEST_NAME_REPLY_ALREADY_OWNER = 4
|
|
+
|
|
def default_reply_handler( *args):
|
|
pass
|
|
|
|
diff --git a/src/Makefile.am b/src/Makefile.am
|
|
index 08152a7..d422106 100644
|
|
--- a/src/Makefile.am
|
|
+++ b/src/Makefile.am
|
|
@@ -87,6 +87,7 @@ ibus_sources = \
|
|
ibusenginedesc.c \
|
|
ibusobservedpath.c \
|
|
ibuscomponent.c \
|
|
+ ibusutil.c \
|
|
$(NULL)
|
|
libibus_1_0_la_SOURCES = \
|
|
$(ibus_sources) \
|
|
@@ -131,6 +132,7 @@ ibus_headers = \
|
|
ibusenginedesc.h \
|
|
ibusobservedpath.h \
|
|
ibuscomponent.h \
|
|
+ ibusutil.h \
|
|
$(NULL)
|
|
ibusincludedir = $(includedir)/ibus-@IBUS_API_VERSION@
|
|
ibus_public_headers = \
|
|
diff --git a/src/ibusbus.c b/src/ibusbus.c
|
|
index 5a3b978..78808a4 100644
|
|
--- a/src/ibusbus.c
|
|
+++ b/src/ibusbus.c
|
|
@@ -613,15 +613,15 @@ ibus_bus_hello (IBusBus *bus)
|
|
#endif
|
|
}
|
|
|
|
-guint
|
|
+guint32
|
|
ibus_bus_request_name (IBusBus *bus,
|
|
const gchar *name,
|
|
- guint flags)
|
|
+ guint32 flags)
|
|
{
|
|
g_return_val_if_fail (IBUS_IS_BUS (bus), 0);
|
|
g_return_val_if_fail (name != NULL, 0);
|
|
|
|
- guint retval = 0;
|
|
+ guint32 retval = 0;
|
|
GVariant *result;
|
|
result = ibus_bus_call_sync (bus,
|
|
DBUS_SERVICE_DBUS,
|
|
diff --git a/src/ibusbus.h b/src/ibusbus.h
|
|
index b1ec63c..de4cd36 100644
|
|
--- a/src/ibusbus.h
|
|
+++ b/src/ibusbus.h
|
|
@@ -122,16 +122,16 @@ const gchar *ibus_bus_hello
|
|
* ibus_bus_request_name:
|
|
* @bus: the IBusBus instance to be processed.
|
|
* @name: Name to be requested.
|
|
- * @flags: Flags (FixMe).
|
|
- * @returns: 0 if failed; positive number otherwise.
|
|
+ * @flags: IBusBusNameFlag.
|
|
+ * @returns: 0 if failed; IBusBusRequestNameReply otherwise.
|
|
*
|
|
* Request a name from IBus daemon synchronously.
|
|
*
|
|
* FIXME add an asynchronous version.
|
|
*/
|
|
-guint ibus_bus_request_name (IBusBus *bus,
|
|
+guint32 ibus_bus_request_name (IBusBus *bus,
|
|
const gchar *name,
|
|
- guint flags);
|
|
+ guint32 flags);
|
|
|
|
/**
|
|
* ibus_bus_release_name:
|
|
diff --git a/src/ibusproperty.c b/src/ibusproperty.c
|
|
index bb9cc21..5a2dd78 100644
|
|
--- a/src/ibusproperty.c
|
|
+++ b/src/ibusproperty.c
|
|
@@ -217,6 +217,30 @@ ibus_property_new (const gchar *key,
|
|
return prop;
|
|
}
|
|
|
|
+#define IBUS_PROPERTY_GET_FIELD(field, return_type) \
|
|
+return_type \
|
|
+ibus_property_get_ ## field (IBusProperty *prop) \
|
|
+{ \
|
|
+ return prop->field; \
|
|
+}
|
|
+
|
|
+IBUS_PROPERTY_GET_FIELD (key, const gchar *)
|
|
+IBUS_PROPERTY_GET_FIELD (icon, const gchar *)
|
|
+IBUS_PROPERTY_GET_FIELD (label, const IBusText *)
|
|
+IBUS_PROPERTY_GET_FIELD (tooltip, const IBusText *)
|
|
+IBUS_PROPERTY_GET_FIELD (sensitive, gboolean)
|
|
+IBUS_PROPERTY_GET_FIELD (visible, gboolean)
|
|
+IBUS_PROPERTY_GET_FIELD (state, IBusPropState)
|
|
+IBUS_PROPERTY_GET_FIELD (sub_props, const IBusPropList *)
|
|
+#undef IBUS_PROPERTY_GET_FIELD
|
|
+
|
|
+/* ibus_property_get_type() exists */
|
|
+IBusPropType
|
|
+ibus_property_get_prop_type (IBusProperty *prop)
|
|
+{
|
|
+ return prop->type;
|
|
+}
|
|
+
|
|
void
|
|
ibus_property_set_label (IBusProperty *prop,
|
|
IBusText *label)
|
|
diff --git a/src/ibusproperty.h b/src/ibusproperty.h
|
|
index 0f8d427..5e76c8f 100644
|
|
--- a/src/ibusproperty.h
|
|
+++ b/src/ibusproperty.h
|
|
@@ -164,12 +164,12 @@ GType ibus_property_get_type ();
|
|
* @key: Unique Identity for the IBusProperty.
|
|
* @type: IBusPropType of IBusProperty.
|
|
* @label: Text shown in UI.
|
|
- * @icon: Icon file for the IBusProperty.
|
|
+ * @icon: (allow-none): Icon file for the IBusProperty.
|
|
* @tooltip: Message shown if mouse hovered the IBusProperty.
|
|
* @sensitive: Whether the IBusProperty is sensitive to keyboard and mouse event.
|
|
* @visible: Whether the IBusProperty is visible.
|
|
* @state: IBusPropState of IBusProperty.
|
|
- * @prop_list: IBusPropList that contains sub IBusProperties.
|
|
+ * @prop_list: (allow-none): IBusPropList that contains sub IBusProperties.
|
|
* @returns: A newly allocated IBusProperty.
|
|
*
|
|
* New a IBusProperty.
|
|
@@ -185,6 +185,33 @@ IBusProperty *ibus_property_new (const gchar *key,
|
|
IBusPropList *prop_list);
|
|
|
|
/**
|
|
+ * ibus_property_get_key:
|
|
+ * @prop: An IBusProperty.
|
|
+ * @returns: the key of IBusProperty. Should not be freed.
|
|
+ *
|
|
+ * Get the key of IBusProperty.
|
|
+ */
|
|
+const gchar * ibus_property_get_key (IBusProperty *prop);
|
|
+
|
|
+/**
|
|
+ * ibus_property_get_prop_type:
|
|
+ * @prop: An IBusProperty.
|
|
+ * @returns: the type of IBusProperty.
|
|
+ *
|
|
+ * Get the type of IBusProperty.
|
|
+ */
|
|
+IBusPropType ibus_property_get_prop_type(IBusProperty *prop);
|
|
+
|
|
+/**
|
|
+ * ibus_property_get_label:
|
|
+ * @prop: An IBusProperty.
|
|
+ * @returns: the label of IBusProperty. Should not be freed.
|
|
+ *
|
|
+ * Get the label of IBusProperty.
|
|
+ */
|
|
+const IBusText * ibus_property_get_label (IBusProperty *prop);
|
|
+
|
|
+/**
|
|
* ibus_property_set_label:
|
|
* @prop: An IBusProperty.
|
|
* @label: Text shown in UI.
|
|
@@ -195,6 +222,15 @@ void ibus_property_set_label (IBusProperty *prop,
|
|
IBusText *label);
|
|
|
|
/**
|
|
+ * ibus_property_get_icon:
|
|
+ * @prop: An IBusProperty.
|
|
+ * @returns: the icon of IBusProperty. Should not be freed.
|
|
+ *
|
|
+ * Get the icon of IBusProperty.
|
|
+ */
|
|
+const gchar * ibus_property_get_icon (IBusProperty *prop);
|
|
+
|
|
+/**
|
|
* ibus_property_set_icon:
|
|
* @prop: An IBusProperty.
|
|
* @icon: Icon shown in UI. It could be a full path of an icon file or an icon name.
|
|
@@ -205,6 +241,15 @@ void ibus_property_set_icon (IBusProperty *prop,
|
|
const gchar *icon);
|
|
|
|
/**
|
|
+ * ibus_property_get_tooltip:
|
|
+ * @prop: An IBusProperty.
|
|
+ * @returns: the tooltip of IBusProperty. Should not be freed.
|
|
+ *
|
|
+ * Get the tooltip of IBusProperty.
|
|
+ */
|
|
+const IBusText * ibus_property_get_tooltip (IBusProperty *prop);
|
|
+
|
|
+/**
|
|
* ibus_property_set_tooltip:
|
|
* @prop: An IBusProperty.
|
|
* @tooltip: Text of the tooltip.
|
|
@@ -215,6 +260,15 @@ void ibus_property_set_tooltip (IBusProperty *prop,
|
|
IBusText *tooltip);
|
|
|
|
/**
|
|
+ * ibus_property_get_sensitive:
|
|
+ * @prop: An IBusProperty.
|
|
+ * @returns: the sensitive of IBusProperty.
|
|
+ *
|
|
+ * Get the sensitive of IBusProperty.
|
|
+ */
|
|
+gboolean ibus_property_get_sensitive(IBusProperty *prop);
|
|
+
|
|
+/**
|
|
* ibus_property_set_sensitive:
|
|
* @prop: An IBusProperty.
|
|
* @sensitive: Whether the IBusProperty is sensitive.
|
|
@@ -225,6 +279,15 @@ void ibus_property_set_sensitive(IBusProperty *prop,
|
|
gboolean sensitive);
|
|
|
|
/**
|
|
+ * ibus_property_get_visible:
|
|
+ * @prop: An IBusProperty.
|
|
+ * @returns: the visible of IBusProperty.
|
|
+ *
|
|
+ * Get the visible of IBusProperty.
|
|
+ */
|
|
+gboolean ibus_property_get_visible (IBusProperty *prop);
|
|
+
|
|
+/**
|
|
* ibus_property_set_visible:
|
|
* @prop: An IBusProperty.
|
|
* @visible: Whether the IBusProperty is visible.
|
|
@@ -235,6 +298,15 @@ void ibus_property_set_visible (IBusProperty *prop,
|
|
gboolean visible);
|
|
|
|
/**
|
|
+ * ibus_property_get_state:
|
|
+ * @prop: An IBusProperty.
|
|
+ * @returns: the state of IBusProperty.
|
|
+ *
|
|
+ * Get the state of IBusProperty.
|
|
+ */
|
|
+IBusPropState ibus_property_get_state (IBusProperty *prop);
|
|
+
|
|
+/**
|
|
* ibus_property_set_state:
|
|
* @prop: An IBusProperty.
|
|
* @state: The state of the IBusProperty.
|
|
@@ -244,6 +316,15 @@ void ibus_property_set_visible (IBusProperty *prop,
|
|
void ibus_property_set_state (IBusProperty *prop,
|
|
IBusPropState state);
|
|
|
|
+/**
|
|
+ * ibus_property_get_sub_props:
|
|
+ * @prop: An IBusProperty.
|
|
+ * @returns: the IBusPropList of IBusProperty. Should not be freed.
|
|
+ *
|
|
+ * Get the IBusPropList of IBusProperty.
|
|
+ */
|
|
+const IBusPropList *
|
|
+ ibus_property_get_sub_props(IBusProperty *prop);
|
|
|
|
/**
|
|
* ibus_property_set_sub_props:
|
|
diff --git a/src/ibustext.c b/src/ibustext.c
|
|
index b63cbc9..5889b64 100644
|
|
--- a/src/ibustext.c
|
|
+++ b/src/ibustext.c
|
|
@@ -268,3 +268,21 @@ ibus_text_get_length (IBusText *text)
|
|
{
|
|
return g_utf8_strlen (text->text, -1);
|
|
}
|
|
+
|
|
+gboolean
|
|
+ibus_text_get_is_static (IBusText *text)
|
|
+{
|
|
+ return text->is_static;
|
|
+}
|
|
+
|
|
+const gchar *
|
|
+ibus_text_get_text (IBusText *text)
|
|
+{
|
|
+ return text->text;
|
|
+}
|
|
+
|
|
+const IBusAttrList *
|
|
+ibus_text_get_attributes (IBusText *text)
|
|
+{
|
|
+ return text->attrs;
|
|
+}
|
|
diff --git a/src/ibustext.h b/src/ibustext.h
|
|
index 246e5ab..6f7c505 100644
|
|
--- a/src/ibustext.h
|
|
+++ b/src/ibustext.h
|
|
@@ -110,7 +110,7 @@ IBusText *ibus_text_new_from_string (const gchar *str);
|
|
IBusText *ibus_text_new_from_ucs4 (const gunichar *str);
|
|
|
|
/**
|
|
- * ibus_text_new_from_static_string:
|
|
+ * ibus_text_new_from_static_string: (skip)
|
|
* @str: An text string to be set.
|
|
* @returns: A newly allocated IBusText.
|
|
*
|
|
@@ -169,6 +169,33 @@ void ibus_text_append_attribute (IBusText *text,
|
|
*/
|
|
guint ibus_text_get_length (IBusText *text);
|
|
|
|
+/**
|
|
+ * ibus_text_get_is_static:
|
|
+ * @text: An IBusText.
|
|
+ * @returns: the is_static in @text.
|
|
+ *
|
|
+ * Return the is_static in an IBusText.
|
|
+ */
|
|
+gboolean ibus_text_get_is_static (IBusText *text);
|
|
+
|
|
+/**
|
|
+ * ibus_text_get_text:
|
|
+ * @text: An IBusText.
|
|
+ * @returns: the text in @text.
|
|
+ *
|
|
+ * Return the text in an IBusText. Should not be freed.
|
|
+ */
|
|
+const gchar * ibus_text_get_text (IBusText *text);
|
|
+
|
|
+/**
|
|
+ * ibus_text_get_attributes:
|
|
+ * @text: An IBusText.
|
|
+ * @returns: the attrs in @text.
|
|
+ *
|
|
+ * Return the attributes in an IBusText. Should not be freed.
|
|
+ */
|
|
+const IBusAttrList *
|
|
+ ibus_text_get_attributes (IBusText *text);
|
|
G_END_DECLS
|
|
#endif
|
|
|
|
diff --git a/src/ibustypes.h b/src/ibustypes.h
|
|
index 035d124..6a31847 100644
|
|
--- a/src/ibustypes.h
|
|
+++ b/src/ibustypes.h
|
|
@@ -154,6 +154,39 @@ typedef enum {
|
|
} IBusPreloadEngineMode;
|
|
|
|
/**
|
|
+ * IBusBusNameFlag:
|
|
+ * @IBUS_BUS_NAME_FLAG_ALLOW_REPLACEMENT:
|
|
+ * same as DBUS_NAME_FLAG_ALLOW_REPLACEMENT
|
|
+ * @IBUS_BUS_NAME_FLAG_REPLACE_EXISTING:
|
|
+ * same as DBUS_NAME_FLAG_REPLACE_EXISTING
|
|
+ * @IBUS_BUS_NAME_FLAG_DO_NOT_QUEUE:
|
|
+ * same as DBUS_NAME_FLAG_DO_NOT_QUEUE
|
|
+ */
|
|
+typedef enum {
|
|
+ IBUS_BUS_NAME_FLAG_ALLOW_REPLACEMENT = (1 << 0),
|
|
+ IBUS_BUS_NAME_FLAG_REPLACE_EXISTING = (1 << 1),
|
|
+ IBUS_BUS_NAME_FLAG_DO_NOT_QUEUE = (1 << 2),
|
|
+} IBusBusNameFlag;
|
|
+
|
|
+/**
|
|
+ * IBusBusRequestNameReply:
|
|
+ * @IBUS_BUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
|
|
+ * same as DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER
|
|
+ * @IBUS_BUS_REQUEST_NAME_REPLY_IN_QUEUE:
|
|
+ * same as DBUS_REQUEST_NAME_REPLY_IN_QUEUE
|
|
+ * @IBUS_BUS_REQUEST_NAME_REPLY_EXISTS:
|
|
+ * same as DBUS_REQUEST_NAME_REPLY_EXISTS
|
|
+ * @IBUS_BUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
|
|
+ * same as DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER
|
|
+ */
|
|
+typedef enum {
|
|
+ IBUS_BUS_REQUEST_NAME_REPLY_PRIMARY_OWNER = 1,
|
|
+ IBUS_BUS_REQUEST_NAME_REPLY_IN_QUEUE = 2,
|
|
+ IBUS_BUS_REQUEST_NAME_REPLY_EXISTS = 3,
|
|
+ IBUS_BUS_REQUEST_NAME_REPLY_ALREADY_OWNER = 4,
|
|
+} IBusBusRequestNameReply;
|
|
+
|
|
+/**
|
|
* IBusRectangle:
|
|
* @x: x coordinate.
|
|
* @y: y coordinate.
|
|
diff --git a/src/ibusutil.c b/src/ibusutil.c
|
|
new file mode 100644
|
|
index 0000000..59291f9
|
|
--- /dev/null
|
|
+++ b/src/ibusutil.c
|
|
@@ -0,0 +1,169 @@
|
|
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
|
|
+/* vim:set et sts=4: */
|
|
+/* bus - The Input Bus
|
|
+ * Copyright (C) 2008-2011 Peng Huang <shawn.p.huang@gmail.com>
|
|
+ * Copyright (C) 2010-2011 Takao Fujiwara <takao.fujiwara1@gmail.com>
|
|
+ * Copyright (C) 2008-2011 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 library; if not, write to the
|
|
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
+ * Boston, MA 02111-1307, USA.
|
|
+ */
|
|
+#ifdef HAVE_CONFIG_H
|
|
+#include <config.h>
|
|
+#endif
|
|
+
|
|
+#include <glib.h>
|
|
+#include <glib/gstdio.h>
|
|
+#include <gio/gio.h>
|
|
+#include "ibusxml.h"
|
|
+
|
|
+#ifdef ENABLE_NLS
|
|
+#include <libintl.h>
|
|
+#endif
|
|
+
|
|
+static GHashTable *__languages_dict;
|
|
+
|
|
+static gboolean
|
|
+_iso_codes_parse_xml_node (XMLNode *node)
|
|
+{
|
|
+ GList *p;
|
|
+ g_assert (node);
|
|
+
|
|
+ if (G_UNLIKELY (g_strcmp0 (node->name, "iso_639_entries") != 0)) {
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ for (p = node->sub_nodes; p != NULL; p = p->next) {
|
|
+ XMLNode *sub_node = (XMLNode *)p->data;
|
|
+ gchar **attributes = NULL;
|
|
+ int i, j;
|
|
+ struct {
|
|
+ const gchar *key;
|
|
+ gchar *value;
|
|
+ } entries[] = {
|
|
+ { "iso_639_2B_code", NULL },
|
|
+ { "iso_639_2T_code", NULL },
|
|
+ { "iso_639_1_code", NULL },
|
|
+ { NULL, NULL },
|
|
+ };
|
|
+
|
|
+
|
|
+ if (sub_node->attributes == NULL) {
|
|
+ continue;
|
|
+ }
|
|
+ attributes = sub_node->attributes;
|
|
+ for (i = 0; attributes[i]; i+=2) {
|
|
+ if (g_strcmp0 (attributes[i], "name") == 0) {
|
|
+ for (j = 0; entries[j].key; j++) {
|
|
+ if (entries[j].value == NULL) {
|
|
+ continue;
|
|
+ }
|
|
+ g_hash_table_insert (__languages_dict,
|
|
+ (gpointer) entries[j].value,
|
|
+ (gpointer) g_strdup (attributes[i + 1]));
|
|
+ entries[j].value = NULL;
|
|
+ }
|
|
+ } else {
|
|
+ for (j = 0; entries[j].key; j++) {
|
|
+ if (g_strcmp0 (attributes[i], entries[j].key) == 0 &&
|
|
+ attributes[i + 1] != NULL) {
|
|
+ entries[j].value = g_strdup (attributes[i + 1]);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+void
|
|
+_load_lang()
|
|
+{
|
|
+ gchar *filename;
|
|
+ XMLNode *node;
|
|
+ struct stat buf;
|
|
+
|
|
+ __languages_dict = g_hash_table_new (g_str_hash, (GEqualFunc) g_str_equal);
|
|
+ filename = g_build_filename ("/usr", "share/xml/iso-codes/iso_639.xml", NULL);
|
|
+ if (g_stat (filename, &buf) != 0) {
|
|
+ g_warning ("Can not get stat of file %s", filename);
|
|
+ g_free (filename);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ node = ibus_xml_parse_file (filename);
|
|
+ g_free (filename);
|
|
+
|
|
+ if (!node) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ _iso_codes_parse_xml_node (node);
|
|
+ ibus_xml_free (node);
|
|
+}
|
|
+
|
|
+const gchar *
|
|
+ibus_get_language_name(const gchar *_locale) {
|
|
+ const gchar *retval;
|
|
+
|
|
+ if (__languages_dict == NULL ) {
|
|
+ _load_lang();
|
|
+ }
|
|
+ retval = (const gchar *) g_hash_table_lookup (__languages_dict, _locale);
|
|
+ if (retval != NULL) {
|
|
+#ifdef ENABLE_NLS
|
|
+ return dgettext("iso_639", retval);
|
|
+#else
|
|
+ return retval;
|
|
+#endif
|
|
+ }
|
|
+ return retval;
|
|
+}
|
|
+
|
|
+gboolean
|
|
+ibus_is_running_gnome_shell (void)
|
|
+{
|
|
+ GDBusConnection *connection = NULL;
|
|
+ GVariant *result;
|
|
+ gboolean is_running = FALSE;
|
|
+
|
|
+ connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
|
|
+ if (connection == NULL) {
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ result = g_dbus_connection_call_sync (connection,
|
|
+ "org.freedesktop.DBus",
|
|
+ "/org/freedesktop/DBus",
|
|
+ "org.freedesktop.DBus",
|
|
+ "GetNameOwner",
|
|
+ g_variant_new ("(s)", "org.gnome.Shell"),
|
|
+ G_VARIANT_TYPE ("(s)"),
|
|
+ G_DBUS_CALL_FLAGS_NONE,
|
|
+ -1,
|
|
+ NULL,
|
|
+ NULL);
|
|
+
|
|
+ if (result != NULL) {
|
|
+ is_running = TRUE;
|
|
+ g_variant_unref (result);
|
|
+ } else {
|
|
+ is_running = FALSE;
|
|
+ }
|
|
+ g_object_unref (connection);
|
|
+
|
|
+ return is_running;
|
|
+}
|
|
diff --git a/src/ibusutil.h b/src/ibusutil.h
|
|
new file mode 100644
|
|
index 0000000..8892996
|
|
--- /dev/null
|
|
+++ b/src/ibusutil.h
|
|
@@ -0,0 +1,39 @@
|
|
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
|
|
+/* vim:set et sts=4: */
|
|
+/* bus - The Input Bus
|
|
+ * Copyright (C) 2008-2011 Peng Huang <shawn.p.huang@gmail.com>
|
|
+ * Copyright (C) 2010-2011 Takao Fujiwara <takao.fujiwara1@gmail.com>
|
|
+ * Copyright (C) 2008-2011 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 library; if not, write to the
|
|
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
+ * Boston, MA 02111-1307, USA.
|
|
+ */
|
|
+
|
|
+#if !defined (__IBUS_H_INSIDE__) && !defined (IBUS_COMPILATION)
|
|
+#error "Only <ibus.h> can be included directly"
|
|
+#endif
|
|
+
|
|
+/**
|
|
+ * ibus_get_language_name:
|
|
+ * @_locale: A const locale name.
|
|
+ * @returns: language name
|
|
+ */
|
|
+const gchar * ibus_get_language_name (const gchar *_locale);
|
|
+
|
|
+/**
|
|
+ * ibus_is_running_gnome_shell:
|
|
+ * @returns: TRUE if gnome-shell is running
|
|
+ */
|
|
+gboolean ibus_is_running_gnome_shell (void);
|
|
diff --git a/ui/gtk/gtkpanel.xml.in.in b/ui/gtk/gtkpanel.xml.in.in
|
|
index edeed1c..1e1e656 100644
|
|
--- a/ui/gtk/gtkpanel.xml.in.in
|
|
+++ b/ui/gtk/gtkpanel.xml.in.in
|
|
@@ -3,7 +3,7 @@
|
|
<component>
|
|
<name>org.freedesktop.IBus.Panel</name>
|
|
<description>Gtk Panel Component</description>
|
|
- <exec>${libexecdir}/ibus-ui-gtk</exec>
|
|
+ <exec>${libexecdir}/ibus-ui-gtk -s</exec>
|
|
<version>@VERSION@</version>
|
|
<author>Peng Huang <shawn.p.huang@gmail.com></author>
|
|
<license>GPL</license>
|
|
diff --git a/ui/gtk/main.py b/ui/gtk/main.py
|
|
index f4c901d..5e75ab7 100644
|
|
--- a/ui/gtk/main.py
|
|
+++ b/ui/gtk/main.py
|
|
@@ -50,7 +50,13 @@ class UIApplication:
|
|
self.__bus.add_match(match_rule)
|
|
|
|
self.__panel = panel.Panel(self.__bus)
|
|
- self.__bus.request_name(ibus.IBUS_SERVICE_PANEL, 0)
|
|
+ self.__bus.request_name(ibus.IBUS_SERVICE_PANEL,
|
|
+ ibus.BUS_NAME_FLAG_ALLOW_REPLACEMENT |
|
|
+ ibus.BUS_NAME_FLAG_REPLACE_EXISTING)
|
|
+ self.__bus.add_match("type='signal',\
|
|
+ sender='org.freedesktop.DBus',\
|
|
+ member='NameLost'")
|
|
+ self.__bus.get_dbusconn().add_signal_receiver(self.__name_lost_cb, signal_name="NameLost")
|
|
self.__notify = pynotify.Notification("IBus", \
|
|
_("Some input methods have been installed, removed or updated. " \
|
|
"Please restart ibus input platform."), \
|
|
@@ -66,6 +72,10 @@ class UIApplication:
|
|
def __registry_changed_cb(self, bus):
|
|
self.__notify.show()
|
|
|
|
+ def __name_lost_cb(self, name):
|
|
+ print "Got NameLost signal", name
|
|
+ gtk.main_quit()
|
|
+
|
|
def run(self):
|
|
try:
|
|
gtk.main()
|
|
@@ -84,8 +94,9 @@ def print_help(out, v = 0):
|
|
|
|
def main():
|
|
daemonize = False
|
|
- shortopt = "hd"
|
|
- longopt = ["help", "daemonize"]
|
|
+ stop_by_shell = False
|
|
+ shortopt = "hds"
|
|
+ longopt = ["help", "daemonize", "stop-by-shell"]
|
|
try:
|
|
opts, args = getopt.getopt(sys.argv[1:], shortopt, longopt)
|
|
except getopt.GetoptError, err:
|
|
@@ -96,10 +107,16 @@ def main():
|
|
print_help(sys.stdout)
|
|
elif o in("-d", "--daemonize"):
|
|
daemonize = True
|
|
+ elif o in("-s", "--stop-by-shell"):
|
|
+ stop_by_shell = True
|
|
else:
|
|
print >> sys.stderr, "Unknown argument: %s" % o
|
|
print_help(sys.stderr, 1)
|
|
|
|
+ if stop_by_shell and ibus.is_running_gnome_shell():
|
|
+ print "Exit because GNOME-Shell is running"
|
|
+ sys.exit()
|
|
+
|
|
if daemonize:
|
|
if os.fork():
|
|
sys.exit()
|
|
--
|
|
1.7.4.1
|
|
|