~kroq-gar78/ubuntu/precise/gnome-control-center/fix-885947

« back to all changes in this revision

Viewing changes to panels/mouse/gnome-mouse-properties.c

  • Committer: Bazaar Package Importer
  • Author(s): Rodrigo Moya
  • Date: 2011-05-17 10:47:27 UTC
  • mfrom: (0.1.11 experimental) (1.1.45 upstream)
  • Revision ID: james.westby@ubuntu.com-20110517104727-lqel6m8vhfw5jby1
Tags: 1:3.0.1.1-1ubuntu1
* Rebase on Debian, remaining Ubuntu changes:
* debian/control:
  - Build-Depend on hardening-wrapper, dpkg-dev and dh-autoreconf
  - Add dependency on ubuntu-system-service
  - Remove dependency on gnome-icon-theme-symbolic
  - Move dependency on apg, gnome-icon-theme-symbolic and accountsservice to
    be a Recommends: until we get them in main
* debian/rules:
  - Use autoreconf
  - Add binary-post-install rule for gnome-control-center-data
  - Run dh-autoreconf
* debian/gnome-control-center.dirs:
* debian/gnome-control-center.links:
  - Add a link to the control center shell for indicators
* debian/patches/00_disable-nm.patch:
  - Temporary patch to disable building with NetworkManager until we get
    the new one in the archive
* debian/patches/01_git_remove_gettext_calls.patch:
  - Remove calls to AM_GNU_GETTEXT, IT_PROG_INTLTOOL should be enough
* debian/patches/01_git_kill_warning.patch:
  - Kill warning
* debian/patches/50_ubuntu_systemwide_prefs.patch:
  - Ubuntu specific proxy preferences
* debian/patches/51_ubuntu_system_keyboard.patch:
  - Implement the global keyboard spec at https://wiki.ubuntu.com/DefaultKeyboardSettings

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
 
2
 *
 
3
 * Copyright (C) 2001 Red Hat, Inc.
 
4
 * Copyright (C) 2001 Ximian, Inc.
 
5
 *
 
6
 * Written by: Jonathon Blandford <jrb@redhat.com>,
 
7
 *             Bradford Hovinen <hovinen@ximian.com>,
 
8
 *
 
9
 * This program is free software; you can redistribute it and/or modify
 
10
 * it under the terms of the GNU General Public License as published by
 
11
 * the Free Software Foundation; either version 2, or (at your option)
 
12
 * any later version.
 
13
 *
 
14
 * This program is distributed in the hope that it will be useful,
 
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
 * GNU General Public License for more details.
 
18
 *
 
19
 * You should have received a copy of the GNU General Public License
 
20
 * along with this program; if not, write to the Free Software
 
21
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
22
 * 02111-1307, USA.
 
23
 */
 
24
 
 
25
#include <config.h>
 
26
 
 
27
#include <glib/gi18n.h>
 
28
#include <string.h>
 
29
#include <gdk/gdk.h>
 
30
#include <gdk/gdkx.h>
 
31
#include <gnome-settings-daemon/gsd-enums.h>
 
32
#include <math.h>
 
33
 
 
34
#include "gnome-mouse-properties.h"
 
35
#include "gsd-input-helper.h"
 
36
 
 
37
#include <sys/types.h>
 
38
#include <sys/stat.h>
 
39
#include <dirent.h>
 
40
 
 
41
#include <X11/Xatom.h>
 
42
#include <X11/extensions/XInput.h>
 
43
 
 
44
#define WID(x) (GtkWidget*) gtk_builder_get_object (dialog, x)
 
45
 
 
46
enum
 
47
{
 
48
        DOUBLE_CLICK_TEST_OFF,
 
49
        DOUBLE_CLICK_TEST_MAYBE,
 
50
        DOUBLE_CLICK_TEST_ON
 
51
};
 
52
 
 
53
/* State in testing the double-click speed. Global for a great deal of
 
54
 * convenience
 
55
 */
 
56
static gint double_click_state = DOUBLE_CLICK_TEST_OFF;
 
57
static GSettings *mouse_settings = NULL;
 
58
static GSettings *touchpad_settings = NULL;
 
59
static GdkDeviceManager *device_manager = NULL;
 
60
static guint device_added_id = 0;
 
61
static guint device_removed_id = 0;
 
62
static gboolean changing_scroll = FALSE;
 
63
 
 
64
/* Double Click handling */
 
65
 
 
66
struct test_data_t
 
67
{
 
68
        gint *timeout_id;
 
69
        GtkWidget *image;
 
70
};
 
