~ubuntu-branches/ubuntu/trusty/xfce4-settings/trusty-proposed

« back to all changes in this revision

Viewing changes to .pc/xubuntu_improved-mouse-touchpad-dialog.patch/dialogs/mouse-settings/main.c

  • Committer: Package Import Robot
  • Author(s): Lionel Le Folgoc
  • Date: 2012-01-23 21:10:18 UTC
  • Revision ID: package-import@ubuntu.com-20120123211018-g3wszngv4plljt2p
Tags: 4.8.3-1ubuntu1
* debian/control: add xfce4-dev-tools, autoconf, automake and libtool
  to build-depends, needed for xdt-autogen, and exo-utils, needed for
  exo-csource.
* debian/rules: run xdt-autogen before configure, and clean up autogenerated
  files after build.
* debian/patches:
  - xubuntu_improved-mouse-touchpad-dialog.patch: added, backport the new
    pointing device dialog from master. lp: #818131
  - xubuntu_refreshed-translations.patch: added, new translations taken
    from master.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id$ */
 
2
/*
 
3
 *  Copyright (c) 2008 Nick Schermer <nick@xfce.org>
 
4
 *                     Jannis Pohlmann <jannis@xfce.org>
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; either version 2 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  This program is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *  GNU Library General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU General Public License
 
17
 *  along with this program; if not, write to the Free Software
 
18
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
19
 */
 
20
 
 
21
#ifdef HAVE_CONFIG_H
 
22
#include <config.h>
 
23
#endif
 
24
 
 
25
#ifdef HAVE_STDLIB_H
 
26
#include <stdlib.h>
 
27
#endif
 
28
#ifdef HAVE_STRING_H
 
29
#include <string.h>
 
30
#endif
 
31
#ifdef HAVE_MATH_H
 
32
#include <math.h>
 
33
#endif
 
34
 
 
35
#include <X11/Xlib.h>
 
36
#include <X11/extensions/XI.h>
 
37
#include <X11/extensions/XInput.h>
 
38
#include <X11/extensions/XIproto.h>
 
39
#ifdef HAVE_XCURSOR
 
40
#include <X11/Xcursor/Xcursor.h>
 
41
#endif /* !HAVE_XCURSOR */
 
42
 
 
43
#include <gtk/gtk.h>
 
44
#include <gdk/gdkx.h>
 
45
 
 
46
#include <xfconf/xfconf.h>
 
47
#include <libxfce4util/libxfce4util.h>
 
48
#include <libxfce4ui/libxfce4ui.h>
 
49
 
 
50
#include "mouse-dialog_ui.h"
 
51
 
 
52
/* test if the required version of inputproto (1.4.2) is available */
 
53
#if XI_Add_DevicePresenceNotify_Major >= 1 && defined (DeviceRemoved)
 
54
#define HAS_DEVICE_HOTPLUGGING
 
55
#else
 
56
#undef HAS_DEVICE_HOTPLUGGING
 
57
#endif
 
58
#ifndef IsXExtensionPointer
 
59
#define IsXExtensionPointer 4
 
60
#endif
 
61
 
 
62
/* Xi 1.4 is required */
 
63
#define MIN_XI_VERS_MAJOR 1
 
64
#define MIN_XI_VERS_MINOR 4
 
65
 
 
66
/* settings */
 
67
#ifdef HAVE_XCURSOR
 
68
#define PREVIEW_ROWS    (3)
 
69
#define PREVIEW_COLUMNS (6)
 
70
#define PREVIEW_SIZE    (24)
 
71
#define PREVIEW_SPACING (2)
 
72
#endif /* !HAVE_XCURSOR */
 
73
 
 
74
 
 
75
/* global setting channels */
 
76
XfconfChannel *xsettings_channel;
 
77
XfconfChannel *pointers_channel;
 
78
 
 
79
/* lock counter to avoid signals during updates */
 
80
static gint locked = 0;
 
81
 
 
82
/* the display for this window */
 
83
static GdkDisplay *display;
 
84
 
 
85
/* device update id */
 
86
static guint timeout_id = 0;
 
87
 
 
88
#ifdef HAS_DEVICE_HOTPLUGGING
 
89
/* event id for device add/remove */
 
90
static gint device_presence_event_type = 0;
 
91
#endif
 
92
 
 
93
/* option entries */
 
94
static GdkNativeWindow opt_socket_id = 0;
 
95
static gchar *opt_device_name = NULL;
 
96
static gboolean opt_version = FALSE;
 
97
static GOptionEntry option_entries[] =
 
98
{
 
99
    { "device", 'd', 0, G_OPTION_ARG_STRING, &opt_device_name, N_("Active device in the dialog"), N_("DEVICE NAME") },
 
100
    { "socket-id", 's', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_INT, &opt_socket_id, N_("Settings manager socket"), N_("SOCKET ID") },
 
101
    { "version", 'v', 0, G_OPTION_ARG_NONE, &opt_version, N_("Version information"), NULL },
 
102
    { NULL }
 
103
};
 
104
 
 
105
#ifdef HAVE_XCURSOR
 
106
/* icon names for the preview widget */
 
107
static const gchar *preview_names[] = {
 
108
    "left_ptr",            "left_ptr_watch",    "watch",             "hand2",
 
109
    "question_arrow",      "sb_h_double_arrow", "sb_v_double_arrow", "bottom_left_corner",
 
110
    "bottom_right_corner", "fleur",             "pirate",            "cross",
 
111
    "X_cursor",            "right_ptr",         "right_side",        "right_tee",
 
112
    "sb_right_arrow",      "sb_right_tee",      "base_arrow_down",   "base_arrow_up",
 
113
    "bottom_side",         "bottom_tee",        "center_ptr",        "circle",
 
114
    "dot",                 "dot_box_mask",      "dot_box_mask",      "double_arrow",
 
115
    "draped_box",          "left_side",         "left_tee",          "ll_angle",
 
116
    "top_side",            "top_tee"
 
117
};
 
118
 
 
119
enum
 
120
{
 
121
    COLUMN_THEME_PIXBUF,
 
122
    COLUMN_THEME_PATH,
 
123
    COLUMN_THEME_NAME,
 
124
    COLUMN_THEME_DISPLAY_NAME,
 
125
    COLUMN_THEME_COMMENT,
 
126
    N_THEME_COLUMNS
 
127
};
 
128
#endif /* !HAVE_XCURSOR */
 
129
 
 
130
enum
 
131
{
 
132
    COLUMN_DEVICE_ICON,
 
133
    COLUMN_DEVICE_NAME,
 
134
    COLUMN_DEVICE_DISPLAY_NAME,
 
135
    COLUMN_DEVICE_XID,
 
136
    COLUMN_DEVICE_NBUTTONS,
 
137
    N_DEVICE_COLUMNS
 
138
};
 
139
 
 
140
 
 
141
#ifdef HAVE_XCURSOR
 
142
static GdkPixbuf *
 
143
mouse_settings_themes_pixbuf_from_filename (const gchar *filename,
 
144
                                            guint        size)
 
