From e46b4adef5c6c6805b3ca6dbfbe99a4299252514 Mon Sep 17 00:00:00 2001 From: haxar Date: Tue, 21 Feb 2012 20:14:01 -0800 Subject: gsd to msd complete rename patch by NiceandGently; file rename commit --- plugins/mouse/gsd-locate-pointer.c | 504 ---------------- plugins/mouse/gsd-locate-pointer.h | 24 - plugins/mouse/gsd-mouse-manager.c | 1124 ------------------------------------ plugins/mouse/gsd-mouse-manager.h | 61 -- plugins/mouse/gsd-mouse-plugin.c | 104 ---- plugins/mouse/gsd-mouse-plugin.h | 63 -- plugins/mouse/gsd-timeline.c | 848 --------------------------- plugins/mouse/gsd-timeline.h | 127 ---- plugins/mouse/msd-locate-pointer.c | 504 ++++++++++++++++ plugins/mouse/msd-locate-pointer.h | 24 + plugins/mouse/msd-mouse-manager.c | 1124 ++++++++++++++++++++++++++++++++++++ plugins/mouse/msd-mouse-manager.h | 61 ++ plugins/mouse/msd-mouse-plugin.c | 104 ++++ plugins/mouse/msd-mouse-plugin.h | 63 ++ plugins/mouse/msd-timeline.c | 848 +++++++++++++++++++++++++++ plugins/mouse/msd-timeline.h | 127 ++++ 16 files changed, 2855 insertions(+), 2855 deletions(-) delete mode 100644 plugins/mouse/gsd-locate-pointer.c delete mode 100644 plugins/mouse/gsd-locate-pointer.h delete mode 100644 plugins/mouse/gsd-mouse-manager.c delete mode 100644 plugins/mouse/gsd-mouse-manager.h delete mode 100644 plugins/mouse/gsd-mouse-plugin.c delete mode 100644 plugins/mouse/gsd-mouse-plugin.h delete mode 100644 plugins/mouse/gsd-timeline.c delete mode 100644 plugins/mouse/gsd-timeline.h create mode 100644 plugins/mouse/msd-locate-pointer.c create mode 100644 plugins/mouse/msd-locate-pointer.h create mode 100644 plugins/mouse/msd-mouse-manager.c create mode 100644 plugins/mouse/msd-mouse-manager.h create mode 100644 plugins/mouse/msd-mouse-plugin.c create mode 100644 plugins/mouse/msd-mouse-plugin.h create mode 100644 plugins/mouse/msd-timeline.c create mode 100644 plugins/mouse/msd-timeline.h (limited to 'plugins/mouse') diff --git a/plugins/mouse/gsd-locate-pointer.c b/plugins/mouse/gsd-locate-pointer.c deleted file mode 100644 index 8582074..0000000 --- a/plugins/mouse/gsd-locate-pointer.c +++ /dev/null @@ -1,504 +0,0 @@ -/* msd-locate-pointer.c - * - * Copyright (C) 2008 Carlos Garnacho - * - * 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 -#include "msd-timeline.h" -#include "msd-locate-pointer.h" - -#include -#include -#include - -#define ANIMATION_LENGTH 750 -#define WINDOW_SIZE 101 -#define N_CIRCLES 4 - -/* All circles are supposed to be moving when progress - * reaches 0.5, and each of them are supposed to long - * for half of the progress, hence the need of 0.5 to - * get the circles interval, and the multiplication - * by 2 to know a circle progress */ -#define CIRCLES_PROGRESS_INTERVAL (0.5 / N_CIRCLES) -#define CIRCLE_PROGRESS(p) (MIN (1., ((gdouble) (p) * 2.))) - -typedef struct MsdLocatePointerData MsdLocatePointerData; - -struct MsdLocatePointerData -{ - MsdTimeline *timeline; - GtkWidget *widget; - GdkWindow *window; - - gdouble progress; -}; - -static MsdLocatePointerData *data = NULL; - -static void -locate_pointer_paint (MsdLocatePointerData *data, - cairo_t *cr, - gboolean composite) -{ - GdkColor color; - gdouble progress, circle_progress; - gint width, height, i; - GtkStyle *style; - - progress = data->progress; - - #if GTK_CHECK_VERSION(3, 0, 0) - width = gdk_window_get_width(GDK_WINDOW(data->window)); - height = gdk_window_get_height(GDK_WINDOW(data->window)); - #else - gdk_drawable_get_size(data->window, &width, &height); - #endif - - style = gtk_widget_get_style (data->widget); - color = style->bg[GTK_STATE_SELECTED]; - - cairo_set_source_rgba (cr, 1., 1., 1., 0.); - cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); - cairo_paint (cr); - - for (i = 0; i <= N_CIRCLES; i++) - { - if (progress < 0.) - break; - - circle_progress = MIN (1., (progress * 2)); - progress -= CIRCLES_PROGRESS_INTERVAL; - - if (circle_progress >= 1.) - continue; - - if (composite) - { - cairo_set_source_rgba (cr, - color.red / 65535., - color.green / 65535., - color.blue / 65535., - 1 - circle_progress); - cairo_arc (cr, - width / 2, - height / 2, - circle_progress * width / 2, - 0, 2 * G_PI); - - cairo_fill (cr); - cairo_stroke (cr); - } - else - { - cairo_set_source_rgb (cr, 0., 0., 0.); - cairo_set_line_width (cr, 3.); - cairo_arc (cr, - width / 2, - height / 2, - circle_progress * width / 2, - 0, 2 * G_PI); - cairo_stroke (cr); - - cairo_set_source_rgb (cr, 1., 1., 1.); - cairo_set_line_width (cr, 1.); - cairo_arc (cr, - width / 2, - height / 2, - circle_progress * width / 2, - 0, 2 * G_PI); - cairo_stroke (cr); - } - } -} - -static gboolean -locate_pointer_expose (GtkWidget *widget, - GdkEventExpose *event, - gpointer user_data) -{ - MsdLocatePointerData *data = (MsdLocatePointerData *) user_data; - cairo_t *cr; - - if (event->window != data->window) - return FALSE; - - cr = gdk_cairo_create (data->window); - locate_pointer_paint (data, cr, gtk_widget_is_composited (data->widget)); - cairo_destroy (cr); - - return TRUE; -} - -static void -update_shape (MsdLocatePointerData *data) -{ - cairo_t *cr; - GdkBitmap *mask; - - mask = gdk_pixmap_new (data->window, WINDOW_SIZE, WINDOW_SIZE, 1); - cr = gdk_cairo_create (mask); - locate_pointer_paint (data, cr, FALSE); - gdk_window_shape_combine_mask (data->window, mask, 0, 0); - g_object_unref (mask); - cairo_destroy (cr); -} - -static void -timeline_frame_cb (MsdTimeline *timeline, - gdouble progress, - gpointer user_data) -{ - MsdLocatePointerData *data = (MsdLocatePointerData *) user_data; - GdkScreen *screen; - gint cursor_x, cursor_y; - - if (gtk_widget_is_composited (data->widget)) - { - gdk_window_invalidate_rect (data->window, NULL, FALSE); - data->progress = progress; - } - else if (progress >= data->progress + CIRCLES_PROGRESS_INTERVAL) - { - /* only invalidate window each circle interval */ - update_shape (data); - gdk_window_invalidate_rect (data->window, NULL, FALSE); - data->progress += CIRCLES_PROGRESS_INTERVAL; - } - - screen = gdk_drawable_get_screen (data->window); - gdk_window_get_pointer (gdk_screen_get_root_window (screen), - &cursor_x, &cursor_y, NULL); - gdk_window_move (data->window, - cursor_x - WINDOW_SIZE / 2, - cursor_y - WINDOW_SIZE / 2); -} - -static void -set_transparent_shape (GdkWindow *window) -{ - GdkBitmap *mask; - cairo_t *cr; - - mask = gdk_pixmap_new (data->window, WINDOW_SIZE, WINDOW_SIZE, 1); - cr = gdk_cairo_create (mask); - - cairo_set_source_rgba (cr, 1., 1., 1., 0.); - cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); - cairo_paint (cr); - - gdk_window_shape_combine_mask (data->window, mask, 0, 0); - g_object_unref (mask); - cairo_destroy (cr); -} - -static void -unset_transparent_shape (GdkWindow *window) -{ - gdk_window_shape_combine_mask (data->window, NULL, 0, 0); -} - -static void -composited_changed (GtkWidget *widget, - MsdLocatePointerData *data) -{ - if (!gtk_widget_is_composited (widget)) - set_transparent_shape (data->window); - else - unset_transparent_shape (data->window); -} - -static void -timeline_finished_cb (MsdTimeline *timeline, - gpointer user_data) -{ - MsdLocatePointerData *data = (MsdLocatePointerData *) user_data; - - /* set transparent shape and hide window */ - if (!gtk_widget_is_composited (data->widget)) - set_transparent_shape (data->window); - - gdk_window_hide (data->window); -} - -static void -create_window (MsdLocatePointerData *data, - GdkScreen *screen) -{ - GdkColormap *colormap; - GdkVisual *visual; - GdkWindowAttr attributes; - - colormap = gdk_screen_get_rgba_colormap (screen); - visual = gdk_screen_get_rgba_visual (screen); - - if (!colormap) - { - colormap = gdk_screen_get_rgb_colormap (screen); - visual = gdk_screen_get_rgb_visual (screen); - } - - attributes.window_type = GDK_WINDOW_TEMP; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.visual = visual; - attributes.colormap = colormap; - attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK; - attributes.width = 1; - attributes.height = 1; - - data->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 (data->window, data->widget); -} - -static MsdLocatePointerData * -msd_locate_pointer_data_new (GdkScreen *screen) -{ - MsdLocatePointerData *data; - - data = g_new0 (MsdLocatePointerData, 1); - - /* this widget will never be shown, it's - * mainly used to get signals/events from - */ - data->widget = gtk_window_new (GTK_WINDOW_POPUP); - gtk_widget_realize (data->widget); - - g_signal_connect (G_OBJECT (data->widget), "expose_event", - G_CALLBACK (locate_pointer_expose), - data); - - data->timeline = msd_timeline_new (ANIMATION_LENGTH); - g_signal_connect (data->timeline, "frame", - G_CALLBACK (timeline_frame_cb), data); - g_signal_connect (data->timeline, "finished", - G_CALLBACK (timeline_finished_cb), data); - - create_window (data, screen); - - return data; -} - -static void -move_locate_pointer_window (MsdLocatePointerData *data, - GdkScreen *screen) -{ - gint cursor_x, cursor_y; - GdkBitmap *mask; - GdkColor col; - GdkGC *gc; - - gdk_window_get_pointer (gdk_screen_get_root_window (screen), &cursor_x, &cursor_y, NULL); - - gdk_window_move_resize (data->window, - cursor_x - WINDOW_SIZE / 2, - cursor_y - WINDOW_SIZE / 2, - WINDOW_SIZE, WINDOW_SIZE); - - col.pixel = 0; - mask = gdk_pixmap_new (data->window, WINDOW_SIZE, WINDOW_SIZE, 1); - - gc = gdk_gc_new (mask); - gdk_gc_set_foreground (gc, &col); - gdk_draw_rectangle (mask, gc, TRUE, 0, 0, WINDOW_SIZE, WINDOW_SIZE); - - /* allow events to happen through the window */ - gdk_window_input_shape_combine_mask (data->window, mask, 0, 0); - - g_object_unref (mask); - g_object_unref (gc); -} - -void -msd_locate_pointer (GdkScreen *screen) -{ - if (!data) - data = msd_locate_pointer_data_new (screen); - - msd_timeline_pause (data->timeline); - msd_timeline_rewind (data->timeline); - - /* Create again the window if it is not for the current screen */ - if (gdk_screen_get_number (screen) != gdk_screen_get_number (gdk_drawable_get_screen (data->window))) - { - gdk_window_set_user_data (data->window, NULL); - gdk_window_destroy (data->window); - - create_window (data, screen); - } - - data->progress = 0.; - - g_signal_connect (data->widget, "composited-changed", - G_CALLBACK (composited_changed), data); - - move_locate_pointer_window (data, screen); - composited_changed (data->widget, data); - gdk_window_show (data->window); - - msd_timeline_start (data->timeline); -} - - -#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 (xev->xkey.display, - SyncKeyboard, - xev->xkey.time); - } - else - { - XAllowEvents (xev->xkey.display, - AsyncKeyboard, - xev->xkey.time); - msd_locate_pointer (screen); - } - } - else - { - XAllowEvents (xev->xkey.display, - ReplayKeyboard, - xev->xkey.time); - XUngrabKeyboard (gdk_x11_get_default_xdisplay (), - xev->xkey.time); - } - } - - return GDK_FILTER_CONTINUE; -} - -static void -set_locate_pointer (void) -{ - 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; - Window xroot; - - screen = gdk_display_get_screen (display, j); - xroot = gdk_x11_drawable_get_xid (gdk_screen_get_root_window (screen)); - - 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); - } - } - - g_free (keys); - - 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); - } - } - } -} - - -int -main (int argc, char *argv[]) -{ - gtk_init (&argc, &argv); - - set_locate_pointer (); - - gtk_main (); - - return 0; -} - diff --git a/plugins/mouse/gsd-locate-pointer.h b/plugins/mouse/gsd-locate-pointer.h deleted file mode 100644 index c21da43..0000000 --- a/plugins/mouse/gsd-locate-pointer.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright © 2001 Jonathan Blandford - * - * 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 - -void msd_locate_pointer (GdkScreen *screen); - -#endif diff --git a/plugins/mouse/gsd-mouse-manager.c b/plugins/mouse/gsd-mouse-manager.c deleted file mode 100644 index d7cb8e4..0000000 --- a/plugins/mouse/gsd-mouse-manager.c +++ /dev/null @@ -1,1124 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- - * - * Copyright (C) 2007 William Jon McCann - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_X11_EXTENSIONS_XINPUT_H -#include -#include -#endif -#include -#include - -#include "mate-settings-profile.h" -#include "msd-mouse-manager.h" - -#define MSD_MOUSE_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MSD_TYPE_MOUSE_MANAGER, MsdMouseManagerPrivate)) - -#define MATECONF_MOUSE_DIR "/desktop/mate/peripherals/mouse" -#define MATECONF_MOUSE_A11Y_DIR "/desktop/mate/accessibility/mouse" -#define MATECONF_TOUCHPAD_DIR "/desktop/mate/peripherals/touchpad" - -#define KEY_LEFT_HANDED MATECONF_MOUSE_DIR "/left_handed" -#define KEY_MOTION_ACCELERATION MATECONF_MOUSE_DIR "/motion_acceleration" -#define KEY_MOTION_THRESHOLD MATECONF_MOUSE_DIR "/motion_threshold" -#define KEY_LOCATE_POINTER MATECONF_MOUSE_DIR "/locate_pointer" -#define KEY_DWELL_ENABLE MATECONF_MOUSE_A11Y_DIR "/dwell_enable" -#define KEY_DELAY_ENABLE MATECONF_MOUSE_A11Y_DIR "/delay_enable" -#define KEY_TOUCHPAD_DISABLE_W_TYPING MATECONF_TOUCHPAD_DIR "/disable_while_typing" -#ifdef HAVE_X11_EXTENSIONS_XINPUT_H -#define KEY_TAP_TO_CLICK MATECONF_TOUCHPAD_DIR "/tap_to_click" -#define KEY_SCROLL_METHOD MATECONF_TOUCHPAD_DIR "/scroll_method" -#define KEY_PAD_HORIZ_SCROLL MATECONF_TOUCHPAD_DIR "/horiz_scroll_enabled" -#define KEY_TOUCHPAD_ENABLED MATECONF_TOUCHPAD_DIR "/touchpad_enabled" -#endif - -struct MsdMouseManagerPrivate -{ - guint notify; - guint notify_a11y; - guint notify_touchpad; - - gboolean mousetweaks_daemon_running; - gboolean syndaemon_spawned; - GPid syndaemon_pid; - gboolean locate_pointer_spawned; - GPid locate_pointer_pid; -}; - -static void msd_mouse_manager_class_init (MsdMouseManagerClass *klass); -static void msd_mouse_manager_init (MsdMouseManager *mouse_manager); -static void msd_mouse_manager_finalize (GObject *object); -static void set_mouse_settings (MsdMouseManager *manager); -#ifdef HAVE_X11_EXTENSIONS_XINPUT_H -static int set_tap_to_click (gboolean state, gboolean left_handed); -static XDevice* device_is_touchpad (XDeviceInfo deviceinfo); -#endif - -G_DEFINE_TYPE (MsdMouseManager, msd_mouse_manager, G_TYPE_OBJECT) - -static gpointer manager_object = NULL; - -static void -msd_mouse_manager_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - MsdMouseManager *self; - - self = MSD_MOUSE_MANAGER (object); - - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -msd_mouse_manager_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - MsdMouseManager *self; - - self = MSD_MOUSE_MANAGER (object); - - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static GObject * -msd_mouse_manager_constructor (GType type, - guint n_construct_properties, - GObjectConstructParam *construct_properties) -{ - MsdMouseManager *mouse_manager; - MsdMouseManagerClass *klass; - - klass = MSD_MOUSE_MANAGER_CLASS (g_type_class_peek (MSD_TYPE_MOUSE_MANAGER)); - - mouse_manager = MSD_MOUSE_MANAGER (G_OBJECT_CLASS (msd_mouse_manager_parent_class)->constructor (type, - n_construct_properties, - construct_properties)); - - return G_OBJECT (mouse_manager); -} - -static void -msd_mouse_manager_dispose (GObject *object) -{ - MsdMouseManager *mouse_manager; - - mouse_manager = MSD_MOUSE_MANAGER (object); - - G_OBJECT_CLASS (msd_mouse_manager_parent_class)->dispose (object); -} - -static void -msd_mouse_manager_class_init (MsdMouseManagerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->get_property = msd_mouse_manager_get_property; - object_class->set_property = msd_mouse_manager_set_property; - object_class->constructor = msd_mouse_manager_constructor; - object_class->dispose = msd_mouse_manager_dispose; - object_class->finalize = msd_mouse_manager_finalize; - - g_type_class_add_private (klass, sizeof (MsdMouseManagerPrivate)); -} - - -#ifdef HAVE_X11_EXTENSIONS_XINPUT_H -static gboolean -supports_xinput_devices (void) -{ - gint op_code, event, error; - - return XQueryExtension (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), - "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_X11_EXTENSIONS_XINPUT_H -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 gboolean -touchpad_has_single_button (XDevice *device) -{ - Atom type, prop; - int format; - unsigned long nitems, bytes_after; - unsigned char *data; - gboolean is_single_button = FALSE; - int rc; - - prop = XInternAtom (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "Synaptics Capabilities", False); - if (!prop) - return FALSE; - - gdk_error_trap_push (); - rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, prop, 0, 1, False, - XA_INTEGER, &type, &format, &nitems, - &bytes_after, &data); - if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 3) - is_single_button = (data[0] == 1 && data[1] == 0 && data[2] == 0); - - if (rc == Success) - XFree (data); - - gdk_error_trap_pop (); - - return is_single_button; -} - - -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_XDISPLAY(gdk_display_get_default()), &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 == IsXPointer) || - (device_info[i].use == IsXKeyboard) || - (!xinput_device_has_buttons (&device_info[i]))) - continue; - - /* If the device is a touchpad, swap tap buttons - * around too, otherwise a tap would be a right-click */ - device = device_is_touchpad (device_info[i]); - if (device != NULL) { - MateConfClient *client = mateconf_client_get_default (); - gboolean tap = mateconf_client_get_bool (client, KEY_TAP_TO_CLICK, NULL); - gboolean single_button = touchpad_has_single_button (device); - - if (tap && !single_button) - set_tap_to_click (tap, left_handed); - XCloseDevice (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device); - g_object_unref (client); - - if (single_button) - continue; - } - - gdk_error_trap_push (); - - device = XOpenDevice (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device_info[i].id); - - if ((gdk_error_trap_pop () != 0) || - (device == NULL)) - continue; - - n_buttons = XGetDeviceButtonMapping (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), 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_XDISPLAY(gdk_display_get_default()), device, - buttons, - buttons_capacity); - } - - configure_button_layout (buttons, n_buttons, left_handed); - - XSetDeviceButtonMapping (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, buttons, n_buttons); - XCloseDevice (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device); - } - g_free (buttons); - - if (device_info != NULL) - XFreeDeviceList (device_info); -} - -static GdkFilterReturn -devicepresence_filter (GdkXEvent *xevent, - GdkEvent *event, - gpointer data) -{ - XEvent *xev = (XEvent *) xevent; - XEventClass class_presence; - int xi_presence; - - DevicePresence (gdk_x11_get_default_xdisplay (), xi_presence, class_presence); - - if (xev->type == xi_presence) - { - XDevicePresenceNotifyEvent *dpn = (XDevicePresenceNotifyEvent *) xev; - if (dpn->devchange == DeviceEnabled) - set_mouse_settings ((MsdMouseManager *) data); - } - return GDK_FILTER_CONTINUE; -} - -static void -set_devicepresence_handler (MsdMouseManager *manager) -{ - Display *display; - XEventClass class_presence; - int xi_presence; - - if (!supports_xinput_devices ()) - return; - - display = gdk_x11_get_default_xdisplay (); - - gdk_error_trap_push (); - DevicePresence (display, xi_presence, class_presence); - XSelectExtensionEvent (display, - RootWindow (display, DefaultScreen (display)), - &class_presence, 1); - - gdk_flush (); - if (!gdk_error_trap_pop ()) - gdk_window_add_filter (NULL, devicepresence_filter, manager); -} -#endif - -static void -set_left_handed (MsdMouseManager *manager, - gboolean left_handed) -{ - guchar *buttons ; - gsize buttons_capacity = 16; - gint n_buttons, i; - -#ifdef HAVE_X11_EXTENSIONS_XINPUT_H - if (supports_xinput_devices ()) { - /* When XInput support is available, never set the - * button ordering on the core pointer as that would - * revert the changes we make on the devices themselves */ - set_xinput_devices_left_handed (left_handed); - return; - } -#endif - - buttons = g_new (guchar, buttons_capacity); - n_buttons = XGetPointerMapping (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), - 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_XDISPLAY(gdk_display_get_default()), - 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_XDISPLAY(gdk_display_get_default()), buttons, n_buttons) == MappingBusy; - ++i) { - g_usleep (300); - } - - g_free (buttons); -} - -static void -set_motion_acceleration (MsdMouseManager *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_XDISPLAY(gdk_display_get_default()), True, False, - numerator, denominator, - 0); -} - -static void -set_motion_threshold (MsdMouseManager *manager, - int motion_threshold) -{ - XChangePointerControl (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), False, True, - 0, 0, motion_threshold); -} - -#ifdef HAVE_X11_EXTENSIONS_XINPUT_H -static XDevice* -device_is_touchpad (XDeviceInfo deviceinfo) -{ - XDevice *device; - Atom realtype, prop; - int realformat; - unsigned long nitems, bytes_after; - unsigned char *data; - - if (deviceinfo.type != XInternAtom (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), XI_TOUCHPAD, False)) - return NULL; - - prop = XInternAtom (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "Synaptics Off", False); - if (!prop) - return NULL; - - gdk_error_trap_push (); - device = XOpenDevice (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), deviceinfo.id); - if (gdk_error_trap_pop () || (device == NULL)) - return NULL; - - gdk_error_trap_push (); - if ((XGetDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, prop, 0, 1, False, - XA_INTEGER, &realtype, &realformat, &nitems, - &bytes_after, &data) == Success) && (realtype != None)) { - gdk_error_trap_pop (); - XFree (data); - return device; - } - gdk_error_trap_pop (); - - XCloseDevice (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device); - return NULL; -} -#endif - -static int -set_disable_w_typing (MsdMouseManager *manager, gboolean state) -{ - - if (state) { - GError *error = NULL; - char *args[5]; - - if (manager->priv->syndaemon_spawned) - return 0; - - args[0] = "syndaemon"; - args[1] = "-i"; - args[2] = "0.5"; - args[3] = "-k"; - args[4] = NULL; - - if (!g_find_program_in_path (args[0])) - return 0; - - g_spawn_async (g_get_home_dir (), args, NULL, - G_SPAWN_SEARCH_PATH, NULL, NULL, - &manager->priv->syndaemon_pid, &error); - - manager->priv->syndaemon_spawned = (error == NULL); - - if (error) { - MateConfClient *client; - client = mateconf_client_get_default (); - mateconf_client_set_bool (client, KEY_TOUCHPAD_DISABLE_W_TYPING, FALSE, NULL); - g_object_unref (client); - g_error_free (error); - } - - } else if (manager->priv->syndaemon_spawned) - { - kill (manager->priv->syndaemon_pid, SIGHUP); - g_spawn_close_pid (manager->priv->syndaemon_pid); - manager->priv->syndaemon_spawned = FALSE; - } - - return 0; -} - -#ifdef HAVE_X11_EXTENSIONS_XINPUT_H -static int -set_tap_to_click (gboolean state, gboolean left_handed) -{ - int numdevices, i, format, rc; - unsigned long nitems, bytes_after; - XDeviceInfo *devicelist = XListInputDevices (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), &numdevices); - XDevice * device; - unsigned char* data; - Atom prop, type; - - if (devicelist == NULL) - return 0; - - prop = XInternAtom (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "Synaptics Tap Action", False); - - if (!prop) - return 0; - - for (i = 0; i < numdevices; i++) { - if ((device = device_is_touchpad (devicelist[i]))) { - gdk_error_trap_push (); - rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, prop, 0, 2, - False, XA_INTEGER, &type, &format, &nitems, - &bytes_after, &data); - - if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 7) - { - /* Set RLM mapping for 1/2/3 fingers*/ - data[4] = (state) ? ((left_handed) ? 3 : 1) : 0; - data[5] = (state) ? ((left_handed) ? 1 : 3) : 0; - data[6] = (state) ? 2 : 0; - XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, prop, XA_INTEGER, 8, - PropModeReplace, data, nitems); - } - - if (rc == Success) - XFree (data); - XCloseDevice (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device); - if (gdk_error_trap_pop ()) { - g_warning ("Error in setting tap to click on \"%s\"", devicelist[i].name); - continue; - } - } - } - - XFreeDeviceList (devicelist); - return 0; -} - -static int -set_horiz_scroll (gboolean state) -{ - int numdevices, i, rc; - XDeviceInfo *devicelist = XListInputDevices (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), &numdevices); - XDevice *device; - Atom act_type, prop_edge, prop_twofinger; - int act_format; - unsigned long nitems, bytes_after; - unsigned char *data; - - if (devicelist == NULL) - return 0; - - prop_edge = XInternAtom (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "Synaptics Edge Scrolling", False); - prop_twofinger = XInternAtom (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "Synaptics Two-Finger Scrolling", False); - - if (!prop_edge || !prop_twofinger) - return 0; - - for (i = 0; i < numdevices; i++) { - if ((device = device_is_touchpad (devicelist[i]))) { - gdk_error_trap_push (); - rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, - prop_edge, 0, 1, False, - XA_INTEGER, &act_type, &act_format, &nitems, - &bytes_after, &data); - if (rc == Success && act_type == XA_INTEGER && - act_format == 8 && nitems >= 2) { - data[1] = (state && data[0]); - XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, - prop_edge, XA_INTEGER, 8, - PropModeReplace, data, nitems); - } - - XFree (data); - - rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, - prop_twofinger, 0, 1, False, - XA_INTEGER, &act_type, &act_format, &nitems, - &bytes_after, &data); - if (rc == Success && act_type == XA_INTEGER && - act_format == 8 && nitems >= 2) { - data[1] = (state && data[0]); - XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, - prop_twofinger, XA_INTEGER, 8, - PropModeReplace, data, nitems); - } - - XFree (data); - XCloseDevice (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device); - if (gdk_error_trap_pop ()) { - g_warning ("Error in setting horiz scroll on \"%s\"", devicelist[i].name); - continue; - } - } - } - - XFreeDeviceList (devicelist); - return 0; -} - - -/** - * Scroll methods are: 0 - disabled, 1 - edge scrolling, 2 - twofinger - * scrolling - */ -static int -set_edge_scroll (int method) -{ - int numdevices, i, rc; - XDeviceInfo *devicelist = XListInputDevices (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), &numdevices); - XDevice *device; - Atom act_type, prop_edge, prop_twofinger; - int act_format; - unsigned long nitems, bytes_after; - unsigned char *data; - - if (devicelist == NULL) - return 0; - - prop_edge = XInternAtom (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "Synaptics Edge Scrolling", False); - prop_twofinger = XInternAtom (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "Synaptics Two-Finger Scrolling", False); - - if (!prop_edge || !prop_twofinger) - return 0; - - for (i = 0; i < numdevices; i++) { - if ((device = device_is_touchpad (devicelist[i]))) { - gdk_error_trap_push (); - rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, - prop_edge, 0, 1, False, - XA_INTEGER, &act_type, &act_format, &nitems, - &bytes_after, &data); - if (rc == Success && act_type == XA_INTEGER && - act_format == 8 && nitems >= 2) { - data[0] = (method == 1) ? 1 : 0; - XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, - prop_edge, XA_INTEGER, 8, - PropModeReplace, data, nitems); - } - - XFree (data); - - rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, - prop_twofinger, 0, 1, False, - XA_INTEGER, &act_type, &act_format, &nitems, - &bytes_after, &data); - if (rc == Success && act_type == XA_INTEGER && - act_format == 8 && nitems >= 2) { - data[0] = (method == 2) ? 1 : 0; - XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, - prop_twofinger, XA_INTEGER, 8, - PropModeReplace, data, nitems); - } - - XFree (data); - XCloseDevice (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device); - if (gdk_error_trap_pop ()) { - g_warning ("Error in setting edge scroll on \"%s\"", devicelist[i].name); - continue; - } - } - } - - XFreeDeviceList (devicelist); - return 0; -} - -static int -set_touchpad_enabled (gboolean state) -{ - int numdevices, i; - XDeviceInfo *devicelist = XListInputDevices (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), &numdevices); - XDevice *device; - Atom prop_enabled; - - if (devicelist == NULL) - return 0; - - prop_enabled = XInternAtom (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "Device Enabled", False); - - if (!prop_enabled) - return 0; - - for (i = 0; i < numdevices; i++) { - if ((device = device_is_touchpad (devicelist[i]))) { - unsigned char data = state; - gdk_error_trap_push (); - XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, - prop_enabled, XA_INTEGER, 8, - PropModeReplace, &data, 1); - XCloseDevice (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device); - gdk_flush (); - if (gdk_error_trap_pop ()) { - g_warning ("Error %s device \"%s\"", - (state) ? "enabling" : "disabling", - devicelist[i].name); - continue; - } - } - } - - XFreeDeviceList (devicelist); - return 0; -} -#endif - -static void -set_locate_pointer (MsdMouseManager *manager, - gboolean state) -{ - if (state) { - GError *error = NULL; - char *args[2]; - - if (manager->priv->locate_pointer_spawned) - return; - - args[0] = LIBEXECDIR "/msd-locate-pointer"; - args[1] = NULL; - - g_spawn_async (NULL, args, NULL, - 0, NULL, NULL, - &manager->priv->locate_pointer_pid, &error); - - manager->priv->locate_pointer_spawned = (error == NULL); - - if (error) { - MateConfClient *client; - client = mateconf_client_get_default (); - mateconf_client_set_bool (client, KEY_LOCATE_POINTER, FALSE, NULL); - g_object_unref (client); - g_error_free (error); - } - - } - else if (manager->priv->locate_pointer_spawned) { - kill (manager->priv->locate_pointer_pid, SIGHUP); - g_spawn_close_pid (manager->priv->locate_pointer_pid); - manager->priv->locate_pointer_spawned = FALSE; - } -} - -static void -set_mousetweaks_daemon (MsdMouseManager *manager, - gboolean dwell_enable, - gboolean delay_enable) -{ - GError *error = NULL; - gchar *comm; - gboolean run_daemon = dwell_enable || delay_enable; - - if (run_daemon || manager->priv->mousetweaks_daemon_running) - comm = g_strdup_printf ("mousetweaks %s", - run_daemon ? "" : "-s"); - else - return; - - if (run_daemon) - manager->priv->mousetweaks_daemon_running = TRUE; - - - if (! g_spawn_command_line_async (comm, &error)) { - if (error->code == G_SPAWN_ERROR_NOENT && - (dwell_enable || delay_enable)) { - GtkWidget *dialog; - MateConfClient *client; - - client = mateconf_client_get_default (); - if (dwell_enable) - mateconf_client_set_bool (client, - KEY_DWELL_ENABLE, - FALSE, NULL); - else if (delay_enable) - mateconf_client_set_bool (client, - KEY_DELAY_ENABLE, - FALSE, NULL); - g_object_unref (client); - - dialog = gtk_message_dialog_new (NULL, 0, - GTK_MESSAGE_WARNING, - GTK_BUTTONS_OK, - _("Could not enable mouse accessibility features")); - gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), - _("Mouse accessibility requires Mousetweaks " - "to be installed on your system.")); - gtk_window_set_title (GTK_WINDOW (dialog), - _("Mouse Preferences")); - gtk_window_set_icon_name (GTK_WINDOW (dialog), - "input-mouse"); - gtk_dialog_run (GTK_DIALOG (dialog)); - gtk_widget_destroy (dialog); - } - g_error_free (error); - } - g_free (comm); -} - -static void -set_mouse_settings (MsdMouseManager *manager) -{ - MateConfClient *client = mateconf_client_get_default (); - gboolean left_handed = mateconf_client_get_bool (client, KEY_LEFT_HANDED, NULL); - - set_left_handed (manager, left_handed); - set_motion_acceleration (manager, mateconf_client_get_float (client, KEY_MOTION_ACCELERATION , NULL)); - set_motion_threshold (manager, mateconf_client_get_int (client, KEY_MOTION_THRESHOLD, NULL)); - - set_disable_w_typing (manager, mateconf_client_get_bool (client, KEY_TOUCHPAD_DISABLE_W_TYPING, NULL)); -#ifdef HAVE_X11_EXTENSIONS_XINPUT_H - set_tap_to_click (mateconf_client_get_bool (client, KEY_TAP_TO_CLICK, NULL), left_handed); - set_edge_scroll (mateconf_client_get_int (client, KEY_SCROLL_METHOD, NULL)); - set_horiz_scroll (mateconf_client_get_bool (client, KEY_PAD_HORIZ_SCROLL, NULL)); - set_touchpad_enabled (mateconf_client_get_bool (client, KEY_TOUCHPAD_ENABLED, NULL)); -#endif - - g_object_unref (client); -} - -static void -mouse_callback (MateConfClient *client, - guint cnxn_id, - MateConfEntry *entry, - MsdMouseManager *manager) -{ - if (! strcmp (entry->key, KEY_LEFT_HANDED)) { - if (entry->value->type == MATECONF_VALUE_BOOL) { - set_left_handed (manager, mateconf_value_get_bool (entry->value)); - } - } else if (! strcmp (entry->key, KEY_MOTION_ACCELERATION)) { - if (entry->value->type == MATECONF_VALUE_FLOAT) { - set_motion_acceleration (manager, mateconf_value_get_float (entry->value)); - } - } else if (! strcmp (entry->key, KEY_MOTION_THRESHOLD)) { - if (entry->value->type == MATECONF_VALUE_INT) { - set_motion_threshold (manager, mateconf_value_get_int (entry->value)); - } - } else if (! strcmp (entry->key, KEY_TOUCHPAD_DISABLE_W_TYPING)) { - if (entry->value->type == MATECONF_VALUE_BOOL) - set_disable_w_typing (manager, mateconf_value_get_bool (entry->value)); -#ifdef HAVE_X11_EXTENSIONS_XINPUT_H - } else if (! strcmp (entry->key, KEY_TAP_TO_CLICK)) { - if (entry->value->type == MATECONF_VALUE_BOOL) { - set_tap_to_click (mateconf_value_get_bool (entry->value), - mateconf_client_get_bool (client, KEY_LEFT_HANDED, NULL)); - } - } else if (! strcmp (entry->key, KEY_SCROLL_METHOD)) { - if (entry->value->type == MATECONF_VALUE_INT) { - set_edge_scroll (mateconf_value_get_int (entry->value)); - set_horiz_scroll (mateconf_client_get_bool (client, KEY_PAD_HORIZ_SCROLL, NULL)); - } - } else if (! strcmp (entry->key, KEY_PAD_HORIZ_SCROLL)) { - if (entry->value->type == MATECONF_VALUE_BOOL) - set_horiz_scroll (mateconf_value_get_bool (entry->value)); -#endif - } else if (! strcmp (entry->key, KEY_LOCATE_POINTER)) { - if (entry->value->type == MATECONF_VALUE_BOOL) { - set_locate_pointer (manager, mateconf_value_get_bool (entry->value)); - } -#ifdef HAVE_X11_EXTENSIONS_XINPUT_H - } else if (! strcmp (entry->key, KEY_TOUCHPAD_ENABLED)) { - if (entry->value->type == MATECONF_VALUE_BOOL) { - set_touchpad_enabled (mateconf_value_get_bool (entry->value)); - } -#endif - } else if (! strcmp (entry->key, KEY_DWELL_ENABLE)) { - if (entry->value->type == MATECONF_VALUE_BOOL) { - set_mousetweaks_daemon (manager, - mateconf_value_get_bool (entry->value), - mateconf_client_get_bool (client, KEY_DELAY_ENABLE, NULL)); - } - } else if (! strcmp (entry->key, KEY_DELAY_ENABLE)) { - if (entry->value->type == MATECONF_VALUE_BOOL) { - set_mousetweaks_daemon (manager, - mateconf_client_get_bool (client, KEY_DWELL_ENABLE, NULL), - mateconf_value_get_bool (entry->value)); - } - } -} - -static guint -register_config_callback (MsdMouseManager *manager, - MateConfClient *client, - const char *path, - MateConfClientNotifyFunc func) -{ - mateconf_client_add_dir (client, path, MATECONF_CLIENT_PRELOAD_ONELEVEL, NULL); - return mateconf_client_notify_add (client, path, func, manager, NULL, NULL); -} - -static void -msd_mouse_manager_init (MsdMouseManager *manager) -{ - manager->priv = MSD_MOUSE_MANAGER_GET_PRIVATE (manager); -} - -static gboolean -msd_mouse_manager_idle_cb (MsdMouseManager *manager) -{ - MateConfClient *client; - - mate_settings_profile_start (NULL); - - client = mateconf_client_get_default (); - - manager->priv->notify = - register_config_callback (manager, - client, - MATECONF_MOUSE_DIR, - (MateConfClientNotifyFunc) mouse_callback); - manager->priv->notify_a11y = - register_config_callback (manager, - client, - MATECONF_MOUSE_A11Y_DIR, - (MateConfClientNotifyFunc) mouse_callback); - manager->priv->notify_touchpad = - register_config_callback (manager, - client, - MATECONF_TOUCHPAD_DIR, - (MateConfClientNotifyFunc) mouse_callback); - manager->priv->syndaemon_spawned = FALSE; - -#ifdef HAVE_X11_EXTENSIONS_XINPUT_H - set_devicepresence_handler (manager); -#endif - set_mouse_settings (manager); - set_locate_pointer (manager, mateconf_client_get_bool (client, KEY_LOCATE_POINTER, NULL)); - set_mousetweaks_daemon (manager, - mateconf_client_get_bool (client, KEY_DWELL_ENABLE, NULL), - mateconf_client_get_bool (client, KEY_DELAY_ENABLE, NULL)); - - set_disable_w_typing (manager, mateconf_client_get_bool (client, KEY_TOUCHPAD_DISABLE_W_TYPING, NULL)); -#ifdef HAVE_X11_EXTENSIONS_XINPUT_H - set_tap_to_click (mateconf_client_get_bool (client, KEY_TAP_TO_CLICK, NULL), - mateconf_client_get_bool (client, KEY_LEFT_HANDED, NULL)); - set_edge_scroll (mateconf_client_get_int (client, KEY_SCROLL_METHOD, NULL)); - set_horiz_scroll (mateconf_client_get_bool (client, KEY_PAD_HORIZ_SCROLL, NULL)); - set_touchpad_enabled (mateconf_client_get_bool (client, KEY_TOUCHPAD_ENABLED, NULL)); -#endif - - g_object_unref (client); - - mate_settings_profile_end (NULL); - - return FALSE; -} - -gboolean -msd_mouse_manager_start (MsdMouseManager *manager, - GError **error) -{ - mate_settings_profile_start (NULL); - - g_idle_add ((GSourceFunc) msd_mouse_manager_idle_cb, manager); - - mate_settings_profile_end (NULL); - - return TRUE; -} - -void -msd_mouse_manager_stop (MsdMouseManager *manager) -{ - MsdMouseManagerPrivate *p = manager->priv; - MateConfClient *client; - - g_debug ("Stopping mouse manager"); - - client = mateconf_client_get_default (); - - if (p->notify != 0) { - mateconf_client_remove_dir (client, MATECONF_MOUSE_DIR, NULL); - mateconf_client_notify_remove (client, p->notify); - p->notify = 0; - } - - if (p->notify_a11y != 0) { - mateconf_client_remove_dir (client, MATECONF_MOUSE_A11Y_DIR, NULL); - mateconf_client_notify_remove (client, p->notify_a11y); - p->notify_a11y = 0; - } - - if (p->notify_touchpad != 0) { - mateconf_client_remove_dir (client, MATECONF_TOUCHPAD_DIR, NULL); - mateconf_client_notify_remove (client, p->notify_touchpad); - p->notify_touchpad = 0; - } - - g_object_unref (client); - - set_locate_pointer (manager, FALSE); - -#ifdef HAVE_X11_EXTENSIONS_XINPUT_H - gdk_window_remove_filter (NULL, devicepresence_filter, manager); -#endif -} - -static void -msd_mouse_manager_finalize (GObject *object) -{ - MsdMouseManager *mouse_manager; - - g_return_if_fail (object != NULL); - g_return_if_fail (MSD_IS_MOUSE_MANAGER (object)); - - mouse_manager = MSD_MOUSE_MANAGER (object); - - g_return_if_fail (mouse_manager->priv != NULL); - - G_OBJECT_CLASS (msd_mouse_manager_parent_class)->finalize (object); -} - -MsdMouseManager * -msd_mouse_manager_new (void) -{ - if (manager_object != NULL) { - g_object_ref (manager_object); - } else { - manager_object = g_object_new (MSD_TYPE_MOUSE_MANAGER, NULL); - g_object_add_weak_pointer (manager_object, - (gpointer *) &manager_object); - } - - return MSD_MOUSE_MANAGER (manager_object); -} diff --git a/plugins/mouse/gsd-mouse-manager.h b/plugins/mouse/gsd-mouse-manager.h deleted file mode 100644 index e691d7b..0000000 --- a/plugins/mouse/gsd-mouse-manager.h +++ /dev/null @@ -1,61 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- - * - * Copyright (C) 2007 William Jon McCann - * - * 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 __MSD_MOUSE_MANAGER_H -#define __MSD_MOUSE_MANAGER_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define MSD_TYPE_MOUSE_MANAGER (msd_mouse_manager_get_type ()) -#define MSD_MOUSE_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MSD_TYPE_MOUSE_MANAGER, MsdMouseManager)) -#define MSD_MOUSE_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), MSD_TYPE_MOUSE_MANAGER, MsdMouseManagerClass)) -#define MSD_IS_MOUSE_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MSD_TYPE_MOUSE_MANAGER)) -#define MSD_IS_MOUSE_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MSD_TYPE_MOUSE_MANAGER)) -#define MSD_MOUSE_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), MSD_TYPE_MOUSE_MANAGER, MsdMouseManagerClass)) - -typedef struct MsdMouseManagerPrivate MsdMouseManagerPrivate; - -typedef struct -{ - GObject parent; - MsdMouseManagerPrivate *priv; -} MsdMouseManager; - -typedef struct -{ - GObjectClass parent_class; -} MsdMouseManagerClass; - -GType msd_mouse_manager_get_type (void); - -MsdMouseManager * msd_mouse_manager_new (void); -gboolean msd_mouse_manager_start (MsdMouseManager *manager, - GError **error); -void msd_mouse_manager_stop (MsdMouseManager *manager); - -#ifdef __cplusplus -} -#endif - -#endif /* __MSD_MOUSE_MANAGER_H */ diff --git a/plugins/mouse/gsd-mouse-plugin.c b/plugins/mouse/gsd-mouse-plugin.c deleted file mode 100644 index 7203002..0000000 --- a/plugins/mouse/gsd-mouse-plugin.c +++ /dev/null @@ -1,104 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- - * - * Copyright (C) 2007 William Jon McCann - * - * 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 -#include - -#include "mate-settings-plugin.h" -#include "msd-mouse-plugin.h" -#include "msd-mouse-manager.h" - -struct MsdMousePluginPrivate { - MsdMouseManager *manager; -}; - -#define MSD_MOUSE_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), MSD_TYPE_MOUSE_PLUGIN, MsdMousePluginPrivate)) - -MATE_SETTINGS_PLUGIN_REGISTER (MsdMousePlugin, msd_mouse_plugin) - -static void -msd_mouse_plugin_init (MsdMousePlugin *plugin) -{ - plugin->priv = MSD_MOUSE_PLUGIN_GET_PRIVATE (plugin); - - g_debug ("MsdMousePlugin initializing"); - - plugin->priv->manager = msd_mouse_manager_new (); -} - -static void -msd_mouse_plugin_finalize (GObject *object) -{ - MsdMousePlugin *plugin; - - g_return_if_fail (object != NULL); - g_return_if_fail (MSD_IS_MOUSE_PLUGIN (object)); - - g_debug ("MsdMousePlugin finalizing"); - - plugin = MSD_MOUSE_PLUGIN (object); - - g_return_if_fail (plugin->priv != NULL); - - if (plugin->priv->manager != NULL) { - g_object_unref (plugin->priv->manager); - } - - G_OBJECT_CLASS (msd_mouse_plugin_parent_class)->finalize (object); -} - -static void -impl_activate (MateSettingsPlugin *plugin) -{ - gboolean res; - GError *error; - - g_debug ("Activating mouse plugin"); - - error = NULL; - res = msd_mouse_manager_start (MSD_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 (MateSettingsPlugin *plugin) -{ - g_debug ("Deactivating mouse plugin"); - msd_mouse_manager_stop (MSD_MOUSE_PLUGIN (plugin)->priv->manager); -} - -static void -msd_mouse_plugin_class_init (MsdMousePluginClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - MateSettingsPluginClass *plugin_class = MATE_SETTINGS_PLUGIN_CLASS (klass); - - object_class->finalize = msd_mouse_plugin_finalize; - - plugin_class->activate = impl_activate; - plugin_class->deactivate = impl_deactivate; - - g_type_class_add_private (klass, sizeof (MsdMousePluginPrivate)); -} diff --git a/plugins/mouse/gsd-mouse-plugin.h b/plugins/mouse/gsd-mouse-plugin.h deleted file mode 100644 index 2c2da6c..0000000 --- a/plugins/mouse/gsd-mouse-plugin.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- - * - * Copyright (C) 2007 William Jon McCann - * - * 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 __MSD_MOUSE_PLUGIN_H__ -#define __MSD_MOUSE_PLUGIN_H__ - -#include -#include -#include - -#include "mate-settings-plugin.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define MSD_TYPE_MOUSE_PLUGIN (msd_mouse_plugin_get_type ()) -#define MSD_MOUSE_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MSD_TYPE_MOUSE_PLUGIN, MsdMousePlugin)) -#define MSD_MOUSE_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), MSD_TYPE_MOUSE_PLUGIN, MsdMousePluginClass)) -#define MSD_IS_MOUSE_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MSD_TYPE_MOUSE_PLUGIN)) -#define MSD_IS_MOUSE_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MSD_TYPE_MOUSE_PLUGIN)) -#define MSD_MOUSE_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), MSD_TYPE_MOUSE_PLUGIN, MsdMousePluginClass)) - -typedef struct MsdMousePluginPrivate MsdMousePluginPrivate; - -typedef struct -{ - MateSettingsPlugin parent; - MsdMousePluginPrivate *priv; -} MsdMousePlugin; - -typedef struct -{ - MateSettingsPluginClass parent_class; -} MsdMousePluginClass; - -GType msd_mouse_plugin_get_type (void) G_GNUC_CONST; - -/* All the plugins must implement this function */ -G_MODULE_EXPORT GType register_mate_settings_plugin (GTypeModule *module); - -#ifdef __cplusplus -} -#endif - -#endif /* __MSD_MOUSE_PLUGIN_H__ */ diff --git a/plugins/mouse/gsd-timeline.c b/plugins/mouse/gsd-timeline.c deleted file mode 100644 index 9bcfd2f..0000000 --- a/plugins/mouse/gsd-timeline.c +++ /dev/null @@ -1,848 +0,0 @@ -/* msd-timeline.c - * - * Copyright (C) 2008 Carlos Garnacho - * - * 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 -#include -#include -#include "msd-timeline.h" - -#define MSD_TIMELINE_GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MSD_TYPE_TIMELINE, MsdTimelinePriv)) -#define MSECS_PER_SEC 1000 -#define FRAME_INTERVAL(nframes) (MSECS_PER_SEC / nframes) -#define DEFAULT_FPS 30 - -typedef struct MsdTimelinePriv MsdTimelinePriv; - -struct MsdTimelinePriv -{ - guint duration; - guint fps; - guint source_id; - - GTimer *timer; - - GdkScreen *screen; - MsdTimelineProgressType progress_type; - MsdTimelineProgressFunc progress_func; - - guint loop : 1; - guint direction : 1; -}; - -enum { - PROP_0, - PROP_FPS, - PROP_DURATION, - PROP_LOOP, - PROP_DIRECTION, - PROP_SCREEN, - PROP_PROGRESS_TYPE, -}; - -enum { - STARTED, - PAUSED, - FINISHED, - FRAME, - LAST_SIGNAL -}; - -static guint signals [LAST_SIGNAL] = { 0, }; - - -static void msd_timeline_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void msd_timeline_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); -static void msd_timeline_finalize (GObject *object); - - -G_DEFINE_TYPE (MsdTimeline, msd_timeline, G_TYPE_OBJECT) - - -GType -msd_timeline_direction_get_type (void) -{ - static GType type = 0; - - if (G_UNLIKELY (type == 0)) - { - static const GEnumValue values[] = { - { MSD_TIMELINE_DIRECTION_FORWARD, "MSD_TIMELINE_DIRECTION_FORWARD", "forward" }, - { MSD_TIMELINE_DIRECTION_BACKWARD, "MSD_TIMELINE_DIRECTION_BACKWARD", "backward" }, - { 0, NULL, NULL } - }; - - type = g_enum_register_static (g_intern_static_string ("MsdTimelineDirection"), values); - } - - return type; -} - -GType -msd_timeline_progress_type_get_type (void) -{ - static GType type = 0; - - if (G_UNLIKELY (type == 0)) - { - static const GEnumValue values[] = { - { MSD_TIMELINE_PROGRESS_LINEAR, "MSD_TIMELINE_PROGRESS_LINEAR", "linear" }, - { MSD_TIMELINE_PROGRESS_SINUSOIDAL, "MSD_TIMELINE_PROGRESS_SINUSOIDAL", "sinusoidal" }, - { MSD_TIMELINE_PROGRESS_EXPONENTIAL, "MSD_TIMELINE_PROGRESS_EXPONENTIAL", "exponential" }, - { 0, NULL, NULL } - }; - - type = g_enum_register_static (g_intern_static_string ("MsdTimelineProgressType"), values); - } - - return type; -} - -static void -msd_timeline_class_init (MsdTimelineClass *class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (class); - - object_class->set_property = msd_timeline_set_property; - object_class->get_property = msd_timeline_get_property; - object_class->finalize = msd_timeline_finalize; - - g_object_class_install_property (object_class, - PROP_FPS, - g_param_spec_uint ("fps", - "FPS", - "Frames per second for the timeline", - 1, - G_MAXUINT, - DEFAULT_FPS, - G_PARAM_READWRITE)); - g_object_class_install_property (object_class, - PROP_DURATION, - g_param_spec_uint ("duration", - "Animation Duration", - "Animation Duration", - 0, - G_MAXUINT, - 0, - G_PARAM_READWRITE)); - g_object_class_install_property (object_class, - PROP_LOOP, - g_param_spec_boolean ("loop", - "Loop", - "Whether the timeline loops or not", - FALSE, - G_PARAM_READWRITE)); - g_object_class_install_property (object_class, - PROP_DIRECTION, - g_param_spec_enum ("direction", - "Direction", - "Whether the timeline moves forward or backward in time", - MSD_TYPE_TIMELINE_DIRECTION, - MSD_TIMELINE_DIRECTION_FORWARD, - G_PARAM_READWRITE)); - g_object_class_install_property (object_class, - PROP_DIRECTION, - g_param_spec_enum ("progress-type", - "Progress type", - "Type of progress through the timeline", - MSD_TYPE_TIMELINE_PROGRESS_TYPE, - MSD_TIMELINE_PROGRESS_LINEAR, - G_PARAM_READWRITE)); - g_object_class_install_property (object_class, - PROP_SCREEN, - g_param_spec_object ("screen", - "Screen", - "Screen to get the settings from", - GDK_TYPE_SCREEN, - G_PARAM_READWRITE)); - - signals[STARTED] = - g_signal_new ("started", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (MsdTimelineClass, started), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - signals[PAUSED] = - g_signal_new ("paused", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (MsdTimelineClass, paused), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - signals[FINISHED] = - g_signal_new ("finished", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (MsdTimelineClass, finished), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - signals[FRAME] = - g_signal_new ("frame", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (MsdTimelineClass, frame), - NULL, NULL, - g_cclosure_marshal_VOID__DOUBLE, - G_TYPE_NONE, 1, - G_TYPE_DOUBLE); - - g_type_class_add_private (class, sizeof (MsdTimelinePriv)); -} - -static void -msd_timeline_init (MsdTimeline *timeline) -{ - MsdTimelinePriv *priv; - - priv = MSD_TIMELINE_GET_PRIV (timeline); - - priv->fps = DEFAULT_FPS; - priv->duration = 0; - priv->direction = MSD_TIMELINE_DIRECTION_FORWARD; - priv->screen = gdk_screen_get_default (); -} - -static void -msd_timeline_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - MsdTimeline *timeline; - MsdTimelinePriv *priv; - - timeline = MSD_TIMELINE (object); - priv = MSD_TIMELINE_GET_PRIV (timeline); - - switch (prop_id) - { - case PROP_FPS: - msd_timeline_set_fps (timeline, g_value_get_uint (value)); - break; - case PROP_DURATION: - msd_timeline_set_duration (timeline, g_value_get_uint (value)); - break; - case PROP_LOOP: - msd_timeline_set_loop (timeline, g_value_get_boolean (value)); - break; - case PROP_DIRECTION: - msd_timeline_set_direction (timeline, g_value_get_enum (value)); - break; - case PROP_SCREEN: - msd_timeline_set_screen (timeline, - GDK_SCREEN (g_value_get_object (value))); - break; - case PROP_PROGRESS_TYPE: - msd_timeline_set_progress_type (timeline, g_value_get_enum (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -msd_timeline_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - MsdTimeline *timeline; - MsdTimelinePriv *priv; - - timeline = MSD_TIMELINE (object); - priv = MSD_TIMELINE_GET_PRIV (timeline); - - switch (prop_id) - { - case PROP_FPS: - g_value_set_uint (value, priv->fps); - break; - case PROP_DURATION: - g_value_set_uint (value, priv->duration); - break; - case PROP_LOOP: - g_value_set_boolean (value, priv->loop); - break; - case PROP_DIRECTION: - g_value_set_enum (value, priv->direction); - break; - case PROP_SCREEN: - g_value_set_object (value, priv->screen); - break; - case PROP_PROGRESS_TYPE: - g_value_set_enum (value, priv->progress_type); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -msd_timeline_finalize (GObject *object) -{ - MsdTimelinePriv *priv; - - priv = MSD_TIMELINE_GET_PRIV (object); - - if (priv->source_id) - { - g_source_remove (priv->source_id); - priv->source_id = 0; - } - - if (priv->timer) - g_timer_destroy (priv->timer); - - G_OBJECT_CLASS (msd_timeline_parent_class)->finalize (object); -} - -/* Sinusoidal progress */ -static gdouble -sinusoidal_progress (gdouble progress) -{ - return (sinf ((progress * G_PI) / 2)); -} - -static gdouble -exponential_progress (gdouble progress) -{ - return progress * progress; -} - -static MsdTimelineProgressFunc -progress_type_to_func (MsdTimelineProgressType type) -{ - if (type == MSD_TIMELINE_PROGRESS_SINUSOIDAL) - return sinusoidal_progress; - else if (type == MSD_TIMELINE_PROGRESS_EXPONENTIAL) - return exponential_progress; - - return NULL; -} - -static gboolean -msd_timeline_run_frame (MsdTimeline *timeline, - gboolean enable_animations) -{ - MsdTimelinePriv *priv; - gdouble linear_progress, progress; - guint elapsed_time; - MsdTimelineProgressFunc progress_func = NULL; - - priv = MSD_TIMELINE_GET_PRIV (timeline); - - if (enable_animations) - { - elapsed_time = (guint) (g_timer_elapsed (priv->timer, NULL) * 1000); - - linear_progress = (gdouble) elapsed_time / priv->duration; - - if (priv->direction == MSD_TIMELINE_DIRECTION_BACKWARD) - linear_progress = 1 - linear_progress; - - linear_progress = CLAMP (linear_progress, 0., 1.); - - if (priv->progress_func) - progress_func = priv->progress_func; - else if (priv->progress_type) - progress_func = progress_type_to_func (priv->progress_type); - - if (progress_func) - progress = (progress_func) (linear_progress); - else - progress = linear_progress; - } - else - progress = (priv->direction == MSD_TIMELINE_DIRECTION_FORWARD) ? 1.0 : 0.0; - - g_signal_emit (timeline, signals [FRAME], 0, - CLAMP (progress, 0.0, 1.0)); - - if ((priv->direction == MSD_TIMELINE_DIRECTION_FORWARD && progress >= 1.0) || - (priv->direction == MSD_TIMELINE_DIRECTION_BACKWARD && progress <= 0.0)) - { - if (!priv->loop) - { - if (priv->source_id) - { - g_source_remove (priv->source_id); - priv->source_id = 0; - } - - g_signal_emit (timeline, signals [FINISHED], 0); - return FALSE; - } - else - msd_timeline_rewind (timeline); - } - - return TRUE; -} - -static gboolean -msd_timeline_frame_idle_func (MsdTimeline *timeline) -{ - return msd_timeline_run_frame (timeline, TRUE); -} - -/** - * msd_timeline_new: - * @duration: duration in milliseconds for the timeline - * - * Creates a new #MsdTimeline with the specified number of frames. - * - * Return Value: the newly created #MsdTimeline - **/ -MsdTimeline * -msd_timeline_new (guint duration) -{ - return g_object_new (MSD_TYPE_TIMELINE, - "duration", duration, - NULL); -} - -MsdTimeline * -msd_timeline_new_for_screen (guint duration, - GdkScreen *screen) -{ - return g_object_new (MSD_TYPE_TIMELINE, - "duration", duration, - "screen", screen, - NULL); -} - -/** - * msd_timeline_start: - * @timeline: A #MsdTimeline - * - * Runs the timeline from the current frame. - **/ -void -msd_timeline_start (MsdTimeline *timeline) -{ - MsdTimelinePriv *priv; - GtkSettings *settings; - gboolean enable_animations = FALSE; - - g_return_if_fail (MSD_IS_TIMELINE (timeline)); - - priv = MSD_TIMELINE_GET_PRIV (timeline); - - if (priv->screen) - { - settings = gtk_settings_get_for_screen (priv->screen); - g_object_get (settings, "gtk-enable-animations", &enable_animations, NULL); - } - - if (enable_animations) - { - if (!priv->source_id) - { - if (priv->timer) - g_timer_continue (priv->timer); - else - priv->timer = g_timer_new (); - - /* sanity check */ - g_assert (priv->fps > 0); - - g_signal_emit (timeline, signals [STARTED], 0); - - priv->source_id = gdk_threads_add_timeout (FRAME_INTERVAL (priv->fps), - (GSourceFunc) msd_timeline_frame_idle_func, - timeline); - } - } - else - { - /* If animations are not enabled, only run the last frame, - * it take us instantaneously to the last state of the animation. - * The only potential flaw happens when people use the ::finished - * signal to trigger another animation, or even worse, finally - * loop into this animation again. - */ - g_signal_emit (timeline, signals [STARTED], 0); - msd_timeline_run_frame (timeline, FALSE); - } -} - -/** - * msd_timeline_pause: - * @timeline: A #MsdTimeline - * - * Pauses the timeline. - **/ -void -msd_timeline_pause (MsdTimeline *timeline) -{ - MsdTimelinePriv *priv; - - g_return_if_fail (MSD_IS_TIMELINE (timeline)); - - priv = MSD_TIMELINE_GET_PRIV (timeline); - - if (priv->source_id) - { - g_source_remove (priv->source_id); - priv->source_id = 0; - g_timer_stop (priv->timer); - g_signal_emit (timeline, signals [PAUSED], 0); - } -} - -/** - * msd_timeline_rewind: - * @timeline: A #MsdTimeline - * - * Rewinds the timeline. - **/ -void -msd_timeline_rewind (MsdTimeline *timeline) -{ - MsdTimelinePriv *priv; - - g_return_if_fail (MSD_IS_TIMELINE (timeline)); - - priv = MSD_TIMELINE_GET_PRIV (timeline); - - /* destroy and re-create timer if neccesary */ - if (priv->timer) - { - g_timer_destroy (priv->timer); - - if (msd_timeline_is_running (timeline)) - priv->timer = g_timer_new (); - else - priv->timer = NULL; - } -} - -/** - * msd_timeline_is_running: - * @timeline: A #MsdTimeline - * - * Returns whether the timeline is running or not. - * - * Return Value: %TRUE if the timeline is running - **/ -gboolean -msd_timeline_is_running (MsdTimeline *timeline) -{ - MsdTimelinePriv *priv; - - g_return_val_if_fail (MSD_IS_TIMELINE (timeline), FALSE); - - priv = MSD_TIMELINE_GET_PRIV (timeline); - - return (priv->source_id != 0); -} - -/** - * msd_timeline_get_fps: - * @timeline: A #MsdTimeline - * - * Returns the number of frames per second. - * - * Return Value: frames per second - **/ -guint -msd_timeline_get_fps (MsdTimeline *timeline) -{ - MsdTimelinePriv *priv; - - g_return_val_if_fail (MSD_IS_TIMELINE (timeline), 1); - - priv = MSD_TIMELINE_GET_PRIV (timeline); - return priv->fps; -} - -/** - * msd_timeline_set_fps: - * @timeline: A #MsdTimeline - * @fps: frames per second - * - * Sets the number of frames per second that - * the timeline will play. - **/ -void -msd_timeline_set_fps (MsdTimeline *timeline, - guint fps) -{ - MsdTimelinePriv *priv; - - g_return_if_fail (MSD_IS_TIMELINE (timeline)); - g_return_if_fail (fps > 0); - - priv = MSD_TIMELINE_GET_PRIV (timeline); - - priv->fps = fps; - - if (msd_timeline_is_running (timeline)) - { - g_source_remove (priv->source_id); - priv->source_id = gdk_threads_add_timeout (FRAME_INTERVAL (priv->fps), - (GSourceFunc) msd_timeline_run_frame, - timeline); - } - - g_object_notify (G_OBJECT (timeline), "fps"); -} - -/** - * msd_timeline_get_loop: - * @timeline: A #MsdTimeline - * - * Returns whether the timeline loops to the - * beginning when it has reached the end. - * - * Return Value: %TRUE if the timeline loops - **/ -gboolean -msd_timeline_get_loop (MsdTimeline *timeline) -{ - MsdTimelinePriv *priv; - - g_return_val_if_fail (MSD_IS_TIMELINE (timeline), FALSE); - - priv = MSD_TIMELINE_GET_PRIV (timeline); - return priv->loop; -} - -/** - * msd_timeline_set_loop: - * @timeline: A #MsdTimeline - * @loop: %TRUE to make the timeline loop - * - * Sets whether the timeline loops to the beginning - * when it has reached the end. - **/ -void -msd_timeline_set_loop (MsdTimeline *timeline, - gboolean loop) -{ - MsdTimelinePriv *priv; - - g_return_if_fail (MSD_IS_TIMELINE (timeline)); - - priv = MSD_TIMELINE_GET_PRIV (timeline); - priv->loop = loop; - - g_object_notify (G_OBJECT (timeline), "loop"); -} - -void -msd_timeline_set_duration (MsdTimeline *timeline, - guint duration) -{ - MsdTimelinePriv *priv; - - g_return_if_fail (MSD_IS_TIMELINE (timeline)); - - priv = MSD_TIMELINE_GET_PRIV (timeline); - - priv->duration = duration; - - g_object_notify (G_OBJECT (timeline), "duration"); -} - -guint -msd_timeline_get_duration (MsdTimeline *timeline) -{ - MsdTimelinePriv *priv; - - g_return_val_if_fail (MSD_IS_TIMELINE (timeline), 0); - - priv = MSD_TIMELINE_GET_PRIV (timeline); - - return priv->duration; -} - -/** - * msd_timeline_get_direction: - * @timeline: A #MsdTimeline - * - * Returns the direction of the timeline. - * - * Return Value: direction - **/ -MsdTimelineDirection -msd_timeline_get_direction (MsdTimeline *timeline) -{ - MsdTimelinePriv *priv; - - g_return_val_if_fail (MSD_IS_TIMELINE (timeline), MSD_TIMELINE_DIRECTION_FORWARD); - - priv = MSD_TIMELINE_GET_PRIV (timeline); - return priv->direction; -} - -/** - * msd_timeline_set_direction: - * @timeline: A #MsdTimeline - * @direction: direction - * - * Sets the direction of the timeline. - **/ -void -msd_timeline_set_direction (MsdTimeline *timeline, - MsdTimelineDirection direction) -{ - MsdTimelinePriv *priv; - - g_return_if_fail (MSD_IS_TIMELINE (timeline)); - - priv = MSD_TIMELINE_GET_PRIV (timeline); - priv->direction = direction; - - g_object_notify (G_OBJECT (timeline), "direction"); -} - -GdkScreen * -msd_timeline_get_screen (MsdTimeline *timeline) -{ - MsdTimelinePriv *priv; - - g_return_val_if_fail (MSD_IS_TIMELINE (timeline), NULL); - - priv = MSD_TIMELINE_GET_PRIV (timeline); - return priv->screen; -} - -void -msd_timeline_set_screen (MsdTimeline *timeline, - GdkScreen *screen) -{ - MsdTimelinePriv *priv; - - g_return_if_fail (MSD_IS_TIMELINE (timeline)); - g_return_if_fail (GDK_IS_SCREEN (screen)); - - priv = MSD_TIMELINE_GET_PRIV (timeline); - - if (priv->screen) - g_object_unref (priv->screen); - - priv->screen = g_object_ref (screen); - - g_object_notify (G_OBJECT (timeline), "screen"); -} - -void -msd_timeline_set_progress_type (MsdTimeline *timeline, - MsdTimelineProgressType type) -{ - MsdTimelinePriv *priv; - - g_return_if_fail (MSD_IS_TIMELINE (timeline)); - - priv = MSD_TIMELINE_GET_PRIV (timeline); - - priv->progress_type = type; - - g_object_notify (G_OBJECT (timeline), "progress-type"); -} - -MsdTimelineProgressType -msd_timeline_get_progress_type (MsdTimeline *timeline) -{ - MsdTimelinePriv *priv; - - g_return_val_if_fail (MSD_IS_TIMELINE (timeline), MSD_TIMELINE_PROGRESS_LINEAR); - - priv = MSD_TIMELINE_GET_PRIV (timeline); - - if (priv->progress_func) - return MSD_TIMELINE_PROGRESS_LINEAR; - - return priv->progress_type; -} - -/** - * msd_timeline_set_progress_func: - * @timeline: A #MsdTimeline - * @progress_func: progress function - * - * Sets the progress function. This function will be used to calculate - * a different progress to pass to the ::frame signal based on the - * linear progress through the timeline. Setting progress_func - * to %NULL will make the timeline use the default function, - * which is just a linear progress. - * - * All progresses are in the [0.0, 1.0] range. - **/ -void -msd_timeline_set_progress_func (MsdTimeline *timeline, - MsdTimelineProgressFunc progress_func) -{ - MsdTimelinePriv *priv; - - g_return_if_fail (MSD_IS_TIMELINE (timeline)); - - priv = MSD_TIMELINE_GET_PRIV (timeline); - priv->progress_func = progress_func; -} - -gdouble -msd_timeline_get_progress (MsdTimeline *timeline) -{ - MsdTimelinePriv *priv; - MsdTimelineProgressFunc progress_func = NULL; - gdouble linear_progress, progress; - guint elapsed_time; - - g_return_val_if_fail (MSD_IS_TIMELINE (timeline), 0.0); - - priv = MSD_TIMELINE_GET_PRIV (timeline); - - if (!priv->timer) - return 0.; - - elapsed_time = (guint) (g_timer_elapsed (priv->timer, NULL) * 1000); - - linear_progress = (gdouble) elapsed_time / priv->duration; - - if (priv->direction == MSD_TIMELINE_DIRECTION_BACKWARD) - linear_progress = 1 - linear_progress; - - linear_progress = CLAMP (linear_progress, 0., 1.); - - if (priv->progress_func) - progress_func = priv->progress_func; - else if (priv->progress_type) - progress_func = progress_type_to_func (priv->progress_type); - - if (progress_func) - progress = (progress_func) (linear_progress); - else - progress = linear_progress; - - return CLAMP (progress, 0., 1.); -} diff --git a/plugins/mouse/gsd-timeline.h b/plugins/mouse/gsd-timeline.h deleted file mode 100644 index b8d40ca..0000000 --- a/plugins/mouse/gsd-timeline.h +++ /dev/null @@ -1,127 +0,0 @@ -/* msdtimeline.c - * - * Copyright (C) 2008 Carlos Garnacho - * - * 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 __MSD_TIMELINE_H__ -#define __MSD_TIMELINE_H__ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define MSD_TYPE_TIMELINE_DIRECTION (msd_timeline_direction_get_type ()) -#define MSD_TYPE_TIMELINE_PROGRESS_TYPE (msd_timeline_progress_type_get_type ()) -#define MSD_TYPE_TIMELINE (msd_timeline_get_type ()) -#define MSD_TIMELINE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MSD_TYPE_TIMELINE, MsdTimeline)) -#define MSD_TIMELINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MSD_TYPE_TIMELINE, MsdTimelineClass)) -#define MSD_IS_TIMELINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MSD_TYPE_TIMELINE)) -#define MSD_IS_TIMELINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MSD_TYPE_TIMELINE)) -#define MSD_TIMELINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MSD_TYPE_TIMELINE, MsdTimelineClass)) - -typedef enum { - MSD_TIMELINE_DIRECTION_FORWARD, - MSD_TIMELINE_DIRECTION_BACKWARD -} MsdTimelineDirection; - -typedef enum { - MSD_TIMELINE_PROGRESS_LINEAR, - MSD_TIMELINE_PROGRESS_SINUSOIDAL, - MSD_TIMELINE_PROGRESS_EXPONENTIAL -} MsdTimelineProgressType; - -typedef struct MsdTimeline MsdTimeline; -typedef struct MsdTimelineClass MsdTimelineClass; - -struct MsdTimeline -{ - GObject parent_instance; -}; - -struct MsdTimelineClass -{ - GObjectClass parent_class; - - void (* started) (MsdTimeline *timeline); - void (* finished) (MsdTimeline *timeline); - void (* paused) (MsdTimeline *timeline); - - void (* frame) (MsdTimeline *timeline, - gdouble progress); - - void (* __msd_reserved1) (void); - void (* __msd_reserved2) (void); - void (* __msd_reserved3) (void); - void (* __msd_reserved4) (void); -}; - -typedef gdouble (*MsdTimelineProgressFunc) (gdouble progress); - - -GType msd_timeline_get_type (void) G_GNUC_CONST; -GType msd_timeline_direction_get_type (void) G_GNUC_CONST; -GType msd_timeline_progress_type_get_type (void) G_GNUC_CONST; - -MsdTimeline *msd_timeline_new (guint duration); -MsdTimeline *msd_timeline_new_for_screen (guint duration, - GdkScreen *screen); - -void msd_timeline_start (MsdTimeline *timeline); -void msd_timeline_pause (MsdTimeline *timeline); -void msd_timeline_rewind (MsdTimeline *timeline); - -gboolean msd_timeline_is_running (MsdTimeline *timeline); - -guint msd_timeline_get_fps (MsdTimeline *timeline); -void msd_timeline_set_fps (MsdTimeline *timeline, - guint fps); - -gboolean msd_timeline_get_loop (MsdTimeline *timeline); -void msd_timeline_set_loop (MsdTimeline *timeline, - gboolean loop); - -guint msd_timeline_get_duration (MsdTimeline *timeline); -void msd_timeline_set_duration (MsdTimeline *timeline, - guint duration); - -GdkScreen *msd_timeline_get_screen (MsdTimeline *timeline); -void msd_timeline_set_screen (MsdTimeline *timeline, - GdkScreen *screen); - -MsdTimelineDirection msd_timeline_get_direction (MsdTimeline *timeline); -void msd_timeline_set_direction (MsdTimeline *timeline, - MsdTimelineDirection direction); - -MsdTimelineProgressType msd_timeline_get_progress_type (MsdTimeline *timeline); -void msd_timeline_set_progress_type (MsdTimeline *timeline, - MsdTimelineProgressType type); -void msd_timeline_get_progress_func (MsdTimeline *timeline); - -void msd_timeline_set_progress_func (MsdTimeline *timeline, - MsdTimelineProgressFunc progress_func); - -gdouble msd_timeline_get_progress (MsdTimeline *timeline); - - -#ifdef __cplusplus -} -#endif - -#endif /* __MSD_TIMELINE_H__ */ diff --git a/plugins/mouse/msd-locate-pointer.c b/plugins/mouse/msd-locate-pointer.c new file mode 100644 index 0000000..8582074 --- /dev/null +++ b/plugins/mouse/msd-locate-pointer.c @@ -0,0 +1,504 @@ +/* msd-locate-pointer.c + * + * Copyright (C) 2008 Carlos Garnacho + * + * 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 +#include "msd-timeline.h" +#include "msd-locate-pointer.h" + +#include +#include +#include + +#define ANIMATION_LENGTH 750 +#define WINDOW_SIZE 101 +#define N_CIRCLES 4 + +/* All circles are supposed to be moving when progress + * reaches 0.5, and each of them are supposed to long + * for half of the progress, hence the need of 0.5 to + * get the circles interval, and the multiplication + * by 2 to know a circle progress */ +#define CIRCLES_PROGRESS_INTERVAL (0.5 / N_CIRCLES) +#define CIRCLE_PROGRESS(p) (MIN (1., ((gdouble) (p) * 2.))) + +typedef struct MsdLocatePointerData MsdLocatePointerData; + +struct MsdLocatePointerData +{ + MsdTimeline *timeline; + GtkWidget *widget; + GdkWindow *window; + + gdouble progress; +}; + +static MsdLocatePointerData *data = NULL; + +static void +locate_pointer_paint (MsdLocatePointerData *data, + cairo_t *cr, + gboolean composite) +{ + GdkColor color; + gdouble progress, circle_progress; + gint width, height, i; + GtkStyle *style; + + progress = data->progress; + + #if GTK_CHECK_VERSION(3, 0, 0) + width = gdk_window_get_width(GDK_WINDOW(data->window)); + height = gdk_window_get_height(GDK_WINDOW(data->window)); + #else + gdk_drawable_get_size(data->window, &width, &height); + #endif + + style = gtk_widget_get_style (data->widget); + color = style->bg[GTK_STATE_SELECTED]; + + cairo_set_source_rgba (cr, 1., 1., 1., 0.); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + + for (i = 0; i <= N_CIRCLES; i++) + { + if (progress < 0.) + break; + + circle_progress = MIN (1., (progress * 2)); + progress -= CIRCLES_PROGRESS_INTERVAL; + + if (circle_progress >= 1.) + continue; + + if (composite) + { + cairo_set_source_rgba (cr, + color.red / 65535., + color.green / 65535., + color.blue / 65535., + 1 - circle_progress); + cairo_arc (cr, + width / 2, + height / 2, + circle_progress * width / 2, + 0, 2 * G_PI); + + cairo_fill (cr); + cairo_stroke (cr); + } + else + { + cairo_set_source_rgb (cr, 0., 0., 0.); + cairo_set_line_width (cr, 3.); + cairo_arc (cr, + width / 2, + height / 2, + circle_progress * width / 2, + 0, 2 * G_PI); + cairo_stroke (cr); + + cairo_set_source_rgb (cr, 1., 1., 1.); + cairo_set_line_width (cr, 1.); + cairo_arc (cr, + width / 2, + height / 2, + circle_progress * width / 2, + 0, 2 * G_PI); + cairo_stroke (cr); + } + } +} + +static gboolean +locate_pointer_expose (GtkWidget *widget, + GdkEventExpose *event, + gpointer user_data) +{ + MsdLocatePointerData *data = (MsdLocatePointerData *) user_data; + cairo_t *cr; + + if (event->window != data->window) + return FALSE; + + cr = gdk_cairo_create (data->window); + locate_pointer_paint (data, cr, gtk_widget_is_composited (data->widget)); + cairo_destroy (cr); + + return TRUE; +} + +static void +update_shape (MsdLocatePointerData *data) +{ + cairo_t *cr; + GdkBitmap *mask; + + mask = gdk_pixmap_new (data->window, WINDOW_SIZE, WINDOW_SIZE, 1); + cr = gdk_cairo_create (mask); + locate_pointer_paint (data, cr, FALSE); + gdk_window_shape_combine_mask (data->window, mask, 0, 0); + g_object_unref (mask); + cairo_destroy (cr); +} + +static void +timeline_frame_cb (MsdTimeline *timeline, + gdouble progress, + gpointer user_data) +{ + MsdLocatePointerData *data = (MsdLocatePointerData *) user_data; + GdkScreen *screen; + gint cursor_x, cursor_y; + + if (gtk_widget_is_composited (data->widget)) + { + gdk_window_invalidate_rect (data->window, NULL, FALSE); + data->progress = progress; + } + else if (progress >= data->progress + CIRCLES_PROGRESS_INTERVAL) + { + /* only invalidate window each circle interval */ + update_shape (data); + gdk_window_invalidate_rect (data->window, NULL, FALSE); + data->progress += CIRCLES_PROGRESS_INTERVAL; + } + + screen = gdk_drawable_get_screen (data->window); + gdk_window_get_pointer (gdk_screen_get_root_window (screen), + &cursor_x, &cursor_y, NULL); + gdk_window_move (data->window, + cursor_x - WINDOW_SIZE / 2, + cursor_y - WINDOW_SIZE / 2); +} + +static void +set_transparent_shape (GdkWindow *window) +{ + GdkBitmap *mask; + cairo_t *cr; + + mask = gdk_pixmap_new (data->window, WINDOW_SIZE, WINDOW_SIZE, 1); + cr = gdk_cairo_create (mask); + + cairo_set_source_rgba (cr, 1., 1., 1., 0.); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + + gdk_window_shape_combine_mask (data->window, mask, 0, 0); + g_object_unref (mask); + cairo_destroy (cr); +} + +static void +unset_transparent_shape (GdkWindow *window) +{ + gdk_window_shape_combine_mask (data->window, NULL, 0, 0); +} + +static void +composited_changed (GtkWidget *widget, + MsdLocatePointerData *data) +{ + if (!gtk_widget_is_composited (widget)) + set_transparent_shape (data->window); + else + unset_transparent_shape (data->window); +} + +static void +timeline_finished_cb (MsdTimeline *timeline, + gpointer user_data) +{ + MsdLocatePointerData *data = (MsdLocatePointerData *) user_data; + + /* set transparent shape and hide window */ + if (!gtk_widget_is_composited (data->widget)) + set_transparent_shape (data->window); + + gdk_window_hide (data->window); +} + +static void +create_window (MsdLocatePointerData *data, + GdkScreen *screen) +{ + GdkColormap *colormap; + GdkVisual *visual; + GdkWindowAttr attributes; + + colormap = gdk_screen_get_rgba_colormap (screen); + visual = gdk_screen_get_rgba_visual (screen); + + if (!colormap) + { + colormap = gdk_screen_get_rgb_colormap (screen); + visual = gdk_screen_get_rgb_visual (screen); + } + + attributes.window_type = GDK_WINDOW_TEMP; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = visual; + attributes.colormap = colormap; + attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK; + attributes.width = 1; + attributes.height = 1; + + data->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 (data->window, data->widget); +} + +static MsdLocatePointerData * +msd_locate_pointer_data_new (GdkScreen *screen) +{ + MsdLocatePointerData *data; + + data = g_new0 (MsdLocatePointerData, 1); + + /* this widget will never be shown, it's + * mainly used to get signals/events from + */ + data->widget = gtk_window_new (GTK_WINDOW_POPUP); + gtk_widget_realize (data->widget); + + g_signal_connect (G_OBJECT (data->widget), "expose_event", + G_CALLBACK (locate_pointer_expose), + data); + + data->timeline = msd_timeline_new (ANIMATION_LENGTH); + g_signal_connect (data->timeline, "frame", + G_CALLBACK (timeline_frame_cb), data); + g_signal_connect (data->timeline, "finished", + G_CALLBACK (timeline_finished_cb), data); + + create_window (data, screen); + + return data; +} + +static void +move_locate_pointer_window (MsdLocatePointerData *data, + GdkScreen *screen) +{ + gint cursor_x, cursor_y; + GdkBitmap *mask; + GdkColor col; + GdkGC *gc; + + gdk_window_get_pointer (gdk_screen_get_root_window (screen), &cursor_x, &cursor_y, NULL); + + gdk_window_move_resize (data->window, + cursor_x - WINDOW_SIZE / 2, + cursor_y - WINDOW_SIZE / 2, + WINDOW_SIZE, WINDOW_SIZE); + + col.pixel = 0; + mask = gdk_pixmap_new (data->window, WINDOW_SIZE, WINDOW_SIZE, 1); + + gc = gdk_gc_new (mask); + gdk_gc_set_foreground (gc, &col); + gdk_draw_rectangle (mask, gc, TRUE, 0, 0, WINDOW_SIZE, WINDOW_SIZE); + + /* allow events to happen through the window */ + gdk_window_input_shape_combine_mask (data->window, mask, 0, 0); + + g_object_unref (mask); + g_object_unref (gc); +} + +void +msd_locate_pointer (GdkScreen *screen) +{ + if (!data) + data = msd_locate_pointer_data_new (screen); + + msd_timeline_pause (data->timeline); + msd_timeline_rewind (data->timeline); + + /* Create again the window if it is not for the current screen */ + if (gdk_screen_get_number (screen) != gdk_screen_get_number (gdk_drawable_get_screen (data->window))) + { + gdk_window_set_user_data (data->window, NULL); + gdk_window_destroy (data->window); + + create_window (data, screen); + } + + data->progress = 0.; + + g_signal_connect (data->widget, "composited-changed", + G_CALLBACK (composited_changed), data); + + move_locate_pointer_window (data, screen); + composited_changed (data->widget, data); + gdk_window_show (data->window); + + msd_timeline_start (data->timeline); +} + + +#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 (xev->xkey.display, + SyncKeyboard, + xev->xkey.time); + } + else + { + XAllowEvents (xev->xkey.display, + AsyncKeyboard, + xev->xkey.time); + msd_locate_pointer (screen); + } + } + else + { + XAllowEvents (xev->xkey.display, + ReplayKeyboard, + xev->xkey.time); + XUngrabKeyboard (gdk_x11_get_default_xdisplay (), + xev->xkey.time); + } + } + + return GDK_FILTER_CONTINUE; +} + +static void +set_locate_pointer (void) +{ + 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; + Window xroot; + + screen = gdk_display_get_screen (display, j); + xroot = gdk_x11_drawable_get_xid (gdk_screen_get_root_window (screen)); + + 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); + } + } + + g_free (keys); + + 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); + } + } + } +} + + +int +main (int argc, char *argv[]) +{ + gtk_init (&argc, &argv); + + set_locate_pointer (); + + gtk_main (); + + return 0; +} + diff --git a/plugins/mouse/msd-locate-pointer.h b/plugins/mouse/msd-locate-pointer.h new file mode 100644 index 0000000..c21da43 --- /dev/null +++ b/plugins/mouse/msd-locate-pointer.h @@ -0,0 +1,24 @@ +/* + * Copyright © 2001 Jonathan Blandford + * + * 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 + +void msd_locate_pointer (GdkScreen *screen); + +#endif diff --git a/plugins/mouse/msd-mouse-manager.c b/plugins/mouse/msd-mouse-manager.c new file mode 100644 index 0000000..d7cb8e4 --- /dev/null +++ b/plugins/mouse/msd-mouse-manager.c @@ -0,0 +1,1124 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 William Jon McCann + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_X11_EXTENSIONS_XINPUT_H +#include +#include +#endif +#include +#include + +#include "mate-settings-profile.h" +#include "msd-mouse-manager.h" + +#define MSD_MOUSE_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MSD_TYPE_MOUSE_MANAGER, MsdMouseManagerPrivate)) + +#define MATECONF_MOUSE_DIR "/desktop/mate/peripherals/mouse" +#define MATECONF_MOUSE_A11Y_DIR "/desktop/mate/accessibility/mouse" +#define MATECONF_TOUCHPAD_DIR "/desktop/mate/peripherals/touchpad" + +#define KEY_LEFT_HANDED MATECONF_MOUSE_DIR "/left_handed" +#define KEY_MOTION_ACCELERATION MATECONF_MOUSE_DIR "/motion_acceleration" +#define KEY_MOTION_THRESHOLD MATECONF_MOUSE_DIR "/motion_threshold" +#define KEY_LOCATE_POINTER MATECONF_MOUSE_DIR "/locate_pointer" +#define KEY_DWELL_ENABLE MATECONF_MOUSE_A11Y_DIR "/dwell_enable" +#define KEY_DELAY_ENABLE MATECONF_MOUSE_A11Y_DIR "/delay_enable" +#define KEY_TOUCHPAD_DISABLE_W_TYPING MATECONF_TOUCHPAD_DIR "/disable_while_typing" +#ifdef HAVE_X11_EXTENSIONS_XINPUT_H +#define KEY_TAP_TO_CLICK MATECONF_TOUCHPAD_DIR "/tap_to_click" +#define KEY_SCROLL_METHOD MATECONF_TOUCHPAD_DIR "/scroll_method" +#define KEY_PAD_HORIZ_SCROLL MATECONF_TOUCHPAD_DIR "/horiz_scroll_enabled" +#define KEY_TOUCHPAD_ENABLED MATECONF_TOUCHPAD_DIR "/touchpad_enabled" +#endif + +struct MsdMouseManagerPrivate +{ + guint notify; + guint notify_a11y; + guint notify_touchpad; + + gboolean mousetweaks_daemon_running; + gboolean syndaemon_spawned; + GPid syndaemon_pid; + gboolean locate_pointer_spawned; + GPid locate_pointer_pid; +}; + +static void msd_mouse_manager_class_init (MsdMouseManagerClass *klass); +static void msd_mouse_manager_init (MsdMouseManager *mouse_manager); +static void msd_mouse_manager_finalize (GObject *object); +static void set_mouse_settings (MsdMouseManager *manager); +#ifdef HAVE_X11_EXTENSIONS_XINPUT_H +static int set_tap_to_click (gboolean state, gboolean left_handed); +static XDevice* device_is_touchpad (XDeviceInfo deviceinfo); +#endif + +G_DEFINE_TYPE (MsdMouseManager, msd_mouse_manager, G_TYPE_OBJECT) + +static gpointer manager_object = NULL; + +static void +msd_mouse_manager_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MsdMouseManager *self; + + self = MSD_MOUSE_MANAGER (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +msd_mouse_manager_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MsdMouseManager *self; + + self = MSD_MOUSE_MANAGER (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GObject * +msd_mouse_manager_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + MsdMouseManager *mouse_manager; + MsdMouseManagerClass *klass; + + klass = MSD_MOUSE_MANAGER_CLASS (g_type_class_peek (MSD_TYPE_MOUSE_MANAGER)); + + mouse_manager = MSD_MOUSE_MANAGER (G_OBJECT_CLASS (msd_mouse_manager_parent_class)->constructor (type, + n_construct_properties, + construct_properties)); + + return G_OBJECT (mouse_manager); +} + +static void +msd_mouse_manager_dispose (GObject *object) +{ + MsdMouseManager *mouse_manager; + + mouse_manager = MSD_MOUSE_MANAGER (object); + + G_OBJECT_CLASS (msd_mouse_manager_parent_class)->dispose (object); +} + +static void +msd_mouse_manager_class_init (MsdMouseManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->get_property = msd_mouse_manager_get_property; + object_class->set_property = msd_mouse_manager_set_property; + object_class->constructor = msd_mouse_manager_constructor; + object_class->dispose = msd_mouse_manager_dispose; + object_class->finalize = msd_mouse_manager_finalize; + + g_type_class_add_private (klass, sizeof (MsdMouseManagerPrivate)); +} + + +#ifdef HAVE_X11_EXTENSIONS_XINPUT_H +static gboolean +supports_xinput_devices (void) +{ + gint op_code, event, error; + + return XQueryExtension (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), + "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_X11_EXTENSIONS_XINPUT_H +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 gboolean +touchpad_has_single_button (XDevice *device) +{ + Atom type, prop; + int format; + unsigned long nitems, bytes_after; + unsigned char *data; + gboolean is_single_button = FALSE; + int rc; + + prop = XInternAtom (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "Synaptics Capabilities", False); + if (!prop) + return FALSE; + + gdk_error_trap_push (); + rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, prop, 0, 1, False, + XA_INTEGER, &type, &format, &nitems, + &bytes_after, &data); + if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 3) + is_single_button = (data[0] == 1 && data[1] == 0 && data[2] == 0); + + if (rc == Success) + XFree (data); + + gdk_error_trap_pop (); + + return is_single_button; +} + + +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_XDISPLAY(gdk_display_get_default()), &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 == IsXPointer) || + (device_info[i].use == IsXKeyboard) || + (!xinput_device_has_buttons (&device_info[i]))) + continue; + + /* If the device is a touchpad, swap tap buttons + * around too, otherwise a tap would be a right-click */ + device = device_is_touchpad (device_info[i]); + if (device != NULL) { + MateConfClient *client = mateconf_client_get_default (); + gboolean tap = mateconf_client_get_bool (client, KEY_TAP_TO_CLICK, NULL); + gboolean single_button = touchpad_has_single_button (device); + + if (tap && !single_button) + set_tap_to_click (tap, left_handed); + XCloseDevice (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device); + g_object_unref (client); + + if (single_button) + continue; + } + + gdk_error_trap_push (); + + device = XOpenDevice (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device_info[i].id); + + if ((gdk_error_trap_pop () != 0) || + (device == NULL)) + continue; + + n_buttons = XGetDeviceButtonMapping (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), 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_XDISPLAY(gdk_display_get_default()), device, + buttons, + buttons_capacity); + } + + configure_button_layout (buttons, n_buttons, left_handed); + + XSetDeviceButtonMapping (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, buttons, n_buttons); + XCloseDevice (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device); + } + g_free (buttons); + + if (device_info != NULL) + XFreeDeviceList (device_info); +} + +static GdkFilterReturn +devicepresence_filter (GdkXEvent *xevent, + GdkEvent *event, + gpointer data) +{ + XEvent *xev = (XEvent *) xevent; + XEventClass class_presence; + int xi_presence; + + DevicePresence (gdk_x11_get_default_xdisplay (), xi_presence, class_presence); + + if (xev->type == xi_presence) + { + XDevicePresenceNotifyEvent *dpn = (XDevicePresenceNotifyEvent *) xev; + if (dpn->devchange == DeviceEnabled) + set_mouse_settings ((MsdMouseManager *) data); + } + return GDK_FILTER_CONTINUE; +} + +static void +set_devicepresence_handler (MsdMouseManager *manager) +{ + Display *display; + XEventClass class_presence; + int xi_presence; + + if (!supports_xinput_devices ()) + return; + + display = gdk_x11_get_default_xdisplay (); + + gdk_error_trap_push (); + DevicePresence (display, xi_presence, class_presence); + XSelectExtensionEvent (display, + RootWindow (display, DefaultScreen (display)), + &class_presence, 1); + + gdk_flush (); + if (!gdk_error_trap_pop ()) + gdk_window_add_filter (NULL, devicepresence_filter, manager); +} +#endif + +static void +set_left_handed (MsdMouseManager *manager, + gboolean left_handed) +{ + guchar *buttons ; + gsize buttons_capacity = 16; + gint n_buttons, i; + +#ifdef HAVE_X11_EXTENSIONS_XINPUT_H + if (supports_xinput_devices ()) { + /* When XInput support is available, never set the + * button ordering on the core pointer as that would + * revert the changes we make on the devices themselves */ + set_xinput_devices_left_handed (left_handed); + return; + } +#endif + + buttons = g_new (guchar, buttons_capacity); + n_buttons = XGetPointerMapping (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), + 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_XDISPLAY(gdk_display_get_default()), + 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_XDISPLAY(gdk_display_get_default()), buttons, n_buttons) == MappingBusy; + ++i) { + g_usleep (300); + } + + g_free (buttons); +} + +static void +set_motion_acceleration (MsdMouseManager *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_XDISPLAY(gdk_display_get_default()), True, False, + numerator, denominator, + 0); +} + +static void +set_motion_threshold (MsdMouseManager *manager, + int motion_threshold) +{ + XChangePointerControl (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), False, True, + 0, 0, motion_threshold); +} + +#ifdef HAVE_X11_EXTENSIONS_XINPUT_H +static XDevice* +device_is_touchpad (XDeviceInfo deviceinfo) +{ + XDevice *device; + Atom realtype, prop; + int realformat; + unsigned long nitems, bytes_after; + unsigned char *data; + + if (deviceinfo.type != XInternAtom (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), XI_TOUCHPAD, False)) + return NULL; + + prop = XInternAtom (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "Synaptics Off", False); + if (!prop) + return NULL; + + gdk_error_trap_push (); + device = XOpenDevice (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), deviceinfo.id); + if (gdk_error_trap_pop () || (device == NULL)) + return NULL; + + gdk_error_trap_push (); + if ((XGetDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, prop, 0, 1, False, + XA_INTEGER, &realtype, &realformat, &nitems, + &bytes_after, &data) == Success) && (realtype != None)) { + gdk_error_trap_pop (); + XFree (data); + return device; + } + gdk_error_trap_pop (); + + XCloseDevice (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device); + return NULL; +} +#endif + +static int +set_disable_w_typing (MsdMouseManager *manager, gboolean state) +{ + + if (state) { + GError *error = NULL; + char *args[5]; + + if (manager->priv->syndaemon_spawned) + return 0; + + args[0] = "syndaemon"; + args[1] = "-i"; + args[2] = "0.5"; + args[3] = "-k"; + args[4] = NULL; + + if (!g_find_program_in_path (args[0])) + return 0; + + g_spawn_async (g_get_home_dir (), args, NULL, + G_SPAWN_SEARCH_PATH, NULL, NULL, + &manager->priv->syndaemon_pid, &error); + + manager->priv->syndaemon_spawned = (error == NULL); + + if (error) { + MateConfClient *client; + client = mateconf_client_get_default (); + mateconf_client_set_bool (client, KEY_TOUCHPAD_DISABLE_W_TYPING, FALSE, NULL); + g_object_unref (client); + g_error_free (error); + } + + } else if (manager->priv->syndaemon_spawned) + { + kill (manager->priv->syndaemon_pid, SIGHUP); + g_spawn_close_pid (manager->priv->syndaemon_pid); + manager->priv->syndaemon_spawned = FALSE; + } + + return 0; +} + +#ifdef HAVE_X11_EXTENSIONS_XINPUT_H +static int +set_tap_to_click (gboolean state, gboolean left_handed) +{ + int numdevices, i, format, rc; + unsigned long nitems, bytes_after; + XDeviceInfo *devicelist = XListInputDevices (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), &numdevices); + XDevice * device; + unsigned char* data; + Atom prop, type; + + if (devicelist == NULL) + return 0; + + prop = XInternAtom (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "Synaptics Tap Action", False); + + if (!prop) + return 0; + + for (i = 0; i < numdevices; i++) { + if ((device = device_is_touchpad (devicelist[i]))) { + gdk_error_trap_push (); + rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, prop, 0, 2, + False, XA_INTEGER, &type, &format, &nitems, + &bytes_after, &data); + + if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 7) + { + /* Set RLM mapping for 1/2/3 fingers*/ + data[4] = (state) ? ((left_handed) ? 3 : 1) : 0; + data[5] = (state) ? ((left_handed) ? 1 : 3) : 0; + data[6] = (state) ? 2 : 0; + XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, prop, XA_INTEGER, 8, + PropModeReplace, data, nitems); + } + + if (rc == Success) + XFree (data); + XCloseDevice (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device); + if (gdk_error_trap_pop ()) { + g_warning ("Error in setting tap to click on \"%s\"", devicelist[i].name); + continue; + } + } + } + + XFreeDeviceList (devicelist); + return 0; +} + +static int +set_horiz_scroll (gboolean state) +{ + int numdevices, i, rc; + XDeviceInfo *devicelist = XListInputDevices (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), &numdevices); + XDevice *device; + Atom act_type, prop_edge, prop_twofinger; + int act_format; + unsigned long nitems, bytes_after; + unsigned char *data; + + if (devicelist == NULL) + return 0; + + prop_edge = XInternAtom (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "Synaptics Edge Scrolling", False); + prop_twofinger = XInternAtom (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "Synaptics Two-Finger Scrolling", False); + + if (!prop_edge || !prop_twofinger) + return 0; + + for (i = 0; i < numdevices; i++) { + if ((device = device_is_touchpad (devicelist[i]))) { + gdk_error_trap_push (); + rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, + prop_edge, 0, 1, False, + XA_INTEGER, &act_type, &act_format, &nitems, + &bytes_after, &data); + if (rc == Success && act_type == XA_INTEGER && + act_format == 8 && nitems >= 2) { + data[1] = (state && data[0]); + XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, + prop_edge, XA_INTEGER, 8, + PropModeReplace, data, nitems); + } + + XFree (data); + + rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, + prop_twofinger, 0, 1, False, + XA_INTEGER, &act_type, &act_format, &nitems, + &bytes_after, &data); + if (rc == Success && act_type == XA_INTEGER && + act_format == 8 && nitems >= 2) { + data[1] = (state && data[0]); + XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, + prop_twofinger, XA_INTEGER, 8, + PropModeReplace, data, nitems); + } + + XFree (data); + XCloseDevice (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device); + if (gdk_error_trap_pop ()) { + g_warning ("Error in setting horiz scroll on \"%s\"", devicelist[i].name); + continue; + } + } + } + + XFreeDeviceList (devicelist); + return 0; +} + + +/** + * Scroll methods are: 0 - disabled, 1 - edge scrolling, 2 - twofinger + * scrolling + */ +static int +set_edge_scroll (int method) +{ + int numdevices, i, rc; + XDeviceInfo *devicelist = XListInputDevices (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), &numdevices); + XDevice *device; + Atom act_type, prop_edge, prop_twofinger; + int act_format; + unsigned long nitems, bytes_after; + unsigned char *data; + + if (devicelist == NULL) + return 0; + + prop_edge = XInternAtom (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "Synaptics Edge Scrolling", False); + prop_twofinger = XInternAtom (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "Synaptics Two-Finger Scrolling", False); + + if (!prop_edge || !prop_twofinger) + return 0; + + for (i = 0; i < numdevices; i++) { + if ((device = device_is_touchpad (devicelist[i]))) { + gdk_error_trap_push (); + rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, + prop_edge, 0, 1, False, + XA_INTEGER, &act_type, &act_format, &nitems, + &bytes_after, &data); + if (rc == Success && act_type == XA_INTEGER && + act_format == 8 && nitems >= 2) { + data[0] = (method == 1) ? 1 : 0; + XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, + prop_edge, XA_INTEGER, 8, + PropModeReplace, data, nitems); + } + + XFree (data); + + rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, + prop_twofinger, 0, 1, False, + XA_INTEGER, &act_type, &act_format, &nitems, + &bytes_after, &data); + if (rc == Success && act_type == XA_INTEGER && + act_format == 8 && nitems >= 2) { + data[0] = (method == 2) ? 1 : 0; + XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, + prop_twofinger, XA_INTEGER, 8, + PropModeReplace, data, nitems); + } + + XFree (data); + XCloseDevice (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device); + if (gdk_error_trap_pop ()) { + g_warning ("Error in setting edge scroll on \"%s\"", devicelist[i].name); + continue; + } + } + } + + XFreeDeviceList (devicelist); + return 0; +} + +static int +set_touchpad_enabled (gboolean state) +{ + int numdevices, i; + XDeviceInfo *devicelist = XListInputDevices (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), &numdevices); + XDevice *device; + Atom prop_enabled; + + if (devicelist == NULL) + return 0; + + prop_enabled = XInternAtom (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "Device Enabled", False); + + if (!prop_enabled) + return 0; + + for (i = 0; i < numdevices; i++) { + if ((device = device_is_touchpad (devicelist[i]))) { + unsigned char data = state; + gdk_error_trap_push (); + XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device, + prop_enabled, XA_INTEGER, 8, + PropModeReplace, &data, 1); + XCloseDevice (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), device); + gdk_flush (); + if (gdk_error_trap_pop ()) { + g_warning ("Error %s device \"%s\"", + (state) ? "enabling" : "disabling", + devicelist[i].name); + continue; + } + } + } + + XFreeDeviceList (devicelist); + return 0; +} +#endif + +static void +set_locate_pointer (MsdMouseManager *manager, + gboolean state) +{ + if (state) { + GError *error = NULL; + char *args[2]; + + if (manager->priv->locate_pointer_spawned) + return; + + args[0] = LIBEXECDIR "/msd-locate-pointer"; + args[1] = NULL; + + g_spawn_async (NULL, args, NULL, + 0, NULL, NULL, + &manager->priv->locate_pointer_pid, &error); + + manager->priv->locate_pointer_spawned = (error == NULL); + + if (error) { + MateConfClient *client; + client = mateconf_client_get_default (); + mateconf_client_set_bool (client, KEY_LOCATE_POINTER, FALSE, NULL); + g_object_unref (client); + g_error_free (error); + } + + } + else if (manager->priv->locate_pointer_spawned) { + kill (manager->priv->locate_pointer_pid, SIGHUP); + g_spawn_close_pid (manager->priv->locate_pointer_pid); + manager->priv->locate_pointer_spawned = FALSE; + } +} + +static void +set_mousetweaks_daemon (MsdMouseManager *manager, + gboolean dwell_enable, + gboolean delay_enable) +{ + GError *error = NULL; + gchar *comm; + gboolean run_daemon = dwell_enable || delay_enable; + + if (run_daemon || manager->priv->mousetweaks_daemon_running) + comm = g_strdup_printf ("mousetweaks %s", + run_daemon ? "" : "-s"); + else + return; + + if (run_daemon) + manager->priv->mousetweaks_daemon_running = TRUE; + + + if (! g_spawn_command_line_async (comm, &error)) { + if (error->code == G_SPAWN_ERROR_NOENT && + (dwell_enable || delay_enable)) { + GtkWidget *dialog; + MateConfClient *client; + + client = mateconf_client_get_default (); + if (dwell_enable) + mateconf_client_set_bool (client, + KEY_DWELL_ENABLE, + FALSE, NULL); + else if (delay_enable) + mateconf_client_set_bool (client, + KEY_DELAY_ENABLE, + FALSE, NULL); + g_object_unref (client); + + dialog = gtk_message_dialog_new (NULL, 0, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_OK, + _("Could not enable mouse accessibility features")); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + _("Mouse accessibility requires Mousetweaks " + "to be installed on your system.")); + gtk_window_set_title (GTK_WINDOW (dialog), + _("Mouse Preferences")); + gtk_window_set_icon_name (GTK_WINDOW (dialog), + "input-mouse"); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + } + g_error_free (error); + } + g_free (comm); +} + +static void +set_mouse_settings (MsdMouseManager *manager) +{ + MateConfClient *client = mateconf_client_get_default (); + gboolean left_handed = mateconf_client_get_bool (client, KEY_LEFT_HANDED, NULL); + + set_left_handed (manager, left_handed); + set_motion_acceleration (manager, mateconf_client_get_float (client, KEY_MOTION_ACCELERATION , NULL)); + set_motion_threshold (manager, mateconf_client_get_int (client, KEY_MOTION_THRESHOLD, NULL)); + + set_disable_w_typing (manager, mateconf_client_get_bool (client, KEY_TOUCHPAD_DISABLE_W_TYPING, NULL)); +#ifdef HAVE_X11_EXTENSIONS_XINPUT_H + set_tap_to_click (mateconf_client_get_bool (client, KEY_TAP_TO_CLICK, NULL), left_handed); + set_edge_scroll (mateconf_client_get_int (client, KEY_SCROLL_METHOD, NULL)); + set_horiz_scroll (mateconf_client_get_bool (client, KEY_PAD_HORIZ_SCROLL, NULL)); + set_touchpad_enabled (mateconf_client_get_bool (client, KEY_TOUCHPAD_ENABLED, NULL)); +#endif + + g_object_unref (client); +} + +static void +mouse_callback (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + MsdMouseManager *manager) +{ + if (! strcmp (entry->key, KEY_LEFT_HANDED)) { + if (entry->value->type == MATECONF_VALUE_BOOL) { + set_left_handed (manager, mateconf_value_get_bool (entry->value)); + } + } else if (! strcmp (entry->key, KEY_MOTION_ACCELERATION)) { + if (entry->value->type == MATECONF_VALUE_FLOAT) { + set_motion_acceleration (manager, mateconf_value_get_float (entry->value)); + } + } else if (! strcmp (entry->key, KEY_MOTION_THRESHOLD)) { + if (entry->value->type == MATECONF_VALUE_INT) { + set_motion_threshold (manager, mateconf_value_get_int (entry->value)); + } + } else if (! strcmp (entry->key, KEY_TOUCHPAD_DISABLE_W_TYPING)) { + if (entry->value->type == MATECONF_VALUE_BOOL) + set_disable_w_typing (manager, mateconf_value_get_bool (entry->value)); +#ifdef HAVE_X11_EXTENSIONS_XINPUT_H + } else if (! strcmp (entry->key, KEY_TAP_TO_CLICK)) { + if (entry->value->type == MATECONF_VALUE_BOOL) { + set_tap_to_click (mateconf_value_get_bool (entry->value), + mateconf_client_get_bool (client, KEY_LEFT_HANDED, NULL)); + } + } else if (! strcmp (entry->key, KEY_SCROLL_METHOD)) { + if (entry->value->type == MATECONF_VALUE_INT) { + set_edge_scroll (mateconf_value_get_int (entry->value)); + set_horiz_scroll (mateconf_client_get_bool (client, KEY_PAD_HORIZ_SCROLL, NULL)); + } + } else if (! strcmp (entry->key, KEY_PAD_HORIZ_SCROLL)) { + if (entry->value->type == MATECONF_VALUE_BOOL) + set_horiz_scroll (mateconf_value_get_bool (entry->value)); +#endif + } else if (! strcmp (entry->key, KEY_LOCATE_POINTER)) { + if (entry->value->type == MATECONF_VALUE_BOOL) { + set_locate_pointer (manager, mateconf_value_get_bool (entry->value)); + } +#ifdef HAVE_X11_EXTENSIONS_XINPUT_H + } else if (! strcmp (entry->key, KEY_TOUCHPAD_ENABLED)) { + if (entry->value->type == MATECONF_VALUE_BOOL) { + set_touchpad_enabled (mateconf_value_get_bool (entry->value)); + } +#endif + } else if (! strcmp (entry->key, KEY_DWELL_ENABLE)) { + if (entry->value->type == MATECONF_VALUE_BOOL) { + set_mousetweaks_daemon (manager, + mateconf_value_get_bool (entry->value), + mateconf_client_get_bool (client, KEY_DELAY_ENABLE, NULL)); + } + } else if (! strcmp (entry->key, KEY_DELAY_ENABLE)) { + if (entry->value->type == MATECONF_VALUE_BOOL) { + set_mousetweaks_daemon (manager, + mateconf_client_get_bool (client, KEY_DWELL_ENABLE, NULL), + mateconf_value_get_bool (entry->value)); + } + } +} + +static guint +register_config_callback (MsdMouseManager *manager, + MateConfClient *client, + const char *path, + MateConfClientNotifyFunc func) +{ + mateconf_client_add_dir (client, path, MATECONF_CLIENT_PRELOAD_ONELEVEL, NULL); + return mateconf_client_notify_add (client, path, func, manager, NULL, NULL); +} + +static void +msd_mouse_manager_init (MsdMouseManager *manager) +{ + manager->priv = MSD_MOUSE_MANAGER_GET_PRIVATE (manager); +} + +static gboolean +msd_mouse_manager_idle_cb (MsdMouseManager *manager) +{ + MateConfClient *client; + + mate_settings_profile_start (NULL); + + client = mateconf_client_get_default (); + + manager->priv->notify = + register_config_callback (manager, + client, + MATECONF_MOUSE_DIR, + (MateConfClientNotifyFunc) mouse_callback); + manager->priv->notify_a11y = + register_config_callback (manager, + client, + MATECONF_MOUSE_A11Y_DIR, + (MateConfClientNotifyFunc) mouse_callback); + manager->priv->notify_touchpad = + register_config_callback (manager, + client, + MATECONF_TOUCHPAD_DIR, + (MateConfClientNotifyFunc) mouse_callback); + manager->priv->syndaemon_spawned = FALSE; + +#ifdef HAVE_X11_EXTENSIONS_XINPUT_H + set_devicepresence_handler (manager); +#endif + set_mouse_settings (manager); + set_locate_pointer (manager, mateconf_client_get_bool (client, KEY_LOCATE_POINTER, NULL)); + set_mousetweaks_daemon (manager, + mateconf_client_get_bool (client, KEY_DWELL_ENABLE, NULL), + mateconf_client_get_bool (client, KEY_DELAY_ENABLE, NULL)); + + set_disable_w_typing (manager, mateconf_client_get_bool (client, KEY_TOUCHPAD_DISABLE_W_TYPING, NULL)); +#ifdef HAVE_X11_EXTENSIONS_XINPUT_H + set_tap_to_click (mateconf_client_get_bool (client, KEY_TAP_TO_CLICK, NULL), + mateconf_client_get_bool (client, KEY_LEFT_HANDED, NULL)); + set_edge_scroll (mateconf_client_get_int (client, KEY_SCROLL_METHOD, NULL)); + set_horiz_scroll (mateconf_client_get_bool (client, KEY_PAD_HORIZ_SCROLL, NULL)); + set_touchpad_enabled (mateconf_client_get_bool (client, KEY_TOUCHPAD_ENABLED, NULL)); +#endif + + g_object_unref (client); + + mate_settings_profile_end (NULL); + + return FALSE; +} + +gboolean +msd_mouse_manager_start (MsdMouseManager *manager, + GError **error) +{ + mate_settings_profile_start (NULL); + + g_idle_add ((GSourceFunc) msd_mouse_manager_idle_cb, manager); + + mate_settings_profile_end (NULL); + + return TRUE; +} + +void +msd_mouse_manager_stop (MsdMouseManager *manager) +{ + MsdMouseManagerPrivate *p = manager->priv; + MateConfClient *client; + + g_debug ("Stopping mouse manager"); + + client = mateconf_client_get_default (); + + if (p->notify != 0) { + mateconf_client_remove_dir (client, MATECONF_MOUSE_DIR, NULL); + mateconf_client_notify_remove (client, p->notify); + p->notify = 0; + } + + if (p->notify_a11y != 0) { + mateconf_client_remove_dir (client, MATECONF_MOUSE_A11Y_DIR, NULL); + mateconf_client_notify_remove (client, p->notify_a11y); + p->notify_a11y = 0; + } + + if (p->notify_touchpad != 0) { + mateconf_client_remove_dir (client, MATECONF_TOUCHPAD_DIR, NULL); + mateconf_client_notify_remove (client, p->notify_touchpad); + p->notify_touchpad = 0; + } + + g_object_unref (client); + + set_locate_pointer (manager, FALSE); + +#ifdef HAVE_X11_EXTENSIONS_XINPUT_H + gdk_window_remove_filter (NULL, devicepresence_filter, manager); +#endif +} + +static void +msd_mouse_manager_finalize (GObject *object) +{ + MsdMouseManager *mouse_manager; + + g_return_if_fail (object != NULL); + g_return_if_fail (MSD_IS_MOUSE_MANAGER (object)); + + mouse_manager = MSD_MOUSE_MANAGER (object); + + g_return_if_fail (mouse_manager->priv != NULL); + + G_OBJECT_CLASS (msd_mouse_manager_parent_class)->finalize (object); +} + +MsdMouseManager * +msd_mouse_manager_new (void) +{ + if (manager_object != NULL) { + g_object_ref (manager_object); + } else { + manager_object = g_object_new (MSD_TYPE_MOUSE_MANAGER, NULL); + g_object_add_weak_pointer (manager_object, + (gpointer *) &manager_object); + } + + return MSD_MOUSE_MANAGER (manager_object); +} diff --git a/plugins/mouse/msd-mouse-manager.h b/plugins/mouse/msd-mouse-manager.h new file mode 100644 index 0000000..e691d7b --- /dev/null +++ b/plugins/mouse/msd-mouse-manager.h @@ -0,0 +1,61 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 William Jon McCann + * + * 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 __MSD_MOUSE_MANAGER_H +#define __MSD_MOUSE_MANAGER_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MSD_TYPE_MOUSE_MANAGER (msd_mouse_manager_get_type ()) +#define MSD_MOUSE_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MSD_TYPE_MOUSE_MANAGER, MsdMouseManager)) +#define MSD_MOUSE_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), MSD_TYPE_MOUSE_MANAGER, MsdMouseManagerClass)) +#define MSD_IS_MOUSE_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MSD_TYPE_MOUSE_MANAGER)) +#define MSD_IS_MOUSE_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MSD_TYPE_MOUSE_MANAGER)) +#define MSD_MOUSE_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), MSD_TYPE_MOUSE_MANAGER, MsdMouseManagerClass)) + +typedef struct MsdMouseManagerPrivate MsdMouseManagerPrivate; + +typedef struct +{ + GObject parent; + MsdMouseManagerPrivate *priv; +} MsdMouseManager; + +typedef struct +{ + GObjectClass parent_class; +} MsdMouseManagerClass; + +GType msd_mouse_manager_get_type (void); + +MsdMouseManager * msd_mouse_manager_new (void); +gboolean msd_mouse_manager_start (MsdMouseManager *manager, + GError **error); +void msd_mouse_manager_stop (MsdMouseManager *manager); + +#ifdef __cplusplus +} +#endif + +#endif /* __MSD_MOUSE_MANAGER_H */ diff --git a/plugins/mouse/msd-mouse-plugin.c b/plugins/mouse/msd-mouse-plugin.c new file mode 100644 index 0000000..7203002 --- /dev/null +++ b/plugins/mouse/msd-mouse-plugin.c @@ -0,0 +1,104 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 William Jon McCann + * + * 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 +#include + +#include "mate-settings-plugin.h" +#include "msd-mouse-plugin.h" +#include "msd-mouse-manager.h" + +struct MsdMousePluginPrivate { + MsdMouseManager *manager; +}; + +#define MSD_MOUSE_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), MSD_TYPE_MOUSE_PLUGIN, MsdMousePluginPrivate)) + +MATE_SETTINGS_PLUGIN_REGISTER (MsdMousePlugin, msd_mouse_plugin) + +static void +msd_mouse_plugin_init (MsdMousePlugin *plugin) +{ + plugin->priv = MSD_MOUSE_PLUGIN_GET_PRIVATE (plugin); + + g_debug ("MsdMousePlugin initializing"); + + plugin->priv->manager = msd_mouse_manager_new (); +} + +static void +msd_mouse_plugin_finalize (GObject *object) +{ + MsdMousePlugin *plugin; + + g_return_if_fail (object != NULL); + g_return_if_fail (MSD_IS_MOUSE_PLUGIN (object)); + + g_debug ("MsdMousePlugin finalizing"); + + plugin = MSD_MOUSE_PLUGIN (object); + + g_return_if_fail (plugin->priv != NULL); + + if (plugin->priv->manager != NULL) { + g_object_unref (plugin->priv->manager); + } + + G_OBJECT_CLASS (msd_mouse_plugin_parent_class)->finalize (object); +} + +static void +impl_activate (MateSettingsPlugin *plugin) +{ + gboolean res; + GError *error; + + g_debug ("Activating mouse plugin"); + + error = NULL; + res = msd_mouse_manager_start (MSD_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 (MateSettingsPlugin *plugin) +{ + g_debug ("Deactivating mouse plugin"); + msd_mouse_manager_stop (MSD_MOUSE_PLUGIN (plugin)->priv->manager); +} + +static void +msd_mouse_plugin_class_init (MsdMousePluginClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + MateSettingsPluginClass *plugin_class = MATE_SETTINGS_PLUGIN_CLASS (klass); + + object_class->finalize = msd_mouse_plugin_finalize; + + plugin_class->activate = impl_activate; + plugin_class->deactivate = impl_deactivate; + + g_type_class_add_private (klass, sizeof (MsdMousePluginPrivate)); +} diff --git a/plugins/mouse/msd-mouse-plugin.h b/plugins/mouse/msd-mouse-plugin.h new file mode 100644 index 0000000..2c2da6c --- /dev/null +++ b/plugins/mouse/msd-mouse-plugin.h @@ -0,0 +1,63 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 William Jon McCann + * + * 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 __MSD_MOUSE_PLUGIN_H__ +#define __MSD_MOUSE_PLUGIN_H__ + +#include +#include +#include + +#include "mate-settings-plugin.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MSD_TYPE_MOUSE_PLUGIN (msd_mouse_plugin_get_type ()) +#define MSD_MOUSE_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MSD_TYPE_MOUSE_PLUGIN, MsdMousePlugin)) +#define MSD_MOUSE_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), MSD_TYPE_MOUSE_PLUGIN, MsdMousePluginClass)) +#define MSD_IS_MOUSE_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MSD_TYPE_MOUSE_PLUGIN)) +#define MSD_IS_MOUSE_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MSD_TYPE_MOUSE_PLUGIN)) +#define MSD_MOUSE_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), MSD_TYPE_MOUSE_PLUGIN, MsdMousePluginClass)) + +typedef struct MsdMousePluginPrivate MsdMousePluginPrivate; + +typedef struct +{ + MateSettingsPlugin parent; + MsdMousePluginPrivate *priv; +} MsdMousePlugin; + +typedef struct +{ + MateSettingsPluginClass parent_class; +} MsdMousePluginClass; + +GType msd_mouse_plugin_get_type (void) G_GNUC_CONST; + +/* All the plugins must implement this function */ +G_MODULE_EXPORT GType register_mate_settings_plugin (GTypeModule *module); + +#ifdef __cplusplus +} +#endif + +#endif /* __MSD_MOUSE_PLUGIN_H__ */ diff --git a/plugins/mouse/msd-timeline.c b/plugins/mouse/msd-timeline.c new file mode 100644 index 0000000..9bcfd2f --- /dev/null +++ b/plugins/mouse/msd-timeline.c @@ -0,0 +1,848 @@ +/* msd-timeline.c + * + * Copyright (C) 2008 Carlos Garnacho + * + * 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 +#include +#include +#include "msd-timeline.h" + +#define MSD_TIMELINE_GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MSD_TYPE_TIMELINE, MsdTimelinePriv)) +#define MSECS_PER_SEC 1000 +#define FRAME_INTERVAL(nframes) (MSECS_PER_SEC / nframes) +#define DEFAULT_FPS 30 + +typedef struct MsdTimelinePriv MsdTimelinePriv; + +struct MsdTimelinePriv +{ + guint duration; + guint fps; + guint source_id; + + GTimer *timer; + + GdkScreen *screen; + MsdTimelineProgressType progress_type; + MsdTimelineProgressFunc progress_func; + + guint loop : 1; + guint direction : 1; +}; + +enum { + PROP_0, + PROP_FPS, + PROP_DURATION, + PROP_LOOP, + PROP_DIRECTION, + PROP_SCREEN, + PROP_PROGRESS_TYPE, +}; + +enum { + STARTED, + PAUSED, + FINISHED, + FRAME, + LAST_SIGNAL +}; + +static guint signals [LAST_SIGNAL] = { 0, }; + + +static void msd_timeline_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void msd_timeline_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void msd_timeline_finalize (GObject *object); + + +G_DEFINE_TYPE (MsdTimeline, msd_timeline, G_TYPE_OBJECT) + + +GType +msd_timeline_direction_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) + { + static const GEnumValue values[] = { + { MSD_TIMELINE_DIRECTION_FORWARD, "MSD_TIMELINE_DIRECTION_FORWARD", "forward" }, + { MSD_TIMELINE_DIRECTION_BACKWARD, "MSD_TIMELINE_DIRECTION_BACKWARD", "backward" }, + { 0, NULL, NULL } + }; + + type = g_enum_register_static (g_intern_static_string ("MsdTimelineDirection"), values); + } + + return type; +} + +GType +msd_timeline_progress_type_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) + { + static const GEnumValue values[] = { + { MSD_TIMELINE_PROGRESS_LINEAR, "MSD_TIMELINE_PROGRESS_LINEAR", "linear" }, + { MSD_TIMELINE_PROGRESS_SINUSOIDAL, "MSD_TIMELINE_PROGRESS_SINUSOIDAL", "sinusoidal" }, + { MSD_TIMELINE_PROGRESS_EXPONENTIAL, "MSD_TIMELINE_PROGRESS_EXPONENTIAL", "exponential" }, + { 0, NULL, NULL } + }; + + type = g_enum_register_static (g_intern_static_string ("MsdTimelineProgressType"), values); + } + + return type; +} + +static void +msd_timeline_class_init (MsdTimelineClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->set_property = msd_timeline_set_property; + object_class->get_property = msd_timeline_get_property; + object_class->finalize = msd_timeline_finalize; + + g_object_class_install_property (object_class, + PROP_FPS, + g_param_spec_uint ("fps", + "FPS", + "Frames per second for the timeline", + 1, + G_MAXUINT, + DEFAULT_FPS, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_DURATION, + g_param_spec_uint ("duration", + "Animation Duration", + "Animation Duration", + 0, + G_MAXUINT, + 0, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_LOOP, + g_param_spec_boolean ("loop", + "Loop", + "Whether the timeline loops or not", + FALSE, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_DIRECTION, + g_param_spec_enum ("direction", + "Direction", + "Whether the timeline moves forward or backward in time", + MSD_TYPE_TIMELINE_DIRECTION, + MSD_TIMELINE_DIRECTION_FORWARD, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_DIRECTION, + g_param_spec_enum ("progress-type", + "Progress type", + "Type of progress through the timeline", + MSD_TYPE_TIMELINE_PROGRESS_TYPE, + MSD_TIMELINE_PROGRESS_LINEAR, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_SCREEN, + g_param_spec_object ("screen", + "Screen", + "Screen to get the settings from", + GDK_TYPE_SCREEN, + G_PARAM_READWRITE)); + + signals[STARTED] = + g_signal_new ("started", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (MsdTimelineClass, started), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[PAUSED] = + g_signal_new ("paused", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (MsdTimelineClass, paused), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[FINISHED] = + g_signal_new ("finished", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (MsdTimelineClass, finished), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[FRAME] = + g_signal_new ("frame", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (MsdTimelineClass, frame), + NULL, NULL, + g_cclosure_marshal_VOID__DOUBLE, + G_TYPE_NONE, 1, + G_TYPE_DOUBLE); + + g_type_class_add_private (class, sizeof (MsdTimelinePriv)); +} + +static void +msd_timeline_init (MsdTimeline *timeline) +{ + MsdTimelinePriv *priv; + + priv = MSD_TIMELINE_GET_PRIV (timeline); + + priv->fps = DEFAULT_FPS; + priv->duration = 0; + priv->direction = MSD_TIMELINE_DIRECTION_FORWARD; + priv->screen = gdk_screen_get_default (); +} + +static void +msd_timeline_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MsdTimeline *timeline; + MsdTimelinePriv *priv; + + timeline = MSD_TIMELINE (object); + priv = MSD_TIMELINE_GET_PRIV (timeline); + + switch (prop_id) + { + case PROP_FPS: + msd_timeline_set_fps (timeline, g_value_get_uint (value)); + break; + case PROP_DURATION: + msd_timeline_set_duration (timeline, g_value_get_uint (value)); + break; + case PROP_LOOP: + msd_timeline_set_loop (timeline, g_value_get_boolean (value)); + break; + case PROP_DIRECTION: + msd_timeline_set_direction (timeline, g_value_get_enum (value)); + break; + case PROP_SCREEN: + msd_timeline_set_screen (timeline, + GDK_SCREEN (g_value_get_object (value))); + break; + case PROP_PROGRESS_TYPE: + msd_timeline_set_progress_type (timeline, g_value_get_enum (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +msd_timeline_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MsdTimeline *timeline; + MsdTimelinePriv *priv; + + timeline = MSD_TIMELINE (object); + priv = MSD_TIMELINE_GET_PRIV (timeline); + + switch (prop_id) + { + case PROP_FPS: + g_value_set_uint (value, priv->fps); + break; + case PROP_DURATION: + g_value_set_uint (value, priv->duration); + break; + case PROP_LOOP: + g_value_set_boolean (value, priv->loop); + break; + case PROP_DIRECTION: + g_value_set_enum (value, priv->direction); + break; + case PROP_SCREEN: + g_value_set_object (value, priv->screen); + break; + case PROP_PROGRESS_TYPE: + g_value_set_enum (value, priv->progress_type); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +msd_timeline_finalize (GObject *object) +{ + MsdTimelinePriv *priv; + + priv = MSD_TIMELINE_GET_PRIV (object); + + if (priv->source_id) + { + g_source_remove (priv->source_id); + priv->source_id = 0; + } + + if (priv->timer) + g_timer_destroy (priv->timer); + + G_OBJECT_CLASS (msd_timeline_parent_class)->finalize (object); +} + +/* Sinusoidal progress */ +static gdouble +sinusoidal_progress (gdouble progress) +{ + return (sinf ((progress * G_PI) / 2)); +} + +static gdouble +exponential_progress (gdouble progress) +{ + return progress * progress; +} + +static MsdTimelineProgressFunc +progress_type_to_func (MsdTimelineProgressType type) +{ + if (type == MSD_TIMELINE_PROGRESS_SINUSOIDAL) + return sinusoidal_progress; + else if (type == MSD_TIMELINE_PROGRESS_EXPONENTIAL) + return exponential_progress; + + return NULL; +} + +static gboolean +msd_timeline_run_frame (MsdTimeline *timeline, + gboolean enable_animations) +{ + MsdTimelinePriv *priv; + gdouble linear_progress, progress; + guint elapsed_time; + MsdTimelineProgressFunc progress_func = NULL; + + priv = MSD_TIMELINE_GET_PRIV (timeline); + + if (enable_animations) + { + elapsed_time = (guint) (g_timer_elapsed (priv->timer, NULL) * 1000); + + linear_progress = (gdouble) elapsed_time / priv->duration; + + if (priv->direction == MSD_TIMELINE_DIRECTION_BACKWARD) + linear_progress = 1 - linear_progress; + + linear_progress = CLAMP (linear_progress, 0., 1.); + + if (priv->progress_func) + progress_func = priv->progress_func; + else if (priv->progress_type) + progress_func = progress_type_to_func (priv->progress_type); + + if (progress_func) + progress = (progress_func) (linear_progress); + else + progress = linear_progress; + } + else + progress = (priv->direction == MSD_TIMELINE_DIRECTION_FORWARD) ? 1.0 : 0.0; + + g_signal_emit (timeline, signals [FRAME], 0, + CLAMP (progress, 0.0, 1.0)); + + if ((priv->direction == MSD_TIMELINE_DIRECTION_FORWARD && progress >= 1.0) || + (priv->direction == MSD_TIMELINE_DIRECTION_BACKWARD && progress <= 0.0)) + { + if (!priv->loop) + { + if (priv->source_id) + { + g_source_remove (priv->source_id); + priv->source_id = 0; + } + + g_signal_emit (timeline, signals [FINISHED], 0); + return FALSE; + } + else + msd_timeline_rewind (timeline); + } + + return TRUE; +} + +static gboolean +msd_timeline_frame_idle_func (MsdTimeline *timeline) +{ + return msd_timeline_run_frame (timeline, TRUE); +} + +/** + * msd_timeline_new: + * @duration: duration in milliseconds for the timeline + * + * Creates a new #MsdTimeline with the specified number of frames. + * + * Return Value: the newly created #MsdTimeline + **/ +MsdTimeline * +msd_timeline_new (guint duration) +{ + return g_object_new (MSD_TYPE_TIMELINE, + "duration", duration, + NULL); +} + +MsdTimeline * +msd_timeline_new_for_screen (guint duration, + GdkScreen *screen) +{ + return g_object_new (MSD_TYPE_TIMELINE, + "duration", duration, + "screen", screen, + NULL); +} + +/** + * msd_timeline_start: + * @timeline: A #MsdTimeline + * + * Runs the timeline from the current frame. + **/ +void +msd_timeline_start (MsdTimeline *timeline) +{ + MsdTimelinePriv *priv; + GtkSettings *settings; + gboolean enable_animations = FALSE; + + g_return_if_fail (MSD_IS_TIMELINE (timeline)); + + priv = MSD_TIMELINE_GET_PRIV (timeline); + + if (priv->screen) + { + settings = gtk_settings_get_for_screen (priv->screen); + g_object_get (settings, "gtk-enable-animations", &enable_animations, NULL); + } + + if (enable_animations) + { + if (!priv->source_id) + { + if (priv->timer) + g_timer_continue (priv->timer); + else + priv->timer = g_timer_new (); + + /* sanity check */ + g_assert (priv->fps > 0); + + g_signal_emit (timeline, signals [STARTED], 0); + + priv->source_id = gdk_threads_add_timeout (FRAME_INTERVAL (priv->fps), + (GSourceFunc) msd_timeline_frame_idle_func, + timeline); + } + } + else + { + /* If animations are not enabled, only run the last frame, + * it take us instantaneously to the last state of the animation. + * The only potential flaw happens when people use the ::finished + * signal to trigger another animation, or even worse, finally + * loop into this animation again. + */ + g_signal_emit (timeline, signals [STARTED], 0); + msd_timeline_run_frame (timeline, FALSE); + } +} + +/** + * msd_timeline_pause: + * @timeline: A #MsdTimeline + * + * Pauses the timeline. + **/ +void +msd_timeline_pause (MsdTimeline *timeline) +{ + MsdTimelinePriv *priv; + + g_return_if_fail (MSD_IS_TIMELINE (timeline)); + + priv = MSD_TIMELINE_GET_PRIV (timeline); + + if (priv->source_id) + { + g_source_remove (priv->source_id); + priv->source_id = 0; + g_timer_stop (priv->timer); + g_signal_emit (timeline, signals [PAUSED], 0); + } +} + +/** + * msd_timeline_rewind: + * @timeline: A #MsdTimeline + * + * Rewinds the timeline. + **/ +void +msd_timeline_rewind (MsdTimeline *timeline) +{ + MsdTimelinePriv *priv; + + g_return_if_fail (MSD_IS_TIMELINE (timeline)); + + priv = MSD_TIMELINE_GET_PRIV (timeline); + + /* destroy and re-create timer if neccesary */ + if (priv->timer) + { + g_timer_destroy (priv->timer); + + if (msd_timeline_is_running (timeline)) + priv->timer = g_timer_new (); + else + priv->timer = NULL; + } +} + +/** + * msd_timeline_is_running: + * @timeline: A #MsdTimeline + * + * Returns whether the timeline is running or not. + * + * Return Value: %TRUE if the timeline is running + **/ +gboolean +msd_timeline_is_running (MsdTimeline *timeline) +{ + MsdTimelinePriv *priv; + + g_return_val_if_fail (MSD_IS_TIMELINE (timeline), FALSE); + + priv = MSD_TIMELINE_GET_PRIV (timeline); + + return (priv->source_id != 0); +} + +/** + * msd_timeline_get_fps: + * @timeline: A #MsdTimeline + * + * Returns the number of frames per second. + * + * Return Value: frames per second + **/ +guint +msd_timeline_get_fps (MsdTimeline *timeline) +{ + MsdTimelinePriv *priv; + + g_return_val_if_fail (MSD_IS_TIMELINE (timeline), 1); + + priv = MSD_TIMELINE_GET_PRIV (timeline); + return priv->fps; +} + +/** + * msd_timeline_set_fps: + * @timeline: A #MsdTimeline + * @fps: frames per second + * + * Sets the number of frames per second that + * the timeline will play. + **/ +void +msd_timeline_set_fps (MsdTimeline *timeline, + guint fps) +{ + MsdTimelinePriv *priv; + + g_return_if_fail (MSD_IS_TIMELINE (timeline)); + g_return_if_fail (fps > 0); + + priv = MSD_TIMELINE_GET_PRIV (timeline); + + priv->fps = fps; + + if (msd_timeline_is_running (timeline)) + { + g_source_remove (priv->source_id); + priv->source_id = gdk_threads_add_timeout (FRAME_INTERVAL (priv->fps), + (GSourceFunc) msd_timeline_run_frame, + timeline); + } + + g_object_notify (G_OBJECT (timeline), "fps"); +} + +/** + * msd_timeline_get_loop: + * @timeline: A #MsdTimeline + * + * Returns whether the timeline loops to the + * beginning when it has reached the end. + * + * Return Value: %TRUE if the timeline loops + **/ +gboolean +msd_timeline_get_loop (MsdTimeline *timeline) +{ + MsdTimelinePriv *priv; + + g_return_val_if_fail (MSD_IS_TIMELINE (timeline), FALSE); + + priv = MSD_TIMELINE_GET_PRIV (timeline); + return priv->loop; +} + +/** + * msd_timeline_set_loop: + * @timeline: A #MsdTimeline + * @loop: %TRUE to make the timeline loop + * + * Sets whether the timeline loops to the beginning + * when it has reached the end. + **/ +void +msd_timeline_set_loop (MsdTimeline *timeline, + gboolean loop) +{ + MsdTimelinePriv *priv; + + g_return_if_fail (MSD_IS_TIMELINE (timeline)); + + priv = MSD_TIMELINE_GET_PRIV (timeline); + priv->loop = loop; + + g_object_notify (G_OBJECT (timeline), "loop"); +} + +void +msd_timeline_set_duration (MsdTimeline *timeline, + guint duration) +{ + MsdTimelinePriv *priv; + + g_return_if_fail (MSD_IS_TIMELINE (timeline)); + + priv = MSD_TIMELINE_GET_PRIV (timeline); + + priv->duration = duration; + + g_object_notify (G_OBJECT (timeline), "duration"); +} + +guint +msd_timeline_get_duration (MsdTimeline *timeline) +{ + MsdTimelinePriv *priv; + + g_return_val_if_fail (MSD_IS_TIMELINE (timeline), 0); + + priv = MSD_TIMELINE_GET_PRIV (timeline); + + return priv->duration; +} + +/** + * msd_timeline_get_direction: + * @timeline: A #MsdTimeline + * + * Returns the direction of the timeline. + * + * Return Value: direction + **/ +MsdTimelineDirection +msd_timeline_get_direction (MsdTimeline *timeline) +{ + MsdTimelinePriv *priv; + + g_return_val_if_fail (MSD_IS_TIMELINE (timeline), MSD_TIMELINE_DIRECTION_FORWARD); + + priv = MSD_TIMELINE_GET_PRIV (timeline); + return priv->direction; +} + +/** + * msd_timeline_set_direction: + * @timeline: A #MsdTimeline + * @direction: direction + * + * Sets the direction of the timeline. + **/ +void +msd_timeline_set_direction (MsdTimeline *timeline, + MsdTimelineDirection direction) +{ + MsdTimelinePriv *priv; + + g_return_if_fail (MSD_IS_TIMELINE (timeline)); + + priv = MSD_TIMELINE_GET_PRIV (timeline); + priv->direction = direction; + + g_object_notify (G_OBJECT (timeline), "direction"); +} + +GdkScreen * +msd_timeline_get_screen (MsdTimeline *timeline) +{ + MsdTimelinePriv *priv; + + g_return_val_if_fail (MSD_IS_TIMELINE (timeline), NULL); + + priv = MSD_TIMELINE_GET_PRIV (timeline); + return priv->screen; +} + +void +msd_timeline_set_screen (MsdTimeline *timeline, + GdkScreen *screen) +{ + MsdTimelinePriv *priv; + + g_return_if_fail (MSD_IS_TIMELINE (timeline)); + g_return_if_fail (GDK_IS_SCREEN (screen)); + + priv = MSD_TIMELINE_GET_PRIV (timeline); + + if (priv->screen) + g_object_unref (priv->screen); + + priv->screen = g_object_ref (screen); + + g_object_notify (G_OBJECT (timeline), "screen"); +} + +void +msd_timeline_set_progress_type (MsdTimeline *timeline, + MsdTimelineProgressType type) +{ + MsdTimelinePriv *priv; + + g_return_if_fail (MSD_IS_TIMELINE (timeline)); + + priv = MSD_TIMELINE_GET_PRIV (timeline); + + priv->progress_type = type; + + g_object_notify (G_OBJECT (timeline), "progress-type"); +} + +MsdTimelineProgressType +msd_timeline_get_progress_type (MsdTimeline *timeline) +{ + MsdTimelinePriv *priv; + + g_return_val_if_fail (MSD_IS_TIMELINE (timeline), MSD_TIMELINE_PROGRESS_LINEAR); + + priv = MSD_TIMELINE_GET_PRIV (timeline); + + if (priv->progress_func) + return MSD_TIMELINE_PROGRESS_LINEAR; + + return priv->progress_type; +} + +/** + * msd_timeline_set_progress_func: + * @timeline: A #MsdTimeline + * @progress_func: progress function + * + * Sets the progress function. This function will be used to calculate + * a different progress to pass to the ::frame signal based on the + * linear progress through the timeline. Setting progress_func + * to %NULL will make the timeline use the default function, + * which is just a linear progress. + * + * All progresses are in the [0.0, 1.0] range. + **/ +void +msd_timeline_set_progress_func (MsdTimeline *timeline, + MsdTimelineProgressFunc progress_func) +{ + MsdTimelinePriv *priv; + + g_return_if_fail (MSD_IS_TIMELINE (timeline)); + + priv = MSD_TIMELINE_GET_PRIV (timeline); + priv->progress_func = progress_func; +} + +gdouble +msd_timeline_get_progress (MsdTimeline *timeline) +{ + MsdTimelinePriv *priv; + MsdTimelineProgressFunc progress_func = NULL; + gdouble linear_progress, progress; + guint elapsed_time; + + g_return_val_if_fail (MSD_IS_TIMELINE (timeline), 0.0); + + priv = MSD_TIMELINE_GET_PRIV (timeline); + + if (!priv->timer) + return 0.; + + elapsed_time = (guint) (g_timer_elapsed (priv->timer, NULL) * 1000); + + linear_progress = (gdouble) elapsed_time / priv->duration; + + if (priv->direction == MSD_TIMELINE_DIRECTION_BACKWARD) + linear_progress = 1 - linear_progress; + + linear_progress = CLAMP (linear_progress, 0., 1.); + + if (priv->progress_func) + progress_func = priv->progress_func; + else if (priv->progress_type) + progress_func = progress_type_to_func (priv->progress_type); + + if (progress_func) + progress = (progress_func) (linear_progress); + else + progress = linear_progress; + + return CLAMP (progress, 0., 1.); +} diff --git a/plugins/mouse/msd-timeline.h b/plugins/mouse/msd-timeline.h new file mode 100644 index 0000000..b8d40ca --- /dev/null +++ b/plugins/mouse/msd-timeline.h @@ -0,0 +1,127 @@ +/* msdtimeline.c + * + * Copyright (C) 2008 Carlos Garnacho + * + * 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 __MSD_TIMELINE_H__ +#define __MSD_TIMELINE_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MSD_TYPE_TIMELINE_DIRECTION (msd_timeline_direction_get_type ()) +#define MSD_TYPE_TIMELINE_PROGRESS_TYPE (msd_timeline_progress_type_get_type ()) +#define MSD_TYPE_TIMELINE (msd_timeline_get_type ()) +#define MSD_TIMELINE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MSD_TYPE_TIMELINE, MsdTimeline)) +#define MSD_TIMELINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MSD_TYPE_TIMELINE, MsdTimelineClass)) +#define MSD_IS_TIMELINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MSD_TYPE_TIMELINE)) +#define MSD_IS_TIMELINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MSD_TYPE_TIMELINE)) +#define MSD_TIMELINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MSD_TYPE_TIMELINE, MsdTimelineClass)) + +typedef enum { + MSD_TIMELINE_DIRECTION_FORWARD, + MSD_TIMELINE_DIRECTION_BACKWARD +} MsdTimelineDirection; + +typedef enum { + MSD_TIMELINE_PROGRESS_LINEAR, + MSD_TIMELINE_PROGRESS_SINUSOIDAL, + MSD_TIMELINE_PROGRESS_EXPONENTIAL +} MsdTimelineProgressType; + +typedef struct MsdTimeline MsdTimeline; +typedef struct MsdTimelineClass MsdTimelineClass; + +struct MsdTimeline +{ + GObject parent_instance; +}; + +struct MsdTimelineClass +{ + GObjectClass parent_class; + + void (* started) (MsdTimeline *timeline); + void (* finished) (MsdTimeline *timeline); + void (* paused) (MsdTimeline *timeline); + + void (* frame) (MsdTimeline *timeline, + gdouble progress); + + void (* __msd_reserved1) (void); + void (* __msd_reserved2) (void); + void (* __msd_reserved3) (void); + void (* __msd_reserved4) (void); +}; + +typedef gdouble (*MsdTimelineProgressFunc) (gdouble progress); + + +GType msd_timeline_get_type (void) G_GNUC_CONST; +GType msd_timeline_direction_get_type (void) G_GNUC_CONST; +GType msd_timeline_progress_type_get_type (void) G_GNUC_CONST; + +MsdTimeline *msd_timeline_new (guint duration); +MsdTimeline *msd_timeline_new_for_screen (guint duration, + GdkScreen *screen); + +void msd_timeline_start (MsdTimeline *timeline); +void msd_timeline_pause (MsdTimeline *timeline); +void msd_timeline_rewind (MsdTimeline *timeline); + +gboolean msd_timeline_is_running (MsdTimeline *timeline); + +guint msd_timeline_get_fps (MsdTimeline *timeline); +void msd_timeline_set_fps (MsdTimeline *timeline, + guint fps); + +gboolean msd_timeline_get_loop (MsdTimeline *timeline); +void msd_timeline_set_loop (MsdTimeline *timeline, + gboolean loop); + +guint msd_timeline_get_duration (MsdTimeline *timeline); +void msd_timeline_set_duration (MsdTimeline *timeline, + guint duration); + +GdkScreen *msd_timeline_get_screen (MsdTimeline *timeline); +void msd_timeline_set_screen (MsdTimeline *timeline, + GdkScreen *screen); + +MsdTimelineDirection msd_timeline_get_direction (MsdTimeline *timeline); +void msd_timeline_set_direction (MsdTimeline *timeline, + MsdTimelineDirection direction); + +MsdTimelineProgressType msd_timeline_get_progress_type (MsdTimeline *timeline); +void msd_timeline_set_progress_type (MsdTimeline *timeline, + MsdTimelineProgressType type); +void msd_timeline_get_progress_func (MsdTimeline *timeline); + +void msd_timeline_set_progress_func (MsdTimeline *timeline, + MsdTimelineProgressFunc progress_func); + +gdouble msd_timeline_get_progress (MsdTimeline *timeline); + + +#ifdef __cplusplus +} +#endif + +#endif /* __MSD_TIMELINE_H__ */ -- cgit v1.2.1