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,6 +30,10 @@ | ||
30 | /** | 30 | /** |
31 | * @brief Implements the accelerator settings widget. | 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 | #include <internals.h> | 39 | #include <internals.h> |
@@ -38,6 +42,7 @@ | @@ -38,6 +42,7 @@ | ||
38 | #include <lib3270/log.h> | 42 | #include <lib3270/log.h> |
39 | #include <v3270/actions.h> | 43 | #include <v3270/actions.h> |
40 | #include <terminal.h> | 44 | #include <terminal.h> |
45 | + #include <gdk/gdkkeysyms-compat.h> | ||
41 | 46 | ||
42 | /*--[ Widget Definition ]----------------------------------------------------------------------------*/ | 47 | /*--[ Widget Definition ]----------------------------------------------------------------------------*/ |
43 | 48 | ||
@@ -69,6 +74,9 @@ | @@ -69,6 +74,9 @@ | ||
69 | static void load(GtkWidget *w, GtkWidget *terminal); | 74 | static void load(GtkWidget *w, GtkWidget *terminal); |
70 | static void apply(GtkWidget *w, GtkWidget *terminal); | 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 | /*--[ Implement ]------------------------------------------------------------------------------------*/ | 80 | /*--[ Implement ]------------------------------------------------------------------------------------*/ |
73 | 81 | ||
74 | static void V3270AcceleratorSettings_class_init(V3270AcceleratorSettingsClass *klass) | 82 | static void V3270AcceleratorSettings_class_init(V3270AcceleratorSettingsClass *klass) |
@@ -95,13 +103,23 @@ | @@ -95,13 +103,23 @@ | ||
95 | // Create Accelerator list | 103 | // Create Accelerator list |
96 | GtkCellRenderer * text_renderer = gtk_cell_renderer_text_new(); | 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 | g_object_set( | 114 | g_object_set( |
100 | - accel_renderer, | 115 | + accel_renderer[1], |
101 | "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER, | 116 | "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER, |
102 | "editable", TRUE, | 117 | "editable", TRUE, |
103 | NULL); | 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 | 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)); | 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 | gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(widget->store),1,GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID); | 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,7 +142,7 @@ | ||
124 | GTK_TREE_VIEW(view), | 142 | GTK_TREE_VIEW(view), |
125 | -1, | 143 | -1, |
126 | _("Accelerator"), | 144 | _("Accelerator"), |
127 | - accel_renderer, | 145 | + accel_renderer[0], |
128 | "accel-mods", MAIN_MASK, | 146 | "accel-mods", MAIN_MASK, |
129 | "accel-key", MAIN_VALUE, | 147 | "accel-key", MAIN_VALUE, |
130 | NULL | 148 | NULL |
@@ -134,7 +152,7 @@ | @@ -134,7 +152,7 @@ | ||
134 | GTK_TREE_VIEW(view), | 152 | GTK_TREE_VIEW(view), |
135 | -1, | 153 | -1, |
136 | _("Alternative"), | 154 | _("Alternative"), |
137 | - accel_renderer, | 155 | + accel_renderer[1], |
138 | "accel-mods", ALTERNATIVE_MASK, | 156 | "accel-mods", ALTERNATIVE_MASK, |
139 | "accel-key", ALTERNATIVE_VALUE, | 157 | "accel-key", ALTERNATIVE_VALUE, |
140 | NULL | 158 | NULL |
@@ -155,7 +173,8 @@ | @@ -155,7 +173,8 @@ | ||
155 | gtk_grid_attach(GTK_GRID(widget),box,0,0,4,4); | 173 | gtk_grid_attach(GTK_GRID(widget),box,0,0,4,4); |
156 | } | 174 | } |
157 | 175 | ||
158 | - } | 176 | +} |
177 | + | ||
159 | 178 | ||
160 | LIB3270_EXPORT GtkWidget * v3270_accelerator_settings_new() | 179 | LIB3270_EXPORT GtkWidget * v3270_accelerator_settings_new() |
161 | { | 180 | { |
@@ -167,6 +186,163 @@ LIB3270_EXPORT GtkWidget * v3270_accelerator_settings_new() | @@ -167,6 +186,163 @@ LIB3270_EXPORT GtkWidget * v3270_accelerator_settings_new() | ||
167 | return GTK_WIDGET(settings); | 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 | void load(GtkWidget *widget, GtkWidget *terminal) | 347 | void load(GtkWidget *widget, GtkWidget *terminal) |
172 | { | 348 | { |
@@ -195,8 +371,17 @@ void load(GtkWidget *widget, GtkWidget *terminal) | @@ -195,8 +371,17 @@ void load(GtkWidget *widget, GtkWidget *terminal) | ||
195 | 371 | ||
196 | if(ix < G_N_ELEMENTS(keymaps)) | 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 | ix++; | 385 | ix++; |
201 | } | 386 | } |
202 | 387 | ||
@@ -206,6 +391,7 @@ void load(GtkWidget *widget, GtkWidget *terminal) | @@ -206,6 +391,7 @@ void load(GtkWidget *widget, GtkWidget *terminal) | ||
206 | // Add entry | 391 | // Add entry |
207 | GtkTreeIter iter; | 392 | GtkTreeIter iter; |
208 | gtk_list_store_append(store, &iter); | 393 | gtk_list_store_append(store, &iter); |
394 | + | ||
209 | gtk_list_store_set( | 395 | gtk_list_store_set( |
210 | store, | 396 | store, |
211 | &iter, | 397 | &iter, |
@@ -218,6 +404,7 @@ void load(GtkWidget *widget, GtkWidget *terminal) | @@ -218,6 +404,7 @@ void load(GtkWidget *widget, GtkWidget *terminal) | ||
218 | -1 | 404 | -1 |
219 | ); | 405 | ); |
220 | 406 | ||
407 | + | ||
221 | } | 408 | } |
222 | 409 | ||
223 | } | 410 | } |
@@ -226,3 +413,4 @@ void apply(GtkWidget *widget, GtkWidget *terminal) | @@ -226,3 +413,4 @@ void apply(GtkWidget *widget, GtkWidget *terminal) | ||
226 | { | 413 | { |
227 | debug("%s::%s","V3270AcceleratorSettings",__FUNCTION__); | 414 | debug("%s::%s","V3270AcceleratorSettings",__FUNCTION__); |
228 | } | 415 | } |
416 | + |
src/terminal/keyboard/accelerator.c
@@ -114,6 +114,11 @@ | @@ -114,6 +114,11 @@ | ||
114 | 114 | ||
115 | break; | 115 | break; |
116 | 116 | ||
117 | + case V3270_ACCELERATOR_TYPE_PFKEY: | ||
118 | + if( ((V3270PFKeyAccelerator *)accel)->name ) | ||
119 | + return ((V3270PFKeyAccelerator *)accel)->name; | ||
120 | + break; | ||
121 | + | ||
117 | } | 122 | } |
118 | 123 | ||
119 | return v3270_accelerator_get_name(accel); | 124 | return v3270_accelerator_get_name(accel); |