~psusi/ubuntu/natty/gnome-power-manager/sleep

« back to all changes in this revision

Viewing changes to .pc/00git-port-to-libupower.patch/src/gpm-button.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2010-07-14 16:19:03 UTC
  • Revision ID: james.westby@ubuntu.com-20100714161903-ji5dlfcj32q854gc
Tags: 2.30.1-1ubuntu2
* Add 00git-port-to-libupower.patch: Port from libdevkit-power to
  libupower-glib, the former will go away soon.
* debian/control.in: Replace libdevkit-power-gobject-dev with
  libupower-glib-dev build dependency.
* 12-add-appindicators.patch: Update to upower port.
* Add 13-energy-star.patch: Change default timings to be Energy Star 5.0
  compliant, except for automatic suspend on AC (since that might be both
  inconvenient, and suspend might not work at all). (LP: #604635)

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) 2006-2007 Richard Hughes <richard@hughsie.com>
 
4
 *
 
5
 * Licensed under the GNU General Public License Version 2
 
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 of the License, or
 
10
 * (at your option) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
20
 */
 
21
 
 
22
#include "config.h"
 
23
 
 
24
#include <string.h>
 
25
#include <glib.h>
 
26
#include <glib/gi18n.h>
 
27
 
 
28
#include <X11/X.h>
 
29
#include <gdk/gdkx.h>
 
30
#include <gtk/gtk.h>
 
31
#include <X11/XF86keysym.h>
 
32
#include <devkit-power-gobject/devicekit-power.h>
 
33
 
 
34
#include "gpm-common.h"
 
35
#include "gpm-button.h"
 
36
 
 
37
#include "egg-debug.h"
 
38
 
 
39
static void     gpm_button_finalize   (GObject        *object);
 
40
 
 
41
#define GPM_BUTTON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPM_TYPE_BUTTON, GpmButtonPrivate))
 
42
 
 
43
struct GpmButtonPrivate
 
44
{
 
45
        GdkScreen               *screen;
 
46
        GdkWindow               *window;
 
47
        GHashTable              *keysym_to_name_hash;
 
48
        gchar                   *last_button;
 
49
        GTimer                  *timer;
 
50
        gboolean                 lid_is_closed;
 
51
        DkpClient               *client;
 
52
};
 
53
 
 
54
enum {
 
55
        BUTTON_PRESSED,
 
56
        LAST_SIGNAL
 
57
};
 
58
 
 
59
static guint signals [LAST_SIGNAL] = { 0 };
 
60
static gpointer gpm_button_object = NULL;
 
61
 
 
62
G_DEFINE_TYPE (GpmButton, gpm_button, G_TYPE_OBJECT)
 
63
 
 
64
#define GPM_BUTTON_DUPLICATE_TIMEOUT    0.125f
 
65
 
 
66
/**
 
67
 * gpm_button_emit_type:
 
68
 **/
 
69
static gboolean
 
70
gpm_button_emit_type (GpmButton *button, const gchar *type)
 
71
{
 
72
        g_return_val_if_fail (GPM_IS_BUTTON (button), FALSE);
 
73
 
 
74
        /* did we just have this button before the timeout? */
 
75
        if (g_strcmp0 (type, button->priv->last_button) == 0 &&
 
76
            g_timer_elapsed (button->priv->timer, NULL) < GPM_BUTTON_DUPLICATE_TIMEOUT) {
 
77
                egg_debug ("ignoring duplicate button %s", type);
 
78
                return FALSE;
 
79
        }
 
80
 
 
81
        egg_debug ("emitting button-pressed : %s", type);
 
82
        g_signal_emit (button, signals [BUTTON_PRESSED], 0, type);
 
83
 
 
84
        /* save type and last size */
 
85
        g_free (button->priv->last_button);
 
86
        button->priv->last_button = g_strdup (type);
 
87
        g_timer_reset (button->priv->timer);
 
88
 
 
89
        return TRUE;
 
90
}
 
91
 
 
92
/**
 
93
 * gpm_button_filter_x_events:
 
94
 **/
 
95
static GdkFilterReturn
 
96
gpm_button_filter_x_events (GdkXEvent *xevent, GdkEvent *event, gpointer data)
 