71
 
 
72
/* Timeout for the double click test */
 
73
 
 
74
static gboolean
 
75
test_maybe_timeout (struct test_data_t *data)
 
76
{
 
77
        double_click_state = DOUBLE_CLICK_TEST_OFF;
 
78
 
 
79
        gtk_image_set_from_icon_name (GTK_IMAGE (data->image), "face-plain", GTK_ICON_SIZE_DIALOG);
 
80
 
 
81
        *data->timeout_id = 0;
 
82
 
 
83
        return FALSE;
 
84
}
 
85
 
 
86
/* Callback issued when the user clicks the double click testing area. */
 
87
 
 
88
static gboolean
 
89
event_box_button_press_event (GtkWidget   *widget,
 
90
                              GdkEventButton *event,
 
91
                              GtkBuilder   *dialog)
 
92
{
 
93
        gint                       double_click_time;
 
94
        static struct test_data_t  data;
 
95
        static gint                test_on_timeout_id     = 0;
 
96
        static gint                test_maybe_timeout_id  = 0;
 
97
        static guint32             double_click_timestamp = 0;
 
98
        GtkWidget                 *image;
 
99
 
 
100
        if (event->type != GDK_BUTTON_PRESS)
 
101
                return FALSE;
 
102
 
 
103
        image = g_object_get_data (G_OBJECT (widget), "image");
 
104
 
 
105
        double_click_time = g_settings_get_int (mouse_settings, "double-click");
 
106
 
 
107
        if (test_maybe_timeout_id != 0)
 
108
                g_source_remove  (test_maybe_timeout_id);
 
109
        if (test_on_timeout_id != 0)
 
110
                g_source_remove (test_on_timeout_id);
 
111
 
 
112
        switch (double_click_state) {
 
113
        case DOUBLE_CLICK_TEST_OFF:
 
114
                double_click_state = DOUBLE_CLICK_TEST_MAYBE;
 
115
                data.image = image;
 
116
                data.timeout_id = &test_maybe_timeout_id;
 
117
                test_maybe_timeout_id = g_timeout_add (double_click_time, (GSourceFunc) test_maybe_timeout, &data);
 
118
                break;
 
119
        case DOUBLE_CLICK_TEST_MAYBE:
 
120
                if (event->time - double_click_timestamp < double_click_time) {
 
121
                        double_click_state = DOUBLE_CLICK_TEST_ON;
 
122
                        data.image = image;
 
123
                        data.timeout_id = &test_on_timeout_id;
 
124
                        test_on_timeout_id = g_timeout_add (2500, (GSourceFunc) test_maybe_timeout, &data);
 
125
                }
 
126
                break;
 
127
        case DOUBLE_CLICK_TEST_ON:
 
128
                double_click_state = DOUBLE_CLICK_TEST_OFF;
 
129
                break;
 
130
        }
 
131
 
 
132
        double_click_timestamp = event->time;
 
133
 
 
134
        switch (double_click_state) {
 
135
        case DOUBLE_CLICK_TEST_ON:
 
136
                gtk_image_set_from_icon_name (GTK_IMAGE (image), "face-laugh", GTK_ICON_SIZE_DIALOG);
 
137
                break;
 
138
        case DOUBLE_CLICK_TEST_MAYBE:
 
139
                gtk_image_set_from_icon_name (GTK_IMAGE (image), "face-smile", GTK_ICON_SIZE_DIALOG);
 
140
                break;
 
141
        case DOUBLE_CLICK_TEST_OFF:
 
142
                gtk_image_set_from_icon_name (GTK_IMAGE (image), "face-plain", GTK_ICON_SIZE_DIALOG);
 
143
                break;
 
144
        }
 
145
 
 
146
        return TRUE;
 
147
}
 
148
 
 
149
static void
 
150
orientation_radio_button_release_event (GtkWidget   *widget,
 
151
                                        GdkEventButton *event)
 
152
{
 
153
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
 
154
}
 
155
 
 
156
static void
 
157
setup_scrollmethod_radios (GtkBuilder *dialog)
 
158
{
 
159
        GsdTouchpadScrollMethod method;
 
160
 
 
161
        method = g_settings_get_enum (touchpad_settings, "scroll-method");
 
162
 
 
163
        switch (method) {
 
164
        case GSD_TOUCHPAD_SCROLL_METHOD_EDGE_SCROLLING:
 
165
                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (WID ("scroll_edge_radio")), TRUE);
 
166
                break;
 
167
        case GSD_TOUCHPAD_SCROLL_METHOD_TWO_FINGER_SCROLLING:
 
168
                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (WID ("scroll_twofinger_radio")), TRUE);
 
