Merge lp:~ossug-hychen/gnome-settings-daemon/fix-868400-oneiric into lp:ubuntu/oneiric-proposed/gnome-settings-daemon

Proposed by James M. Leddy
Status: Merged
Merge reported by: Dimitri John Ledkov
Merged at revision: not available
Proposed branch: lp:~ossug-hychen/gnome-settings-daemon/fix-868400-oneiric
Merge into: lp:ubuntu/oneiric-proposed/gnome-settings-daemon
Diff against target: 1419 lines (+1348/-1)
6 files modified
.pc/52_kill_syndaemon_when_gsd_die.patch/plugins/mouse/gsd-mouse-manager.c (+1229/-0)
.pc/applied-patches (+1/-0)
debian/changelog (+10/-0)
debian/patches/52_kill_syndaemon_when_gsd_die.patch (+76/-0)
debian/patches/series (+1/-0)
plugins/mouse/gsd-mouse-manager.c (+31/-1)
To merge this branch: bzr merge lp:~ossug-hychen/gnome-settings-daemon/fix-868400-oneiric
Reviewer Review Type Date Requested Status
Dimitri John Ledkov Approve
Marc Deslauriers Needs Fixing
Review via email: mp+117358@code.launchpad.net

Description of the change

SRU from Precise that ensures that there is only ever one syndaemon process running.

To post a comment you must log in.
Revision history for this message
Marc Deslauriers (mdeslaur) wrote :

A few comments:

1- Please tag your patch using DEP-3: http://dep.debian.net/deps/dep3/
   - Add link to upstream commit: http://git.gnome.org/browse/gnome-settings-daemon/commit/?id=31aa30a0207b9de77706f03dacb8d914c959d3a6
   - Add link to upstream bug
   - Add link to ubuntu bug
   - etc.
2- Please remove "[ Hsin-Yi, Chen (hychen) ]" from debian/changelog, it's redundant
3- Please fix typo in changelog
4- Please revert modifications to older lines in the debian/changelog file

Thanks!

review: Needs Fixing
185. By Hsin-Yi, Chen (hychen)

* To remove "[ Hsin-Yi, Chen (hychen) ]" from debian/changelog, it's redundant
* To fix typo in debian/changelog
* To revert modifications to older lines in the debian/changelog file

186. By Hsin-Yi, Chen (hychen)

* To tag the patch by using DEP-3: http://dep.debian.net/deps/dep3/

Revision history for this message
Dimitri John Ledkov (xnox) wrote :

