1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
3
* Copyright © 2001 Ximian, Inc.
4
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
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.
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 General Public License for more details.
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.
24
#include <sys/types.h>
35
#include <glib/gi18n.h>
40
#ifdef HAVE_X11_EXTENSIONS_XKB_H
41
#include <X11/XKBlib.h>
42
#include <X11/keysym.h>
45
#include "gnome-settings-profile.h"
46
#include "gsd-keyboard-manager.h"
47
#include "gsd-enums.h"
49
#include "gsd-keyboard-xkb.h"
51
#define GSD_KEYBOARD_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_KEYBOARD_MANAGER, GsdKeyboardManagerPrivate))
54
# define HOST_NAME_MAX 255
57
#define GSD_KEYBOARD_DIR "org.gnome.settings-daemon.peripherals.keyboard"
59
#define KEY_REPEAT "repeat"
60
#define KEY_CLICK "click"
61
#define KEY_INTERVAL "repeat-interval"
62
#define KEY_DELAY "delay"
63
#define KEY_CLICK_VOLUME "click-volume"
65
#define KEY_BELL_VOLUME "bell-volume"
66
#define KEY_BELL_PITCH "bell-pitch"
67
#define KEY_BELL_DURATION "bell-duration"
68
#define KEY_BELL_MODE "bell-mode"
70
struct GsdKeyboardManagerPrivate
78
static void gsd_keyboard_manager_class_init (GsdKeyboardManagerClass *klass);
79
static void gsd_keyboard_manager_init (GsdKeyboardManager *keyboard_manager);
80
static void gsd_keyboard_manager_finalize (GObject *object);
82
G_DEFINE_TYPE (GsdKeyboardManager, gsd_keyboard_manager, G_TYPE_OBJECT)
84
static gpointer manager_object = NULL;
86
#ifdef HAVE_X11_EXTENSIONS_XKB_H
88
xkb_set_keyboard_autorepeat_rate (guint delay, guint interval)
90
return XkbSetAutoRepeatRate (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
98
gsd_keyboard_get_hostname_key (void)
100
/* FIXME disabled for now, as we need GSettingsList support:
101
* https://bugzilla.gnome.org/show_bug.cgi?id=622126 */
103
const char *hostname;
105
hostname = g_get_host_name ();
107
if (g_str_equal (hostname, "localhost") == FALSE &&
108
g_str_equal (hostname, "localhost.localdomain") == FALSE) {
112
/* FIXME, really escape? */
113
escaped = g_strdup (hostname);
114
key = g_strdup_printf ("host-%s-0-numlock-on", escaped);
118
g_message ("NumLock remembering disabled because hostname is set to \"localhost\"");
125
#ifdef HAVE_X11_EXTENSIONS_XKB_H
128
NUMLOCK_STATE_OFF = 0,
129
NUMLOCK_STATE_ON = 1,
130
NUMLOCK_STATE_UNKNOWN = 2
134
numlock_xkb_init (GsdKeyboardManager *manager)
136
Display *dpy = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
138
int opcode, error_base, major, minor;
140
have_xkb = XkbQueryExtension (dpy,
142
&manager->priv->xkb_event_base,
146
&& XkbUseExtension (dpy, &major, &minor);
149
XkbSelectEventDetails (dpy,
153
XkbModifierLockMask);
155
g_warning ("XKB extension not available");
158
manager->priv->have_xkb = have_xkb;
162
numlock_NumLock_modifier_mask (void)
164
Display *dpy = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
165
return XkbKeysymToModifiers (dpy, XK_Num_Lock);
169
numlock_set_xkb_state (NumLockState new_state)
171
unsigned int num_mask;
172
Display *dpy = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
173
if (new_state != NUMLOCK_STATE_ON && new_state != NUMLOCK_STATE_OFF)
175
num_mask = numlock_NumLock_modifier_mask ();
176
XkbLockModifiers (dpy, XkbUseCoreKbd, num_mask, new_state ? num_mask : 0);
180
numlock_get_gsettings_state (GSettings *settings)
185
key = gsd_keyboard_get_hostname_key ();
187
return NUMLOCK_STATE_UNKNOWN;
189
curr_state = g_settings_get_boolean (settings, key);
197
numlock_set_gsettings_state (GSettings *settings,
198
NumLockState new_state)
202
if (new_state != NUMLOCK_STATE_ON && new_state != NUMLOCK_STATE_OFF) {
206
key = gsd_keyboard_get_hostname_key ();
208
g_settings_set_boolean (settings, key, new_state);
213
static GdkFilterReturn
214
numlock_xkb_callback (GdkXEvent *xev_,
218
XEvent *xev = (XEvent *) xev_;
219
GsdKeyboardManager *manager = (GsdKeyboardManager *) user_data;
221
if (xev->type == manager->priv->xkb_event_base) {
222
XkbEvent *xkbev = (XkbEvent *)xev;
223
if (xkbev->any.xkb_type == XkbStateNotify)
224
if (xkbev->state.changed & XkbModifierLockMask) {
225
unsigned num_mask = numlock_NumLock_modifier_mask ();
226
unsigned locked_mods = xkbev->state.locked_mods;
227
int numlock_state = !! (num_mask & locked_mods);
228
numlock_set_gsettings_state (manager->priv->settings, numlock_state);
231
return GDK_FILTER_CONTINUE;
235
numlock_install_xkb_callback (GsdKeyboardManager *manager)
237
if (!manager->priv->have_xkb)
240
gdk_window_add_filter (NULL,
241
numlock_xkb_callback,
245
#endif /* HAVE_X11_EXTENSIONS_XKB_H */
248
_gsd_settings_get_uint (GSettings *settings,
253
g_settings_get (settings, key, "u", &value);
258
apply_settings (GSettings *settings,
260
GsdKeyboardManager *manager)
262
XKeyboardControl kbdcontrol;
271
GsdBellMode bell_mode;
272
#ifdef HAVE_X11_EXTENSIONS_XKB_H
274
#endif /* HAVE_X11_EXTENSIONS_XKB_H */
276
repeat = g_settings_get_boolean (settings, KEY_REPEAT);
277
click = g_settings_get_boolean (settings, KEY_CLICK);
278
interval = _gsd_settings_get_uint (settings, KEY_INTERVAL);
279
delay = _gsd_settings_get_uint (settings, KEY_DELAY);
280
click_volume = g_settings_get_int (settings, KEY_CLICK_VOLUME);
281
bell_pitch = g_settings_get_int (settings, KEY_BELL_PITCH);
282
bell_duration = g_settings_get_int (settings, KEY_BELL_DURATION);
284
bell_mode = g_settings_get_enum (settings, KEY_BELL_MODE);
285
bell_volume = (bell_mode == GSD_BELL_MODE_ON) ? 50 : 0;
287
#ifdef HAVE_X11_EXTENSIONS_XKB_H
288
rnumlock = g_settings_get_boolean (settings, "remember-numlock-state");
289
#endif /* HAVE_X11_EXTENSIONS_XKB_H */
291
gdk_error_trap_push ();
293
gboolean rate_set = FALSE;
295
XAutoRepeatOn (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
296
/* Use XKB in preference */
297
#ifdef HAVE_X11_EXTENSIONS_XKB_H
298
rate_set = xkb_set_keyboard_autorepeat_rate (delay, interval);
301
g_warning ("Neither XKeyboard not Xfree86's keyboard extensions are available,\n"
302
"no way to support keyboard autorepeat rate settings");
304
XAutoRepeatOff (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
307
/* as percentage from 0..100 inclusive */
308
if (click_volume < 0) {
310
} else if (click_volume > 100) {
313
kbdcontrol.key_click_percent = click ? click_volume : 0;
314
kbdcontrol.bell_percent = bell_volume;
315
kbdcontrol.bell_pitch = bell_pitch;
316
kbdcontrol.bell_duration = bell_duration;
317
XChangeKeyboardControl (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
318
KBKeyClickPercent | KBBellPercent | KBBellPitch | KBBellDuration,
321
#ifdef HAVE_X11_EXTENSIONS_XKB_H
322
if (manager->priv->have_xkb && rnumlock) {
323
numlock_set_xkb_state (numlock_get_gsettings_state (manager->priv->settings));
325
#endif /* HAVE_X11_EXTENSIONS_XKB_H */
327
XSync (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), FALSE);
328
gdk_error_trap_pop_ignored ();
332
gsd_keyboard_manager_apply_settings (GsdKeyboardManager *manager)
334
apply_settings (manager->priv->settings, NULL, manager);
338
start_keyboard_idle_cb (GsdKeyboardManager *manager)
340
gnome_settings_profile_start (NULL);
342
g_debug ("Starting keyboard manager");
344
manager->priv->have_xkb = 0;
345
manager->priv->settings = g_settings_new (GSD_KEYBOARD_DIR);
347
/* Essential - xkb initialization should happen before */
348
gsd_keyboard_xkb_init (manager);
350
#ifdef HAVE_X11_EXTENSIONS_XKB_H
351
numlock_xkb_init (manager);
352
#endif /* HAVE_X11_EXTENSIONS_XKB_H */
354
/* apply current settings before we install the callback */
355
gsd_keyboard_manager_apply_settings (manager);
357
g_signal_connect (G_OBJECT (manager->priv->settings), "changed",
358
G_CALLBACK (apply_settings), manager);
360
#ifdef HAVE_X11_EXTENSIONS_XKB_H
361
numlock_install_xkb_callback (manager);
362
#endif /* HAVE_X11_EXTENSIONS_XKB_H */
364
gnome_settings_profile_end (NULL);
366
manager->priv->start_idle_id = 0;
372
gsd_keyboard_manager_start (GsdKeyboardManager *manager,
375
gnome_settings_profile_start (NULL);
377
manager->priv->start_idle_id = g_idle_add ((GSourceFunc) start_keyboard_idle_cb, manager);
379
gnome_settings_profile_end (NULL);
385
gsd_keyboard_manager_stop (GsdKeyboardManager *manager)
387
GsdKeyboardManagerPrivate *p = manager->priv;
389
g_debug ("Stopping keyboard manager");
391
if (p->settings != NULL) {
392
g_object_unref (p->settings);
396
#if HAVE_X11_EXTENSIONS_XKB_H
398
gdk_window_remove_filter (NULL,
399
numlock_xkb_callback,
402
#endif /* HAVE_X11_EXTENSIONS_XKB_H */
404
gsd_keyboard_xkb_shutdown ();
408
gsd_keyboard_manager_set_property (GObject *object,
415
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
421
gsd_keyboard_manager_get_property (GObject *object,
428
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
434
gsd_keyboard_manager_constructor (GType type,
435
guint n_construct_properties,
436
GObjectConstructParam *construct_properties)
438
GsdKeyboardManager *keyboard_manager;
440
keyboard_manager = GSD_KEYBOARD_MANAGER (G_OBJECT_CLASS (gsd_keyboard_manager_parent_class)->constructor (type,
441
n_construct_properties,
442
construct_properties));
444
return G_OBJECT (keyboard_manager);
448
gsd_keyboard_manager_dispose (GObject *object)
450
G_OBJECT_CLASS (gsd_keyboard_manager_parent_class)->dispose (object);
454
gsd_keyboard_manager_class_init (GsdKeyboardManagerClass *klass)
456
GObjectClass *object_class = G_OBJECT_CLASS (klass);
458
object_class->get_property = gsd_keyboard_manager_get_property;
459
object_class->set_property = gsd_keyboard_manager_set_property;
460
object_class->constructor = gsd_keyboard_manager_constructor;
461
object_class->dispose = gsd_keyboard_manager_dispose;
462
object_class->finalize = gsd_keyboard_manager_finalize;
464
g_type_class_add_private (klass, sizeof (GsdKeyboardManagerPrivate));
468
gsd_keyboard_manager_init (GsdKeyboardManager *manager)
470
manager->priv = GSD_KEYBOARD_MANAGER_GET_PRIVATE (manager);
474
gsd_keyboard_manager_finalize (GObject *object)
476
GsdKeyboardManager *keyboard_manager;
478
g_return_if_fail (object != NULL);
479
g_return_if_fail (GSD_IS_KEYBOARD_MANAGER (object));
481
keyboard_manager = GSD_KEYBOARD_MANAGER (object);
483
g_return_if_fail (keyboard_manager->priv != NULL);
485
if (keyboard_manager->priv->start_idle_id != 0)
486
g_source_remove (keyboard_manager->priv->start_idle_id);
488
G_OBJECT_CLASS (gsd_keyboard_manager_parent_class)->finalize (object);
492
gsd_keyboard_manager_new (void)
494
if (manager_object != NULL) {
495
g_object_ref (manager_object);
497
manager_object = g_object_new (GSD_TYPE_KEYBOARD_MANAGER, NULL);
498
g_object_add_weak_pointer (manager_object,
499
(gpointer *) &manager_object);
502
return GSD_KEYBOARD_MANAGER (manager_object);