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