169
                break;
 
170
        case GSD_TOUCHPAD_SCROLL_METHOD_DISABLED:
 
171
                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (WID ("scroll_disabled_radio")), TRUE);
 
172
                break;
 
173
        }
 
174
 
 
175
        gtk_widget_set_sensitive (WID ("horiz_scroll_toggle"),
 
176
                                  !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (WID ("scroll_disabled_radio"))));
 
177
}
 
178
 
 
179
static void
 
180
scrollmethod_changed_event (GtkToggleButton *button, GtkBuilder *dialog)
 
181
{
 
182
        GsdTouchpadScrollMethod method;
 
183
        GtkToggleButton *disabled = GTK_TOGGLE_BUTTON (WID ("scroll_disabled_radio"));
 
184
 
 
185
        if (changing_scroll)
 
186
                return;
 
187
 
 
188
        gtk_widget_set_sensitive (WID ("horiz_scroll_toggle"),
 
189
                                  !gtk_toggle_button_get_active (disabled));
 
190
 
 
191
        if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (WID ("scroll_edge_radio"))))
 
192
                method = GSD_TOUCHPAD_SCROLL_METHOD_EDGE_SCROLLING;
 
193
        else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (WID ("scroll_twofinger_radio"))))
 
194
                method = GSD_TOUCHPAD_SCROLL_METHOD_TWO_FINGER_SCROLLING;
 
195
        else
 
196
                method = GSD_TOUCHPAD_SCROLL_METHOD_DISABLED;
 
197
 
 
198
        g_settings_set_enum (touchpad_settings, "scroll-method", method);
 
199
}
 
200
 
 
201
static void
 
202
synaptics_check_capabilities (GtkBuilder *dialog)
 
203
{
 
204
        int numdevices, i;
 
205
        XDeviceInfo *devicelist;
 
206
        Atom realtype, prop;
 
207
        int realformat;
 
208
        unsigned long nitems, bytes_after;
 
209
        unsigned char *data;
 
210
 
 
211
        prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Capabilities", True);
 
212
        if (!prop)
 
213
                return;
 
214
 
 
215
        devicelist = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &numdevices);
 
216
        for (i = 0; i < numdevices; i++) {
 
217
                if (devicelist[i].use != IsXExtensionPointer)
 
218
                        continue;
 
219
 
 
220
                gdk_error_trap_push ();
 
221
                XDevice *device = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
 
222
                                               devicelist[i].id);
 
223
                if (gdk_error_trap_pop ())
 
224
                        continue;
 
225
 
 
226
                gdk_error_trap_push ();
 
227
                if ((XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device, prop, 0, 2, False,
 
228
                                         XA_INTEGER, &realtype, &realformat, &nitems,
 
229
                                         &bytes_after, &data) == Success) && (realtype != None)) {
 
230
                        /* Property data is booleans for has_left, has_middle, has_right, has_double, has_triple.
 
231
                         * Newer drivers (X.org/kerrnel) will also include has_pressure and has_width. */
 
232
                        if (!data[0]) {
 
233
                                gtk_widget_set_sensitive (WID ("tap_to_click_toggle"), FALSE);
 
234
                        }
 
235
 
 
236
                        /* Disable two finger scrolling unless the hardware supports
 
237
                         * double touch or can emulate it based on finger width. */
 
238
                        if (!(data[3] ||(nitems >= 6 && data[5])))
 
239
                                gtk_widget_set_sensitive (WID ("scroll_twofinger_radio"), FALSE);
 
240
 
 
241
                        XFree (data);
 
242
                }
 
243
                gdk_error_trap_pop_ignored ();
 
244
 
 
245
                XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device);
 
246
        }
 
247
        XFreeDeviceList (devicelist);
 
248
}
 
249
 
 
250
/* Set up the property editors in the dialog. */
 
251
static void
 
252
setup_dialog (GtkBuilder *dialog)
 
