Improve some sieve-related translations
[claws.git] / src / plugins / notification / gtkhotkey / gtk-hotkey-key-file-registry.c
blobbe1aa9fb382d28ecc48c5bcd0f6df1dd71a61398
1 /*
2 * This file is part of GtkHotkey.
3 * Copyright Mikkel Kamstrup Erlandsen, March, 2008
5 * GtkHotkey is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * GtkHotkey is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with GtkHotkey. If not, see <http://www.gnu.org/licenses/>.
19 #include "config.h"
21 #include "utils.h"
23 #include "gtk-hotkey-key-file-registry.h"
24 #include "gtk-hotkey-utils.h"
26 #include <gio/gio.h>
27 #include <gio/gdesktopappinfo.h>
29 enum {
30 GTK_HOTKEY_KEY_FILE_REGISTRY_DUMMY_PROPERTY
33 /* Beware - the lengths of these strings are hardcoded throughout
34 * this file (sorry) */
35 #define HOTKEY_HOME "~/.config/hotkeys"
36 #define HOTKEY_FILE_EXT ".hotkeys"
37 #define HOTKEY_GROUP "hotkey:"
39 static GtkHotkeyInfo* gtk_hotkey_key_file_registry_real_get_hotkey (GtkHotkeyRegistry *base,
40 const char *app_id,
41 const char *key_id,
42 GError **error);
44 static GList* gtk_hotkey_key_file_registry_real_get_application_hotkeys
45 (GtkHotkeyRegistry *base,
46 const char *app_id,
47 GError **error);
49 static GList* gtk_hotkey_key_file_registry_real_get_all_hotkeys
50 (GtkHotkeyRegistry *base);
52 static gboolean gtk_hotkey_key_file_registry_real_store_hotkey(GtkHotkeyRegistry *base,
53 GtkHotkeyInfo *info,
54 GError **error);
56 static gboolean gtk_hotkey_key_file_registry_real_delete_hotkey
57 (GtkHotkeyRegistry *base,
58 const gchar *app_id,
59 const gchar *key_id,
60 GError **error);
62 static gboolean gtk_hotkey_key_file_registry_real_has_hotkey (GtkHotkeyRegistry *base,
63 const gchar *app_id,
64 const gchar *key_id);
66 static GFile* get_hotkey_home (void);
68 static GFile* get_hotkey_file (const gchar *app_id);
70 static GKeyFile* get_hotkey_key_file (const gchar *app_id,
71 GError **error);
73 static GtkHotkeyInfo* get_hotkey_info_from_key_file (GKeyFile *keyfile,
74 const gchar *app_id,
75 const gchar *key_id,
76 GError **error);
78 static GList* get_all_hotkey_infos_from_key_file (GKeyFile *keyfile,
79 const gchar *app_id);
81 static gpointer gtk_hotkey_key_file_registry_parent_class = NULL;
84 static
85 GtkHotkeyInfo*
86 gtk_hotkey_key_file_registry_real_get_hotkey (GtkHotkeyRegistry *base,
87 const char *app_id,
88 const char *key_id,
89 GError **error)
91 GKeyFile *keyfile = NULL;
92 GtkHotkeyInfo *info = NULL;
94 g_return_val_if_fail (GTK_HOTKEY_IS_KEY_FILE_REGISTRY(base), NULL);
95 g_return_val_if_fail (app_id != NULL, NULL);
96 g_return_val_if_fail (key_id != NULL, NULL);
98 keyfile = get_hotkey_key_file (app_id, error);
99 if (keyfile == NULL)
100 goto clean_up;
102 info = get_hotkey_info_from_key_file (keyfile, app_id, key_id, error);
104 clean_up:
105 if (keyfile) g_key_file_free (keyfile);
107 return info;
112 static GList*
113 gtk_hotkey_key_file_registry_real_get_application_hotkeys (GtkHotkeyRegistry *base,
114 const char *app_id,
115 GError **error)
117 GKeyFile *keyfile;
119 g_return_val_if_fail (app_id != NULL, NULL);
121 keyfile = get_hotkey_key_file (app_id, error);
123 if (keyfile == NULL)
124 return NULL; /* error is set by get_hotkey_key_file() */
126 return get_all_hotkey_infos_from_key_file (keyfile, app_id);
130 static GList*
131 gtk_hotkey_key_file_registry_real_get_all_hotkeys (GtkHotkeyRegistry *base)
133 GFile *home;
134 GFileEnumerator *dir;
135 GFileInfo *file_info;
136 GError *error;
137 GList *result = NULL;
139 home = get_hotkey_home ();
141 error = NULL;
142 dir = g_file_enumerate_children (home, G_FILE_ATTRIBUTE_STANDARD_NAME,
143 0, NULL, &error);
144 if (error) {
145 gchar *path = g_file_get_path (home);
146 g_critical ("Failed to read hotkey home directory '%s': %s",
147 path, error->message);
148 g_free (path);
149 g_error_free (error);
150 return NULL;
153 error = NULL;
154 while ((file_info = g_file_enumerator_next_file (dir, NULL, &error)) != NULL) {
155 const gchar *filename;
156 GFile *file;
157 GString *app_id;
158 GList *app_hotkeys;
160 filename = g_file_info_get_name(file_info);
162 if (g_str_has_suffix (filename, HOTKEY_FILE_EXT)) {
163 file = g_file_get_child (home, filename);
165 /* Extract app_id from file name */
166 app_id = g_string_new (filename);
167 g_string_erase (app_id, app_id->len - 8, 8);
169 /* Load all hotkeys from the file, and append it to
170 * the total result */
171 app_hotkeys = gtk_hotkey_registry_get_application_hotkeys (base,
172 app_id->str,
173 &error);
174 if (error) {
175 g_warning("failed to read hotkeys for application '%s': %s",
176 app_id->str, error->message);
177 g_error_free (error);
178 error = NULL;
179 } else {
180 result = g_list_concat (result, app_hotkeys);
183 g_string_free (app_id, TRUE);
184 g_object_unref (file);
187 g_object_unref (file_info);
190 if (error) {
191 gchar *path = g_file_get_path (home);
192 g_warning("failed to read hotkey home directory '%s': %s",
193 path, error->message);
194 g_free (path);
195 g_error_free (error);
199 g_object_unref (dir);
200 g_object_unref (home);
202 return result;
206 static gboolean
207 gtk_hotkey_key_file_registry_real_store_hotkey (GtkHotkeyRegistry *base,
208 GtkHotkeyInfo *info,
209 GError **error)
211 GKeyFile *keyfile;
212 GFile *file, *home;
213 GError *tmp_error;
214 gchar *file_path, *group = NULL;
217 g_return_val_if_fail (GTK_HOTKEY_IS_INFO (info), FALSE);
218 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
220 /* Make sure we have our root dir */
221 home = get_hotkey_home ();
222 if (!g_file_query_exists(home, NULL)) {
223 tmp_error = NULL;
224 if (!g_file_make_directory (home, NULL, &tmp_error)) {
225 g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR,
226 GTK_HOTKEY_REGISTRY_ERROR_IO,
227 "Failed to create hotkey configuration dir "
228 HOTKEY_HOME": %s", tmp_error->message);
229 g_error_free (tmp_error);
230 g_object_unref (home);
231 return FALSE;
235 /* Now load any old contents of the keyfile */
236 file = get_hotkey_file (gtk_hotkey_info_get_application_id (info));
237 file_path = g_file_get_path (file);
238 keyfile = g_key_file_new ();
240 tmp_error = NULL;
241 if (!g_key_file_load_from_file (keyfile, file_path, 0, &tmp_error)) {
242 if (tmp_error->code == G_KEY_FILE_ERROR_PARSE) {
243 g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR,
244 GTK_HOTKEY_REGISTRY_ERROR_MALFORMED_MEDIUM,
245 "The file %s is not in a valid key-file format: %s",
246 file_path, tmp_error->message);
247 goto clean_up;
249 /* Ignore other errors */
250 g_error_free (tmp_error);
253 /* Prepare keyfile data */
254 group = g_strconcat (HOTKEY_GROUP, gtk_hotkey_info_get_key_id (info), NULL);
256 g_key_file_set_string (keyfile, group, "Owner",
257 gtk_hotkey_info_get_application_id (info));
258 g_key_file_set_string (keyfile, group, "Signature",
259 gtk_hotkey_info_get_signature (info));
261 if (gtk_hotkey_info_get_description (info))
262 g_key_file_set_string (keyfile, group, "Description",
263 gtk_hotkey_info_get_description (info));
265 if (gtk_hotkey_info_get_app_info (info)) {
266 GAppInfo *ai = gtk_hotkey_info_get_app_info (info);
267 g_key_file_set_string (keyfile, group, "AppInfo",
268 g_app_info_get_id (ai));
271 gsize size;
272 gchar *contents;
273 tmp_error = NULL;
274 contents = g_key_file_to_data (keyfile, &size, &tmp_error);
275 if (tmp_error) {
276 g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR,
277 GTK_HOTKEY_REGISTRY_ERROR_UNKNOWN,
278 "Failed to generate keyfile contents: %s",
279 tmp_error->message);
280 goto clean_up;
283 /* Write the actual data */
284 g_file_set_contents (file_path, contents, size, &tmp_error);
285 if (tmp_error) {
286 g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR,
287 GTK_HOTKEY_REGISTRY_ERROR_IO,
288 "Failed to write keyfile '%s': %s",
289 file_path, tmp_error->message);
290 goto clean_up;
293 clean_up:
294 if (tmp_error) g_error_free (tmp_error);
295 g_free (file_path);
296 if (group) g_free (group);
297 g_key_file_free (keyfile);
298 g_object_unref (file);
299 g_object_unref (home);
301 if (*error)
302 return FALSE;
304 g_return_val_if_fail (GTK_HOTKEY_IS_INFO (info), FALSE);
305 gtk_hotkey_registry_hotkey_stored (base, info);
306 return TRUE;
309 static gboolean
310 gtk_hotkey_key_file_registry_real_delete_hotkey (GtkHotkeyRegistry *base,
311 const gchar *app_id,
312 const gchar *key_id,
313 GError **error)
315 GtkHotkeyInfo *info = NULL;
316 GFile *file;
317 GKeyFile *keyfile;
318 GError *tmp_error;
319 gboolean is_error = FALSE;
320 gchar *path, *group;
322 g_return_val_if_fail (app_id != NULL, FALSE);
323 g_return_val_if_fail (key_id != NULL, FALSE);
324 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
326 group = NULL;
328 file = get_hotkey_file (app_id);
329 g_return_val_if_fail (G_IS_FILE(file), FALSE);
331 path = g_file_get_path (file);
332 keyfile = g_key_file_new ();
334 /* Load the old keyfile */
335 tmp_error = NULL;
336 g_key_file_load_from_file (keyfile, path, 0, &tmp_error);
337 if (tmp_error) {
338 if ((tmp_error->domain == G_FILE_ERROR &&
339 tmp_error->code == G_FILE_ERROR_NOENT) ||
340 (tmp_error->domain == G_KEY_FILE_ERROR &&
341 tmp_error->code == G_KEY_FILE_ERROR_NOT_FOUND))
342 g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR,
343 GTK_HOTKEY_REGISTRY_ERROR_UNKNOWN_APP,
344 "No such keyfile '%s'. Application '%s' has not "
345 "registered any hotkeys",
346 path, app_id);
347 else
348 g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR,
349 GTK_HOTKEY_REGISTRY_ERROR_IO,
350 "Failed to load keyfile '%s': %s",
351 app_id, tmp_error->message);
352 is_error = TRUE;
353 goto clean_up;
356 /* Get a ref to the GtkHotkeyInfo so that we can emit it with the
357 * hotkey-deleted signal */
358 tmp_error = NULL;
359 info = get_hotkey_info_from_key_file (keyfile, app_id, key_id, error);
360 if (info == NULL) {
361 is_error = TRUE;
362 goto clean_up;
365 /* Remove the group for key_id */
366 group = g_strconcat (HOTKEY_GROUP, key_id, NULL);
367 tmp_error = NULL;
368 g_key_file_remove_group (keyfile, group, &tmp_error);
369 if (tmp_error) {
370 if (tmp_error->domain == G_KEY_FILE_ERROR &&
371 tmp_error->code == G_KEY_FILE_ERROR_GROUP_NOT_FOUND)
372 g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR,
373 GTK_HOTKEY_REGISTRY_ERROR_UNKNOWN_APP,
374 "Application '%s' has not registered a hotkey with"
375 "id '%s'", app_id, key_id);
376 else
377 g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR,
378 GTK_HOTKEY_REGISTRY_ERROR_UNKNOWN,
379 "Failed to delete hotkey '%s' from application %s: %s",
380 key_id, app_id, tmp_error->message);
381 is_error = TRUE;
382 goto clean_up;
385 /* Check if the keyfile is empty. If it is we delete it */
386 gsize count;
387 GStrv groups;
388 groups = g_key_file_get_groups (keyfile, &count);
389 g_strfreev (groups);
390 if (count == 0) {
391 tmp_error = NULL;
392 g_file_delete (file, NULL, &tmp_error);
394 if (tmp_error) {
395 g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR,
396 GTK_HOTKEY_REGISTRY_ERROR_IO,
397 "Failed to delete empty keyfile '%s': %s",
398 path, tmp_error->message);
399 is_error = TRUE;
401 /* File deleted, we should just clean up and exit */
402 goto clean_up;
405 /* Write new keyfile */
406 gsize size;
407 gchar *contents;
408 tmp_error = NULL;
409 contents = g_key_file_to_data (keyfile, &size, &tmp_error);
410 if (tmp_error) {
411 g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR,
412 GTK_HOTKEY_REGISTRY_ERROR_UNKNOWN,
413 "Failed to generate keyfile contents: %s",
414 tmp_error->message);
415 is_error = TRUE;
416 goto clean_up;
419 tmp_error = NULL;
420 if (g_file_set_contents (path, contents, size, &tmp_error) != TRUE)
421 FILE_OP_ERROR(path, "g_file_set_contents");
422 if (tmp_error) {
423 g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR,
424 GTK_HOTKEY_REGISTRY_ERROR_IO,
425 "Failed to write keyfile '%s': %s",
426 path, tmp_error->message);
427 is_error = TRUE;
428 goto clean_up;
431 clean_up:
432 if (tmp_error) g_error_free (tmp_error);
433 g_object_unref (file);
434 g_free (path);
435 if (group) g_free (group);
436 g_key_file_free (keyfile);
438 if (is_error)
439 return FALSE;
441 gtk_hotkey_registry_hotkey_deleted (base, info);
442 g_object_unref (info);
443 return TRUE;
446 static gboolean
447 gtk_hotkey_key_file_registry_real_has_hotkey (GtkHotkeyRegistry *base,
448 const gchar *app_id,
449 const gchar *key_id)
451 GFile *file;
452 gboolean exists;
454 g_return_val_if_fail (app_id != NULL, FALSE);
455 g_return_val_if_fail (key_id != NULL, FALSE);
457 file = get_hotkey_file (app_id);
458 g_return_val_if_fail (G_IS_FILE(file), FALSE);
460 if (g_file_query_exists (file, NULL))
461 exists = TRUE;
462 else
463 exists = FALSE;
465 g_object_unref (file);
466 return exists;
469 static void
470 gtk_hotkey_key_file_registry_class_init (GtkHotkeyKeyFileRegistryClass *klass)
472 gtk_hotkey_key_file_registry_parent_class = g_type_class_peek_parent (klass);
473 GTK_HOTKEY_REGISTRY_CLASS (klass)->get_hotkey = gtk_hotkey_key_file_registry_real_get_hotkey;
474 GTK_HOTKEY_REGISTRY_CLASS (klass)->get_application_hotkeys = gtk_hotkey_key_file_registry_real_get_application_hotkeys;
475 GTK_HOTKEY_REGISTRY_CLASS (klass)->get_all_hotkeys = gtk_hotkey_key_file_registry_real_get_all_hotkeys;
476 GTK_HOTKEY_REGISTRY_CLASS (klass)->store_hotkey = gtk_hotkey_key_file_registry_real_store_hotkey;
477 GTK_HOTKEY_REGISTRY_CLASS (klass)->delete_hotkey = gtk_hotkey_key_file_registry_real_delete_hotkey;
478 GTK_HOTKEY_REGISTRY_CLASS (klass)->has_hotkey = gtk_hotkey_key_file_registry_real_has_hotkey;
482 static void
483 gtk_hotkey_key_file_registry_init (GtkHotkeyKeyFileRegistry *self)
488 static void
489 gtk_hotkey_key_file_registry_finalize (GtkHotkeyKeyFileRegistry *self)
494 GType
495 gtk_hotkey_key_file_registry_get_type (void)
497 static GType gtk_hotkey_key_file_registry_type_id = 0;
499 if (G_UNLIKELY (gtk_hotkey_key_file_registry_type_id == 0)) {
500 static const GTypeInfo g_define_type_info = {
501 sizeof (GtkHotkeyKeyFileRegistryClass),
502 (GBaseInitFunc) gtk_hotkey_key_file_registry_init,
503 (GBaseFinalizeFunc) gtk_hotkey_key_file_registry_finalize,
504 (GClassInitFunc) gtk_hotkey_key_file_registry_class_init,
505 (GClassFinalizeFunc) NULL,
506 NULL,
507 sizeof (GtkHotkeyKeyFileRegistry),
509 (GInstanceInitFunc) gtk_hotkey_key_file_registry_init,
510 (const GTypeValueTable *) NULL /* value table */
513 gtk_hotkey_key_file_registry_type_id = g_type_register_static (GTK_HOTKEY_TYPE_STORAGE, "GtkHotkeyKeyFileRegistry", &g_define_type_info, 0);
515 return gtk_hotkey_key_file_registry_type_id;
518 static GFile*
519 get_hotkey_home (void)
521 GFile *home;
523 home = g_file_parse_name (HOTKEY_HOME);
525 if (g_file_query_exists(home, NULL) &&
526 !gtk_hotkey_g_file_is_directory(home)) {
527 g_critical (HOTKEY_HOME" exists but is not a directory");
528 g_object_unref (home);
529 return NULL;
532 return home;
535 /* It is not guaranteed that the keyfile exists */
536 static GFile*
537 get_hotkey_file (const gchar *app_id)
539 GFile *home, *file;
540 gchar *filename;
542 g_return_val_if_fail (app_id != NULL, NULL);
544 home = get_hotkey_home();
545 g_return_val_if_fail (home != NULL, NULL);
547 filename = g_strconcat (app_id, HOTKEY_FILE_EXT, NULL);
548 file = g_file_get_child (home, filename);
550 g_object_unref (home);
551 g_free (filename);
552 return file;
555 static GKeyFile*
556 get_hotkey_key_file (const gchar *app_id, GError **error)
558 gchar *path;
559 GFile *file;
560 GKeyFile *keyfile = NULL;
561 GError *tmp_error;
563 g_return_val_if_fail (app_id != NULL, NULL);
564 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
566 file = get_hotkey_file (app_id);
567 if (!g_file_query_exists (file, NULL)) {
568 g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR,
569 GTK_HOTKEY_REGISTRY_ERROR_UNKNOWN_APP,
570 "Application '%s' has not registered any hotkeys", app_id);
571 g_object_unref (file);
572 return NULL;
575 path = g_file_get_path (file);
576 keyfile = g_key_file_new ();
578 tmp_error = NULL;
579 g_key_file_load_from_file (keyfile, path, 0, &tmp_error);
580 if (tmp_error) {
581 g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR,
582 GTK_HOTKEY_REGISTRY_ERROR_IO,
583 "Failed to load keyfile '%s': %s", path, tmp_error->message);
584 goto clean_up;
587 clean_up:
588 g_free (path);
589 g_object_unref (file);
590 if (tmp_error) g_error_free (tmp_error);
592 if (*error) {
593 g_key_file_free (keyfile);
594 return NULL;
597 return keyfile;
600 static GtkHotkeyInfo*
601 get_hotkey_info_from_key_file (GKeyFile *keyfile,
602 const gchar *app_id,
603 const gchar *key_id,
604 GError **error)
606 GtkHotkeyInfo *info = NULL;
607 gchar *group, *description, *app_info_id, *signature;
608 GAppInfo *app_info = NULL;
610 g_return_val_if_fail (keyfile != NULL, NULL);
611 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
612 g_return_val_if_fail (app_id != NULL, NULL);
613 g_return_val_if_fail (key_id != NULL, NULL);
615 group = g_strconcat (HOTKEY_GROUP, key_id, NULL);
616 description = g_key_file_get_string (keyfile, group, "Description", NULL);
617 app_info_id = g_key_file_get_string (keyfile, group, "AppInfo", NULL);
618 signature = g_key_file_get_string (keyfile, group, "Signature", NULL);
620 if (!g_key_file_has_group (keyfile, group)) {
621 g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR,
622 GTK_HOTKEY_REGISTRY_ERROR_UNKNOWN_KEY,
623 "Keyfile has no group "HOTKEY_GROUP"%s", key_id);
624 goto clean_up;
627 if (!signature) {
628 g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR,
629 GTK_HOTKEY_REGISTRY_ERROR_BAD_SIGNATURE,
630 "No 'Signature' defined for hotkey '%s' for application '%s'",
631 key_id, app_id);
632 goto clean_up;
635 if (app_info_id) {
636 app_info = G_APP_INFO(g_desktop_app_info_new (app_info_id));
637 if (!G_IS_APP_INFO(app_info)) {
638 g_set_error (error, GTK_HOTKEY_REGISTRY_ERROR,
639 GTK_HOTKEY_REGISTRY_ERROR_MISSING_APP,
640 "Keyfile referring to 'AppInfo = %s', but no application"
641 "by that id is registered on the system", app_info_id);
642 goto clean_up;
646 info = gtk_hotkey_info_new (app_id, key_id, signature, app_info);
647 if (description)
648 gtk_hotkey_info_set_description (info, description);
650 clean_up:
651 g_free (group);
652 if (signature) g_free (signature);
653 if (description) g_free (description);
654 if (app_info_id) g_free (app_info_id);
655 if (app_info) g_object_unref (app_info);
657 return info;
660 static GList*
661 get_all_hotkey_infos_from_key_file (GKeyFile *keyfile,
662 const gchar *app_id)
664 GList *hotkeys;
665 GtkHotkeyInfo *hotkey;
666 GStrv groups;
667 gsize count;
668 gchar *group;
669 GString *key_id;
670 GError *error;
672 g_return_val_if_fail (keyfile != NULL, NULL);
673 g_return_val_if_fail (app_id != NULL, NULL);
675 hotkeys = NULL;
676 groups = g_key_file_get_groups (keyfile, &count);
678 int i;
679 for (i = 0; i < count; i++) {
680 group = groups[i];
681 key_id = g_string_new (group);
683 /* Ignore non hotkey groups */
684 if (!g_str_has_prefix (key_id->str, HOTKEY_GROUP)) {
685 g_warning("hotkey file for %s contains non 'hotkey:' group '%s'",
686 app_id, group);
687 g_string_free (key_id, TRUE);
688 continue;
691 /* Strip 'hotkey:' prefix from key_id */
692 g_string_erase (key_id, 0, 7);
694 error = NULL;
695 hotkey = get_hotkey_info_from_key_file (keyfile, app_id, key_id->str, &error);
696 if (error) {
697 g_warning("failed to read hotkey '%s' for application '%s': %s",
698 key_id->str, app_id, error->message);
699 g_error_free (error);
700 g_string_free (key_id, TRUE);
701 continue;
704 hotkeys = g_list_prepend (hotkeys, hotkey);
706 g_string_free (key_id, TRUE);
709 g_strfreev (groups);
710 return hotkeys;