97
{
 
98
        GpmButton *button = (GpmButton *) data;
 
99
        XEvent *xev = (XEvent *) xevent;
 
100
        guint keycode;
 
101
        const gchar *key;
 
102
        gchar *keycode_str;
 
103
 
 
104
        if (xev->type != KeyPress)
 
105
                return GDK_FILTER_CONTINUE;
 
106
 
 
107
        keycode = xev->xkey.keycode;
 
108
 
 
109
        /* is the key string already in our DB? */
 
110
        keycode_str = g_strdup_printf ("0x%x", keycode);
 
111
        key = g_hash_table_lookup (button->priv->keysym_to_name_hash, (gpointer) keycode_str);
 
112
        g_free (keycode_str);
 
113
 
 
114
        /* found anything? */
 
115
        if (key == NULL) {
 
116
                egg_debug ("Key %i not found in hash", keycode);
 
117
                /* pass normal keypresses on, which might help with accessibility access */
 
118
                return GDK_FILTER_CONTINUE;
 
119
        }
 
120
 
 
121
        egg_debug ("Key %i mapped to key %s", keycode, key);
 
122
        gpm_button_emit_type (button, key);
 
123
 
 
124
        return GDK_FILTER_REMOVE;
 
125
}
 
126
 
 
127
/**
 
128
 * gpm_button_grab_keystring:
 
129
 * @button: This button class instance
 
130
 * @keystr: The key string, e.g. "<Control><Alt>F11"
 
131
 * @hashkey: A unique key made up from the modmask and keycode suitable for
 
132
 *           referencing in a hashtable.
 
133
 *           You must free this string, or specify NULL to ignore.
 
134
 *
 
135
 * Grab the key specified in the key string.
 
136
 *
 
137
 * Return value: TRUE if we parsed and grabbed okay
 
138
 **/
 
139
static gboolean
 
140
gpm_button_grab_keystring (GpmButton *button, guint64 keycode)
 
141
{
 
142
        guint modmask = AnyModifier;
 
143
        Display *display;
 
144
        gint ret;
 
145
 
 
146
        /* get the current X Display */
 
147
        display = GDK_DISPLAY ();
 
148
 
 
149
        /* don't abort on error */
 
150
        gdk_error_trap_push ();
 
151
 
 
152
        /* grab the key if possible */
 
153
        ret = XGrabKey (display, keycode, modmask,
 
154
                        GDK_WINDOW_XID (button->priv->window), True,
 
155
                        GrabModeAsync, GrabModeAsync);
 
156
        if (ret == BadAccess) {
 
157
                egg_warning ("Failed to grab modmask=%u, keycode=%li",
 
158
                             modmask, (long int) keycode);
 
159
                return FALSE;
 
160
        }
 
161
 
 
162
        /* grab the lock key if possible */
 
163
        ret = XGrabKey (display, keycode, LockMask | modmask,
 
164
                        GDK_WINDOW_XID (button->priv->window), True,
 
165
                        GrabModeAsync, GrabModeAsync);
 
166
        if (ret == BadAccess) {
 
167
                egg_warning ("Failed to grab modmask=%u, keycode=%li",
 
168
                             LockMask | modmask, (long int) keycode);
 
169
                return FALSE;
 
170
        }
 
171
 
 
172
        /* we are not processing the error */
 
173
        gdk_flush ();
 
174
        gdk_error_trap_pop ();
 
175
 
 
176
        egg_debug ("Grabbed modmask=%x, keycode=%li", modmask, (long int) keycode);
 
177
        return TRUE;
 
178
}
 
179
 
 
180
/**
 
181
 * gpm_button_grab_keystring:
 
182
 * @button: This button class instance
 
183
 * @keystr: The key string, e.g. "<Control><Alt>F11"
 
184
 * @hashkey: A unique key made up from the modmask and keycode suitable for
 
185
 *           referencing in a hashtable.
 
186
 *           You must free this string, or specify NULL to ignore.
 
187
 *
 
188
 * Grab the key specified in the key string.
 
189
 *
 
190
 * Return value: TRUE if we parsed and grabbed okay
 
191
 **/
 
192
static gboolean
 
193
gpm_button_xevent_key (GpmButton *button, guint keysym, const gchar *key_name)
 