145
{
 
146
    XcursorImage *image;
 
147
    GdkPixbuf    *scaled, *pixbuf = NULL;
 
148
    gsize         bsize;
 
149
    guchar       *buffer, *p, tmp;
 
150
    gdouble       wratio, hratio;
 
151
    gint          dest_width, dest_height;
 
152
 
 
153
    /* load the image */
 
154
    image = XcursorFilenameLoadImage (filename, size);
 
155
    if (G_LIKELY (image))
 
156
    {
 
157
        /* buffer size */
 
158
        bsize = image->width * image->height * 4;
 
159
 
 
160
        /* allocate buffer */
 
161
        buffer = g_malloc (bsize);
 
162
 
 
163
        /* copy pixel data to buffer */
 
164
        memcpy (buffer, image->pixels, bsize);
 
165
 
 
166
        /* swap bits */
 
167
        for (p = buffer; p < buffer + bsize; p += 4)
 
168
        {
 
169
            tmp = p[0];
 
170
            p[0] = p[2];
 
171
            p[2] = tmp;
 
172
        }
 
173
 
 
174
        /* create pixbuf */
 
175
        pixbuf = gdk_pixbuf_new_from_data (buffer, GDK_COLORSPACE_RGB, TRUE,
 
176
                                           8, image->width, image->height,
 
177
                                           4 * image->width,
 
178
                                           (GdkPixbufDestroyNotify) g_free, NULL);
 
179
 
 
180
        /* don't leak when creating the pixbuf failed */
 
181
        if (G_UNLIKELY (pixbuf == NULL))
 
182
            g_free (buffer);
 
183
 
 
184
        /* scale pixbuf if needed */
 
185
        if (pixbuf && (image->height > size || image->width > size))
 
186
        {
 
187
            /* calculate the ratio */
 
188
            wratio = (gdouble) image->width / (gdouble) size;
 
189
            hratio = (gdouble) image->height / (gdouble) size;
 
190
 
 
191
            /* init */
 
192
            dest_width = dest_height = size;
 
193
 
 
194
            /* set dest size */
 
195
            if (hratio > wratio)
 
196
                dest_width  = rint (image->width / hratio);
 
197
            else
 
198
                dest_height = rint (image->height / wratio);
 
199
 
 
200
            /* scale pixbuf */
 
201
            scaled = gdk_pixbuf_scale_simple (pixbuf, MAX (dest_width, 1), MAX (dest_height, 1), GDK_INTERP_BILINEAR);
 
202
 
 
203
            /* release and set scaled pixbuf */
 
204
            g_object_unref (G_OBJECT (pixbuf));
 
205
            pixbuf = scaled;
 
206
        }
 
207
 
 
208
        /* cleanup */
 
209
        XcursorImageDestroy (image);
 
210
    }
 
211
 
 
212
    return pixbuf;
 
213
}
 
214
 
 
215
 
 
216
 
 
217
static GdkPixbuf *
 
218
mouse_settings_themes_preview_icon (const gchar *path)
 
219
{
 
220
    GdkPixbuf *pixbuf = NULL;
 
221
    gchar     *filename;
 
222
 
 
223
    /* we only try the normal cursor, it is (most likely) always there */
 
224
    filename = g_build_filename (path, "left_ptr", NULL);
 
225
 
 
226
    /* try to load the pixbuf */
 
227
    pixbuf = mouse_settings_themes_pixbuf_from_filename (filename, PREVIEW_SIZE);
 
228
 
 
229
    /* cleanup */
 
230
    g_free (filename);
 
231
 
 
232
    return pixbuf;
 
233
}
 
234
 
 
235
 
 
236
 
 
237
static void
 
238
mouse_settings_themes_preview_image (const gchar *path,
 
239
                                     GtkImage    *image)
 
240
{
 
241
    GdkPixbuf *pixbuf;
 
242
    GdkPixbuf *preview;
 
243
    guint      i, position;
 
244
    gchar     *filename;
 
245
    gint       dest_x, dest_y;
 
246
 
 
247
    /* create an empty preview image */
 
248
    preview = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
 
249
                              (PREVIEW_SIZE + PREVIEW_SPACING) * PREVIEW_COLUMNS - PREVIEW_SPACING,
 
250
                              (PREVIEW_SIZE + PREVIEW_SPACING) * PREVIEW_ROWS - PREVIEW_SPACING);
 
251
 
 
252
    if (G_LIKELY (preview))
 
253
    {
 
254
        /* make the pixbuf transparent */
 
255
        gdk_pixbuf_fill (preview, 0x00000000);
 
256
 
 
257
        for (i = 0, position = 0; i < G_N_ELEMENTS (preview_names); i++)
 
258
        {
 
259
            /* create cursor filename and try to load the pixbuf */
 
260
            filename = g_build_filename (path, preview_names[i], NULL);
 
261
            pixbuf = mouse_settings_themes_pixbuf_from_filename (filename, PREVIEW_SIZE);
 
262
            g_free (filename);
 
263
 
 
264
            if (G_LIKELY (pixbuf))
 
265
            {
 
266
                /* calculate the icon position */
 
267
                dest_x = (position % PREVIEW_COLUMNS) * (PREVIEW_SIZE + PREVIEW_SPACING);
 
268
                dest_y = (position / PREVIEW_COLUMNS) * (PREVIEW_SIZE + PREVIEW_SPACING);
 
269
 
 
270
                /* render it in the preview */
 
271
                gdk_pixbuf_scale (pixbuf, preview, dest_x, dest_y,
 
272
                                  gdk_pixbuf_get_width (pixbuf),
 
273
                                  gdk_pixbuf_get_height (pixbuf),
 
274
                                  dest_x, dest_y,
 
275
                                  1.00, 1.00, GDK_INTERP_BILINEAR);
 
276
 
 
277
 
 
278
                /* release the pixbuf */
 
279
                g_object_unref (G_OBJECT (pixbuf));
 
280
 
 
281
                /* break if we've added enough icons */
 
282
                if (++position >= PREVIEW_ROWS * PREVIEW_COLUMNS)
 
283
                    break;
 
284
            }
 
285
        }
 
286
 
 
287
        /* set the image */
 
288
        gtk_image_set_from_pixbuf (GTK_IMAGE (image), preview);
 
289
 
 
290
        /* release the pixbuf */
 
291
        g_object_unref (G_OBJECT (preview));
 
292
    }
 
293
    else
 
294
    {
 
295
        /* clear the image */
 
296
        gtk_image_clear (GTK_IMAGE (image));
 
297
    }
 
298
}
 
299
 
 
300
 
 
301
 
 
302
static void
 
303
mouse_settings_themes_selection_changed (GtkTreeSelection *selection,
 
304
                                         GtkBuilder       *builder)
 
305
{
 
306
    GtkTreeModel *model;
 
307
    GtkTreeIter   iter;
 
308
    gboolean      has_selection;
 
309
    gchar        *path, *name;
 
310
    GObject      *image;
 
311
 
 
312
    has_selection = gtk_tree_selection_get_selected (selection, &model, &iter);
 
313
    if (G_LIKELY (has_selection))
 
314
    {
 
315
        /* get theme information from model */
 
316
        gtk_tree_model_get (model, &iter, COLUMN_THEME_PATH, &path,
 
317
                            COLUMN_THEME_NAME, &name, -1);
 
318
 
 
319
        /* update the preview widget */
 
320
        image = gtk_builder_get_object (builder, "mouse-theme-preview");
 
321
        mouse_settings_themes_preview_image (path, GTK_IMAGE (image));
 
322
 
 
323
        /* write configuration (not during a lock) */
 
324
        if (locked == 0)
 
325
            xfconf_channel_set_string (xsettings_channel, "/Gtk/CursorThemeName", name);
 
326
 
 
327
        /* cleanup */
 
328
        g_free (path);
 
329
        g_free (name);
 
330
    }
 
331
}
 
332
 
 
333
 
 
334
 
 
335
static gint
 
336
mouse_settings_themes_sort_func (GtkTreeModel *model,
 
337
                                 GtkTreeIter  *a,
 
338
                                 GtkTreeIter  *b,
 
339
                                 gpointer      user_data)
 
