File: | capplets/keybindings/cafe-keybinding-properties.c |
Warning: | line 1208, column 51 Access to field 'message' results in a dereference of a null pointer (loaded from variable 'err') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* This program was written with lots of love under the GPL by Jonathan | |||
2 | * Blandford <jrb@gnome.org> | |||
3 | */ | |||
4 | ||||
5 | #include <config.h> | |||
6 | ||||
7 | #include <stdlib.h> | |||
8 | #include <string.h> | |||
9 | #include <ctk/ctk.h> | |||
10 | #include <gio/gio.h> | |||
11 | #include <cdk/cdkx.h> | |||
12 | #include <X11/Xatom.h> | |||
13 | #include <glib/gi18n.h> | |||
14 | #include <cdk/cdkkeysyms.h> | |||
15 | ||||
16 | #include "wm-common.h" | |||
17 | #include "capplet-util.h" | |||
18 | #include "eggcellrendererkeys.h" | |||
19 | #include "activate-settings-daemon.h" | |||
20 | #include "dconf-util.h" | |||
21 | ||||
22 | #define GSETTINGS_KEYBINDINGS_DIR"/org/cafe/desktop/keybindings/" "/org/cafe/desktop/keybindings/" | |||
23 | #define CUSTOM_KEYBINDING_SCHEMA"org.cafe.control-center.keybinding" "org.cafe.control-center.keybinding" | |||
24 | ||||
25 | #define MAX_ELEMENTS_BEFORE_SCROLLING10 10 | |||
26 | #define MAX_CUSTOM_SHORTCUTS1000 1000 | |||
27 | #define RESPONSE_ADD0 0 | |||
28 | #define RESPONSE_REMOVE1 1 | |||
29 | ||||
30 | typedef struct { | |||
31 | /* The untranslated name, combine with ->package to translate */ | |||
32 | char *name; | |||
33 | /* The gettext package to use to translate the section title */ | |||
34 | char *package; | |||
35 | /* Name of the window manager the keys would apply to */ | |||
36 | char *wm_name; | |||
37 | /* The GSettings schema for the whole file */ | |||
38 | char *schema; | |||
39 | /* an array of KeyListEntry */ | |||
40 | GArray *entries; | |||
41 | } KeyList; | |||
42 | ||||
43 | typedef enum { | |||
44 | COMPARISON_NONE = 0, | |||
45 | COMPARISON_GT, | |||
46 | COMPARISON_LT, | |||
47 | COMPARISON_EQ | |||
48 | } Comparison; | |||
49 | ||||
50 | typedef struct | |||
51 | { | |||
52 | char *gsettings_path; | |||
53 | char *schema; | |||
54 | char *name; | |||
55 | int value; | |||
56 | char *value_schema; /* gsettings schema for key/value */ | |||
57 | char *value_key; | |||
58 | char *description; | |||
59 | char *description_key; | |||
60 | char *cmd_key; | |||
61 | Comparison comparison; | |||
62 | } KeyListEntry; | |||
63 | ||||
64 | enum | |||
65 | { | |||
66 | DESCRIPTION_COLUMN, | |||
67 | KEYENTRY_COLUMN, | |||
68 | N_COLUMNS | |||
69 | }; | |||
70 | ||||
71 | typedef struct | |||
72 | { | |||
73 | GSettings *settings; | |||
74 | char *gsettings_path; | |||
75 | char *gsettings_key; | |||
76 | guint keyval; | |||
77 | guint keycode; | |||
78 | EggVirtualModifierType mask; | |||
79 | gboolean editable; | |||
80 | CtkTreeModel *model; | |||
81 | char *description; | |||
82 | char *desc_gsettings_key; | |||
83 | gboolean desc_editable; | |||
84 | char *command; | |||
85 | char *cmd_gsettings_key; | |||
86 | gboolean cmd_editable; | |||
87 | gulong gsettings_cnxn; | |||
88 | gulong gsettings_cnxn_desc; | |||
89 | gulong gsettings_cnxn_cmd; | |||
90 | } KeyEntry; | |||
91 | ||||
92 | static gboolean block_accels = FALSE(0); | |||
93 | static CtkWidget *custom_shortcut_dialog = NULL((void*)0); | |||
94 | static CtkWidget *custom_shortcut_name_entry = NULL((void*)0); | |||
95 | static CtkWidget *custom_shortcut_command_entry = NULL((void*)0); | |||
96 | ||||
97 | static CtkWidget* _ctk_builder_get_widget(CtkBuilder* builder, const gchar* name) | |||
98 | { | |||
99 | return CTK_WIDGET (ctk_builder_get_object (builder, name))((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((ctk_builder_get_object (builder, name))), ((ctk_widget_get_type ())))))); | |||
100 | } | |||
101 | ||||
102 | static CtkBuilder * | |||
103 | create_builder (void) | |||
104 | { | |||
105 | CtkBuilder *builder = ctk_builder_new(); | |||
106 | GError *error = NULL((void*)0); | |||
107 | ||||
108 | if (ctk_builder_add_from_resource (builder, "/org/cafe/ccc/keybindings/cafe-keybinding-properties.ui", &error) == 0) { | |||
109 | g_warning ("Could not load UI: %s", error->message); | |||
110 | g_error_free (error); | |||
111 | g_object_unref (builder); | |||
112 | builder = NULL((void*)0); | |||
113 | } | |||
114 | ||||
115 | return builder; | |||
116 | } | |||
117 | ||||
118 | static char* binding_name(guint keyval, guint keycode, EggVirtualModifierType mask, gboolean translate) | |||
119 | { | |||
120 | if (keyval != 0 || keycode != 0) | |||
121 | { | |||
122 | if (translate) | |||
123 | { | |||
124 | return egg_virtual_accelerator_label (keyval, keycode, mask); | |||
125 | } | |||
126 | else | |||
127 | { | |||
128 | return egg_virtual_accelerator_name (keyval, keycode, mask); | |||
129 | } | |||
130 | } | |||
131 | else | |||
132 | { | |||
133 | return g_strdup (translate ? _("Disabled") : "")g_strdup_inline (translate ? gettext ("Disabled") : ""); | |||
134 | } | |||
135 | } | |||
136 | ||||
137 | static gboolean | |||
138 | binding_from_string (const char *str, | |||
139 | guint *accelerator_key, | |||
140 | guint *keycode, | |||
141 | EggVirtualModifierType *accelerator_mods) | |||
142 | { | |||
143 | g_return_val_if_fail (accelerator_key != NULL, FALSE)do { if ((accelerator_key != ((void*)0))) { } else { g_return_if_fail_warning ("keybinding-properties", ((const char*) (__func__)), "accelerator_key != NULL" ); return ((0)); } } while (0); | |||
144 | ||||
145 | if (str == NULL((void*)0) || strcmp (str, "disabled") == 0) | |||
146 | { | |||
147 | *accelerator_key = 0; | |||
148 | *keycode = 0; | |||
149 | *accelerator_mods = 0; | |||
150 | return TRUE(!(0)); | |||
151 | } | |||
152 | ||||
153 | egg_accelerator_parse_virtual (str, accelerator_key, keycode, accelerator_mods); | |||
154 | ||||
155 | if (*accelerator_key == 0) | |||
156 | return FALSE(0); | |||
157 | else | |||
158 | return TRUE(!(0)); | |||
159 | } | |||
160 | ||||
161 | static void | |||
162 | accel_set_func (CtkTreeViewColumn *tree_column, | |||
163 | CtkCellRenderer *cell, | |||
164 | CtkTreeModel *model, | |||
165 | CtkTreeIter *iter, | |||
166 | gpointer data) | |||
167 | { | |||
168 | KeyEntry *key_entry; | |||
169 | ||||
170 | ctk_tree_model_get (model, iter, | |||
171 | KEYENTRY_COLUMN, &key_entry, | |||
172 | -1); | |||
173 | ||||
174 | if (key_entry == NULL((void*)0)) | |||
175 | g_object_set (cell, | |||
176 | "visible", FALSE(0), | |||
177 | NULL((void*)0)); | |||
178 | else if (! key_entry->editable) | |||
179 | g_object_set (cell, | |||
180 | "visible", TRUE(!(0)), | |||
181 | "editable", FALSE(0), | |||
182 | "accel_key", key_entry->keyval, | |||
183 | "accel_mask", key_entry->mask, | |||
184 | "keycode", key_entry->keycode, | |||
185 | "style", PANGO_STYLE_ITALIC, | |||
186 | NULL((void*)0)); | |||
187 | else | |||
188 | g_object_set (cell, | |||
189 | "visible", TRUE(!(0)), | |||
190 | "editable", TRUE(!(0)), | |||
191 | "accel_key", key_entry->keyval, | |||
192 | "accel_mask", key_entry->mask, | |||
193 | "keycode", key_entry->keycode, | |||
194 | "style", PANGO_STYLE_NORMAL, | |||
195 | NULL((void*)0)); | |||
196 | } | |||
197 | ||||
198 | static void | |||
199 | description_set_func (CtkTreeViewColumn *tree_column, | |||
200 | CtkCellRenderer *cell, | |||
201 | CtkTreeModel *model, | |||
202 | CtkTreeIter *iter, | |||
203 | gpointer data) | |||
204 | { | |||
205 | KeyEntry *key_entry; | |||
206 | ||||
207 | ctk_tree_model_get (model, iter, | |||
208 | KEYENTRY_COLUMN, &key_entry, | |||
209 | -1); | |||
210 | ||||
211 | if (key_entry != NULL((void*)0)) | |||
212 | g_object_set (cell, | |||
213 | "editable", FALSE(0), | |||
214 | "text", key_entry->description != NULL((void*)0) ? | |||
215 | key_entry->description : _("<Unknown Action>")gettext ("<Unknown Action>"), | |||
216 | NULL((void*)0)); | |||
217 | else | |||
218 | g_object_set (cell, | |||
219 | "editable", FALSE(0), NULL((void*)0)); | |||
220 | } | |||
221 | ||||
222 | static gboolean | |||
223 | keybinding_key_changed_foreach (CtkTreeModel *model, | |||
224 | CtkTreePath *path, | |||
225 | CtkTreeIter *iter, | |||
226 | gpointer user_data) | |||
227 | { | |||
228 | KeyEntry *key_entry; | |||
229 | KeyEntry *tmp_key_entry; | |||
230 | ||||
231 | key_entry = (KeyEntry *)user_data; | |||
232 | ctk_tree_model_get (key_entry->model, iter, | |||
233 | KEYENTRY_COLUMN, &tmp_key_entry, | |||
234 | -1); | |||
235 | ||||
236 | if (key_entry == tmp_key_entry) | |||
237 | { | |||
238 | ctk_tree_model_row_changed (key_entry->model, path, iter); | |||
239 | return TRUE(!(0)); | |||
240 | } | |||
241 | return FALSE(0); | |||
242 | } | |||
243 | ||||
244 | static void | |||
245 | keybinding_key_changed (GSettings *settings, | |||
246 | gchar *key, | |||
247 | KeyEntry *key_entry) | |||
248 | { | |||
249 | gchar *key_value; | |||
250 | ||||
251 | key_value = g_settings_get_string (settings, key); | |||
252 | ||||
253 | binding_from_string (key_value, &key_entry->keyval, &key_entry->keycode, &key_entry->mask); | |||
254 | key_entry->editable = g_settings_is_writable (settings, key); | |||
255 | ||||
256 | /* update the model */ | |||
257 | ctk_tree_model_foreach (key_entry->model, keybinding_key_changed_foreach, key_entry); | |||
258 | } | |||
259 | ||||
260 | static void | |||
261 | keybinding_description_changed (GSettings *settings, | |||
262 | gchar *key, | |||
263 | KeyEntry *key_entry) | |||
264 | { | |||
265 | gchar *key_value; | |||
266 | ||||
267 | key_value = g_settings_get_string (settings, key); | |||
268 | ||||
269 | g_free (key_entry->description); | |||
270 | key_entry->description = key_value ? g_strdup (key_value)g_strdup_inline (key_value) : NULL((void*)0); | |||
271 | g_free (key_value); | |||
272 | ||||
273 | key_entry->desc_editable = g_settings_is_writable (settings, key); | |||
274 | ||||
275 | /* update the model */ | |||
276 | ctk_tree_model_foreach (key_entry->model, keybinding_key_changed_foreach, key_entry); | |||
277 | } | |||
278 | ||||
279 | static void | |||
280 | keybinding_command_changed (GSettings *settings, | |||
281 | gchar *key, | |||
282 | KeyEntry *key_entry) | |||
283 | { | |||
284 | gchar *key_value; | |||
285 | ||||
286 | key_value = g_settings_get_string (settings, key); | |||
287 | ||||
288 | g_free (key_entry->command); | |||
289 | key_entry->command = key_value ? g_strdup (key_value)g_strdup_inline (key_value) : NULL((void*)0); | |||
290 | key_entry->cmd_editable = g_settings_is_writable (settings, key); | |||
291 | g_free (key_value); | |||
292 | ||||
293 | /* update the model */ | |||
294 | ctk_tree_model_foreach (key_entry->model, keybinding_key_changed_foreach, key_entry); | |||
295 | } | |||
296 | ||||
297 | static int | |||
298 | keyentry_sort_func (CtkTreeModel *model, | |||
299 | CtkTreeIter *a, | |||
300 | CtkTreeIter *b, | |||
301 | gpointer user_data) | |||
302 | { | |||
303 | KeyEntry *key_entry_a; | |||
304 | KeyEntry *key_entry_b; | |||
305 | int retval; | |||
306 | ||||
307 | key_entry_a = NULL((void*)0); | |||
308 | ctk_tree_model_get (model, a, | |||
309 | KEYENTRY_COLUMN, &key_entry_a, | |||
310 | -1); | |||
311 | ||||
312 | key_entry_b = NULL((void*)0); | |||
313 | ctk_tree_model_get (model, b, | |||
314 | KEYENTRY_COLUMN, &key_entry_b, | |||
315 | -1); | |||
316 | ||||
317 | if (key_entry_a && key_entry_b) | |||
318 | { | |||
319 | if ((key_entry_a->keyval || key_entry_a->keycode) && | |||
320 | (key_entry_b->keyval || key_entry_b->keycode)) | |||
321 | { | |||
322 | gchar *name_a, *name_b; | |||
323 | ||||
324 | name_a = binding_name (key_entry_a->keyval, | |||
325 | key_entry_a->keycode, | |||
326 | key_entry_a->mask, | |||
327 | TRUE(!(0))); | |||
328 | ||||
329 | name_b = binding_name (key_entry_b->keyval, | |||
330 | key_entry_b->keycode, | |||
331 | key_entry_b->mask, | |||
332 | TRUE(!(0))); | |||
333 | ||||
334 | retval = g_utf8_collate (name_a, name_b); | |||
335 | ||||
336 | g_free (name_a); | |||
337 | g_free (name_b); | |||
338 | } | |||
339 | else if (key_entry_a->keyval || key_entry_a->keycode) | |||
340 | retval = -1; | |||
341 | else if (key_entry_b->keyval || key_entry_b->keycode) | |||
342 | retval = 1; | |||
343 | else | |||
344 | retval = 0; | |||
345 | } | |||
346 | else if (key_entry_a) | |||
347 | retval = -1; | |||
348 | else if (key_entry_b) | |||
349 | retval = 1; | |||
350 | else | |||
351 | retval = 0; | |||
352 | ||||
353 | return retval; | |||
354 | } | |||
355 | ||||
356 | static void | |||
357 | clear_old_model (CtkBuilder *builder) | |||
358 | { | |||
359 | CtkWidget *tree_view; | |||
360 | CtkWidget *actions_swindow; | |||
361 | CtkTreeModel *model; | |||
362 | ||||
363 | tree_view = _ctk_builder_get_widget (builder, "shortcut_treeview"); | |||
364 | model = ctk_tree_view_get_model (CTK_TREE_VIEW (tree_view)((((CtkTreeView*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((tree_view)), ((ctk_tree_view_get_type ()))))))); | |||
365 | ||||
366 | if (model == NULL((void*)0)) | |||
367 | { | |||
368 | /* create a new model */ | |||
369 | model = (CtkTreeModel *) ctk_tree_store_new (N_COLUMNS, G_TYPE_STRING((GType) ((16) << (2))), G_TYPE_POINTER((GType) ((17) << (2)))); | |||
370 | ||||
371 | ctk_tree_sortable_set_sort_func (CTK_TREE_SORTABLE (model)((((CtkTreeSortable*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((model)), ((ctk_tree_sortable_get_type ())))))), | |||
372 | KEYENTRY_COLUMN, | |||
373 | keyentry_sort_func, | |||
374 | NULL((void*)0), NULL((void*)0)); | |||
375 | ||||
376 | ctk_tree_view_set_model (CTK_TREE_VIEW (tree_view)((((CtkTreeView*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((tree_view)), ((ctk_tree_view_get_type ())))))), model); | |||
377 | ||||
378 | g_object_unref (model); | |||
379 | } | |||
380 | else | |||
381 | { | |||
382 | /* clear the existing model */ | |||
383 | gboolean valid; | |||
384 | CtkTreeIter iter; | |||
385 | KeyEntry *key_entry; | |||
386 | ||||
387 | for (valid = ctk_tree_model_get_iter_first (model, &iter); | |||
388 | valid; | |||
389 | valid = ctk_tree_model_iter_next (model, &iter)) | |||
390 | { | |||
391 | ctk_tree_model_get (model, &iter, | |||
392 | KEYENTRY_COLUMN, &key_entry, | |||
393 | -1); | |||
394 | ||||
395 | if (key_entry != NULL((void*)0)) | |||
396 | { | |||
397 | g_signal_handler_disconnect (key_entry->settings, key_entry->gsettings_cnxn); | |||
398 | if (key_entry->gsettings_cnxn_desc != 0) | |||
399 | g_signal_handler_disconnect (key_entry->settings, key_entry->gsettings_cnxn_desc); | |||
400 | if (key_entry->gsettings_cnxn_cmd != 0) | |||
401 | g_signal_handler_disconnect (key_entry->settings, key_entry->gsettings_cnxn_cmd); | |||
402 | ||||
403 | g_object_unref (key_entry->settings); | |||
404 | if (key_entry->gsettings_path) | |||
405 | g_free (key_entry->gsettings_path); | |||
406 | g_free (key_entry->gsettings_key); | |||
407 | g_free (key_entry->description); | |||
408 | g_free (key_entry->desc_gsettings_key); | |||
409 | g_free (key_entry->command); | |||
410 | g_free (key_entry->cmd_gsettings_key); | |||
411 | g_free (key_entry); | |||
412 | } | |||
413 | } | |||
414 | ||||
415 | ctk_tree_store_clear (CTK_TREE_STORE (model)((((CtkTreeStore*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((model)), ((ctk_tree_store_get_type ()))))))); | |||
416 | } | |||
417 | ||||
418 | actions_swindow = _ctk_builder_get_widget (builder, "actions_swindow"); | |||
419 | ctk_scrolled_window_set_policy (CTK_SCROLLED_WINDOW (actions_swindow)((((CtkScrolledWindow*) (void *) g_type_check_instance_cast ( (GTypeInstance*) ((actions_swindow)), ((ctk_scrolled_window_get_type ())))))), | |||
420 | CTK_POLICY_NEVER, CTK_POLICY_NEVER); | |||
421 | ctk_widget_set_size_request (actions_swindow, -1, -1); | |||
422 | } | |||
423 | ||||
424 | typedef struct { | |||
425 | const char *key; | |||
426 | const char *path; | |||
427 | const char *schema; | |||
428 | gboolean found; | |||
429 | } KeyMatchData; | |||
430 | ||||
431 | static gboolean key_match(CtkTreeModel* model, CtkTreePath* path, CtkTreeIter* iter, gpointer data) | |||
432 | { | |||
433 | KeyMatchData* match_data = data; | |||
434 | KeyEntry* element = NULL((void*)0); | |||
435 | gchar *element_schema = NULL((void*)0); | |||
436 | gchar *element_path = NULL((void*)0); | |||
437 | ||||
438 | ctk_tree_model_get(model, iter, | |||
439 | KEYENTRY_COLUMN, &element, | |||
440 | -1); | |||
441 | ||||
442 | if (element && element->settings && G_IS_SETTINGS(element->settings)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) ( (element->settings)); GType __t = ((g_settings_get_type () )); gboolean __r; if (!__inst) __r = (0); else if (__inst-> g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; }))))) | |||
443 | { | |||
444 | g_object_get (element->settings, "schema-id", &element_schema, NULL((void*)0)); | |||
445 | g_object_get (element->settings, "path", &element_path, NULL((void*)0)); | |||
446 | } | |||
447 | ||||
448 | if (element && g_strcmp0(element->gsettings_key, match_data->key) == 0 | |||
449 | && g_strcmp0(element_schema, match_data->schema) == 0 | |||
450 | && g_strcmp0(element_path, match_data->path) == 0) | |||
451 | { | |||
452 | match_data->found = TRUE(!(0)); | |||
453 | return TRUE(!(0)); | |||
454 | } | |||
455 | ||||
456 | return FALSE(0); | |||
457 | } | |||
458 | ||||
459 | static gboolean key_is_already_shown(CtkTreeModel* model, const KeyListEntry* entry) | |||
460 | { | |||
461 | KeyMatchData data; | |||
462 | ||||
463 | data.key = entry->name; | |||
464 | data.schema = entry->schema; | |||
465 | data.path = entry->gsettings_path; | |||
466 | data.found = FALSE(0); | |||
467 | ctk_tree_model_foreach(model, key_match, &data); | |||
468 | ||||
469 | return data.found; | |||
470 | } | |||
471 | ||||
472 | static gboolean should_show_key(const KeyListEntry* entry) | |||
473 | { | |||
474 | GSettings *settings; | |||
475 | int value; | |||
476 | ||||
477 | if (entry->comparison == COMPARISON_NONE) | |||
478 | { | |||
479 | return TRUE(!(0)); | |||
480 | } | |||
481 | ||||
482 | g_return_val_if_fail(entry->value_key != NULL, FALSE)do { if ((entry->value_key != ((void*)0))) { } else { g_return_if_fail_warning ("keybinding-properties", ((const char*) (__func__)), "entry->value_key != NULL" ); return ((0)); } } while (0); | |||
483 | g_return_val_if_fail(entry->value_schema != NULL, FALSE)do { if ((entry->value_schema != ((void*)0))) { } else { g_return_if_fail_warning ("keybinding-properties", ((const char*) (__func__)), "entry->value_schema != NULL" ); return ((0)); } } while (0); | |||
484 | ||||
485 | settings = g_settings_new (entry->value_schema); | |||
486 | value = g_settings_get_int (settings, entry->value_key); | |||
487 | g_object_unref (settings); | |||
488 | ||||
489 | switch (entry->comparison) | |||
490 | { | |||
491 | case COMPARISON_NONE: | |||
492 | /* For compiler warnings */ | |||
493 | g_assert_not_reached ()do { g_assertion_message_expr ("keybinding-properties", "cafe-keybinding-properties.c" , 493, ((const char*) (__func__)), ((void*)0)); } while (0); | |||
494 | return FALSE(0); | |||
495 | case COMPARISON_GT: | |||
496 | if (value > entry->value) | |||
497 | { | |||
498 | return TRUE(!(0)); | |||
499 | } | |||
500 | break; | |||
501 | case COMPARISON_LT: | |||
502 | if (value < entry->value) | |||
503 | { | |||
504 | return TRUE(!(0)); | |||
505 | } | |||
506 | break; | |||
507 | case COMPARISON_EQ: | |||
508 | if (value == entry->value) | |||
509 | { | |||
510 | return TRUE(!(0)); | |||
511 | } | |||
512 | break; | |||
513 | } | |||
514 | ||||
515 | return FALSE(0); | |||
516 | } | |||
517 | ||||
518 | static gboolean | |||
519 | count_rows_foreach (CtkTreeModel *model, CtkTreePath *path, CtkTreeIter *iter, gpointer data) | |||
520 | { | |||
521 | gint *rows = data; | |||
522 | ||||
523 | (*rows)++; | |||
524 | ||||
525 | return FALSE(0); | |||
526 | } | |||
527 | ||||
528 | static void | |||
529 | ensure_scrollbar (CtkBuilder *builder, int i) | |||
530 | { | |||
531 | if (i == MAX_ELEMENTS_BEFORE_SCROLLING10) | |||
532 | { | |||
533 | CtkRequisition rectangle; | |||
534 | GObject *actions_swindow = ctk_builder_get_object (builder, | |||
535 | "actions_swindow"); | |||
536 | CtkWidget *treeview = _ctk_builder_get_widget (builder, | |||
537 | "shortcut_treeview"); | |||
538 | ctk_widget_get_preferred_size (treeview, &rectangle, NULL((void*)0)); | |||
539 | ctk_widget_set_size_request (treeview, -1, rectangle.height); | |||
540 | ctk_scrolled_window_set_policy (CTK_SCROLLED_WINDOW (actions_swindow)((((CtkScrolledWindow*) (void *) g_type_check_instance_cast ( (GTypeInstance*) ((actions_swindow)), ((ctk_scrolled_window_get_type ())))))), | |||
541 | CTK_POLICY_NEVER, CTK_POLICY_AUTOMATIC); | |||
542 | } | |||
543 | } | |||
544 | ||||
545 | static void | |||
546 | find_section (CtkTreeModel *model, | |||
547 | CtkTreeIter *iter, | |||
548 | const char *title) | |||
549 | { | |||
550 | gboolean success; | |||
551 | ||||
552 | success = ctk_tree_model_get_iter_first (model, iter); | |||
553 | while (success) | |||
554 | { | |||
555 | char *description = NULL((void*)0); | |||
556 | ||||
557 | ctk_tree_model_get (model, iter, | |||
558 | DESCRIPTION_COLUMN, &description, | |||
559 | -1); | |||
560 | ||||
561 | if (g_strcmp0 (description, title) == 0) | |||
562 | return; | |||
563 | success = ctk_tree_model_iter_next (model, iter); | |||
564 | } | |||
565 | ||||
566 | ctk_tree_store_append (CTK_TREE_STORE (model)((((CtkTreeStore*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((model)), ((ctk_tree_store_get_type ())))))), iter, NULL((void*)0)); | |||
567 | ctk_tree_store_set (CTK_TREE_STORE (model)((((CtkTreeStore*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((model)), ((ctk_tree_store_get_type ())))))), iter, | |||
568 | DESCRIPTION_COLUMN, title, | |||
569 | -1); | |||
570 | } | |||
571 | ||||
572 | static void | |||
573 | append_keys_to_tree (CtkBuilder *builder, | |||
574 | const gchar *title, | |||
575 | const gchar *schema, | |||
576 | const gchar *package, | |||
577 | const KeyListEntry *keys_list) | |||
578 | { | |||
579 | CtkTreeIter parent_iter, iter; | |||
580 | CtkTreeModel *model; | |||
581 | gint i, j; | |||
582 | ||||
583 | model = ctk_tree_view_get_model (CTK_TREE_VIEW (ctk_builder_get_object (builder, "shortcut_treeview"))((((CtkTreeView*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((ctk_builder_get_object (builder, "shortcut_treeview"))), ((ctk_tree_view_get_type ()))))))); | |||
584 | ||||
585 | /* Try to find a section parent iter, if it already exists */ | |||
586 | find_section (model, &iter, title); | |||
587 | parent_iter = iter; | |||
588 | ||||
589 | i = 0; | |||
590 | ctk_tree_model_foreach (model, count_rows_foreach, &i); | |||
591 | ||||
592 | /* If the header we just added is the MAX_ELEMENTS_BEFORE_SCROLLING th, | |||
593 | * then we need to scroll now */ | |||
594 | ensure_scrollbar (builder, i - 1); | |||
595 | ||||
596 | for (j = 0; keys_list[j].name != NULL((void*)0); j++) | |||
597 | { | |||
598 | GSettings *settings = NULL((void*)0); | |||
599 | gchar *settings_path; | |||
600 | KeyEntry *key_entry; | |||
601 | const gchar *key_string; | |||
602 | gchar *key_value; | |||
603 | gchar *description; | |||
604 | gchar *command; | |||
605 | ||||
606 | if (!should_show_key (&keys_list[j])) | |||
607 | continue; | |||
608 | ||||
609 | if (key_is_already_shown (model, &keys_list[j])) | |||
610 | continue; | |||
611 | ||||
612 | key_string = keys_list[j].name; | |||
613 | ||||
614 | if (keys_list[j].gsettings_path != NULL((void*)0)) | |||
615 | { | |||
616 | settings = g_settings_new_with_path (schema, keys_list[j].gsettings_path); | |||
617 | settings_path = g_strdup(keys_list[j].gsettings_path)g_strdup_inline (keys_list[j].gsettings_path); | |||
618 | } | |||
619 | else | |||
620 | { | |||
621 | settings = g_settings_new (schema); | |||
622 | settings_path = NULL((void*)0); | |||
623 | } | |||
624 | ||||
625 | if (keys_list[j].description_key != NULL((void*)0)) | |||
626 | { | |||
627 | /* it's a custom shortcut, so description is in gsettings */ | |||
628 | description = g_settings_get_string (settings, keys_list[j].description_key); | |||
629 | } | |||
630 | else | |||
631 | { | |||
632 | /* it's from keyfile, so description need to be translated */ | |||
633 | description = keys_list[j].description; | |||
634 | if (package) | |||
635 | { | |||
636 | bind_textdomain_codeset (package, "UTF-8"); | |||
637 | description = dgettext (package, description); | |||
638 | } | |||
639 | else | |||
640 | { | |||
641 | description = _(description)gettext (description); | |||
642 | } | |||
643 | } | |||
644 | ||||
645 | if (description == NULL((void*)0)) | |||
646 | { | |||
647 | /* Only print a warning for keys that should have a schema */ | |||
648 | if (keys_list[j].description_key == NULL((void*)0)) | |||
649 | g_warning ("No description for key '%s'", key_string); | |||
650 | } | |||
651 | ||||
652 | ||||
653 | ||||
654 | if (keys_list[j].cmd_key != NULL((void*)0)) | |||
655 | { | |||
656 | command = g_settings_get_string (settings, keys_list[j].cmd_key); | |||
657 | } | |||
658 | else | |||
659 | { | |||
660 | command = NULL((void*)0); | |||
661 | } | |||
662 | ||||
663 | key_entry = g_new0 (KeyEntry, 1)((KeyEntry *) g_malloc0_n ((1), sizeof (KeyEntry))); | |||
664 | key_entry->settings = settings; | |||
665 | key_entry->gsettings_path = settings_path; | |||
666 | key_entry->gsettings_key = g_strdup (key_string)g_strdup_inline (key_string); | |||
667 | key_entry->editable = g_settings_is_writable (settings, key_string); | |||
668 | key_entry->model = model; | |||
669 | key_entry->description = description; | |||
670 | key_entry->command = command; | |||
671 | if (keys_list[j].description_key != NULL((void*)0)) | |||
672 | { | |||
673 | key_entry->desc_gsettings_key = g_strdup (keys_list[j].description_key)g_strdup_inline (keys_list[j].description_key); | |||
674 | key_entry->desc_editable = g_settings_is_writable (settings, key_entry->desc_gsettings_key); | |||
675 | gchar *gsettings_signal = g_strconcat ("changed::", key_entry->desc_gsettings_key, NULL((void*)0)); | |||
676 | key_entry->gsettings_cnxn_desc = g_signal_connect (settings,g_signal_connect_data ((settings), (gsettings_signal), (((GCallback ) (keybinding_description_changed))), (key_entry), ((void*)0) , (GConnectFlags) 0) | |||
677 | gsettings_signal,g_signal_connect_data ((settings), (gsettings_signal), (((GCallback ) (keybinding_description_changed))), (key_entry), ((void*)0) , (GConnectFlags) 0) | |||
678 | G_CALLBACK (keybinding_description_changed),g_signal_connect_data ((settings), (gsettings_signal), (((GCallback ) (keybinding_description_changed))), (key_entry), ((void*)0) , (GConnectFlags) 0) | |||
679 | key_entry)g_signal_connect_data ((settings), (gsettings_signal), (((GCallback ) (keybinding_description_changed))), (key_entry), ((void*)0) , (GConnectFlags) 0); | |||
680 | g_free (gsettings_signal); | |||
681 | } | |||
682 | if (keys_list[j].cmd_key != NULL((void*)0)) | |||
683 | { | |||
684 | key_entry->cmd_gsettings_key = g_strdup (keys_list[j].cmd_key)g_strdup_inline (keys_list[j].cmd_key); | |||
685 | key_entry->cmd_editable = g_settings_is_writable (settings, key_entry->cmd_gsettings_key); | |||
686 | gchar *gsettings_signal = g_strconcat ("changed::", key_entry->cmd_gsettings_key, NULL((void*)0)); | |||
687 | key_entry->gsettings_cnxn_cmd = g_signal_connect (settings,g_signal_connect_data ((settings), (gsettings_signal), (((GCallback ) (keybinding_command_changed))), (key_entry), ((void*)0), (GConnectFlags ) 0) | |||
688 | gsettings_signal,g_signal_connect_data ((settings), (gsettings_signal), (((GCallback ) (keybinding_command_changed))), (key_entry), ((void*)0), (GConnectFlags ) 0) | |||
689 | G_CALLBACK (keybinding_command_changed),g_signal_connect_data ((settings), (gsettings_signal), (((GCallback ) (keybinding_command_changed))), (key_entry), ((void*)0), (GConnectFlags ) 0) | |||
690 | key_entry)g_signal_connect_data ((settings), (gsettings_signal), (((GCallback ) (keybinding_command_changed))), (key_entry), ((void*)0), (GConnectFlags ) 0); | |||
691 | g_free (gsettings_signal); | |||
692 | } | |||
693 | ||||
694 | gchar *gsettings_signal = g_strconcat ("changed::", key_string, NULL((void*)0)); | |||
695 | key_entry->gsettings_cnxn = g_signal_connect (settings,g_signal_connect_data ((settings), (gsettings_signal), (((GCallback ) (keybinding_key_changed))), (key_entry), ((void*)0), (GConnectFlags ) 0) | |||
696 | gsettings_signal,g_signal_connect_data ((settings), (gsettings_signal), (((GCallback ) (keybinding_key_changed))), (key_entry), ((void*)0), (GConnectFlags ) 0) | |||
697 | G_CALLBACK (keybinding_key_changed),g_signal_connect_data ((settings), (gsettings_signal), (((GCallback ) (keybinding_key_changed))), (key_entry), ((void*)0), (GConnectFlags ) 0) | |||
698 | key_entry)g_signal_connect_data ((settings), (gsettings_signal), (((GCallback ) (keybinding_key_changed))), (key_entry), ((void*)0), (GConnectFlags ) 0); | |||
699 | g_free (gsettings_signal); | |||
700 | ||||
701 | key_value = g_settings_get_string (settings, key_string); | |||
702 | binding_from_string (key_value, &key_entry->keyval, &key_entry->keycode, &key_entry->mask); | |||
703 | g_free (key_value); | |||
704 | ||||
705 | ensure_scrollbar (builder, i); | |||
706 | ||||
707 | ++i; | |||
708 | ctk_tree_store_append (CTK_TREE_STORE (model)((((CtkTreeStore*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((model)), ((ctk_tree_store_get_type ())))))), &iter, &parent_iter); | |||
709 | /* we use the DESCRIPTION_COLUMN only for the section headers */ | |||
710 | ctk_tree_store_set (CTK_TREE_STORE (model)((((CtkTreeStore*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((model)), ((ctk_tree_store_get_type ())))))), &iter, | |||
711 | KEYENTRY_COLUMN, key_entry, | |||
712 | -1); | |||
713 | ctk_tree_view_expand_all (CTK_TREE_VIEW (ctk_builder_get_object (builder, "shortcut_treeview"))((((CtkTreeView*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((ctk_builder_get_object (builder, "shortcut_treeview"))), ((ctk_tree_view_get_type ()))))))); | |||
714 | } | |||
715 | ||||
716 | /* Don't show an empty section */ | |||
717 | if (ctk_tree_model_iter_n_children (model, &parent_iter) == 0) | |||
718 | ctk_tree_store_remove (CTK_TREE_STORE (model)((((CtkTreeStore*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((model)), ((ctk_tree_store_get_type ())))))), &parent_iter); | |||
719 | ||||
720 | if (i == 0) | |||
721 | ctk_widget_hide (_ctk_builder_get_widget (builder, "shortcuts_vbox")); | |||
722 | else | |||
723 | ctk_widget_show (_ctk_builder_get_widget (builder, "shortcuts_vbox")); | |||
724 | } | |||
725 | ||||
726 | static void | |||
727 | parse_start_tag (GMarkupParseContext *ctx, | |||
728 | const gchar *element_name, | |||
729 | const gchar **attr_names, | |||
730 | const gchar **attr_values, | |||
731 | gpointer user_data, | |||
732 | GError **error) | |||
733 | { | |||
734 | KeyList *keylist = (KeyList *) user_data; | |||
735 | KeyListEntry key; | |||
736 | const char *name, *value_key, *description, *value_schema; | |||
737 | int value; | |||
738 | Comparison comparison; | |||
739 | const char *schema = NULL((void*)0); | |||
740 | ||||
741 | name = NULL((void*)0); | |||
742 | ||||
743 | /* The top-level element, names the section in the tree */ | |||
744 | if (g_str_equal (element_name, "KeyListEntries")(strcmp ((const char *) (element_name), (const char *) ("KeyListEntries" )) == 0)) | |||
745 | { | |||
746 | const char *wm_name = NULL((void*)0); | |||
747 | const char *package = NULL((void*)0); | |||
748 | ||||
749 | while (*attr_names && *attr_values) | |||
750 | { | |||
751 | if (g_str_equal (*attr_names, "name")(strcmp ((const char *) (*attr_names), (const char *) ("name" )) == 0)) | |||
752 | { | |||
753 | if (**attr_values) | |||
754 | name = *attr_values; | |||
755 | } | |||
756 | else if (g_str_equal (*attr_names, "wm_name")(strcmp ((const char *) (*attr_names), (const char *) ("wm_name" )) == 0)) | |||
757 | { | |||
758 | if (**attr_values) | |||
759 | wm_name = *attr_values; | |||
760 | } | |||
761 | else if (g_str_equal (*attr_names, "package")(strcmp ((const char *) (*attr_names), (const char *) ("package" )) == 0)) | |||
762 | { | |||
763 | if (**attr_values) | |||
764 | package = *attr_values; | |||
765 | } | |||
766 | else if (g_str_equal (*attr_names, "schema")(strcmp ((const char *) (*attr_names), (const char *) ("schema" )) == 0)) | |||
767 | { | |||
768 | if (**attr_values) | |||
769 | schema = *attr_values; | |||
770 | } | |||
771 | ++attr_names; | |||
772 | ++attr_values; | |||
773 | } | |||
774 | ||||
775 | if (name) | |||
776 | { | |||
777 | if (keylist->name) | |||
778 | g_warning ("Duplicate section name"); | |||
779 | g_free (keylist->name); | |||
780 | keylist->name = g_strdup (name)g_strdup_inline (name); | |||
781 | } | |||
782 | if (wm_name) | |||
783 | { | |||
784 | if (keylist->wm_name) | |||
785 | g_warning ("Duplicate window manager name"); | |||
786 | g_free (keylist->wm_name); | |||
787 | keylist->wm_name = g_strdup (wm_name)g_strdup_inline (wm_name); | |||
788 | } | |||
789 | if (package) | |||
790 | { | |||
791 | if (keylist->package) | |||
792 | g_warning ("Duplicate gettext package name"); | |||
793 | g_free (keylist->package); | |||
794 | keylist->package = g_strdup (package)g_strdup_inline (package); | |||
795 | } | |||
796 | if (schema) | |||
797 | { | |||
798 | if (keylist->schema) | |||
799 | g_warning ("Duplicate schema name"); | |||
800 | g_free (keylist->schema); | |||
801 | keylist->schema = g_strdup (schema)g_strdup_inline (schema); | |||
802 | } | |||
803 | return; | |||
804 | } | |||
805 | ||||
806 | if (!g_str_equal (element_name, "KeyListEntry")(strcmp ((const char *) (element_name), (const char *) ("KeyListEntry" )) == 0) | |||
807 | || attr_names == NULL((void*)0) | |||
808 | || attr_values == NULL((void*)0)) | |||
809 | return; | |||
810 | ||||
811 | value = 0; | |||
812 | comparison = COMPARISON_NONE; | |||
813 | value_key = NULL((void*)0); | |||
814 | value_schema = NULL((void*)0); | |||
815 | description = NULL((void*)0); | |||
816 | ||||
817 | while (*attr_names && *attr_values) | |||
818 | { | |||
819 | if (g_str_equal (*attr_names, "name")(strcmp ((const char *) (*attr_names), (const char *) ("name" )) == 0)) | |||
820 | { | |||
821 | /* skip if empty */ | |||
822 | if (**attr_values) | |||
823 | name = *attr_values; | |||
824 | } else if (g_str_equal (*attr_names, "value")(strcmp ((const char *) (*attr_names), (const char *) ("value" )) == 0)) { | |||
825 | if (**attr_values) { | |||
826 | value = (int) g_ascii_strtoull (*attr_values, NULL((void*)0), 0); | |||
827 | } | |||
828 | } else if (g_str_equal (*attr_names, "key")(strcmp ((const char *) (*attr_names), (const char *) ("key") ) == 0)) { | |||
829 | if (**attr_values) { | |||
830 | value_key = *attr_values; | |||
831 | } | |||
832 | } else if (g_str_equal (*attr_names, "comparison")(strcmp ((const char *) (*attr_names), (const char *) ("comparison" )) == 0)) { | |||
833 | if (**attr_values) { | |||
834 | if (g_str_equal (*attr_values, "gt")(strcmp ((const char *) (*attr_values), (const char *) ("gt") ) == 0)) { | |||
835 | comparison = COMPARISON_GT; | |||
836 | } else if (g_str_equal (*attr_values, "lt")(strcmp ((const char *) (*attr_values), (const char *) ("lt") ) == 0)) { | |||
837 | comparison = COMPARISON_LT; | |||
838 | } else if (g_str_equal (*attr_values, "eq")(strcmp ((const char *) (*attr_values), (const char *) ("eq") ) == 0)) { | |||
839 | comparison = COMPARISON_EQ; | |||
840 | } | |||
841 | } | |||
842 | } else if (g_str_equal (*attr_names, "description")(strcmp ((const char *) (*attr_names), (const char *) ("description" )) == 0)) { | |||
843 | if (**attr_values) { | |||
844 | description = *attr_values; | |||
845 | } | |||
846 | } else if (g_str_equal (*attr_names, "schema")(strcmp ((const char *) (*attr_names), (const char *) ("schema" )) == 0)) { | |||
847 | if (**attr_values) { | |||
848 | value_schema = *attr_values; | |||
849 | } | |||
850 | } | |||
851 | ||||
852 | ++attr_names; | |||
853 | ++attr_values; | |||
854 | } | |||
855 | ||||
856 | if (name == NULL((void*)0)) | |||
857 | return; | |||
858 | ||||
859 | key.name = g_strdup (name)g_strdup_inline (name); | |||
860 | key.gsettings_path = NULL((void*)0); | |||
861 | key.description_key = NULL((void*)0); | |||
862 | key.description = g_strdup(description)g_strdup_inline (description); | |||
863 | key.schema = g_strdup(schema)g_strdup_inline (schema); | |||
864 | key.value = value; | |||
865 | if (value_key) { | |||
866 | key.value_key = g_strdup (value_key)g_strdup_inline (value_key); | |||
867 | key.value_schema = g_strdup (value_schema)g_strdup_inline (value_schema); | |||
868 | } | |||
869 | else { | |||
870 | key.value_key = NULL((void*)0); | |||
871 | key.value_schema = NULL((void*)0); | |||
872 | } | |||
873 | key.comparison = comparison; | |||
874 | key.cmd_key = NULL((void*)0); | |||
875 | g_array_append_val (keylist->entries, key)g_array_append_vals (keylist->entries, &(key), 1); | |||
876 | } | |||
877 | ||||
878 | static gboolean | |||
879 | strv_contains (char **strv, | |||
880 | char *str) | |||
881 | { | |||
882 | char **p = strv; | |||
883 | for (p = strv; *p; p++) | |||
884 | if (strcmp (*p, str) == 0) | |||
885 | return TRUE(!(0)); | |||
886 | ||||
887 | return FALSE(0); | |||
888 | } | |||
889 | ||||
890 | static void | |||
891 | append_keys_to_tree_from_file (CtkBuilder *builder, | |||
892 | const char *filename, | |||
893 | char **wm_keybindings) | |||
894 | { | |||
895 | GMarkupParseContext *ctx; | |||
896 | GMarkupParser parser = { parse_start_tag, NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0) }; | |||
897 | KeyList *keylist; | |||
898 | KeyListEntry key, *keys; | |||
899 | GError *err = NULL((void*)0); | |||
900 | char *buf; | |||
901 | const char *title; | |||
902 | gsize buf_len; | |||
903 | guint i; | |||
904 | ||||
905 | if (!g_file_get_contents (filename, &buf, &buf_len, &err)) | |||
906 | return; | |||
907 | ||||
908 | keylist = g_new0 (KeyList, 1)((KeyList *) g_malloc0_n ((1), sizeof (KeyList))); | |||
909 | keylist->entries = g_array_new (FALSE(0), TRUE(!(0)), sizeof (KeyListEntry)); | |||
910 | ctx = g_markup_parse_context_new (&parser, 0, keylist, NULL((void*)0)); | |||
911 | ||||
912 | if (!g_markup_parse_context_parse (ctx, buf, buf_len, &err)) | |||
913 | { | |||
914 | g_warning ("Failed to parse '%s': '%s'", filename, err->message); | |||
915 | g_error_free (err); | |||
916 | g_free (keylist->name); | |||
917 | g_free (keylist->package); | |||
918 | g_free (keylist->wm_name); | |||
919 | g_free (keylist->schema); | |||
920 | for (i = 0; i < keylist->entries->len; i++) | |||
921 | g_free (((KeyListEntry *) &(keylist->entries->data[i]))->name); | |||
922 | g_array_free (keylist->entries, TRUE(!(0))); | |||
923 | g_free (keylist); | |||
924 | keylist = NULL((void*)0); | |||
925 | } | |||
926 | g_markup_parse_context_free (ctx); | |||
927 | g_free (buf); | |||
928 | ||||
929 | if (keylist == NULL((void*)0)) | |||
930 | return; | |||
931 | ||||
932 | /* If there's no keys to add, or the settings apply to a window manager | |||
933 | * that's not the one we're running */ | |||
934 | if (keylist->entries->len == 0 | |||
935 | || (keylist->wm_name != NULL((void*)0) && !strv_contains (wm_keybindings, keylist->wm_name)) | |||
936 | || keylist->name == NULL((void*)0)) | |||
937 | { | |||
938 | g_free (keylist->name); | |||
939 | g_free (keylist->package); | |||
940 | g_free (keylist->wm_name); | |||
941 | g_free (keylist->schema); | |||
942 | g_array_free (keylist->entries, TRUE(!(0))); | |||
943 | g_free (keylist); | |||
944 | return; | |||
945 | } | |||
946 | ||||
947 | /* Empty KeyListEntry to end the array */ | |||
948 | key.name = NULL((void*)0); | |||
949 | key.description_key = NULL((void*)0); | |||
950 | key.value_key = NULL((void*)0); | |||
951 | key.value = 0; | |||
952 | key.comparison = COMPARISON_NONE; | |||
953 | g_array_append_val (keylist->entries, key)g_array_append_vals (keylist->entries, &(key), 1); | |||
954 | ||||
955 | keys = (KeyListEntry *) g_array_free (keylist->entries, FALSE(0)); | |||
956 | if (keylist->package) | |||
957 | { | |||
958 | bind_textdomain_codeset (keylist->package, "UTF-8"); | |||
959 | title = dgettext (keylist->package, keylist->name); | |||
960 | } else { | |||
961 | title = _(keylist->name)gettext (keylist->name); | |||
962 | } | |||
963 | ||||
964 | append_keys_to_tree (builder, title, keylist->schema, keylist->package, keys); | |||
965 | ||||
966 | g_free (keylist->name); | |||
967 | g_free (keylist->package); | |||
968 | for (i = 0; keys[i].name != NULL((void*)0); i++) | |||
969 | g_free (keys[i].name); | |||
970 | g_free (keylist); | |||
971 | } | |||
972 | ||||
973 | static void | |||
974 | append_keys_to_tree_from_gsettings (CtkBuilder *builder, const gchar *gsettings_path) | |||
975 | { | |||
976 | gchar **custom_list; | |||
977 | GArray *entries; | |||
978 | KeyListEntry key; | |||
979 | guint i; | |||
980 | ||||
981 | /* load custom shortcuts from GSettings */ | |||
982 | entries = g_array_new (FALSE(0), TRUE(!(0)), sizeof (KeyListEntry)); | |||
983 | ||||
984 | key.value_key = NULL((void*)0); | |||
985 | key.value = 0; | |||
986 | key.comparison = COMPARISON_NONE; | |||
987 | ||||
988 | custom_list = dconf_util_list_subdirs (gsettings_path, FALSE(0)); | |||
989 | ||||
990 | if (custom_list != NULL((void*)0)) | |||
991 | { | |||
992 | for (i = 0; custom_list[i] != NULL((void*)0); i++) | |||
993 | { | |||
994 | key.gsettings_path = g_strdup_printf("%s%s", gsettings_path, custom_list[i]); | |||
995 | key.name = g_strdup("binding")g_strdup_inline ("binding"); | |||
996 | key.cmd_key = g_strdup("action")g_strdup_inline ("action"); | |||
997 | key.description_key = g_strdup("name")g_strdup_inline ("name"); | |||
998 | key.schema = NULL((void*)0); | |||
999 | g_array_append_val (entries, key)g_array_append_vals (entries, &(key), 1); | |||
1000 | } | |||
1001 | } | |||
1002 | ||||
1003 | g_strfreev (custom_list); | |||
1004 | ||||
1005 | if (entries->len > 0) | |||
1006 | { | |||
1007 | KeyListEntry *keys; | |||
1008 | ||||
1009 | /* Empty KeyListEntry to end the array */ | |||
1010 | key.gsettings_path = NULL((void*)0); | |||
1011 | key.name = NULL((void*)0); | |||
1012 | key.description_key = NULL((void*)0); | |||
1013 | key.cmd_key = NULL((void*)0); | |||
1014 | g_array_append_val (entries, key)g_array_append_vals (entries, &(key), 1); | |||
1015 | ||||
1016 | keys = (KeyListEntry *) entries->data; | |||
1017 | append_keys_to_tree (builder, _("Custom Shortcuts")gettext ("Custom Shortcuts"), CUSTOM_KEYBINDING_SCHEMA"org.cafe.control-center.keybinding", NULL((void*)0), keys); | |||
1018 | for (i = 0; i < entries->len; ++i) | |||
1019 | { | |||
1020 | g_free (keys[i].name); | |||
1021 | g_free (keys[i].description_key); | |||
1022 | g_free (keys[i].cmd_key); | |||
1023 | g_free (keys[i].gsettings_path); | |||
1024 | } | |||
1025 | } | |||
1026 | ||||
1027 | g_array_free (entries, TRUE(!(0))); | |||
1028 | } | |||
1029 | ||||
1030 | static void | |||
1031 | reload_key_entries (CtkBuilder *builder) | |||
1032 | { | |||
1033 | gchar **wm_keybindings; | |||
1034 | GList *list, *l; | |||
1035 | const gchar * const * data_dirs; | |||
1036 | GHashTable *loaded_files; | |||
1037 | guint i; | |||
1038 | ||||
1039 | wm_keybindings = wm_common_get_current_keybindings(); | |||
1040 | ||||
1041 | clear_old_model (builder); | |||
1042 | ||||
1043 | loaded_files = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); | |||
1044 | data_dirs = g_get_system_data_dirs (); | |||
1045 | for (i = 0; data_dirs[i] != NULL((void*)0); i++) | |||
1046 | { | |||
1047 | g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) gchar *dir_path = NULL((void*)0); | |||
1048 | GDir *dir; | |||
1049 | const gchar *name; | |||
1050 | ||||
1051 | dir_path = g_build_filename (data_dirs[i], "cafe-control-center", "keybindings", NULL((void*)0)); | |||
1052 | g_debug ("Keybinding dir: %s", dir_path); | |||
1053 | ||||
1054 | dir = g_dir_open (dir_path, 0, NULL((void*)0)); | |||
1055 | if (!dir) | |||
1056 | continue; | |||
1057 | ||||
1058 | for (name = g_dir_read_name (dir) ; name ; name = g_dir_read_name (dir)) | |||
1059 | { | |||
1060 | if (g_str_has_suffix (name, ".xml")(__builtin_constant_p (".xml")? __extension__ ({ const char * const __str = (name); const char * const __suffix = (".xml") ; gboolean __result = (0); if (__str == ((void*)0) || __suffix == ((void*)0)) __result = (g_str_has_suffix) (__str, __suffix ); else { const size_t __str_len = strlen (((__str) + !(__str ))); const size_t __suffix_len = strlen (((__suffix) + !(__suffix ))); if (__str_len >= __suffix_len) __result = memcmp (__str + __str_len - __suffix_len, ((__suffix) + !(__suffix)), __suffix_len ) == 0; } __result; }) : (g_str_has_suffix) (name, ".xml") ) == FALSE(0)) | |||
1061 | continue; | |||
1062 | ||||
1063 | if (g_hash_table_lookup (loaded_files, name) != NULL((void*)0)) | |||
1064 | { | |||
1065 | g_debug ("Not loading %s, it was already loaded from another directory", name); | |||
1066 | continue; | |||
1067 | } | |||
1068 | ||||
1069 | g_hash_table_insert (loaded_files, g_strdup (name)g_strdup_inline (name), g_strdup (dir_path)g_strdup_inline (dir_path)); | |||
1070 | } | |||
1071 | ||||
1072 | g_dir_close (dir); | |||
1073 | } | |||
1074 | list = g_hash_table_get_keys (loaded_files); | |||
1075 | list = g_list_sort(list, (GCompareFunc) g_str_equal); | |||
1076 | for (l = list; l != NULL((void*)0); l = l->next) | |||
1077 | { | |||
1078 | g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) gchar *path = NULL((void*)0); | |||
1079 | path = g_build_filename (g_hash_table_lookup (loaded_files, l->data), l->data, NULL((void*)0)); | |||
1080 | g_debug ("Keybinding file: %s", path); | |||
1081 | append_keys_to_tree_from_file (builder, path, wm_keybindings); | |||
1082 | } | |||
1083 | g_list_free (list); | |||
1084 | g_hash_table_destroy (loaded_files); | |||
1085 | ||||
1086 | /* Load custom shortcuts _after_ system-provided ones, | |||
1087 | * since some of the custom shortcuts may also be listed | |||
1088 | * in a file. Loading the custom shortcuts last makes | |||
1089 | * such keys not show up in the custom section. | |||
1090 | */ | |||
1091 | append_keys_to_tree_from_gsettings (builder, GSETTINGS_KEYBINDINGS_DIR"/org/cafe/desktop/keybindings/"); | |||
1092 | ||||
1093 | g_strfreev (wm_keybindings); | |||
1094 | } | |||
1095 | ||||
1096 | static void | |||
1097 | key_entry_controlling_key_changed (GSettings *settings, gchar *key, gpointer user_data) | |||
1098 | { | |||
1099 | reload_key_entries (user_data); | |||
1100 | } | |||
1101 | ||||
1102 | static gboolean cb_check_for_uniqueness(CtkTreeModel* model, CtkTreePath* path, CtkTreeIter* iter, KeyEntry* new_key) | |||
1103 | { | |||
1104 | KeyEntry* element; | |||
1105 | ||||
1106 | ctk_tree_model_get (new_key->model, iter, | |||
1107 | KEYENTRY_COLUMN, &element, | |||
1108 | -1); | |||
1109 | ||||
1110 | /* no conflict for : blanks, different modifiers, or ourselves */ | |||
1111 | if (element == NULL((void*)0) || new_key->mask != element->mask) | |||
1112 | { | |||
1113 | return FALSE(0); | |||
1114 | } | |||
1115 | ||||
1116 | gchar *new_key_schema = NULL((void*)0); | |||
1117 | gchar *element_schema = NULL((void*)0); | |||
1118 | gchar *new_key_path = NULL((void*)0); | |||
1119 | gchar *element_path = NULL((void*)0); | |||
1120 | ||||
1121 | if (new_key && new_key->settings) | |||
1122 | { | |||
1123 | g_object_get (new_key->settings, "schema-id", &new_key_schema, NULL((void*)0)); | |||
1124 | g_object_get (new_key->settings, "path", &new_key_path, NULL((void*)0)); | |||
1125 | } | |||
1126 | ||||
1127 | if (element->settings) | |||
1128 | { | |||
1129 | g_object_get (element->settings, "schema-id", &element_schema, NULL((void*)0)); | |||
1130 | g_object_get (element->settings, "path", &element_path, NULL((void*)0)); | |||
1131 | } | |||
1132 | ||||
1133 | if (!g_strcmp0 (new_key->gsettings_key, element->gsettings_key) && | |||
1134 | !g_strcmp0 (new_key_schema, element_schema) && | |||
1135 | !g_strcmp0 (new_key_path, element_path)) | |||
1136 | { | |||
1137 | return FALSE(0); | |||
1138 | } | |||
1139 | ||||
1140 | if (new_key->keyval != 0) | |||
1141 | { | |||
1142 | if (new_key->keyval != element->keyval) | |||
1143 | { | |||
1144 | return FALSE(0); | |||
1145 | } | |||
1146 | } | |||
1147 | else if (element->keyval != 0 || new_key->keycode != element->keycode) | |||
1148 | { | |||
1149 | return FALSE(0); | |||
1150 | } | |||
1151 | ||||
1152 | new_key->editable = FALSE(0); | |||
1153 | new_key->settings = element->settings; | |||
1154 | new_key->gsettings_key = element->gsettings_key; | |||
1155 | new_key->description = element->description; | |||
1156 | new_key->desc_gsettings_key = element->desc_gsettings_key; | |||
1157 | new_key->desc_editable = element->desc_editable; | |||
1158 | ||||
1159 | return TRUE(!(0)); | |||
1160 | } | |||
1161 | ||||
1162 | static const guint forbidden_keyvals[] = { | |||
1163 | /* Navigation keys */ | |||
1164 | CDK_KEY_Home0xff50, | |||
1165 | CDK_KEY_Left0xff51, | |||
1166 | CDK_KEY_Up0xff52, | |||
1167 | CDK_KEY_Right0xff53, | |||
1168 | CDK_KEY_Down0xff54, | |||
1169 | CDK_KEY_Page_Up0xff55, | |||
1170 | CDK_KEY_Page_Down0xff56, | |||
1171 | CDK_KEY_End0xff57, | |||
1172 | CDK_KEY_Tab0xff09, | |||
1173 | ||||
1174 | /* Return */ | |||
1175 | CDK_KEY_KP_Enter0xff8d, | |||
1176 | CDK_KEY_Return0xff0d, | |||
1177 | ||||
1178 | CDK_KEY_space0x020, | |||
1179 | CDK_KEY_Mode_switch0xff7e | |||
1180 | }; | |||
1181 | ||||
1182 | static gboolean keyval_is_forbidden(guint keyval) | |||
1183 | { | |||
1184 | guint i; | |||
1185 | ||||
1186 | for (i = 0; i < G_N_ELEMENTS(forbidden_keyvals)(sizeof (forbidden_keyvals) / sizeof ((forbidden_keyvals)[0]) ); i++) | |||
1187 | { | |||
1188 | if (keyval == forbidden_keyvals[i]) | |||
1189 | { | |||
1190 | return TRUE(!(0)); | |||
1191 | } | |||
1192 | } | |||
1193 | ||||
1194 | return FALSE(0); | |||
1195 | } | |||
1196 | ||||
1197 | static void show_error(CtkWindow* parent, GError* err) | |||
1198 | { | |||
1199 | CtkWidget *dialog; | |||
1200 | ||||
1201 | dialog = ctk_message_dialog_new (parent, | |||
1202 | CTK_DIALOG_DESTROY_WITH_PARENT | CTK_DIALOG_MODAL, | |||
1203 | CTK_MESSAGE_WARNING, | |||
1204 | CTK_BUTTONS_OK, | |||
1205 | _("Error saving the new shortcut")gettext ("Error saving the new shortcut")); | |||
1206 | ||||
1207 | ctk_message_dialog_format_secondary_text (CTK_MESSAGE_DIALOG (dialog)((((CtkMessageDialog*) (void *) g_type_check_instance_cast (( GTypeInstance*) ((dialog)), ((ctk_message_dialog_get_type ()) ))))), | |||
1208 | "%s", err->message); | |||
| ||||
1209 | ctk_dialog_run (CTK_DIALOG (dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((dialog)), ((ctk_dialog_get_type ()))))))); | |||
1210 | ctk_widget_destroy (dialog); | |||
1211 | } | |||
1212 | ||||
1213 | static void accel_edited_callback(CtkCellRendererText* cell, const char* path_string, guint keyval, EggVirtualModifierType mask, guint keycode, gpointer data) | |||
1214 | { | |||
1215 | CtkTreeView* view = (CtkTreeView*) data; | |||
1216 | CtkTreeModel* model; | |||
1217 | CtkTreePath* path = ctk_tree_path_new_from_string (path_string); | |||
1218 | CtkTreeIter iter; | |||
1219 | KeyEntry* key_entry, tmp_key; | |||
1220 | char* str; | |||
1221 | ||||
1222 | block_accels = FALSE(0); | |||
1223 | ||||
1224 | model = ctk_tree_view_get_model (view); | |||
1225 | ctk_tree_model_get_iter (model, &iter, path); | |||
1226 | ctk_tree_path_free (path); | |||
1227 | ctk_tree_model_get (model, &iter, | |||
1228 | KEYENTRY_COLUMN, &key_entry, | |||
1229 | -1); | |||
1230 | ||||
1231 | /* sanity check */ | |||
1232 | if (key_entry == NULL((void*)0)) | |||
1233 | { | |||
1234 | return; | |||
1235 | } | |||
1236 | ||||
1237 | /* CapsLock isn't supported as a keybinding modifier, so keep it from confusing us */ | |||
1238 | mask &= ~EGG_VIRTUAL_LOCK_MASK; | |||
1239 | ||||
1240 | tmp_key.model = model; | |||
1241 | tmp_key.keyval = keyval; | |||
1242 | tmp_key.keycode = keycode; | |||
1243 | tmp_key.mask = mask; | |||
1244 | tmp_key.settings = key_entry->settings; | |||
1245 | tmp_key.gsettings_key = key_entry->gsettings_key; | |||
1246 | tmp_key.description = NULL((void*)0); | |||
1247 | tmp_key.editable = TRUE(!(0)); /* kludge to stuff in a return flag */ | |||
1248 | ||||
1249 | if (keyval != 0 || keycode != 0) /* any number of keys can be disabled */ | |||
1250 | { | |||
1251 | ctk_tree_model_foreach(model, (CtkTreeModelForeachFunc) cb_check_for_uniqueness, &tmp_key); | |||
1252 | } | |||
1253 | ||||
1254 | /* Check for unmodified keys */ | |||
1255 | if (tmp_key.mask == 0 && tmp_key.keycode != 0) | |||
1256 | { | |||
1257 | if ((tmp_key.keyval >= CDK_KEY_a0x061 && tmp_key.keyval <= CDK_KEY_z0x07a) | |||
1258 | || (tmp_key.keyval >= CDK_KEY_A0x041 && tmp_key.keyval <= CDK_KEY_Z0x05a) | |||
1259 | || (tmp_key.keyval >= CDK_KEY_00x030 && tmp_key.keyval <= CDK_KEY_90x039) | |||
1260 | || (tmp_key.keyval >= CDK_KEY_kana_fullstop0x4a1 && tmp_key.keyval <= CDK_KEY_semivoicedsound0x4df) | |||
1261 | || (tmp_key.keyval >= CDK_KEY_Arabic_comma0x5ac && tmp_key.keyval <= CDK_KEY_Arabic_sukun0x5f2) | |||
1262 | || (tmp_key.keyval >= CDK_KEY_Serbian_dje0x6a1 && tmp_key.keyval <= CDK_KEY_Cyrillic_HARDSIGN0x6ff) | |||
1263 | || (tmp_key.keyval >= CDK_KEY_Greek_ALPHAaccent0x7a1 && tmp_key.keyval <= CDK_KEY_Greek_omega0x7f9) | |||
1264 | || (tmp_key.keyval >= CDK_KEY_hebrew_doublelowline0xcdf && tmp_key.keyval <= CDK_KEY_hebrew_taf0xcfa) | |||
1265 | || (tmp_key.keyval >= CDK_KEY_Thai_kokai0xda1 && tmp_key.keyval <= CDK_KEY_Thai_lekkao0xdf9) | |||
1266 | || (tmp_key.keyval >= CDK_KEY_Hangul0xff31 && tmp_key.keyval <= CDK_KEY_Hangul_Special0xff3f) | |||
1267 | || (tmp_key.keyval >= CDK_KEY_Hangul_Kiyeog0xea1 && tmp_key.keyval <= CDK_KEY_Hangul_J_YeorinHieuh0xefa) | |||
1268 | || keyval_is_forbidden (tmp_key.keyval)) | |||
1269 | { | |||
1270 | ||||
1271 | CtkWidget *dialog; | |||
1272 | char *name; | |||
1273 | ||||
1274 | name = binding_name (keyval, keycode, mask, TRUE(!(0))); | |||
1275 | ||||
1276 | dialog = ctk_message_dialog_new ( | |||
1277 | CTK_WINDOW (ctk_widget_get_toplevel (CTK_WIDGET (view)))((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((ctk_widget_get_toplevel (((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((view)), ((ctk_widget_get_type ())))))))) ), ((ctk_window_get_type ())))))), | |||
1278 | CTK_DIALOG_DESTROY_WITH_PARENT | CTK_DIALOG_MODAL, | |||
1279 | CTK_MESSAGE_WARNING, | |||
1280 | CTK_BUTTONS_CANCEL, | |||
1281 | _("The shortcut \"%s\" cannot be used because it will become impossible to type using this key.\n"gettext ("The shortcut \"%s\" cannot be used because it will become impossible to type using this key.\n" "Please try with a key such as Control, Alt or Shift at the same time." ) | |||
1282 | "Please try with a key such as Control, Alt or Shift at the same time.")gettext ("The shortcut \"%s\" cannot be used because it will become impossible to type using this key.\n" "Please try with a key such as Control, Alt or Shift at the same time." ), | |||
1283 | name); | |||
1284 | ||||
1285 | g_free (name); | |||
1286 | ctk_dialog_run (CTK_DIALOG (dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((dialog)), ((ctk_dialog_get_type ()))))))); | |||
1287 | ctk_widget_destroy (dialog); | |||
1288 | ||||
1289 | /* set it back to its previous value. */ | |||
1290 | egg_cell_renderer_keys_set_accelerator( | |||
1291 | EGG_CELL_RENDERER_KEYS(cell)((((EggCellRendererKeys*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((cell)), ((egg_cell_renderer_keys_get_type ())))))), | |||
1292 | key_entry->keyval, | |||
1293 | key_entry->keycode, | |||
1294 | key_entry->mask); | |||
1295 | return; | |||
1296 | } | |||
1297 | } | |||
1298 | ||||
1299 | /* flag to see if the new accelerator was in use by something */ | |||
1300 | if (!tmp_key.editable) | |||
1301 | { | |||
1302 | CtkWidget* dialog; | |||
1303 | char* name; | |||
1304 | int response; | |||
1305 | ||||
1306 | name = binding_name(keyval, keycode, mask, TRUE(!(0))); | |||
1307 | ||||
1308 | dialog = ctk_message_dialog_new( | |||
1309 | CTK_WINDOW(ctk_widget_get_toplevel(CTK_WIDGET(view)))((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((ctk_widget_get_toplevel(((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((view)), ((ctk_widget_get_type ())))))))) ), ((ctk_window_get_type ())))))), | |||
1310 | CTK_DIALOG_DESTROY_WITH_PARENT | CTK_DIALOG_MODAL, | |||
1311 | CTK_MESSAGE_WARNING, | |||
1312 | CTK_BUTTONS_CANCEL, | |||
1313 | _("The shortcut \"%s\" is already used for\n\"%s\"")gettext ("The shortcut \"%s\" is already used for\n\"%s\""), | |||
1314 | name, | |||
1315 | tmp_key.description ? tmp_key.description : tmp_key.gsettings_key); | |||
1316 | g_free (name); | |||
1317 | ||||
1318 | ctk_message_dialog_format_secondary_text ( | |||
1319 | CTK_MESSAGE_DIALOG (dialog)((((CtkMessageDialog*) (void *) g_type_check_instance_cast (( GTypeInstance*) ((dialog)), ((ctk_message_dialog_get_type ()) ))))), | |||
1320 | _("If you reassign the shortcut to \"%s\", the \"%s\" shortcut "gettext ("If you reassign the shortcut to \"%s\", the \"%s\" shortcut " "will be disabled.") | |||
1321 | "will be disabled.")gettext ("If you reassign the shortcut to \"%s\", the \"%s\" shortcut " "will be disabled."), | |||
1322 | key_entry->description ? key_entry->description : key_entry->gsettings_key, | |||
1323 | tmp_key.description ? tmp_key.description : tmp_key.gsettings_key); | |||
1324 | ||||
1325 | ctk_dialog_add_button(CTK_DIALOG (dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((dialog)), ((ctk_dialog_get_type ())))))), _("_Reassign")gettext ("_Reassign"), CTK_RESPONSE_ACCEPT); | |||
1326 | ||||
1327 | ctk_dialog_set_default_response(CTK_DIALOG (dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((dialog)), ((ctk_dialog_get_type ())))))), CTK_RESPONSE_ACCEPT); | |||
1328 | ||||
1329 | response = ctk_dialog_run (CTK_DIALOG (dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((dialog)), ((ctk_dialog_get_type ()))))))); | |||
1330 | ctk_widget_destroy (dialog); | |||
1331 | ||||
1332 | if (response == CTK_RESPONSE_ACCEPT) | |||
1333 | { | |||
1334 | g_settings_set_string (tmp_key.settings, tmp_key.gsettings_key, "disabled"); | |||
1335 | ||||
1336 | str = binding_name (keyval, keycode, mask, FALSE(0)); | |||
1337 | g_settings_set_string (key_entry->settings, key_entry->gsettings_key, str); | |||
1338 | ||||
1339 | g_free (str); | |||
1340 | } | |||
1341 | else | |||
1342 | { | |||
1343 | /* set it back to its previous value. */ | |||
1344 | egg_cell_renderer_keys_set_accelerator( | |||
1345 | EGG_CELL_RENDERER_KEYS(cell)((((EggCellRendererKeys*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((cell)), ((egg_cell_renderer_keys_get_type ())))))), | |||
1346 | key_entry->keyval, | |||
1347 | key_entry->keycode, | |||
1348 | key_entry->mask); | |||
1349 | } | |||
1350 | ||||
1351 | return; | |||
1352 | } | |||
1353 | ||||
1354 | str = binding_name (keyval, keycode, mask, FALSE(0)); | |||
1355 | ||||
1356 | g_settings_set_string( | |||
1357 | key_entry->settings, | |||
1358 | key_entry->gsettings_key, | |||
1359 | str); | |||
1360 | ||||
1361 | g_free (str); | |||
1362 | ||||
1363 | } | |||
1364 | ||||
1365 | static void | |||
1366 | accel_cleared_callback (CtkCellRendererText *cell, | |||
1367 | const char *path_string, | |||
1368 | gpointer data) | |||
1369 | { | |||
1370 | CtkTreeView *view = (CtkTreeView *) data; | |||
1371 | CtkTreePath *path = ctk_tree_path_new_from_string (path_string); | |||
1372 | KeyEntry *key_entry; | |||
1373 | CtkTreeIter iter; | |||
1374 | CtkTreeModel *model; | |||
1375 | ||||
1376 | block_accels = FALSE(0); | |||
1377 | ||||
1378 | model = ctk_tree_view_get_model (view); | |||
1379 | ctk_tree_model_get_iter (model, &iter, path); | |||
1380 | ctk_tree_path_free (path); | |||
1381 | ctk_tree_model_get (model, &iter, | |||
1382 | KEYENTRY_COLUMN, &key_entry, | |||
1383 | -1); | |||
1384 | ||||
1385 | /* sanity check */ | |||
1386 | if (key_entry == NULL((void*)0)) | |||
1387 | return; | |||
1388 | ||||
1389 | /* Unset the key */ | |||
1390 | g_settings_set_string (key_entry->settings, | |||
1391 | key_entry->gsettings_key, | |||
1392 | "disabled"); | |||
1393 | } | |||
1394 | ||||
1395 | static void | |||
1396 | description_edited_callback (CtkCellRendererText *renderer, | |||
1397 | gchar *path_string, | |||
1398 | gchar *new_text, | |||
1399 | gpointer user_data) | |||
1400 | { | |||
1401 | CtkTreeView *view = CTK_TREE_VIEW (user_data)((((CtkTreeView*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((user_data)), ((ctk_tree_view_get_type ())))))); | |||
1402 | CtkTreeModel *model; | |||
1403 | CtkTreePath *path = ctk_tree_path_new_from_string (path_string); | |||
1404 | CtkTreeIter iter; | |||
1405 | KeyEntry *key_entry; | |||
1406 | ||||
1407 | model = ctk_tree_view_get_model (view); | |||
1408 | ctk_tree_model_get_iter (model, &iter, path); | |||
1409 | ctk_tree_path_free (path); | |||
1410 | ||||
1411 | ctk_tree_model_get (model, &iter, | |||
1412 | KEYENTRY_COLUMN, &key_entry, | |||
1413 | -1); | |||
1414 | ||||
1415 | /* sanity check */ | |||
1416 | if (key_entry == NULL((void*)0) || key_entry->desc_gsettings_key == NULL((void*)0)) | |||
1417 | return; | |||
1418 | ||||
1419 | if (!g_settings_set_string (key_entry->settings, key_entry->desc_gsettings_key, new_text)) | |||
1420 | key_entry->desc_editable = FALSE(0); | |||
1421 | } | |||
1422 | ||||
1423 | ||||
1424 | typedef struct | |||
1425 | { | |||
1426 | CtkTreeView *tree_view; | |||
1427 | CtkTreePath *path; | |||
1428 | CtkTreeViewColumn *column; | |||
1429 | } IdleData; | |||
1430 | ||||
1431 | static gboolean | |||
1432 | real_start_editing_cb (IdleData *idle_data) | |||
1433 | { | |||
1434 | ctk_widget_grab_focus (CTK_WIDGET (idle_data->tree_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((idle_data->tree_view)), ((ctk_widget_get_type ()))))) )); | |||
1435 | ctk_tree_view_set_cursor (idle_data->tree_view, | |||
1436 | idle_data->path, | |||
1437 | idle_data->column, | |||
1438 | TRUE(!(0))); | |||
1439 | ctk_tree_path_free (idle_data->path); | |||
1440 | g_free (idle_data); | |||
1441 | return FALSE(0); | |||
1442 | } | |||
1443 | ||||
1444 | static gboolean | |||
1445 | edit_custom_shortcut (KeyEntry *key) | |||
1446 | { | |||
1447 | gint result; | |||
1448 | const gchar *text; | |||
1449 | gboolean ret; | |||
1450 | ||||
1451 | ctk_entry_set_text (CTK_ENTRY (custom_shortcut_name_entry)((((CtkEntry*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((custom_shortcut_name_entry)), ((ctk_entry_get_type ()))) ))), key->description ? key->description : ""); | |||
1452 | ctk_widget_set_sensitive (custom_shortcut_name_entry, key->desc_editable); | |||
1453 | ctk_widget_grab_focus (custom_shortcut_name_entry); | |||
1454 | ctk_entry_set_text (CTK_ENTRY (custom_shortcut_command_entry)((((CtkEntry*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((custom_shortcut_command_entry)), ((ctk_entry_get_type () )))))), key->command ? key->command : ""); | |||
1455 | ctk_widget_set_sensitive (custom_shortcut_command_entry, key->cmd_editable); | |||
1456 | ||||
1457 | ctk_window_present (CTK_WINDOW (custom_shortcut_dialog)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((custom_shortcut_dialog)), ((ctk_window_get_type ()))))))); | |||
1458 | result = ctk_dialog_run (CTK_DIALOG (custom_shortcut_dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((custom_shortcut_dialog)), ((ctk_dialog_get_type ()))))))); | |||
1459 | switch (result) | |||
1460 | { | |||
1461 | case CTK_RESPONSE_OK: | |||
1462 | text = ctk_entry_get_text (CTK_ENTRY (custom_shortcut_name_entry)((((CtkEntry*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((custom_shortcut_name_entry)), ((ctk_entry_get_type ()))) )))); | |||
1463 | g_free (key->description); | |||
1464 | key->description = g_strdup (text)g_strdup_inline (text); | |||
1465 | text = ctk_entry_get_text (CTK_ENTRY (custom_shortcut_command_entry)((((CtkEntry*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((custom_shortcut_command_entry)), ((ctk_entry_get_type () ))))))); | |||
1466 | g_free (key->command); | |||
1467 | key->command = g_strdup (text)g_strdup_inline (text); | |||
1468 | ret = TRUE(!(0)); | |||
1469 | break; | |||
1470 | default: | |||
1471 | ret = FALSE(0); | |||
1472 | break; | |||
1473 | } | |||
1474 | ||||
1475 | ctk_widget_hide (custom_shortcut_dialog); | |||
1476 | ||||
1477 | return ret; | |||
1478 | } | |||
1479 | ||||
1480 | static gboolean | |||
1481 | remove_custom_shortcut (CtkTreeModel *model, CtkTreeIter *iter) | |||
1482 | { | |||
1483 | CtkTreeIter parent; | |||
1484 | KeyEntry *key; | |||
1485 | ||||
1486 | ctk_tree_model_get (model, iter, | |||
1487 | KEYENTRY_COLUMN, &key, | |||
1488 | -1); | |||
1489 | ||||
1490 | /* not a custom shortcut */ | |||
1491 | if (key->command == NULL((void*)0)) | |||
1492 | return FALSE(0); | |||
1493 | ||||
1494 | g_signal_handler_disconnect (key->settings, key->gsettings_cnxn); | |||
1495 | if (key->gsettings_cnxn_desc != 0) | |||
1496 | g_signal_handler_disconnect (key->settings, key->gsettings_cnxn_desc); | |||
1497 | if (key->gsettings_cnxn_cmd != 0) | |||
1498 | g_signal_handler_disconnect (key->settings, key->gsettings_cnxn_cmd); | |||
1499 | ||||
1500 | dconf_util_recursive_reset (key->gsettings_path, NULL((void*)0)); | |||
1501 | g_object_unref (key->settings); | |||
1502 | ||||
1503 | g_free (key->gsettings_path); | |||
1504 | g_free (key->gsettings_key); | |||
1505 | g_free (key->description); | |||
1506 | g_free (key->desc_gsettings_key); | |||
1507 | g_free (key->command); | |||
1508 | g_free (key->cmd_gsettings_key); | |||
1509 | g_free (key); | |||
1510 | ||||
1511 | ctk_tree_model_iter_parent (model, &parent, iter); | |||
1512 | ctk_tree_store_remove (CTK_TREE_STORE (model)((((CtkTreeStore*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((model)), ((ctk_tree_store_get_type ())))))), iter); | |||
1513 | if (!ctk_tree_model_iter_has_child (model, &parent)) | |||
1514 | ctk_tree_store_remove (CTK_TREE_STORE (model)((((CtkTreeStore*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((model)), ((ctk_tree_store_get_type ())))))), &parent); | |||
1515 | ||||
1516 | return TRUE(!(0)); | |||
1517 | } | |||
1518 | ||||
1519 | static void | |||
1520 | update_custom_shortcut (CtkTreeModel *model, CtkTreeIter *iter) | |||
1521 | { | |||
1522 | KeyEntry *key; | |||
1523 | ||||
1524 | ctk_tree_model_get (model, iter, | |||
1525 | KEYENTRY_COLUMN, &key, | |||
1526 | -1); | |||
1527 | ||||
1528 | edit_custom_shortcut (key); | |||
1529 | if (key->command == NULL((void*)0) || key->command[0] == '\0') | |||
1530 | { | |||
1531 | remove_custom_shortcut (model, iter); | |||
1532 | } | |||
1533 | else | |||
1534 | { | |||
1535 | ctk_tree_store_set (CTK_TREE_STORE (model)((((CtkTreeStore*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((model)), ((ctk_tree_store_get_type ())))))), iter, | |||
1536 | KEYENTRY_COLUMN, key, -1); | |||
1537 | if (key->description != NULL((void*)0)) | |||
1538 | g_settings_set_string (key->settings, key->desc_gsettings_key, key->description); | |||
1539 | else | |||
1540 | g_settings_reset (key->settings, key->desc_gsettings_key); | |||
1541 | g_settings_set_string (key->settings, key->cmd_gsettings_key, key->command); | |||
1542 | } | |||
1543 | } | |||
1544 | ||||
1545 | static gchar * | |||
1546 | find_free_gsettings_path (GError **error) | |||
1547 | { | |||
1548 | gchar **existing_dirs; | |||
1549 | gchar *dir = NULL((void*)0); | |||
1550 | gchar *fulldir = NULL((void*)0); | |||
1551 | int i; | |||
1552 | int j; | |||
1553 | gboolean found; | |||
1554 | ||||
1555 | existing_dirs = dconf_util_list_subdirs (GSETTINGS_KEYBINDINGS_DIR"/org/cafe/desktop/keybindings/", FALSE(0)); | |||
1556 | ||||
1557 | for (i = 0; i < MAX_CUSTOM_SHORTCUTS1000; i++) | |||
1558 | { | |||
1559 | found = TRUE(!(0)); | |||
1560 | dir = g_strdup_printf ("custom%d/", i); | |||
1561 | for (j = 0; existing_dirs[j] != NULL((void*)0); j++) | |||
1562 | if (!g_strcmp0(dir, existing_dirs[j])) | |||
1563 | { | |||
1564 | found = FALSE(0); | |||
1565 | g_free (dir); | |||
1566 | break; | |||
1567 | } | |||
1568 | if (found
| |||
1569 | break; | |||
1570 | } | |||
1571 | g_strfreev (existing_dirs); | |||
1572 | ||||
1573 | if (i
| |||
1574 | { | |||
1575 | g_free (dir); | |||
1576 | dir = NULL((void*)0); | |||
1577 | g_set_error_literal (error, | |||
1578 | g_quark_from_string ("Keyboard Shortcuts"), | |||
1579 | 0, | |||
1580 | _("Too many custom shortcuts")gettext ("Too many custom shortcuts")); | |||
1581 | } | |||
1582 | ||||
1583 | fulldir = g_strdup_printf ("%s%s", GSETTINGS_KEYBINDINGS_DIR"/org/cafe/desktop/keybindings/", dir); | |||
1584 | g_free (dir); | |||
1585 | return fulldir; | |||
1586 | } | |||
1587 | ||||
1588 | static void | |||
1589 | add_custom_shortcut (CtkTreeView *tree_view, | |||
1590 | CtkTreeModel *model) | |||
1591 | { | |||
1592 | KeyEntry *key_entry; | |||
1593 | CtkTreeIter iter; | |||
1594 | CtkTreeIter parent_iter; | |||
1595 | CtkTreePath *path; | |||
1596 | gchar *dir; | |||
1597 | GError *error; | |||
1598 | ||||
1599 | error = NULL((void*)0); | |||
1600 | dir = find_free_gsettings_path (&error); | |||
1601 | if (dir == NULL((void*)0)) | |||
1602 | { | |||
1603 | show_error (CTK_WINDOW (ctk_widget_get_toplevel (CTK_WIDGET (tree_view)))((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((ctk_widget_get_toplevel (((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((tree_view)), ((ctk_widget_get_type ()))) )))))), ((ctk_window_get_type ())))))), error); | |||
1604 | ||||
1605 | g_error_free (error); | |||
1606 | return; | |||
1607 | } | |||
1608 | ||||
1609 | key_entry = g_new0 (KeyEntry, 1)((KeyEntry *) g_malloc0_n ((1), sizeof (KeyEntry))); | |||
1610 | key_entry->gsettings_path = g_strdup(dir)g_strdup_inline (dir); | |||
1611 | key_entry->gsettings_key = g_strdup("binding")g_strdup_inline ("binding"); | |||
1612 | key_entry->editable = TRUE(!(0)); | |||
1613 | key_entry->model = model; | |||
1614 | key_entry->desc_gsettings_key = g_strdup("name")g_strdup_inline ("name"); | |||
1615 | key_entry->description = g_strdup ("")g_strdup_inline (""); | |||
1616 | key_entry->desc_editable = TRUE(!(0)); | |||
1617 | key_entry->cmd_gsettings_key = g_strdup("action")g_strdup_inline ("action"); | |||
1618 | key_entry->command = g_strdup ("")g_strdup_inline (""); | |||
1619 | key_entry->cmd_editable = TRUE(!(0)); | |||
1620 | g_free (dir); | |||
1621 | ||||
1622 | if (edit_custom_shortcut (key_entry) && | |||
1623 | key_entry->command && key_entry->command[0]) | |||
1624 | { | |||
1625 | find_section (model, &iter, _("Custom Shortcuts")gettext ("Custom Shortcuts")); | |||
1626 | parent_iter = iter; | |||
1627 | ctk_tree_store_append (CTK_TREE_STORE (model)((((CtkTreeStore*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((model)), ((ctk_tree_store_get_type ())))))), &iter, &parent_iter); | |||
1628 | ctk_tree_store_set (CTK_TREE_STORE (model)((((CtkTreeStore*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((model)), ((ctk_tree_store_get_type ())))))), &iter, KEYENTRY_COLUMN, key_entry, -1); | |||
1629 | ||||
1630 | /* store in gsettings */ | |||
1631 | key_entry->settings = g_settings_new_with_path (CUSTOM_KEYBINDING_SCHEMA"org.cafe.control-center.keybinding", key_entry->gsettings_path); | |||
1632 | g_settings_set_string (key_entry->settings, key_entry->gsettings_key, "disabled"); | |||
1633 | g_settings_set_string (key_entry->settings, key_entry->desc_gsettings_key, key_entry->description); | |||
1634 | g_settings_set_string (key_entry->settings, key_entry->cmd_gsettings_key, key_entry->command); | |||
1635 | ||||
1636 | /* add gsettings watches */ | |||
1637 | key_entry->gsettings_cnxn_desc = g_signal_connect (key_entry->settings,g_signal_connect_data ((key_entry->settings), ("changed::name" ), (((GCallback) (keybinding_description_changed))), (key_entry ), ((void*)0), (GConnectFlags) 0) | |||
1638 | "changed::name",g_signal_connect_data ((key_entry->settings), ("changed::name" ), (((GCallback) (keybinding_description_changed))), (key_entry ), ((void*)0), (GConnectFlags) 0) | |||
1639 | G_CALLBACK (keybinding_description_changed),g_signal_connect_data ((key_entry->settings), ("changed::name" ), (((GCallback) (keybinding_description_changed))), (key_entry ), ((void*)0), (GConnectFlags) 0) | |||
1640 | key_entry)g_signal_connect_data ((key_entry->settings), ("changed::name" ), (((GCallback) (keybinding_description_changed))), (key_entry ), ((void*)0), (GConnectFlags) 0); | |||
1641 | key_entry->gsettings_cnxn_cmd = g_signal_connect (key_entry->settings,g_signal_connect_data ((key_entry->settings), ("changed::action" ), (((GCallback) (keybinding_command_changed))), (key_entry), ((void*)0), (GConnectFlags) 0) | |||
1642 | "changed::action",g_signal_connect_data ((key_entry->settings), ("changed::action" ), (((GCallback) (keybinding_command_changed))), (key_entry), ((void*)0), (GConnectFlags) 0) | |||
1643 | G_CALLBACK (keybinding_command_changed),g_signal_connect_data ((key_entry->settings), ("changed::action" ), (((GCallback) (keybinding_command_changed))), (key_entry), ((void*)0), (GConnectFlags) 0) | |||
1644 | key_entry)g_signal_connect_data ((key_entry->settings), ("changed::action" ), (((GCallback) (keybinding_command_changed))), (key_entry), ((void*)0), (GConnectFlags) 0); | |||
1645 | key_entry->gsettings_cnxn = g_signal_connect (key_entry->settings,g_signal_connect_data ((key_entry->settings), ("changed::binding" ), (((GCallback) (keybinding_key_changed))), (key_entry), ((void *)0), (GConnectFlags) 0) | |||
1646 | "changed::binding",g_signal_connect_data ((key_entry->settings), ("changed::binding" ), (((GCallback) (keybinding_key_changed))), (key_entry), ((void *)0), (GConnectFlags) 0) | |||
1647 | G_CALLBACK (keybinding_key_changed),g_signal_connect_data ((key_entry->settings), ("changed::binding" ), (((GCallback) (keybinding_key_changed))), (key_entry), ((void *)0), (GConnectFlags) 0) | |||
1648 | key_entry)g_signal_connect_data ((key_entry->settings), ("changed::binding" ), (((GCallback) (keybinding_key_changed))), (key_entry), ((void *)0), (GConnectFlags) 0); | |||
1649 | ||||
1650 | /* make the new shortcut visible */ | |||
1651 | path = ctk_tree_model_get_path (model, &iter); | |||
1652 | ctk_tree_view_expand_to_path (tree_view, path); | |||
1653 | ctk_tree_view_scroll_to_cell (tree_view, path, NULL((void*)0), FALSE(0), 0, 0); | |||
1654 | ctk_tree_path_free (path); | |||
1655 | } | |||
1656 | else | |||
1657 | { | |||
1658 | g_free (key_entry->gsettings_path); | |||
1659 | g_free (key_entry->gsettings_key); | |||
1660 | g_free (key_entry->description); | |||
1661 | g_free (key_entry->desc_gsettings_key); | |||
1662 | g_free (key_entry->command); | |||
1663 | g_free (key_entry->cmd_gsettings_key); | |||
1664 | g_free (key_entry); | |||
1665 | } | |||
1666 | } | |||
1667 | ||||
1668 | static void | |||
1669 | start_editing_kb_cb (CtkTreeView *treeview, | |||
1670 | CtkTreePath *path, | |||
1671 | CtkTreeViewColumn *column, | |||
1672 | gpointer user_data) | |||
1673 | { | |||
1674 | CtkTreeModel *model; | |||
1675 | CtkTreeIter iter; | |||
1676 | KeyEntry *key; | |||
1677 | ||||
1678 | model = ctk_tree_view_get_model (treeview); | |||
1679 | ctk_tree_model_get_iter (model, &iter, path); | |||
1680 | ctk_tree_model_get (model, &iter, | |||
1681 | KEYENTRY_COLUMN, &key, | |||
1682 | -1); | |||
1683 | ||||
1684 | if (key == NULL((void*)0)) | |||
1685 | { | |||
1686 | /* This is a section heading - expand or collapse */ | |||
1687 | if (ctk_tree_view_row_expanded (treeview, path)) | |||
1688 | ctk_tree_view_collapse_row (treeview, path); | |||
1689 | else | |||
1690 | ctk_tree_view_expand_row (treeview, path, FALSE(0)); | |||
1691 | return; | |||
1692 | } | |||
1693 | ||||
1694 | /* if only the accel can be edited on the selected row | |||
1695 | * always select the accel column */ | |||
1696 | if (key->desc_editable && | |||
1697 | column == ctk_tree_view_get_column (treeview, 0)) | |||
1698 | { | |||
1699 | ctk_widget_grab_focus (CTK_WIDGET (treeview)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((treeview)), ((ctk_widget_get_type ()))))))); | |||
1700 | ctk_tree_view_set_cursor (treeview, path, | |||
1701 | ctk_tree_view_get_column (treeview, 0), | |||
1702 | FALSE(0)); | |||
1703 | update_custom_shortcut (model, &iter); | |||
1704 | } | |||
1705 | else | |||
1706 | { | |||
1707 | ctk_widget_grab_focus (CTK_WIDGET (treeview)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((treeview)), ((ctk_widget_get_type ()))))))); | |||
1708 | ctk_tree_view_set_cursor (treeview, | |||
1709 | path, | |||
1710 | ctk_tree_view_get_column (treeview, 1), | |||
1711 | TRUE(!(0))); | |||
1712 | } | |||
1713 | } | |||
1714 | ||||
1715 | static gboolean | |||
1716 | start_editing_cb (CtkTreeView *tree_view, | |||
1717 | CdkEventButton *event, | |||
1718 | gpointer user_data) | |||
1719 | { | |||
1720 | CtkTreePath *path; | |||
1721 | CtkTreeViewColumn *column; | |||
1722 | ||||
1723 | if ((event->window != ctk_tree_view_get_bin_window (tree_view)) || | |||
1724 | (event->type != CDK_2BUTTON_PRESS)) | |||
1725 | return FALSE(0); | |||
1726 | ||||
1727 | if (ctk_tree_view_get_path_at_pos (tree_view, | |||
1728 | (gint) event->x, | |||
1729 | (gint) event->y, | |||
1730 | &path, &column, | |||
1731 | NULL((void*)0), NULL((void*)0))) | |||
1732 | { | |||
1733 | IdleData *idle_data; | |||
1734 | CtkTreeModel *model; | |||
1735 | CtkTreeIter iter; | |||
1736 | KeyEntry *key; | |||
1737 | ||||
1738 | if (ctk_tree_path_get_depth (path) == 1) | |||
1739 | { | |||
1740 | ctk_tree_path_free (path); | |||
1741 | return FALSE(0); | |||
1742 | } | |||
1743 | ||||
1744 | model = ctk_tree_view_get_model (tree_view); | |||
1745 | ctk_tree_model_get_iter (model, &iter, path); | |||
1746 | ctk_tree_model_get (model, &iter, | |||
1747 | KEYENTRY_COLUMN, &key, | |||
1748 | -1); | |||
1749 | ||||
1750 | /* if only the accel can be edited on the selected row | |||
1751 | * always select the accel column */ | |||
1752 | if (key->desc_editable && | |||
1753 | column == ctk_tree_view_get_column (tree_view, 0)) | |||
1754 | { | |||
1755 | ctk_widget_grab_focus (CTK_WIDGET (tree_view)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((tree_view)), ((ctk_widget_get_type ()))))))); | |||
1756 | ctk_tree_view_set_cursor (tree_view, path, | |||
1757 | ctk_tree_view_get_column (tree_view, 0), | |||
1758 | FALSE(0)); | |||
1759 | update_custom_shortcut (model, &iter); | |||
1760 | } | |||
1761 | else | |||
1762 | { | |||
1763 | idle_data = g_new (IdleData, 1)((IdleData *) g_malloc_n ((1), sizeof (IdleData))); | |||
1764 | idle_data->tree_view = tree_view; | |||
1765 | idle_data->path = path; | |||
1766 | idle_data->column = key->desc_editable ? column : | |||
1767 | ctk_tree_view_get_column (tree_view, 1); | |||
1768 | g_idle_add ((GSourceFunc) real_start_editing_cb, idle_data); | |||
1769 | block_accels = TRUE(!(0)); | |||
1770 | } | |||
1771 | g_signal_stop_emission_by_name (tree_view, "button_press_event"); | |||
1772 | } | |||
1773 | return TRUE(!(0)); | |||
1774 | } | |||
1775 | ||||
1776 | /* this handler is used to keep accels from activating while the user | |||
1777 | * is assigning a new shortcut so that he won't accidentally trigger one | |||
1778 | * of the widgets */ | |||
1779 | static gboolean maybe_block_accels(CtkWidget* widget, CdkEventKey* event, gpointer user_data) | |||
1780 | { | |||
1781 | if (block_accels) | |||
1782 | { | |||
1783 | return ctk_window_propagate_key_event(CTK_WINDOW(widget)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((widget)), ((ctk_window_get_type ())))))), event); | |||
1784 | } | |||
1785 | ||||
1786 | return FALSE(0); | |||
1787 | } | |||
1788 | ||||
1789 | static void | |||
1790 | cb_dialog_response (CtkWidget *widget, gint response_id, gpointer data) | |||
1791 | { | |||
1792 | CtkBuilder *builder = data; | |||
1793 | CtkTreeView *treeview; | |||
1794 | CtkTreeModel *model; | |||
1795 | CtkTreeSelection *selection; | |||
1796 | CtkTreeIter iter; | |||
1797 | ||||
1798 | treeview = CTK_TREE_VIEW (ctk_builder_get_object (builder,((((CtkTreeView*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((ctk_builder_get_object (builder, "shortcut_treeview"))), ((ctk_tree_view_get_type ())))))) | |||
1799 | "shortcut_treeview"))((((CtkTreeView*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((ctk_builder_get_object (builder, "shortcut_treeview"))), ((ctk_tree_view_get_type ())))))); | |||
1800 | model = ctk_tree_view_get_model (treeview); | |||
1801 | ||||
1802 | if (response_id == CTK_RESPONSE_HELP) | |||
| ||||
1803 | { | |||
1804 | capplet_help (CTK_WINDOW (widget)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((widget)), ((ctk_window_get_type ())))))), | |||
1805 | "goscustdesk-39"); | |||
1806 | } | |||
1807 | else if (response_id == RESPONSE_ADD0) | |||
1808 | { | |||
1809 | add_custom_shortcut (treeview, model); | |||
1810 | } | |||
1811 | else if (response_id == RESPONSE_REMOVE1) | |||
1812 | { | |||
1813 | selection = ctk_tree_view_get_selection (treeview); | |||
1814 | if (ctk_tree_selection_get_selected (selection, NULL((void*)0), &iter)) | |||
1815 | { | |||
1816 | remove_custom_shortcut (model, &iter); | |||
1817 | } | |||
1818 | } | |||
1819 | else | |||
1820 | { | |||
1821 | clear_old_model (builder); | |||
1822 | ctk_main_quit (); | |||
1823 | } | |||
1824 | } | |||
1825 | ||||
1826 | static void | |||
1827 | selection_changed (CtkTreeSelection *selection, gpointer data) | |||
1828 | { | |||
1829 | CtkWidget *button = data; | |||
1830 | CtkTreeModel *model; | |||
1831 | CtkTreeIter iter; | |||
1832 | KeyEntry *key; | |||
1833 | gboolean can_remove; | |||
1834 | ||||
1835 | can_remove = FALSE(0); | |||
1836 | if (ctk_tree_selection_get_selected (selection, &model, &iter)) | |||
1837 | { | |||
1838 | ctk_tree_model_get (model, &iter, KEYENTRY_COLUMN, &key, -1); | |||
1839 | if (key && key->command != NULL((void*)0) && key->editable) | |||
1840 | can_remove = TRUE(!(0)); | |||
1841 | } | |||
1842 | ||||
1843 | ctk_widget_set_sensitive (button, can_remove); | |||
1844 | } | |||
1845 | ||||
1846 | static void | |||
1847 | cb_app_dialog_response (CtkWidget *dialog, gint response_id, gpointer data) | |||
1848 | { | |||
1849 | if (response_id == CTK_RESPONSE_OK) | |||
1850 | { | |||
1851 | GAppInfo *info; | |||
1852 | const gchar *custom_name; | |||
1853 | ||||
1854 | info = ctk_app_chooser_get_app_info (CTK_APP_CHOOSER (dialog)((((CtkAppChooser*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((dialog)), ((ctk_app_chooser_get_type ()))))))); | |||
1855 | ||||
1856 | ctk_entry_set_text (CTK_ENTRY (custom_shortcut_command_entry)((((CtkEntry*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((custom_shortcut_command_entry)), ((ctk_entry_get_type () )))))), | |||
1857 | g_app_info_get_executable (info)); | |||
1858 | /* if name isn't set yet, use the associated one */ | |||
1859 | custom_name = ctk_entry_get_text (CTK_ENTRY (custom_shortcut_name_entry)((((CtkEntry*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((custom_shortcut_name_entry)), ((ctk_entry_get_type ()))) )))); | |||
1860 | if (! custom_name || custom_name[0] == '\0') | |||
1861 | ctk_entry_set_text (CTK_ENTRY (custom_shortcut_name_entry)((((CtkEntry*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((custom_shortcut_name_entry)), ((ctk_entry_get_type ()))) ))), | |||
1862 | g_app_info_get_display_name (info)); | |||
1863 | ||||
1864 | g_object_unref (info); | |||
1865 | } | |||
1866 | ||||
1867 | ctk_widget_hide (dialog); | |||
1868 | } | |||
1869 | ||||
1870 | static void | |||
1871 | setup_dialog (CtkBuilder *builder, GSettings *croma_settings) | |||
1872 | { | |||
1873 | CtkCellRenderer *renderer; | |||
1874 | CtkTreeViewColumn *column; | |||
1875 | CtkWidget *widget; | |||
1876 | CtkTreeView *treeview; | |||
1877 | CtkTreeSelection *selection; | |||
1878 | CtkWidget *button; | |||
1879 | ||||
1880 | treeview = CTK_TREE_VIEW (ctk_builder_get_object (builder,((((CtkTreeView*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((ctk_builder_get_object (builder, "shortcut_treeview"))), ((ctk_tree_view_get_type ())))))) | |||
1881 | "shortcut_treeview"))((((CtkTreeView*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((ctk_builder_get_object (builder, "shortcut_treeview"))), ((ctk_tree_view_get_type ())))))); | |||
1882 | ||||
1883 | g_signal_connect (treeview, "button_press_event",g_signal_connect_data ((treeview), ("button_press_event"), (( (GCallback) (start_editing_cb))), (builder), ((void*)0), (GConnectFlags ) 0) | |||
1884 | G_CALLBACK (start_editing_cb), builder)g_signal_connect_data ((treeview), ("button_press_event"), (( (GCallback) (start_editing_cb))), (builder), ((void*)0), (GConnectFlags ) 0); | |||
1885 | g_signal_connect (treeview, "row-activated",g_signal_connect_data ((treeview), ("row-activated"), (((GCallback ) (start_editing_kb_cb))), (((void*)0)), ((void*)0), (GConnectFlags ) 0) | |||
1886 | G_CALLBACK (start_editing_kb_cb), NULL)g_signal_connect_data ((treeview), ("row-activated"), (((GCallback ) (start_editing_kb_cb))), (((void*)0)), ((void*)0), (GConnectFlags ) 0); | |||
1887 | ||||
1888 | renderer = ctk_cell_renderer_text_new (); | |||
1889 | ||||
1890 | g_signal_connect (renderer, "edited",g_signal_connect_data ((renderer), ("edited"), (((GCallback) ( description_edited_callback))), (treeview), ((void*)0), (GConnectFlags ) 0) | |||
1891 | G_CALLBACK (description_edited_callback),g_signal_connect_data ((renderer), ("edited"), (((GCallback) ( description_edited_callback))), (treeview), ((void*)0), (GConnectFlags ) 0) | |||
1892 | treeview)g_signal_connect_data ((renderer), ("edited"), (((GCallback) ( description_edited_callback))), (treeview), ((void*)0), (GConnectFlags ) 0); | |||
1893 | ||||
1894 | column = ctk_tree_view_column_new_with_attributes (_("Action")gettext ("Action"), | |||
1895 | renderer, | |||
1896 | "text", DESCRIPTION_COLUMN, | |||
1897 | NULL((void*)0)); | |||
1898 | ctk_tree_view_column_set_cell_data_func (column, renderer, description_set_func, NULL((void*)0), NULL((void*)0)); | |||
1899 | ctk_tree_view_column_set_resizable (column, FALSE(0)); | |||
1900 | ||||
1901 | ctk_tree_view_append_column (treeview, column); | |||
1902 | ctk_tree_view_column_set_sort_column_id (column, DESCRIPTION_COLUMN); | |||
1903 | ||||
1904 | renderer = (CtkCellRenderer *) g_object_new (EGG_TYPE_CELL_RENDERER_KEYS(egg_cell_renderer_keys_get_type ()), | |||
1905 | "accel_mode", EGG_CELL_RENDERER_KEYS_MODE_X, | |||
1906 | NULL((void*)0)); | |||
1907 | ||||
1908 | g_signal_connect (renderer, "accel_edited",g_signal_connect_data ((renderer), ("accel_edited"), (((GCallback ) (accel_edited_callback))), (treeview), ((void*)0), (GConnectFlags ) 0) | |||
1909 | G_CALLBACK (accel_edited_callback),g_signal_connect_data ((renderer), ("accel_edited"), (((GCallback ) (accel_edited_callback))), (treeview), ((void*)0), (GConnectFlags ) 0) | |||
1910 | treeview)g_signal_connect_data ((renderer), ("accel_edited"), (((GCallback ) (accel_edited_callback))), (treeview), ((void*)0), (GConnectFlags ) 0); | |||
1911 | ||||
1912 | g_signal_connect (renderer, "accel_cleared",g_signal_connect_data ((renderer), ("accel_cleared"), (((GCallback ) (accel_cleared_callback))), (treeview), ((void*)0), (GConnectFlags ) 0) | |||
1913 | G_CALLBACK (accel_cleared_callback),g_signal_connect_data ((renderer), ("accel_cleared"), (((GCallback ) (accel_cleared_callback))), (treeview), ((void*)0), (GConnectFlags ) 0) | |||
1914 | treeview)g_signal_connect_data ((renderer), ("accel_cleared"), (((GCallback ) (accel_cleared_callback))), (treeview), ((void*)0), (GConnectFlags ) 0); | |||
1915 | ||||
1916 | column = ctk_tree_view_column_new_with_attributes (_("Shortcut")gettext ("Shortcut"), renderer, NULL((void*)0)); | |||
1917 | ctk_tree_view_column_set_cell_data_func (column, renderer, accel_set_func, NULL((void*)0), NULL((void*)0)); | |||
1918 | ctk_tree_view_column_set_resizable (column, FALSE(0)); | |||
1919 | ||||
1920 | ctk_tree_view_append_column (treeview, column); | |||
1921 | ctk_tree_view_column_set_sort_column_id (column, KEYENTRY_COLUMN); | |||
1922 | ||||
1923 | g_signal_connect (croma_settings,g_signal_connect_data ((croma_settings), ("changed::num-workspaces" ), (((GCallback) (key_entry_controlling_key_changed))), (builder ), ((void*)0), (GConnectFlags) 0) | |||
1924 | "changed::num-workspaces",g_signal_connect_data ((croma_settings), ("changed::num-workspaces" ), (((GCallback) (key_entry_controlling_key_changed))), (builder ), ((void*)0), (GConnectFlags) 0) | |||
1925 | G_CALLBACK (key_entry_controlling_key_changed),g_signal_connect_data ((croma_settings), ("changed::num-workspaces" ), (((GCallback) (key_entry_controlling_key_changed))), (builder ), ((void*)0), (GConnectFlags) 0) | |||
1926 | builder)g_signal_connect_data ((croma_settings), ("changed::num-workspaces" ), (((GCallback) (key_entry_controlling_key_changed))), (builder ), ((void*)0), (GConnectFlags) 0); | |||
1927 | ||||
1928 | /* set up the dialog */ | |||
1929 | reload_key_entries (builder); | |||
1930 | ||||
1931 | widget = _ctk_builder_get_widget (builder, "cafe-keybinding-dialog"); | |||
1932 | ctk_window_set_default_size (CTK_WINDOW (widget)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((widget)), ((ctk_window_get_type ())))))), 400, 500); | |||
1933 | widget = _ctk_builder_get_widget (builder, "label-suggest"); | |||
1934 | ctk_label_set_line_wrap (CTK_LABEL (widget)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((widget)), ((ctk_label_get_type ())))))), TRUE(!(0))); | |||
1935 | ctk_label_set_max_width_chars (CTK_LABEL (widget)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((widget)), ((ctk_label_get_type ())))))), 60); | |||
1936 | ||||
1937 | widget = _ctk_builder_get_widget (builder, "cafe-keybinding-dialog"); | |||
1938 | capplet_set_icon (widget, "preferences-desktop-keyboard-shortcuts"); | |||
1939 | ctk_widget_show (widget); | |||
1940 | ||||
1941 | g_signal_connect (widget, "key_press_event", G_CALLBACK (maybe_block_accels), NULL)g_signal_connect_data ((widget), ("key_press_event"), (((GCallback ) (maybe_block_accels))), (((void*)0)), ((void*)0), (GConnectFlags ) 0); | |||
1942 | g_signal_connect (widget, "response", G_CALLBACK (cb_dialog_response), builder)g_signal_connect_data ((widget), ("response"), (((GCallback) ( cb_dialog_response))), (builder), ((void*)0), (GConnectFlags) 0); | |||
1943 | ||||
1944 | selection = ctk_tree_view_get_selection (CTK_TREE_VIEW (treeview)((((CtkTreeView*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((treeview)), ((ctk_tree_view_get_type ()))))))); | |||
1945 | g_signal_connect (selection, "changed",g_signal_connect_data ((selection), ("changed"), (((GCallback ) (selection_changed))), (_ctk_builder_get_widget (builder, "remove-button" )), ((void*)0), (GConnectFlags) 0) | |||
1946 | G_CALLBACK (selection_changed),g_signal_connect_data ((selection), ("changed"), (((GCallback ) (selection_changed))), (_ctk_builder_get_widget (builder, "remove-button" )), ((void*)0), (GConnectFlags) 0) | |||
1947 | _ctk_builder_get_widget (builder, "remove-button"))g_signal_connect_data ((selection), ("changed"), (((GCallback ) (selection_changed))), (_ctk_builder_get_widget (builder, "remove-button" )), ((void*)0), (GConnectFlags) 0); | |||
1948 | ||||
1949 | /* setup the custom shortcut dialog */ | |||
1950 | custom_shortcut_dialog = _ctk_builder_get_widget (builder, | |||
1951 | "custom-shortcut-dialog"); | |||
1952 | custom_shortcut_name_entry = _ctk_builder_get_widget (builder, | |||
1953 | "custom-shortcut-name-entry"); | |||
1954 | custom_shortcut_command_entry = _ctk_builder_get_widget (builder, | |||
1955 | "custom-shortcut-command-entry"); | |||
1956 | ctk_dialog_set_default_response (CTK_DIALOG (custom_shortcut_dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((custom_shortcut_dialog)), ((ctk_dialog_get_type ())))))), | |||
1957 | CTK_RESPONSE_OK); | |||
1958 | ctk_window_set_transient_for (CTK_WINDOW (custom_shortcut_dialog)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((custom_shortcut_dialog)), ((ctk_window_get_type ())))))), | |||
1959 | CTK_WINDOW (widget)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((widget)), ((ctk_window_get_type ()))))))); | |||
1960 | button = _ctk_builder_get_widget (builder, "custom-shortcut-command-button"); | |||
1961 | widget = _ctk_builder_get_widget (builder, "custom-shortcut-application-dialog"); | |||
1962 | g_signal_connect_swapped (button, "clicked", G_CALLBACK (ctk_dialog_run), widget)g_signal_connect_data ((button), ("clicked"), (((GCallback) ( ctk_dialog_run))), (widget), ((void*)0), G_CONNECT_SWAPPED); | |||
1963 | g_signal_connect (widget, "response", G_CALLBACK (cb_app_dialog_response), NULL)g_signal_connect_data ((widget), ("response"), (((GCallback) ( cb_app_dialog_response))), (((void*)0)), ((void*)0), (GConnectFlags ) 0); | |||
1964 | widget = ctk_app_chooser_dialog_get_widget (CTK_APP_CHOOSER_DIALOG (widget)((((CtkAppChooserDialog*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((widget)), ((ctk_app_chooser_dialog_get_type ()))))))); | |||
1965 | ctk_app_chooser_widget_set_show_all (CTK_APP_CHOOSER_WIDGET (widget)((((CtkAppChooserWidget*) (void *) g_type_check_instance_cast ((GTypeInstance*) ((widget)), ((ctk_app_chooser_widget_get_type ())))))), TRUE(!(0))); | |||
1966 | } | |||
1967 | ||||
1968 | static void | |||
1969 | on_window_manager_change (const char *wm_name, CtkBuilder *builder) | |||
1970 | { | |||
1971 | reload_key_entries (builder); | |||
1972 | } | |||
1973 | ||||
1974 | int | |||
1975 | main (int argc, char *argv[]) | |||
1976 | { | |||
1977 | CtkBuilder *builder; | |||
1978 | GSettings *croma_settings; | |||
1979 | ||||
1980 | capplet_init (NULL((void*)0), &argc, &argv); | |||
1981 | ||||
1982 | activate_settings_daemon (); | |||
1983 | ||||
1984 | builder = create_builder (); | |||
1985 | ||||
1986 | if (!builder) /* Warning was already printed to console */ | |||
1987 | exit (EXIT_FAILURE1); | |||
1988 | ||||
1989 | wm_common_register_window_manager_change ((GFunc) on_window_manager_change, builder); | |||
1990 | ||||
1991 | croma_settings = g_settings_new ("org.cafe.Croma.general"); | |||
1992 | ||||
1993 | setup_dialog (builder, croma_settings); | |||
1994 | ||||
1995 | g_object_set (ctk_settings_get_default (), "ctk-button-images", TRUE(!(0)), NULL((void*)0)); | |||
1996 | ||||
1997 | ctk_main (); | |||
1998 | ||||
1999 | g_object_unref (croma_settings); | |||
2000 | g_object_unref (builder); | |||
2001 | return 0; | |||
2002 | } | |||
2003 | ||||
2004 | /* | |||
2005 | * vim: sw=2 ts=8 cindent noai bs=2 | |||
2006 | */ |