~ubuntu-branches/ubuntu/trusty/unity-control-center/trusty

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Robert Ancell
  • Date: 2014-01-08 16:29:18 UTC
  • Revision ID: package-import@ubuntu.com-20140108162918-g29dd08tr913y2qh
Tags: upstream-14.04.0
ImportĀ upstreamĀ versionĀ 14.04.0

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) 2012 Red Hat, Inc.
 
4
 *
 
5
 * Written by: Ondrej Holy <oholy@redhat.com>,
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or modify
 
8
 * it under the terms of the GNU General Public License as published by
 
9
 * the Free Software Foundation; either version 2, or (at your option)
 
10
 * any later version.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 * GNU General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with this program; if not, write to the Free Software
 
19
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
20
 * 02111-1307, USA.
 
21
 */
 
22
 
 
23
#include <config.h>
 
24
 
 
25
#include <glib/gi18n.h>
 
26
#include <string.h>
 
27
#include <gdk/gdk.h>
 
28
#include <gdk/gdkx.h>
 
29
#include <gnome-settings-daemon/gsd-enums.h>
 
30
#include <math.h>
 
31
 
 
32
#include "gnome-mouse-test.h"
 
33
 
 
34
#include <sys/types.h>
 
35
#include <sys/stat.h>
 
36
 
 
37
#define WID(x) (GtkWidget*) gtk_builder_get_object (dialog, x)
 
38
 
 
39
/* Click test button sizes. */
 
40
#define SHADOW_SIZE (10.0 / 180 * size)
 
41
#define SHADOW_SHIFT_Y (-1.0 / 180 * size)
 
42
#define SHADOW_OPACITY (0.15 / 180 * size)
 
43
#define OUTER_CIRCLE_SIZE (22.0 / 180 * size)
 
44
#define ANNULUS_SIZE (6.0 / 180 * size)
 
45
#define INNER_CIRCLE_SIZE (52.0 / 180 * size)
 
46
 
 
47
static void setup_information_label (GtkWidget *widget);
 
48
static void setup_scroll_image      (GtkWidget *widget);
 
49
 
 
50
enum
 
51
{
 
52
        DOUBLE_CLICK_TEST_OFF,
 
53
        DOUBLE_CLICK_TEST_MAYBE,
 
54
        DOUBLE_CLICK_TEST_ON,
 
55
        DOUBLE_CLICK_TEST_STILL_ON,
 
56
        DOUBLE_CLICK_TEST_ALMOST_THERE,
 
57
        DOUBLE_CLICK_TEST_GEGL
 
58
};
 
59
 
 
60
/* State in testing the double-click speed. Global for a great deal of
 
61
 * convenience
 
62
 */
 
63
static gint double_click_state = DOUBLE_CLICK_TEST_OFF;
 
64
static gint button_state = 0;
 
65
 
 
66
static GSettings *mouse_settings = NULL;
 
67
 
 
68
static gint information_label_timeout_id = 0;
 
69
static gint button_drawing_area_timeout_id = 0;
 
70
static gint scroll_image_timeout_id = 0;
 
71
 
 
72
/* Double Click handling */
 
73
 
 
74
struct test_data_t
 
75
{
 
76
        gint *timeout_id;
 
77
        GtkWidget *widget;
 
78
};
 
79
 
 
80
/* Timeout for the double click test */
 
81
 
 
82
static gboolean
 
83
test_maybe_timeout (struct test_data_t *data)
 
84
{
 
85
        double_click_state = DOUBLE_CLICK_TEST_OFF;
 
86
 
 
87
        gtk_widget_queue_draw (data->widget);
 
88
 
 
89
        *data->timeout_id = 0;
 
90
 
 
91
        return FALSE;
 
92
}
 
93
 
 
94
/* Timeout for the information label */
 
95
 
 
96
static gboolean
 
97
information_label_timeout (struct test_data_t *data)
 
98
{
 
99
        setup_information_label (data->widget);
 
100
 
 
101
        *data->timeout_id = 0;
 
102
 
 
103
        return FALSE;
 
104
}
 
105
 
 
106
/* Timeout for the scroll image */
 
107
 
 
108
static gboolean
 