340
{
 
341
    gchar *name_a, *name_b;
 
342
    gint   retval;
 
343
 
 
344
    /* get the names from the model */
 
345
    gtk_tree_model_get (model, a, COLUMN_THEME_DISPLAY_NAME, &name_a, -1);
 
346
    gtk_tree_model_get (model, b, COLUMN_THEME_DISPLAY_NAME, &name_b, -1);
 
347
 
 
348
    /* make sure the names are not null */
 
349
    if (G_UNLIKELY (name_a == NULL))
 
350
        name_a = g_strdup ("");
 
351
    if (G_UNLIKELY (name_b == NULL))
 
352
        name_b = g_strdup ("");
 
353
 
 
354
    /* sort the names but keep Default on top */
 
355
    if (g_utf8_collate (name_a, _("Default")) == 0)
 
356
        retval = -1;
 
357
    else if (g_utf8_collate (name_b, _("Default")) == 0)
 
358
        retval = 1;
 
359
    else
 
360
        retval = g_utf8_collate (name_a, name_b);
 
361
 
 
362
    /* cleanup */
 
363
    g_free (name_a);
 
364
    g_free (name_b);
 
365
 
 
366
    return retval;
 
367
}
 
368
 
 
369
 
 
370
 
 
371
static void
 
372
mouse_settings_themes_populate_store (GtkBuilder *builder)
 
373
{
 
374
    const gchar        *path;
 
375
    gchar             **basedirs;
 
376
    gint                i;
 
377
    gchar              *homedir;
 
378
    GDir               *dir;
 
379
    const gchar        *theme;
 
380
    gchar              *filename;
 
381
    gchar              *index_file;
 
382
    XfceRc             *rc;
 
383
    const gchar        *name;
 
384
    const gchar        *comment;
 
385
    GtkTreeIter         iter;
 
386
    gint                position = 0;
 
387
    GdkPixbuf          *pixbuf;
 
388
    gchar              *active_theme;
 
389
    GtkTreePath        *active_path = NULL;
 
390
    GtkListStore       *store;
 
391
    GtkCellRenderer    *renderer;
 
392
    GtkTreeViewColumn  *column;
 
393
    GObject            *treeview;
 
394
    GtkTreeSelection   *selection;
 
395
    gchar              *comment_escaped;
 
396
 
 
397
    /* get the cursor paths */
 
398
#if XCURSOR_LIB_MAJOR == 1 && XCURSOR_LIB_MINOR < 1
 
399
    path = "~/.icons:/usr/share/icons:/usr/share/pixmaps:/usr/X11R6/lib/X11/icons";
 
400
#else
 
401
    path = XcursorLibraryPath ();
 
402
#endif
 
403
 
 
404
    /* split the paths */
 
405
    basedirs = g_strsplit (path, ":", -1);
 
406
 
 
407
    /* get the active theme */
 
408
    active_theme = xfconf_channel_get_string (xsettings_channel, "/Gtk/CursorThemeName", "default");
 
409
 
 
410
    /* create the store */
 
411
    store = gtk_list_store_new (N_THEME_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING,
 
412
                                G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
 
413
 
 
414
    /* insert default */
 
415
    gtk_list_store_insert_with_values (store, &iter, position++,
 
416
                                       COLUMN_THEME_NAME, "default",
 
417
                                       COLUMN_THEME_DISPLAY_NAME, _("Default"), -1);
 
418
 
 
419
    /* store the default path, so we always select a theme */
 
420
    active_path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
 
421
 
 
422
    if (G_LIKELY (basedirs))
 
423
    {
 
424
        /* walk the base directories */
 
425
        for (i = 0; basedirs[i] != NULL; i++)
 
426
        {
 
427
            /* init */
 
428
            homedir = NULL;
 
429
 
 
430
            /* parse the homedir if needed */
 
431
            if (strstr (basedirs[i], "~/") != NULL)
 
432
                path = homedir = g_strconcat (g_get_home_dir (), basedirs[i] + 1, NULL);
 
433
            else
 
434
                path = basedirs[i];
 
435
 
 
436
            /* open directory */
 
437
            dir = g_dir_open (path, 0, NULL);
 
438
            if (G_LIKELY (dir))
 
439
            {
 
440
                for (;;)
 
441
                {
 
442
                    /* get the directory name */
 
443
                    theme = g_dir_read_name (dir);
 
444
                    if (G_UNLIKELY (theme == NULL))
 
445
                        break;
 
446
 
 
447
                    /* build the full cursor path */
 
448
                    filename = g_build_filename (path, theme, "cursors", NULL);
 
449
 
 
450
                    /* check if it looks like a cursor theme */
 
451
                    if (g_file_test (filename, G_FILE_TEST_IS_DIR))
 
452
                    {
 
453
                        /* try to load a pixbuf */
 
454
                        pixbuf = mouse_settings_themes_preview_icon (filename);
 
455
 
 
456
                        /* insert in the store */
 
457
                        gtk_list_store_insert_with_values (store, &iter, position++,
 
458
                                                           COLUMN_THEME_PIXBUF, pixbuf,
 
459
                                                           COLUMN_THEME_NAME, theme,
 
460
                                                           COLUMN_THEME_DISPLAY_NAME, theme,
 
461
                                                           COLUMN_THEME_PATH, filename, -1);
 
462
 
 
463
                        /* check if this is the active theme, set the path */
 
464
                        if (strcmp (active_theme, theme) == 0)
 
465
                        {
 
466
                            gtk_tree_path_free (active_path);
 
467
                            active_path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
 
468
                        }
 
469
 
 
470
                        /* release pixbuf */
 
471
                        if (G_LIKELY (pixbuf))
 
472
                            g_object_unref (G_OBJECT (pixbuf));
 
473
 
 
474
                        /* check for a index.theme file for additional information */
 
475
                        index_file = g_build_filename (path, theme, "index.theme", NULL);
 
476
                        if (g_file_test (index_file, G_FILE_TEST_IS_REGULAR))
 
477
                        {
 
478
                            /* open theme desktop file */
 
479
                            rc = xfce_rc_simple_open (index_file, TRUE);
 
480
                            if (G_LIKELY (rc))
 
481
                            {
 
482
                                /* check for the theme group */
 
483
                                if (xfce_rc_has_group (rc, "Icon Theme"))
 
484
                                {
 
485
                                    /* set group */
 
486
                                    xfce_rc_set_group (rc, "Icon Theme");
 
487
 
 
488
                                    /* read values */
 
489
                                    name = xfce_rc_read_entry (rc, "Name", theme);
 
490
                                    comment = xfce_rc_read_entry (rc, "Comment", NULL);
 
491
 
 
492
                                    /* escape the comment */
 
493
                                    comment_escaped = comment ? g_markup_escape_text (comment, -1) : NULL;
 
494
 
 
495
                                    /* update store */
 
496
                                    gtk_list_store_set (store, &iter,
 
497
                                                        COLUMN_THEME_DISPLAY_NAME, name,
 
498
                                                        COLUMN_THEME_COMMENT, comment_escaped, -1);
 
499
 
 
500
                                    /* cleanup */
 
501
                                    g_free (comment_escaped);
 
502
                                }
 
503
 
 
504
                                /* close rc file */
 
505
                                xfce_rc_close (rc);
 
506
                            }
 
507
                        }
 
508
 
 
509
                        /* cleanup */
 
510
                        g_free (index_file);
 
511
                    }
 
512
 
 
513
                    /* cleanup */
 
514
                    g_free (filename);
 
515
                }
 
516
 
 
517
                /* close directory */
 
518
                g_dir_close (dir);
 
519
            }
 
520
 
 
521
            /* cleanup */
 
522
            g_free (homedir);
 
523
        }
 
524
 
 
525
        /* cleanup */
 
526
        g_strfreev (basedirs);
 
527
    }
 
528
 
 
529
    /* cleanup */
 
530
    g_free (active_theme);
 
531
 
 
532
    /* set the treeview store */
 
533
    treeview = gtk_builder_get_object (builder, "mouse-theme-treeview");
 
534
    gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (store));
 
535
    gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (treeview), COLUMN_THEME_COMMENT);
 
