adding option to keep system layouts
[lxde/lxpanel.git] / src / plugins / xkb / xkb-plugin.c
CommitLineData
438d9fdb
MJ
1/**
2 * Copyright (c) 2010 LxDE Developers, see the file AUTHORS for details.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19/* Originally derived from xfce4-xkb-plugin, Copyright 2004 Alexander Iliev,
20 * which credits Michael Glickman. */
22242ed4 21
4496e880
JL
22/* Modified by Giuseppe Penone <giuspen@gmail.com> starting from 2012-07 and lxpanel 0.5.10 */
23
22242ed4
HJYP
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
28#include <glib/gi18n.h>
29
30#include <stdio.h>
45bd719e 31#include <stdlib.h>
22242ed4
HJYP
32#include <ctype.h>
33
34#include "xkb.h"
35
4496e880
JL
36enum
37{
38 COLUMN_ICON,
39 COLUMN_LAYOUT,
40 COLUMN_VARIANT,
41 NUM_COLUMNS
42};
43
44enum
45{
46 COLUMN_ADD_ICON,
47 COLUMN_ADD_LAYOUT,
48 COLUMN_ADD_DESC,
49 NUM_ADD_COLUMNS
50};
51
52enum
53{
54 COLUMN_MODEL_NAME,
55 COLUMN_MODEL_DESC,
56 NUM_MODEL_COLUMNS
57};
58
59enum
60{
61 COLUMN_CHANGE_NAME,
62 COLUMN_CHANGE_DESC,
63 NUM_CHANGE_COLUMNS
64};
65
18ecfe2a 66void panel_config_save(Panel * panel); /* defined in configurator.c */
67
4496e880
JL
68static int xkb_constructor(Plugin * p_plugin, char ** fp);
69static void xkb_destructor(Plugin * p_plugin);
70static void xkb_configure(Plugin * p, GtkWindow * parent);
71static void xkb_save_configuration(Plugin * p, FILE * fp);
72static void xkb_panel_configuration_changed(Plugin * p);
73static void xkb_settings_fill_layout_tree_model_with_config(XkbPlugin *p_xkb);
4496e880
JL
74static void xkb_update_layouts_n_variants(XkbPlugin *p_xkb);
75static void xkb_add_layout(XkbPlugin *p_xkb, gchar *layout, gchar*variant);
76static int xkb_get_flag_size(XkbPlugin *p_xkb);
77
895da737 78static void on_xkb_fbev_active_window_event(FbEv *ev, gpointer p_data);
4496e880
JL
79static gboolean on_xkb_button_scroll_event(GtkWidget * widget, GdkEventScroll * event, gpointer p_data);
80static gboolean on_xkb_button_press_event(GtkWidget * widget, GdkEventButton * event, gpointer p_data);
81static void on_radiobutton_disp_type_image_toggled(GtkToggleButton *p_radiobutton, gpointer p_data);
82static void on_radiobutton_disp_type_image_cust_toggled(GtkToggleButton *p_radiobutton, gpointer p_data);
83static void on_radiobutton_disp_type_text_toggled(GtkToggleButton *p_radiobutton, gpointer p_data);
895da737 84static void on_xkb_checkbutton_per_app_toggled(GtkToggleButton *tb, gpointer p_data);
876e3dd1 85static void on_xkb_checkbutton_no_reset_opt_toggled(GtkToggleButton *tb, gpointer p_data);
b3d38a01 86static void on_xkb_checkbutton_keep_system_layouts_toggled(GtkToggleButton *tb, gpointer p_data);
4496e880 87static void on_dialog_config_response(GtkDialog *p_dialog, gint response, gpointer p_data);
035ee619
GP
88static void on_xkb_entry_advanced_opt_icon_press(GtkEntry *p_entry,
89 GtkEntryIconPosition icon_pos,
90 GdkEvent *p_event,
91 gpointer p_data);
4496e880
JL
92
93static unsigned char user_active = FALSE;
94static const gchar flag_filepath_generator[] = "%s/%s.png";
95
96static int xkb_get_flag_size(XkbPlugin *p_xkb)
97{
98 int size = p_xkb->p_plugin->panel->icon_size;
99 switch(p_xkb->flag_size)
100 {
101 case 1: return size*0.5;
102 case 2: return size*0.6;
103 case 3: return size*0.7;
104 case 4: return size*0.8;
895da737 105 case 5: return size*0.9;
4496e880
JL
106 default: break;
107 }
895da737 108 return size;
4496e880 109}
d862b520 110
111/* Redraw the graphics. */
4496e880 112void xkb_redraw(XkbPlugin *p_xkb)
22242ed4 113{
d862b520 114 /* Set the image. */
115 gboolean valid_image = FALSE;
4496e880
JL
116 int size = xkb_get_flag_size(p_xkb);
117 if( (p_xkb->display_type == DISP_TYPE_IMAGE) || (p_xkb->display_type == DISP_TYPE_IMAGE_CUST) )
22242ed4 118 {
4496e880
JL
119 char * group_name = (char *)xkb_get_current_symbol_name_lowercase(p_xkb);
120 if(group_name != NULL)
d862b520 121 {
4496e880
JL
122 gchar *flag_filepath = NULL;
123 gchar *flags_dir = (p_xkb->cust_dir_exists && (p_xkb->display_type == DISP_TYPE_IMAGE_CUST)) ? g_strdup(FLAGSCUSTDIR):g_strdup(FLAGSDIR);
124 if(strchr(group_name, '/') != NULL)
125 {
126 gchar *layout_mod = g_strdup(group_name);
127 layout_mod = g_strdelimit(layout_mod, "/", '-');
128 flag_filepath = g_strdup_printf(flag_filepath_generator, flags_dir, layout_mod);
129 g_free(layout_mod);
130 }
131 else
132 {
133 flag_filepath = g_strdup_printf(flag_filepath_generator, flags_dir, group_name);
134 }
135 GdkPixbuf * unscaled_pixbuf = gdk_pixbuf_new_from_file(flag_filepath, NULL);
136 g_free(flag_filepath);
137 g_free(flags_dir);
438d9fdb
MJ
138 g_free(group_name);
139
4496e880 140 if(unscaled_pixbuf != NULL)
d862b520 141 {
438d9fdb
MJ
142 /* Loaded successfully. */
143 int width = gdk_pixbuf_get_width(unscaled_pixbuf);
144 int height = gdk_pixbuf_get_height(unscaled_pixbuf);
145 GdkPixbuf * pixbuf = gdk_pixbuf_scale_simple(unscaled_pixbuf, size * width / height, size, GDK_INTERP_BILINEAR);
4496e880 146 if(pixbuf != NULL)
438d9fdb 147 {
4496e880 148 gtk_image_set_from_pixbuf(GTK_IMAGE(p_xkb->p_image), pixbuf);
438d9fdb 149 g_object_unref(G_OBJECT(pixbuf));
4496e880
JL
150 gtk_widget_hide(p_xkb->p_label);
151 gtk_widget_show(p_xkb->p_image);
152 gtk_widget_set_tooltip_text(p_xkb->p_plugin->pwid, xkb_get_current_group_name(p_xkb));
438d9fdb
MJ
153 valid_image = TRUE;
154 }
155 g_object_unref(unscaled_pixbuf);
22242ed4
HJYP
156 }
157 }
158 }
159
d862b520 160 /* Set the label. */
4496e880 161 if( (p_xkb->display_type == DISP_TYPE_TEXT) || ( ! valid_image) )
d862b520 162 {
4496e880 163 char *group_name = (char *)xkb_get_current_symbol_name(p_xkb);
438d9fdb
MJ
164 if (group_name != NULL)
165 {
4496e880 166 GString *p_gstring_markup = g_string_new("");
895da737
JL
167 g_string_printf(p_gstring_markup,
168 "<span font='%u' weight='heavy' color=\"#%06x\">%s</span>",
169 size/2, gcolor2rgb24(&p_xkb->p_plugin->panel->gfontcolor), group_name);
4496e880
JL
170 gtk_label_set_markup(GTK_LABEL(p_xkb->p_label), p_gstring_markup->str);
171 g_string_free(p_gstring_markup, TRUE/*free also gstring->str*/);
172 gtk_widget_hide(p_xkb->p_image);
173 gtk_widget_show(p_xkb->p_label);
174 gtk_widget_set_tooltip_text(p_xkb->p_plugin->pwid, xkb_get_current_group_name(p_xkb));
d862b520 175 }
176 }
22242ed4
HJYP
177}
178
895da737
JL
179/* Handler for "active_window" event on root window listener. */
180static void on_xkb_fbev_active_window_event(FbEv * ev, gpointer p_data)
181{
182 XkbPlugin * xkb = (XkbPlugin *)p_data;
183 if (xkb->enable_perwin)
184 {
185 Window * win = fb_ev_active_window(ev);
186 if (*win != None)
187 {
188 xkb_active_window_changed(xkb, *win);
189 xkb_redraw(xkb);
190 }
191 }
192}
193
d862b520 194/* Handler for "scroll-event" on drawing area. */
4496e880 195static gboolean on_xkb_button_scroll_event(GtkWidget * widget, GdkEventScroll * event, gpointer p_data)
22242ed4 196{
4496e880 197 XkbPlugin * xkb = (XkbPlugin *)p_data;
22242ed4 198
d862b520 199 /* Change to next or previous group. */
200 xkb_change_group(xkb,
201 (((event->direction == GDK_SCROLL_UP) || (event->direction == GDK_SCROLL_RIGHT)) ? 1 : -1));
202 return TRUE;
22242ed4
HJYP
203}
204
d862b520 205/* Handler for button-press-event on top level widget. */
4496e880 206static gboolean on_xkb_button_press_event(GtkWidget * widget, GdkEventButton * event, gpointer p_data)
22242ed4 207{
4496e880 208 XkbPlugin * xkb = (XkbPlugin *)p_data;
22242ed4 209
d862b520 210 /* Standard right-click handling. */
4496e880 211 if (plugin_button_press_event(widget, event, xkb->p_plugin))
d862b520 212 return TRUE;
22242ed4 213
d862b520 214 /* Change to next group. */
215 xkb_change_group(xkb, 1);
18ecfe2a 216 return TRUE;
22242ed4
HJYP
217}
218
035ee619
GP
219static void on_xkb_entry_advanced_opt_icon_press(GtkEntry *p_entry,
220 GtkEntryIconPosition icon_pos,
221 GdkEvent *p_event,
222 gpointer p_data)
223{
224 XkbPlugin *p_xkb = (XkbPlugin *)p_data;
225 g_free(p_xkb->kbd_advanced_options);
226 p_xkb->kbd_advanced_options = g_strdup(gtk_entry_get_text(p_entry));
226cc442 227 xkb_setxkbmap(p_xkb);
035ee619
GP
228}
229
d862b520 230/* Plugin constructor. */
4496e880 231static int xkb_constructor(Plugin * p_plugin, char ** fp)
22242ed4 232{
d862b520 233 /* Allocate plugin context and set into Plugin private data pointer. */
4496e880
JL
234 XkbPlugin * p_xkb = g_new0(XkbPlugin, 1);
235 p_xkb->p_plugin = p_plugin;
236 p_plugin->priv = p_xkb;
d862b520 237
238 /* Initialize to defaults. */
4496e880 239 p_xkb->display_type = DISP_TYPE_IMAGE;
895da737 240 p_xkb->enable_perwin = FALSE;
876e3dd1 241 p_xkb->do_not_reset_opt = FALSE;
b3d38a01 242 p_xkb->keep_system_layouts = FALSE;
4496e880
JL
243 p_xkb->kbd_model = NULL;
244 p_xkb->kbd_layouts = NULL;
245 p_xkb->kbd_variants = NULL;
246 p_xkb->kbd_change_option = NULL;
f8918f4a 247 p_xkb->kbd_advanced_options = NULL;
4496e880
JL
248 p_xkb->flag_size = 3;
249 p_xkb->cust_dir_exists = g_file_test(FLAGSCUSTDIR, G_FILE_TEST_IS_DIR);
d862b520 250
251 /* Load parameters from the configuration file. */
252 line s;
253 s.len = 256;
254 if (fp != NULL)
255 {
256 while (lxpanel_get_line(fp, &s) != LINE_BLOCK_END)
257 {
258 if (s.type == LINE_NONE)
259 {
260 ERR( "xkb: illegal token %s\n", s.str);
261 return 0;
262 }
263 if (s.type == LINE_VAR)
264 {
4496e880
JL
265 if(g_ascii_strcasecmp(s.t[0], "DisplayType") == 0)
266 {
267 p_xkb->display_type = atoi(s.t[1]);
268 }
895da737
JL
269 else if(g_ascii_strcasecmp(s.t[0], "PerWinLayout") == 0)
270 {
271 p_xkb->enable_perwin = str2num(bool_pair, s.t[1], 0);
272 }
876e3dd1
GP
273 else if(g_ascii_strcasecmp(s.t[0], "NoResetOpt") == 0)
274 {
275 p_xkb->do_not_reset_opt = str2num(bool_pair, s.t[1], 0);
276 }
b3d38a01
GP
277 else if(g_ascii_strcasecmp(s.t[0], "KeepSysLayouts") == 0)
278 {
279 p_xkb->keep_system_layouts = str2num(bool_pair, s.t[1], 0);
280 }
4496e880
JL
281 else if(g_ascii_strcasecmp(s.t[0], "Model") == 0)
282 {
283 p_xkb->kbd_model = g_strdup(s.t[1]);
284 }
285 else if(g_ascii_strcasecmp(s.t[0], "LayoutsList") == 0)
286 {
287 p_xkb->kbd_layouts = g_strdup(s.t[1]);
288 }
289 else if(g_ascii_strcasecmp(s.t[0], "VariantsList") == 0)
290 {
291 p_xkb->kbd_variants = g_strdup(s.t[1]);
292 }
293 else if(g_ascii_strcasecmp(s.t[0], "ToggleOpt") == 0)
294 {
295 p_xkb->kbd_change_option = g_strdup(s.t[1]);
296 }
f8918f4a
GP
297 else if(g_ascii_strcasecmp(s.t[0], "AdvancedOpt") == 0)
298 {
299 p_xkb->kbd_advanced_options = g_strdup(s.t[1]);
300 }
4496e880
JL
301 else if(g_ascii_strcasecmp(s.t[0], "FlagSize") == 0)
302 {
303 p_xkb->flag_size = atoi(s.t[1]);
304 }
d862b520 305 else
306 ERR( "xkb: unknown var %s\n", s.t[0]);
307 }
308 else
309 {
310 ERR( "xkb: illegal in this context %s\n", s.str);
311 return 0;
312 }
313 }
314 }
2918994e 315
d862b520 316 /* Allocate top level widget and set into Plugin widget pointer. */
4496e880
JL
317 p_plugin->pwid = gtk_event_box_new();
318 gtk_widget_add_events(p_plugin->pwid, GDK_BUTTON_PRESS_MASK);
d862b520 319
320 /* Create a horizontal box as the child of the button. */
321 GtkWidget * hbox = gtk_hbox_new(FALSE, 0);
4496e880
JL
322 gtk_container_set_border_width(GTK_CONTAINER(hbox), 1);
323 gtk_container_add(GTK_CONTAINER(p_xkb->p_plugin->pwid), hbox);
d862b520 324 gtk_widget_show(hbox);
325
326 /* Create a label and an image as children of the horizontal box.
327 * Only one of these is visible at a time, controlled by user preference
328 * and the successful loading of the image. */
4496e880
JL
329 p_xkb->p_label = gtk_label_new("");
330 gtk_container_add(GTK_CONTAINER(hbox), p_xkb->p_label);
331 p_xkb->p_image = gtk_image_new();
332 gtk_container_add(GTK_CONTAINER(hbox), p_xkb->p_image);
d862b520 333
895da737
JL
334 /* Chech for first run */
335 if( (p_xkb->kbd_model == NULL) || (p_xkb->kbd_layouts == NULL) ||
336 (p_xkb->kbd_variants == NULL) || (p_xkb->kbd_change_option == NULL) )
337 {
338 /* This is a first run, read the current layout */
339 xkb_mechanism_constructor(p_xkb);
340
341 if(p_xkb->kbd_model != NULL) g_free(p_xkb->kbd_model);
342 if(p_xkb->kbd_layouts != NULL) g_free(p_xkb->kbd_layouts);
343 if(p_xkb->kbd_variants != NULL) g_free(p_xkb->kbd_variants);
344 if(p_xkb->kbd_change_option != NULL) g_free(p_xkb->kbd_change_option);
345
346 p_xkb->kbd_model = g_strdup("pc105");
347 gchar *symbol_name_lowercase = (char *)xkb_get_current_symbol_name_lowercase(p_xkb);
348 p_xkb->kbd_layouts = g_strdup(symbol_name_lowercase);
349 g_free(symbol_name_lowercase);
350 p_xkb->kbd_variants = g_strdup(",");
351 p_xkb->kbd_change_option = g_strdup("shift_caps_toggle");
352
353 xkb_mechanism_destructor(p_xkb);
354 }
355
d862b520 356 /* Initialize the XKB interface. */
895da737 357 xkb_setxkbmap(p_xkb);
4496e880 358 xkb_mechanism_constructor(p_xkb);
d862b520 359
d862b520 360 /* Connect signals. */
4496e880
JL
361 g_signal_connect(p_plugin->pwid, "button-press-event", G_CALLBACK(on_xkb_button_press_event), p_xkb);
362 g_signal_connect(p_plugin->pwid, "scroll-event", G_CALLBACK(on_xkb_button_scroll_event), p_xkb);
895da737 363 g_signal_connect(G_OBJECT(fbev), "active_window", G_CALLBACK(on_xkb_fbev_active_window_event), p_xkb);
d862b520 364
365 /* Show the widget and return. */
4496e880
JL
366 xkb_redraw(p_xkb);
367 gtk_widget_show(p_plugin->pwid);
d862b520 368 return 1;
22242ed4
HJYP
369}
370
d862b520 371/* Plugin destructor. */
4496e880 372static void xkb_destructor(Plugin * p_plugin)
22242ed4 373{
4496e880 374 XkbPlugin *p_xkb = (XkbPlugin *)p_plugin->priv;
22242ed4 375
895da737
JL
376 /* Disconnect root window event handler. */
377 g_signal_handlers_disconnect_by_func(G_OBJECT(fbev), on_xkb_fbev_active_window_event, p_xkb);
378
d862b520 379 /* Disconnect from the XKB mechanism. */
4496e880
JL
380 g_source_remove(p_xkb->source_id);
381 xkb_mechanism_destructor(p_xkb);
22242ed4 382
d862b520 383 /* Ensure that the configuration dialog is dismissed. */
4496e880
JL
384 if(p_xkb->p_dialog_config != NULL)
385 gtk_widget_destroy(p_xkb->p_dialog_config);
22242ed4 386
d862b520 387 /* Deallocate all memory. */
4496e880
JL
388 g_free(p_xkb->kbd_model);
389 g_free(p_xkb->kbd_layouts);
390 g_free(p_xkb->kbd_variants);
391 g_free(p_xkb->kbd_change_option);
f8918f4a 392 g_free(p_xkb->kbd_advanced_options);
4496e880
JL
393 g_free(p_xkb);
394}
395
895da737
JL
396/* Handler for "toggled" event on per-application check box of configuration dialog. */
397static void on_xkb_checkbutton_per_app_toggled(GtkToggleButton *tb, gpointer p_data)
398{
399 if(user_active == TRUE)
400 {
401 /* Fetch the new value and redraw. */
402 XkbPlugin * xkb = (XkbPlugin *)p_data;
403 xkb->enable_perwin = gtk_toggle_button_get_active(tb);
404 if(!xkb->enable_perwin)
405 {
406 /* at deactivation clear the hash table */
407 if(xkb->p_hash_table_group != NULL)
408 g_hash_table_destroy(xkb->p_hash_table_group);
409 xkb->p_hash_table_group = g_hash_table_new(g_direct_hash, NULL);
410 }
411 xkb_redraw(xkb);
412 }
413}
414
876e3dd1 415/* Handler for "toggled" event on no reset options check box of configuration dialog. */
b3d38a01 416static void on_xkb_checkbutton_no_reset_opt_toggled(GtkToggleButton *tb, gpointer p_data)
876e3dd1
GP
417{
418 if(user_active == TRUE)
419 {
420 /* Fetch the new value and redraw. */
421 XkbPlugin * xkb = (XkbPlugin *)p_data;
422 xkb->do_not_reset_opt = gtk_toggle_button_get_active(tb);
423 xkb_redraw(xkb);
424 }
425}
426
b3d38a01
GP
427/* Handler for "toggled" event on keep system layouts check box of configuration dialog. */
428static void on_xkb_checkbutton_keep_system_layouts_toggled(GtkToggleButton *tb, gpointer p_data)
429{
430 if(user_active == TRUE)
431 {
432 /* Fetch the new value and redraw. */
433 XkbPlugin * xkb = (XkbPlugin *)p_data;
434 xkb->keep_system_layouts = gtk_toggle_button_get_active(tb);
435 xkb_redraw(xkb);
436 }
437}
438
4496e880
JL
439static void on_radiobutton_flag_size_1_toggled(GtkToggleButton *p_radiobutton, gpointer p_data)
440{
441 if( (user_active == TRUE) && gtk_toggle_button_get_active(p_radiobutton) )
442 {
443 XkbPlugin * p_xkb = (XkbPlugin *)p_data;
444 p_xkb->flag_size = 1;
445 xkb_redraw(p_xkb);
446 }
447}
448
449static void on_radiobutton_flag_size_2_toggled(GtkToggleButton *p_radiobutton, gpointer p_data)
450{
451 if( (user_active == TRUE) && gtk_toggle_button_get_active(p_radiobutton) )
452 {
453 XkbPlugin * p_xkb = (XkbPlugin *)p_data;
454 p_xkb->flag_size = 2;
455 xkb_redraw(p_xkb);
456 }
22242ed4
HJYP
457}
458
4496e880 459static void on_radiobutton_flag_size_3_toggled(GtkToggleButton *p_radiobutton, gpointer p_data)
22242ed4 460{
4496e880
JL
461 if( (user_active == TRUE) && gtk_toggle_button_get_active(p_radiobutton) )
462 {
463 XkbPlugin * p_xkb = (XkbPlugin *)p_data;
464 p_xkb->flag_size = 3;
465 xkb_redraw(p_xkb);
466 }
22242ed4
HJYP
467}
468
4496e880 469static void on_radiobutton_flag_size_4_toggled(GtkToggleButton *p_radiobutton, gpointer p_data)
22242ed4 470{
4496e880
JL
471 if( (user_active == TRUE) && gtk_toggle_button_get_active(p_radiobutton) )
472 {
473 XkbPlugin * p_xkb = (XkbPlugin *)p_data;
474 p_xkb->flag_size = 4;
475 xkb_redraw(p_xkb);
476 }
22242ed4
HJYP
477}
478
4496e880 479static void on_radiobutton_flag_size_5_toggled(GtkToggleButton *p_radiobutton, gpointer p_data)
22242ed4 480{
4496e880
JL
481 if( (user_active == TRUE) && gtk_toggle_button_get_active(p_radiobutton) )
482 {
483 XkbPlugin * p_xkb = (XkbPlugin *)p_data;
484 p_xkb->flag_size = 5;
485 xkb_redraw(p_xkb);
486 }
487}
488
895da737
JL
489static void on_radiobutton_flag_size_6_toggled(GtkToggleButton *p_radiobutton, gpointer p_data)
490{
491 if( (user_active == TRUE) && gtk_toggle_button_get_active(p_radiobutton) )
492 {
493 XkbPlugin * p_xkb = (XkbPlugin *)p_data;
494 p_xkb->flag_size = 6;
495 xkb_redraw(p_xkb);
496 }
497}
498
4496e880
JL
499/* Handler for "toggled" event on display type image radiobutton of configuration dialog. */
500static void on_radiobutton_disp_type_image_toggled(GtkToggleButton *p_radiobutton, gpointer p_data)
501{
502 if( (user_active == TRUE) && gtk_toggle_button_get_active(p_radiobutton) )
503 {
504 /* Fetch the new value and redraw. */
505 XkbPlugin * p_xkb = (XkbPlugin *)p_data;
506 p_xkb->display_type = DISP_TYPE_IMAGE;
507 xkb_redraw(p_xkb);
508 }
509}
510
511/* Handler for "toggled" event on display type image radiobutton of configuration dialog. */
512static void on_radiobutton_disp_type_image_cust_toggled(GtkToggleButton *p_radiobutton, gpointer p_data)
513{
514 if( (user_active == TRUE) && gtk_toggle_button_get_active(p_radiobutton) )
515 {
516 /* Fetch the new value and redraw. */
517 XkbPlugin * p_xkb = (XkbPlugin *)p_data;
518 p_xkb->display_type = DISP_TYPE_IMAGE_CUST;
519 xkb_redraw(p_xkb);
520 }
521}
522
523/* Handler for "toggled" event on display type image radiobutton of configuration dialog. */
524static void on_radiobutton_disp_type_text_toggled(GtkToggleButton *p_radiobutton, gpointer p_data)
525{
526 if( (user_active == TRUE) && gtk_toggle_button_get_active(p_radiobutton) )
527 {
528 /* Fetch the new value and redraw. */
529 XkbPlugin * p_xkb = (XkbPlugin *)p_data;
530 p_xkb->display_type = DISP_TYPE_TEXT;
531 xkb_redraw(p_xkb);
532 }
22242ed4
HJYP
533}
534
d862b520 535/* Handler for "response" event on configuration dialog. */
4496e880 536static void on_dialog_config_response(GtkDialog *p_dialog, gint response, gpointer data)
22242ed4 537{
4496e880 538 XkbPlugin * p_xkb = (XkbPlugin *)data;
22242ed4 539
d862b520 540 /* Save the new configuration and redraw the plugin. */
4496e880
JL
541 panel_config_save(p_xkb->p_plugin->panel);
542 xkb_redraw(p_xkb);
22242ed4 543
d862b520 544 /* Destroy the dialog. */
4496e880
JL
545 gtk_widget_destroy(p_xkb->p_dialog_config);
546 p_xkb->p_dialog_config = NULL;
547}
548
895da737
JL
549static gboolean on_treeviews_lists_button_press_event(GtkWidget *p_widget,
550 GdkEventButton *p_event,
551 gpointer p_data)
4496e880 552{
895da737
JL
553 if(p_event->button == 1)
554 {
555 if(p_event->type == GDK_2BUTTON_PRESS)
556 {
557 GtkButton *p_button_ok = (GtkButton *)p_data;
558 gtk_button_clicked(p_button_ok);
559 }
560 }
1d0e30c1
GP
561 else if(p_event->button == 2)
562 {
563 GtkTreePath *p_tree_path;
564 if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(p_widget),
565 p_event->x, p_event->y,
566 &p_tree_path,
567 NULL, NULL, NULL))
568 {
569 if(gtk_tree_view_row_expanded(GTK_TREE_VIEW(p_widget), p_tree_path))
570 gtk_tree_view_collapse_row(GTK_TREE_VIEW(p_widget), p_tree_path);
571 else
572 gtk_tree_view_expand_row(GTK_TREE_VIEW(p_widget), p_tree_path, FALSE);
573 gtk_tree_path_free(p_tree_path);
574 }
575 }
895da737 576 return FALSE;
4496e880
JL
577}
578
579static void on_button_kbd_model_clicked(GtkButton *p_button, gpointer *p_data)
580{
581 XkbPlugin *p_xkb = (XkbPlugin *)p_data;
582
583 // dialog
584 GtkWidget *p_dialog = gtk_dialog_new_with_buttons(_("Select Keyboard Model"),
585 GTK_WINDOW(p_xkb->p_dialog_config),
586 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
587 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
588 GTK_STOCK_OK, GTK_RESPONSE_OK,
589 NULL);
590
591 // scrolledwindow
592 GtkWidget * p_scrolledwindow_kbd_model = gtk_scrolled_window_new(NULL, NULL);
593 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(p_scrolledwindow_kbd_model),
594 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
595 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(p_dialog)->vbox), p_scrolledwindow_kbd_model, TRUE, TRUE, 2);
596
597 // liststore
598 GtkListStore *p_liststore_kbd_model = gtk_list_store_new(NUM_MODEL_COLUMNS, G_TYPE_STRING, G_TYPE_STRING);
599 GtkWidget *p_treeview_kbd_model = gtk_tree_view_new_with_model(GTK_TREE_MODEL(p_liststore_kbd_model));
600 g_object_unref(G_OBJECT(p_liststore_kbd_model));
601 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(p_treeview_kbd_model), TRUE);
602 gtk_container_add(GTK_CONTAINER(p_scrolledwindow_kbd_model), p_treeview_kbd_model);
603 GtkCellRenderer *p_renderer;
604 GtkTreeViewColumn *p_column;
605 // model
606 p_renderer = gtk_cell_renderer_text_new();
607 p_column = gtk_tree_view_column_new_with_attributes(_("Model"), p_renderer, "text", COLUMN_CHANGE_NAME, NULL);
e03d81df 608 gtk_tree_view_column_set_sort_column_id(p_column, COLUMN_CHANGE_NAME);
4496e880
JL
609 gtk_tree_view_append_column(GTK_TREE_VIEW(p_treeview_kbd_model), p_column);
610 // desc
611 p_renderer = gtk_cell_renderer_text_new();
612 p_column = gtk_tree_view_column_new_with_attributes(_("Description"), p_renderer, "text", COLUMN_CHANGE_DESC, NULL);
e03d81df 613 gtk_tree_view_column_set_sort_column_id(p_column, COLUMN_CHANGE_DESC);
4496e880
JL
614 gtk_tree_view_append_column(GTK_TREE_VIEW(p_treeview_kbd_model), p_column);
615
616 // populate model
617 GKeyFile *p_keyfile = g_key_file_new();
618 gchar *xkbcfg_filepath = g_strdup_printf("%s/models.cfg", XKBCONFDIR);
619 if(g_key_file_load_from_file(p_keyfile, xkbcfg_filepath, 0, NULL))
620 {
621 gchar **keys_models = g_key_file_get_keys(p_keyfile, "MODELS", NULL, NULL);
622 guint model_idx = 0;
623 GtkTreeIter tree_iter;
624 gchar *p_model_desc;
625 while(keys_models[model_idx] != NULL)
626 {
627 p_model_desc = g_key_file_get_string(p_keyfile, "MODELS", keys_models[model_idx], NULL);
628 gtk_list_store_append(p_liststore_kbd_model, &tree_iter);
629 gtk_list_store_set(p_liststore_kbd_model, &tree_iter,
630 COLUMN_MODEL_NAME, keys_models[model_idx],
631 COLUMN_MODEL_DESC, p_model_desc,
632 -1);
633 g_free(p_model_desc);
634 model_idx++;
635 }
636 g_strfreev(keys_models);
637 g_key_file_free(p_keyfile);
638 }
639 g_free(xkbcfg_filepath);
640
641 // callback for double click
4496e880 642 g_signal_connect(p_treeview_kbd_model, "button-press-event",
895da737
JL
643 G_CALLBACK(on_treeviews_lists_button_press_event),
644 gtk_dialog_get_widget_for_response(GTK_DIALOG(p_dialog), GTK_RESPONSE_OK));
e03d81df
GP
645 // sort for description
646 gtk_tree_view_column_clicked(p_column);
647
648 gtk_widget_set_size_request(p_dialog, 700, 500);
4496e880
JL
649 gtk_widget_show_all(GTK_WIDGET(p_scrolledwindow_kbd_model));
650 gint response = gtk_dialog_run(GTK_DIALOG(p_dialog));
651 if(response == GTK_RESPONSE_OK)
652 {
653 GtkTreeIter tree_iter_sel;
654 GtkTreeSelection *p_treeselection_kbd_model = gtk_tree_view_get_selection(GTK_TREE_VIEW(p_treeview_kbd_model));
655 if(gtk_tree_selection_get_selected(p_treeselection_kbd_model,
656 (GtkTreeModel **)(&p_liststore_kbd_model),
657 &tree_iter_sel))
658 {
659 gchar *kbd_model_new;
660 gtk_tree_model_get(GTK_TREE_MODEL(p_liststore_kbd_model),
661 &tree_iter_sel, COLUMN_MODEL_NAME, &kbd_model_new, -1);
662 g_free(p_xkb->kbd_model);
663 p_xkb->kbd_model = g_strdup(kbd_model_new);
664 gtk_button_set_label(GTK_BUTTON(p_xkb->p_button_kbd_model), p_xkb->kbd_model);
665 g_free(kbd_model_new);
666 xkb_setxkbmap(p_xkb);
667 xkb_redraw(p_xkb);
668 }
669 }
670 gtk_widget_destroy(p_dialog);
671}
672
673static void on_button_kbd_change_layout_clicked(GtkButton *p_button, gpointer *p_data)
674{
675 XkbPlugin *p_xkb = (XkbPlugin *)p_data;
676
677 // dialog
678 GtkWidget *p_dialog = gtk_dialog_new_with_buttons(_("Select Layout Change Type"),
679 GTK_WINDOW(p_xkb->p_dialog_config),
680 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
681 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
682 GTK_STOCK_OK, GTK_RESPONSE_OK,
683 NULL);
684
685 // scrolledwindow
686 GtkWidget * p_scrolledwindow_kbd_change = gtk_scrolled_window_new(NULL, NULL);
687 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(p_scrolledwindow_kbd_change),
688 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
689 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(p_dialog)->vbox), p_scrolledwindow_kbd_change, TRUE, TRUE, 2);
690
691 // liststore
692 GtkListStore *p_liststore_kbd_change = gtk_list_store_new(NUM_CHANGE_COLUMNS, G_TYPE_STRING, G_TYPE_STRING);
693 GtkWidget *p_treeview_kbd_change = gtk_tree_view_new_with_model(GTK_TREE_MODEL(p_liststore_kbd_change));
694 g_object_unref(G_OBJECT(p_liststore_kbd_change));
695 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(p_treeview_kbd_change), TRUE);
696 gtk_container_add(GTK_CONTAINER(p_scrolledwindow_kbd_change), p_treeview_kbd_change);
697 GtkCellRenderer *p_renderer;
698 GtkTreeViewColumn *p_column;
699 // model
700 p_renderer = gtk_cell_renderer_text_new();
701 p_column = gtk_tree_view_column_new_with_attributes(_("Change Type"), p_renderer, "text", COLUMN_CHANGE_NAME, NULL);
702 gtk_tree_view_append_column(GTK_TREE_VIEW(p_treeview_kbd_change), p_column);
703 // desc
704 p_renderer = gtk_cell_renderer_text_new();
705 p_column = gtk_tree_view_column_new_with_attributes(_("Description"), p_renderer, "text", COLUMN_CHANGE_DESC, NULL);
706 gtk_tree_view_append_column(GTK_TREE_VIEW(p_treeview_kbd_change), p_column);
707
708 // populate model
709 GKeyFile *p_keyfile = g_key_file_new();
710 gchar *xkbcfg_filepath = g_strdup_printf("%s/toggle.cfg", XKBCONFDIR);
711 if(g_key_file_load_from_file(p_keyfile, xkbcfg_filepath, 0, NULL))
712 {
713 gchar **keys_changes = g_key_file_get_keys(p_keyfile, "TOGGLE", NULL, NULL);
714 guint change_idx = 0;
715 GtkTreeIter tree_iter;
716 gchar *p_change_desc;
717 while(keys_changes[change_idx] != NULL)
718 {
719 p_change_desc = g_key_file_get_string(p_keyfile, "TOGGLE", keys_changes[change_idx], NULL);
720 gtk_list_store_append(p_liststore_kbd_change, &tree_iter);
721 gtk_list_store_set(p_liststore_kbd_change, &tree_iter,
722 COLUMN_CHANGE_NAME, keys_changes[change_idx],
723 COLUMN_CHANGE_DESC, p_change_desc,
724 -1);
725 g_free(p_change_desc);
726 change_idx++;
727 }
728 g_strfreev(keys_changes);
729 g_key_file_free(p_keyfile);
730 }
731 g_free(xkbcfg_filepath);
732
733 // callback for double click
4496e880 734 g_signal_connect(p_treeview_kbd_change, "button-press-event",
895da737
JL
735 G_CALLBACK(on_treeviews_lists_button_press_event),
736 gtk_dialog_get_widget_for_response(GTK_DIALOG(p_dialog), GTK_RESPONSE_OK));
e03d81df 737 gtk_widget_set_size_request(p_dialog, 700, 500);
4496e880
JL
738 gtk_widget_show_all(GTK_WIDGET(p_scrolledwindow_kbd_change));
739 gint response = gtk_dialog_run(GTK_DIALOG(p_dialog));
740 if(response == GTK_RESPONSE_OK)
741 {
742 GtkTreeIter tree_iter_sel;
743 GtkTreeSelection *p_treeselection_kbd_change = gtk_tree_view_get_selection(GTK_TREE_VIEW(p_treeview_kbd_change));
744 if(gtk_tree_selection_get_selected(p_treeselection_kbd_change,
745 (GtkTreeModel **)(&p_liststore_kbd_change),
746 &tree_iter_sel))
747 {
748 gchar *kbd_change_new;
749 gtk_tree_model_get(GTK_TREE_MODEL(p_liststore_kbd_change),
750 &tree_iter_sel, COLUMN_CHANGE_NAME, &kbd_change_new, -1);
751 g_free(p_xkb->kbd_change_option);
752 p_xkb->kbd_change_option = g_strdup(kbd_change_new);
753 gtk_button_set_label(GTK_BUTTON(p_xkb->p_button_change_layout), p_xkb->kbd_change_option);
754 g_free(kbd_change_new);
755 xkb_setxkbmap(p_xkb);
756 xkb_redraw(p_xkb);
757 }
758 }
759 gtk_widget_destroy(p_dialog);
760}
761
762static void on_button_up_layout_clicked(GtkButton *p_button, gpointer *p_data)
763{
764 XkbPlugin *p_xkb = (XkbPlugin *)p_data;
765 GtkTreeIter tree_iter_sel;
766 GtkTreeIter tree_iter_prev;
767 if(gtk_tree_selection_get_selected(p_xkb->p_treeselection_layout,
768 (GtkTreeModel **)(&p_xkb->p_liststore_layout),
769 &tree_iter_sel))
770 {
771 GtkTreePath *p_tree_path = gtk_tree_model_get_path(GTK_TREE_MODEL(p_xkb->p_liststore_layout),
772 &tree_iter_sel);
773 if( (gtk_tree_path_prev(p_tree_path)) &&
774 (gtk_tree_model_get_iter(GTK_TREE_MODEL(p_xkb->p_liststore_layout),
775 &tree_iter_prev,
776 p_tree_path)))
777 {
778 gtk_list_store_swap(p_xkb->p_liststore_layout, &tree_iter_sel, &tree_iter_prev);
779 xkb_update_layouts_n_variants(p_xkb);
780 }
781 gtk_tree_path_free(p_tree_path);
782 }
783}
784
785static void on_button_down_layout_clicked(GtkButton *p_button, gpointer *p_data)
786{
787 XkbPlugin *p_xkb = (XkbPlugin *)p_data;
788 GtkTreeIter tree_iter_sel;
789 GtkTreeIter tree_iter_next;
790 if(gtk_tree_selection_get_selected(p_xkb->p_treeselection_layout,
791 (GtkTreeModel **)(&p_xkb->p_liststore_layout),
792 &tree_iter_sel))
793 {
794 tree_iter_next = tree_iter_sel;
795 if(gtk_tree_model_iter_next(GTK_TREE_MODEL(p_xkb->p_liststore_layout),
796 &tree_iter_next))
797 {
798 gtk_list_store_swap(p_xkb->p_liststore_layout, &tree_iter_sel, &tree_iter_next);
799 xkb_update_layouts_n_variants(p_xkb);
800 }
801 }
802}
803
804static void on_button_rm_layout_clicked(GtkButton *p_button, gpointer *p_data)
805{
806 XkbPlugin *p_xkb = (XkbPlugin *)p_data;
807 GtkTreeIter tree_iter_sel;
808 if(gtk_tree_selection_get_selected(p_xkb->p_treeselection_layout,
809 (GtkTreeModel **)(&p_xkb->p_liststore_layout),
810 &tree_iter_sel))
811 {
812 gtk_list_store_remove(p_xkb->p_liststore_layout, &tree_iter_sel);
813 xkb_update_layouts_n_variants(p_xkb);
814 gtk_widget_set_sensitive(p_xkb->p_button_rm_layout, p_xkb->num_layouts > 1);
815 }
816}
817
818static void on_button_add_layout_clicked(GtkButton *p_button, gpointer *p_data)
819{
820 XkbPlugin *p_xkb = (XkbPlugin *)p_data;
821
822 // dialog
823 GtkWidget *p_dialog = gtk_dialog_new_with_buttons(_("Add Keyboard Layout"),
824 GTK_WINDOW(p_xkb->p_dialog_config),
825 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
826 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
827 GTK_STOCK_OK, GTK_RESPONSE_OK,
828 NULL);
829
830 // scrolledwindow
831 GtkWidget * p_scrolledwindow_add_layout = gtk_scrolled_window_new(NULL, NULL);
832 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(p_scrolledwindow_add_layout),
833 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
834 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(p_dialog)->vbox), p_scrolledwindow_add_layout, TRUE, TRUE, 2);
835
836 // treestore
837 GtkTreeStore *p_treestore_add_layout = gtk_tree_store_new(NUM_ADD_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
838 GtkWidget *p_treeview_add_layout = gtk_tree_view_new_with_model(GTK_TREE_MODEL(p_treestore_add_layout));
839 g_object_unref(G_OBJECT(p_treestore_add_layout));
840 gtk_tree_view_set_enable_tree_lines(GTK_TREE_VIEW(p_treeview_add_layout), TRUE);
841 gtk_container_add(GTK_CONTAINER(p_scrolledwindow_add_layout), p_treeview_add_layout);
842 GtkCellRenderer *p_renderer;
895da737 843 GtkTreeViewColumn *p_column, *p_column_desc;
4496e880
JL
844 // icon
845 p_renderer = gtk_cell_renderer_pixbuf_new();
895da737
JL
846 p_column = gtk_tree_view_column_new_with_attributes(_("Flag"), p_renderer, "pixbuf", COLUMN_ADD_ICON, NULL);
847 gtk_tree_view_column_set_sort_column_id(p_column, COLUMN_ADD_DESC);
4496e880
JL
848 gtk_tree_view_append_column(GTK_TREE_VIEW(p_treeview_add_layout), p_column);
849 // layout
850 p_renderer = gtk_cell_renderer_text_new();
895da737
JL
851 p_column = gtk_tree_view_column_new_with_attributes(_("Layout"), p_renderer, "text", COLUMN_ADD_LAYOUT, NULL);
852 gtk_tree_view_column_set_sort_column_id(p_column, COLUMN_ADD_LAYOUT);
4496e880
JL
853 gtk_tree_view_append_column(GTK_TREE_VIEW(p_treeview_add_layout), p_column);
854 // desc
855 p_renderer = gtk_cell_renderer_text_new();
895da737
JL
856 p_column_desc = gtk_tree_view_column_new_with_attributes(_("Description"), p_renderer, "text", COLUMN_ADD_DESC, NULL);
857 gtk_tree_view_column_set_sort_column_id(p_column_desc, COLUMN_ADD_DESC);
858 gtk_tree_view_append_column(GTK_TREE_VIEW(p_treeview_add_layout), p_column_desc);
859 // search column
860 gtk_tree_view_set_search_column(GTK_TREE_VIEW(p_treeview_add_layout), COLUMN_ADD_DESC);
4496e880
JL
861
862 // populate model
863 GKeyFile *p_keyfile = g_key_file_new();
864 gchar *xkbcfg_filepath = g_strdup_printf("%s/layouts.cfg", XKBCONFDIR);
865 if(g_key_file_load_from_file(p_keyfile, xkbcfg_filepath, 0, NULL))
866 {
867 gchar **keys_layouts = g_key_file_get_keys(p_keyfile, "LAYOUTS", NULL, NULL);
868 guint layout_idx = 0;
869 GtkTreeIter tree_top, tree_child;
870 gchar *p_layout_desc;
871 while(keys_layouts[layout_idx] != NULL)
872 {
873 p_layout_desc = g_key_file_get_string(p_keyfile, "LAYOUTS", keys_layouts[layout_idx], NULL);
874 if(strchr(keys_layouts[layout_idx], '(') == NULL)
875 {
876 gchar *flag_filepath = NULL;
877 gchar *flags_dir = (p_xkb->cust_dir_exists && (p_xkb->display_type == DISP_TYPE_IMAGE_CUST)) ? g_strdup(FLAGSCUSTDIR):g_strdup(FLAGSDIR);
878 if(strchr(keys_layouts[layout_idx], '/') != NULL)
879 {
880 gchar *layout_mod = g_strdup(keys_layouts[layout_idx]);
881 layout_mod = g_strdelimit(layout_mod, "/", '-');
882 flag_filepath = g_strdup_printf(flag_filepath_generator, flags_dir, layout_mod);
883 g_free(layout_mod);
884 }
885 else
886 {
887 flag_filepath = g_strdup_printf(flag_filepath_generator, flags_dir, keys_layouts[layout_idx]);
888 }
889 GdkPixbuf *p_pixbuf = gdk_pixbuf_new_from_file_at_size(flag_filepath, -1, 16, NULL);
890 gtk_tree_store_append(p_treestore_add_layout, &tree_top, NULL);
891 if(p_pixbuf != NULL)
892 {
893 gtk_tree_store_set(p_treestore_add_layout, &tree_top,
894 COLUMN_ADD_ICON, p_pixbuf,
895 COLUMN_ADD_LAYOUT, keys_layouts[layout_idx],
896 COLUMN_ADD_DESC, p_layout_desc,
897 -1);
898 g_object_unref(G_OBJECT(p_pixbuf));
899 }
900 else
901 {
902 gtk_tree_store_set(p_treestore_add_layout, &tree_top,
903 COLUMN_ADD_LAYOUT, keys_layouts[layout_idx],
904 COLUMN_ADD_DESC, p_layout_desc,
905 -1);
906 }
907 g_free(flag_filepath);
908 g_free(flags_dir);
909 }
910 else
911 {
912
913 gtk_tree_store_append(p_treestore_add_layout, &tree_child, &tree_top);
914 gtk_tree_store_set(p_treestore_add_layout, &tree_child,
915 COLUMN_ADD_LAYOUT, keys_layouts[layout_idx],
916 COLUMN_ADD_DESC, p_layout_desc,
917 -1);
918 }
919 g_free(p_layout_desc);
920 layout_idx++;
921 }
922 g_strfreev(keys_layouts);
923 g_key_file_free(p_keyfile);
924 }
925 g_free(xkbcfg_filepath);
926
927 // callback for double click
4496e880 928 g_signal_connect(p_treeview_add_layout, "button-press-event",
895da737
JL
929 G_CALLBACK(on_treeviews_lists_button_press_event),
930 gtk_dialog_get_widget_for_response(GTK_DIALOG(p_dialog), GTK_RESPONSE_OK));
931 // sort for description
932 gtk_tree_view_column_clicked(p_column_desc);
933
e03d81df 934 gtk_widget_set_size_request(p_dialog, 700, 500);
4496e880
JL
935 gtk_widget_show_all(GTK_WIDGET(p_scrolledwindow_add_layout));
936 gint response = gtk_dialog_run(GTK_DIALOG(p_dialog));
937 if(response == GTK_RESPONSE_OK)
938 {
939 GtkTreeIter tree_iter_sel;
940 GtkTreeSelection *p_treeselection_add_layout = gtk_tree_view_get_selection(GTK_TREE_VIEW(p_treeview_add_layout));
941 if(gtk_tree_selection_get_selected(p_treeselection_add_layout,
942 (GtkTreeModel **)(&p_treestore_add_layout),
943 &tree_iter_sel))
944 {
945 gchar *layout_add;
946 GString *p_gstring_new_layout = g_string_new("");
947 GString *p_gstring_new_variant = g_string_new("");
948 gtk_tree_model_get(GTK_TREE_MODEL(p_treestore_add_layout),
949 &tree_iter_sel, COLUMN_ADD_LAYOUT, &layout_add, -1);
950
951 if(strchr(layout_add, '(') == NULL)
952 {
953 g_string_append(p_gstring_new_layout, layout_add);
954 }
955 else
956 {
957 gboolean parsing_variant = FALSE;
958 guchar i;
959 for(i=0; layout_add[i]; i++)
960 {
961 if(!parsing_variant)
962 {
963 if(layout_add[i] == '(')
964 parsing_variant = TRUE;
965 else
966 g_string_append_c(p_gstring_new_layout, layout_add[i]);
967 }
968 else
969 {
970 if(layout_add[i] == ')')
971 break;
972 else
973 g_string_append_c(p_gstring_new_variant, layout_add[i]);
974 }
975 }
976 }
977 xkb_add_layout(p_xkb, p_gstring_new_layout->str, p_gstring_new_variant->str);
978 xkb_update_layouts_n_variants(p_xkb);
979
980 gtk_widget_set_sensitive(p_xkb->p_button_rm_layout, p_xkb->num_layouts > 1);
981
982 g_free(layout_add);
983 g_string_free(p_gstring_new_layout, TRUE/*free also gstring->str*/);
984 g_string_free(p_gstring_new_variant, TRUE/*free also gstring->str*/);
985 }
986 }
987 gtk_widget_destroy(p_dialog);
988}
989
047cf801 990void xkb_setxkbmap(XkbPlugin *p_xkb)
4496e880 991{
b3d38a01
GP
992 if(p_xkb->keep_system_layouts) return;
993
4496e880
JL
994 GString *p_gstring_syscmd = g_string_new("");
995 g_string_printf(p_gstring_syscmd,
996 "setxkbmap -model %s -layout %s -variant %s -option grp:%s",
226cc442
GP
997 p_xkb->kbd_model, p_xkb->kbd_layouts, p_xkb->kbd_variants,
998 p_xkb->kbd_change_option);
999 if( (p_xkb->kbd_advanced_options != NULL) && strlen(p_xkb->kbd_advanced_options) )
1000 {
1001 g_string_append(p_gstring_syscmd, " ");
1002 g_string_append(p_gstring_syscmd, p_xkb->kbd_advanced_options);
1003 }
876e3dd1 1004 if(!p_xkb->do_not_reset_opt)
895da737 1005 {
876e3dd1
GP
1006 if(system("setxkbmap -option")) // reset options
1007 {
1008 ERR("xkb: system(setxkbmap -option)\n");
1009 }
895da737
JL
1010 }
1011 if(system(p_gstring_syscmd->str)) // set new map
1012 {
1013 ERR("xkb: system(%s)\n", p_gstring_syscmd->str);
1014 }
4496e880
JL
1015 //g_printf("\n%s\n", p_gstring_syscmd->str);
1016 g_string_free(p_gstring_syscmd, TRUE/*free also gstring->str*/);
1017}
1018
1019static gboolean layouts_tree_model_foreach(GtkTreeModel *p_model,
1020 GtkTreePath *p_path,
1021 GtkTreeIter *p_iter,
1022 gpointer p_data)
1023{
1024 XkbPlugin *p_xkb = (XkbPlugin *)p_data;
1025 gchar *layout_val;
1026 gchar *variant_val;
1027
1028 gtk_tree_model_get(p_model, p_iter, COLUMN_LAYOUT, &layout_val, -1);
1029 gtk_tree_model_get(p_model, p_iter, COLUMN_VARIANT, &variant_val, -1);
1030
1031 if(strlen(p_xkb->p_gstring_layouts_partial->str))
1032 {
1033 g_string_append_c(p_xkb->p_gstring_layouts_partial, ',');
1034 g_string_append_c(p_xkb->p_gstring_variants_partial, ',');
1035 }
1036 g_string_append(p_xkb->p_gstring_layouts_partial, layout_val);
1037 g_string_append(p_xkb->p_gstring_variants_partial, variant_val);
1038
895da737
JL
1039 //g_printf("\npartial layouts = '%s'\n", p_xkb->p_gstring_layouts_partial->str);
1040 //g_printf("partial variants = '%s'\n", p_xkb->p_gstring_variants_partial->str);
4496e880
JL
1041
1042 g_free(layout_val);
1043 g_free(variant_val);
1044 p_xkb->num_layouts++;
1045 return FALSE;
1046}
1047
1048static void xkb_update_layouts_n_variants(XkbPlugin *p_xkb)
1049{
1050 p_xkb->p_gstring_layouts_partial = g_string_new("");
1051 p_xkb->p_gstring_variants_partial = g_string_new("");
1052 p_xkb->num_layouts = 0;
1053 gtk_tree_model_foreach(GTK_TREE_MODEL(p_xkb->p_liststore_layout),
1054 layouts_tree_model_foreach,
1055 p_xkb);
1056 if(!strlen(p_xkb->p_gstring_variants_partial->str))
1057 {
1058 g_string_append_c(p_xkb->p_gstring_variants_partial, ',');
1059 }
1060 g_free(p_xkb->kbd_layouts);
1061 g_free(p_xkb->kbd_variants);
1062 p_xkb->kbd_layouts = g_strdup(p_xkb->p_gstring_layouts_partial->str);
1063 p_xkb->kbd_variants = g_strdup(p_xkb->p_gstring_variants_partial->str);
1064 g_string_free(p_xkb->p_gstring_layouts_partial, TRUE/*free also gstring->str*/);
1065 g_string_free(p_xkb->p_gstring_variants_partial, TRUE/*free also gstring->str*/);
1066 xkb_setxkbmap(p_xkb);
1067 xkb_mechanism_destructor(p_xkb);
1068 xkb_mechanism_constructor(p_xkb);
1069 xkb_redraw(p_xkb);
1070}
1071
1072static void xkb_add_layout(XkbPlugin *p_xkb, gchar *layout, gchar*variant)
1073{
1074 GtkTreeIter tree_iter;
1075 gtk_list_store_append(p_xkb->p_liststore_layout, &tree_iter);
1076 gchar *flag_filepath = NULL;
1077 gchar *flags_dir = (p_xkb->cust_dir_exists && (p_xkb->display_type == DISP_TYPE_IMAGE_CUST)) ? g_strdup(FLAGSCUSTDIR):g_strdup(FLAGSDIR);
1078 if(strchr(layout, '/') != NULL)
1079 {
1080 gchar *layout_mod = g_strdup(layout);
1081 layout_mod = g_strdelimit(layout_mod, "/", '-');
1082 flag_filepath = g_strdup_printf(flag_filepath_generator, flags_dir, layout_mod);
1083 g_free(layout_mod);
1084 }
1085 else
1086 {
1087 flag_filepath = g_strdup_printf(flag_filepath_generator, flags_dir, layout);
1088 }
1089 GdkPixbuf *p_pixbuf = gdk_pixbuf_new_from_file_at_size(flag_filepath, -1, 20, NULL);
1090 if(p_pixbuf != NULL)
1091 {
1092 gtk_list_store_set(p_xkb->p_liststore_layout, &tree_iter,
1093 COLUMN_ICON, p_pixbuf,
1094 COLUMN_LAYOUT, layout,
1095 COLUMN_VARIANT, variant,
1096 -1);
1097 g_object_unref(G_OBJECT(p_pixbuf));
1098 }
1099 else
1100 {
1101 gtk_list_store_set(p_xkb->p_liststore_layout, &tree_iter,
1102 COLUMN_LAYOUT, layout,
1103 COLUMN_VARIANT, variant,
1104 -1);
1105 }
1106 g_free(flag_filepath);
1107 g_free(flags_dir);
1108}
1109
1110static void xkb_settings_fill_layout_tree_model_with_config(XkbPlugin *p_xkb)
1111{
1112 p_xkb->num_layouts = 0;
1113 if(strlen(p_xkb->kbd_layouts) && strlen(p_xkb->kbd_variants))
1114 {
1115 char **layouts = g_strsplit_set(p_xkb->kbd_layouts, ",", 0);
1116 char **variants = g_strsplit_set(p_xkb->kbd_variants, ",", 0);
1117
1118 while(layouts[p_xkb->num_layouts] != NULL)
1119 {
1120 xkb_add_layout(p_xkb, layouts[p_xkb->num_layouts], variants[p_xkb->num_layouts]);
1121 p_xkb->num_layouts++;
1122 }
1123 gtk_widget_set_sensitive(p_xkb->p_button_rm_layout, p_xkb->num_layouts > 1);
1124
1125 g_strfreev(layouts);
1126 g_strfreev(variants);
1127 }
22242ed4
HJYP
1128}
1129
d862b520 1130/* Callback when the configuration dialog is to be shown. */
1131static void xkb_configure(Plugin * p, GtkWindow * parent)
22242ed4 1132{
4496e880
JL
1133 XkbPlugin * p_xkb = (XkbPlugin *)p->priv;
1134 gchar markup_str[MAX_MARKUP_LEN];
1135
1136 user_active = FALSE;
d862b520 1137
4496e880 1138 // configuration dialog
d862b520 1139 GtkWidget * dlg = gtk_dialog_new_with_buttons(
4496e880 1140 _("Keyboard Layout Handler"),
d862b520 1141 NULL,
1142 GTK_DIALOG_NO_SEPARATOR,
4496e880 1143 GTK_STOCK_CLOSE,
d862b520 1144 GTK_RESPONSE_OK,
1145 NULL);
4496e880 1146 p_xkb->p_dialog_config = dlg;
d862b520 1147 panel_apply_icon(GTK_WINDOW(dlg));
1148
4496e880 1149 // main vbox of the config dialog
59df548f
GP
1150 GtkWidget * p_hbox_main = gtk_hbox_new(TRUE, 0);
1151 GtkWidget * p_vbox_left = gtk_vbox_new(FALSE, 0);
1152 GtkWidget * p_vbox_right = gtk_vbox_new(FALSE, 0);
1153 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dlg)->vbox), p_hbox_main);
1154 gtk_box_pack_start(GTK_BOX(p_hbox_main), p_vbox_left, FALSE, TRUE, 0);
1155 gtk_box_pack_start(GTK_BOX(p_hbox_main), p_vbox_right, FALSE, TRUE, 0);
4496e880
JL
1156
1157
1158 // 'KEYBOARD MODEL' frame
1159 GtkWidget * p_frame_kbd_model = gtk_frame_new(NULL);
b3d38a01 1160 gtk_widget_set_sensitive(p_frame_kbd_model, !p_xkb->keep_system_layouts);
4496e880
JL
1161 GtkWidget * p_label_kbd_model = gtk_label_new(NULL);
1162 snprintf(markup_str, MAX_MARKUP_LEN, "<b>%s</b>", _("Keyboard Model"));
1163 gtk_label_set_markup(GTK_LABEL(p_label_kbd_model), markup_str);
1164 gtk_misc_set_padding(GTK_MISC(p_label_kbd_model), 1, 0);
1165 gtk_frame_set_label_widget(GTK_FRAME(p_frame_kbd_model), p_label_kbd_model);
1166 gtk_frame_set_shadow_type(GTK_FRAME(p_frame_kbd_model), GTK_SHADOW_NONE);
59df548f 1167 gtk_box_pack_start(GTK_BOX(p_vbox_left), p_frame_kbd_model, TRUE, TRUE, 2);
4496e880
JL
1168 gtk_container_set_border_width(GTK_CONTAINER(p_frame_kbd_model), 3);
1169
1170 // frame alignment
1171 GtkWidget * p_alignment_kbd_model = gtk_alignment_new(0.5, 0.5, 1, 1);
1172 gtk_container_add(GTK_CONTAINER(p_frame_kbd_model), p_alignment_kbd_model);
1173 gtk_alignment_set_padding(GTK_ALIGNMENT(p_alignment_kbd_model), 4, 4, 10, 10);
1174 p_xkb->p_button_kbd_model = gtk_button_new_with_label(p_xkb->kbd_model);
1175 g_signal_connect(p_xkb->p_button_kbd_model, "clicked", G_CALLBACK(on_button_kbd_model_clicked), p_xkb);
1176 gtk_container_add(GTK_CONTAINER(p_alignment_kbd_model), p_xkb->p_button_kbd_model);
1177
1178
1179 // 'KEYBOARD LAYOUTS' frame
1180 GtkWidget * p_frame_kbd_layouts = gtk_frame_new(NULL);
b3d38a01 1181 gtk_widget_set_sensitive(p_frame_kbd_layouts, !p_xkb->keep_system_layouts);
4496e880
JL
1182 GtkWidget * p_label_kbd_layouts = gtk_label_new(NULL);
1183 snprintf(markup_str, MAX_MARKUP_LEN, "<b>%s</b>", _("Keyboard Layouts"));
1184 gtk_label_set_markup(GTK_LABEL(p_label_kbd_layouts), markup_str);
1185 gtk_misc_set_padding(GTK_MISC(p_label_kbd_layouts), 1, 0);
1186 gtk_frame_set_label_widget(GTK_FRAME(p_frame_kbd_layouts), p_label_kbd_layouts);
1187 gtk_frame_set_shadow_type(GTK_FRAME(p_frame_kbd_layouts), GTK_SHADOW_NONE);
59df548f 1188 gtk_box_pack_start(GTK_BOX(p_vbox_left), p_frame_kbd_layouts, TRUE, TRUE, 2);
4496e880 1189 gtk_container_set_border_width(GTK_CONTAINER(p_frame_kbd_layouts), 3);
59df548f 1190 gtk_widget_set_size_request(GTK_WIDGET(p_frame_kbd_layouts), 300, 180);
4496e880
JL
1191
1192 // frame alignment
1193 GtkWidget * p_alignment_kbd_layouts = gtk_alignment_new(0.5, 0.5, 1, 1);
1194 gtk_container_add(GTK_CONTAINER(p_frame_kbd_layouts), p_alignment_kbd_layouts);
1195 gtk_alignment_set_padding(GTK_ALIGNMENT(p_alignment_kbd_layouts), 4, 4, 10, 10);
1196 GtkWidget * p_hbox_kbd_layouts = gtk_hbox_new(FALSE, 0);
1197 gtk_container_add(GTK_CONTAINER(p_alignment_kbd_layouts), p_hbox_kbd_layouts);
1198
1199 // scrolledwindow and buttons
1200 GtkWidget * p_scrolledwindow_kbd_layouts = gtk_scrolled_window_new(NULL, NULL);
1201 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(p_scrolledwindow_kbd_layouts),
1202 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1203 gtk_box_pack_start(GTK_BOX(p_hbox_kbd_layouts), p_scrolledwindow_kbd_layouts, TRUE, TRUE, 2);
1204 GtkWidget * p_vbox_kbd_layouts = gtk_vbox_new(FALSE, 2);
1205 gtk_box_pack_start(GTK_BOX(p_hbox_kbd_layouts), p_vbox_kbd_layouts, FALSE, TRUE, 4);
1206 GtkWidget * p_button_add_layout = gtk_button_new_from_stock(GTK_STOCK_ADD);
1207 GtkWidget * p_button_up_layout = gtk_button_new_from_stock(GTK_STOCK_GO_UP);
1208 GtkWidget * p_button_down_layout = gtk_button_new_from_stock(GTK_STOCK_GO_DOWN);
1209 p_xkb->p_button_rm_layout = gtk_button_new_from_stock(GTK_STOCK_REMOVE);
1210 g_signal_connect(p_button_add_layout, "clicked", G_CALLBACK(on_button_add_layout_clicked), p_xkb);
1211 g_signal_connect(p_xkb->p_button_rm_layout, "clicked", G_CALLBACK(on_button_rm_layout_clicked), p_xkb);
1212 g_signal_connect(p_button_up_layout, "clicked", G_CALLBACK(on_button_up_layout_clicked), p_xkb);
1213 g_signal_connect(p_button_down_layout, "clicked", G_CALLBACK(on_button_down_layout_clicked), p_xkb);
1214 gtk_box_pack_start(GTK_BOX(p_vbox_kbd_layouts), p_button_add_layout, FALSE, TRUE, 0);
1215 gtk_box_pack_start(GTK_BOX(p_vbox_kbd_layouts), p_xkb->p_button_rm_layout, FALSE, TRUE, 0);
1216 gtk_box_pack_start(GTK_BOX(p_vbox_kbd_layouts), p_button_up_layout, FALSE, TRUE, 0);
1217 gtk_box_pack_start(GTK_BOX(p_vbox_kbd_layouts), p_button_down_layout, FALSE, TRUE, 0);
1218
1219 // liststore
1220 p_xkb->p_liststore_layout = gtk_list_store_new(NUM_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
1221 p_xkb->p_treeview_layout = gtk_tree_view_new_with_model(GTK_TREE_MODEL(p_xkb->p_liststore_layout));
1222 g_object_unref(G_OBJECT(p_xkb->p_liststore_layout));
1223 p_xkb->p_treeselection_layout = gtk_tree_view_get_selection(GTK_TREE_VIEW(p_xkb->p_treeview_layout));
1224 gtk_container_add(GTK_CONTAINER(p_scrolledwindow_kbd_layouts), p_xkb->p_treeview_layout);
1225 GtkCellRenderer *p_renderer;
1226 GtkTreeViewColumn *p_column;
1227 // icon
1228 p_renderer = gtk_cell_renderer_pixbuf_new();
1229 p_column = gtk_tree_view_column_new_with_attributes(_("Flag"), p_renderer, "pixbuf", COLUMN_ICON, NULL);
1230 gtk_tree_view_append_column(GTK_TREE_VIEW(p_xkb->p_treeview_layout), p_column);
1231 // layout
1232 p_renderer = gtk_cell_renderer_text_new();
1233 p_column = gtk_tree_view_column_new_with_attributes(_("Layout"), p_renderer, "text", COLUMN_LAYOUT, NULL);
1234 gtk_tree_view_append_column(GTK_TREE_VIEW(p_xkb->p_treeview_layout), p_column);
1235 // variant
1236 p_renderer = gtk_cell_renderer_text_new();
1237 p_column = gtk_tree_view_column_new_with_attributes(_("Variant"), p_renderer, "text", COLUMN_VARIANT, NULL);
1238 gtk_tree_view_append_column(GTK_TREE_VIEW(p_xkb->p_treeview_layout), p_column);
1239 xkb_settings_fill_layout_tree_model_with_config(p_xkb);
1240
1241
1242 // 'CHANGE LAYOUT OPTION' frame
1243 GtkWidget * p_frame_change_layout = gtk_frame_new(NULL);
b3d38a01 1244 gtk_widget_set_sensitive(p_frame_change_layout, !p_xkb->keep_system_layouts);
4496e880
JL
1245 GtkWidget * p_label_change_layout = gtk_label_new(NULL);
1246 snprintf(markup_str, MAX_MARKUP_LEN, "<b>%s</b>", _("Change Layout Option"));
1247 gtk_label_set_markup(GTK_LABEL(p_label_change_layout), markup_str);
1248 gtk_misc_set_padding(GTK_MISC(p_label_change_layout), 1, 0);
1249 gtk_frame_set_label_widget(GTK_FRAME(p_frame_change_layout), p_label_change_layout);
1250 gtk_frame_set_shadow_type(GTK_FRAME(p_frame_change_layout), GTK_SHADOW_NONE);
59df548f 1251 gtk_box_pack_start(GTK_BOX(p_vbox_left), p_frame_change_layout, TRUE, TRUE, 2);
4496e880
JL
1252 gtk_container_set_border_width(GTK_CONTAINER(p_frame_change_layout), 3);
1253
1254 // frame alignment
1255 GtkWidget * p_alignment_change_layout = gtk_alignment_new(0.5, 0.5, 1, 1);
1256 gtk_container_add(GTK_CONTAINER(p_frame_change_layout), p_alignment_change_layout);
1257 gtk_alignment_set_padding(GTK_ALIGNMENT(p_alignment_change_layout), 4, 4, 10, 10);
1258 p_xkb->p_button_change_layout = gtk_button_new_with_label(p_xkb->kbd_change_option);
1259 g_signal_connect(p_xkb->p_button_change_layout, "clicked", G_CALLBACK(on_button_kbd_change_layout_clicked), p_xkb);
1260 gtk_container_add(GTK_CONTAINER(p_alignment_change_layout), p_xkb->p_button_change_layout);
1261
1262
ee25642c
GP
1263 // 'ADVANCED setxkbmap OPTIONS' frame
1264 GtkWidget * p_frame_advanced_opt = gtk_frame_new(NULL);
1265 GtkWidget * p_label_advanced_opt = gtk_label_new(NULL);
1266 snprintf(markup_str, MAX_MARKUP_LEN, "<b>%s</b>", _("Advanced setxkbmap Options"));
1267 gtk_label_set_markup(GTK_LABEL(p_label_advanced_opt), markup_str);
1268 gtk_misc_set_padding(GTK_MISC(p_label_advanced_opt), 1, 0);
1269 gtk_frame_set_label_widget(GTK_FRAME(p_frame_advanced_opt), p_label_advanced_opt);
1270 gtk_frame_set_shadow_type(GTK_FRAME(p_frame_advanced_opt), GTK_SHADOW_NONE);
1271 gtk_box_pack_start(GTK_BOX(p_vbox_right), p_frame_advanced_opt, TRUE, TRUE, 2);
1272 gtk_container_set_border_width(GTK_CONTAINER(p_frame_advanced_opt), 3);
1273
1274 // frame alignment
1275 GtkWidget * p_alignment_advanced_opt = gtk_alignment_new(0.5, 0.5, 1, 1);
1276 gtk_container_add(GTK_CONTAINER(p_frame_advanced_opt), p_alignment_advanced_opt);
1277 gtk_alignment_set_padding(GTK_ALIGNMENT(p_alignment_advanced_opt), 4, 4, 10, 10);
bf60cb65
GP
1278 GtkWidget * p_vbox_advanced_opt = gtk_vbox_new(FALSE, 0);
1279 gtk_container_add(GTK_CONTAINER(p_alignment_advanced_opt), p_vbox_advanced_opt);
1280 GtkWidget * p_entry_advanced_opt = gtk_entry_new();
b3d38a01 1281 gtk_widget_set_sensitive(p_entry_advanced_opt, !p_xkb->keep_system_layouts);
035ee619 1282 gtk_entry_set_text(GTK_ENTRY(p_entry_advanced_opt), p_xkb->kbd_advanced_options);
f8918f4a 1283 gtk_entry_set_icon_from_stock(GTK_ENTRY(p_entry_advanced_opt), GTK_ENTRY_ICON_SECONDARY, "gtk-save");
035ee619 1284 g_signal_connect(p_entry_advanced_opt, "icon-press", G_CALLBACK(on_xkb_entry_advanced_opt_icon_press), p_xkb);
bf60cb65
GP
1285 gtk_box_pack_start(GTK_BOX(p_vbox_advanced_opt), p_entry_advanced_opt, FALSE, TRUE, 0);
1286 GtkWidget *p_checkbutton_no_reset_opt = gtk_check_button_new_with_mnemonic(_("Do _not reset existing options"));
b3d38a01 1287 gtk_widget_set_sensitive(p_checkbutton_no_reset_opt, !p_xkb->keep_system_layouts);
876e3dd1
GP
1288 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p_checkbutton_no_reset_opt), p_xkb->do_not_reset_opt);
1289 g_signal_connect(p_checkbutton_no_reset_opt, "toggled", G_CALLBACK(on_xkb_checkbutton_no_reset_opt_toggled), p_xkb);
bf60cb65 1290 gtk_box_pack_start(GTK_BOX(p_vbox_advanced_opt), p_checkbutton_no_reset_opt, FALSE, TRUE, 0);
b3d38a01
GP
1291 GtkWidget *p_checkbutton_keep_system_layouts = gtk_check_button_new_with_mnemonic(_("Keep _system layouts"));
1292 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p_checkbutton_keep_system_layouts), p_xkb->keep_system_layouts);
1293 g_signal_connect(p_checkbutton_keep_system_layouts, "toggled", G_CALLBACK(on_xkb_checkbutton_keep_system_layouts_toggled), p_xkb);
1294 gtk_box_pack_start(GTK_BOX(p_vbox_advanced_opt), p_checkbutton_keep_system_layouts, FALSE, TRUE, 0);
ee25642c
GP
1295
1296
895da737
JL
1297 // 'PER WINDOW SETTINGS' frame
1298 GtkWidget * p_frame_perapp_layout = gtk_frame_new(NULL);
1299 GtkWidget * p_label_perapp_layout = gtk_label_new(NULL);
1300 snprintf(markup_str, MAX_MARKUP_LEN, "<b>%s</b>", _("Per Window Settings"));
1301 gtk_label_set_markup(GTK_LABEL(p_label_perapp_layout), markup_str);
1302 gtk_misc_set_padding(GTK_MISC(p_label_perapp_layout), 1, 0);
1303 gtk_frame_set_label_widget(GTK_FRAME(p_frame_perapp_layout), p_label_perapp_layout);
1304 gtk_frame_set_shadow_type(GTK_FRAME(p_frame_perapp_layout), GTK_SHADOW_NONE);
59df548f 1305 gtk_box_pack_start(GTK_BOX(p_vbox_right), p_frame_perapp_layout, TRUE, TRUE, 2);
895da737
JL
1306 gtk_container_set_border_width(GTK_CONTAINER(p_frame_perapp_layout), 3);
1307
1308 // frame alignment
1309 GtkWidget * p_alignment_perapp_layout = gtk_alignment_new(0.5, 0.5, 1, 1);
1310 gtk_container_add(GTK_CONTAINER(p_frame_perapp_layout), p_alignment_perapp_layout);
1311 gtk_alignment_set_padding(GTK_ALIGNMENT(p_alignment_perapp_layout), 4, 4, 10, 10);
1312 GtkWidget *p_checkbutton_per_app = gtk_check_button_new_with_mnemonic(_("_Remember layout for each window"));
1313 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p_checkbutton_per_app), p_xkb->enable_perwin);
1314 g_signal_connect(p_checkbutton_per_app, "toggled", G_CALLBACK(on_xkb_checkbutton_per_app_toggled), p_xkb);
1315 gtk_container_add(GTK_CONTAINER(p_alignment_perapp_layout), p_checkbutton_per_app);
1316
1317
4496e880
JL
1318 // 'SHOW LAYOUT AS' frame
1319 GtkWidget * p_frame_display_type = gtk_frame_new(NULL);
1320 GtkWidget * p_label_show_layout_as = gtk_label_new(NULL);
1321 snprintf(markup_str, MAX_MARKUP_LEN, "<b>%s</b>", _("Show Layout as"));
1322 gtk_label_set_markup(GTK_LABEL(p_label_show_layout_as), markup_str);
1323 gtk_misc_set_padding(GTK_MISC(p_label_show_layout_as), 1, 0);
1324 gtk_frame_set_label_widget(GTK_FRAME(p_frame_display_type), p_label_show_layout_as);
1325 gtk_frame_set_shadow_type(GTK_FRAME(p_frame_display_type), GTK_SHADOW_NONE);
59df548f 1326 gtk_box_pack_start(GTK_BOX(p_vbox_right), p_frame_display_type, TRUE, TRUE, 2);
4496e880
JL
1327 gtk_container_set_border_width(GTK_CONTAINER(p_frame_display_type), 3);
1328
1329 // frame alignment
1330 GtkWidget * p_alignment_display_type = gtk_alignment_new(0.5, 0.5, 1, 1);
1331 gtk_container_add(GTK_CONTAINER(p_frame_display_type), p_alignment_display_type);
1332 gtk_alignment_set_padding(GTK_ALIGNMENT(p_alignment_display_type), 4, 4, 10, 10);
1333 GtkWidget *p_table = gtk_table_new(3, 2, FALSE);
1334 gtk_table_set_col_spacings(GTK_TABLE(p_table), 10);
1335 gtk_container_add(GTK_CONTAINER(p_alignment_display_type), p_table);
1336
1337 // radiobuttons
1338 GtkWidget * p_image_disp_type_image = gtk_image_new();
1339 GtkWidget * p_image_disp_type_image_cust = NULL;
1340 gchar *symbol_name_lowercase = (char *)xkb_get_current_symbol_name_lowercase(p_xkb);
1341 gchar *flag_filepath = NULL;
1342 gchar *flag_filepath_cust = NULL;
1343 if(strchr(symbol_name_lowercase, '/') != NULL)
1344 {
1345 gchar *layout_mod = g_strdup(symbol_name_lowercase);
1346 layout_mod = g_strdelimit(layout_mod, "/", '-');
1347 flag_filepath = g_strdup_printf(flag_filepath_generator, FLAGSDIR, layout_mod);
1348 if(p_xkb->cust_dir_exists)
1349 flag_filepath_cust = g_strdup_printf(flag_filepath_generator, FLAGSCUSTDIR, layout_mod);
1350 g_free(layout_mod);
1351 }
1352 else
1353 {
1354 flag_filepath = g_strdup_printf(flag_filepath_generator, FLAGSDIR, symbol_name_lowercase);
1355 if(p_xkb->cust_dir_exists)
1356 flag_filepath_cust = g_strdup_printf(flag_filepath_generator, FLAGSCUSTDIR, symbol_name_lowercase);
1357 }
1358 GdkPixbuf *p_pixbuf = gdk_pixbuf_new_from_file_at_size(flag_filepath, -1, 16, NULL);
1359 if(p_pixbuf != NULL)
1360 {
1361 gtk_image_set_from_pixbuf(GTK_IMAGE(p_image_disp_type_image), p_pixbuf);
1362 g_object_unref(G_OBJECT(p_pixbuf));
1363 }
1364 if(flag_filepath_cust != NULL)
1365 {
1366 p_image_disp_type_image_cust = gtk_image_new();
1367 GdkPixbuf *p_pixbuf_cust = gdk_pixbuf_new_from_file_at_size(flag_filepath_cust, -1, 16, NULL);
1368 if(p_pixbuf_cust != NULL)
1369 {
1370 gtk_image_set_from_pixbuf(GTK_IMAGE(p_image_disp_type_image_cust), p_pixbuf_cust);
1371 g_object_unref(G_OBJECT(p_pixbuf_cust));
1372 }
1373 }
1374 g_free(flag_filepath);
1375 if(flag_filepath_cust != NULL)
1376 g_free(flag_filepath_cust);
1377 g_free(symbol_name_lowercase);
1378 GtkWidget * p_label_disp_type_text = gtk_label_new(NULL);
1379 snprintf(markup_str, MAX_MARKUP_LEN, "<span font='%d' font_weight='heavy'>%s</span>", 16, xkb_get_current_symbol_name(p_xkb));
1380 gtk_label_set_markup(GTK_LABEL(p_label_disp_type_text), markup_str);
895da737 1381 GtkWidget * p_radiobutton_disp_type_image = gtk_radio_button_new_with_label(NULL, (const gchar *)_("Image"));
4496e880
JL
1382 GtkWidget * p_radiobutton_disp_type_image_cust = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(p_radiobutton_disp_type_image), (const gchar *)_("Custom Image"));
1383 GtkWidget * p_radiobutton_disp_type_text = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(p_radiobutton_disp_type_image), (const gchar *)_("Text"));
1384
1385 gtk_table_attach(GTK_TABLE(p_table), p_image_disp_type_image, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
1386 gtk_table_attach(GTK_TABLE(p_table), p_radiobutton_disp_type_image, 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
1387 if(p_xkb->cust_dir_exists)
1388 {
1389 gtk_table_attach(GTK_TABLE(p_table), p_image_disp_type_image_cust, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
1390 gtk_table_attach(GTK_TABLE(p_table), p_radiobutton_disp_type_image_cust, 1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
1391 }
1392 gtk_table_attach(GTK_TABLE(p_table), p_label_disp_type_text, 0, 1, 2, 3, GTK_FILL, GTK_FILL, 0, 0);
1393 gtk_table_attach(GTK_TABLE(p_table), p_radiobutton_disp_type_text, 1, 2, 2, 3, GTK_FILL, GTK_FILL, 0, 0);
1394
1395 g_signal_connect(p_radiobutton_disp_type_image, "toggled", G_CALLBACK(on_radiobutton_disp_type_image_toggled), p_xkb);
1396 if(p_xkb->cust_dir_exists)
1397 g_signal_connect(p_radiobutton_disp_type_image_cust, "toggled", G_CALLBACK(on_radiobutton_disp_type_image_cust_toggled), p_xkb);
1398 g_signal_connect(p_radiobutton_disp_type_text, "toggled", G_CALLBACK(on_radiobutton_disp_type_text_toggled), p_xkb);
1399 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p_radiobutton_disp_type_image), (p_xkb->display_type == DISP_TYPE_IMAGE) ||
1400 ( (p_xkb->display_type == DISP_TYPE_IMAGE_CUST) && (!p_xkb->cust_dir_exists) ) );
1401 if(p_xkb->cust_dir_exists)
1402 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p_radiobutton_disp_type_image_cust), p_xkb->display_type == DISP_TYPE_IMAGE_CUST);
1403 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p_radiobutton_disp_type_text), p_xkb->display_type == DISP_TYPE_TEXT);
1404
1405
1406 // 'PANEL ICON SIZE' frame
1407 GtkWidget * p_frame_flag_size = gtk_frame_new(NULL);
1408 GtkWidget * p_label_flag_size = gtk_label_new(NULL);
1409 snprintf(markup_str, MAX_MARKUP_LEN, "<b>%s</b>", _("Panel Icon Size"));
1410 gtk_label_set_markup(GTK_LABEL(p_label_flag_size), markup_str);
1411 gtk_misc_set_padding(GTK_MISC(p_label_flag_size), 1, 0);
1412 gtk_frame_set_label_widget(GTK_FRAME(p_frame_flag_size), p_label_flag_size);
1413 gtk_frame_set_shadow_type(GTK_FRAME(p_frame_flag_size), GTK_SHADOW_NONE);
59df548f 1414 gtk_box_pack_start(GTK_BOX(p_vbox_right), p_frame_flag_size, TRUE, TRUE, 2);
4496e880
JL
1415 gtk_container_set_border_width(GTK_CONTAINER(p_frame_flag_size), 3);
1416
1417 // frame alignment
1418 GtkWidget * p_alignment_flag_size = gtk_alignment_new(0.5, 0.5, 1, 1);
1419 gtk_container_add(GTK_CONTAINER(p_frame_flag_size), p_alignment_flag_size);
1420 gtk_alignment_set_padding(GTK_ALIGNMENT(p_alignment_flag_size), 4, 4, 10, 10);
1421 GtkWidget *p_hbox_flag_size = gtk_hbox_new(FALSE, 2);
1422 gtk_container_add(GTK_CONTAINER(p_alignment_flag_size), p_hbox_flag_size);
1423
1424 GtkWidget *p_radiobutton_flag_size_1 = gtk_radio_button_new_with_label(NULL, "1");
1425 GtkWidget *p_radiobutton_flag_size_2 = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(p_radiobutton_flag_size_1), "2");
1426 GtkWidget *p_radiobutton_flag_size_3 = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(p_radiobutton_flag_size_1), "3");
1427 GtkWidget *p_radiobutton_flag_size_4 = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(p_radiobutton_flag_size_1), "4");
1428 GtkWidget *p_radiobutton_flag_size_5 = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(p_radiobutton_flag_size_1), "5");
895da737 1429 GtkWidget *p_radiobutton_flag_size_6 = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(p_radiobutton_flag_size_1), "6");
4496e880
JL
1430 g_signal_connect(p_radiobutton_flag_size_1, "toggled", G_CALLBACK(on_radiobutton_flag_size_1_toggled), p_xkb);
1431 g_signal_connect(p_radiobutton_flag_size_2, "toggled", G_CALLBACK(on_radiobutton_flag_size_2_toggled), p_xkb);
1432 g_signal_connect(p_radiobutton_flag_size_3, "toggled", G_CALLBACK(on_radiobutton_flag_size_3_toggled), p_xkb);
1433 g_signal_connect(p_radiobutton_flag_size_4, "toggled", G_CALLBACK(on_radiobutton_flag_size_4_toggled), p_xkb);
1434 g_signal_connect(p_radiobutton_flag_size_5, "toggled", G_CALLBACK(on_radiobutton_flag_size_5_toggled), p_xkb);
895da737 1435 g_signal_connect(p_radiobutton_flag_size_6, "toggled", G_CALLBACK(on_radiobutton_flag_size_6_toggled), p_xkb);
4496e880
JL
1436 gtk_box_pack_start(GTK_BOX(p_hbox_flag_size), p_radiobutton_flag_size_1, TRUE, TRUE, 2);
1437 gtk_box_pack_start(GTK_BOX(p_hbox_flag_size), p_radiobutton_flag_size_2, TRUE, TRUE, 2);
1438 gtk_box_pack_start(GTK_BOX(p_hbox_flag_size), p_radiobutton_flag_size_3, TRUE, TRUE, 2);
1439 gtk_box_pack_start(GTK_BOX(p_hbox_flag_size), p_radiobutton_flag_size_4, TRUE, TRUE, 2);
1440 gtk_box_pack_start(GTK_BOX(p_hbox_flag_size), p_radiobutton_flag_size_5, TRUE, TRUE, 2);
895da737 1441 gtk_box_pack_start(GTK_BOX(p_hbox_flag_size), p_radiobutton_flag_size_6, TRUE, TRUE, 2);
4496e880
JL
1442 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p_radiobutton_flag_size_1), p_xkb->flag_size == 1);
1443 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p_radiobutton_flag_size_2), p_xkb->flag_size == 2);
1444 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p_radiobutton_flag_size_3), p_xkb->flag_size == 3);
1445 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p_radiobutton_flag_size_4), p_xkb->flag_size == 4);
1446 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p_radiobutton_flag_size_5), p_xkb->flag_size == 5);
895da737 1447 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p_radiobutton_flag_size_6), p_xkb->flag_size == 6);
22242ed4 1448
d862b520 1449 /* Connect signals. */
4496e880 1450 g_signal_connect(p_xkb->p_dialog_config, "response", G_CALLBACK(on_dialog_config_response), p_xkb);
22242ed4 1451
d862b520 1452 /* Display the dialog. */
4496e880
JL
1453 gtk_widget_show_all(p_xkb->p_dialog_config);
1454 gtk_window_present(GTK_WINDOW(p_xkb->p_dialog_config));
1455
1456 user_active = TRUE;
22242ed4
HJYP
1457}
1458
8f9e6256 1459/* Callback when the configuration is to be saved. */
1460static void xkb_save_configuration(Plugin * p, FILE * fp)
1461{
4496e880
JL
1462 XkbPlugin * p_xkb = (XkbPlugin *)p->priv;
1463 lxpanel_put_int(fp, "DisplayType", p_xkb->display_type);
895da737 1464 lxpanel_put_int(fp, "PerWinLayout", p_xkb->enable_perwin);
876e3dd1 1465 lxpanel_put_int(fp, "NoResetOpt", p_xkb->do_not_reset_opt);
b3d38a01 1466 lxpanel_put_int(fp, "KeepSysLayouts", p_xkb->keep_system_layouts);
4496e880
JL
1467 lxpanel_put_str(fp, "Model", p_xkb->kbd_model);
1468 lxpanel_put_str(fp, "LayoutsList", p_xkb->kbd_layouts);
1469 lxpanel_put_str(fp, "VariantsList", p_xkb->kbd_variants);
1470 lxpanel_put_str(fp, "ToggleOpt", p_xkb->kbd_change_option);
f8918f4a 1471 lxpanel_put_str(fp, "AdvancedOpt", p_xkb->kbd_advanced_options);
4496e880 1472 lxpanel_put_int(fp, "FlagSize", p_xkb->flag_size);
8f9e6256 1473}
1474
1475/* Callback when panel configuration changes. */
1476static void xkb_panel_configuration_changed(Plugin * p)
1477{
1478 /* Do a full redraw. */
4496e880
JL
1479 XkbPlugin * p_xkb = (XkbPlugin *)p->priv;
1480 xkb_redraw(p_xkb);
8f9e6256 1481}
22242ed4 1482
d862b520 1483/* Plugin descriptor. */
22242ed4 1484PluginClass xkb_plugin_class = {
2918994e 1485
1486 PLUGINCLASS_VERSIONING,
22242ed4
HJYP
1487
1488 type : "xkb",
4496e880
JL
1489 name : N_("Keyboard Layout Handler"),
1490 version: "2.0",
1491 description : N_("Handle keyboard layouts"),
22242ed4
HJYP
1492
1493 constructor : xkb_constructor,
1494 destructor : xkb_destructor,
8f9e6256 1495 config : xkb_configure,
1496 save : xkb_save_configuration,
1497 panel_configuration_changed : xkb_panel_configuration_changed
d862b520 1498
22242ed4 1499};