Line |
Branch |
Exec |
Source |
1 |
|
|
/* cc-keyboard-shortcut-editor.h |
2 |
|
|
* |
3 |
|
|
* Copyright (C) 2016 Endless, Inc |
4 |
|
|
* |
5 |
|
|
* This program is free software: you can redistribute it and/or modify |
6 |
|
|
* it under the terms of the GNU General Public License as published by |
7 |
|
|
* the Free Software Foundation, either version 2 of the License, or |
8 |
|
|
* (at your option) any later version. |
9 |
|
|
* |
10 |
|
|
* This program is distributed in the hope that it will be useful, |
11 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 |
|
|
* GNU General Public License for more details. |
14 |
|
|
* |
15 |
|
|
* You should have received a copy of the GNU General Public License |
16 |
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 |
|
|
* |
18 |
|
|
* Authors: Georges Basile Stavracas Neto <georges.stavracas@gmail.com> |
19 |
|
|
*/ |
20 |
|
|
|
21 |
|
|
#include <glib-object.h> |
22 |
|
|
#include <glib/gi18n.h> |
23 |
|
|
|
24 |
|
|
#include "cc-keyboard-shortcut-editor.h" |
25 |
|
|
#include "keyboard-shortcuts.h" |
26 |
|
|
|
27 |
|
|
struct _CcKeyboardShortcutEditor |
28 |
|
|
{ |
29 |
|
|
AdwWindow parent; |
30 |
|
|
|
31 |
|
|
GtkButton *add_button; |
32 |
|
|
GtkButton *cancel_button; |
33 |
|
|
GtkButton *change_custom_shortcut_button; |
34 |
|
|
GtkEntry *command_entry; |
35 |
|
|
GtkGrid *custom_grid; |
36 |
|
|
GtkShortcutLabel *custom_shortcut_accel_label; |
37 |
|
|
GtkBox *edit_box; |
38 |
|
|
AdwHeaderBar *headerbar; |
39 |
|
|
GtkEntry *name_entry; |
40 |
|
|
GtkLabel *new_shortcut_conflict_label; |
41 |
|
|
GtkButton *remove_button; |
42 |
|
|
GtkButton *replace_button; |
43 |
|
|
GtkButton *reset_button; |
44 |
|
|
GtkButton *reset_custom_button; |
45 |
|
|
GtkButton *set_button; |
46 |
|
|
GtkShortcutLabel *shortcut_accel_label; |
47 |
|
|
GtkLabel *shortcut_conflict_label; |
48 |
|
|
GtkBox *standard_box; |
49 |
|
|
GtkStack *stack; |
50 |
|
|
GtkLabel *top_info_label; |
51 |
|
|
|
52 |
|
|
CcShortcutEditorMode mode; |
53 |
|
|
|
54 |
|
|
CcKeyboardManager *manager; |
55 |
|
|
CcKeyboardItem *item; |
56 |
|
|
GBinding *reset_item_binding; |
57 |
|
|
|
58 |
|
|
CcKeyboardItem *collision_item; |
59 |
|
|
|
60 |
|
|
/* Custom shortcuts */ |
61 |
|
|
gboolean system_shortcuts_inhibited; |
62 |
|
|
guint grab_idle_id; |
63 |
|
|
|
64 |
|
|
CcKeyCombo *custom_combo; |
65 |
|
|
gboolean custom_is_modifier; |
66 |
|
|
gboolean edited : 1; |
67 |
|
|
}; |
68 |
|
|
|
69 |
|
|
static void command_entry_changed_cb (CcKeyboardShortcutEditor *self); |
70 |
|
|
static void name_entry_changed_cb (CcKeyboardShortcutEditor *self); |
71 |
|
|
static void set_button_clicked_cb (CcKeyboardShortcutEditor *self); |
72 |
|
|
|
73 |
|
✗ |
G_DEFINE_TYPE (CcKeyboardShortcutEditor, cc_keyboard_shortcut_editor, ADW_TYPE_WINDOW) |
74 |
|
|
|
75 |
|
|
enum |
76 |
|
|
{ |
77 |
|
|
PROP_0, |
78 |
|
|
PROP_KEYBOARD_ITEM, |
79 |
|
|
PROP_MANAGER, |
80 |
|
|
N_PROPS |
81 |
|
|
}; |
82 |
|
|
|
83 |
|
|
typedef enum |
84 |
|
|
{ |
85 |
|
|
HEADER_MODE_NONE, |
86 |
|
|
HEADER_MODE_ADD, |
87 |
|
|
HEADER_MODE_SET, |
88 |
|
|
HEADER_MODE_REPLACE, |
89 |
|
|
HEADER_MODE_CUSTOM_CANCEL, |
90 |
|
|
HEADER_MODE_CUSTOM_EDIT |
91 |
|
|
} HeaderMode; |
92 |
|
|
|
93 |
|
|
typedef enum |
94 |
|
|
{ |
95 |
|
|
PAGE_CUSTOM, |
96 |
|
|
PAGE_EDIT, |
97 |
|
|
PAGE_STANDARD, |
98 |
|
|
} ShortcutEditorPage; |
99 |
|
|
|
100 |
|
|
static GParamSpec *properties [N_PROPS] = { NULL, }; |
101 |
|
|
|
102 |
|
|
/* Getter and setter for ShortcutEditorPage */ |
103 |
|
|
static ShortcutEditorPage |
104 |
|
✗ |
get_shortcut_editor_page (CcKeyboardShortcutEditor *self) |
105 |
|
|
{ |
106 |
|
✗ |
if (gtk_stack_get_visible_child (self->stack) == GTK_WIDGET (self->edit_box)) |
107 |
|
✗ |
return PAGE_EDIT; |
108 |
|
|
|
109 |
|
✗ |
if (gtk_stack_get_visible_child (self->stack) == GTK_WIDGET (self->custom_grid)) |
110 |
|
✗ |
return PAGE_CUSTOM; |
111 |
|
|
|
112 |
|
✗ |
return PAGE_STANDARD; |
113 |
|
|
} |
114 |
|
|
|
115 |
|
|
static void |
116 |
|
✗ |
set_shortcut_editor_page (CcKeyboardShortcutEditor *self, |
117 |
|
|
ShortcutEditorPage page) |
118 |
|
|
{ |
119 |
|
✗ |
switch (page) |
120 |
|
|
{ |
121 |
|
✗ |
case PAGE_CUSTOM: |
122 |
|
✗ |
gtk_stack_set_visible_child (self->stack, GTK_WIDGET (self->custom_grid)); |
123 |
|
✗ |
break; |
124 |
|
|
|
125 |
|
✗ |
case PAGE_EDIT: |
126 |
|
✗ |
gtk_stack_set_visible_child (self->stack, GTK_WIDGET (self->edit_box)); |
127 |
|
✗ |
break; |
128 |
|
|
|
129 |
|
✗ |
case PAGE_STANDARD: |
130 |
|
✗ |
gtk_stack_set_visible_child (self->stack, GTK_WIDGET (self->standard_box)); |
131 |
|
✗ |
break; |
132 |
|
|
|
133 |
|
✗ |
default: |
134 |
|
✗ |
g_assert_not_reached (); |
135 |
|
|
} |
136 |
|
|
|
137 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->top_info_label), page != PAGE_CUSTOM); |
138 |
|
✗ |
} |
139 |
|
|
|
140 |
|
|
static void |
141 |
|
✗ |
apply_custom_item_fields (CcKeyboardShortcutEditor *self, |
142 |
|
|
CcKeyboardItem *item) |
143 |
|
|
{ |
144 |
|
|
/* Only setup the binding when it was actually edited */ |
145 |
|
✗ |
if (self->edited) |
146 |
|
|
{ |
147 |
|
✗ |
CcKeyCombo *combo = self->custom_combo; |
148 |
|
|
|
149 |
|
✗ |
cc_keyboard_item_disable (item); |
150 |
|
|
|
151 |
|
✗ |
if (combo->keycode != 0 || combo->keyval != 0 || combo->mask != 0) |
152 |
|
✗ |
cc_keyboard_item_add_key_combo (item, combo); |
153 |
|
|
} |
154 |
|
|
|
155 |
|
|
/* Set the keyboard shortcut name and command for custom entries */ |
156 |
|
✗ |
if (cc_keyboard_item_get_item_type (item) == CC_KEYBOARD_ITEM_TYPE_GSETTINGS_PATH) |
157 |
|
|
{ |
158 |
|
✗ |
g_settings_set_string (cc_keyboard_item_get_settings (item), |
159 |
|
|
"name", |
160 |
|
✗ |
gtk_editable_get_text (GTK_EDITABLE (self->name_entry))); |
161 |
|
✗ |
g_settings_set_string (cc_keyboard_item_get_settings (item), |
162 |
|
|
"command", |
163 |
|
✗ |
gtk_editable_get_text (GTK_EDITABLE (self->command_entry))); |
164 |
|
|
} |
165 |
|
✗ |
} |
166 |
|
|
|
167 |
|
|
static void |
168 |
|
✗ |
clear_custom_entries (CcKeyboardShortcutEditor *self) |
169 |
|
|
{ |
170 |
|
✗ |
g_signal_handlers_block_by_func (self->command_entry, command_entry_changed_cb, self); |
171 |
|
✗ |
g_signal_handlers_block_by_func (self->name_entry, name_entry_changed_cb, self); |
172 |
|
|
|
173 |
|
✗ |
gtk_editable_set_text (GTK_EDITABLE (self->name_entry), ""); |
174 |
|
✗ |
gtk_editable_set_text (GTK_EDITABLE (self->command_entry), ""); |
175 |
|
|
|
176 |
|
✗ |
gtk_shortcut_label_set_accelerator (GTK_SHORTCUT_LABEL (self->custom_shortcut_accel_label), ""); |
177 |
|
✗ |
gtk_label_set_label (self->new_shortcut_conflict_label, ""); |
178 |
|
✗ |
gtk_label_set_label (self->shortcut_conflict_label, ""); |
179 |
|
|
|
180 |
|
✗ |
memset (self->custom_combo, 0, sizeof (CcKeyCombo)); |
181 |
|
✗ |
self->custom_is_modifier = TRUE; |
182 |
|
✗ |
self->edited = FALSE; |
183 |
|
|
|
184 |
|
✗ |
self->collision_item = NULL; |
185 |
|
|
|
186 |
|
✗ |
g_signal_handlers_unblock_by_func (self->command_entry, command_entry_changed_cb, self); |
187 |
|
✗ |
g_signal_handlers_unblock_by_func (self->name_entry, name_entry_changed_cb, self); |
188 |
|
✗ |
} |
189 |
|
|
|
190 |
|
|
static void |
191 |
|
✗ |
cancel_editing (CcKeyboardShortcutEditor *self) |
192 |
|
|
{ |
193 |
|
✗ |
cc_keyboard_shortcut_editor_set_item (self, NULL); |
194 |
|
✗ |
clear_custom_entries (self); |
195 |
|
|
|
196 |
|
✗ |
gtk_window_close (GTK_WINDOW (self)); |
197 |
|
✗ |
} |
198 |
|
|
|
199 |
|
|
static gboolean |
200 |
|
✗ |
is_custom_shortcut (CcKeyboardShortcutEditor *self) { |
201 |
|
✗ |
return self->item == NULL || cc_keyboard_item_get_item_type (self->item) == CC_KEYBOARD_ITEM_TYPE_GSETTINGS_PATH; |
202 |
|
|
} |
203 |
|
|
|
204 |
|
|
static void |
205 |
|
✗ |
inhibit_system_shortcuts (CcKeyboardShortcutEditor *self) |
206 |
|
|
{ |
207 |
|
|
GtkNative *native; |
208 |
|
|
GdkSurface *surface; |
209 |
|
|
|
210 |
|
✗ |
if (self->system_shortcuts_inhibited) |
211 |
|
✗ |
return; |
212 |
|
|
|
213 |
|
✗ |
native = gtk_widget_get_native (GTK_WIDGET (self)); |
214 |
|
✗ |
surface = gtk_native_get_surface (native); |
215 |
|
|
|
216 |
|
✗ |
if (GDK_IS_TOPLEVEL (surface)) |
217 |
|
|
{ |
218 |
|
✗ |
gdk_toplevel_inhibit_system_shortcuts (GDK_TOPLEVEL (surface), NULL); |
219 |
|
✗ |
self->system_shortcuts_inhibited = TRUE; |
220 |
|
|
} |
221 |
|
|
} |
222 |
|
|
|
223 |
|
|
static void |
224 |
|
✗ |
uninhibit_system_shortcuts (CcKeyboardShortcutEditor *self) |
225 |
|
|
{ |
226 |
|
|
GtkNative *native; |
227 |
|
|
GdkSurface *surface; |
228 |
|
|
|
229 |
|
✗ |
if (!self->system_shortcuts_inhibited) |
230 |
|
✗ |
return; |
231 |
|
|
|
232 |
|
✗ |
native = gtk_widget_get_native (GTK_WIDGET (self)); |
233 |
|
✗ |
surface = gtk_native_get_surface (native); |
234 |
|
|
|
235 |
|
✗ |
if (GDK_IS_TOPLEVEL (surface)) |
236 |
|
|
{ |
237 |
|
✗ |
gdk_toplevel_restore_system_shortcuts (GDK_TOPLEVEL (surface)); |
238 |
|
✗ |
self->system_shortcuts_inhibited = FALSE; |
239 |
|
|
} |
240 |
|
|
} |
241 |
|
|
|
242 |
|
|
static void |
243 |
|
✗ |
update_shortcut (CcKeyboardShortcutEditor *self) |
244 |
|
|
{ |
245 |
|
✗ |
if (!self->item) |
246 |
|
✗ |
return; |
247 |
|
|
|
248 |
|
|
/* Setup the binding */ |
249 |
|
✗ |
apply_custom_item_fields (self, self->item); |
250 |
|
|
|
251 |
|
|
/* Eventually disable the conflict shortcut */ |
252 |
|
✗ |
if (self->collision_item) |
253 |
|
✗ |
cc_keyboard_item_disable (self->collision_item); |
254 |
|
|
|
255 |
|
|
/* Cleanup whatever was set before */ |
256 |
|
✗ |
clear_custom_entries (self); |
257 |
|
|
|
258 |
|
✗ |
cc_keyboard_shortcut_editor_set_item (self, NULL); |
259 |
|
|
} |
260 |
|
|
|
261 |
|
|
static GtkShortcutLabel* |
262 |
|
✗ |
get_current_shortcut_label (CcKeyboardShortcutEditor *self) |
263 |
|
|
{ |
264 |
|
✗ |
if (is_custom_shortcut (self)) |
265 |
|
✗ |
return GTK_SHORTCUT_LABEL (self->custom_shortcut_accel_label); |
266 |
|
|
|
267 |
|
✗ |
return GTK_SHORTCUT_LABEL (self->shortcut_accel_label); |
268 |
|
|
} |
269 |
|
|
|
270 |
|
|
static void |
271 |
|
✗ |
set_header_mode (CcKeyboardShortcutEditor *self, |
272 |
|
|
HeaderMode mode) |
273 |
|
|
{ |
274 |
|
✗ |
gboolean show_end_title_buttons = mode == HEADER_MODE_CUSTOM_EDIT || |
275 |
|
|
mode == HEADER_MODE_NONE; |
276 |
|
✗ |
adw_header_bar_set_show_end_title_buttons (self->headerbar, show_end_title_buttons); |
277 |
|
|
|
278 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->add_button), mode == HEADER_MODE_ADD); |
279 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->cancel_button), mode != HEADER_MODE_NONE && |
280 |
|
|
mode != HEADER_MODE_CUSTOM_EDIT); |
281 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->replace_button), mode == HEADER_MODE_REPLACE); |
282 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->set_button), mode == HEADER_MODE_SET); |
283 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->remove_button), mode == HEADER_MODE_CUSTOM_EDIT); |
284 |
|
✗ |
} |
285 |
|
|
|
286 |
|
|
static void |
287 |
|
✗ |
setup_custom_shortcut (CcKeyboardShortcutEditor *self) |
288 |
|
|
{ |
289 |
|
|
GtkShortcutLabel *shortcut_label; |
290 |
|
|
CcKeyboardItem *collision_item; |
291 |
|
|
HeaderMode mode; |
292 |
|
|
gboolean is_custom, is_accel_empty; |
293 |
|
|
gboolean valid, accel_valid; |
294 |
|
✗ |
g_autofree char *accel = NULL; |
295 |
|
|
|
296 |
|
✗ |
is_custom = is_custom_shortcut (self); |
297 |
|
✗ |
accel_valid = is_valid_binding (self->custom_combo) && |
298 |
|
✗ |
is_valid_accel (self->custom_combo) && |
299 |
|
✗ |
!self->custom_is_modifier; |
300 |
|
|
|
301 |
|
✗ |
is_accel_empty = is_empty_binding (self->custom_combo); |
302 |
|
|
|
303 |
|
✗ |
if (is_accel_empty) |
304 |
|
✗ |
accel_valid = TRUE; |
305 |
|
✗ |
valid = accel_valid; |
306 |
|
|
|
307 |
|
|
/* Additional checks for custom shortcuts */ |
308 |
|
✗ |
if (is_custom) |
309 |
|
|
{ |
310 |
|
✗ |
if (accel_valid) |
311 |
|
|
{ |
312 |
|
✗ |
set_shortcut_editor_page (self, PAGE_CUSTOM); |
313 |
|
|
|
314 |
|
|
/* We have to check if the current accelerator is empty in order to |
315 |
|
|
* decide if we show the "Set Shortcut" button or the accelerator label */ |
316 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->reset_custom_button), !is_accel_empty); |
317 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->change_custom_shortcut_button), is_accel_empty); |
318 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->custom_shortcut_accel_label), !is_accel_empty); |
319 |
|
|
} |
320 |
|
|
|
321 |
|
✗ |
valid = accel_valid && |
322 |
|
✗ |
gtk_entry_get_text_length (self->name_entry) > 0 && |
323 |
|
✗ |
gtk_entry_get_text_length (self->command_entry) > 0; |
324 |
|
|
} |
325 |
|
|
|
326 |
|
✗ |
gtk_widget_set_sensitive (GTK_WIDGET (self->replace_button), valid); |
327 |
|
✗ |
gtk_widget_set_sensitive (GTK_WIDGET (self->add_button), valid); |
328 |
|
✗ |
if (valid) |
329 |
|
✗ |
set_header_mode (self, HEADER_MODE_ADD); |
330 |
|
|
else |
331 |
|
✗ |
set_header_mode (self, is_custom ? HEADER_MODE_CUSTOM_CANCEL : HEADER_MODE_NONE); |
332 |
|
|
|
333 |
|
|
/* Nothing else to do if the shortcut is invalid */ |
334 |
|
✗ |
if (!accel_valid) |
335 |
|
✗ |
return; |
336 |
|
|
|
337 |
|
|
/* Valid shortcut, show it in the standard page */ |
338 |
|
✗ |
if (!is_custom) |
339 |
|
✗ |
set_shortcut_editor_page (self, PAGE_STANDARD); |
340 |
|
|
|
341 |
|
✗ |
shortcut_label = get_current_shortcut_label (self); |
342 |
|
|
|
343 |
|
✗ |
collision_item = cc_keyboard_manager_get_collision (self->manager, |
344 |
|
|
self->item, |
345 |
|
|
self->custom_combo); |
346 |
|
|
|
347 |
|
✗ |
accel = gtk_accelerator_name (self->custom_combo->keyval, self->custom_combo->mask); |
348 |
|
|
|
349 |
|
|
|
350 |
|
|
/* Setup the accelerator label */ |
351 |
|
✗ |
gtk_shortcut_label_set_accelerator (shortcut_label, accel); |
352 |
|
|
|
353 |
|
✗ |
self->edited = TRUE; |
354 |
|
|
|
355 |
|
✗ |
uninhibit_system_shortcuts (self); |
356 |
|
|
|
357 |
|
|
/* |
358 |
|
|
* Oops! Looks like the accelerator is already being used, so we |
359 |
|
|
* must warn the user and let it be very clear that adding this |
360 |
|
|
* shortcut will disable the other. |
361 |
|
|
*/ |
362 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->new_shortcut_conflict_label), collision_item != NULL); |
363 |
|
|
|
364 |
|
✗ |
if (collision_item) |
365 |
|
|
{ |
366 |
|
|
GtkLabel *label; |
367 |
|
✗ |
g_autofree gchar *friendly_accelerator = NULL; |
368 |
|
✗ |
g_autofree gchar *collision_text = NULL; |
369 |
|
|
|
370 |
|
✗ |
friendly_accelerator = convert_keysym_state_to_string (self->custom_combo); |
371 |
|
|
|
372 |
|
|
/* TRANSLATORS: Don't translate/transliterate <b>%s</b>, which is the accelerator used */ |
373 |
|
✗ |
collision_text = g_markup_printf_escaped (_("<b>%s</b> is already being used for %s. If you " |
374 |
|
|
"replace it, %s will be disabled"), |
375 |
|
|
friendly_accelerator, |
376 |
|
|
cc_keyboard_item_get_description (collision_item), |
377 |
|
|
cc_keyboard_item_get_description (collision_item)); |
378 |
|
✗ |
label = is_custom_shortcut (self) ? self->new_shortcut_conflict_label : self->shortcut_conflict_label; |
379 |
|
|
|
380 |
|
✗ |
gtk_label_set_markup (label, collision_text); |
381 |
|
|
} |
382 |
|
|
|
383 |
|
|
/* |
384 |
|
|
* When there is a collision between the current shortcut and another shortcut, |
385 |
|
|
* and we're editing an existing shortcut (rather than creating a new one), setup |
386 |
|
|
* the headerbar to display "Cancel" and "Replace". Otherwise, make sure to set |
387 |
|
|
* only the close button again. |
388 |
|
|
*/ |
389 |
|
✗ |
if (collision_item) |
390 |
|
|
{ |
391 |
|
✗ |
mode = HEADER_MODE_REPLACE; |
392 |
|
|
} |
393 |
|
|
else |
394 |
|
|
{ |
395 |
|
✗ |
if (self->mode == CC_SHORTCUT_EDITOR_EDIT) |
396 |
|
✗ |
mode = is_custom ? HEADER_MODE_CUSTOM_EDIT : HEADER_MODE_SET; |
397 |
|
|
else |
398 |
|
✗ |
mode = is_custom ? HEADER_MODE_ADD : HEADER_MODE_SET; |
399 |
|
|
} |
400 |
|
|
|
401 |
|
✗ |
set_header_mode (self, mode); |
402 |
|
|
|
403 |
|
✗ |
self->collision_item = collision_item; |
404 |
|
|
} |
405 |
|
|
|
406 |
|
|
static void |
407 |
|
✗ |
add_button_clicked_cb (CcKeyboardShortcutEditor *self) |
408 |
|
|
{ |
409 |
|
|
CcKeyboardItem *item; |
410 |
|
|
|
411 |
|
✗ |
item = cc_keyboard_manager_create_custom_shortcut (self->manager); |
412 |
|
|
|
413 |
|
|
/* Apply the custom shortcut setup at the new item */ |
414 |
|
✗ |
apply_custom_item_fields (self, item); |
415 |
|
|
|
416 |
|
|
/* Eventually disable the conflict shortcut */ |
417 |
|
✗ |
if (self->collision_item) |
418 |
|
✗ |
cc_keyboard_item_disable (self->collision_item); |
419 |
|
|
|
420 |
|
|
/* Cleanup everything once we're done */ |
421 |
|
✗ |
clear_custom_entries (self); |
422 |
|
|
|
423 |
|
✗ |
cc_keyboard_manager_add_custom_shortcut (self->manager, item); |
424 |
|
|
|
425 |
|
✗ |
gtk_window_close (GTK_WINDOW (self)); |
426 |
|
✗ |
} |
427 |
|
|
|
428 |
|
|
static void |
429 |
|
✗ |
cancel_button_clicked_cb (CcKeyboardShortcutEditor *self) |
430 |
|
|
{ |
431 |
|
✗ |
cancel_editing (self); |
432 |
|
✗ |
} |
433 |
|
|
|
434 |
|
|
static void |
435 |
|
✗ |
change_custom_shortcut_button_clicked_cb (CcKeyboardShortcutEditor *self) |
436 |
|
|
{ |
437 |
|
✗ |
inhibit_system_shortcuts (self); |
438 |
|
✗ |
set_shortcut_editor_page (self, PAGE_EDIT); |
439 |
|
✗ |
set_header_mode (self, HEADER_MODE_NONE); |
440 |
|
✗ |
} |
441 |
|
|
|
442 |
|
|
static void |
443 |
|
✗ |
command_entry_changed_cb (CcKeyboardShortcutEditor *self) |
444 |
|
|
{ |
445 |
|
✗ |
setup_custom_shortcut (self); |
446 |
|
✗ |
} |
447 |
|
|
|
448 |
|
|
static void |
449 |
|
✗ |
name_entry_changed_cb (CcKeyboardShortcutEditor *self) |
450 |
|
|
{ |
451 |
|
✗ |
setup_custom_shortcut (self); |
452 |
|
✗ |
} |
453 |
|
|
|
454 |
|
|
static void |
455 |
|
✗ |
remove_button_clicked_cb (CcKeyboardShortcutEditor *self) |
456 |
|
|
{ |
457 |
|
✗ |
cc_keyboard_manager_remove_custom_shortcut (self->manager, self->item); |
458 |
|
✗ |
gtk_window_close (GTK_WINDOW (self)); |
459 |
|
✗ |
} |
460 |
|
|
|
461 |
|
|
static void |
462 |
|
✗ |
replace_button_clicked_cb (CcKeyboardShortcutEditor *self) |
463 |
|
|
{ |
464 |
|
✗ |
if (self->mode == CC_SHORTCUT_EDITOR_CREATE) |
465 |
|
✗ |
add_button_clicked_cb (self); |
466 |
|
|
else |
467 |
|
✗ |
set_button_clicked_cb (self); |
468 |
|
✗ |
} |
469 |
|
|
|
470 |
|
|
static void |
471 |
|
✗ |
reset_custom_clicked_cb (CcKeyboardShortcutEditor *self) |
472 |
|
|
{ |
473 |
|
✗ |
if (self->item) |
474 |
|
✗ |
cc_keyboard_manager_reset_shortcut (self->manager, self->item); |
475 |
|
|
|
476 |
|
|
|
477 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->custom_shortcut_accel_label), FALSE); |
478 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->reset_custom_button), FALSE); |
479 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->change_custom_shortcut_button), TRUE); |
480 |
|
✗ |
} |
481 |
|
|
|
482 |
|
|
static void |
483 |
|
✗ |
reset_item_clicked_cb (CcKeyboardShortcutEditor *self) |
484 |
|
|
{ |
485 |
|
|
CcKeyCombo combo; |
486 |
|
|
gchar *accel; |
487 |
|
|
|
488 |
|
|
/* Reset first, then update the shortcut */ |
489 |
|
✗ |
cc_keyboard_manager_reset_shortcut (self->manager, self->item); |
490 |
|
|
|
491 |
|
✗ |
combo = cc_keyboard_item_get_primary_combo (self->item); |
492 |
|
✗ |
accel = gtk_accelerator_name (combo.keyval, combo.mask); |
493 |
|
✗ |
gtk_shortcut_label_set_accelerator (GTK_SHORTCUT_LABEL (self->shortcut_accel_label), accel); |
494 |
|
|
|
495 |
|
✗ |
g_free (accel); |
496 |
|
✗ |
} |
497 |
|
|
|
498 |
|
|
static void |
499 |
|
✗ |
set_button_clicked_cb (CcKeyboardShortcutEditor *self) |
500 |
|
|
{ |
501 |
|
✗ |
update_shortcut (self); |
502 |
|
✗ |
gtk_window_close (GTK_WINDOW (self)); |
503 |
|
✗ |
} |
504 |
|
|
|
505 |
|
|
static void |
506 |
|
✗ |
setup_keyboard_item (CcKeyboardShortcutEditor *self, |
507 |
|
|
CcKeyboardItem *item) |
508 |
|
|
{ |
509 |
|
|
CcKeyCombo combo; |
510 |
|
|
gboolean is_custom; |
511 |
|
✗ |
g_autofree gchar *accel = NULL; |
512 |
|
✗ |
g_autofree gchar *text = NULL; |
513 |
|
|
|
514 |
|
✗ |
if (!item) { |
515 |
|
✗ |
gtk_label_set_text (self->top_info_label, _("Enter the new shortcut")); |
516 |
|
✗ |
return; |
517 |
|
|
} |
518 |
|
|
|
519 |
|
✗ |
combo = cc_keyboard_item_get_primary_combo (item); |
520 |
|
✗ |
is_custom = cc_keyboard_item_get_item_type (item) == CC_KEYBOARD_ITEM_TYPE_GSETTINGS_PATH; |
521 |
|
✗ |
accel = gtk_accelerator_name (combo.keyval, combo.mask); |
522 |
|
|
|
523 |
|
|
/* To avoid accidentally thinking we unset the current keybinding, set the values |
524 |
|
|
* of the keyboard item that is being edited */ |
525 |
|
✗ |
self->custom_is_modifier = FALSE; |
526 |
|
✗ |
*self->custom_combo = combo; |
527 |
|
|
|
528 |
|
|
/* Headerbar */ |
529 |
|
✗ |
gtk_window_set_title (GTK_WINDOW (self), |
530 |
|
✗ |
is_custom ? _("Set Custom Shortcut") : _("Set Shortcut")); |
531 |
|
|
|
532 |
|
✗ |
set_header_mode (self, is_custom ? HEADER_MODE_CUSTOM_EDIT : HEADER_MODE_NONE); |
533 |
|
|
|
534 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->add_button), FALSE); |
535 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->cancel_button), FALSE); |
536 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->replace_button), FALSE); |
537 |
|
|
|
538 |
|
|
/* Setup the top label */ |
539 |
|
|
/* |
540 |
|
|
* TRANSLATORS: %s is replaced with a description of the keyboard shortcut, |
541 |
|
|
* don't translate/transliterate <b>%s</b> |
542 |
|
|
*/ |
543 |
|
✗ |
text = g_markup_printf_escaped (_("Enter new shortcut to change <b>%s</b>"), |
544 |
|
|
cc_keyboard_item_get_description (item)); |
545 |
|
|
|
546 |
|
✗ |
gtk_label_set_markup (self->top_info_label, text); |
547 |
|
|
|
548 |
|
|
/* Accelerator labels */ |
549 |
|
✗ |
gtk_shortcut_label_set_accelerator (self->shortcut_accel_label, accel); |
550 |
|
✗ |
gtk_shortcut_label_set_accelerator (self->custom_shortcut_accel_label, accel); |
551 |
|
|
|
552 |
|
✗ |
g_clear_pointer (&self->reset_item_binding, g_binding_unbind); |
553 |
|
✗ |
self->reset_item_binding = g_object_bind_property (item, |
554 |
|
|
"is-value-default", |
555 |
|
✗ |
self->reset_button, |
556 |
|
|
"visible", |
557 |
|
|
G_BINDING_DEFAULT | G_BINDING_INVERT_BOOLEAN | G_BINDING_SYNC_CREATE); |
558 |
|
|
|
559 |
|
|
/* Setup the custom entries */ |
560 |
|
✗ |
if (is_custom) |
561 |
|
|
{ |
562 |
|
|
gboolean is_accel_empty; |
563 |
|
|
|
564 |
|
✗ |
g_signal_handlers_block_by_func (self->command_entry, command_entry_changed_cb, self); |
565 |
|
✗ |
g_signal_handlers_block_by_func (self->name_entry, name_entry_changed_cb, self); |
566 |
|
|
|
567 |
|
|
/* Name entry */ |
568 |
|
✗ |
gtk_editable_set_text (GTK_EDITABLE (self->name_entry), cc_keyboard_item_get_description (item)); |
569 |
|
✗ |
gtk_widget_set_sensitive (GTK_WIDGET (self->name_entry), cc_keyboard_item_get_desc_editable (item)); |
570 |
|
|
|
571 |
|
|
/* Command entry */ |
572 |
|
✗ |
gtk_editable_set_text (GTK_EDITABLE (self->command_entry), cc_keyboard_item_get_command (item)); |
573 |
|
✗ |
gtk_widget_set_sensitive (GTK_WIDGET (self->command_entry), cc_keyboard_item_get_cmd_editable (item)); |
574 |
|
|
|
575 |
|
|
/* If there is no accelerator set for this custom shortcut, show the "Set Shortcut" button. */ |
576 |
|
✗ |
is_accel_empty = !accel || accel[0] == '\0'; |
577 |
|
|
|
578 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->change_custom_shortcut_button), is_accel_empty); |
579 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->custom_shortcut_accel_label), !is_accel_empty); |
580 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->reset_custom_button), !is_accel_empty); |
581 |
|
|
|
582 |
|
✗ |
g_signal_handlers_unblock_by_func (self->command_entry, command_entry_changed_cb, self); |
583 |
|
✗ |
g_signal_handlers_unblock_by_func (self->name_entry, name_entry_changed_cb, self); |
584 |
|
|
|
585 |
|
✗ |
uninhibit_system_shortcuts (self); |
586 |
|
|
} |
587 |
|
|
|
588 |
|
|
/* Show the appropriate view */ |
589 |
|
✗ |
set_shortcut_editor_page (self, is_custom ? PAGE_CUSTOM : PAGE_EDIT); |
590 |
|
|
} |
591 |
|
|
|
592 |
|
|
static void |
593 |
|
✗ |
cc_keyboard_shortcut_editor_finalize (GObject *object) |
594 |
|
|
{ |
595 |
|
✗ |
CcKeyboardShortcutEditor *self = (CcKeyboardShortcutEditor *)object; |
596 |
|
|
|
597 |
|
✗ |
g_clear_object (&self->item); |
598 |
|
✗ |
g_clear_object (&self->manager); |
599 |
|
|
|
600 |
|
✗ |
g_clear_pointer (&self->custom_combo, g_free); |
601 |
|
|
|
602 |
|
✗ |
G_OBJECT_CLASS (cc_keyboard_shortcut_editor_parent_class)->finalize (object); |
603 |
|
✗ |
} |
604 |
|
|
|
605 |
|
|
static void |
606 |
|
✗ |
cc_keyboard_shortcut_editor_get_property (GObject *object, |
607 |
|
|
guint prop_id, |
608 |
|
|
GValue *value, |
609 |
|
|
GParamSpec *pspec) |
610 |
|
|
{ |
611 |
|
✗ |
CcKeyboardShortcutEditor *self = CC_KEYBOARD_SHORTCUT_EDITOR (object); |
612 |
|
|
|
613 |
|
✗ |
switch (prop_id) |
614 |
|
|
{ |
615 |
|
✗ |
case PROP_KEYBOARD_ITEM: |
616 |
|
✗ |
g_value_set_object (value, self->item); |
617 |
|
✗ |
break; |
618 |
|
|
|
619 |
|
✗ |
case PROP_MANAGER: |
620 |
|
✗ |
g_value_set_object (value, self->manager); |
621 |
|
✗ |
break; |
622 |
|
|
|
623 |
|
✗ |
default: |
624 |
|
✗ |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
625 |
|
|
} |
626 |
|
✗ |
} |
627 |
|
|
|
628 |
|
|
static void |
629 |
|
✗ |
cc_keyboard_shortcut_editor_set_property (GObject *object, |
630 |
|
|
guint prop_id, |
631 |
|
|
const GValue *value, |
632 |
|
|
GParamSpec *pspec) |
633 |
|
|
{ |
634 |
|
✗ |
CcKeyboardShortcutEditor *self = CC_KEYBOARD_SHORTCUT_EDITOR (object); |
635 |
|
|
|
636 |
|
✗ |
switch (prop_id) |
637 |
|
|
{ |
638 |
|
✗ |
case PROP_KEYBOARD_ITEM: |
639 |
|
✗ |
cc_keyboard_shortcut_editor_set_item (self, g_value_get_object (value)); |
640 |
|
✗ |
break; |
641 |
|
|
|
642 |
|
✗ |
case PROP_MANAGER: |
643 |
|
✗ |
g_set_object (&self->manager, g_value_get_object (value)); |
644 |
|
✗ |
break; |
645 |
|
|
|
646 |
|
✗ |
default: |
647 |
|
✗ |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
648 |
|
|
} |
649 |
|
✗ |
} |
650 |
|
|
|
651 |
|
|
static gboolean |
652 |
|
✗ |
on_key_pressed_cb (CcKeyboardShortcutEditor *self, |
653 |
|
|
guint keyval, |
654 |
|
|
guint keycode, |
655 |
|
|
GdkModifierType state, |
656 |
|
|
GtkEventControllerKey *key_controller) |
657 |
|
|
{ |
658 |
|
|
GdkModifierType real_mask; |
659 |
|
|
GdkEvent *event; |
660 |
|
|
gboolean editing; |
661 |
|
|
gboolean is_modifier; |
662 |
|
|
guint keyval_lower; |
663 |
|
|
|
664 |
|
|
/* Being in the "change-shortcut" page is the only check we must |
665 |
|
|
* perform to decide if we're editing a shortcut. */ |
666 |
|
✗ |
editing = get_shortcut_editor_page (self) == PAGE_EDIT; |
667 |
|
|
|
668 |
|
✗ |
if (!editing) |
669 |
|
✗ |
return GDK_EVENT_PROPAGATE; |
670 |
|
|
|
671 |
|
✗ |
normalize_keyval_and_mask (keycode, state, |
672 |
|
|
gtk_event_controller_key_get_group (key_controller), |
673 |
|
|
&keyval_lower, &real_mask); |
674 |
|
|
|
675 |
|
✗ |
event = gtk_event_controller_get_current_event (GTK_EVENT_CONTROLLER (key_controller)); |
676 |
|
✗ |
is_modifier = gdk_key_event_is_modifier (event); |
677 |
|
|
|
678 |
|
|
/* A single Escape press cancels the editing */ |
679 |
|
✗ |
if (!is_modifier && real_mask == 0 && keyval_lower == GDK_KEY_Escape) |
680 |
|
|
{ |
681 |
|
✗ |
self->edited = FALSE; |
682 |
|
|
|
683 |
|
✗ |
uninhibit_system_shortcuts (self); |
684 |
|
✗ |
cancel_editing (self); |
685 |
|
|
|
686 |
|
✗ |
return GDK_EVENT_STOP; |
687 |
|
|
} |
688 |
|
|
|
689 |
|
|
/* Backspace disables the current shortcut */ |
690 |
|
✗ |
if (!is_modifier && real_mask == 0 && keyval_lower == GDK_KEY_BackSpace) |
691 |
|
|
{ |
692 |
|
✗ |
self->edited = TRUE; |
693 |
|
✗ |
self->custom_is_modifier = FALSE; |
694 |
|
✗ |
memset (self->custom_combo, 0, sizeof (CcKeyCombo)); |
695 |
|
|
|
696 |
|
✗ |
gtk_shortcut_label_set_accelerator (GTK_SHORTCUT_LABEL (self->custom_shortcut_accel_label), ""); |
697 |
|
✗ |
gtk_shortcut_label_set_accelerator (GTK_SHORTCUT_LABEL (self->shortcut_accel_label), ""); |
698 |
|
|
|
699 |
|
✗ |
uninhibit_system_shortcuts (self); |
700 |
|
|
|
701 |
|
✗ |
self->edited = FALSE; |
702 |
|
|
|
703 |
|
✗ |
setup_custom_shortcut (self); |
704 |
|
|
|
705 |
|
✗ |
return GDK_EVENT_STOP; |
706 |
|
|
} |
707 |
|
|
|
708 |
|
✗ |
self->custom_is_modifier = is_modifier; |
709 |
|
✗ |
self->custom_combo->keycode = keycode; |
710 |
|
✗ |
self->custom_combo->keyval = keyval_lower; |
711 |
|
✗ |
self->custom_combo->mask = real_mask; |
712 |
|
|
|
713 |
|
|
/* CapsLock isn't supported as a keybinding modifier, so keep it from confusing us */ |
714 |
|
✗ |
self->custom_combo->mask &= ~GDK_LOCK_MASK; |
715 |
|
|
|
716 |
|
✗ |
setup_custom_shortcut (self); |
717 |
|
|
|
718 |
|
✗ |
return GDK_EVENT_STOP; |
719 |
|
|
} |
720 |
|
|
|
721 |
|
|
static gboolean |
722 |
|
✗ |
cc_keyboard_shortcut_editor_close_request (GtkWindow *window) |
723 |
|
|
{ |
724 |
|
✗ |
CcKeyboardShortcutEditor *self = CC_KEYBOARD_SHORTCUT_EDITOR (window); |
725 |
|
|
|
726 |
|
✗ |
if (self->mode == CC_SHORTCUT_EDITOR_EDIT && get_shortcut_editor_page (self) != PAGE_STANDARD) |
727 |
|
✗ |
update_shortcut (self); |
728 |
|
|
|
729 |
|
✗ |
return GTK_WINDOW_CLASS (cc_keyboard_shortcut_editor_parent_class)->close_request (window); |
730 |
|
|
} |
731 |
|
|
|
732 |
|
|
static gboolean |
733 |
|
✗ |
grab_idle (gpointer data) |
734 |
|
|
{ |
735 |
|
✗ |
CcKeyboardShortcutEditor *self = data; |
736 |
|
|
|
737 |
|
✗ |
if (self->item && cc_keyboard_item_get_item_type (self->item) != CC_KEYBOARD_ITEM_TYPE_GSETTINGS_PATH) |
738 |
|
✗ |
inhibit_system_shortcuts (self); |
739 |
|
|
|
740 |
|
✗ |
self->grab_idle_id = 0; |
741 |
|
|
|
742 |
|
✗ |
return G_SOURCE_REMOVE; |
743 |
|
|
} |
744 |
|
|
|
745 |
|
|
static void |
746 |
|
✗ |
cc_keyboard_shortcut_editor_show (GtkWidget *widget) |
747 |
|
|
{ |
748 |
|
✗ |
CcKeyboardShortcutEditor *self = CC_KEYBOARD_SHORTCUT_EDITOR (widget); |
749 |
|
|
|
750 |
|
|
/* Map before grabbing, so that the window is visible */ |
751 |
|
✗ |
GTK_WIDGET_CLASS (cc_keyboard_shortcut_editor_parent_class)->show (widget); |
752 |
|
|
|
753 |
|
✗ |
self->grab_idle_id = g_timeout_add (100, grab_idle, self); |
754 |
|
✗ |
} |
755 |
|
|
|
756 |
|
|
static void |
757 |
|
✗ |
cc_keyboard_shortcut_editor_unrealize (GtkWidget *widget) |
758 |
|
|
{ |
759 |
|
✗ |
CcKeyboardShortcutEditor *self = CC_KEYBOARD_SHORTCUT_EDITOR (widget); |
760 |
|
|
|
761 |
|
✗ |
g_clear_handle_id (&self->grab_idle_id, g_source_remove); |
762 |
|
|
|
763 |
|
✗ |
uninhibit_system_shortcuts (self); |
764 |
|
|
|
765 |
|
✗ |
GTK_WIDGET_CLASS (cc_keyboard_shortcut_editor_parent_class)->unrealize (widget); |
766 |
|
✗ |
} |
767 |
|
|
|
768 |
|
|
static void |
769 |
|
✗ |
cc_keyboard_shortcut_editor_class_init (CcKeyboardShortcutEditorClass *klass) |
770 |
|
|
{ |
771 |
|
✗ |
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); |
772 |
|
✗ |
GtkWindowClass *window_class = GTK_WINDOW_CLASS (klass); |
773 |
|
✗ |
GObjectClass *object_class = G_OBJECT_CLASS (klass); |
774 |
|
|
|
775 |
|
✗ |
object_class->finalize = cc_keyboard_shortcut_editor_finalize; |
776 |
|
✗ |
object_class->get_property = cc_keyboard_shortcut_editor_get_property; |
777 |
|
✗ |
object_class->set_property = cc_keyboard_shortcut_editor_set_property; |
778 |
|
|
|
779 |
|
✗ |
widget_class->show = cc_keyboard_shortcut_editor_show; |
780 |
|
✗ |
widget_class->unrealize = cc_keyboard_shortcut_editor_unrealize; |
781 |
|
|
|
782 |
|
✗ |
window_class->close_request = cc_keyboard_shortcut_editor_close_request; |
783 |
|
|
|
784 |
|
|
/** |
785 |
|
|
* CcKeyboardShortcutEditor:keyboard-item: |
786 |
|
|
* |
787 |
|
|
* The current keyboard shortcut being edited. |
788 |
|
|
*/ |
789 |
|
✗ |
properties[PROP_KEYBOARD_ITEM] = g_param_spec_object ("keyboard-item", |
790 |
|
|
"Keyboard item", |
791 |
|
|
"The keyboard item being edited", |
792 |
|
|
CC_TYPE_KEYBOARD_ITEM, |
793 |
|
|
G_PARAM_READWRITE); |
794 |
|
|
|
795 |
|
|
/** |
796 |
|
|
* CcKeyboardShortcutEditor:panel: |
797 |
|
|
* |
798 |
|
|
* The current keyboard panel. |
799 |
|
|
*/ |
800 |
|
✗ |
properties[PROP_MANAGER] = g_param_spec_object ("manager", |
801 |
|
|
"Keyboard manager", |
802 |
|
|
"The keyboard manager", |
803 |
|
|
CC_TYPE_KEYBOARD_MANAGER, |
804 |
|
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); |
805 |
|
|
|
806 |
|
✗ |
g_object_class_install_properties (object_class, N_PROPS, properties); |
807 |
|
|
|
808 |
|
✗ |
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/keyboard/cc-keyboard-shortcut-editor.ui"); |
809 |
|
|
|
810 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutEditor, add_button); |
811 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutEditor, cancel_button); |
812 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutEditor, change_custom_shortcut_button); |
813 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutEditor, command_entry); |
814 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutEditor, custom_grid); |
815 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutEditor, custom_shortcut_accel_label); |
816 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutEditor, edit_box); |
817 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutEditor, headerbar); |
818 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutEditor, name_entry); |
819 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutEditor, new_shortcut_conflict_label); |
820 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutEditor, remove_button); |
821 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutEditor, replace_button); |
822 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutEditor, reset_button); |
823 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutEditor, reset_custom_button); |
824 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutEditor, set_button); |
825 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutEditor, shortcut_accel_label); |
826 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutEditor, shortcut_conflict_label); |
827 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutEditor, standard_box); |
828 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutEditor, stack); |
829 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcKeyboardShortcutEditor, top_info_label); |
830 |
|
|
|
831 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, add_button_clicked_cb); |
832 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, cancel_button_clicked_cb); |
833 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, change_custom_shortcut_button_clicked_cb); |
834 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, command_entry_changed_cb); |
835 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, name_entry_changed_cb); |
836 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, on_key_pressed_cb); |
837 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, remove_button_clicked_cb); |
838 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, replace_button_clicked_cb); |
839 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, reset_custom_clicked_cb); |
840 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, reset_item_clicked_cb); |
841 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, set_button_clicked_cb); |
842 |
|
✗ |
} |
843 |
|
|
|
844 |
|
|
static void |
845 |
|
✗ |
cc_keyboard_shortcut_editor_init (CcKeyboardShortcutEditor *self) |
846 |
|
|
{ |
847 |
|
✗ |
gtk_widget_init_template (GTK_WIDGET (self)); |
848 |
|
|
|
849 |
|
✗ |
self->mode = CC_SHORTCUT_EDITOR_EDIT; |
850 |
|
✗ |
self->custom_is_modifier = TRUE; |
851 |
|
✗ |
self->custom_combo = g_new0 (CcKeyCombo, 1); |
852 |
|
|
|
853 |
|
✗ |
gtk_widget_set_direction (GTK_WIDGET (self->custom_shortcut_accel_label), GTK_TEXT_DIR_LTR); |
854 |
|
✗ |
gtk_widget_set_direction (GTK_WIDGET (self->shortcut_accel_label), GTK_TEXT_DIR_LTR); |
855 |
|
✗ |
} |
856 |
|
|
|
857 |
|
|
/** |
858 |
|
|
* cc_keyboard_shortcut_editor_new: |
859 |
|
|
* |
860 |
|
|
* Creates a new #CcKeyboardShortcutEditor. |
861 |
|
|
* |
862 |
|
|
* Returns: (transfer full): a newly created #CcKeyboardShortcutEditor. |
863 |
|
|
*/ |
864 |
|
|
GtkWidget* |
865 |
|
✗ |
cc_keyboard_shortcut_editor_new (GtkWindow *parent_window, |
866 |
|
|
CcKeyboardManager *manager) |
867 |
|
|
{ |
868 |
|
✗ |
return g_object_new (CC_TYPE_KEYBOARD_SHORTCUT_EDITOR, |
869 |
|
|
"transient-for", parent_window, |
870 |
|
|
"manager", manager, |
871 |
|
|
NULL); |
872 |
|
|
} |
873 |
|
|
|
874 |
|
|
/** |
875 |
|
|
* cc_keyboard_shortcut_editor_get_item: |
876 |
|
|
* @self: a #CcKeyboardShortcutEditor |
877 |
|
|
* |
878 |
|
|
* Retrieves the current keyboard shortcut being edited. |
879 |
|
|
* |
880 |
|
|
* Returns: (transfer none)(nullable): a #CcKeyboardItem |
881 |
|
|
*/ |
882 |
|
|
CcKeyboardItem* |
883 |
|
✗ |
cc_keyboard_shortcut_editor_get_item (CcKeyboardShortcutEditor *self) |
884 |
|
|
{ |
885 |
|
✗ |
g_return_val_if_fail (CC_IS_KEYBOARD_SHORTCUT_EDITOR (self), NULL); |
886 |
|
|
|
887 |
|
✗ |
return self->item; |
888 |
|
|
} |
889 |
|
|
|
890 |
|
|
/** |
891 |
|
|
* cc_keyboard_shortcut_editor_set_item: |
892 |
|
|
* @self: a #CcKeyboardShortcutEditor |
893 |
|
|
* @item: a #CcKeyboardItem |
894 |
|
|
* |
895 |
|
|
* Sets the current keyboard shortcut to be edited. |
896 |
|
|
*/ |
897 |
|
|
void |
898 |
|
✗ |
cc_keyboard_shortcut_editor_set_item (CcKeyboardShortcutEditor *self, |
899 |
|
|
CcKeyboardItem *item) |
900 |
|
|
{ |
901 |
|
✗ |
g_return_if_fail (CC_IS_KEYBOARD_SHORTCUT_EDITOR (self)); |
902 |
|
|
|
903 |
|
✗ |
setup_keyboard_item (self, item); |
904 |
|
|
|
905 |
|
✗ |
if (!g_set_object (&self->item, item)) |
906 |
|
✗ |
return; |
907 |
|
|
|
908 |
|
✗ |
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_KEYBOARD_ITEM]); |
909 |
|
|
} |
910 |
|
|
|
911 |
|
|
CcShortcutEditorMode |
912 |
|
✗ |
cc_keyboard_shortcut_editor_get_mode (CcKeyboardShortcutEditor *self) |
913 |
|
|
{ |
914 |
|
✗ |
g_return_val_if_fail (CC_IS_KEYBOARD_SHORTCUT_EDITOR (self), 0); |
915 |
|
|
|
916 |
|
✗ |
return self->mode; |
917 |
|
|
} |
918 |
|
|
|
919 |
|
|
void |
920 |
|
✗ |
cc_keyboard_shortcut_editor_set_mode (CcKeyboardShortcutEditor *self, |
921 |
|
|
CcShortcutEditorMode mode) |
922 |
|
|
{ |
923 |
|
|
gboolean is_create_mode; |
924 |
|
|
|
925 |
|
✗ |
g_return_if_fail (CC_IS_KEYBOARD_SHORTCUT_EDITOR (self)); |
926 |
|
|
|
927 |
|
✗ |
self->mode = mode; |
928 |
|
✗ |
is_create_mode = mode == CC_SHORTCUT_EDITOR_CREATE; |
929 |
|
|
|
930 |
|
✗ |
if (mode == CC_SHORTCUT_EDITOR_CREATE) |
931 |
|
|
{ |
932 |
|
|
/* Cleanup whatever was set before */ |
933 |
|
✗ |
clear_custom_entries (self); |
934 |
|
|
|
935 |
|
✗ |
set_header_mode (self, HEADER_MODE_ADD); |
936 |
|
✗ |
set_shortcut_editor_page (self, PAGE_CUSTOM); |
937 |
|
✗ |
gtk_window_set_title (GTK_WINDOW (self), _("Add Custom Shortcut")); |
938 |
|
|
|
939 |
|
✗ |
gtk_widget_set_sensitive (GTK_WIDGET (self->command_entry), TRUE); |
940 |
|
✗ |
gtk_widget_set_sensitive (GTK_WIDGET (self->name_entry), TRUE); |
941 |
|
✗ |
gtk_widget_set_sensitive (GTK_WIDGET (self->add_button), FALSE); |
942 |
|
|
|
943 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->custom_shortcut_accel_label), FALSE); |
944 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->change_custom_shortcut_button), TRUE); |
945 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->reset_custom_button), FALSE); |
946 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->new_shortcut_conflict_label), !is_create_mode); |
947 |
|
|
} |
948 |
|
|
else |
949 |
|
|
{ |
950 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self->new_shortcut_conflict_label), is_create_mode); |
951 |
|
|
} |
952 |
|
|
} |
953 |
|
|
|
954 |
|
|
|