536
 
 
537
    /* setup the columns */
 
538
    renderer = gtk_cell_renderer_pixbuf_new ();
 
539
    column = gtk_tree_view_column_new_with_attributes ("", renderer, "pixbuf", COLUMN_THEME_PIXBUF, NULL);
 
540
    gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
 
541
 
 
542
    renderer = gtk_cell_renderer_text_new ();
 
543
    column = gtk_tree_view_column_new_with_attributes ("", renderer, "text", COLUMN_THEME_DISPLAY_NAME, NULL);
 
544
    g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
 
545
    gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
 
546
 
 
547
    /* setup selection */
 
548
    selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
 
549
    gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
 
550
    g_signal_connect (G_OBJECT (selection), "changed", G_CALLBACK (mouse_settings_themes_selection_changed), builder);
 
551
 
 
552
    /* select the active theme in the treeview */
 
553
    gtk_tree_view_set_cursor (GTK_TREE_VIEW (treeview), active_path, NULL, FALSE);
 
554
    gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (treeview), active_path, NULL, TRUE, 0.5, 0.0);
 
555
    gtk_tree_path_free (active_path);
 
556
 
 
557
    /* sort the store */
 
558
    gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store), COLUMN_THEME_DISPLAY_NAME, mouse_settings_themes_sort_func, NULL, NULL);
 
559
    gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), COLUMN_THEME_DISPLAY_NAME, GTK_SORT_ASCENDING);
 
560
 
 
561
    /* release the store */
 
562
    g_object_unref (G_OBJECT (store));
 
563
}
 
564
#endif /* !HAVE_XCURSOR */
 
565
 
 
566
 
 
567
 
 
568
static void
 
569
mouse_settings_device_selection_changed (GtkTreeSelection *selection,
 
570
                                         GtkBuilder       *builder)
 
571
{
 
572
    gint               nbuttons;
 
573
    Display           *xdisplay;
 
574
    XDevice           *device;
 
575
    XFeedbackState    *states, *pt;
 
576
    gint               nstates;
 
577
    XPtrFeedbackState *state;
 
578
    gint               i;
 
579
    guchar            *buttonmap;
 
580
    gint               id_1 = 0, id_3 = 0;
 
581
    gint               id_4 = 0, id_5 = 0;
 
582
    gdouble            acceleration = -1.00;
 
583
    gint               threshold = -1;
 
584
    GObject           *object;
 
585
    GtkTreeModel      *model;
 
586
    GtkTreeIter        iter;
 
587
    gboolean           has_selection;
 
588
    XID                xid;
 
589
 
 
590
    /* lock the dialog */
 
591
    locked++;
 
592
 
 
593
    /* flush x and trap errors */
 
594
    gdk_flush ();
 
595
    gdk_error_trap_push ();
 
596
 
 
597
    /* get the selected item */
 
598
    has_selection = gtk_tree_selection_get_selected (selection, &model, &iter);
 
599
    if (G_LIKELY (has_selection))
 
600
    {
 
601
        /* get device id and number of buttons */
 
602
        gtk_tree_model_get (model, &iter, COLUMN_DEVICE_XID, &xid,
 
603
                            COLUMN_DEVICE_NBUTTONS, &nbuttons, -1);
 
604
 
 
605
        /* get the x display */
 
606
        xdisplay = gdk_x11_display_get_xdisplay (display);
 
607
 
 
608
        /* open the device */
 
609
        device = XOpenDevice (xdisplay, xid);
 
610
 
 
611
        if (G_LIKELY (device))
 
612
        {
 
613
            /* allocate button map */
 
614
            buttonmap = g_new0 (guchar, nbuttons);
 
615
 
 
616
            /* get the button mapping */
 
617
            XGetDeviceButtonMapping (xdisplay, device, buttonmap, nbuttons);
 
618
 
 
619
            /* figure out the position of the first and second/third button in the map */
 
620
            for (i = 0; i < nbuttons; i++)
 
621
            {
 
622
                if (buttonmap[i] == 1)
 
623
                    id_1 = i;
 
624
                else if (buttonmap[i] == (nbuttons < 3 ? 2 : 3))
 
625
                    id_3 = i;
 
626
                else if (buttonmap[i] == 4)
 
627
                    id_4 = i;
 
628
                else if (buttonmap[i] == 5)
 
629
                    id_5 = i;
 
630
            }
 
631
 
 
632
            /* cleanup */
 
633
            g_free (buttonmap);
 
634
 
 
635
            /* get the feedback states for this device */
 
636
            states = XGetFeedbackControl (xdisplay, device, &nstates);
 
637
            if (states != NULL)
 
638
            {
 
639
                /* get the pointer feedback class */
 
640
                for (pt = states, i = 0; i < nstates; i++)
 
641
                {
 
642
                    if (pt->class == PtrFeedbackClass)
 
643
                    {
 
644
                        /* get the state */
 
645
                        state = (XPtrFeedbackState *) pt;
 
646
                        acceleration = (gdouble) state->accelNum / (gdouble) state->accelDenom;
 
647
                        threshold = state->threshold;
 
648
 
 
649
                        /* done */
 
650
                        break;
 
651
                    }
 
652
 
 
653
                    /* advance the offset */
 
654
                    pt = (XFeedbackState *) ((gchar *) pt + pt->length);
 
655
                }
 
656
 
 
657
                XFreeFeedbackList (states);
 
658
            }
 
659
 
 
660
            /* close the device */
 
661
            XCloseDevice (xdisplay, device);
 
662
        }
 
663
    }
 
664
 
 
665
    /* update button order */
 
666
    object = gtk_builder_get_object (builder, id_1 > id_3 ? "mouse-left-handed" : "mouse-right-handed");
 
667
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (object), TRUE);
 
668
 
 
669
    object = gtk_builder_get_object (builder, "mouse-reverse-scrolling");
 
670
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (object), !!(id_5 < id_4));
 
671
    gtk_widget_set_sensitive (GTK_WIDGET (object), nbuttons >= 5);
 
672
 
 
673
    /* update acceleration scale */
 
674
    object = gtk_builder_get_object (builder, "mouse-acceleration-scale");
 
675
    gtk_range_set_value (GTK_RANGE (object), acceleration);
 
676
    gtk_widget_set_sensitive (GTK_WIDGET (object), acceleration != -1);
 
677
 
 
678
    /* update threshold scale */
 
679
    object = gtk_builder_get_object (builder, "mouse-threshold-scale");
 
680
    gtk_range_set_value (GTK_RANGE (object), threshold);
 
681
    gtk_widget_set_sensitive (GTK_WIDGET (object), threshold != -1);
 
682
 
 
683
    /* flush and remove the x error trap */
 
684
    gdk_flush ();
 
685
    gdk_error_trap_pop ();
 
686
 
 
687
    /* unlock */
 
688
    locked--;
 
689
}
 
690
 
 
691
 
 
692
 
 
693
static void
 
694
mouse_settings_device_save (GtkBuilder *builder)
 