109
scroll_image_timeout (struct test_data_t *data)
 
110
{
 
111
        setup_scroll_image (data->widget);
 
112
 
 
113
        *data->timeout_id = 0;
 
114
 
 
115
        return FALSE;
 
116
}
 
117
 
 
118
/* Set information label according global state variables. */
 
119
 
 
120
static void
 
121
setup_information_label (GtkWidget *widget)
 
122
{
 
123
        static struct test_data_t data;
 
124
        gchar *message = NULL;
 
125
        gchar *label_text = NULL;
 
126
        gboolean double_click;
 
127
 
 
128
        if (information_label_timeout_id != 0) {
 
129
                g_source_remove (information_label_timeout_id);
 
130
                information_label_timeout_id = 0;
 
131
        }
 
132
 
 
133
        if (double_click_state == DOUBLE_CLICK_TEST_OFF) {
 
134
                gtk_label_set_label (GTK_LABEL (widget), _("Try clicking, double clicking, scrolling"));
 
135
                return;
 
136
        }
 
137
 
 
138
        if (double_click_state == DOUBLE_CLICK_TEST_GEGL) {
 
139
                message = _("Five clicks, GEGL time!"), "</b>";
 
140
        } else {
 
141
                double_click = (double_click_state >= DOUBLE_CLICK_TEST_ON);
 
142
                switch (button_state) {
 
143
                case 1:
 
144
                        message = (double_click) ? _("Double click, primary button") : _("Single click, primary button");
 
145
                        break;
 
146
                case 2:
 
147
                        message = (double_click) ? _("Double click, middle button") : _("Single click, middle button");
 
148
                        break;
 
149
                case 3:
 
150
                        message = (double_click) ? _("Double click, secondary button") : _("Single click, secondary button");
 
151
                        break;
 
152
                }
 
153
        }
 
154
 
 
155
        label_text = g_strconcat ("<b>", message, "</b>", NULL);
 
156
        gtk_label_set_markup (GTK_LABEL (widget), label_text);
 
157
        g_free (label_text);
 
158
 
 
159
        data.widget = widget;
 
160
        data.timeout_id = &information_label_timeout_id;
 
161
        information_label_timeout_id = g_timeout_add (2500,
 
162
                                                      (GSourceFunc) information_label_timeout,
 
163
                                                      &data);
 
164
}
 
165
 
 
166
/* Update scroll image according to the global state variables */
 
167
 
 
168
static void
 
169
setup_scroll_image (GtkWidget *widget)
 
170
{
 
171
        static struct test_data_t data;
 
172
        char *filename;
 
173
 
 
174
        if (scroll_image_timeout_id != 0) {
 
175
                g_source_remove (scroll_image_timeout_id);
 
176
                scroll_image_timeout_id = 0;
 
177
        }
 
178
 
 
179
        if (double_click_state == DOUBLE_CLICK_TEST_GEGL)
 
180
                filename = GNOMECC_UI_DIR "/scroll-test-gegl.svg";
 
181
        else
 
182
                filename = GNOMECC_UI_DIR "/scroll-test.svg";
 
183
        gtk_image_set_from_file (GTK_IMAGE (widget), filename);
 
184
 
 
185
        if (double_click_state != DOUBLE_CLICK_TEST_GEGL)
 
186
                return;
 
187
 
 
188
        data.widget = widget;
 
189
        data.timeout_id = &scroll_image_timeout_id;
 
190
        scroll_image_timeout_id = g_timeout_add (5000,
 
191
                                                 (GSourceFunc) scroll_image_timeout,
 
192
                                                 &data);
 
193
}
 
194
 
 
195
 
 
196
/* Callback issued when the user clicks the double click testing area. */
 
197
 
 
198
static gboolean
 
199
button_drawing_area_button_press_event (GtkWidget      *widget,
 
200
                                        GdkEventButton *event,
 
201
                                        GtkBuilder     *dialog)
 
