diff options
author | William Jon McCann <mccann@jhu.edu> | 2007-12-17 03:51:50 +0000 |
---|---|---|
committer | William Jon McCann <mccann@src.gnome.org> | 2007-12-17 03:51:50 +0000 |
commit | bbb4511718cff9392a7bbaf6627e3ec440567b3c (patch) | |
tree | 5a9ec609007812101752814de679aa498daefa2e | |
parent | 0c7411c894b3a6e6ccb0a8d575ce113ec17d4554 (diff) | |
download | gnome-settings-daemon-bbb4511718cff9392a7bbaf6627e3ec440567b3c.tar.gz |
Add mouse plugin.
2007-12-16 William Jon McCann <mccann@jhu.edu>
* 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.
svn path=/trunk/; revision=14
-rw-r--r-- | ChangeLog | 28 | ||||
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | data/gnome-settings-daemon.schemas.in | 12 | ||||
-rw-r--r-- | plugins/Makefile.am | 1 | ||||
-rw-r--r-- | plugins/mouse/Makefile.am | 57 | ||||
-rw-r--r-- | plugins/mouse/gsd-locate-pointer.c | 243 | ||||
-rw-r--r-- | plugins/mouse/gsd-locate-pointer.h | 24 | ||||
-rw-r--r-- | plugins/mouse/gsd-mouse-manager.c | 641 | ||||
-rw-r--r-- | plugins/mouse/gsd-mouse-manager.h | 57 | ||||
-rw-r--r-- | plugins/mouse/gsd-mouse-plugin.c | 103 | ||||
-rw-r--r-- | plugins/mouse/gsd-mouse-plugin.h | 59 | ||||
-rw-r--r-- | plugins/mouse/mouse.gnome-settings-plugin.desktop.in | 8 |
12 files changed, 1234 insertions, 0 deletions
@@ -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= |