695
{
 
696
    GObject          *treeview;
 
697
    GtkTreeSelection *selection;
 
698
    GtkTreeModel     *model;
 
699
    GtkTreeIter       iter;
 
700
    gboolean          has_selection;
 
701
    gchar            *name;
 
702
    GObject          *object;
 
703
    gchar             property_name[512];
 
704
    gboolean          righthanded;
 
705
    gint              threshold;
 
706
    gdouble           acceleration;
 
707
    gboolean          reverse_scrolling;
 
708
 
 
709
    /* leave when locked */
 
710
    if (locked > 0)
 
711
        return;
 
712
 
 
713
    /* get the treeview */
 
714
    treeview = gtk_builder_get_object (builder, "mouse-devices-treeview");
 
715
 
 
716
    /* get the selection */
 
717
    selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
 
718
 
 
719
    has_selection = gtk_tree_selection_get_selected (selection, &model, &iter);
 
720
    if (G_LIKELY (has_selection))
 
721
    {
 
722
        /* get device id and number of buttons */
 
723
        gtk_tree_model_get (model, &iter, COLUMN_DEVICE_NAME, &name, -1);
 
724
 
 
725
        if (G_LIKELY (name))
 
726
        {
 
727
            /* store the button order */
 
728
            object = gtk_builder_get_object (builder, "mouse-right-handed");
 
729
            g_snprintf (property_name, sizeof (property_name), "/%s/RightHanded", name);
 
730
            righthanded = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (object));
 
731
            if (!xfconf_channel_has_property (pointers_channel, property_name)
 
732
                || xfconf_channel_get_bool (pointers_channel, property_name, TRUE) != righthanded)
 
733
                xfconf_channel_set_bool (pointers_channel, property_name, righthanded);
 
734
 
 
735
            /* store reverse scrolling */
 
736
            object = gtk_builder_get_object (builder, "mouse-reverse-scrolling");
 
737
            g_snprintf (property_name, sizeof (property_name), "/%s/ReverseScrolling", name);
 
738
            reverse_scrolling = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (object));
 
739
            if (xfconf_channel_get_bool (pointers_channel, property_name, FALSE) != reverse_scrolling)
 
740
                xfconf_channel_set_bool (pointers_channel, property_name, reverse_scrolling);
 
741
 
 
742
            /* store the threshold */
 
743
            object = gtk_builder_get_object (builder, "mouse-threshold-scale");
 
744
            g_snprintf (property_name, sizeof (property_name), "/%s/Threshold", name);
 
745
            threshold = gtk_range_get_value (GTK_RANGE (object));
 
746
            if (xfconf_channel_get_int (pointers_channel, property_name, -1) != threshold)
 
747
                xfconf_channel_set_int (pointers_channel, property_name, threshold);
 
748
 
 
749
            /* store the acceleration */
 
750
            object = gtk_builder_get_object (builder, "mouse-acceleration-scale");
 
751
            g_snprintf (property_name, sizeof (property_name), "/%s/Acceleration", name);
 
752
            acceleration = gtk_range_get_value (GTK_RANGE (object));
 
753
            if (xfconf_channel_get_double (pointers_channel, property_name, -1) != acceleration)
 
754
                xfconf_channel_set_double (pointers_channel, property_name, acceleration);
 
755
 
 
756
            /* cleanup */
 
757
            g_free (name);
 
758
        }
 
759
    }
 
760
}
 
761
 
 
762
 
 
763
 
 
764
static void
 
765
mouse_settings_device_name_edited (GtkCellRendererText *renderer,
 
766
                                   gchar               *path,
 
767
                                   gchar               *new_name,
 
768
                                   GtkBuilder          *builder)
 
769
{
 
770
    GObject          *treeview;
 
771
    GtkTreeSelection *selection;
 
772
    gboolean          has_selection;
 
773
    GtkTreeModel     *model;
 
774
    GtkTreeIter       iter;
 
775
    gchar            *internal_name;
 
776
    gchar            *property_name;
 
777
    gchar            *new_name_escaped;
 
778
 
 
779
    /* check if the new name is valid */
 
780
    if (new_name == NULL || *new_name == '\0')
 
781
        return;
 
782
 
 
783
    /* get the treeview's selection */
 
784
    treeview = gtk_builder_get_object (builder, "mouse-devices-treeview");
 
785
    selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
 
786
 
 
787
    /* get the selected item */
 
788
    has_selection = gtk_tree_selection_get_selected (selection, &model, &iter);
 
789
    if (G_LIKELY (has_selection))
 
790
    {
 
791
        /* get the internal device name */
 
792
        gtk_tree_model_get (model, &iter, COLUMN_DEVICE_NAME, &internal_name, -1);
 
793
 
 
794
        /* store the new name in the channel */
 
795
        property_name = g_strdup_printf ("/%s", internal_name);
 
796
        xfconf_channel_set_string (pointers_channel, property_name, new_name);
 
797
 
 
798
        /* escape before adding in the store */
 
799
        new_name_escaped = g_markup_escape_text (new_name, -1);
 
800
 
 
801
        /* set the new device name in the store */
 
802
        gtk_list_store_set (GTK_LIST_STORE (model), &iter, COLUMN_DEVICE_DISPLAY_NAME, new_name_escaped, -1);
 
803
 
 
804
        /* cleanup */
 
805
        g_free (new_name_escaped);
 
806
        g_free (property_name);
 
807
        g_free (internal_name);
 
808
    }
 
809
}
 
810
 
 
811
 
 
812
 
 
813
static gchar *
 
814
mouse_settings_device_xfconf_name (const gchar *name)
 
815
{
 
816
    GString     *string;
 
817
    const gchar *p;
 
818
 
 
819
    /* NOTE: this function exists in both the dialog and
 
820
     *       helper code and they have to identical! */
 
821
 
 
822
    /* allocate a string */
 
823
    string = g_string_sized_new (strlen (name));
 
824
 
 
825
    /* create a name with only valid chars */
 
826
    for (p = name; *p != '\0'; p++)
 
827
    {
 
828
        if ((*p >= 'A' && *p <= 'Z')
 
829
            || (*p >= 'a' && *p <= 'z')
 
830
            || (*p >= '0' && *p <= '9')
 
831
            || *p == '_' || *p == '-')
 
832
          string = g_string_append_c (string, *p);
 
833
        else if (*p == ' ')
 
834
            string = g_string_append_c (string, '_');
 
835
    }
 
836
 
 
837
    /* return the new string */
 
838
    return g_string_free (string, FALSE);
 
839
}
 
840
 
 
841
 
 
842
 
 
843
static void
 
844
mouse_settings_device_populate_store (GtkBuilder *builder,
 
845
                                      gboolean    create_store)
 
846
{
 
847
    Display           *xdisplay;
 
848
    XDeviceInfo       *device_list, *device_info;
 
849
    gchar             *display_name, *usb;
 
850
    gshort             num_buttons;
 
851
    gint               ndevices;
 
852
    gint               i, m;
 
853
    XAnyClassPtr       ptr;
 
854
    GtkTreeIter        iter;
 
855
    GtkListStore      *store;
 
856
    GObject           *treeview;
 
857
    GtkTreePath       *path = NULL;
 
858
    GtkTreeViewColumn *column;
 
859
    GtkCellRenderer   *renderer;
 
860
    GtkTreeSelection  *selection;
 
861
    gchar             *device_name;
 
862
    gchar             *property_name;
 
863
    gchar             *property_value;
 
864
 
 
865
    /* lock */
 
866
    locked++;
 
867
 
 
868
    /* flush x and trap errors */
 
869
    gdk_flush ();
 
870
    gdk_error_trap_push ();
 
871
 
 
872
    /* get the treeview */
 
873
    treeview = gtk_builder_get_object (builder, "mouse-devices-treeview");
 
874
 
 
875
    /* create or get the store */
 
876
    if (G_LIKELY (create_store))
 
877
    {
 
878
        store = gtk_list_store_new (N_DEVICE_COLUMNS, G_TYPE_STRING, G_TYPE_STRING,
 
879
                                    G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT);
 
880
    }
 
881
    else
 
882
    {
 
883
        store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)));
 