194
{
 
195
        gchar *key = NULL;
 
196
        gboolean ret;
 
197
        gchar *keycode_str;
 
198
        guint keycode;
 
199
 
 
200
        /* convert from keysym to keycode */
 
201
        keycode = XKeysymToKeycode (GDK_DISPLAY (), keysym);
 
202
        if (keycode == 0) {
 
203
                egg_warning ("could not map keysym %x to keycode", keysym);
 
204
                return FALSE;
 
205
        }
 
206
 
 
207
        /* is the key string already in our DB? */
 
208
        keycode_str = g_strdup_printf ("0x%x", keycode);
 
209
        key = g_hash_table_lookup (button->priv->keysym_to_name_hash, (gpointer) keycode_str);
 
210
        if (key != NULL) {
 
211
                egg_warning ("found in hash %i", keycode);
 
212
                g_free (keycode_str);
 
213
                return FALSE;
 
214
        }
 
215
 
 
216
        /* try to register X event */
 
217
        ret = gpm_button_grab_keystring (button, keycode);
 
218
        if (!ret) {
 
219
                egg_warning ("Failed to grab %i", keycode);
 
220
                g_free (keycode_str);
 
221
                return FALSE;
 
222
        }
 
223
 
 
224
        /* add to hash table */
 
225
        g_hash_table_insert (button->priv->keysym_to_name_hash, (gpointer) keycode_str, (gpointer) g_strdup (key_name));
 
226
 
 
227
        /* the key is freed in the hash function unref */
 
228
        return TRUE;
 
229
}
 
230
 
 
231
/**
 
232
 * gpm_button_class_init:
 
233
 * @button: This class instance
 
234
 **/
 
235
static void
 
236
gpm_button_class_init (GpmButtonClass *klass)
 
237
{
 
238
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
239
        object_class->finalize = gpm_button_finalize;
 
240
        g_type_class_add_private (klass, sizeof (GpmButtonPrivate));
 
241
 
 
242
        signals [BUTTON_PRESSED] =
 
243
                g_signal_new ("button-pressed",
 
244
                              G_TYPE_FROM_CLASS (object_class),
 
245
                              G_SIGNAL_RUN_LAST,
 
246
                              G_STRUCT_OFFSET (GpmButtonClass, button_pressed),
 
247
                              NULL, NULL,
 
248
                              g_cclosure_marshal_VOID__STRING,
 
249
                              G_TYPE_NONE, 1, G_TYPE_STRING);
 
250
}
 
251
 
 
252
/**
 
253
 * gpm_button_is_lid_closed:
 
254
 **/
 
255
gboolean
 
256
gpm_button_is_lid_closed (GpmButton *button)
 
257
{
 
258
        gboolean lid_is_closed;
 
259
 
 
260
        g_return_val_if_fail (GPM_IS_BUTTON (button), FALSE);
 
261
 
 
262
        g_object_get (button->priv->client,
 
263
                      "lid-is-closed", &lid_is_closed,
 
264
                      NULL);
 
265
        return lid_is_closed;
 
266
}
 
267
 
 
268
/**
 
269
 * gpm_button_reset_time:
 
270
 *
 
271
 * We have to refresh the event time on resume to handle duplicate buttons
 
272
 * properly when the time is significant when we suspend.
 
273
 **/
 
274
gboolean
 
275
gpm_button_reset_time (GpmButton *button)
 
276
{
 
277
        g_return_val_if_fail (GPM_IS_BUTTON (button), FALSE);
 
278
        g_timer_reset (button->priv->timer);
 
279
        return TRUE;
 
280
}
 
281
 
 
282
/**
 
283
 * gpm_button_client_changed_cb
 
284
 **/
 
285
static void
 
286
gpm_button_client_changed_cb (DkpClient *client, GpmButton *button)
 
287
{
 
288
        gboolean lid_is_closed;
 
289
 
 
290
        /* get new state */
 
291
        g_object_get (client,
 
292
                      "lid-is-closed", &lid_is_closed,
 
293
                      NULL);
 
294
 
 
295
        /* same state */
 
296
        if (button->priv->lid_is_closed == lid_is_closed)
 
297
                return;
 
298
 
 
299
        /* save state */
 
300
        button->priv->lid_is_closed = lid_is_closed;
 
301
 
 
302
        /* sent correct event */
 
303
        if (lid_is_closed)
 
304
                gpm_button_emit_type (button, GPM_BUTTON_LID_CLOSED);
 
305
        else
 
306
                gpm_button_emit_type (button, GPM_BUTTON_LID_OPEN);
 
307
}
 
308
 
 
309
/**
 
310
 * gpm_button_init:
 
311
 * @button: This class instance
 
312
 **/
 
313
static void
 
314
gpm_button_init (GpmButton *button)
 