253
{
 
254
        GtkRadioButton *radio;
 
255
        gboolean        touchpad_present;
 
256
 
 
257
        /* Orientation radio buttons */
 
258
        radio = GTK_RADIO_BUTTON (WID ("left_handed_radio"));
 
259
        g_settings_bind (mouse_settings, "left-handed", radio, "active", G_SETTINGS_BIND_DEFAULT);
 
260
 
 
261
        /* explicitly connect to button-release so that you can change orientation with either button */
 
262
        g_signal_connect (WID ("right_handed_radio"), "button_release_event",
 
263
                G_CALLBACK (orientation_radio_button_release_event), NULL);
 
264
        g_signal_connect (WID ("left_handed_radio"), "button_release_event",
 
265
                G_CALLBACK (orientation_radio_button_release_event), NULL);
 
266
 
 
267
        /* Locate pointer toggle */
 
268
        g_settings_bind (mouse_settings, "locate-pointer",
 
269
                         WID ("locate_pointer_toggle"), "active",
 
270
                         G_SETTINGS_BIND_DEFAULT);
 
271
 
 
272
        /* Double-click time */
 
273
        g_settings_bind (mouse_settings, "double-click",
 
274
                         gtk_range_get_adjustment (GTK_RANGE (WID ("delay_scale"))), "value",
 
275
                         G_SETTINGS_BIND_DEFAULT);
 
276
        gtk_image_set_from_icon_name (GTK_IMAGE (WID ("double_click_image")), "face-plain", GTK_ICON_SIZE_DIALOG);
 
277
        g_object_set_data (G_OBJECT (WID ("double_click_eventbox")), "image", WID ("double_click_image"));
 
278
        g_signal_connect (WID ("double_click_eventbox"), "button_press_event",
 
279
                          G_CALLBACK (event_box_button_press_event), dialog);
 
280
 
 
281
        /* speed */
 
282
        g_settings_bind (mouse_settings, "motion-acceleration",
 
283
                         gtk_range_get_adjustment (GTK_RANGE (WID ("accel_scale"))), "value",
 
284
                         G_SETTINGS_BIND_DEFAULT);
 
285
        g_settings_bind (mouse_settings, "motion-threshold",
 
286
                         gtk_range_get_adjustment (GTK_RANGE (WID ("sensitivity_scale"))), "value",
 
287
                         G_SETTINGS_BIND_DEFAULT);
 
288
 
 
289
        /* DnD threshold */
 
290
        g_settings_bind (mouse_settings, "drag-threshold",
 
291
                         gtk_range_get_adjustment (GTK_RANGE (WID ("drag_threshold_scale"))), "value",
 
292
                         G_SETTINGS_BIND_DEFAULT);
 
293
 
 
294
        /* Trackpad page */
 
295
        touchpad_present = touchpad_is_present ();
 
296
        gtk_widget_set_visible (WID ("touchpad_vbox"), touchpad_present);
 
297
 
 
298
        g_settings_bind (touchpad_settings, "disable-while-typing",
 
299
                         WID ("disable_w_typing_toggle"), "active",
 
300
                         G_SETTINGS_BIND_DEFAULT);
 
301
        g_settings_bind (touchpad_settings, "tap-to-click",
 
302
                         WID ("tap_to_click_toggle"), "active",
 
303
                         G_SETTINGS_BIND_DEFAULT);
 
304
        g_settings_bind (touchpad_settings, "horiz-scroll-enabled",
 
305
                         WID ("horiz_scroll_toggle"), "active",
 
306
                         G_SETTINGS_BIND_DEFAULT);
 
307
        g_settings_bind (touchpad_settings, "motion-acceleration",
 
308
                         gtk_range_get_adjustment (GTK_RANGE (WID ("touchpad_accel_scale"))), "value",
 
309
                         G_SETTINGS_BIND_DEFAULT);
 
310
        g_settings_bind (touchpad_settings, "motion-threshold",
 
311
                         gtk_range_get_adjustment (GTK_RANGE (WID ("touchpad_sensitivity_scale"))), "value",
 
312
                         G_SETTINGS_BIND_DEFAULT);
 
313
 
 
314
        if (touchpad_present) {
 
315
                synaptics_check_capabilities (dialog);
 
316
                setup_scrollmethod_radios (dialog);
 
317
        }
 
318
 
 
319
        g_signal_connect (WID ("scroll_disabled_radio"), "toggled",
 
320
                          G_CALLBACK (scrollmethod_changed_event), dialog);
 
321
        g_signal_connect (WID ("scroll_edge_radio"), "toggled",
 
322
                          G_CALLBACK (scrollmethod_changed_event), dialog);
 
323
        g_signal_connect (WID ("scroll_twofinger_radio"), "toggled",
 
324
                          G_CALLBACK (scrollmethod_changed_event), dialog);
 
325
}
 
326
 
 
327
/* Construct the dialog */
 
328
 
 
329
static void
 
330
create_dialog (GtkBuilder *dialog)
 
