[mousetweaks/at-spi2] Migrate to AT-SPI over DBus



commit d3533a3c0bbc4a392d0f902aae6e240c3dc4c7ce
Author: Gerd Kohlberger <gerdk src gnome org>
Date:   Fri Jan 8 19:15:36 2010 +0100

    Migrate to AT-SPI over DBus

 src/mt-listener.c |  294 ++++++++++++++++++++++++++++++-----------------------
 src/mt-listener.h |   19 ++--
 src/mt-main.c     |  257 +++++++++++++++++++++-------------------------
 src/mt-main.h     |    9 ++-
 src/mt-service.c  |   86 +++++++---------
 src/mt-service.h  |   12 +-
 6 files changed, 343 insertions(+), 334 deletions(-)
---
diff --git a/src/mt-listener.c b/src/mt-listener.c
index 3d5d701..5284c36 100644
--- a/src/mt-listener.c
+++ b/src/mt-listener.c
@@ -17,52 +17,74 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
 
 #include "mt-listener.h"
 
+#define SPI_EVENT_MOUSE_IFACE "org.freedesktop.atspi.Event.Mouse"
+#define SPI_SIGNAL_BUTTON     "Button"
+#define SPI_SIGNAL_ABS        "Abs"
+
+#define SPI_EVENT_FOCUS_IFACE "org.freedesktop.atspi.Event.Focus"
+#define SPI_SIGNAL_FOCUS      "Focus"
+
+#define SPI_ACCESSIBLE_IFACE  "org.freedesktop.atspi.Accessible"
+
 struct _MtListenerPrivate {
-    AccessibleEventListener *motion;
-    AccessibleEventListener *button;
-    AccessibleEventListener *focus;
-    Accessible              *current_focus;
+    DBusGConnection *connection;
+    DBusGProxy      *focus;
+    guint            track_focus : 1;
 };
 
 enum {
     MOTION_EVENT,
     BUTTON_EVENT,
-    FOCUS_CHANGED,
     LAST_SIGNAL
 };
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
-static void mt_listener_dispose      (GObject               *object);
-static void mt_listener_motion_event (const AccessibleEvent *event,
-				      gpointer               data);
-static void mt_listener_button_event (const AccessibleEvent *event,
-				      gpointer               data);
-static void mt_listener_focus_event  (const AccessibleEvent *event,
-				      gpointer               data);
-
 G_DEFINE_TYPE (MtListener, mt_listener, G_TYPE_OBJECT)
 
 static void
