summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog28
-rw-r--r--configure.ac1
-rw-r--r--data/gnome-settings-daemon.schemas.in12
-rw-r--r--plugins/Makefile.am1
-rw-r--r--plugins/mouse/Makefile.am57
-rw-r--r--plugins/mouse/gsd-locate-pointer.c243
-rw-r--r--plugins/mouse/gsd-locate-pointer.h24
-rw-r--r--plugins/mouse/gsd-mouse-manager.c641
-rw-r--r--plugins/mouse/gsd-mouse-manager.h57
-rw-r--r--plugins/mouse/gsd-mouse-plugin.c103
-rw-r--r--plugins/mouse/gsd-mouse-plugin.h59
-rw-r--r--plugins/mouse/mouse.gnome-settings-plugin.desktop.in8
12 files changed, 1234 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 0e03ee79..d2e8b210 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -3,6 +3,34 @@
* configure.ac:
* data/gnome-settings-daemon.schemas.in:
* plugins/Makefile.am:
+ * plugins/mouse/Makefile.am:
+ * plugins/mouse/gsd-locate-pointer.c: (locate_pointer_expose),
+ (setup_window), (create_window), (locate_pointer_timeout),
+ (gsd_locate_pointer):
+ * plugins/mouse/gsd-locate-pointer.h:
+ * plugins/mouse/gsd-mouse-manager.c: (gsd_mouse_manager_stop),
+ (gsd_mouse_manager_set_property), (gsd_mouse_manager_get_property),
+ (gsd_mouse_manager_constructor), (gsd_mouse_manager_dispose),
+ (gsd_mouse_manager_class_init), (supports_xinput_devices),
+ (configure_button_layout), (xinput_device_has_buttons),
+ (set_xinput_devices_left_handed), (set_left_handed),
+ (set_motion_acceleration), (set_motion_threshold), (filter),
+ (set_locate_pointer), (mouse_callback), (register_config_callback),
+ (gsd_mouse_manager_init), (gsd_mouse_manager_start),
+ (gsd_mouse_manager_finalize), (gsd_mouse_manager_new):
+ * plugins/mouse/gsd-mouse-manager.h:
+ * plugins/mouse/gsd-mouse-plugin.c: (gsd_mouse_plugin_init),
+ (gsd_mouse_plugin_finalize), (impl_activate), (impl_deactivate),
+ (gsd_mouse_plugin_class_init):
+ * plugins/mouse/gsd-mouse-plugin.h:
+ * plugins/mouse/mouse.gnome-settings-plugin.desktop.in:
+ Add mouse plugin.
+
+2007-12-16 William Jon McCann <mccann@jhu.edu>
+
+ * configure.ac:
+ * data/gnome-settings-daemon.schemas.in:
+ * plugins/Makefile.am:
* plugins/keyboard/Makefile.am:
* plugins/keyboard/delayed-dialog.c: (gsd_delayed_show_dialog),
(delayed_show_timeout), (message_filter):
diff --git a/configure.ac b/configure.ac
index 52f2f074..27ec4aa6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -231,6 +231,7 @@ plugins/default-editor/Makefile
plugins/dummy/Makefile
plugins/font/Makefile
plugins/keyboard/Makefile
+plugins/mouse/Makefile
plugins/xrandr/Makefile
plugins/xrdb/Makefile
plugins/xrdb/data/Makefile
diff --git a/data/gnome-settings-daemon.schemas.in b/data/gnome-settings-daemon.schemas.in
index 811f4d60..085f83d8 100644
--- a/data/gnome-settings-daemon.schemas.in
+++ b/data/gnome-settings-daemon.schemas.in
@@ -50,6 +50,18 @@
</schema>
<schema>
+ <key>/schemas/apps/gnome-settings-daemon/plugins/mouse/active</key>
+ <applyto>/apps/gnome-settings-daemon/plugins/mouse/active</applyto>
+ <owner>gnome-settings-daemon</owner>
+ <type>bool</type>
+ <default>TRUE</default>
+ <locale name="C">
+ <short>True if the mouse settings manager plugin is enabled.</short>
+ <long>Set to True to enable the mouse settings manager plugin.</long>
+ </locale>
+ </schema>
+
+ <schema>
<key>/schemas/apps/gnome-settings-daemon/plugins/xrandr/active</key>
<applyto>/apps/gnome-settings-daemon/plugins/xrandr/active</applyto>
<owner>gnome-settings-daemon</owner>
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 425ff893..41bd723a 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -6,6 +6,7 @@ SUBDIRS = \
dummy \
font \
keyboard \
+ mouse \
xrandr \
xrdb \
xsettings \
diff --git a/plugins/mouse/Makefile.am b/plugins/mouse/Makefile.am
new file mode 100644
index 00000000..14388a39
--- /dev/null
+++ b/plugins/mouse/Makefile.am
@@ -0,0 +1,57 @@
+NULL =
+
+modules_flags = -export_dynamic -avoid-version -module -no-undefined
+
+plugindir = $(libdir)/gnome-settings-daemon/plugins
+
+INCLUDES = \
+ -I$(top_srcdir)/src \
+ -DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\"\
+ $(SETTINGS_PLUGIN_CFLAGS) \
+ $(NULL)
+
+plugin_LTLIBRARIES = \
+ libmouse.la \
+ $(NULL)
+
+libmouse_la_SOURCES = \
+ gsd-mouse-plugin.h \
+ gsd-mouse-plugin.c \
+ gsd-mouse-manager.h \
+ gsd-mouse-manager.c \
+ gsd-locate-pointer.h \
+ gsd-locate-pointer.c \
+ $(NULL)
+
+libmouse_la_LDFLAGS = \
+ $(PLUGIN_LIBTOOL_FLAGS) \
+ $(modules_flags) \
+ $(NULL)
+
+libmouse_la_LIBADD = \
+ $(SETTINGS_PLUGIN_LIBS) \
+ $(NULL)
+
+libmouse_la_CFLAGS = \
+ $(NULL)
+
+plugin_in_files = \
+ mouse.gnome-settings-plugin.desktop.in \
+ $(NULL)
+
+%.gnome-settings-plugin: %.gnome-settings-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache
+
+plugin_DATA = $(plugin_in_files:.gnome-settings-plugin.desktop.in=.gnome-settings-plugin)
+
+EXTRA_DIST = \
+ $(plugin_in_files) \
+ $(NULL)
+
+CLEANFILES = \
+ $(plugin_DATA) \
+ $(NULL)
+
+DISTCLEANFILES = \
+ $(plugin_DATA) \
+ $(NULL)
+
diff --git a/plugins/mouse/gsd-locate-pointer.c b/plugins/mouse/gsd-locate-pointer.c
new file mode 100644
index 00000000..68245112
--- /dev/null
+++ b/plugins/mouse/gsd-locate-pointer.c
@@ -0,0 +1,243 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * Copyright © 2001 Jonathan Blandford <jrb@gnome.org>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Red Hat not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. Red Hat makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * Authors: Jonathan Blandford
+ */
+
+#include <gtk/gtk.h>
+
+#include "gsd-locate-pointer.h"
+
+#define LARGE_SIZE 101
+#define SMALL_SIZE 51
+
+typedef enum {
+ STAGE_ONE,
+ STAGE_TWO,
+ STAGE_THREE,
+ STAGE_FOUR,
+ STAGE_DONE
+} LocatePointerStage;
+
+static LocatePointerStage stage;
+static GdkWindow *window = NULL;
+static gint cursor_x, cursor_y;
+static guint locate_pointer_id = 0;
+
+static gint
+locate_pointer_expose (GtkWidget *widget,
+ GdkEventExpose *event,
+ gpointer data)
+{
+ gint size;
+ GdkPoint points[4];
+
+ if (event->window != window)
+ return FALSE;
+
+ switch (stage)
+ {
+ case STAGE_ONE:
+ case STAGE_TWO:
+ size = LARGE_SIZE;
+ break;
+ case STAGE_THREE:
+ case STAGE_FOUR:
+ size = SMALL_SIZE;
+ break;
+ default:
+ return FALSE;
+ }
+
+ gdk_draw_rectangle (event->window,
+ widget->style->black_gc,
+ TRUE,
+ 0, 0, size, size);
+ switch (stage)
+ {
+ case STAGE_ONE:
+ case STAGE_THREE:
+ gdk_draw_rectangle (event->window,
+ widget->style->white_gc,
+ FALSE,
+ 1, 1, size - 3, size - 3);
+ break;
+ case STAGE_TWO:
+ case STAGE_FOUR:
+ points[0].x = size/2;
+ points[0].y = 0 + 1;
+ points[1].x = size - 2;
+ points[1].y = size/2;
+ points[2].x = size/2;
+ points[2].y = size - 2;
+ points[3].x = 0 + 1;
+ points[3].y = size/2;
+ gdk_draw_polygon (event->window,
+ widget->style->white_gc,
+ FALSE, points, 4);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ return TRUE;
+}
+
+static void
+setup_window (void)
+{
+ gint size;
+ GdkBitmap *mask;
+ GdkGC *gc;
+ GdkColor col;
+ GdkPoint points[4];
+
+ gdk_window_hide (window);
+ switch (stage)
+ {
+ case STAGE_ONE:
+ case STAGE_TWO:
+ size = LARGE_SIZE;
+ break;
+ case STAGE_THREE:
+ case STAGE_FOUR:
+ size = SMALL_SIZE;
+ break;
+ default:
+ return;
+ }
+
+ gdk_window_move_resize (window,
+ cursor_x - size/2,
+ cursor_y - size/2,
+ size, size);
+ mask = gdk_pixmap_new (window, size, size, 1);
+ gc = gdk_gc_new (mask);
+ switch (stage)
+ {
+ case STAGE_ONE:
+ case STAGE_THREE:
+ col.pixel = 1;
+ gdk_gc_set_foreground (gc, &col);
+ gdk_draw_rectangle (mask, gc, TRUE, 0, 0, size, size);
+ col.pixel = 0;
+ gdk_gc_set_foreground (gc, &col);
+ gdk_draw_rectangle (mask, gc, TRUE, 3, 3, size - 6, size - 6);
+ break;
+ case STAGE_TWO:
+ case STAGE_FOUR:
+ col.pixel = 0;
+ gdk_gc_set_foreground (gc, &col);
+ gdk_draw_rectangle (mask, gc, TRUE, 0, 0, size, size);
+ col.pixel = 1;
+ gdk_gc_set_foreground (gc, &col);
+ points[0].x = size/2;
+ points[0].y = 0;
+ points[1].x = size - 1;
+ points[1].y = size/2;
+ points[2].x = size/2;
+ points[2].y = size - 1;
+ points[3].x = 0;
+ points[3].y = size/2;
+ gdk_draw_polygon (mask, gc, FALSE, points, 4);
+ points[0].x = size/2;
+ points[0].y = 0 + 1;
+ points[1].x = size - 2;
+ points[1].y = size/2;
+ points[2].x = size/2;
+ points[2].y = size - 2;
+ points[3].x = 0 + 1;
+ points[3].y = size/2;
+ gdk_draw_polygon (mask, gc, FALSE, points, 4);
+ points[0].x = size/2;
+ points[0].y = 0 + 2;
+ points[1].x = size - 3;
+ points[1].y = size/2;
+ points[2].x = size/2;
+ points[2].y = size - 3;
+ points[3].x = 0 + 2;
+ points[3].y = size/2;
+ gdk_draw_polygon (mask, gc, FALSE, points, 4);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ gdk_window_shape_combine_mask (window, mask, 0, 0);
+ g_object_unref (G_OBJECT (gc));
+ g_object_unref (G_OBJECT (mask));
+ gdk_window_show (window);
+}
+
+static void
+create_window (GdkScreen *screen)
+{
+ GdkWindowAttr attributes;
+ GtkWidget *invisible;
+
+ invisible = gtk_invisible_new_for_screen (screen);
+
+ attributes.window_type = GDK_WINDOW_TEMP;
+ attributes.wclass = GDK_INPUT_OUTPUT;
+ attributes.visual = gtk_widget_get_visual (invisible);
+ attributes.colormap = gtk_widget_get_colormap (invisible);
+ attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK;
+ attributes.width = 1;
+ attributes.height = 1;
+ window = gdk_window_new (gdk_screen_get_root_window (screen),
+ &attributes,
+ GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP);
+ gdk_window_set_user_data (window, invisible);
+ g_signal_connect (G_OBJECT (invisible),
+ "expose_event",
+ (GCallback) locate_pointer_expose,
+ NULL);
+}
+
+static gboolean
+locate_pointer_timeout (gpointer data)
+{
+ stage++;
+ if (stage == STAGE_DONE)
+ {
+ gdk_window_hide (window);
+ locate_pointer_id = 0;
+ return FALSE;
+ }
+ setup_window ();
+ return TRUE;
+}
+
+void
+gsd_locate_pointer (GdkScreen *screen)
+{
+ gdk_window_get_pointer (gdk_screen_get_root_window (screen), &cursor_x, &cursor_y, NULL);
+
+ if (locate_pointer_id)
+ gtk_timeout_remove (locate_pointer_id);
+
+ /* Create the window if it is not created OR if it is not for the
+ * current screen.
+ */
+
+ if (window == NULL)
+ create_window (screen);
+ else if( gdk_screen_get_number (screen) != gdk_screen_get_number (gdk_drawable_get_screen (window)))
+ create_window (screen);
+
+ stage = STAGE_ONE;
+ setup_window ();
+ gdk_window_show (window);
+ locate_pointer_id = gtk_timeout_add (100, locate_pointer_timeout, NULL);
+}
diff --git a/plugins/mouse/gsd-locate-pointer.h b/plugins/mouse/gsd-locate-pointer.h
new file mode 100644
index 00000000..2d90e2e0
--- /dev/null
+++ b/plugins/mouse/gsd-locate-pointer.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright © 2001 Jonathan Blandford <jrb@gnome.org>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Red Hat not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. Red Hat makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * Authors: Jonathan Blandford
+ */
+
+#ifndef LOCATE_POINTER_H
+#define LOCATE_POINTER_H
+
+#include <gdk/gdkscreen.h>
+
+void gsd_locate_pointer (GdkScreen *screen);
+
+#endif
diff --git a/plugins/mouse/gsd-mouse-manager.c b/plugins/mouse/gsd-mouse-manager.c
new file mode 100644
index 00000000..fa286461
--- /dev/null
+++ b/plugins/mouse/gsd-mouse-manager.c
@@ -0,0 +1,641 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+
+#include <locale.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include <gdk/gdkkeysyms.h>
+#include <X11/keysym.h>
+
+#ifdef HAVE_XINPUT
+#include <X11/extensions/XInput.h>
+#endif
+#include <gconf/gconf.h>
+#include <gconf/gconf-client.h>
+
+#include "gsd-mouse-manager.h"
+
+#include "gsd-locate-pointer.h"
+
+#define GSD_MOUSE_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_MOUSE_MANAGER, GsdMouseManagerPrivate))
+
+#define KEY_LEFT_HANDED "/desktop/gnome/peripherals/mouse/left_handed"
+#define KEY_MOTION_ACCELERATION "/desktop/gnome/peripherals/mouse/motion_acceleration"
+#define KEY_MOTION_THRESHOLD "/desktop/gnome/peripherals/mouse/motion_threshold"
+#define KEY_LOCATE_POINTER "/desktop/gnome/peripherals/mouse/locate_pointer"
+
+struct GsdMouseManagerPrivate
+{
+
+};
+
+enum {
+ PROP_0,
+};
+
+static void gsd_mouse_manager_class_init (GsdMouseManagerClass *klass);
+static void gsd_mouse_manager_init (GsdMouseManager *mouse_manager);
+static void gsd_mouse_manager_finalize (GObject *object);
+
+G_DEFINE_TYPE (GsdMouseManager, gsd_mouse_manager, G_TYPE_OBJECT)
+
+static gpointer manager_object = NULL;
+
+void
+gsd_mouse_manager_stop (GsdMouseManager *manager)
+{
+ g_debug ("Stopping mouse manager");
+}
+
+static void
+gsd_mouse_manager_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GsdMouseManager *self;
+
+ self = GSD_MOUSE_MANAGER (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gsd_mouse_manager_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GsdMouseManager *self;
+
+ self = GSD_MOUSE_MANAGER (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GObject *
+gsd_mouse_manager_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GsdMouseManager *mouse_manager;
+ GsdMouseManagerClass *klass;
+
+ klass = GSD_MOUSE_MANAGER_CLASS (g_type_class_peek (GSD_TYPE_MOUSE_MANAGER));
+
+ mouse_manager = GSD_MOUSE_MANAGER (G_OBJECT_CLASS (gsd_mouse_manager_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_properties));
+
+ return G_OBJECT (mouse_manager);
+}
+
+static void
+gsd_mouse_manager_dispose (GObject *object)
+{
+ GsdMouseManager *mouse_manager;
+
+ mouse_manager = GSD_MOUSE_MANAGER (object);
+
+ G_OBJECT_CLASS (gsd_mouse_manager_parent_class)->dispose (object);
+}
+
+static void
+gsd_mouse_manager_class_init (GsdMouseManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->get_property = gsd_mouse_manager_get_property;
+ object_class->set_property = gsd_mouse_manager_set_property;
+ object_class->constructor = gsd_mouse_manager_constructor;
+ object_class->dispose = gsd_mouse_manager_dispose;
+ object_class->finalize = gsd_mouse_manager_finalize;
+
+ g_type_class_add_private (klass, sizeof (GsdMouseManagerPrivate));
+}
+
+
+#ifdef HAVE_XINPUT
+static gboolean
+supports_xinput_devices (void)
+{
+ gint op_code, event, error;
+
+ return XQueryExtension (GDK_DISPLAY (),
+ "XInputExtension",
+ &op_code,
+ &event,
+ &error);
+}
+#endif
+
+static void
+configure_button_layout (guchar *buttons,
+ gint n_buttons,
+ gboolean left_handed)
+{
+ const gint left_button = 1;
+ gint right_button;
+ gint i;
+
+ /* if the button is higher than 2 (3rd button) then it's
+ * probably one direction of a scroll wheel or something else
+ * uninteresting
+ */
+ right_button = MIN (n_buttons, 3);
+
+ /* If we change things we need to make sure we only swap buttons.
+ * If we end up with multiple physical buttons assigned to the same
+ * logical button the server will complain. This code assumes physical
+ * button 0 is the physical left mouse button, and that the physical
+ * button other than 0 currently assigned left_button or right_button
+ * is the physical right mouse button.
+ */
+
+ /* check if the current mapping satisfies the above assumptions */
+ if (buttons[left_button - 1] != left_button &&
+ buttons[left_button - 1] != right_button)
+ /* The current mapping is weird. Swapping buttons is probably not a
+ * good idea.
+ */
+ return;
+
+ /* check if we are left_handed and currently not swapped */
+ if (left_handed && buttons[left_button - 1] == left_button) {
+ /* find the right button */
+ for (i = 0; i < n_buttons; i++) {
+ if (buttons[i] == right_button) {
+ buttons[i] = left_button;
+ break;
+ }
+ }
+ /* swap the buttons */
+ buttons[left_button - 1] = right_button;
+ }
+ /* check if we are not left_handed but are swapped */
+ else if (!left_handed && buttons[left_button - 1] == right_button) {
+ /* find the right button */
+ for (i = 0; i < n_buttons; i++) {
+ if (buttons[i] == left_button) {
+ buttons[i] = right_button;
+ break;
+ }
+ }
+ /* swap the buttons */
+ buttons[left_button - 1] = left_button;
+ }
+}
+
+#ifdef HAVE_XINPUT
+static gboolean
+xinput_device_has_buttons (XDeviceInfo *device_info)
+{
+ int i;
+ XAnyClassInfo *class_info;
+
+ class_info = device_info->inputclassinfo;
+ for (i = 0; i < device_info->num_classes; i++) {
+ if (class_info->class == ButtonClass) {
+ XButtonInfo *button_info;
+
+ button_info = (XButtonInfo *) class_info;
+ if (button_info->num_buttons > 0)
+ return TRUE;
+ }
+
+ class_info = (XAnyClassInfo *) (((guchar *) class_info) +
+ class_info->length);
+ }
+ return FALSE;
+}
+
+static void
+set_xinput_devices_left_handed (gboolean left_handed)
+{
+ XDeviceInfo *device_info;
+ gint n_devices;
+ guchar *buttons;
+ gsize buttons_capacity = 16;
+ gint n_buttons;
+ gint i;
+
+ device_info = XListInputDevices (GDK_DISPLAY (), &n_devices);
+
+ if (n_devices > 0)
+ buttons = g_new (guchar, buttons_capacity);
+ else
+ buttons = NULL;
+
+ for (i = 0; i < n_devices; i++) {
+ XDevice *device = NULL;
+
+ if ((device_info[i].use != IsXExtensionDevice) ||
+ (!xinput_device_has_buttons (&device_info[i])))
+ continue;
+
+ gdk_error_trap_push ();
+
+ device = XOpenDevice (GDK_DISPLAY (), device_info[i].id);
+
+ if ((gdk_error_trap_pop () != 0) ||
+ (device == NULL))
+ continue;
+
+ n_buttons = XGetDeviceButtonMapping (GDK_DISPLAY (), device,
+ buttons,
+ buttons_capacity);
+
+ while (n_buttons > buttons_capacity) {
+ buttons_capacity = n_buttons;
+ buttons = (guchar *) g_realloc (buttons,
+ buttons_capacity * sizeof (guchar));
+
+ n_buttons = XGetDeviceButtonMapping (GDK_DISPLAY (), device,
+ buttons,
+ buttons_capacity);
+ }
+
+ configure_button_layout (buttons, n_buttons, left_handed);
+
+ XSetDeviceButtonMapping (GDK_DISPLAY (), device, buttons, n_buttons);
+ XCloseDevice (GDK_DISPLAY (), device);
+ }
+ g_free (buttons);
+
+ if (device_info != NULL)
+ XFreeDeviceList (device_info);
+}
+#endif
+
+static void
+set_left_handed (GsdMouseManager *manager,
+ gboolean left_handed)
+{
+ guchar *buttons ;
+ gsize buttons_capacity = 16;
+ gint n_buttons, i;
+
+#ifdef HAVE_XINPUT
+ if (supports_xinput_devices ()) {
+ set_xinput_devices_left_handed (left_handed);
+ }
+#endif
+
+ buttons = g_new (guchar, buttons_capacity);
+ n_buttons = XGetPointerMapping (GDK_DISPLAY (),
+ buttons,
+ (gint) buttons_capacity);
+ while (n_buttons > buttons_capacity) {
+ buttons_capacity = n_buttons;
+ buttons = (guchar *) g_realloc (buttons,
+ buttons_capacity * sizeof (guchar));
+
+ n_buttons = XGetPointerMapping (GDK_DISPLAY (),
+ buttons,
+ (gint) buttons_capacity);
+ }
+
+ configure_button_layout (buttons, n_buttons, left_handed);
+
+ /* X refuses to change the mapping while buttons are engaged,
+ * so if this is the case we'll retry a few times
+ */
+ for (i = 0;
+ i < 20 && XSetPointerMapping (GDK_DISPLAY (), buttons, n_buttons) == MappingBusy;
+ ++i) {
+ g_usleep (300);
+ }
+
+ g_free (buttons);
+}
+
+static void
+set_motion_acceleration (GsdMouseManager *manager,
+ gfloat motion_acceleration)
+{
+ gint numerator, denominator;
+
+ if (motion_acceleration >= 1.0) {
+ /* we want to get the acceleration, with a resolution of 0.5
+ */
+ if ((motion_acceleration - floor (motion_acceleration)) < 0.25) {
+ numerator = floor (motion_acceleration);
+ denominator = 1;
+ } else if ((motion_acceleration - floor (motion_acceleration)) < 0.5) {
+ numerator = ceil (2.0 * motion_acceleration);
+ denominator = 2;
+ } else if ((motion_acceleration - floor (motion_acceleration)) < 0.75) {
+ numerator = floor (2.0 *motion_acceleration);
+ denominator = 2;
+ } else {
+ numerator = ceil (motion_acceleration);
+ denominator = 1;
+ }
+ } else if (motion_acceleration < 1.0 && motion_acceleration > 0) {
+ /* This we do to 1/10ths */
+ numerator = floor (motion_acceleration * 10) + 1;
+ denominator= 10;
+ } else {
+ numerator = -1;
+ denominator = -1;
+ }
+
+ XChangePointerControl (GDK_DISPLAY (), True, False,
+ numerator, denominator,
+ 0);
+}
+
+static void
+set_motion_threshold (GsdMouseManager *manager,
+ int motion_threshold)
+{
+ XChangePointerControl (GDK_DISPLAY (), False, True,
+ 0, 0, motion_threshold);
+}
+
+
+#define KEYBOARD_GROUP_SHIFT 13
+#define KEYBOARD_GROUP_MASK ((1 << 13) | (1 << 14))
+
+/* Owen magic */
+static GdkFilterReturn
+filter (GdkXEvent *xevent,
+ GdkEvent *event,
+ gpointer data)
+{
+ XEvent *xev = (XEvent *) xevent;
+ guint keyval;
+ gint group;
+
+ GdkScreen *screen = (GdkScreen *)data;
+
+ if (xev->type == KeyPress ||
+ xev->type == KeyRelease) {
+ /* get the keysym */
+ group = (xev->xkey.state & KEYBOARD_GROUP_MASK) >> KEYBOARD_GROUP_SHIFT;
+ gdk_keymap_translate_keyboard_state (gdk_keymap_get_default (),
+ xev->xkey.keycode,
+ xev->xkey.state,
+ group,
+ &keyval,
+ NULL, NULL, NULL);
+ if (keyval == GDK_Control_L || keyval == GDK_Control_R) {
+ if (xev->type == KeyPress) {
+ XAllowEvents (gdk_x11_get_default_xdisplay (),
+ SyncKeyboard,
+ xev->xkey.time);
+ } else {
+ XAllowEvents (gdk_x11_get_default_xdisplay (),
+ AsyncKeyboard,
+ xev->xkey.time);
+ gsd_locate_pointer (screen);
+ }
+ } else {
+ XAllowEvents (gdk_x11_get_default_xdisplay (),
+ ReplayKeyboard,
+ xev->xkey.time);
+ XUngrabKeyboard (gdk_x11_get_default_xdisplay (),
+ xev->xkey.time);
+ }
+
+ return GDK_FILTER_REMOVE;
+ }
+ return GDK_FILTER_CONTINUE;
+}
+
+static void
+set_locate_pointer (GsdMouseManager *manager,
+ gboolean locate_pointer)
+{
+ GdkKeymapKey *keys;
+ GdkDisplay *display;
+ int n_screens;
+ int n_keys;
+ gboolean has_entries;
+ static const guint keyvals[] = { GDK_Control_L, GDK_Control_R };
+ unsigned j;
+
+ display = gdk_display_get_default ();
+ n_screens = gdk_display_get_n_screens (display);
+
+ for (j = 0 ; j < G_N_ELEMENTS (keyvals) ; j++) {
+ has_entries = gdk_keymap_get_entries_for_keyval (gdk_keymap_get_default (),
+ keyvals[j],
+ &keys,
+ &n_keys);
+ if (has_entries) {
+ gint i, j;
+
+ for (i = 0; i < n_keys; i++) {
+ for(j=0; j< n_screens; j++) {
+ GdkScreen *screen = gdk_display_get_screen (display, j);
+ Window xroot = gdk_x11_drawable_get_xid (gdk_screen_get_root_window (screen));
+
+ if (locate_pointer) {
+ XGrabKey (GDK_DISPLAY_XDISPLAY (display),
+ keys[i].keycode,
+ 0,
+ xroot,
+ False,
+ GrabModeAsync,
+ GrabModeSync);
+ XGrabKey (GDK_DISPLAY_XDISPLAY (display),
+ keys[i].keycode,
+ LockMask,
+ xroot,
+ False,
+ GrabModeAsync,
+ GrabModeSync);
+ XGrabKey (GDK_DISPLAY_XDISPLAY (display),
+ keys[i].keycode,
+ Mod2Mask,
+ xroot,
+ False,
+ GrabModeAsync,
+ GrabModeSync);
+ XGrabKey (GDK_DISPLAY_XDISPLAY (display),
+ keys[i].keycode,
+ Mod4Mask,
+ xroot,
+ False,
+ GrabModeAsync,
+ GrabModeSync);
+ } else {
+ XUngrabKey (GDK_DISPLAY_XDISPLAY (display),
+ keys[i].keycode,
+ Mod4Mask,
+ xroot);
+ XUngrabKey (GDK_DISPLAY_XDISPLAY (display),
+ keys[i].keycode,
+ Mod2Mask,
+ xroot);
+ XUngrabKey (GDK_DISPLAY_XDISPLAY (display),
+ keys[i].keycode,
+ LockMask,
+ xroot);
+ XUngrabKey (GDK_DISPLAY_XDISPLAY (display),
+ keys[i].keycode,
+ 0,
+ xroot);
+ }
+ }
+ }
+ g_free (keys);
+ if (locate_pointer) {
+ for (i = 0; i < n_screens; i++) {
+ GdkScreen *screen;
+ screen = gdk_display_get_screen (display, i);
+ gdk_window_add_filter (gdk_screen_get_root_window (screen),
+ filter,
+ screen);
+ }
+ } else {
+ for (i = 0; i < n_screens; i++) {
+ GdkScreen *screen;
+ screen = gdk_display_get_screen (display, i);
+ gdk_window_remove_filter (gdk_screen_get_root_window (screen),
+ filter,
+ screen);
+ }
+ }
+ }
+ }
+}
+
+static void
+mouse_callback (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ GsdMouseManager *manager)
+{
+ if (! strcmp (entry->key, KEY_LEFT_HANDED)) {
+ if (entry->value->type == GCONF_VALUE_BOOL) {
+ set_left_handed (manager, gconf_value_get_bool (entry->value));
+ }
+ } else if (! strcmp (entry->key, KEY_MOTION_ACCELERATION)) {
+ if (entry->value->type == GCONF_VALUE_FLOAT) {
+ set_motion_acceleration (manager, gconf_value_get_float (entry->value));
+ }
+ } else if (! strcmp (entry->key, KEY_MOTION_THRESHOLD)) {
+ if (entry->value->type == GCONF_VALUE_INT) {
+ set_motion_threshold (manager, gconf_value_get_int (entry->value));
+ }
+ } else if (! strcmp (entry->key, KEY_LOCATE_POINTER)) {
+ if (entry->value->type == GCONF_VALUE_BOOL) {
+ set_locate_pointer (manager, gconf_value_get_bool (entry->value));
+ }
+ }
+}
+
+static void
+register_config_callback (GsdMouseManager *manager,
+ const char *path,
+ GConfClientNotifyFunc func)
+{
+ GConfClient *client;
+
+ client = gconf_client_get_default ();
+
+ gconf_client_add_dir (client, path, GCONF_CLIENT_PRELOAD_NONE, NULL);
+ gconf_client_notify_add (client, path, func, manager, NULL, NULL);
+
+ g_object_unref (client);
+}
+
+static void
+gsd_mouse_manager_init (GsdMouseManager *manager)
+{
+ manager->priv = GSD_MOUSE_MANAGER_GET_PRIVATE (manager);
+
+ register_config_callback (manager,
+ "/desktop/gnome/peripherals/mouse",
+ (GConfClientNotifyFunc)mouse_callback);
+}
+
+gboolean
+gsd_mouse_manager_start (GsdMouseManager *manager,
+ GError **error)
+{
+ GConfClient *client;
+
+ g_debug ("Starting mouse manager");
+
+ client = gconf_client_get_default ();
+
+ set_left_handed (manager, gconf_client_get_bool (client, KEY_LEFT_HANDED, NULL));
+ set_motion_acceleration (manager, gconf_client_get_float (client, KEY_MOTION_ACCELERATION , NULL));
+ set_motion_threshold (manager, gconf_client_get_int (client, KEY_MOTION_THRESHOLD, NULL));
+ set_locate_pointer (manager, gconf_client_get_bool (client, KEY_LOCATE_POINTER, NULL));
+
+ g_object_unref (client);
+
+ return TRUE;
+}
+
+static void
+gsd_mouse_manager_finalize (GObject *object)
+{
+ GsdMouseManager *mouse_manager;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GSD_IS_MOUSE_MANAGER (object));
+
+ mouse_manager = GSD_MOUSE_MANAGER (object);
+
+ g_return_if_fail (mouse_manager->priv != NULL);
+
+ G_OBJECT_CLASS (gsd_mouse_manager_parent_class)->finalize (object);
+}
+
+GsdMouseManager *
+gsd_mouse_manager_new (void)
+{
+ if (manager_object != NULL) {
+ g_object_ref (manager_object);
+ } else {
+ manager_object = g_object_new (GSD_TYPE_MOUSE_MANAGER, NULL);
+ g_object_add_weak_pointer (manager_object,
+ (gpointer *) &manager_object);
+ }
+
+ return GSD_MOUSE_MANAGER (manager_object);
+}
diff --git a/plugins/mouse/gsd-mouse-manager.h b/plugins/mouse/gsd-mouse-manager.h
new file mode 100644
index 00000000..96f571f9
--- /dev/null
+++ b/plugins/mouse/gsd-mouse-manager.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ */
+
+#ifndef __GSD_MOUSE_MANAGER_H
+#define __GSD_MOUSE_MANAGER_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GSD_TYPE_MOUSE_MANAGER (gsd_mouse_manager_get_type ())
+#define GSD_MOUSE_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_MOUSE_MANAGER, GsdMouseManager))
+#define GSD_MOUSE_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GSD_TYPE_MOUSE_MANAGER, GsdMouseManagerClass))
+#define GSD_IS_MOUSE_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_MOUSE_MANAGER))
+#define GSD_IS_MOUSE_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_TYPE_MOUSE_MANAGER))
+#define GSD_MOUSE_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_TYPE_MOUSE_MANAGER, GsdMouseManagerClass))
+
+typedef struct GsdMouseManagerPrivate GsdMouseManagerPrivate;
+
+typedef struct
+{
+ GObject parent;
+ GsdMouseManagerPrivate *priv;
+} GsdMouseManager;
+
+typedef struct
+{
+ GObjectClass parent_class;
+} GsdMouseManagerClass;
+
+GType gsd_mouse_manager_get_type (void);
+
+GsdMouseManager * gsd_mouse_manager_new (void);
+gboolean gsd_mouse_manager_start (GsdMouseManager *manager,
+ GError **error);
+void gsd_mouse_manager_stop (GsdMouseManager *manager);
+
+G_END_DECLS
+
+#endif /* __GSD_MOUSE_MANAGER_H */
diff --git a/plugins/mouse/gsd-mouse-plugin.c b/plugins/mouse/gsd-mouse-plugin.c
new file mode 100644
index 00000000..0b55ca90
--- /dev/null
+++ b/plugins/mouse/gsd-mouse-plugin.c
@@ -0,0 +1,103 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ */
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+
+#include "gnome-settings-plugin.h"
+#include "gsd-mouse-plugin.h"
+#include "gsd-mouse-manager.h"
+
+struct GsdMousePluginPrivate {
+ GsdMouseManager *manager;
+};
+
+#define GSD_MOUSE_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), GSD_TYPE_MOUSE_PLUGIN, GsdMousePluginPrivate))
+
+GNOME_SETTINGS_PLUGIN_REGISTER (GsdMousePlugin, gsd_mouse_plugin)
+
+static void
+gsd_mouse_plugin_init (GsdMousePlugin *plugin)
+{
+ plugin->priv = GSD_MOUSE_PLUGIN_GET_PRIVATE (plugin);
+
+ g_debug ("GsdMousePlugin initializing");
+
+ plugin->priv->manager = gsd_mouse_manager_new ();
+}
+
+static void
+gsd_mouse_plugin_finalize (GObject *object)
+{
+ GsdMousePlugin *plugin;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GSD_IS_MOUSE_PLUGIN (object));
+
+ g_debug ("GsdMousePlugin finalizing");
+
+ plugin = GSD_MOUSE_PLUGIN (object);
+
+ g_return_if_fail (plugin->priv != NULL);
+
+ if (plugin->priv->manager != NULL) {
+ g_object_unref (plugin->priv->manager);
+ }
+
+ G_OBJECT_CLASS (gsd_mouse_plugin_parent_class)->finalize (object);
+}
+
+static void
+impl_activate (GnomeSettingsPlugin *plugin)
+{
+ gboolean res;
+ GError *error;
+
+ g_debug ("Activating mouse plugin");
+
+ error = NULL;
+ res = gsd_mouse_manager_start (GSD_MOUSE_PLUGIN (plugin)->priv->manager, &error);
+ if (! res) {
+ g_warning ("Unable to start mouse manager: %s", error->message);
+ g_error_free (error);
+ }
+}
+
+static void
+impl_deactivate (GnomeSettingsPlugin *plugin)
+{
+ g_debug ("Deactivating mouse plugin");
+}
+
+static void
+gsd_mouse_plugin_class_init (GsdMousePluginClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GnomeSettingsPluginClass *plugin_class = GNOME_SETTINGS_PLUGIN_CLASS (klass);
+
+ object_class->finalize = gsd_mouse_plugin_finalize;
+
+ plugin_class->activate = impl_activate;
+ plugin_class->deactivate = impl_deactivate;
+
+ g_type_class_add_private (klass, sizeof (GsdMousePluginPrivate));
+}
diff --git a/plugins/mouse/gsd-mouse-plugin.h b/plugins/mouse/gsd-mouse-plugin.h
new file mode 100644
index 00000000..6c7b5b63
--- /dev/null
+++ b/plugins/mouse/gsd-mouse-plugin.h
@@ -0,0 +1,59 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ */
+
+#ifndef __GSD_MOUSE_PLUGIN_H__
+#define __GSD_MOUSE_PLUGIN_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gmodule.h>
+
+#include "gnome-settings-plugin.h"
+
+G_BEGIN_DECLS
+
+#define GSD_TYPE_MOUSE_PLUGIN (gsd_mouse_plugin_get_type ())
+#define GSD_MOUSE_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_MOUSE_PLUGIN, GsdMousePlugin))
+#define GSD_MOUSE_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GSD_TYPE_MOUSE_PLUGIN, GsdMousePluginClass))
+#define GSD_IS_MOUSE_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_MOUSE_PLUGIN))
+#define GSD_IS_MOUSE_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_TYPE_MOUSE_PLUGIN))
+#define GSD_MOUSE_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_TYPE_MOUSE_PLUGIN, GsdMousePluginClass))
+
+typedef struct GsdMousePluginPrivate GsdMousePluginPrivate;
+
+typedef struct
+{
+ GnomeSettingsPlugin parent;
+ GsdMousePluginPrivate *priv;
+} GsdMousePlugin;
+
+typedef struct
+{
+ GnomeSettingsPluginClass parent_class;
+} GsdMousePluginClass;
+
+GType gsd_mouse_plugin_get_type (void) G_GNUC_CONST;
+
+/* All the plugins must implement this function */
+G_MODULE_EXPORT GType register_gnome_settings_plugin (GTypeModule *module);
+
+G_END_DECLS
+
+#endif /* __GSD_MOUSE_PLUGIN_H__ */
diff --git a/plugins/mouse/mouse.gnome-settings-plugin.desktop.in b/plugins/mouse/mouse.gnome-settings-plugin.desktop.in
new file mode 100644
index 00000000..3632a8c7
--- /dev/null
+++ b/plugins/mouse/mouse.gnome-settings-plugin.desktop.in
@@ -0,0 +1,8 @@
+[GNOME Settings Plugin]
+Module=dummy
+IAge=0
+_Name=Dummy
+_Description=Dummy plugin
+Authors=AUTHOR
+Copyright=Copyright © 2007 AUTHOR
+Website=