884
        gtk_list_store_clear (store);
 
885
    }
 
886
 
 
887
    /* get the x display */
 
888
    xdisplay = gdk_x11_display_get_xdisplay (display);
 
889
 
 
890
    /* get all the registered devices */
 
891
    device_list = XListInputDevices (xdisplay, &ndevices);
 
892
 
 
893
    for (i = 0; i < ndevices; i++)
 
894
    {
 
895
        /* get the device */
 
896
        device_info = &device_list[i];
 
897
 
 
898
        /* filter out the pointer devices */
 
899
        if (device_info->use == IsXExtensionPointer)
 
900
        {
 
901
            /* get the device classes */
 
902
            ptr = device_info->inputclassinfo;
 
903
 
 
904
            /* walk all the classes */
 
905
            for (m = 0, num_buttons = 0; m < device_info->num_classes; m++)
 
906
            {
 
907
                /* find the button class */
 
908
                if (ptr->class == ButtonClass)
 
909
                {
 
910
                    /* get the number of buttons */
 
911
                    num_buttons = ((XButtonInfoPtr) ptr)->num_buttons;
 
912
 
 
913
                    /* done */
 
914
                    break;
 
915
                }
 
916
 
 
917
                /* advance the offset */
 
918
                ptr = (XAnyClassPtr) ((gchar *) ptr + ptr->length);
 
919
            }
 
920
 
 
921
            /* only append devices with buttons */
 
922
            if (G_UNLIKELY (num_buttons <= 0))
 
923
                continue;
 
924
 
 
925
            /* ignore XTEST device */
 
926
            if (g_str_has_prefix (device_info->name, "Virtual core XTEST"))
 
927
                continue;
 
928
 
 
929
            /* create a valid xfconf device name */
 
930
            device_name = mouse_settings_device_xfconf_name (device_info->name);
 
931
 
 
932
            /* check if there is a custom name set by the user */
 
933
            property_name = g_strdup_printf ("/%s", device_name);
 
934
            if (xfconf_channel_has_property (pointers_channel, property_name))
 
935
            {
 
936
                /* get the name from the config file, escape it */
 
937
                property_value = xfconf_channel_get_string (pointers_channel, property_name, NULL);
 
938
                display_name = g_markup_escape_text (property_value, -1);
 
939
                g_free (property_value);
 
940
            }
 
941
            else
 
942
            {
 
943
                /* get the device name, escaped */
 
944
                display_name = g_markup_escape_text (device_info->name, -1);
 
945
 
 
946
                /* get rid of usb crap in the name */
 
947
                if ((usb = strstr (display_name, "-usb")) != NULL)
 
948
                    *usb = '\0';
 
949
            }
 
950
 
 
951
            /* insert in the store */
 
952
            gtk_list_store_insert_with_values (store, &iter, i,
 
953
                                               COLUMN_DEVICE_ICON, "input-mouse",
 
954
                                               COLUMN_DEVICE_NAME, device_name,
 
955
                                               COLUMN_DEVICE_DISPLAY_NAME, display_name,
 
956
                                               COLUMN_DEVICE_XID, device_info->id,
 
957
                                               COLUMN_DEVICE_NBUTTONS, num_buttons, -1);
 
958
 
 
959
            /* check if we should select this device (for user convience also the display name) */
 
960
            if (opt_device_name && (strcmp (opt_device_name, device_info->name) == 0
 
961
                || (display_name && strcmp (opt_device_name, display_name) == 0)))
 
962
            {
 
963
                path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
 
964
                g_free (opt_device_name);
 
965
                opt_device_name = NULL;
 
966
            }
 
967
 
 
968
            /* cleanup */
 
969
            g_free (property_name);
 
970
            g_free (device_name);
 
971
            g_free (display_name);
 
972
        }
 
973
    }
 
974
 
 
975
    /* cleanup */
 
976
    XFreeDeviceList (device_list);
 
977
 
 
978
    /* flush and remove the x error trap */
 
979
    gdk_flush ();
 
980
    gdk_error_trap_pop ();
 
981
 
 
982
    /* get the selection */
 
983
    selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
 
984
 
 
985
    if (G_LIKELY (create_store))
 
986
    {
 
987
        /* set the treeview model */
 
988
        gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (store));
 
989
        gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (treeview), COLUMN_DEVICE_DISPLAY_NAME);
 
990
 
 
991
        /* icon renderer */
 
992
        renderer = gtk_cell_renderer_pixbuf_new ();
 
993
        column = gtk_tree_view_column_new_with_attributes ("", renderer, "icon-name", COLUMN_DEVICE_ICON, NULL);
 
994
        g_object_set (G_OBJECT (renderer), "stock-size", GTK_ICON_SIZE_DND, NULL);
 
995
        gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
 
996
 
 
997
        /* text renderer */
 
998
        renderer = gtk_cell_renderer_text_new ();
 
999
        column = gtk_tree_view_column_new_with_attributes ("", renderer, "markup", COLUMN_DEVICE_DISPLAY_NAME, NULL);
 
1000
        g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, "editable", TRUE, NULL);
 
1001
        g_signal_connect (G_OBJECT (renderer), "edited", G_CALLBACK (mouse_settings_device_name_edited), builder);
 
1002
        gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
 
1003
 
 
1004
        /* setup tree selection */
 
1005
        gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
 
1006
        g_signal_connect (G_OBJECT (selection), "changed", G_CALLBACK (mouse_settings_device_selection_changed), builder);
 
1007
    }
 
1008
 
 
1009
    /* select the mouse in the tree */
 
1010
    if (G_LIKELY (path == NULL))
 
1011
        path = gtk_tree_path_new_first ();
 
1012
    gtk_tree_selection_select_path (selection, path);
 
1013
    gtk_tree_path_free (path);
 
1014
 
 
1015
    /* sort after selecting the path */
 
1016
    if (G_LIKELY (create_store))
 
1017
    {
 
1018
        gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), COLUMN_DEVICE_XID, GTK_SORT_ASCENDING);
 
1019
        g_object_unref (G_OBJECT (store));
 
1020
    }
 
1021
 
 
1022
    /* unlock */
 
1023
    locked--;
 
1024
}
 
1025
 
 
1026
 
 
1027
 
 
1028
static gboolean
 
1029
mouse_settings_device_update_sliders (gpointer user_data)
 
1030
{
 
1031
    GtkBuilder *builder = GTK_BUILDER (user_data);
 
1032
    GObject    *treeview, *button;
 
1033
 
 
1034
    GDK_THREADS_ENTER ();
 
1035
 
 
1036
    /* get the treeview */
 
1037
    treeview = gtk_builder_get_object (builder, "mouse-devices-treeview");
 
1038
 
 
1039
    /* update */
 
1040
    mouse_settings_device_selection_changed (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)), builder);
 
1041
 
 
1042
    /* make the button sensitive again */
 
1043
    button = gtk_builder_get_object (builder, "mouse-reset");
 
1044
    gtk_widget_set_sensitive (GTK_WIDGET (button), TRUE);
 
1045
 
 
1046
    GDK_THREADS_LEAVE ();
 
1047
 
 
1048
    return FALSE;
 
1049
}
 
1050
 
 
1051
 
 
1052
 
 
1053
static void
 
1054
mouse_settings_device_list_changed_timeout_destroyed (gpointer user_data)
 