+mt_listener_init (MtListener *listener)
+{
+    listener->priv = G_TYPE_INSTANCE_GET_PRIVATE (listener,
+						  MT_TYPE_LISTENER,
+						  MtListenerPrivate);
+}
+
+static void
+mt_listener_dispose (GObject *object)
+{
+    MtListenerPrivate *priv = MT_LISTENER (object)->priv;
+
+    if (priv->connection) {
+	dbus_g_connection_unref (priv->connection);
+	priv->connection = NULL;
+    }
+    if (priv->focus) {
+	g_object_unref (priv->focus);
+	priv->focus = NULL;
+    }
+    G_OBJECT_CLASS (mt_listener_parent_class)->dispose (object);
+}
+
+static void
 mt_listener_class_init (MtListenerClass *klass)
 {
     GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
     object_class->dispose = mt_listener_dispose;
 
-    signals[MOTION_EVENT] = 
+    signals[MOTION_EVENT] =
 	g_signal_new (g_intern_static_string ("motion_event"),
 		      G_OBJECT_CLASS_TYPE (klass),
 		      G_SIGNAL_RUN_LAST,
 		      0, NULL, NULL,
 		      g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE,
 		      1, MT_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
-
-    signals[BUTTON_EVENT] = 
+    signals[BUTTON_EVENT] =
 	g_signal_new (g_intern_static_string ("button_event"),
 		      G_OBJECT_CLASS_TYPE (klass),
 		      G_SIGNAL_RUN_LAST,
@@ -70,152 +92,170 @@ mt_listener_class_init (MtListenerClass *klass)
 		      g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE,
 		      1, MT_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
 
-    signals[FOCUS_CHANGED] =
-	g_signal_new (g_intern_static_string ("focus_changed"),
-		      G_OBJECT_CLASS_TYPE (klass),
-		      G_SIGNAL_RUN_LAST,
-		      0, NULL, NULL,
-		      g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
-
     g_type_class_add_private (klass, sizeof (MtListenerPrivate));
 }
 
-static void
-mt_listener_init (MtListener *listener)
+static gboolean
+mt_listener_msg_to_event (MtListener  *listener,
+                          DBusMessage *msg,
+                          MtEvent     *event)
 {
-    MtListenerPrivate *priv;
-
-    listener->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (listener,
-							 MT_TYPE_LISTENER,
-							 MtListenerPrivate);
-
-    priv->motion = SPI_createAccessibleEventListener (mt_listener_motion_event,
-						      listener);
-    SPI_registerGlobalEventListener (priv->motion, "mouse:abs");
-
-    priv->button = SPI_createAccessibleEventListener (mt_listener_button_event,
-						      listener);
-    SPI_registerGlobalEventListener (priv->button, "mouse:button:");
-
-    priv->focus = SPI_createAccessibleEventListener (mt_listener_focus_event,
-						     listener);
-    SPI_registerGlobalEventListener (priv->focus, "focus:");
+    DBusMessageIter iter;
+    dbus_uint32_t u;
+    char *s;
+    int type, arg = 1;
+
+    dbus_message_iter_init (msg, &iter);
+    while (dbus_message_iter_has_next (&iter))
+    {
+	type = dbus_message_iter_get_arg_type (&iter);
+	if (type == DBUS_TYPE_STRING) {
+	    dbus_message_iter_get_basic (&iter, &s);
+	    if (!s)
+		return FALSE;
+	    if (*s == '\0') {
+		event->button = 0;
+		event->type = EV_MOTION;
+	    }
+	    else if (s[0] && s[1]) {
+		event->button = (guint) g_ascii_strtod (s, NULL);
+		event->type = s[1] == 'p' ? EV_BUTTON_PRESS : EV_BUTTON_RELEASE;
+	    }
+	    else
+		return FALSE;
+	}
+	else if (type == DBUS_TYPE_UINT32) {
+	    dbus_message_iter_get_basic (&iter, &u);
+	    if (arg++ == 1)
+		event->x = u;
+	    else
+		event->y = u;
+	}
+	dbus_message_iter_next (&iter);
+    }
+    return TRUE;
 }
 
-static void
-mt_listener_dispose (GObject *object)
+static DBusHandlerResult
+mt_listener_dispatch (DBusConnection *bus,
+		      DBusMessage    *msg,
+		      gpointer        data)
 {
-    MtListenerPrivate *priv = MT_LISTENER (object)->priv;
+    MtListener *listener = data;
+    MtEvent ev;
 
-    if (priv->motion) {
-	SPI_deregisterGlobalEventListenerAll (priv->motion);
-	AccessibleEventListener_unref (priv->motion);
-	priv->motion = NULL;
-    }
-    if (priv->button) {
-	SPI_deregisterGlobalEventListenerAll (priv->button);
-	AccessibleEventListener_unref (priv->button);
-	priv->button = NULL;
+    if (dbus_message_has_sender (msg, DBUS_SERVICE_DBUS))
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+    if (dbus_message_has_member (msg, SPI_SIGNAL_ABS))
+    {
+	if (mt_listener_msg_to_event (listener, msg, &ev))
+	    g_signal_emit (data, signals[MOTION_EVENT], 0, &ev);
     }
-    if (priv->focus) {
-	SPI_deregisterGlobalEventListenerAll (priv->focus);
-	AccessibleEventListener_unref (priv->focus);
-	priv->focus = NULL;
+    else if (dbus_message_has_member (msg, SPI_SIGNAL_BUTTON))
+    {
+	if (mt_listener_msg_to_event (listener, msg, &ev))
+	    g_signal_emit (data, signals[BUTTON_EVENT], 0, &ev);
     }
-    if (priv->current_focus) {
-	Accessible_unref (priv->current_focus);
-	priv->current_focus = NULL;
+    else if (listener->priv->track_focus &&
+	     dbus_message_has_member (msg, SPI_SIGNAL_FOCUS))
+    {
+	if (listener->priv->focus)
+	    g_object_unref (listener->priv->focus);
+
+	listener->priv->focus =
+	    dbus_g_proxy_new_for_name (listener->priv->connection,
+				       dbus_message_get_sender (msg),
+				       dbus_message_get_path (msg),
+				       SPI_ACCESSIBLE_IFACE);
     }
-
-    G_OBJECT_CLASS (mt_listener_parent_class)->dispose (object);
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 }
 
-GType
-mt_event_get_type (void)
-{
-    static GType event = 0;
-
-    if (G_UNLIKELY (event == 0))
-	event = g_boxed_type_register_static (g_intern_static_string ("MtEvent"),
-					      (GBoxedCopyFunc) mt_event_copy,
-					      (GBoxedFreeFunc) mt_event_free);
-    return event;
-}
-
-MtEvent *
-mt_event_copy (const MtEvent *event)
+static void
+mt_listener_setup_filter (MtListener *listener)
 {
-    return (MtEvent *) g_memdup (event, sizeof (MtEvent));
+    DBusConnection *bus;
+
+    bus = dbus_g_connection_get_connection (listener->priv->connection);
+    dbus_bus_add_match (bus,
+			"type='signal',"
+			"interface='" SPI_EVENT_MOUSE_IFACE "',"
+			"member='" SPI_SIGNAL_ABS "'",
+			NULL);
+    dbus_bus_add_match (bus,
+			"type='signal',"
+			"interface='" SPI_EVENT_MOUSE_IFACE "',"
+			"member='" SPI_SIGNAL_BUTTON "'",
+			NULL);
+    dbus_bus_add_match (bus,
+			"type='signal',"
+			"interface='" SPI_EVENT_FOCUS_IFACE "'",
+			NULL);
+    dbus_connection_add_filter (bus, mt_listener_dispatch, listener, NULL);
 }
 
-void
-mt_event_free (MtEvent *event)
+MtListener *
+mt_listener_new (DBusGConnection *connection)
 {
-    g_free (event);
-}
+    MtListener *listener;
 
-static void
-mt_listener_motion_event (const AccessibleEvent *event, gpointer data)
-{
-    MtEvent ev;
+    g_return_val_if_fail (connection != NULL, NULL);
 
-    ev.type = EV_MOTION;
-    ev.x = (gint) event->detail1;
-    ev.y = (gint) event->detail2;
-    ev.button = 0;
+    listener = g_object_new (MT_TYPE_LISTENER, NULL);
+    listener->priv->connection = dbus_g_connection_ref (connection);
+    mt_listener_setup_filter (listener);
 
-    g_signal_emit (data, signals[MOTION_EVENT], 0, &ev);
+    return listener;
 }
 
-static void
-mt_listener_button_event (const AccessibleEvent *event, gpointer data)
+DBusGProxy *
+mt_listener_current_focus (MtListener *listener)
 {
-    MtEvent ev;
+    g_return_val_if_fail (MT_IS_LISTENER (listener), NULL);
 
-    /*
-     * This is obviously dangerous, but it should be
-     * guarantied that event-type strings will always
-     * be in the form of "mouse:button:[1,2,3][p,r]"
-     */
-    ev.type = event->type[14] == 'p' ? EV_BUTTON_PRESS : EV_BUTTON_RELEASE;
-    ev.x = (gint) event->detail1;
-    ev.y = (gint) event->detail2;
-    ev.button = event->type[13] == '1' ? 1 : (event->type[13] == '2' ? 2 : 3);
-
-    g_signal_emit (data, signals[BUTTON_EVENT], 0, &ev);
+    if (listener->priv->track_focus && listener->priv->focus)
+	return g_object_ref (listener->priv->focus);
+    else
+	return NULL;
 }
 
-static void
-mt_listener_focus_event (const AccessibleEvent *event, gpointer data)
+void
+mt_listener_track_focus (MtListener *listener,
+                         gboolean    track)
 {
-    MtListenerPrivate *priv = MT_LISTENER (data)->priv;
-
-    if (event->source) {
-	if (priv->current_focus)
-	    Accessible_unref (priv->current_focus);
+    MtListenerPrivate *priv;
 
-	Accessible_ref (event->source);
-	priv->current_focus = event->source;
+    g_return_if_fail (MT_IS_LISTENER (listener));
 
-	g_signal_emit (data, signals[FOCUS_CHANGED], 0);
+    priv = listener->priv;
+    priv->track_focus = track;
+    if (!track && priv->focus) {
+	g_object_unref (priv->focus);
+	priv->focus = NULL;
     }
 }
 
-MtListener *
-mt_listener_get_default (void)
+GType
+mt_event_get_type (void)
 {
-    static MtListener *listener = NULL;
-
-    if (!listener)
-	listener = g_object_new (MT_TYPE_LISTENER, NULL);
+    static GType event = 0;
 
-    return listener;
+    if (G_UNLIKELY (event == 0))
+	event = g_boxed_type_register_static (g_intern_static_string ("MtEvent"),
+					      (GBoxedCopyFunc) mt_event_copy,
+					      (GBoxedFreeFunc) mt_event_free);
+    return event;
 }
 
-Accessible *
-mt_listener_current_focus (MtListener *listener)
+MtEvent *
+mt_event_copy (const MtEvent *event)
 {
-    g_return_val_if_fail (MT_IS_LISTENER (listener), NULL);
+    return g_memdup (event, sizeof (MtEvent));
+}
 
-    return listener->priv->current_focus;
+void
+mt_event_free (MtEvent *event)
+{
+    g_free (event);
 }
diff --git a/src/mt-listener.h b/src/mt-listener.h
index e000835..bacbbbd 100644
--- a/src/mt-listener.h
+++ b/src/mt-listener.h
@@ -20,10 +20,7 @@
 #ifndef __MT_LISTENER_H__
 #define __MT_LISTENER_H__
 
-#include <glib-object.h>
-#include <cspi/spi.h>
-
-G_BEGIN_DECLS
+#include <dbus/dbus-glib.h>
 
 #define MT_TYPE_EVENT            (mt_event_get_type ())
 #define MT_TYPE_LISTENER         (mt_listener_get_type ())
@@ -33,6 +30,8 @@ G_BEGIN_DECLS
 #define MT_IS_LISTENER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), MT_TYPE_LISTENER))
 #define MT_LISTENER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), MT_TYPE_LISTENER, MtListenerClass))
 
+G_BEGIN_DECLS
+
 typedef GObjectClass              MtListenerClass;
 typedef struct _MtListener        MtListener;
 typedef struct _MtListenerPrivate MtListenerPrivate;
@@ -43,8 +42,10 @@ struct _MtListener {
 };
 
 GType        mt_listener_get_type       (void) G_GNUC_CONST;
-MtListener * mt_listener_get_default    (void);
-Accessible * mt_listener_current_focus  (MtListener *listener);
+MtListener * mt_listener_new            (DBusGConnection *connection);
+DBusGProxy * mt_listener_current_focus  (MtListener      *listener);
+void         mt_listener_track_focus    (MtListener      *listener,
+					 gboolean         track);
 
 typedef enum {
     EV_MOTION = 0,
@@ -55,9 +56,9 @@ typedef enum {
 typedef struct _MtEvent MtEvent;
 struct _MtEvent {
     MtEventType type;
-    gint        x;
-    gint        y;
-    gint        button;
+    guint       x;
+    guint       y;
+    guint       button;
 };
 
 GType     mt_event_get_type (void) G_GNUC_CONST;
diff --git a/src/mt-main.c b/src/mt-main.c
index f62fa60..662451e 100644
--- a/src/mt-main.c
+++ b/src/mt-main.c
@@ -22,26 +22,21 @@
 #include <locale.h>
 
 #include <gtk/gtk.h>
-#include <gdk/gdkx.h>
-#include <cspi/spi.h>
-#include <dbus/dbus-glib.h>
 #include <X11/extensions/XTest.h>
 
+#include "mt-main.h"
 #include "mt-common.h"
-#include "mt-service.h"
 #include "mt-pidfile.h"
 #include "mt-ctw.h"
-#include "mt-timer.h"
 #include "mt-cursor-manager.h"
-#include "mt-cursor.h"
-#include "mt-main.h"
-#include "mt-listener.h"
-#include "mt-accessible.h"
 
 #define GSM_DBUS_NAME      "org.gnome.SessionManager"
 #define GSM_DBUS_PATH      "/org/gnome/SessionManager"
 #define GSM_DBUS_INTERFACE "org.gnome.SessionManager"
 
+#define SPI_ACCESSIBLE_GET_ROLE   "GetRole"
+#define ACCESSIBLE_ROLE_HYPERLINK 88
+
 enum {
     PRESS = 0,
     RELEASE,
@@ -297,7 +292,7 @@ dwell_start_gesture (MtData *mt)
 	cursor = gdk_cursor_new (GDK_CROSS);
 	root = gdk_screen_get_root_window (mt_main_current_screen (mt));
 	gdk_pointer_grab (root, FALSE,
-			  GDK_POINTER_MOTION_MASK, 
+			  GDK_POINTER_MOTION_MASK,
 			  NULL, cursor,
 			  gtk_get_current_event_time ());
 	gdk_cursor_unref (cursor);
@@ -357,55 +352,25 @@ dwell_timer_finished (MtTimer *timer, gpointer data)
 }
 
 static gboolean
-eval_func (Accessible *a, gpointer data)
-{
-    gchar *name;
-    gboolean found = FALSE;
-
-    name = Accessible_getName (a);
-    if (name) {
-	found = g_str_equal (name, "Window List");
-	SPI_freeString (name);
-    }
-    return found;
-}
-
-static gboolean
-push_func (Accessible *a, gpointer data)
+hyperlink_is_focused (MtData *mt)
 {
-    MtData *mt = data;
-    AccessibleRole role;
-
-    role = Accessible_getRole (a);
-    if (role != SPI_ROLE_PANEL && role != SPI_ROLE_EMBEDDED)
-	return FALSE;
+    DBusGProxy *focus;
+    GError *error = NULL;
+    guint role = 0;
 
-    if (!mt_accessible_is_visible (a))
+    focus = mt_listener_current_focus (mt->listener);
+    if (!focus)
 	return FALSE;
 
-    if (Accessible_isComponent (a))
-	return mt_accessible_in_extents (a, mt->pointer_x, mt->pointer_y);
-
-    return TRUE;
-}
-
-static gboolean
-mt_main_use_move_release (MtData *mt)
-{
-    Accessible *point, *search;
-
-    point = mt_accessible_at_point (mt->pointer_x, mt->pointer_y);
-    if (point) {
-	search = mt_accessible_search (point,
-				       MT_SEARCH_TYPE_BREADTH,
-				       eval_func, push_func, mt);
-	Accessible_unref (point);
-	if (search) {
-	    Accessible_unref (search);
-	    return TRUE;
-	}
+    dbus_g_proxy_call (focus, SPI_ACCESSIBLE_GET_ROLE, &error,
+		       G_TYPE_INVALID, G_TYPE_UINT, &role, G_TYPE_INVALID);
+    if (error) {
+	g_warning ("%s", error->message);
+	g_error_free (error);
     }
-    return FALSE;
+    g_object_unref (focus);
+
+    return role == ACCESSIBLE_ROLE_HYPERLINK;
 }
 
 static gboolean
@@ -426,7 +391,7 @@ delay_timer_finished (MtTimer *timer, gpointer data)
 
     mt_cursor_manager_restore_all (mt_cursor_manager_get_default ());
 
-    if (mt->move_release || mt_main_use_move_release (mt)) {
+    if (hyperlink_is_focused (mt)) {
 	/* release the click outside of the focused object to
 	 * abort any action started by button-press.
 	 */
@@ -492,7 +457,7 @@ global_motion_event (MtListener *listener,
 				   mt->pointer_x, mt->pointer_y,
 				   mt->x_old, mt->y_old);
 	    }
-	    mt_main_draw_line (mt, 
+	    mt_main_draw_line (mt,
 			       mt->pointer_x, mt->pointer_y,
 			       event->x, event->y);
 	    mt->x_old = event->x;
@@ -519,32 +484,13 @@ global_button_event (MtListener *listener,
 	    mt_cursor_manager_restore_all (mt_cursor_manager_get_default ());
 	}
     }
-    /*
-     * cancel a dwell-click in progress if a physical button
-     * is pressed - useful for mixed use-cases and testing
-     */
+    /* cancel a dwell-click in progress if a physical button is pressed */
     if ((event->type == EV_BUTTON_PRESS && mt_timer_is_running (mt->dwell_timer)) ||
         (event->type == EV_BUTTON_RELEASE && mt->dwell_drag_started)) {
 	mt_dwell_click_cancel (mt);
     }
 }
 
-static void
-global_focus_event (MtListener *listener,
-		    gpointer    data)
-{
-    MtData *mt = data;
-    Accessible *accessible;
-
-    if (mt->delay_enabled) {
-	accessible = mt_listener_current_focus (listener);
-	/* TODO: check for more objects and conditions.
-	 * Some links don't have jump actions, eg: text-mails in thunderbird.
-	 */
-	mt->move_release = mt_accessible_supports_action (accessible, "jump");
-    }
-}
-
 static gboolean
 cursor_overlay_time (MtData  *mt,
 		     guchar  *image,
@@ -669,8 +615,10 @@ gconf_value_changed (GConfClient *client,
 
     if (g_str_equal (key, OPT_THRESHOLD) && value->type == GCONF_VALUE_INT)
 	mt->threshold = gconf_value_get_int (value);
-    else if (g_str_equal (key, OPT_DELAY) && value->type == GCONF_VALUE_BOOL)
+    else if (g_str_equal (key, OPT_DELAY) && value->type == GCONF_VALUE_BOOL) {
 	mt->delay_enabled = gconf_value_get_bool (value);
+	mt_listener_track_focus (mt->listener, mt->delay_enabled);
+    }
     else if (g_str_equal (key, OPT_DELAY_T) && value->type == GCONF_VALUE_FLOAT)
 	mt_timer_set_target (mt->delay_timer, gconf_value_get_float (value));
     else if (g_str_equal (key, OPT_DWELL) && value->type == GCONF_VALUE_BOOL) {
@@ -751,33 +699,35 @@ get_gconf_options (MtData *mt)
 static void
 mt_main_request_logout (MtData *mt)
 {
-    DBusGConnection *bus;
     DBusGProxy *proxy;
+    GError *error = NULL;
 
-    bus = dbus_g_bus_get (DBUS_BUS_SESSION, NULL);
-    if (bus) {
-	proxy = dbus_g_proxy_new_for_name (bus,
-					   GSM_DBUS_NAME,
-					   GSM_DBUS_PATH,
-					   GSM_DBUS_INTERFACE);
-	/*
-	 * Call logout method of session manager:
-	 * mode: 0 = normal, 1 = no confirmation, 2 = force
-	 */
-	dbus_g_proxy_call (proxy, "Logout", NULL,
-			   G_TYPE_UINT, 1, G_TYPE_INVALID,
-			   G_TYPE_INVALID);
-	g_object_unref (proxy);
+    proxy = dbus_g_proxy_new_for_name (mt->session_bus,
+				       GSM_DBUS_NAME,
+				       GSM_DBUS_PATH,
+				       GSM_DBUS_INTERFACE);
+    /*
+     * Call the Logout method of the session manager:
+     * mode: 0 = normal, 1 = no confirmation, 2 = force
+     */
+    dbus_g_proxy_call (proxy, "Logout", NULL,
+		       G_TYPE_UINT, 1, G_TYPE_INVALID,
+		       G_TYPE_INVALID);
+    g_object_unref (proxy);
+    if (error) {
+	g_warning ("Logout: %s", error->message);
+	g_error_free (error);
     }
 }
 
 static gboolean
-accessibility_enabled (MtData *mt,
-		       gint    spi_status)
+accessibility_enabled (MtData *mt)
 {
+    gboolean a11y;
     gint ret;
 
-    if (spi_status != 0) {
+    a11y = gconf_client_get_bool (mt->client, GNOME_A11Y_KEY, NULL);
+    if (!a11y) {
 	ret = mt_common_show_dialog
 	    (_("Assistive Technology Support is not Enabled"),
 	     _("Mousetweaks requires assistive technologies to be enabled "
@@ -792,7 +742,7 @@ accessibility_enabled (MtData *mt,
 	    mt_main_request_logout (mt);
 	}
 	else {
-	    /* reset the selected option again */
+	    /* reset the selected option */
 	    if (gconf_client_get_bool (mt->client, OPT_DELAY, NULL))
 		gconf_client_set_bool (mt->client, OPT_DELAY, FALSE, NULL);
 	    if (gconf_client_get_bool (mt->client, OPT_DWELL, NULL))
@@ -803,6 +753,30 @@ accessibility_enabled (MtData *mt,
     return TRUE;
 }
 
+static DBusGConnection *
+mt_main_get_accessibility_bus (void)
+{
+    DBusGConnection *bus = NULL;
+    Display *dpy = GDK_DISPLAY ();
+    Atom at;
+    gint af;
+    gulong nitems, bytes;
+    guchar *bus_addr;
+
+    gdk_error_trap_push ();
+    if (XGetWindowProperty (dpy, XDefaultRootWindow (dpy),
+			    XInternAtom (dpy, "AT_SPI_BUS", FALSE),
+			    0L, 32L, False, AnyPropertyType,
+			    &at, &af, &nitems, &bytes, &bus_addr) == Success) {
+	if (at != None && af == 8)
+	    bus = dbus_g_connection_open ((gchar *) bus_addr, NULL);
+
+	XFree (bus_addr);
+    }
+    gdk_error_trap_pop ();
+    return bus;
+}
+
 static MtData *
 mt_data_init (void)
 {
@@ -816,10 +790,23 @@ mt_data_init (void)
 			      &ev_base, &err_base, &maj, &min)) {
 	XCloseDisplay (mt->xtst_display);
 	g_slice_free (MtData, mt);
-	g_critical ("No XTest extension found. Aborting..");
+	g_print ("No XTest extension found. Aborting.");
+	return NULL;
+    }
+
+    mt->session_bus = dbus_g_bus_get (DBUS_BUS_SESSION, NULL);
+    if (!mt->session_bus) {
+	g_print ("No connection to DBus session bus. Aborting.");
+	XCloseDisplay (mt->xtst_display);
+	g_slice_free (MtData, mt);
 	return NULL;
     }
 
+    /* connect to a11y bus, if it is not available reuse the session bus */
+    mt->a11y_bus = mt_main_get_accessibility_bus ();
+    if (!mt->a11y_bus)
+	mt->a11y_bus = dbus_g_connection_ref (mt->session_bus);
+
     mt->client = gconf_client_get_default ();
     gconf_client_add_dir (mt->client, GNOME_MOUSE_DIR,
 			  GCONF_CLIENT_PRELOAD_NONE, NULL);
@@ -840,7 +827,7 @@ mt_data_init (void)
     g_signal_connect (mt->dwell_timer, "tick",
 		      G_CALLBACK (mt_main_timer_tick), mt);
 
-    mt->service = mt_service_get_default ();
+    mt->service = mt_service_new (mt->session_bus);
     mt_service_set_clicktype (mt->service, DWELL_CLICK_TYPE_SINGLE, NULL);
 
     mt->n_screens = gdk_display_get_n_screens (gdk_display_get_default ());
@@ -854,17 +841,22 @@ mt_data_init (void)
 static void
 mt_data_free (MtData *mt)
 {
-    g_object_unref (mt->delay_timer);
-    g_object_unref (mt->dwell_timer);
-    g_object_unref (mt->service);
-    g_object_unref (mt->client);
-
-    if (mt->ui) {
-	gtk_widget_destroy (mt_ctw_get_window (mt));
-	g_object_unref (mt->ui);
-    }
+    if (mt) {
+	g_object_unref (mt->delay_timer);
+	g_object_unref (mt->dwell_timer);
+	g_object_unref (mt->service);
+	g_object_unref (mt->client);
+	dbus_g_connection_unref (mt->session_bus);
+	dbus_g_connection_unref (mt->a11y_bus);
+	XCloseDisplay (mt->xtst_display);
+
+	if (mt->ui) {
+	    gtk_widget_destroy (mt_ctw_get_window (mt));
+	    g_object_unref (mt->ui);
+	}
 
-    g_slice_free (MtData, mt);
+	g_slice_free (MtData, mt);
+    }
 }
 
 static MtCliArgs
@@ -929,12 +921,11 @@ mt_main (int argc, char **argv, MtCliArgs cli_args)
 {
     MtData *mt;
     MtCursorManager *manager;
-    MtListener *listener;
-    gint spi_status;
-    gint spi_leaks = 0;
+
+    gtk_init (&argc, &argv);
 
     if (mt_pidfile_create () < 0) {
-	g_warning ("Couldn't create PID file.");
+	g_print ("Could not create PID file. Aborting.");
 	return;
     }
 
@@ -943,20 +934,12 @@ mt_main (int argc, char **argv, MtCliArgs cli_args)
     signal (SIGQUIT, signal_handler);
     signal (SIGHUP, signal_handler);
 
-    gtk_init (&argc, &argv);
+    if (!(mt = mt_data_init ()))
+	goto out;
 
-    mt = mt_data_init ();
-    if (!mt)
-	goto FINISH;
-
-    spi_status = SPI_init ();
-    /* don't check a11y key in login mode */
-    if (!cli_args.login) {
-	if (!accessibility_enabled (mt, spi_status)) {
-	    mt_data_free (mt);
-	    goto FINISH;
-	}
-    }
+    if (!cli_args.login)
+	if (!accessibility_enabled (mt))
+	    goto out;
 
     /* load gconf settings */
     get_gconf_options (mt);
@@ -985,9 +968,9 @@ mt_main (int argc, char **argv, MtCliArgs cli_args)
 	g_free (cli_args.mode);
     }
 
-    /* init click-type windoe */
+    /* init click-type window */
     if (!mt_ctw_init (mt, cli_args.pos_x, cli_args.pos_y))
-	goto CLEANUP;
+	goto out;
 
     /* init cursor animation */
     manager = mt_cursor_manager_get_default ();
@@ -998,29 +981,21 @@ mt_main (int argc, char **argv, MtCliArgs cli_args)
                       G_CALLBACK (cursor_cache_cleared), mt);
 
     /* init at-spi signals */
-    listener = mt_listener_get_default ();
-    g_signal_connect (listener, "motion_event",
+    mt->listener = mt_listener_new (mt->a11y_bus);
+    mt_listener_track_focus (mt->listener, mt->delay_enabled);
+    g_signal_connect (mt->listener, "motion_event",
                       G_CALLBACK (global_motion_event), mt);
-    g_signal_connect (listener, "button_event",
+    g_signal_connect (mt->listener, "button_event",
                       G_CALLBACK (global_button_event), mt);
-    g_signal_connect (listener, "focus_changed",
-                      G_CALLBACK (global_focus_event), mt);
 
     gtk_main ();
 
     mt_cursor_manager_restore_all (manager);
     g_object_unref (manager);
-    g_object_unref (listener);
-
-CLEANUP:
-    spi_leaks = SPI_exit ();
+    g_object_unref (mt->listener);
+out:
     mt_data_free (mt);
-FINISH:
     mt_pidfile_remove ();
-
-    if (spi_leaks)
-	g_warning ("AT-SPI reported %i leak%s.",
-		   spi_leaks, spi_leaks != 1 ? "s" : "");
 }
 
 int
diff --git a/src/mt-main.h b/src/mt-main.h
index beedd94..d4ff5bb 100644
--- a/src/mt-main.h
+++ b/src/mt-main.h
@@ -22,21 +22,27 @@
 
 #include <gdk/gdkx.h>
 #include <gconf/gconf-client.h>
+#include <dbus/dbus-glib.h>
 
 #include "mt-timer.h"
 #include "mt-service.h"
 #include "mt-cursor.h"
+#include "mt-listener.h"
 
 G_BEGIN_DECLS
 
 typedef struct _MtData MtData;
 struct _MtData {
+    DBusGConnection *session_bus;
+    DBusGConnection *a11y_bus;
+
     GConfClient *client;
     GtkBuilder  *ui;
     MtService   *service;
     MtTimer     *delay_timer;
     MtTimer     *dwell_timer;
     MtCursor    *cursor;
+    MtListener  *listener;
     Display     *xtst_display;
     gint         n_screens;
     gint         direction;
@@ -54,13 +60,12 @@ struct _MtData {
     guint        dwell_enabled  : 1;
     guint        dwell_show_ctw : 1;
     guint        animate_cursor : 1;
+    guint        left_handed    : 1;
 
     /* state flags */
-    guint        left_handed           : 1;
     guint        dwell_drag_started    : 1;
     guint        dwell_gesture_started : 1;
     guint        override_cursor       : 1;
-    guint        move_release          : 1;
 };
 
 G_END_DECLS
diff --git a/src/mt-service.c b/src/mt-service.c
index e664cc8..aec13f7 100644
--- a/src/mt-service.c
+++ b/src/mt-service.c
@@ -17,7 +17,6 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <dbus/dbus-glib.h>
 #include <dbus/dbus-glib-bindings.h>
 
 #include "mt-service.h"
@@ -27,7 +26,8 @@
 #define MOUSETWEAKS_DBUS_PATH    "/org/gnome/Mousetweaks"
 
 struct _MtServicePrivate {
-    guint clicktype;
+    DBusGConnection *connection;
+    guint            clicktype;
 };
 
 enum {
@@ -40,8 +40,26 @@ static guint signals[LAST_SIGNAL] = { 0 };
 
 G_DEFINE_TYPE (MtService, mt_service, G_TYPE_OBJECT)
 
-static void mt_service_dispose  (GObject   *object);
-static void mt_service_register (MtService *service);
+static void
+mt_service_init (MtService *service)
+{
+    service->priv = G_TYPE_INSTANCE_GET_PRIVATE (service,
+						 MT_TYPE_SERVICE,
+						 MtServicePrivate);
+}
+
+static void
+mt_service_dispose (GObject *object)
+{
+    MtServicePrivate *priv = MT_SERVICE (object)->priv;
+
+    if (priv->connection) {
+	g_signal_emit (object, signals[STATUS_CHANGED], 0, FALSE);
+	dbus_g_connection_unref (priv->connection);
+	priv->connection = NULL;
+    }
+    G_OBJECT_CLASS (mt_service_parent_class)->dispose (object);
+}
 
 static void
 mt_service_class_init (MtServiceClass *klass)
@@ -71,43 +89,17 @@ mt_service_class_init (MtServiceClass *klass)
 				     &dbus_glib_mt_service_object_info);
 }
 
-static void
-mt_service_init (MtService *service)
-{
-    service->priv = G_TYPE_INSTANCE_GET_PRIVATE (service,
-						 MT_TYPE_SERVICE,
-						 MtServicePrivate);
-    mt_service_register (service);
-}
-
-static void
-mt_service_dispose (GObject *object)
-{
-    g_signal_emit (object, signals[STATUS_CHANGED], 0, FALSE);
-
-    G_OBJECT_CLASS (mt_service_parent_class)->dispose (object);
-}
-
-static void
+static gboolean
 mt_service_register (MtService *service)
 {
-    DBusGConnection *bus;
     DBusGProxy *proxy;
     GError *error = NULL;
     guint result;
 
-    bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
-    if (bus == NULL) {
-	g_warning ("Unable to connect to session bus: %s", error->message);
-	g_error_free (error);
-	return;
-    }
-
-    proxy = dbus_g_proxy_new_for_name (bus,
+    proxy = dbus_g_proxy_new_for_name (service->priv->connection,
 				       DBUS_SERVICE_DBUS,
 				       DBUS_PATH_DBUS,
 				       DBUS_INTERFACE_DBUS);
-
     if (!dbus_g_proxy_call (proxy, "RequestName", &error,
 			    G_TYPE_STRING, MOUSETWEAKS_DBUS_SERVICE,
 			    G_TYPE_UINT, DBUS_NAME_FLAG_DO_NOT_QUEUE,
@@ -117,34 +109,32 @@ mt_service_register (MtService *service)
 	g_warning ("Unable to acquire name: %s", error->message);
 	g_error_free (error);
 	g_object_unref (proxy);
-	return;
+	return FALSE;
     }
-
     g_object_unref (proxy);
 
     if (result == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
-	dbus_g_connection_register_g_object (bus,
+	dbus_g_connection_register_g_object (service->priv->connection,
 					     MOUSETWEAKS_DBUS_PATH,
 					     G_OBJECT (service));
     else
 	g_warning ("DBus: Not primary name owner.");
-}
 
-static MtService *
-mt_service_new (void)
-{
-    return g_object_new (MT_TYPE_SERVICE, NULL);
+    return TRUE;
 }
 
 MtService *
-mt_service_get_default (void)
+mt_service_new (DBusGConnection *connection)
 {
-    static MtService *service = NULL;
+    MtService *service;
 
-    if (!service) {
-	service = mt_service_new ();
-	g_signal_emit (service, signals[STATUS_CHANGED], 0, TRUE);
-    }
+    g_return_val_if_fail (connection != NULL, NULL);
+
+    service = g_object_new (MT_TYPE_SERVICE, NULL);
+    service->priv->connection = dbus_g_connection_ref (connection);
+
+    mt_service_register (service);
+    g_signal_emit (service, signals[STATUS_CHANGED], 0, TRUE);
 
     return service;
 }
@@ -157,10 +147,8 @@ mt_service_set_clicktype (MtService *service,
     g_return_val_if_fail (MT_IS_SERVICE (service), FALSE);
 
     service->priv->clicktype = clicktype;
+    g_signal_emit (service, signals[CLICKTYPE_CHANGED], 0, clicktype);
 
-    g_signal_emit (service,
-		   signals[CLICKTYPE_CHANGED],
-		   0, service->priv->clicktype);
     return TRUE;
 }
 
diff --git a/src/mt-service.h b/src/mt-service.h
index 602824f..3992a9b 100644
--- a/src/mt-service.h
+++ b/src/mt-service.h
@@ -20,7 +20,7 @@
 #ifndef __MT_SERVICE_H__
 #define __MT_SERVICE_H__
 
-#include <glib-object.h>
+#include <dbus/dbus-glib.h>
 
 G_BEGIN_DECLS
 
@@ -41,11 +41,11 @@ struct _MtService {
 };
 
 GType       mt_service_get_type      (void) G_GNUC_CONST;
-MtService * mt_service_get_default   (void);
-gboolean    mt_service_set_clicktype (MtService *service,
-				      guint      clicktype,
-				      GError   **error);
-guint       mt_service_get_clicktype (MtService *service);
+MtService * mt_service_new           (DBusGConnection *connection);
+gboolean    mt_service_set_clicktype (MtService       *service,
+				      guint            clicktype,
+				      GError         **error);
+guint       mt_service_get_clicktype (MtService       *service);
 
 G_END_DECLS
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]