202
{
 
203
        gint                       double_click_time;
 
204
        static struct test_data_t  data;
 
205
        static guint32             double_click_timestamp = 0;
 
206
 
 
207
        if (event->type != GDK_BUTTON_PRESS || event->button > 3)
 
208
                return FALSE;
 
209
 
 
210
        double_click_time = g_settings_get_int (mouse_settings, "double-click");
 
211
 
 
212
        if (button_drawing_area_timeout_id != 0) {
 
213
                g_source_remove  (button_drawing_area_timeout_id);
 
214
                button_drawing_area_timeout_id = 0;
 
215
        }
 
216
 
 
217
        /* Ignore fake double click using different buttons. */
 
218
        if (double_click_state != DOUBLE_CLICK_TEST_OFF && button_state != event->button)
 
219
                double_click_state = DOUBLE_CLICK_TEST_OFF;
 
220
 
 
221
        switch (double_click_state) {
 
222
        case DOUBLE_CLICK_TEST_OFF:
 
223
                double_click_state = DOUBLE_CLICK_TEST_MAYBE;
 
224
                data.widget = widget;
 
225
                data.timeout_id = &button_drawing_area_timeout_id;
 
226
                button_drawing_area_timeout_id = g_timeout_add (double_click_time, (GSourceFunc) test_maybe_timeout, &data);
 
227
                break;
 
228
        case DOUBLE_CLICK_TEST_MAYBE:
 
229
        case DOUBLE_CLICK_TEST_ON:
 
230
        case DOUBLE_CLICK_TEST_STILL_ON:
 
231
        case DOUBLE_CLICK_TEST_ALMOST_THERE:
 
232
                if (event->time - double_click_timestamp < double_click_time) {
 
233
                        double_click_state++;
 
234
                        data.widget = widget;
 
235
                        data.timeout_id = &button_drawing_area_timeout_id;
 
236
                        button_drawing_area_timeout_id = g_timeout_add (2500, (GSourceFunc) test_maybe_timeout, &data);
 
237
                } else {
 
238
                        test_maybe_timeout (&data);
 
239
                }
 
240
                break;
 
241
        case DOUBLE_CLICK_TEST_GEGL:
 
242
                double_click_state = DOUBLE_CLICK_TEST_OFF;
 
243
                break;
 
244
        }
 
245
 
 
246
        double_click_timestamp = event->time;
 
247
 
 
248
        gtk_widget_queue_draw (widget);
 
249
 
 
250
        button_state = event->button;
 
251
        setup_information_label (WID ("information_label"));
 
252
        setup_scroll_image (WID ("image"));
 
253
 
 
254
        return TRUE;
 
255
}
 
256
 
 
257
static gboolean
 
258
button_drawing_area_draw_event (GtkWidget  *widget,
 
259
                                cairo_t    *cr,
 
260
                                GtkBuilder *dialog)
 