1055
{
 
1056
    /* reset the timeout id */
 
1057
    timeout_id = 0;
 
1058
}
 
1059
 
 
1060
 
 
1061
 
 
1062
static void
 
1063
mouse_settings_device_reset (GtkWidget  *button,
 
1064
                             GtkBuilder *builder)
 
1065
{
 
1066
    GObject          *treeview;
 
1067
    GtkTreeSelection *selection;
 
1068
    gchar            *name, *property_name;
 
1069
    gboolean          has_selection;
 
1070
    GtkTreeModel     *model;
 
1071
    GtkTreeIter       iter;
 
1072
 
 
1073
    /* leave when locked */
 
1074
    if (locked > 0)
 
1075
        return;
 
1076
 
 
1077
    /* get the treeview */
 
1078
    treeview = gtk_builder_get_object (builder, "mouse-devices-treeview");
 
1079
 
 
1080
    /* get the selection */
 
1081
    selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
 
1082
 
 
1083
    has_selection = gtk_tree_selection_get_selected (selection, &model, &iter);
 
1084
    if (G_LIKELY (has_selection))
 
1085
    {
 
1086
        /* get device id and number of buttons */
 
1087
        gtk_tree_model_get (model, &iter, COLUMN_DEVICE_NAME, &name, -1);
 
1088
 
 
1089
        if (G_LIKELY (name && timeout_id == 0))
 
1090
        {
 
1091
            /* make the button insensitive */
 
1092
            gtk_widget_set_sensitive (button, FALSE);
 
1093
 
 
1094
            /* set the threshold to -1 */
 
1095
            property_name = g_strdup_printf ("/%s/Threshold", name);
 
1096
            xfconf_channel_set_int (pointers_channel, property_name, -1);
 
1097
            g_free (property_name);
 
1098
 
 
1099
            /* set the acceleration to -1 */
 
1100
            property_name = g_strdup_printf ("/%s/Acceleration", name);
 
1101
            xfconf_channel_set_double (pointers_channel, property_name, -1.00);
 
1102
            g_free (property_name);
 
1103
 
 
1104
            /* update the sliders in 500ms */
 
1105
            timeout_id = g_timeout_add_full (G_PRIORITY_LOW, 500, mouse_settings_device_update_sliders,
 
1106
                                             builder, mouse_settings_device_list_changed_timeout_destroyed);
 
1107
        }
 
1108
 
 
1109
        /* cleanup */
 
1110
        g_free (name);
 
1111
    }
 
1112
}
 
1113
 
 
1114
 
 
1115
 
 
1116
#ifdef HAS_DEVICE_HOTPLUGGING
 
1117
static GdkFilterReturn
 
1118
mouse_settings_event_filter (GdkXEvent *xevent,
 
1119
                             GdkEvent  *gdk_event,
 
1120
                             gpointer   user_data)
 
1121
{
 
1122
    XEvent                     *event = xevent;
 
1123
    XDevicePresenceNotifyEvent *dpn_event = xevent;
 
1124
 
 
1125
    /* update on device changes */
 
1126
    if (event->type == device_presence_event_type
 
1127
        && (dpn_event->devchange == DeviceAdded
 
1128
            || dpn_event->devchange == DeviceRemoved))
 
1129
        mouse_settings_device_populate_store (GTK_BUILDER (user_data), FALSE);
 
1130
 
 
1131
    return GDK_FILTER_CONTINUE;
 
1132
}
 
1133
 
 
1134
 
 
1135
 
 
1136
static void
 
1137
mouse_settings_create_event_filter (GtkBuilder *builder)
 
1138
{
 
1139
    Display     *xdisplay;
 
1140
    XEventClass  event_class;
 
1141
 
 
1142
    /* flush x and trap errors */
 
1143
    gdk_flush ();
 
1144
    gdk_error_trap_push ();
 
1145
 
 
1146
    /* get the default display and root window */
 
1147
    xdisplay = gdk_x11_display_get_xdisplay (display);
 
1148
    if (G_UNLIKELY (!xdisplay))
 
1149
        return;
 
1150
 
 
1151
    /* monitor device change events */
 
1152
    DevicePresence (xdisplay, device_presence_event_type, event_class);
 
1153
    XSelectExtensionEvent (xdisplay, RootWindow (xdisplay, DefaultScreen (xdisplay)), &event_class, 1);
 
1154
 
 
1155
    /* flush and remove the x error trap */
 
1156
    gdk_flush ();
 
1157
    gdk_error_trap_pop ();
 
1158
 
 
1159
    /* add an event filter */
 
1160
    gdk_window_add_filter (NULL, mouse_settings_event_filter, builder);
 
1161
}
 
1162
#endif
 
1163
 
 
1164
 
 
1165
 
 
1166
gint
 
1167
main (gint argc, gchar **argv)
 
