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