Looks good. Uploaded.
[ubuntu/oneiric-proposed] gnome-settings-daemon 3.2.2-0ubuntu2.3 (Waiting for approval)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory '.pc/52_kill_syndaemon_when_gsd_die.patch'
2=== added file '.pc/52_kill_syndaemon_when_gsd_die.patch/.timestamp'
3=== added directory '.pc/52_kill_syndaemon_when_gsd_die.patch/plugins'
4=== added directory '.pc/52_kill_syndaemon_when_gsd_die.patch/plugins/mouse'
5=== added file '.pc/52_kill_syndaemon_when_gsd_die.patch/plugins/mouse/gsd-mouse-manager.c'
6--- .pc/52_kill_syndaemon_when_gsd_die.patch/plugins/mouse/gsd-mouse-manager.c 1970-01-01 00:00:00 +0000
7+++ .pc/52_kill_syndaemon_when_gsd_die.patch/plugins/mouse/gsd-mouse-manager.c 2012-08-09 06:39:20 +0000
8@@ -0,0 +1,1229 @@
9+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
10+ *
11+ * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
12+ *
13+ * This program is free software; you can redistribute it and/or modify
14+ * it under the terms of the GNU General Public License as published by
15+ * the Free Software Foundation; either version 2 of the License, or
16+ * (at your option) any later version.
17+ *
18+ * This program is distributed in the hope that it will be useful,
19+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
20+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21+ * GNU General Public License for more details.
22+ *
23+ * You should have received a copy of the GNU General Public License
24+ * along with this program; if not, write to the Free Software
25+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26+ *
27+ */
28+
29+#include "config.h"
30+
31+#include <sys/types.h>
32+#include <sys/wait.h>
33+#include <stdlib.h>
34+#include <stdio.h>
35+#include <unistd.h>
36+#include <string.h>
37+#include <errno.h>
38+#include <math.h>
39+
40+#include <locale.h>
41+
42+#include <glib.h>
43+#include <glib/gi18n.h>
44+#include <gio/gio.h>
45+#include <gtk/gtk.h>
46+#include <gdk/gdk.h>
47+#include <gdk/gdkx.h>
48+#include <gdk/gdkkeysyms.h>
49+#include <X11/keysym.h>
50+#include <X11/Xatom.h>
51+
52+#include <X11/extensions/XInput.h>
53+#include <X11/extensions/XIproto.h>
54+
55+#include "gnome-settings-profile.h"
56+#include "gsd-mouse-manager.h"
57+#include "gsd-input-helper.h"
58+#include "gsd-enums.h"
59+
60+#define GSD_MOUSE_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_MOUSE_MANAGER, GsdMouseManagerPrivate))
61+
62+#define SETTINGS_MOUSE_DIR "org.gnome.settings-daemon.peripherals.mouse"
63+#define SETTINGS_TOUCHPAD_DIR "org.gnome.settings-daemon.peripherals.touchpad"
64+
65+/* Keys for both touchpad and mouse */
66+#define KEY_LEFT_HANDED "left-handed" /* a boolean for mouse, an enum for touchpad */
67+#define KEY_MOTION_ACCELERATION "motion-acceleration"
68+#define KEY_MOTION_THRESHOLD "motion-threshold"
69+
70+/* Touchpad settings */
71+#define KEY_TOUCHPAD_DISABLE_W_TYPING "disable-while-typing"
72+#define KEY_PAD_HORIZ_SCROLL "horiz-scroll-enabled"
73+#define KEY_SCROLL_METHOD "scroll-method"
74+#define KEY_TAP_TO_CLICK "tap-to-click"
75+#define KEY_TOUCHPAD_ENABLED "touchpad-enabled"
76+
77+/* Mouse settings */
78+#define KEY_LOCATE_POINTER "locate-pointer"
79+#define KEY_DWELL_CLICK_ENABLED "dwell-click-enabled"
80+#define KEY_SECONDARY_CLICK_ENABLED "secondary-click-enabled"
81+#define KEY_MIDDLE_BUTTON_EMULATION "middle-button-enabled"
82+
83+struct GsdMouseManagerPrivate
84+{
85+ guint start_idle_id;
86+ GSettings *touchpad_settings;
87+ GSettings *mouse_settings;
88+ GSettings *mouse_a11y_settings;
89+ GdkDeviceManager *device_manager;
90+ guint device_added_id;
91+ guint device_removed_id;
92+ GHashTable *blacklist;
93+
94+ gboolean mousetweaks_daemon_running;
95+ gboolean syndaemon_spawned;
96+ GPid syndaemon_pid;
97+ gboolean locate_pointer_spawned;
98+ GPid locate_pointer_pid;
99+};
100+
101+static void gsd_mouse_manager_class_init (GsdMouseManagerClass *klass);
102+static void gsd_mouse_manager_init (GsdMouseManager *mouse_manager);
103+static void gsd_mouse_manager_finalize (GObject *object);
104+static void set_tap_to_click (GdkDevice *device,
105+ gboolean state,
106+ gboolean left_handed);
107+
108+G_DEFINE_TYPE (GsdMouseManager, gsd_mouse_manager, G_TYPE_OBJECT)
109+
110+static gpointer manager_object = NULL;
111+
112+static void
113+gsd_mouse_manager_set_property (GObject *object,
114+ guint prop_id,
115+ const GValue *value,
116+ GParamSpec *pspec)
117+{
118+ switch (prop_id) {
119+ default:
120+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
121+ break;
122+ }
123+}
124+
125+static void
126+gsd_mouse_manager_get_property (GObject *object,
127+ guint prop_id,
128+ GValue *value,
129+ GParamSpec *pspec)
130+{
131+ switch (prop_id) {
132+ default:
133+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
134+ break;
135+ }
136+}
137+
138+static GObject *
139+gsd_mouse_manager_constructor (GType type,
140+ guint n_construct_properties,
141+ GObjectConstructParam *construct_properties)
142+{
143+ GsdMouseManager *mouse_manager;
144+
145+ mouse_manager = GSD_MOUSE_MANAGER (G_OBJECT_CLASS (gsd_mouse_manager_parent_class)->constructor (type,
146+ n_construct_properties,
147+ construct_properties));
148+
149+ return G_OBJECT (mouse_manager);
150+}
151+
152+static void
153+gsd_mouse_manager_dispose (GObject *object)
154+{
155+ G_OBJECT_CLASS (gsd_mouse_manager_parent_class)->dispose (object);
156+}
157+
158+static void
159+gsd_mouse_manager_class_init (GsdMouseManagerClass *klass)
160+{
161+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
162+
163+ object_class->get_property = gsd_mouse_manager_get_property;
164+ object_class->set_property = gsd_mouse_manager_set_property;
165+ object_class->constructor = gsd_mouse_manager_constructor;
166+ object_class->dispose = gsd_mouse_manager_dispose;
167+ object_class->finalize = gsd_mouse_manager_finalize;
168+
169+ g_type_class_add_private (klass, sizeof (GsdMouseManagerPrivate));
170+}
171+
172+static XDevice *
173+open_gdk_device (GdkDevice *device)
174+{
175+ XDevice *xdevice;
176+ int id;
177+
178+ g_object_get (G_OBJECT (device), "device-id", &id, NULL);
179+
180+ gdk_error_trap_push ();
181+
182+ xdevice = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), id);
183+
184+ if (gdk_error_trap_pop () != 0)
185+ return NULL;
186+
187+ return xdevice;
188+}
189+
190+static gboolean
191+device_is_blacklisted (GsdMouseManager *manager,
192+ GdkDevice *device)
193+{
194+ int id;
195+ g_object_get (G_OBJECT (device), "device-id", &id, NULL);
196+ if (g_hash_table_lookup (manager->priv->blacklist, GINT_TO_POINTER (id)) != NULL) {
197+ g_debug ("device %s (%d) is blacklisted", gdk_device_get_name (device), id);
198+ return TRUE;
199+ }
200+ return FALSE;
201+}
202+
203+static void
204+configure_button_layout (guchar *buttons,
205+ gint n_buttons,
206+ gboolean left_handed)
207+{
208+ const gint left_button = 1;
209+ gint right_button;
210+ gint i;
211+
212+ /* if the button is higher than 2 (3rd button) then it's
213+ * probably one direction of a scroll wheel or something else
214+ * uninteresting
215+ */
216+ right_button = MIN (n_buttons, 3);
217+
218+ /* If we change things we need to make sure we only swap buttons.
219+ * If we end up with multiple physical buttons assigned to the same
220+ * logical button the server will complain. This code assumes physical
221+ * button 0 is the physical left mouse button, and that the physical
222+ * button other than 0 currently assigned left_button or right_button
223+ * is the physical right mouse button.
224+ */
225+
226+ /* check if the current mapping satisfies the above assumptions */
227+ if (buttons[left_button - 1] != left_button &&
228+ buttons[left_button - 1] != right_button)
229+ /* The current mapping is weird. Swapping buttons is probably not a
230+ * good idea.
231+ */
232+ return;
233+
234+ /* check if we are left_handed and currently not swapped */
235+ if (left_handed && buttons[left_button - 1] == left_button) {
236+ /* find the right button */
237+ for (i = 0; i < n_buttons; i++) {
238+ if (buttons[i] == right_button) {
239+ buttons[i] = left_button;
240+ break;
241+ }
242+ }
243+ /* swap the buttons */
244+ buttons[left_button - 1] = right_button;
245+ }
246+ /* check if we are not left_handed but are swapped */
247+ else if (!left_handed && buttons[left_button - 1] == right_button) {
248+ /* find the right button */
249+ for (i = 0; i < n_buttons; i++) {
250+ if (buttons[i] == left_button) {
251+ buttons[i] = right_button;
252+ break;
253+ }
254+ }
255+ /* swap the buttons */
256+ buttons[left_button - 1] = left_button;
257+ }
258+}
259+
260+static gboolean
261+xinput_device_has_buttons (GdkDevice *device)
262+{
263+ int i;
264+ XAnyClassInfo *class_info;
265+
266+ /* FIXME can we use the XDevice's classes here instead? */
267+ XDeviceInfo *device_info, *info;
268+ gint n_devices;
269+ int id;
270+
271+ /* Find the XDeviceInfo for the GdkDevice */
272+ g_object_get (G_OBJECT (device), "device-id", &id, NULL);
273+
274+ device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &n_devices);
275+ if (device_info == NULL)
276+ return FALSE;
277+
278+ info = NULL;
279+ for (i = 0; i < n_devices; i++) {
280+ if (device_info[i].id == id) {
281+ info = &device_info[i];
282+ break;
283+ }
284+ }
285+ if (info == NULL)
286+ goto bail;
287+
288+ class_info = info->inputclassinfo;
289+ for (i = 0; i < info->num_classes; i++) {
290+ if (class_info->class == ButtonClass) {
291+ XButtonInfo *button_info;
292+
293+ button_info = (XButtonInfo *) class_info;
294+ if (button_info->num_buttons > 0) {
295+ XFreeDeviceList (device_info);
296+ return TRUE;
297+ }
298+ }
299+
300+ class_info = (XAnyClassInfo *) (((guchar *) class_info) +
301+ class_info->length);
302+ }
303+
304+bail:
305+ XFreeDeviceList (device_info);
306+
307+ return FALSE;
308+}
309+
310+static gboolean
311+touchpad_has_single_button (XDevice *device)
312+{
313+ Atom type, prop;
314+ int format;
315+ unsigned long nitems, bytes_after;
316+ unsigned char *data;
317+ gboolean is_single_button = FALSE;
318+ int rc;
319+
320+ prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Capabilities", False);
321+ if (!prop)
322+ return FALSE;
323+
324+ gdk_error_trap_push ();
325+ rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device, prop, 0, 1, False,
326+ XA_INTEGER, &type, &format, &nitems,
327+ &bytes_after, &data);
328+ if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 3)
329+ is_single_button = (data[0] == 1 && data[1] == 0 && data[2] == 0);
330+
331+ if (rc == Success)
332+ XFree (data);
333+
334+ gdk_error_trap_pop_ignored ();
335+
336+ return is_single_button;
337+}
338+
339+static void
340+set_left_handed (GsdMouseManager *manager,
341+ GdkDevice *device,
342+ gboolean mouse_left_handed,
343+ gboolean touchpad_left_handed)
344+{
345+ XDevice *xdevice;
346+ guchar *buttons;
347+ gsize buttons_capacity = 16;
348+ gboolean left_handed;
349+ gint n_buttons;
350+ const char *name;
351+
352+ buttons = g_new (guchar, buttons_capacity);
353+
354+ name = gdk_device_get_name (device);
355+ if (name != NULL && g_str_equal ("Virtual core XTEST pointer", name))
356+ return;
357+ if (!xinput_device_has_buttons (device))
358+ return;
359+
360+ xdevice = open_gdk_device (device);
361+ if (xdevice == NULL)
362+ return;
363+
364+ /* If the device is a touchpad, swap tap buttons
365+ * around too, otherwise a tap would be a right-click */
366+ if (device_is_touchpad (xdevice)) {
367+ gboolean tap = g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TAP_TO_CLICK);
368+ gboolean single_button = touchpad_has_single_button (xdevice);
369+
370+ left_handed = touchpad_left_handed;
371+
372+ if (tap && !single_button)
373+ set_tap_to_click (device, tap, left_handed);
374+
375+ if (single_button)
376+ goto out;
377+ } else {
378+ left_handed = mouse_left_handed;
379+ }
380+
381+ n_buttons = XGetDeviceButtonMapping (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice,
382+ buttons,
383+ buttons_capacity);
384+
385+ while (n_buttons > buttons_capacity) {
386+ buttons_capacity = n_buttons;
387+ buttons = (guchar *) g_realloc (buttons,
388+ buttons_capacity * sizeof (guchar));
389+
390+ n_buttons = XGetDeviceButtonMapping (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice,
391+ buttons,
392+ buttons_capacity);
393+ }
394+
395+ configure_button_layout (buttons, n_buttons, left_handed);
396+
397+ XSetDeviceButtonMapping (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, buttons, n_buttons);
398+
399+out:
400+ XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice);
401+ g_free (buttons);
402+}
403+
404+static void
405+set_motion (GsdMouseManager *manager,
406+ GdkDevice *device)
407+{
408+ XDevice *xdevice;
409+ XPtrFeedbackControl feedback;
410+ XFeedbackState *states, *state;
411+ int num_feedbacks;
412+ int numerator, denominator;
413+ gfloat motion_acceleration;
414+ int motion_threshold;
415+ GSettings *settings;
416+ guint i;
417+
418+ xdevice = open_gdk_device (device);
419+ if (xdevice == NULL)
420+ return;
421+
422+ if (device_is_touchpad (xdevice))
423+ settings = manager->priv->touchpad_settings;
424+ else
425+ settings = manager->priv->mouse_settings;
426+
427+ /* Calculate acceleration */
428+ motion_acceleration = g_settings_get_double (settings, KEY_MOTION_ACCELERATION);
429+
430+ if (motion_acceleration >= 1.0) {
431+ /* we want to get the acceleration, with a resolution of 0.5
432+ */
433+ if ((motion_acceleration - floor (motion_acceleration)) < 0.25) {
434+ numerator = floor (motion_acceleration);
435+ denominator = 1;
436+ } else if ((motion_acceleration - floor (motion_acceleration)) < 0.5) {
437+ numerator = ceil (2.0 * motion_acceleration);
438+ denominator = 2;
439+ } else if ((motion_acceleration - floor (motion_acceleration)) < 0.75) {
440+ numerator = floor (2.0 *motion_acceleration);
441+ denominator = 2;
442+ } else {
443+ numerator = ceil (motion_acceleration);
444+ denominator = 1;
445+ }
446+ } else if (motion_acceleration < 1.0 && motion_acceleration > 0) {
447+ /* This we do to 1/10ths */
448+ numerator = floor (motion_acceleration * 10) + 1;
449+ denominator= 10;
450+ } else {
451+ numerator = -1;
452+ denominator = -1;
453+ }
454+
455+ /* And threshold */
456+ motion_threshold = g_settings_get_int (settings, KEY_MOTION_THRESHOLD);
457+
458+ /* Get the list of feedbacks for the device */
459+ states = XGetFeedbackControl (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, &num_feedbacks);
460+ if (states == NULL)
461+ goto out;
462+ state = (XFeedbackState *) states;
463+ for (i = 0; i < num_feedbacks; i++) {
464+ if (state->class == PtrFeedbackClass) {
465+ /* And tell the device */
466+ feedback.class = PtrFeedbackClass;
467+ feedback.length = sizeof (XPtrFeedbackControl);
468+ feedback.id = state->id;
469+ feedback.threshold = motion_threshold;
470+ feedback.accelNum = numerator;
471+ feedback.accelDenom = denominator;
472+
473+ g_debug ("Setting accel %d/%d, threshold %d for device '%s'",
474+ numerator, denominator, motion_threshold, gdk_device_get_name (device));
475+
476+ XChangeFeedbackControl (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
477+ xdevice,
478+ DvAccelNum | DvAccelDenom | DvThreshold,
479+ (XFeedbackControl *) &feedback);
480+
481+ break;
482+ }
483+ state = (XFeedbackState *) ((char *) state + state->length);
484+ }
485+
486+ XFreeFeedbackList (states);
487+
488+ out:
489+
490+ XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice);
491+}
492+
493+static void
494+set_middle_button (GsdMouseManager *manager,
495+ GdkDevice *device,
496+ gboolean middle_button)
497+{
498+ Atom prop;
499+ XDevice *xdevice;
500+ Atom type;
501+ int format;
502+ unsigned long nitems, bytes_after;
503+ unsigned char *data;
504+ int rc;
505+
506+ prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
507+ "Evdev Middle Button Emulation", True);
508+
509+ if (!prop) /* no evdev devices */
510+ return;
511+
512+ xdevice = open_gdk_device (device);
513+ if (xdevice == NULL)
514+ return;
515+
516+ gdk_error_trap_push ();
517+
518+ rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
519+ xdevice, prop, 0, 1, False, XA_INTEGER, &type, &format,
520+ &nitems, &bytes_after, &data);
521+
522+ if (rc == Success && format == 8 && type == XA_INTEGER && nitems == 1) {
523+ data[0] = middle_button ? 1 : 0;
524+
525+ XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
526+ xdevice, prop, type, format, PropModeReplace, data, nitems);
527+ }
528+
529+ if (gdk_error_trap_pop ())
530+ g_warning ("Error in setting middle button emulation on \"%s\"", gdk_device_get_name (device));
531+
532+ if (rc == Success)
533+ XFree (data);
534+
535+ XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice);
536+}
537+
538+static int
539+set_disable_w_typing (GsdMouseManager *manager, gboolean state)
540+{
541+ if (state && touchpad_is_present ()) {
542+ GError *error = NULL;
543+ char *args[6];
544+
545+ if (manager->priv->syndaemon_spawned)
546+ return 0;
547+
548+ args[0] = "syndaemon";
549+ args[1] = "-i";
550+ args[2] = "0.5";
551+ args[3] = "-K";
552+ args[4] = "-R";
553+ args[5] = NULL;
554+
555+ if (!g_find_program_in_path (args[0]))
556+ return 0;
557+
558+ g_spawn_async (g_get_home_dir (), args, NULL,
559+ G_SPAWN_SEARCH_PATH, NULL, NULL,
560+ &manager->priv->syndaemon_pid, &error);
561+
562+ manager->priv->syndaemon_spawned = (error == NULL);
563+
564+ if (error) {
565+ g_settings_set_boolean (manager->priv->touchpad_settings, KEY_TOUCHPAD_DISABLE_W_TYPING, FALSE);
566+ g_error_free (error);
567+ }
568+ } else if (manager->priv->syndaemon_spawned) {
569+ kill (manager->priv->syndaemon_pid, SIGHUP);
570+ g_spawn_close_pid (manager->priv->syndaemon_pid);
571+ manager->priv->syndaemon_spawned = FALSE;
572+ }
573+
574+ return 0;
575+}
576+
577+static void
578+set_tap_to_click (GdkDevice *device,
579+ gboolean state,
580+ gboolean left_handed)
581+{
582+ int format, rc;
583+ unsigned long nitems, bytes_after;
584+ XDevice *xdevice;
585+ unsigned char* data;
586+ Atom prop, type;
587+
588+ prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Tap Action", False);
589+ if (!prop)
590+ return;
591+
592+ xdevice = open_gdk_device (device);
593+ if (xdevice == NULL)
594+ return;
595+
596+ if (!device_is_touchpad (xdevice)) {
597+ XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice);
598+ return;
599+ }
600+
601+ gdk_error_trap_push ();
602+ rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, 0, 2,
603+ False, XA_INTEGER, &type, &format, &nitems,
604+ &bytes_after, &data);
605+
606+ if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 7) {
607+ /* Set MR mapping for corner tapping on the right side*/
608+ data[0] = (state) ? 2 : 0;
609+ data[1] = (state) ? 3 : 0;
610+
611+ /* Set RLM mapping for 1/2/3 fingers*/
612+ data[4] = (state) ? ((left_handed) ? 3 : 1) : 0;
613+ data[5] = (state) ? ((left_handed) ? 1 : 3) : 0;
614+ data[6] = (state) ? 2 : 0;
615+ XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, XA_INTEGER, 8,
616+ PropModeReplace, data, nitems);
617+ }
618+
619+ if (rc == Success)
620+ XFree (data);
621+
622+ if (gdk_error_trap_pop ())
623+ g_warning ("Error in setting tap to click on \"%s\"", gdk_device_get_name (device));
624+
625+ XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice);
626+}
627+
628+static void
629+set_horiz_scroll (GdkDevice *device,
630+ gboolean state)
631+{
632+ int rc;
633+ XDevice *xdevice;
634+ Atom act_type, prop_edge, prop_twofinger;
635+ int act_format;
636+ unsigned long nitems, bytes_after;
637+ unsigned char *data;
638+
639+ prop_edge = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Edge Scrolling", False);
640+ prop_twofinger = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Two-Finger Scrolling", False);
641+
642+ if (!prop_edge || !prop_twofinger)
643+ return;
644+
645+ xdevice = open_gdk_device (device);
646+ if (xdevice == NULL)
647+ return;
648+
649+ if (!device_is_touchpad (xdevice)) {
650+ XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice);
651+ return;
652+ }
653+
654+ gdk_error_trap_push ();
655+ rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice,
656+ prop_edge, 0, 1, False,
657+ XA_INTEGER, &act_type, &act_format, &nitems,
658+ &bytes_after, &data);
659+ if (rc == Success && act_type == XA_INTEGER &&
660+ act_format == 8 && nitems >= 2) {
661+ data[1] = (state && data[0]);
662+ XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice,
663+ prop_edge, XA_INTEGER, 8,
664+ PropModeReplace, data, nitems);
665+ }
666+
667+ XFree (data);
668+
669+ rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice,
670+ prop_twofinger, 0, 1, False,
671+ XA_INTEGER, &act_type, &act_format, &nitems,
672+ &bytes_after, &data);
673+ if (rc == Success && act_type == XA_INTEGER &&
674+ act_format == 8 && nitems >= 2) {
675+ data[1] = (state && data[0]);
676+ XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice,
677+ prop_twofinger, XA_INTEGER, 8,
678+ PropModeReplace, data, nitems);
679+ }
680+
681+ if (gdk_error_trap_pop ())
682+ g_warning ("Error in setting horiz scroll on \"%s\"", gdk_device_get_name (device));
683+
684+ if (rc == Success)
685+ XFree (data);
686+
687+ XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice);
688+
689+}
690+
691+static void
692+set_edge_scroll (GdkDevice *device,
693+ GsdTouchpadScrollMethod method)
694+{
695+ int rc;
696+ XDevice *xdevice;
697+ Atom act_type, prop_edge, prop_twofinger;
698+ int act_format;
699+ unsigned long nitems, bytes_after;
700+ unsigned char *data;
701+
702+ prop_edge = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Edge Scrolling", False);
703+ prop_twofinger = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Two-Finger Scrolling", False);
704+
705+ if (!prop_edge || !prop_twofinger)
706+ return;
707+
708+ xdevice = open_gdk_device (device);
709+ if (xdevice == NULL)
710+ return;
711+
712+ if (!device_is_touchpad (xdevice)) {
713+ XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice);
714+ return;
715+ }
716+
717+ gdk_error_trap_push ();
718+ rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice,
719+ prop_edge, 0, 1, False,
720+ XA_INTEGER, &act_type, &act_format, &nitems,
721+ &bytes_after, &data);
722+ if (rc == Success && act_type == XA_INTEGER &&
723+ act_format == 8 && nitems >= 2) {
724+ data[0] = (method == GSD_TOUCHPAD_SCROLL_METHOD_EDGE_SCROLLING) ? 1 : 0;
725+ XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice,
726+ prop_edge, XA_INTEGER, 8,
727+ PropModeReplace, data, nitems);
728+ }
729+
730+ XFree (data);
731+
732+ rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice,
733+ prop_twofinger, 0, 1, False,
734+ XA_INTEGER, &act_type, &act_format, &nitems,
735+ &bytes_after, &data);
736+ if (rc == Success && act_type == XA_INTEGER &&
737+ act_format == 8 && nitems >= 2) {
738+ data[0] = (method == GSD_TOUCHPAD_SCROLL_METHOD_TWO_FINGER_SCROLLING) ? 1 : 0;
739+ XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice,
740+ prop_twofinger, XA_INTEGER, 8,
741+ PropModeReplace, data, nitems);
742+ }
743+
744+ if (gdk_error_trap_pop ())
745+ g_warning ("Error in setting edge scroll on \"%s\"", gdk_device_get_name (device));
746+
747+ if (rc == Success)
748+ XFree (data);
749+
750+ XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice);
751+}
752+
753+static void
754+set_touchpad_disabled (GdkDevice *device)
755+{
756+ int id;
757+ XDevice *xdevice;
758+
759+ g_object_get (G_OBJECT (device), "device-id", &id, NULL);
760+
761+ g_debug ("Trying to set device disabled for \"%s\" (%d)", gdk_device_get_name (device), id);
762+
763+ xdevice = open_gdk_device (device);
764+ if (xdevice == NULL)
765+ return;
766+
767+ if (!device_is_touchpad (xdevice)) {
768+ XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice);
769+ return;
770+ }
771+
772+ if (set_device_enabled (id, FALSE) == FALSE)
773+ g_warning ("Error disabling device \"%s\" (%d)", gdk_device_get_name (device), id);
774+ else
775+ g_debug ("Disabled device \"%s\" (%d)", gdk_device_get_name (device), id);
776+
777+ XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice);
778+}
779+
780+static void
781+set_touchpad_enabled (int id)
782+{
783+ XDevice *xdevice;
784+
785+ g_debug ("Trying to set device enabled for %d", id);
786+
787+ gdk_error_trap_push ();
788+ xdevice = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), id);
789+ if (gdk_error_trap_pop () != 0)
790+ return;
791+
792+ if (!device_is_touchpad (xdevice)) {
793+ XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice);
794+ return;
795+ }
796+
797+ if (set_device_enabled (id, TRUE) == FALSE)
798+ g_warning ("Error enabling device \"%d\"", id);
799+ else
800+ g_debug ("Enabled device %d", id);
801+
802+ XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice);
803+}
804+
805+static void
806+set_locate_pointer (GsdMouseManager *manager,
807+ gboolean state)
808+{
809+ if (state) {
810+ GError *error = NULL;
811+ char *args[2];
812+
813+ if (manager->priv->locate_pointer_spawned)
814+ return;
815+
816+ args[0] = LIBEXECDIR "/gsd-locate-pointer";
817+ args[1] = NULL;
818+
819+ g_spawn_async (NULL, args, NULL,
820+ 0, NULL, NULL,
821+ &manager->priv->locate_pointer_pid, &error);
822+
823+ manager->priv->locate_pointer_spawned = (error == NULL);
824+
825+ if (error) {
826+ g_settings_set_boolean (manager->priv->mouse_settings, KEY_LOCATE_POINTER, FALSE);
827+ g_error_free (error);
828+ }
829+
830+ } else if (manager->priv->locate_pointer_spawned) {
831+ kill (manager->priv->locate_pointer_pid, SIGHUP);
832+ g_spawn_close_pid (manager->priv->locate_pointer_pid);
833+ manager->priv->locate_pointer_spawned = FALSE;
834+ }
835+}
836+
837+static void
838+set_mousetweaks_daemon (GsdMouseManager *manager,
839+ gboolean dwell_click_enabled,
840+ gboolean secondary_click_enabled)
841+{
842+ GError *error = NULL;
843+ gchar *comm;
844+ gboolean run_daemon = dwell_click_enabled || secondary_click_enabled;
845+
846+ if (run_daemon || manager->priv->mousetweaks_daemon_running)
847+ comm = g_strdup_printf ("mousetweaks %s",
848+ run_daemon ? "" : "-s");
849+ else
850+ return;
851+
852+ if (run_daemon)
853+ manager->priv->mousetweaks_daemon_running = TRUE;
854+
855+ if (! g_spawn_command_line_async (comm, &error)) {
856+ if (error->code == G_SPAWN_ERROR_NOENT && run_daemon) {
857+ GtkWidget *dialog;
858+
859+ if (dwell_click_enabled) {
860+ g_settings_set_boolean (manager->priv->mouse_a11y_settings,
861+ KEY_DWELL_CLICK_ENABLED, FALSE);
862+ } else if (secondary_click_enabled) {
863+ g_settings_set_boolean (manager->priv->mouse_a11y_settings,
864+ KEY_SECONDARY_CLICK_ENABLED, FALSE);
865+ }
866+
867+ dialog = gtk_message_dialog_new (NULL, 0,
868+ GTK_MESSAGE_WARNING,
869+ GTK_BUTTONS_OK,
870+ _("Could not enable mouse accessibility features"));
871+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
872+ _("Mouse accessibility requires Mousetweaks "
873+ "to be installed on your system."));
874+ gtk_window_set_title (GTK_WINDOW (dialog), _("Universal Access"));
875+ gtk_window_set_icon_name (GTK_WINDOW (dialog),
876+ "preferences-desktop-accessibility");
877+ gtk_dialog_run (GTK_DIALOG (dialog));
878+ gtk_widget_destroy (dialog);
879+ }
880+ g_error_free (error);
881+ }
882+ g_free (comm);
883+}
884+
885+static gboolean
886+get_touchpad_handedness (GsdMouseManager *manager, gboolean mouse_left_handed)
887+{
888+ switch (g_settings_get_enum (manager->priv->touchpad_settings, KEY_LEFT_HANDED)) {
889+ case GSD_TOUCHPAD_HANDEDNESS_RIGHT:
890+ return FALSE;
891+ case GSD_TOUCHPAD_HANDEDNESS_LEFT:
892+ return TRUE;
893+ case GSD_TOUCHPAD_HANDEDNESS_MOUSE:
894+ return mouse_left_handed;
895+ default:
896+ g_assert_not_reached ();
897+ }
898+}
899+
900+static void
901+set_mouse_settings (GsdMouseManager *manager,
902+ GdkDevice *device)
903+{
904+ gboolean mouse_left_handed, touchpad_left_handed;
905+
906+ mouse_left_handed = g_settings_get_boolean (manager->priv->mouse_settings, KEY_LEFT_HANDED);
907+ touchpad_left_handed = get_touchpad_handedness (manager, mouse_left_handed);
908+ set_left_handed (manager, device, mouse_left_handed, touchpad_left_handed);
909+
910+ set_motion (manager, device);
911+ set_middle_button (manager, device, g_settings_get_boolean (manager->priv->mouse_settings, KEY_MIDDLE_BUTTON_EMULATION));
912+
913+ set_tap_to_click (device, g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TAP_TO_CLICK), touchpad_left_handed);
914+ set_edge_scroll (device, g_settings_get_enum (manager->priv->touchpad_settings, KEY_SCROLL_METHOD));
915+ set_horiz_scroll (device, g_settings_get_boolean (manager->priv->touchpad_settings, KEY_PAD_HORIZ_SCROLL));
916+ if (g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TOUCHPAD_ENABLED) == FALSE)
917+ set_touchpad_disabled (device);
918+}
919+
920+static void
921+mouse_callback (GSettings *settings,
922+ const gchar *key,
923+ GsdMouseManager *manager)
924+{
925+ GList *devices, *l;
926+
927+ if (g_str_equal (key, KEY_DWELL_CLICK_ENABLED) ||
928+ g_str_equal (key, KEY_SECONDARY_CLICK_ENABLED)) {
929+ set_mousetweaks_daemon (manager,
930+ g_settings_get_boolean (settings, KEY_DWELL_CLICK_ENABLED),
931+ g_settings_get_boolean (settings, KEY_SECONDARY_CLICK_ENABLED));
932+ return;
933+ } else if (g_str_equal (key, KEY_LOCATE_POINTER)) {
934+ set_locate_pointer (manager, g_settings_get_boolean (settings, KEY_LOCATE_POINTER));
935+ return;
936+ }
937+
938+ devices = gdk_device_manager_list_devices (manager->priv->device_manager, GDK_DEVICE_TYPE_SLAVE);
939+
940+ for (l = devices; l != NULL; l = l->next) {
941+ GdkDevice *device = l->data;
942+
943+ if (device_is_blacklisted (manager, device))
944+ return;
945+
946+ if (g_str_equal (key, KEY_LEFT_HANDED)) {
947+ gboolean mouse_left_handed;
948+ mouse_left_handed = g_settings_get_boolean (settings, KEY_LEFT_HANDED);
949+ set_left_handed (manager, device, mouse_left_handed, get_touchpad_handedness (manager, mouse_left_handed));
950+ } else if (g_str_equal (key, KEY_MOTION_ACCELERATION) ||
951+ g_str_equal (key, KEY_MOTION_THRESHOLD)) {
952+ set_motion (manager, device);
953+ } else if (g_str_equal (key, KEY_MIDDLE_BUTTON_EMULATION)) {
954+ set_middle_button (manager, device, g_settings_get_boolean (settings, KEY_MIDDLE_BUTTON_EMULATION));
955+ }
956+ }
957+ g_list_free (devices);
958+}
959+
960+static void
961+touchpad_callback (GSettings *settings,
962+ const gchar *key,
963+ GsdMouseManager *manager)
964+{
965+ GList *devices, *l;
966+
967+ if (g_str_equal (key, KEY_TOUCHPAD_DISABLE_W_TYPING)) {
968+ set_disable_w_typing (manager, g_settings_get_boolean (manager->priv->touchpad_settings, key));
969+ return;
970+ }
971+
972+ devices = gdk_device_manager_list_devices (manager->priv->device_manager, GDK_DEVICE_TYPE_SLAVE);
973+
974+ for (l = devices; l != NULL; l = l->next) {
975+ GdkDevice *device = l->data;
976+
977+ g_message ("checking on device %s", gdk_device_get_name (device));
978+
979+ if (device_is_blacklisted (manager, device))
980+ return;
981+
982+ if (g_str_equal (key, KEY_TAP_TO_CLICK)) {
983+ set_tap_to_click (device, g_settings_get_boolean (settings, key),
984+ g_settings_get_boolean (manager->priv->touchpad_settings, KEY_LEFT_HANDED));
985+ } else if (g_str_equal (key, KEY_SCROLL_METHOD)) {
986+ set_edge_scroll (device, g_settings_get_enum (settings, key));
987+ set_horiz_scroll (device, g_settings_get_boolean (settings, KEY_PAD_HORIZ_SCROLL));
988+ } else if (g_str_equal (key, KEY_PAD_HORIZ_SCROLL)) {
989+ set_horiz_scroll (device, g_settings_get_boolean (settings, key));
990+ } else if (g_str_equal (key, KEY_TOUCHPAD_ENABLED)) {
991+ if (g_settings_get_boolean (settings, key) == FALSE)
992+ set_touchpad_disabled (device);
993+ else
994+ set_touchpad_enabled (gdk_x11_device_get_id (device));
995+ } else if (g_str_equal (key, KEY_MOTION_ACCELERATION) ||
996+ g_str_equal (key, KEY_MOTION_THRESHOLD)) {
997+ set_motion (manager, device);
998+ } else if (g_str_equal (key, KEY_LEFT_HANDED)) {
999+ gboolean mouse_left_handed;
1000+ mouse_left_handed = g_settings_get_boolean (manager->priv->mouse_settings, KEY_LEFT_HANDED);
1001+ set_left_handed (manager, device, mouse_left_handed, get_touchpad_handedness (manager, mouse_left_handed));
1002+ }
1003+ }
1004+ g_list_free (devices);
1005+
1006+ if (g_str_equal (key, KEY_TOUCHPAD_ENABLED) &&
1007+ g_settings_get_boolean (settings, key)) {
1008+ devices = get_disabled_devices (manager->priv->device_manager);
1009+ for (l = devices; l != NULL; l = l->next) {
1010+ int device_id;
1011+
1012+ device_id = GPOINTER_TO_INT (l->data);
1013+ set_touchpad_enabled (device_id);
1014+ }
1015+ g_list_free (devices);
1016+ }
1017+}
1018+
1019+static void
1020+device_added_cb (GdkDeviceManager *device_manager,
1021+ GdkDevice *device,
1022+ GsdMouseManager *manager)
1023+{
1024+ if (gdk_device_get_source (device) == GDK_SOURCE_MOUSE) {
1025+ if (run_custom_command (device, COMMAND_DEVICE_ADDED) == FALSE) {
1026+ set_mouse_settings (manager, device);
1027+ } else {
1028+ int id;
1029+ g_object_get (G_OBJECT (device), "device-id", &id, NULL);
1030+ g_hash_table_insert (manager->priv->blacklist,
1031+ GINT_TO_POINTER (id), GINT_TO_POINTER (1));
1032+ }
1033+
1034+ /* If a touchpad was to appear... */
1035+ set_disable_w_typing (manager, g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TOUCHPAD_DISABLE_W_TYPING));
1036+ }
1037+}
1038+
1039+static void
1040+device_removed_cb (GdkDeviceManager *device_manager,
1041+ GdkDevice *device,
1042+ GsdMouseManager *manager)
1043+{
1044+ if (gdk_device_get_source (device) == GDK_SOURCE_MOUSE) {
1045+ int id;
1046+
1047+ run_custom_command (device, COMMAND_DEVICE_REMOVED);
1048+
1049+ g_object_get (G_OBJECT (device), "device-id", &id, NULL);
1050+ g_hash_table_remove (manager->priv->blacklist,
1051+ GINT_TO_POINTER (id));
1052+
1053+ /* If a touchpad was to disappear... */
1054+ set_disable_w_typing (manager, g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TOUCHPAD_DISABLE_W_TYPING));
1055+ }
1056+}
1057+
1058+static void
1059+set_devicepresence_handler (GsdMouseManager *manager)
1060+{
1061+ GdkDeviceManager *device_manager;
1062+
1063+ device_manager = gdk_display_get_device_manager (gdk_display_get_default ());
1064+
1065+ manager->priv->device_added_id = g_signal_connect (G_OBJECT (device_manager), "device-added",
1066+ G_CALLBACK (device_added_cb), manager);
1067+ manager->priv->device_removed_id = g_signal_connect (G_OBJECT (device_manager), "device-removed",
1068+ G_CALLBACK (device_removed_cb), manager);
1069+ manager->priv->device_manager = device_manager;
1070+}
1071+
1072+static void
1073+gsd_mouse_manager_init (GsdMouseManager *manager)
1074+{
1075+ manager->priv = GSD_MOUSE_MANAGER_GET_PRIVATE (manager);
1076+ manager->priv->blacklist = g_hash_table_new (g_direct_hash, g_direct_equal);
1077+}
1078+
1079+static gboolean
1080+gsd_mouse_manager_idle_cb (GsdMouseManager *manager)
1081+{
1082+ GList *devices, *l;
1083+
1084+ gnome_settings_profile_start (NULL);
1085+
1086+ set_devicepresence_handler (manager);
1087+
1088+ manager->priv->mouse_settings = g_settings_new (SETTINGS_MOUSE_DIR);
1089+ g_signal_connect (manager->priv->mouse_settings, "changed",
1090+ G_CALLBACK (mouse_callback), manager);
1091+
1092+ manager->priv->mouse_a11y_settings = g_settings_new ("org.gnome.desktop.a11y.mouse");
1093+ g_signal_connect (manager->priv->mouse_a11y_settings, "changed",
1094+ G_CALLBACK (mouse_callback), manager);
1095+
1096+ manager->priv->touchpad_settings = g_settings_new (SETTINGS_TOUCHPAD_DIR);
1097+ g_signal_connect (manager->priv->touchpad_settings, "changed",
1098+ G_CALLBACK (touchpad_callback), manager);
1099+
1100+ manager->priv->syndaemon_spawned = FALSE;
1101+
1102+ set_locate_pointer (manager, g_settings_get_boolean (manager->priv->mouse_settings, KEY_LOCATE_POINTER));
1103+ set_mousetweaks_daemon (manager,
1104+ g_settings_get_boolean (manager->priv->mouse_a11y_settings, KEY_DWELL_CLICK_ENABLED),
1105+ g_settings_get_boolean (manager->priv->mouse_a11y_settings, KEY_SECONDARY_CLICK_ENABLED));
1106+ set_disable_w_typing (manager, g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TOUCHPAD_DISABLE_W_TYPING));
1107+
1108+ devices = gdk_device_manager_list_devices (manager->priv->device_manager, GDK_DEVICE_TYPE_SLAVE);
1109+ for (l = devices; l != NULL; l = l->next) {
1110+ GdkDevice *device = l->data;
1111+
1112+ if (run_custom_command (device, COMMAND_DEVICE_PRESENT) == FALSE) {
1113+ set_mouse_settings (manager, device);
1114+ } else {
1115+ int id;
1116+ g_object_get (G_OBJECT (device), "device-id", &id, NULL);
1117+ g_hash_table_insert (manager->priv->blacklist,
1118+ GINT_TO_POINTER (id), GINT_TO_POINTER (1));
1119+ }
1120+ }
1121+ g_list_free (devices);
1122+
1123+ if (g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TOUCHPAD_ENABLED)) {
1124+ devices = get_disabled_devices (manager->priv->device_manager);
1125+ for (l = devices; l != NULL; l = l->next) {
1126+ int device_id;
1127+
1128+ device_id = GPOINTER_TO_INT (l->data);
1129+ set_touchpad_enabled (device_id);
1130+ }
1131+ g_list_free (devices);
1132+ }
1133+
1134+ gnome_settings_profile_end (NULL);
1135+
1136+ manager->priv->start_idle_id = 0;
1137+
1138+ return FALSE;
1139+}
1140+
1141+gboolean
1142+gsd_mouse_manager_start (GsdMouseManager *manager,
1143+ GError **error)
1144+{
1145+ gnome_settings_profile_start (NULL);
1146+
1147+ if (!supports_xinput_devices ()) {
1148+ g_debug ("XInput is not supported, not applying any settings");
1149+ return TRUE;
1150+ }
1151+
1152+ manager->priv->start_idle_id = g_idle_add ((GSourceFunc) gsd_mouse_manager_idle_cb, manager);
1153+
1154+ gnome_settings_profile_end (NULL);
1155+
1156+ return TRUE;
1157+}
1158+
1159+void
1160+gsd_mouse_manager_stop (GsdMouseManager *manager)
1161+{
1162+ GsdMouseManagerPrivate *p = manager->priv;
1163+
1164+ g_debug ("Stopping mouse manager");
1165+
1166+ if (p->device_manager != NULL) {
1167+ g_signal_handler_disconnect (p->device_manager, p->device_added_id);
1168+ g_signal_handler_disconnect (p->device_manager, p->device_removed_id);
1169+ p->device_manager = NULL;
1170+ }
1171+
1172+ if (p->mouse_a11y_settings != NULL) {
1173+ g_object_unref (p->mouse_a11y_settings);
1174+ p->mouse_a11y_settings = NULL;
1175+ }
1176+
1177+ if (p->mouse_settings != NULL) {
1178+ g_object_unref (p->mouse_settings);
1179+ p->mouse_settings = NULL;
1180+ }
1181+
1182+ if (p->touchpad_settings != NULL) {
1183+ g_object_unref (p->touchpad_settings);
1184+ p->touchpad_settings = NULL;
1185+ }
1186+
1187+ set_locate_pointer (manager, FALSE);
1188+}
1189+
1190+static void
1191+gsd_mouse_manager_finalize (GObject *object)
1192+{
1193+ GsdMouseManager *mouse_manager;
1194+
1195+ g_return_if_fail (object != NULL);
1196+ g_return_if_fail (GSD_IS_MOUSE_MANAGER (object));
1197+
1198+ mouse_manager = GSD_MOUSE_MANAGER (object);
1199+
1200+ g_return_if_fail (mouse_manager->priv != NULL);
1201+
1202+ if (mouse_manager->priv->blacklist != NULL)
1203+ g_hash_table_destroy (mouse_manager->priv->blacklist);
1204+
1205+ if (mouse_manager->priv->start_idle_id != 0)
1206+ g_source_remove (mouse_manager->priv->start_idle_id);
1207+
1208+ if (mouse_manager->priv->device_manager != NULL) {
1209+ g_signal_handler_disconnect (mouse_manager->priv->device_manager, mouse_manager->priv->device_added_id);
1210+ g_signal_handler_disconnect (mouse_manager->priv->device_manager, mouse_manager->priv->device_removed_id);
1211+ }
1212+
1213+ if (mouse_manager->priv->mouse_settings != NULL)
1214+ g_object_unref (mouse_manager->priv->mouse_settings);
1215+
1216+ if (mouse_manager->priv->mouse_a11y_settings != NULL)
1217+ g_object_unref (mouse_manager->priv->mouse_a11y_settings);
1218+
1219+ if (mouse_manager->priv->touchpad_settings != NULL)
1220+ g_object_unref (mouse_manager->priv->touchpad_settings);
1221+
1222+ G_OBJECT_CLASS (gsd_mouse_manager_parent_class)->finalize (object);
1223+}
1224+
1225+GsdMouseManager *
1226+gsd_mouse_manager_new (void)
1227+{
1228+ if (manager_object != NULL) {
1229+ g_object_ref (manager_object);
1230+ } else {
1231+ manager_object = g_object_new (GSD_TYPE_MOUSE_MANAGER, NULL);
1232+ g_object_add_weak_pointer (manager_object,
1233+ (gpointer *) &manager_object);
1234+ }
1235+
1236+ return GSD_MOUSE_MANAGER (manager_object);
1237+}
1238
1239=== modified file '.pc/applied-patches'
1240--- .pc/applied-patches 2012-06-18 12:32:40 +0000
1241+++ .pc/applied-patches 2012-08-09 06:39:20 +0000
1242@@ -15,3 +15,4 @@
1243 50_add_dell_backlight.patch
1244 51_always_lock_screen_on_suspend.patch
1245 git_xrandr_explicitly_set_clone_state.patch
1246+52_kill_syndaemon_when_gsd_die.patch
1247
1248=== modified file 'debian/changelog'
1249--- debian/changelog 2012-06-18 12:32:40 +0000
1250+++ debian/changelog 2012-08-09 06:39:20 +0000
1251@@ -1,3 +1,13 @@
1252+gnome-settings-daemon (3.2.2-0ubuntu2.3) oneiric-proposed; urgency=low
1253+
1254+ * debian/patches/52_kill_syndaemon_when_gsd_die.patch:
1255+ - Ensure that a spawned syndaemon gets killed when settings-daemon exists
1256+ due to a crash, a keyboard interrupt, etc. This avoids having multiple
1257+ syndaemons run at the same time, which can lead to the trackpad be
1258+ unexpected disabled. (LP: #868400)
1259+
1260+ -- Hsin-Yi Chen (hychen) <hychen@ubuntu.com> Thu, 09 Aug 2012 14:28:59 +0800
1261+
1262 gnome-settings-daemon (3.2.2-0ubuntu2.2) oneiric-proposed; urgency=low
1263
1264 [ Hsin-Yi, Chen (hychen) ]
1265
1266=== added file 'debian/patches/52_kill_syndaemon_when_gsd_die.patch'
1267--- debian/patches/52_kill_syndaemon_when_gsd_die.patch 1970-01-01 00:00:00 +0000
1268+++ debian/patches/52_kill_syndaemon_when_gsd_die.patch 2012-08-09 06:39:20 +0000
1269@@ -0,0 +1,76 @@
1270+From: Hsin-Yi Chen (hychen) <hychen@ubuntu.com>
1271+Description: Ensure that a spawned syndaemon gets killed when
1272+ settings-daemon exists due to a crash, a keyboard interrupt, etc.
1273+ This avoids having multiple syndaemons run at the same time, which
1274+ can lead to the trackpad malfunctioning.
1275+Origin: upstream, http://git.gnome.org/browse/gnome-settings-daemon/commit/?id=31aa30a0207b9de77706f03dacb8d914c959d3a6
1276+Author: Martin Pitt <martin.pitt@ubuntu.com>
1277+Forwarded: not-needed
1278+Bug: https://bugzilla.gnome.org/668667
1279+Bug-Ubuntu: https://launchpad.net/bugs/868400
1280+
1281+Index: fix-868400-oneiric/plugins/mouse/gsd-mouse-manager.c
1282+===================================================================
1283+--- fix-868400-oneiric.orig/plugins/mouse/gsd-mouse-manager.c 2012-07-25 15:27:51.745956000 +0800
1284++++ fix-868400-oneiric/plugins/mouse/gsd-mouse-manager.c 2012-07-25 15:31:29.608752850 +0800
1285+@@ -28,6 +28,9 @@
1286+ #include <string.h>
1287+ #include <errno.h>
1288+ #include <math.h>
1289++#ifdef __linux
1290++#include <sys/prctl.h>
1291++#endif
1292+
1293+ #include <locale.h>
1294+
1295+@@ -527,6 +530,26 @@
1296+ XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice);
1297+ }
1298+
1299++/* Ensure that syndaemon dies together with us, to avoid running several of
1300++ * them */
1301++static void
1302++setup_syndaemon (gpointer user_data)
1303++{
1304++#ifdef __linux
1305++ prctl (PR_SET_PDEATHSIG, SIGHUP);
1306++#endif
1307++}
1308++
1309++static void
1310++syndaemon_died (GPid pid, gint status, gpointer user_data)
1311++{
1312++ GsdMouseManager *manager = GSD_MOUSE_MANAGER (user_data);
1313++
1314++ g_debug ("syndaemon stopped with status %i", status);
1315++ g_spawn_close_pid (pid);
1316++ manager->priv->syndaemon_spawned = FALSE;
1317++}
1318++
1319+ static int
1320+ set_disable_w_typing (GsdMouseManager *manager, gboolean state)
1321+ {
1322+@@ -547,15 +570,22 @@
1323+ if (!g_find_program_in_path (args[0]))
1324+ return 0;
1325+
1326++ /* we must use G_SPAWN_DO_NOT_REAP_CHILD to avoid
1327++ * double-forking, otherwise syndaemon will immediately get
1328++ * killed again through (PR_SET_PDEATHSIG when the intermediate
1329++ * process dies */
1330+ g_spawn_async (g_get_home_dir (), args, NULL,
1331+- G_SPAWN_SEARCH_PATH, NULL, NULL,
1332++ G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD, setup_syndaemon, NULL,
1333+ &manager->priv->syndaemon_pid, &error);
1334+
1335+ manager->priv->syndaemon_spawned = (error == NULL);
1336+
1337+ if (error) {
1338++ g_warning ("Failed to launch syndaemon: %s", error->message);
1339+ g_settings_set_boolean (manager->priv->touchpad_settings, KEY_TOUCHPAD_DISABLE_W_TYPING, FALSE);
1340+ g_error_free (error);
1341++ } else {
1342++ g_child_watch_add (manager->priv->syndaemon_pid, syndaemon_died, manager);
1343+ }
1344+ } else if (manager->priv->syndaemon_spawned) {
1345+ kill (manager->priv->syndaemon_pid, SIGHUP);
1346
1347=== modified file 'debian/patches/series'
1348--- debian/patches/series 2012-06-18 12:32:40 +0000
1349+++ debian/patches/series 2012-08-09 06:39:20 +0000
1350@@ -15,3 +15,4 @@
1351 50_add_dell_backlight.patch
1352 51_always_lock_screen_on_suspend.patch
1353 git_xrandr_explicitly_set_clone_state.patch
1354+52_kill_syndaemon_when_gsd_die.patch
1355
1356=== modified file 'plugins/mouse/gsd-mouse-manager.c'
1357--- plugins/mouse/gsd-mouse-manager.c 2011-11-10 12:15:05 +0000
1358+++ plugins/mouse/gsd-mouse-manager.c 2012-08-09 06:39:20 +0000
1359@@ -28,6 +28,9 @@
1360 #include <string.h>
1361 #include <errno.h>
1362 #include <math.h>
1363+#ifdef __linux
1364+#include <sys/prctl.h>
1365+#endif
1366
1367 #include <locale.h>
1368
1369@@ -527,6 +530,26 @@
1370 XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice);
1371 }
1372
1373+/* Ensure that syndaemon dies together with us, to avoid running several of
1374+ * them */
1375+static void
1376+setup_syndaemon (gpointer user_data)
1377+{
1378+#ifdef __linux
1379+ prctl (PR_SET_PDEATHSIG, SIGHUP);
1380+#endif
1381+}
1382+
1383+static void
1384+syndaemon_died (GPid pid, gint status, gpointer user_data)
1385+{
1386+ GsdMouseManager *manager = GSD_MOUSE_MANAGER (user_data);
1387+
1388+ g_debug ("syndaemon stopped with status %i", status);
1389+ g_spawn_close_pid (pid);
1390+ manager->priv->syndaemon_spawned = FALSE;
1391+}
1392+
1393 static int
1394 set_disable_w_typing (GsdMouseManager *manager, gboolean state)
1395 {
1396@@ -547,15 +570,22 @@
1397 if (!g_find_program_in_path (args[0]))
1398 return 0;
1399
1400+ /* we must use G_SPAWN_DO_NOT_REAP_CHILD to avoid
1401+ * double-forking, otherwise syndaemon will immediately get
1402+ * killed again through (PR_SET_PDEATHSIG when the intermediate
1403+ * process dies */
1404 g_spawn_async (g_get_home_dir (), args, NULL,
1405- G_SPAWN_SEARCH_PATH, NULL, NULL,
1406+ G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD, setup_syndaemon, NULL,
1407 &manager->priv->syndaemon_pid, &error);
1408
1409 manager->priv->syndaemon_spawned = (error == NULL);
1410
1411 if (error) {
1412+ g_warning ("Failed to launch syndaemon: %s", error->message);
1413 g_settings_set_boolean (manager->priv->touchpad_settings, KEY_TOUCHPAD_DISABLE_W_TYPING, FALSE);
1414 g_error_free (error);
1415+ } else {
1416+ g_child_watch_add (manager->priv->syndaemon_pid, syndaemon_died, manager);
1417 }
1418 } else if (manager->priv->syndaemon_spawned) {
1419 kill (manager->priv->syndaemon_pid, SIGHUP);

Subscribers

People subscribed via source and target branches