1168
{
 
1169
    GObject           *dialog;
 
1170
    GtkWidget         *plug;
 
1171
    GObject           *plug_child;
 
1172
    GtkBuilder        *builder;
 
1173
    GError            *error = NULL;
 
1174
    GObject           *object;
 
1175
    XExtensionVersion *version = NULL;
 
1176
 
 
1177
    /* setup translation domain */
 
1178
    xfce_textdomain (GETTEXT_PACKAGE, LOCALEDIR, "UTF-8");
 
1179
 
 
1180
    /* initialize Gtk+ */
 
1181
    if (!gtk_init_with_args (&argc, &argv, "", option_entries, GETTEXT_PACKAGE, &error))
 
1182
    {
 
1183
        if (G_LIKELY (error))
 
1184
        {
 
1185
            /* print error */
 
1186
            g_print ("%s: %s.\n", G_LOG_DOMAIN, error->message);
 
1187
            g_print (_("Type '%s --help' for usage."), G_LOG_DOMAIN);
 
1188
            g_print ("\n");
 
1189
 
 
1190
            /* cleanup */
 
1191
            g_error_free (error);
 
1192
        }
 
1193
        else
 
1194
        {
 
1195
            g_error ("Unable to open display.");
 
1196
        }
 
1197
 
 
1198
        return EXIT_FAILURE;
 
1199
    }
 
1200
 
 
1201
    /* print version information */
 
1202
    if (G_UNLIKELY (opt_version))
 
1203
    {
 
1204
        g_print ("%s %s (Xfce %s)\n\n", G_LOG_DOMAIN, PACKAGE_VERSION, xfce_version_string ());
 
1205
        g_print ("%s\n", "Copyright (c) 2004-2011");
 
1206
        g_print ("\t%s\n\n", _("The Xfce development team. All rights reserved."));
 
1207
        g_print (_("Please report bugs to <%s>."), PACKAGE_BUGREPORT);
 
1208
        g_print ("\n");
 
1209
 
 
1210
        return EXIT_SUCCESS;
 
1211
    }
 
1212
 
 
1213
    /* initialize xfconf */
 
1214
    if (G_UNLIKELY (!xfconf_init (&error)))
 
1215
    {
 
1216
        /* print error and leave */
 
1217
        g_critical ("Failed to connect to Xfconf daemon: %s", error->message);
 
1218
        g_error_free (error);
 
1219
 
 
1220
        return EXIT_FAILURE;
 
1221
    }
 
1222
 
 
1223
    /* check for Xi */
 
1224
    version = XGetExtensionVersion (GDK_DISPLAY (), INAME);
 
1225
    if (version == NULL || !version->present)
 
1226
    {
 
1227
        g_critical ("XI is not present.");
 
1228
        return EXIT_FAILURE;
 
1229
    }
 
1230
    else if (version->major_version < MIN_XI_VERS_MAJOR
 
1231
             || (version->major_version == MIN_XI_VERS_MAJOR
 
1232
                 && version->minor_version < MIN_XI_VERS_MINOR))
 
1233
    {
 
1234
        g_critical ("Your XI is too old (%d.%d) version %d.%d is required.",
 
1235
                    version->major_version, version->minor_version,
 
1236
                    MIN_XI_VERS_MAJOR, MIN_XI_VERS_MINOR);
 
1237
        return EXIT_FAILURE;
 
1238
    }
 
1239
 
 
1240
    /* hook to make sure the libxfce4ui library is linked */
 
1241
    if (xfce_titled_dialog_get_type () == 0)
 
1242
        return EXIT_FAILURE;
 
1243
 
 
1244
    /* open the xsettings and pointers channel */
 
1245
    xsettings_channel = xfconf_channel_new ("xsettings");
 
1246
    pointers_channel = xfconf_channel_new ("pointers");
 
1247
 
 
1248
    if (G_LIKELY (pointers_channel && xsettings_channel))
 
1249
    {
 
1250
        /* load the Gtk+ user-interface file */
 
1251
        builder = gtk_builder_new ();
 
1252
        if (gtk_builder_add_from_string (builder, mouse_dialog_ui,
 
1253
                                         mouse_dialog_ui_length, &error) != 0)
 
1254
        {
 
1255
            /* lock */
 
1256
            locked++;
 
1257
 
 
1258
            /* set the working display for this instance */
 
1259
            display = gdk_display_get_default ();
 
1260
 
 
1261
            /* populate the devices treeview */
 
1262
            mouse_settings_device_populate_store (builder, TRUE);
 
1263
 
 
1264
            /* connect signals */
 
1265
            object = gtk_builder_get_object (builder, "mouse-acceleration-scale");
 
1266
            g_signal_connect_swapped (G_OBJECT (object), "value-changed", G_CALLBACK (mouse_settings_device_save), builder);
 
1267
 
 
1268
            object = gtk_builder_get_object (builder, "mouse-threshold-scale");
 
1269
            g_signal_connect_swapped (G_OBJECT (object), "value-changed", G_CALLBACK (mouse_settings_device_save), builder);
 
1270
 
 
1271
            object = gtk_builder_get_object (builder, "mouse-left-handed");
 
1272
            g_signal_connect_swapped (G_OBJECT (object), "toggled", G_CALLBACK (mouse_settings_device_save), builder);
 
1273
 
 
1274
            object = gtk_builder_get_object (builder, "mouse-right-handed");
 
1275
            g_signal_connect_swapped (G_OBJECT (object), "toggled", G_CALLBACK (mouse_settings_device_save), builder);
 
1276
 
 
1277
            object = gtk_builder_get_object (builder, "mouse-reverse-scrolling");
 
1278
            g_signal_connect_swapped (G_OBJECT (object), "toggled", G_CALLBACK (mouse_settings_device_save), builder);
 
1279
 
 
1280
            object = gtk_builder_get_object (builder, "mouse-reset");
 
1281
            g_signal_connect (G_OBJECT (object), "clicked", G_CALLBACK (mouse_settings_device_reset), builder);
 
1282
 
 
1283
#ifdef HAVE_XCURSOR
 
1284
            /* populate the themes treeview */
 
1285
            mouse_settings_themes_populate_store (builder);
 
1286
 
 
1287
            /* connect the cursor size in the cursor tab */
 
1288
            object = gtk_builder_get_object (builder, "mouse-cursor-size");
 
1289
            xfconf_g_property_bind (xsettings_channel, "/Gtk/CursorThemeSize", G_TYPE_INT, G_OBJECT (object), "value");
 
1290
#else
 
1291
            /* hide the themes tab */
 
1292
            object = gtk_builder_get_object (builder, "mouse-themes-hbox");
 
1293
            gtk_widget_hide (GTK_WIDGET (object));
 
1294
#endif /* !HAVE_XCURSOR */
 
1295
 
 
1296
            /* connect sliders in the gtk tab */
 
1297
            object = gtk_builder_get_object (builder, "mouse-dnd-threshold");
 
1298
            xfconf_g_property_bind (xsettings_channel, "/Net/DndDragThreshold", G_TYPE_INT, G_OBJECT (object), "value");
 
1299
 
 
1300
            object = gtk_builder_get_object (builder, "mouse-double-click-time");
 
1301
            xfconf_g_property_bind (xsettings_channel, "/Net/DoubleClickTime", G_TYPE_INT, G_OBJECT (object), "value");
 
1302
 
 
1303
            object = gtk_builder_get_object (builder, "mouse-double-click-distance");
 
1304
            xfconf_g_property_bind (xsettings_channel, "/Net/DoubleClickDistance", G_TYPE_INT, G_OBJECT (object), "value");
 
1305
 
 
1306
#ifdef HAS_DEVICE_HOTPLUGGING
 
1307
            /* create the event filter for device monitoring */
 
1308
            mouse_settings_create_event_filter (builder);
 
1309
#endif
 
1310
 
 
1311
            if (G_UNLIKELY (opt_socket_id == 0))
 
1312
            {
 
1313
                /* get the dialog */
 
1314
                dialog = gtk_builder_get_object (builder, "mouse-dialog");
 
1315
 
 
1316
                /* unlock */
 
1317
                locked--;
 
1318
 
 
1319
                gtk_widget_show (GTK_WIDGET (dialog));
 
1320
                g_signal_connect (dialog, "response", G_CALLBACK (gtk_main_quit), NULL);
 
1321
 
 
1322
                /* To prevent the settings dialog to be saved in the session */
 
1323
                gdk_set_sm_client_id ("FAKE ID");
 
1324
 
 
1325
                gtk_main ();
 
1326
 
 
1327
                gtk_widget_destroy (GTK_WIDGET (dialog));
 
1328
            }
 
1329
            else
 
1330
            {
 
1331
                /* Create plug widget */
 
1332
                plug = gtk_plug_new (opt_socket_id);
 
1333
                g_signal_connect (plug, "delete-event", G_CALLBACK (gtk_main_quit), NULL);
 
1334
                gtk_widget_show (plug);
 
1335
 
 
1336
                /* Stop startup notification */
 
1337
                gdk_notify_startup_complete ();
 
1338
 
 
1339
                /* Get plug child widget */
 
1340
                plug_child = gtk_builder_get_object (builder, "plug-child");
 
1341
                gtk_widget_reparent (GTK_WIDGET (plug_child), plug);
 
1342
                gtk_widget_show (GTK_WIDGET (plug_child));
 
1343
 
 
1344
                /* Unlock */
 
1345
                locked--;
 
1346
 
 
1347
                /* To prevent the settings dialog to be saved in the session */
 
1348
                gdk_set_sm_client_id ("FAKE ID");
 
1349
 
 
1350
                /* Enter main loop */
 
1351
                gtk_main ();
 
1352
            }
 
1353
        }
 
1354
        else
 
1355
        {
 
1356
            g_error ("Failed to load the UI file: %s.", error->message);
 
1357
            g_error_free (error);
 
1358
        }
 
1359
 
 
1360
        /* release the Gtk+ user-interface file */
 
1361
        g_object_unref (G_OBJECT (builder));
 
1362
 
 
1363
        /* release the channels */
 
1364
        g_object_unref (G_OBJECT (xsettings_channel));
 
1365
        g_object_unref (G_OBJECT (pointers_channel));
 
1366
    }
 
1367
 
 
1368
    /* shutdown xfconf */
 
1369
    xfconf_shutdown ();
 
1370
 
 
1371
    /* cleanup */
 
1372
    g_free (opt_device_name);
 
1373
 
 
1374
    return EXIT_SUCCESS;
 
1375
}