331
{
 
332
        GtkSizeGroup *size_group;
 
333
 
 
334
        size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
 
335
        gtk_size_group_add_widget (size_group, WID ("acceleration_label"));
 
336
        gtk_size_group_add_widget (size_group, WID ("sensitivity_label"));
 
337
        gtk_size_group_add_widget (size_group, WID ("threshold_label"));
 
338
        gtk_size_group_add_widget (size_group, WID ("timeout_label"));
 
339
 
 
340
        size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
 
341
        gtk_size_group_add_widget (size_group, WID ("acceleration_fast_label"));
 
342
        gtk_size_group_add_widget (size_group, WID ("sensitivity_high_label"));
 
343
        gtk_size_group_add_widget (size_group, WID ("threshold_large_label"));
 
344
        gtk_size_group_add_widget (size_group, WID ("timeout_long_label"));
 
345
 
 
346
        size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
 
347
        gtk_size_group_add_widget (size_group, WID ("acceleration_slow_label"));
 
348
        gtk_size_group_add_widget (size_group, WID ("sensitivity_low_label"));
 
349
        gtk_size_group_add_widget (size_group, WID ("threshold_small_label"));
 
350
        gtk_size_group_add_widget (size_group, WID ("timeout_short_label"));
 
351
}
 
352
 
 
353
/* Callback issued when a button is clicked on the dialog */
 
354
 
 
355
static void
 
356
dialog_response_cb (GtkDialog *dialog, gint response_id, gpointer user_data)
 
357
{
 
358
/*
 
359
        if (response_id == GTK_RESPONSE_HELP)
 
360
                capplet_help (GTK_WINDOW (dialog),
 
361
                              "goscustperiph-5");
 
362
        else
 
363
                gtk_main_quit ();
 
364
*/
 
365
}
 
366
 
 
367
static void
 
368
device_changed (GdkDeviceManager *device_manager,
 
369
                GdkDevice        *device,
 
370
                GtkBuilder       *dialog)
 
371
{
 
372
        gboolean present;
 
373
 
 
374
        present = touchpad_is_present ();
 
375
        gtk_widget_set_visible (WID ("touchpad_vbox"), present);
 
376
 
 
377
        if (present) {
 
378
                changing_scroll = TRUE;
 
379
                synaptics_check_capabilities (dialog);
 
380
                setup_scrollmethod_radios (dialog);
 
381
                changing_scroll = FALSE;
 
382
        }
 
383
}
 
384
 
 
385
GtkWidget *
 
386
gnome_mouse_properties_init (GtkBuilder *dialog)
 
387
{
 
388
        GtkWidget      *dialog_win;
 
389
 
 
390
        mouse_settings = g_settings_new ("org.gnome.settings-daemon.peripherals.mouse");
 
391
        touchpad_settings = g_settings_new ("org.gnome.settings-daemon.peripherals.touchpad");
 
392
 
 
393
        device_manager = gdk_display_get_device_manager (gdk_display_get_default ());
 
394
        device_added_id = g_signal_connect (device_manager, "device-added",
 
395
                                            G_CALLBACK (device_changed), dialog);
 
396
        device_removed_id = g_signal_connect (device_manager, "device-removed",
 
397
                                              G_CALLBACK (device_changed), dialog);
 
398
 
 
399
        create_dialog (dialog);
 
400
 
 
401
        if (dialog) {
 
402
                setup_dialog (dialog);
 
403
 
 
404
                dialog_win = WID ("mouse_properties_dialog");
 
405
                g_signal_connect (dialog_win, "response",
 
406
                                  G_CALLBACK (dialog_response_cb), NULL);
 
407
        } else {
 
408
                dialog_win = NULL;
 
409
        }
 
410
 
 
411
        return dialog_win;
 
412
}
 
413
 
 
414
void
 
415
gnome_mouse_properties_dispose (GtkWidget *widget)
 
416
{
 
417
        if (mouse_settings != NULL) {
 
418
                g_object_unref (mouse_settings);
 
419
                mouse_settings = NULL;
 
420
        }
 
421
        if (touchpad_settings != NULL) {
 
422
                g_object_unref (touchpad_settings);
 
423
                touchpad_settings = NULL;
 
424
        }
 
425
        if (device_manager != NULL) {
 
426
                g_signal_handler_disconnect (device_manager, device_added_id);
 
427
                device_added_id = 0;
 
428
                g_signal_handler_disconnect (device_manager, device_removed_id);
 
429
                device_removed_id = 0;
 
430
                device_manager = NULL;
 
431
        }
 
432
}