261
{
 
262
        gdouble center_x, center_y, size;
 
263
        GdkRGBA inner_color, outer_color;
 
264
        cairo_pattern_t *pattern;
 
265
 
 
266
        size = MAX (MIN (gtk_widget_get_allocated_width (widget), gtk_widget_get_allocated_height (widget)), 1);
 
267
        center_x = gtk_widget_get_allocated_width (widget) / 2.0;
 
268
        center_y = gtk_widget_get_allocated_height (widget) / 2.0;
 
269
 
 
270
        switch (double_click_state) {
 
271
        case DOUBLE_CLICK_TEST_ON:
 
272
        case DOUBLE_CLICK_TEST_STILL_ON:
 
273
        case DOUBLE_CLICK_TEST_ALMOST_THERE:
 
274
        case DOUBLE_CLICK_TEST_GEGL:
 
275
                gdk_rgba_parse (&outer_color, "#729fcf");
 
276
                gdk_rgba_parse (&inner_color, "#729fcf");
 
277
                break;
 
278
        case DOUBLE_CLICK_TEST_MAYBE:
 
279
                gdk_rgba_parse (&outer_color, "#729fcf");
 
280
                gdk_rgba_parse (&inner_color, "#ffffff");
 
281
                break;
 
282
        case DOUBLE_CLICK_TEST_OFF:
 
283
                gdk_rgba_parse (&outer_color, "#ffffff");
 
284
                gdk_rgba_parse (&inner_color, "#ffffff");
 
285
                break;
 
286
        }
 
287
 
 
288
        /* Draw shadow. */
 
289
        cairo_rectangle (cr, center_x - size / 2,  center_y - size / 2, size, size);
 
290
        pattern = cairo_pattern_create_radial (center_x, center_y, 0, center_x, center_y, size);
 
291
        cairo_pattern_add_color_stop_rgba (pattern, 0.5 - SHADOW_SIZE / size, 0, 0, 0, SHADOW_OPACITY);
 
292
        cairo_pattern_add_color_stop_rgba (pattern, 0.5, 0, 0, 0, 0);
 
293
        cairo_set_source (cr, pattern);
 
294
        cairo_fill (cr);
 
295
 
 
296
        /* Draw outer circle. */
 
297
        cairo_set_line_width (cr, OUTER_CIRCLE_SIZE);
 
298
        cairo_arc (cr, center_x, center_y + SHADOW_SHIFT_Y,
 
299
                   INNER_CIRCLE_SIZE + ANNULUS_SIZE + OUTER_CIRCLE_SIZE / 2,
 
300
                   0, 2 * G_PI);
 
301
        gdk_cairo_set_source_rgba (cr, &outer_color);
 
302
        cairo_stroke (cr);
 
303
 
 
304
        /* Draw inner circle. */
 
305
        cairo_set_line_width (cr, 0);
 
306
        cairo_arc (cr, center_x, center_y + SHADOW_SHIFT_Y,
 
307
                   INNER_CIRCLE_SIZE,
 
308
                   0, 2 * G_PI);
 
309
        gdk_cairo_set_source_rgba (cr, &inner_color);
 
310
        cairo_fill (cr);
 
311
 
 
312
        return FALSE;
 
313
}
 
314
 
 
315
/* Set up the property editors in the dialog. */
 
316
static void
 
317
setup_dialog (GtkBuilder *dialog)
 
318
{
 
319
        GtkAdjustment *adjustment;
 
320
        GdkRGBA color;
 
321
 
 
322
        g_signal_connect (WID ("button_drawing_area"), "button_press_event",
 
323
                          G_CALLBACK (button_drawing_area_button_press_event),
 
324
                          dialog);
 
325
        g_signal_connect (WID ("button_drawing_area"), "draw",
 
326
                          G_CALLBACK (button_drawing_area_draw_event),
 
327
                          dialog);
 
328
 
 
329
        adjustment = GTK_ADJUSTMENT (WID ("scrolled_window_adjustment"));
 
330
        gtk_adjustment_set_value (adjustment,
 
331
                                  gtk_adjustment_get_upper (adjustment));
 
332
 
 
333
        gdk_rgba_parse (&color, "#565854");
 
334
        gtk_widget_override_background_color (WID ("viewport"), GTK_STATE_FLAG_NORMAL, &color);
 
335
        gtk_widget_override_background_color (WID ("button_drawing_area"), GTK_STATE_FLAG_NORMAL, &color);
 
336
}
 
337
 
 
338
GtkWidget *
 
339
gnome_mouse_test_init (GtkBuilder *dialog)
 
340
{
 
341
        mouse_settings = g_settings_new ("org.gnome.settings-daemon.peripherals.mouse");
 
342
 
 
343
        setup_dialog (dialog);
 
344
 
 
345
        return WID ("mouse_test_window");
 
346
}
 
347
 
 
348
void
 
349
gnome_mouse_test_dispose (GtkWidget *widget)
 
350
{
 
351
        if (mouse_settings != NULL) {
 
352
                g_object_unref (mouse_settings);
 
353
                mouse_settings = NULL;
 
354
        }
 
355
 
 
356
        if (information_label_timeout_id != 0) {
 
357
                g_source_remove (information_label_timeout_id);
 
358
                information_label_timeout_id = 0;
 
359
        }
 
360
 
 
361
        if (scroll_image_timeout_id != 0) {
 
362
                g_source_remove (scroll_image_timeout_id);
 
363
                scroll_image_timeout_id = 0;
 
364
        }
 
365
 
 
366
        if (button_drawing_area_timeout_id != 0) {
 
367
                g_source_remove  (button_drawing_area_timeout_id);
 
368
                button_drawing_area_timeout_id = 0;
 
369
        }
 
370
}
 
371