315
{
 
316
        button->priv = GPM_BUTTON_GET_PRIVATE (button);
 
317
 
 
318
        button->priv->screen = gdk_screen_get_default ();
 
319
        button->priv->window = gdk_screen_get_root_window (button->priv->screen);
 
320
 
 
321
        button->priv->keysym_to_name_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
 
322
        button->priv->last_button = NULL;
 
323
        button->priv->timer = g_timer_new ();
 
324
 
 
325
        button->priv->lid_is_closed = FALSE;
 
326
        button->priv->client = dkp_client_new ();
 
327
        g_signal_connect (button->priv->client, "changed",
 
328
                          G_CALLBACK (gpm_button_client_changed_cb), button);
 
329
 
 
330
        /* register the brightness keys */
 
331
        gpm_button_xevent_key (button, XF86XK_PowerOff, GPM_BUTTON_POWER);
 
332
#ifdef HAVE_XF86XK_SUSPEND
 
333
        /* The kernel messes up suspend/hibernate in some places. One of
 
334
         * them is the key names. Unfortunately, they refuse to see the
 
335
         * errors of their way in the name of 'compatibility'. Meh
 
336
         */
 
337
        gpm_button_xevent_key (button, XF86XK_Suspend, GPM_BUTTON_HIBERNATE);
 
338
#endif
 
339
        gpm_button_xevent_key (button, XF86XK_Sleep, GPM_BUTTON_SUSPEND); /* should be configurable */
 
340
#ifdef HAVE_XF86XK_HIBERNATE
 
341
        gpm_button_xevent_key (button, XF86XK_Hibernate, GPM_BUTTON_HIBERNATE);
 
342
#endif
 
343
        gpm_button_xevent_key (button, XF86XK_MonBrightnessUp, GPM_BUTTON_BRIGHT_UP);
 
344
        gpm_button_xevent_key (button, XF86XK_MonBrightnessDown, GPM_BUTTON_BRIGHT_DOWN);
 
345
        gpm_button_xevent_key (button, XF86XK_ScreenSaver, GPM_BUTTON_LOCK);
 
346
#ifdef HAVE_XF86XK_BATTERY
 
347
        gpm_button_xevent_key (button, XF86XK_Battery, GPM_BUTTON_BATTERY);
 
348
#endif
 
349
        gpm_button_xevent_key (button, XF86XK_KbdBrightnessUp, GPM_BUTTON_KBD_BRIGHT_UP);
 
350
        gpm_button_xevent_key (button, XF86XK_KbdBrightnessDown, GPM_BUTTON_KBD_BRIGHT_DOWN);
 
351
        gpm_button_xevent_key (button, XF86XK_KbdLightOnOff, GPM_BUTTON_KBD_BRIGHT_TOGGLE);
 
352
 
 
353
        /* use global filter */
 
354
        gdk_window_add_filter (button->priv->window,
 
355
                               gpm_button_filter_x_events, (gpointer) button);
 
356
}
 
357
 
 
358
/**
 
359
 * gpm_button_finalize:
 
360
 * @object: This class instance
 
361
 **/
 
362
static void
 
363
gpm_button_finalize (GObject *object)
 
364
{
 
365
        GpmButton *button;
 
366
        g_return_if_fail (object != NULL);
 
367
        g_return_if_fail (GPM_IS_BUTTON (object));
 
368
 
 
369
        button = GPM_BUTTON (object);
 
370
        button->priv = GPM_BUTTON_GET_PRIVATE (button);
 
371
 
 
372
        g_object_unref (button->priv->client);
 
373
        g_free (button->priv->last_button);
 
374
        g_timer_destroy (button->priv->timer);
 
375
 
 
376
        g_hash_table_unref (button->priv->keysym_to_name_hash);
 
377
 
 
378
        G_OBJECT_CLASS (gpm_button_parent_class)->finalize (object);
 
379
}
 
380
 
 
381
/**
 
382
 * gpm_button_new:
 
383
 * Return value: new class instance.
 
384
 **/
 
385
GpmButton *
 
386
gpm_button_new (void)
 
387
{
 
388
        if (gpm_button_object != NULL) {
 
389
                g_object_ref (gpm_button_object);
 
390
        } else {
 
391
                gpm_button_object = g_object_new (GPM_TYPE_BUTTON, NULL);
 
392
                g_object_add_weak_pointer (gpm_button_object, &gpm_button_object);
 
393
        }
 
394
        return GPM_BUTTON (gpm_button_object);
 
395
}