Commit 9767f7f9f81acfee3cd1f5a9dcade478512b1fb1
1 parent
b08a928d
Exists in
master
and in
1 other branch
Checking for duplicate accelerators.
Showing
2 changed files
with
200 additions
and
7 deletions
Show diff stats
src/dialogs/settings/accelerator.c
... | ... | @@ -30,6 +30,10 @@ |
30 | 30 | /** |
31 | 31 | * @brief Implements the accelerator settings widget. |
32 | 32 | * |
33 | + * References: | |
34 | + * | |
35 | + * <https://github.com/Apress/foundations-of-gtk-dev/blob/master/chapter_8/accelerators.c> | |
36 | + * | |
33 | 37 | */ |
34 | 38 | |
35 | 39 | #include <internals.h> |
... | ... | @@ -38,6 +42,7 @@ |
38 | 42 | #include <lib3270/log.h> |
39 | 43 | #include <v3270/actions.h> |
40 | 44 | #include <terminal.h> |
45 | + #include <gdk/gdkkeysyms-compat.h> | |
41 | 46 | |
42 | 47 | /*--[ Widget Definition ]----------------------------------------------------------------------------*/ |
43 | 48 | |
... | ... | @@ -69,6 +74,9 @@ |
69 | 74 | static void load(GtkWidget *w, GtkWidget *terminal); |
70 | 75 | static void apply(GtkWidget *w, GtkWidget *terminal); |
71 | 76 | |
77 | + static void accel_edited(GtkCellRendererAccel*, gchar*, guint, GdkModifierType, guint, V3270AcceleratorSettings*); | |
78 | + static void alternative_edited(GtkCellRendererAccel*, gchar*, guint, GdkModifierType, guint, V3270AcceleratorSettings*); | |
79 | + | |
72 | 80 | /*--[ Implement ]------------------------------------------------------------------------------------*/ |
73 | 81 | |
74 | 82 | static void V3270AcceleratorSettings_class_init(V3270AcceleratorSettingsClass *klass) |
... | ... | @@ -95,13 +103,23 @@ |
95 | 103 | // Create Accelerator list |
96 | 104 | GtkCellRenderer * text_renderer = gtk_cell_renderer_text_new(); |
97 | 105 | |
98 | - GtkCellRenderer * accel_renderer = gtk_cell_renderer_accel_new(); | |
106 | + GtkCellRenderer * accel_renderer[] = { gtk_cell_renderer_accel_new(), gtk_cell_renderer_accel_new() }; | |
107 | + | |
108 | + g_object_set( | |
109 | + accel_renderer[0], | |
110 | + "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER, | |
111 | + "editable", TRUE, | |
112 | + NULL); | |
113 | + | |
99 | 114 | g_object_set( |
100 | - accel_renderer, | |
115 | + accel_renderer[1], | |
101 | 116 | "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER, |
102 | 117 | "editable", TRUE, |
103 | 118 | NULL); |
104 | 119 | |
120 | + g_signal_connect (G_OBJECT (accel_renderer[0]), "accel_edited", G_CALLBACK (accel_edited), widget); | |
121 | + g_signal_connect (G_OBJECT (accel_renderer[1]), "accel_edited", G_CALLBACK (alternative_edited), widget); | |
122 | + | |
105 | 123 | widget->store = GTK_LIST_STORE(gtk_list_store_new(COLUMNS, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_INT, G_TYPE_UINT, G_TYPE_INT, G_TYPE_UINT)); |
106 | 124 | |
107 | 125 | gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(widget->store),1,GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID); |
... | ... | @@ -124,7 +142,7 @@ |
124 | 142 | GTK_TREE_VIEW(view), |
125 | 143 | -1, |
126 | 144 | _("Accelerator"), |
127 | - accel_renderer, | |
145 | + accel_renderer[0], | |
128 | 146 | "accel-mods", MAIN_MASK, |
129 | 147 | "accel-key", MAIN_VALUE, |
130 | 148 | NULL |
... | ... | @@ -134,7 +152,7 @@ |
134 | 152 | GTK_TREE_VIEW(view), |
135 | 153 | -1, |
136 | 154 | _("Alternative"), |
137 | - accel_renderer, | |
155 | + accel_renderer[1], | |
138 | 156 | "accel-mods", ALTERNATIVE_MASK, |
139 | 157 | "accel-key", ALTERNATIVE_VALUE, |
140 | 158 | NULL |
... | ... | @@ -155,7 +173,8 @@ |
155 | 173 | gtk_grid_attach(GTK_GRID(widget),box,0,0,4,4); |
156 | 174 | } |
157 | 175 | |
158 | - } | |
176 | +} | |
177 | + | |
159 | 178 | |
160 | 179 | LIB3270_EXPORT GtkWidget * v3270_accelerator_settings_new() |
161 | 180 | { |
... | ... | @@ -167,6 +186,163 @@ LIB3270_EXPORT GtkWidget * v3270_accelerator_settings_new() |
167 | 186 | return GTK_WIDGET(settings); |
168 | 187 | } |
169 | 188 | |
189 | +struct AccelEditInfo | |
190 | +{ | |
191 | + GtkWidget * widget; | |
192 | + gint response; | |
193 | + V3270Accelerator * origin; | |
194 | + V3270Accelerator * accel; | |
195 | + GtkTreePath *path; | |
196 | + guint accel_key; | |
197 | + GdkModifierType mask; | |
198 | + int id_key; | |
199 | + int id_mask; | |
200 | +}; | |
201 | + | |
202 | +static gboolean check_accel(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, struct AccelEditInfo * info) | |
203 | +{ | |
204 | + static const gint columns[] = { MAIN_MASK, MAIN_VALUE, ALTERNATIVE_MASK, ALTERNATIVE_VALUE }; | |
205 | + size_t ix; | |
206 | + GValue value; | |
207 | + | |
208 | + debug("%s",__FUNCTION__); | |
209 | + | |
210 | + for(ix = 0; ix < 2; ix++) | |
211 | + { | |
212 | + guint key; | |
213 | + GdkModifierType mask; | |
214 | + | |
215 | + memset(&value,0,sizeof(value)); | |
216 | + gtk_tree_model_get_value(model, iter, columns[(ix * 2)], &value); | |
217 | + mask = (GdkModifierType) g_value_get_int(&value); | |
218 | + g_value_unset(&value); | |
219 | + | |
220 | + memset(&value,0,sizeof(value)); | |
221 | + gtk_tree_model_get_value(model, iter, columns[(ix * 2)+1], &value); | |
222 | + key = g_value_get_uint(&value); | |
223 | + g_value_unset(&value); | |
224 | + | |
225 | + if(key == info->accel_key && mask == info->mask) { | |
226 | + | |
227 | + debug("************ Index %d cmp=%d",(unsigned int) ix, gtk_tree_path_compare(path, info->path)); | |
228 | + GtkWidget * dialog; | |
229 | + | |
230 | + if(gtk_tree_path_compare(path, info->path)) | |
231 | + { | |
232 | + // Another entry, rejects. | |
233 | + memset(&value,0,sizeof(value)); | |
234 | + gtk_tree_model_get_value(model, iter, ACTION, &value); | |
235 | + info->accel = (V3270Accelerator *) g_value_get_pointer(&value); | |
236 | + g_value_unset(&value); | |
237 | + | |
238 | + debug("Key is already set on accel %s",v3270_accelerator_get_name(info->accel)); | |
239 | + | |
240 | + // Ask for what the user wants to do. | |
241 | + dialog = gtk_message_dialog_new_with_markup( | |
242 | + GTK_WINDOW(gtk_widget_get_toplevel(info->widget)), | |
243 | + GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT, | |
244 | + GTK_MESSAGE_QUESTION, | |
245 | + GTK_BUTTONS_YES_NO, | |
246 | + _( "The selected accelerator is in use by action <b>%s</b> (<b>%s</b>)" ), | |
247 | + v3270_accelerator_get_description(info->accel), | |
248 | + v3270_accelerator_get_name(info->accel) | |
249 | + ); | |
250 | + | |
251 | + gtk_message_dialog_format_secondary_markup( | |
252 | + GTK_MESSAGE_DIALOG(dialog), | |
253 | + _( "Assign it to action (<b>%s</b>)?"), | |
254 | + v3270_accelerator_get_name(info->origin) | |
255 | + ); | |
256 | + | |
257 | + } | |
258 | + else | |
259 | + { | |
260 | + // It's on the same entry. | |
261 | + dialog = gtk_message_dialog_new_with_markup( | |
262 | + GTK_WINDOW(gtk_widget_get_toplevel(info->widget)), | |
263 | + GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT, | |
264 | + GTK_MESSAGE_QUESTION, | |
265 | + GTK_BUTTONS_CANCEL, | |
266 | + _( "The selected accelerator is in use by the same action" ) | |
267 | + ); | |
268 | + | |
269 | + } | |
270 | + | |
271 | + gtk_window_set_title(GTK_WINDOW(dialog),_("Accelerator is in use")); | |
272 | + gtk_widget_show_all(dialog); | |
273 | + | |
274 | + info->response = gtk_dialog_run(GTK_DIALOG(dialog)); | |
275 | + if(info->response == GTK_RESPONSE_YES) | |
276 | + { | |
277 | + debug("%s: Removing accelerator from the other action",__FUNCTION__); | |
278 | + | |
279 | + } | |
280 | + | |
281 | + gtk_widget_destroy(dialog); | |
282 | + | |
283 | + return TRUE; | |
284 | + | |
285 | + } | |
286 | + | |
287 | + } | |
288 | + | |
289 | + return FALSE; | |
290 | + | |
291 | +} | |
292 | + | |
293 | +static void change_accel(V3270AcceleratorSettings *widget, gchar *path, guint accel_key, GdkModifierType mask, int id_key, int id_mask) | |
294 | +{ | |
295 | + struct AccelEditInfo info = { | |
296 | + .response = GTK_RESPONSE_YES, | |
297 | + .widget = GTK_WIDGET(widget), | |
298 | + .accel = NULL, | |
299 | + .accel_key = accel_key, | |
300 | + .mask = mask, | |
301 | + .id_key = id_key, | |
302 | + .id_mask = id_mask, | |
303 | + .path = gtk_tree_path_new_from_string(path) | |
304 | + }; | |
305 | + | |
306 | + GtkTreeIter iter; | |
307 | + if(gtk_tree_model_get_iter(GTK_TREE_MODEL(widget->store),&iter,info.path)) | |
308 | + { | |
309 | + GValue value; | |
310 | + memset(&value,0,sizeof(value)); | |
311 | + gtk_tree_model_get_value(GTK_TREE_MODEL(widget->store), &iter, ACTION, &value); | |
312 | + info.origin = (V3270Accelerator *) g_value_get_pointer(&value); | |
313 | + g_value_unset(&value); | |
314 | + | |
315 | + if(!info.origin) | |
316 | + { | |
317 | + g_warning("Can't identify the origin accelerator, aborting action"); | |
318 | + return; | |
319 | + } | |
320 | + | |
321 | + } | |
322 | + | |
323 | + gtk_tree_model_foreach(GTK_TREE_MODEL(widget->store), (GtkTreeModelForeachFunc) check_accel, &info); | |
324 | + | |
325 | + gtk_tree_path_free(info.path); | |
326 | + | |
327 | + if(info.response == GTK_RESPONSE_YES) | |
328 | + { | |
329 | + debug("%s: Aplicar alteração",__FUNCTION__); | |
330 | + | |
331 | + } | |
332 | + | |
333 | +} | |
334 | + | |
335 | +static void accel_edited(GtkCellRendererAccel *renderer, gchar *path, guint accel_key, GdkModifierType mask, guint hardware_keycode, V3270AcceleratorSettings *widget) | |
336 | +{ | |
337 | + debug("%s(%s)",__FUNCTION__,path); | |
338 | + change_accel(widget, path, accel_key, mask, MAIN_MASK, MAIN_VALUE); | |
339 | +} | |
340 | + | |
341 | +static void alternative_edited(GtkCellRendererAccel *renderer, gchar *path, guint accel_key, GdkModifierType mask, guint hardware_keycode, V3270AcceleratorSettings *widget) | |
342 | +{ | |
343 | + debug("%s(%s)",__FUNCTION__,path); | |
344 | + change_accel(widget, path, accel_key, mask, ALTERNATIVE_MASK, ALTERNATIVE_VALUE); | |
345 | +} | |
170 | 346 | |
171 | 347 | void load(GtkWidget *widget, GtkWidget *terminal) |
172 | 348 | { |
... | ... | @@ -195,8 +371,17 @@ void load(GtkWidget *widget, GtkWidget *terminal) |
195 | 371 | |
196 | 372 | if(ix < G_N_ELEMENTS(keymaps)) |
197 | 373 | { |
198 | - keymaps[ix].key = accel->key; | |
199 | - keymaps[ix].mods = accel->mods; | |
374 | + if(accel->type == V3270_ACCELERATOR_TYPE_PFKEY) | |
375 | + { | |
376 | + keymaps[ix].key = GDK_F1 + (((V3270PFKeyAccelerator *)accel)->keycode - 1); | |
377 | + keymaps[ix].mods = 0; | |
378 | + } | |
379 | + else | |
380 | + { | |
381 | + keymaps[ix].key = accel->key; | |
382 | + keymaps[ix].mods = accel->mods; | |
383 | + } | |
384 | + | |
200 | 385 | ix++; |
201 | 386 | } |
202 | 387 | |
... | ... | @@ -206,6 +391,7 @@ void load(GtkWidget *widget, GtkWidget *terminal) |
206 | 391 | // Add entry |
207 | 392 | GtkTreeIter iter; |
208 | 393 | gtk_list_store_append(store, &iter); |
394 | + | |
209 | 395 | gtk_list_store_set( |
210 | 396 | store, |
211 | 397 | &iter, |
... | ... | @@ -218,6 +404,7 @@ void load(GtkWidget *widget, GtkWidget *terminal) |
218 | 404 | -1 |
219 | 405 | ); |
220 | 406 | |
407 | + | |
221 | 408 | } |
222 | 409 | |
223 | 410 | } |
... | ... | @@ -226,3 +413,4 @@ void apply(GtkWidget *widget, GtkWidget *terminal) |
226 | 413 | { |
227 | 414 | debug("%s::%s","V3270AcceleratorSettings",__FUNCTION__); |
228 | 415 | } |
416 | + | ... | ... |
src/terminal/keyboard/accelerator.c