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