Merge branch 'use-libfm'
[lxde/lxpanel.git] / src / plugins / xkb / xkb-plugin.c
index 4b1466f..411c155 100644 (file)
@@ -51,38 +51,44 @@ enum
 
 enum
 {
-    COLUMN_MODEL_NAME,
+    COLUMN_MODEL_ID,
     COLUMN_MODEL_DESC,
     NUM_MODEL_COLUMNS
 };
 
 enum
 {
-    COLUMN_CHANGE_NAME,
+    COLUMN_CHANGE_ID,
     COLUMN_CHANGE_DESC,
+    COLUMN_CHANGE_INCL,
+    COLUMN_CHANGE_WEIGHT,
     NUM_CHANGE_COLUMNS
 };
 
-void panel_config_save(Panel * panel);   /* defined in configurator.c */
-
 static int   xkb_constructor(Plugin * p_plugin, char ** fp);
 static void  xkb_destructor(Plugin * p_plugin);
 static void  xkb_configure(Plugin * p, GtkWindow * parent);
 static void  xkb_save_configuration(Plugin * p, FILE * fp);
 static void  xkb_panel_configuration_changed(Plugin * p);
 static void  xkb_settings_fill_layout_tree_model_with_config(XkbPlugin *p_xkb);
-static void  xkb_setxkbmap(XkbPlugin *p_xkb);
 static void  xkb_update_layouts_n_variants(XkbPlugin *p_xkb);
 static void  xkb_add_layout(XkbPlugin *p_xkb, gchar *layout, gchar*variant);
 static int   xkb_get_flag_size(XkbPlugin *p_xkb);
 
+static void      on_xkb_fbev_active_window_event(FbEv *ev, gpointer p_data);
 static gboolean  on_xkb_button_scroll_event(GtkWidget * widget, GdkEventScroll * event, gpointer p_data);
 static gboolean  on_xkb_button_press_event(GtkWidget * widget,  GdkEventButton * event, gpointer p_data);
 static void      on_radiobutton_disp_type_image_toggled(GtkToggleButton *p_radiobutton, gpointer p_data);
 static void      on_radiobutton_disp_type_image_cust_toggled(GtkToggleButton *p_radiobutton, gpointer p_data);
 static void      on_radiobutton_disp_type_text_toggled(GtkToggleButton *p_radiobutton, gpointer p_data);
-static void      on_hscale_flag_size_value_changed(GtkRange *p_range, gpointer p_data);
+static void      on_xkb_checkbutton_per_app_toggled(GtkToggleButton *tb, gpointer p_data);
+static void      on_xkb_checkbutton_no_reset_opt_toggled(GtkToggleButton *tb, gpointer p_data);
+static void      on_xkb_checkbutton_keep_system_layouts_toggled(GtkToggleButton *tb, gpointer p_data);
 static void      on_dialog_config_response(GtkDialog *p_dialog, gint response, gpointer p_data);
+static void      on_xkb_entry_advanced_opt_icon_press(GtkEntry             *p_entry,
+                                                      GtkEntryIconPosition  icon_pos,
+                                                      GdkEvent             *p_event,
+                                                      gpointer              p_data);
 
 static unsigned char  user_active = FALSE;
 static const gchar    flag_filepath_generator[] = "%s/%s.png";
@@ -96,9 +102,10 @@ static int xkb_get_flag_size(XkbPlugin *p_xkb)
         case 2: return size*0.6;
         case 3: return size*0.7;
         case 4: return size*0.8;
+        case 5: return size*0.9;
         default: break;
     }
-    return size*0.9;
+    return size;
 }
 
 /* Redraw the graphics. */
@@ -156,10 +163,8 @@ void xkb_redraw(XkbPlugin *p_xkb)
         char *group_name = (char *)xkb_get_current_symbol_name(p_xkb);
         if (group_name != NULL)
         {
-            GString *p_gstring_markup = g_string_new("");
-            g_string_printf(p_gstring_markup, "<span font='%u' weight='heavy'>%s</span>", size/2, group_name);
-            gtk_label_set_markup(GTK_LABEL(p_xkb->p_label), p_gstring_markup->str);
-            g_string_free(p_gstring_markup, TRUE/*free also gstring->str*/);
+            panel_draw_label_text(p_xkb->p_plugin->panel, p_xkb->p_label, group_name,
+                    TRUE, size*4/(5*10.0), TRUE);
             gtk_widget_hide(p_xkb->p_image);
             gtk_widget_show(p_xkb->p_label);
             gtk_widget_set_tooltip_text(p_xkb->p_plugin->pwid, xkb_get_current_group_name(p_xkb));
@@ -167,6 +172,21 @@ void xkb_redraw(XkbPlugin *p_xkb)
     }
 }
 
+/* Handler for "active_window" event on root window listener. */
+static void on_xkb_fbev_active_window_event(FbEv * ev, gpointer p_data) 
+{
+    XkbPlugin * xkb = (XkbPlugin *)p_data;
+    if (xkb->enable_perwin)
+    {
+        Window * win = fb_ev_active_window(ev);
+        if (*win != None)
+        {
+            xkb_active_window_changed(xkb, *win);
+            xkb_redraw(xkb);
+        }
+    }
+}
+
 /* Handler for "scroll-event" on drawing area. */
 static gboolean on_xkb_button_scroll_event(GtkWidget * widget, GdkEventScroll * event, gpointer p_data)
 {
@@ -192,6 +212,17 @@ static gboolean on_xkb_button_press_event(GtkWidget * widget,  GdkEventButton *
     return TRUE;
 }
 
+static void on_xkb_entry_advanced_opt_icon_press(GtkEntry             *p_entry,
+                                                 GtkEntryIconPosition  icon_pos,
+                                                 GdkEvent             *p_event,
+                                                 gpointer              p_data)
+{
+    XkbPlugin *p_xkb = (XkbPlugin *)p_data;
+    g_free(p_xkb->kbd_advanced_options);
+    p_xkb->kbd_advanced_options = g_strdup(gtk_entry_get_text(p_entry));
+    xkb_setxkbmap(p_xkb);
+}
+
 /* Plugin constructor. */
 static int xkb_constructor(Plugin * p_plugin, char ** fp)
 {
@@ -202,10 +233,14 @@ static int xkb_constructor(Plugin * p_plugin, char ** fp)
 
     /* Initialize to defaults. */
     p_xkb->display_type = DISP_TYPE_IMAGE;
+    p_xkb->enable_perwin = FALSE;
+    p_xkb->do_not_reset_opt = FALSE;
+    p_xkb->keep_system_layouts = TRUE;
     p_xkb->kbd_model = NULL;
     p_xkb->kbd_layouts = NULL;
     p_xkb->kbd_variants = NULL;
     p_xkb->kbd_change_option = NULL;
+    p_xkb->kbd_advanced_options = NULL;
     p_xkb->flag_size = 3;
     p_xkb->cust_dir_exists = g_file_test(FLAGSCUSTDIR,  G_FILE_TEST_IS_DIR);
 
@@ -227,6 +262,18 @@ static int xkb_constructor(Plugin * p_plugin, char ** fp)
                 {
                     p_xkb->display_type = atoi(s.t[1]);
                 }
+                else if(g_ascii_strcasecmp(s.t[0], "PerWinLayout") == 0)
+                {
+                    p_xkb->enable_perwin = str2num(bool_pair, s.t[1], 0);
+                }
+                else if(g_ascii_strcasecmp(s.t[0], "NoResetOpt") == 0)
+                {
+                    p_xkb->do_not_reset_opt = str2num(bool_pair, s.t[1], 0);
+                }
+                else if(g_ascii_strcasecmp(s.t[0], "KeepSysLayouts") == 0)
+                {
+                    p_xkb->keep_system_layouts = str2num(bool_pair, s.t[1], 0);
+                }
                 else if(g_ascii_strcasecmp(s.t[0], "Model") == 0)
                 {
                     p_xkb->kbd_model = g_strdup(s.t[1]);
@@ -243,6 +290,10 @@ static int xkb_constructor(Plugin * p_plugin, char ** fp)
                 {
                     p_xkb->kbd_change_option = g_strdup(s.t[1]);
                 }
+                else if(g_ascii_strcasecmp(s.t[0], "AdvancedOpt") == 0)
+                {
+                    p_xkb->kbd_advanced_options = g_strdup(s.t[1]);
+                }
                 else if(g_ascii_strcasecmp(s.t[0], "FlagSize") == 0)
                 {
                     p_xkb->flag_size = atoi(s.t[1]);
@@ -257,71 +308,6 @@ static int xkb_constructor(Plugin * p_plugin, char ** fp)
             }
         }
     }
-    
-    if( (p_xkb->kbd_model == NULL) || (p_xkb->kbd_layouts == NULL) ||
-        (p_xkb->kbd_variants == NULL) || (p_xkb->kbd_change_option == NULL) )
-    {
-        if(p_xkb->kbd_model != NULL) g_free(p_xkb->kbd_model);
-        if(p_xkb->kbd_layouts != NULL) g_free(p_xkb->kbd_layouts);
-        if(p_xkb->kbd_variants != NULL) g_free(p_xkb->kbd_variants);
-        if(p_xkb->kbd_change_option != NULL) g_free(p_xkb->kbd_change_option);
-        
-        FILE *fp;
-        char  buf[MAX_ROW_LEN];
-        fp = popen("setxkbmap -query", "r");
-        if(fp != NULL)
-        {
-            GRegex *p_regex_model = g_regex_new("(?<=model:).*", 0, 0, NULL);
-            GRegex *p_regex_layouts = g_regex_new("(?<=layout:).*", 0, 0, NULL);
-            GRegex *p_regex_variants = g_regex_new("(?<=variant:).*", 0, 0, NULL);
-            GMatchInfo *p_match_info;
-            while(fgets(buf, MAX_ROW_LEN, fp) != NULL)
-            {
-                // model
-                g_regex_match(p_regex_model, buf, 0, &p_match_info);
-                if(g_match_info_matches(p_match_info))
-                {
-                    p_xkb->kbd_model = g_strchug(g_match_info_fetch(p_match_info, 0));
-                    g_match_info_free(p_match_info);
-                    continue;
-                }
-                g_match_info_free(p_match_info);
-                
-                // layouts
-                g_regex_match(p_regex_layouts, buf, 0, &p_match_info);
-                if(g_match_info_matches(p_match_info))
-                {
-                    p_xkb->kbd_layouts = g_strchug(g_match_info_fetch(p_match_info, 0));
-                    g_match_info_free(p_match_info);
-                    continue;
-                }
-                g_match_info_free(p_match_info);
-                
-                // variants
-                g_regex_match(p_regex_variants, buf, 0, &p_match_info);
-                if(g_match_info_matches(p_match_info))
-                {
-                    p_xkb->kbd_variants = g_strchug(g_match_info_fetch(p_match_info, 0));
-                    g_match_info_free(p_match_info);
-                    continue;
-                }
-                g_match_info_free(p_match_info);
-            }
-            
-            g_regex_unref(p_regex_model);
-            g_regex_unref(p_regex_layouts);
-            g_regex_unref(p_regex_variants);
-            
-            /* close */
-            pclose(fp);
-        }
-        if(p_xkb->kbd_model == NULL) p_xkb->kbd_model = g_strdup("pc105");
-        if(p_xkb->kbd_layouts == NULL) p_xkb->kbd_layouts = g_strdup("us");
-        if(p_xkb->kbd_variants == NULL) p_xkb->kbd_variants = g_strdup(",");
-        if(p_xkb->kbd_change_option == NULL) p_xkb->kbd_change_option = g_strdup("shift_caps_toggle");
-    }
-    else
-        xkb_setxkbmap(p_xkb);
 
     /* Allocate top level widget and set into Plugin widget pointer. */
     p_plugin->pwid = gtk_event_box_new();
@@ -329,7 +315,7 @@ static int xkb_constructor(Plugin * p_plugin, char ** fp)
 
     /* Create a horizontal box as the child of the button. */
     GtkWidget * hbox = gtk_hbox_new(FALSE, 0);
-    gtk_container_set_border_width(GTK_CONTAINER(hbox), 1);
+    gtk_container_set_border_width(GTK_CONTAINER(hbox), 3);
     gtk_container_add(GTK_CONTAINER(p_xkb->p_plugin->pwid), hbox);
     gtk_widget_show(hbox);
 
@@ -341,12 +327,36 @@ static int xkb_constructor(Plugin * p_plugin, char ** fp)
     p_xkb->p_image = gtk_image_new();
     gtk_container_add(GTK_CONTAINER(hbox), p_xkb->p_image);
 
+    /* Chech for first run */
+    if( (p_xkb->kbd_model == NULL) || (p_xkb->kbd_layouts == NULL) ||
+        (p_xkb->kbd_variants == NULL) || (p_xkb->kbd_change_option == NULL) )
+    {
+        /* This is a first run, read the current layout */
+        xkb_mechanism_constructor(p_xkb);
+        
+        if(p_xkb->kbd_model != NULL) g_free(p_xkb->kbd_model);
+        if(p_xkb->kbd_layouts != NULL) g_free(p_xkb->kbd_layouts);
+        if(p_xkb->kbd_variants != NULL) g_free(p_xkb->kbd_variants);
+        if(p_xkb->kbd_change_option != NULL) g_free(p_xkb->kbd_change_option);
+        
+        p_xkb->kbd_model = g_strdup("pc105");
+        gchar *symbol_name_lowercase = (char *)xkb_get_current_symbol_name_lowercase(p_xkb);
+        p_xkb->kbd_layouts = g_strdup(symbol_name_lowercase);
+        g_free(symbol_name_lowercase);
+        p_xkb->kbd_variants = g_strdup(",");
+        p_xkb->kbd_change_option = g_strdup("grp:shift_caps_toggle");
+        
+        xkb_mechanism_destructor(p_xkb);
+    }
+    
     /* Initialize the XKB interface. */
+    xkb_setxkbmap(p_xkb);
     xkb_mechanism_constructor(p_xkb);
 
     /* Connect signals. */
     g_signal_connect(p_plugin->pwid, "button-press-event", G_CALLBACK(on_xkb_button_press_event), p_xkb);
     g_signal_connect(p_plugin->pwid, "scroll-event", G_CALLBACK(on_xkb_button_scroll_event), p_xkb);
+    g_signal_connect(G_OBJECT(fbev), "active_window", G_CALLBACK(on_xkb_fbev_active_window_event), p_xkb);
 
     /* Show the widget and return. */
     xkb_redraw(p_xkb);
@@ -359,6 +369,9 @@ static void xkb_destructor(Plugin * p_plugin)
 {
     XkbPlugin *p_xkb = (XkbPlugin *)p_plugin->priv;
 
+    /* Disconnect root window event handler. */
+    g_signal_handlers_disconnect_by_func(G_OBJECT(fbev), on_xkb_fbev_active_window_event, p_xkb);
+
     /* Disconnect from the XKB mechanism. */
     g_source_remove(p_xkb->source_id);
     xkb_mechanism_destructor(p_xkb);
@@ -372,9 +385,77 @@ static void xkb_destructor(Plugin * p_plugin)
     g_free(p_xkb->kbd_layouts);
     g_free(p_xkb->kbd_variants);
     g_free(p_xkb->kbd_change_option);
+    g_free(p_xkb->kbd_advanced_options);
     g_free(p_xkb);
 }
 
+/* Handler for "toggled" event on per-application check box of configuration dialog. */
+static void on_xkb_checkbutton_per_app_toggled(GtkToggleButton *tb, gpointer p_data) 
+{
+    if(user_active == TRUE)
+    {
+        /* Fetch the new value and redraw. */
+        XkbPlugin * xkb = (XkbPlugin *)p_data;
+        xkb->enable_perwin = gtk_toggle_button_get_active(tb);
+        if(!xkb->enable_perwin)
+        {
+            /* at deactivation clear the hash table */
+            if(xkb->p_hash_table_group != NULL)
+                g_hash_table_destroy(xkb->p_hash_table_group);
+            xkb->p_hash_table_group = g_hash_table_new(g_direct_hash, NULL);
+        }
+        xkb_redraw(xkb);
+    }
+}
+
+/* Handler for "toggled" event on no reset options check box of configuration dialog. */
+static void on_xkb_checkbutton_no_reset_opt_toggled(GtkToggleButton *tb, gpointer p_data)
+{
+    if(user_active == TRUE)
+    {
+        /* Fetch the new value and redraw. */
+        XkbPlugin * xkb = (XkbPlugin *)p_data;
+        xkb->do_not_reset_opt = gtk_toggle_button_get_active(tb);
+        xkb_redraw(xkb);
+    }
+}
+
+/* Handler for "toggled" event on keep system layouts check box of configuration dialog. */
+static void on_xkb_checkbutton_keep_system_layouts_toggled(GtkToggleButton *tb, gpointer p_data)
+{
+    if(user_active == TRUE)
+    {
+        /* Fetch the new value and redraw. */
+        XkbPlugin * p_xkb = (XkbPlugin *)p_data;
+        p_xkb->keep_system_layouts = gtk_toggle_button_get_active(tb);
+        xkb_redraw(p_xkb);
+        
+        gtk_widget_set_sensitive(p_xkb->p_frame_kbd_model, !p_xkb->keep_system_layouts);
+        gtk_widget_set_sensitive(p_xkb->p_frame_kbd_layouts, !p_xkb->keep_system_layouts);
+        gtk_widget_set_sensitive(p_xkb->p_frame_change_layout, !p_xkb->keep_system_layouts);
+        gtk_widget_set_sensitive(p_xkb->p_entry_advanced_opt, !p_xkb->keep_system_layouts);
+        gtk_widget_set_sensitive(p_xkb->p_checkbutton_no_reset_opt, !p_xkb->keep_system_layouts);
+        
+        if(!p_xkb->keep_system_layouts)
+        {
+            gtk_entry_set_icon_from_stock(GTK_ENTRY(p_xkb->p_entry_advanced_opt), GTK_ENTRY_ICON_SECONDARY, "gtk-save");
+            xkb_update_layouts_n_variants(p_xkb);
+        }
+        else
+        {
+            GtkWidget *dialog;
+            dialog = gtk_message_dialog_new(GTK_WINDOW(p_xkb->p_dialog_config),
+                                            GTK_DIALOG_DESTROY_WITH_PARENT,
+                                            GTK_MESSAGE_WARNING,
+                                            GTK_BUTTONS_OK,
+                                            _("New session is required for this option to take effect"));
+            gtk_window_set_title(GTK_WINDOW(dialog), "Warning");
+            gtk_dialog_run(GTK_DIALOG(dialog));
+            gtk_widget_destroy(dialog);
+        }
+    }
+}
+
 static void on_radiobutton_flag_size_1_toggled(GtkToggleButton *p_radiobutton, gpointer p_data)
 {
     if( (user_active == TRUE) && gtk_toggle_button_get_active(p_radiobutton) )
@@ -425,6 +506,16 @@ static void on_radiobutton_flag_size_5_toggled(GtkToggleButton *p_radiobutton, g
     }
 }
 
+static void on_radiobutton_flag_size_6_toggled(GtkToggleButton *p_radiobutton, gpointer p_data)
+{
+    if( (user_active == TRUE) && gtk_toggle_button_get_active(p_radiobutton) )
+    {
+        XkbPlugin * p_xkb = (XkbPlugin *)p_data;
+        p_xkb->flag_size = 6;
+        xkb_redraw(p_xkb);
+    }
+}
+
 /* Handler for "toggled" event on display type image radiobutton of configuration dialog. */
 static void on_radiobutton_disp_type_image_toggled(GtkToggleButton *p_radiobutton, gpointer p_data)
 {
@@ -475,9 +566,58 @@ static void on_dialog_config_response(GtkDialog *p_dialog, gint response, gpoint
     p_xkb->p_dialog_config = NULL;
 }
 
-static void on_hscale_flag_size_value_changed(GtkRange *p_range, gpointer p_data)
+static void  on_cell_renderer_layout_change_incl_toggled(GtkCellRendererToggle *cell,
+                                                        gchar                 *path_str,
+                                                        gpointer               data)
 {
+    GtkTreeModel *p_model = (GtkTreeModel *)data;
+    GtkTreeIter  tree_iter;
+    GtkTreePath *p_tree_path = gtk_tree_path_new_from_string(path_str);
+    gboolean     included;
     
+    /* get toggled iter */
+    gtk_tree_model_get_iter(p_model, &tree_iter, p_tree_path);
+    gtk_tree_model_get(p_model, &tree_iter, COLUMN_CHANGE_INCL, &included, -1);
+    
+    /* do something with the value */
+    included = !included;
+    
+    /* set new value */
+    gtk_list_store_set(GTK_LIST_STORE(p_model), &tree_iter, COLUMN_CHANGE_INCL, included, -1);
+    gtk_list_store_set(GTK_LIST_STORE(p_model), &tree_iter, COLUMN_CHANGE_WEIGHT, included ? PANGO_WEIGHT_ULTRAHEAVY : PANGO_WEIGHT_NORMAL, -1);
+    
+    /* clean up */
+    gtk_tree_path_free(p_tree_path);
+}
+
+static gboolean  on_treeviews_lists_button_press_event(GtkWidget *p_widget,
+                                                       GdkEventButton *p_event,
+                                                       gpointer p_data)
+{
+    if(p_event->button == 1)
+    {
+        if(p_event->type == GDK_2BUTTON_PRESS)
+        {
+            GtkButton *p_button_ok = (GtkButton *)p_data;
+            gtk_button_clicked(p_button_ok);
+        }
+    }
+    else if(p_event->button == 2)
+    {
+        GtkTreePath  *p_tree_path;
+        if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(p_widget),
+                                         p_event->x, p_event->y,
+                                         &p_tree_path,
+                                         NULL, NULL, NULL))
+        {
+            if(gtk_tree_view_row_expanded(GTK_TREE_VIEW(p_widget), p_tree_path))
+                gtk_tree_view_collapse_row(GTK_TREE_VIEW(p_widget), p_tree_path);
+            else
+                gtk_tree_view_expand_row(GTK_TREE_VIEW(p_widget), p_tree_path, FALSE);
+            gtk_tree_path_free(p_tree_path);
+        }
+    }
+    return FALSE;
 }
 
 static void on_button_kbd_model_clicked(GtkButton *p_button, gpointer *p_data)
@@ -506,15 +646,18 @@ static void on_button_kbd_model_clicked(GtkButton *p_button, gpointer *p_data)
     gtk_container_add(GTK_CONTAINER(p_scrolledwindow_kbd_model), p_treeview_kbd_model);
     GtkCellRenderer *p_renderer;
     GtkTreeViewColumn *p_column;
-    // model
+    // model desc
     p_renderer = gtk_cell_renderer_text_new();
-    p_column = gtk_tree_view_column_new_with_attributes(_("Model"), p_renderer, "text", COLUMN_CHANGE_NAME, NULL);
+    p_column = gtk_tree_view_column_new_with_attributes(_("Description"), p_renderer, "text", COLUMN_MODEL_DESC, NULL);
+    gtk_tree_view_column_set_sort_column_id(p_column, COLUMN_MODEL_DESC);
     gtk_tree_view_append_column(GTK_TREE_VIEW(p_treeview_kbd_model), p_column);
-    // desc
+    // model id
     p_renderer = gtk_cell_renderer_text_new();
-    p_column = gtk_tree_view_column_new_with_attributes(_("Description"), p_renderer, "text", COLUMN_CHANGE_DESC, NULL);
+    p_column = gtk_tree_view_column_new_with_attributes(_("Id"), p_renderer, "text", COLUMN_MODEL_ID, NULL);
+    gtk_tree_view_column_set_sort_column_id(p_column, COLUMN_MODEL_ID);
     gtk_tree_view_append_column(GTK_TREE_VIEW(p_treeview_kbd_model), p_column);
     
+    
     // populate model
     GKeyFile *p_keyfile = g_key_file_new();
     gchar *xkbcfg_filepath = g_strdup_printf("%s/models.cfg", XKBCONFDIR);
@@ -529,7 +672,7 @@ static void on_button_kbd_model_clicked(GtkButton *p_button, gpointer *p_data)
             p_model_desc = g_key_file_get_string(p_keyfile, "MODELS", keys_models[model_idx], NULL);
             gtk_list_store_append(p_liststore_kbd_model, &tree_iter);
             gtk_list_store_set(p_liststore_kbd_model, &tree_iter,
-                                COLUMN_MODEL_NAME, keys_models[model_idx],
+                                COLUMN_MODEL_ID, keys_models[model_idx],
                                 COLUMN_MODEL_DESC, p_model_desc,
                                 -1);
             g_free(p_model_desc);
@@ -541,23 +684,13 @@ static void on_button_kbd_model_clicked(GtkButton *p_button, gpointer *p_data)
     g_free(xkbcfg_filepath);
     
     // callback for double click
-    gboolean  on_treeview_kbd_model_button_press_event(GtkWidget *p_widget,
-                                                       GdkEventButton *p_event,
-                                                       gpointer p_data)
-    {
-        if(p_event->button == 1)
-        {
-            if(p_event->type == GDK_2BUTTON_PRESS)
-            {
-                GtkButton *p_button_ok = (GtkButton *)gtk_dialog_get_widget_for_response(GTK_DIALOG(p_dialog), GTK_RESPONSE_OK);
-                gtk_button_clicked(p_button_ok);
-            }
-        }
-        return FALSE;
-    }
     g_signal_connect(p_treeview_kbd_model, "button-press-event",
-                     G_CALLBACK(on_treeview_kbd_model_button_press_event), NULL);
-    gtk_widget_set_size_request(p_dialog, 600, 500);
+                     G_CALLBACK(on_treeviews_lists_button_press_event),
+                     gtk_dialog_get_widget_for_response(GTK_DIALOG(p_dialog), GTK_RESPONSE_OK));
+    // sort for description
+    gtk_tree_view_column_clicked(p_column);
+    
+    gtk_widget_set_size_request(p_dialog, 700, 500);
     gtk_widget_show_all(GTK_WIDGET(p_scrolledwindow_kbd_model));
     gint  response = gtk_dialog_run(GTK_DIALOG(p_dialog));
     if(response == GTK_RESPONSE_OK)
@@ -570,7 +703,7 @@ static void on_button_kbd_model_clicked(GtkButton *p_button, gpointer *p_data)
         {
             gchar *kbd_model_new;
             gtk_tree_model_get(GTK_TREE_MODEL(p_liststore_kbd_model),
-                               &tree_iter_sel, COLUMN_MODEL_NAME, &kbd_model_new, -1);
+                               &tree_iter_sel, COLUMN_MODEL_ID, &kbd_model_new, -1);
             g_free(p_xkb->kbd_model);
             p_xkb->kbd_model = g_strdup(kbd_model_new);
             gtk_button_set_label(GTK_BUTTON(p_xkb->p_button_kbd_model), p_xkb->kbd_model);
@@ -582,6 +715,33 @@ static void on_button_kbd_model_clicked(GtkButton *p_button, gpointer *p_data)
     gtk_widget_destroy(p_dialog);
 }
 
+static gboolean  change_opt_tree_model_foreach(GtkTreeModel *p_model,
+                                               GtkTreePath *p_path,
+                                               GtkTreeIter *p_iter,
+                                               gpointer p_data)
+{
+    XkbPlugin *p_xkb = (XkbPlugin *)p_data;
+    
+    gboolean  included;
+    
+    gtk_tree_model_get(p_model, p_iter, COLUMN_CHANGE_INCL, &included,  -1);
+    if(included)
+    {
+        gchar  *change_opt_id;
+        gtk_tree_model_get(p_model, p_iter, COLUMN_CHANGE_ID, &change_opt_id,  -1);
+        if(strlen(p_xkb->p_gstring_change_opt_partial->str))
+        {
+            g_string_append_c(p_xkb->p_gstring_change_opt_partial, ',');
+        }
+        g_string_append(p_xkb->p_gstring_change_opt_partial, change_opt_id);
+        
+        //g_printf("\npartial change opt = '%s'\n", p_xkb->p_gstring_change_opt_partial->str);
+        
+        g_free(change_opt_id);
+    }
+    return FALSE;
+}
+
 static void on_button_kbd_change_layout_clicked(GtkButton *p_button, gpointer *p_data)
 {
     XkbPlugin *p_xkb = (XkbPlugin *)p_data;
@@ -601,20 +761,31 @@ static void on_button_kbd_change_layout_clicked(GtkButton *p_button, gpointer *p
     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(p_dialog)->vbox), p_scrolledwindow_kbd_change, TRUE, TRUE, 2);
     
     // liststore
-    GtkListStore *p_liststore_kbd_change = gtk_list_store_new(NUM_CHANGE_COLUMNS, G_TYPE_STRING, G_TYPE_STRING);
+    GtkListStore *p_liststore_kbd_change = gtk_list_store_new(NUM_CHANGE_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_INT);
     GtkWidget *p_treeview_kbd_change = gtk_tree_view_new_with_model(GTK_TREE_MODEL(p_liststore_kbd_change));
     g_object_unref(G_OBJECT(p_liststore_kbd_change));
     gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(p_treeview_kbd_change), TRUE);
     gtk_container_add(GTK_CONTAINER(p_scrolledwindow_kbd_change), p_treeview_kbd_change);
     GtkCellRenderer *p_renderer;
     GtkTreeViewColumn *p_column;
-    // model
+    // change included
+    p_renderer = gtk_cell_renderer_toggle_new();
+    g_signal_connect(p_renderer, "toggled", G_CALLBACK(on_cell_renderer_layout_change_incl_toggled), p_liststore_kbd_change);
+    p_column = gtk_tree_view_column_new_with_attributes("", p_renderer, "active", COLUMN_CHANGE_INCL, NULL);
+    gtk_tree_view_append_column(GTK_TREE_VIEW(p_treeview_kbd_change), p_column);
+    // change desc
     p_renderer = gtk_cell_renderer_text_new();
-    p_column = gtk_tree_view_column_new_with_attributes(_("Change Type"), p_renderer, "text", COLUMN_CHANGE_NAME, NULL);
+    p_column = gtk_tree_view_column_new_with_attributes(_("Description"), p_renderer, "text", COLUMN_CHANGE_DESC,
+                                                                                      "weight", COLUMN_CHANGE_WEIGHT,
+                                                                                      NULL);
+    gtk_tree_view_column_set_sort_column_id(p_column, COLUMN_CHANGE_DESC);
     gtk_tree_view_append_column(GTK_TREE_VIEW(p_treeview_kbd_change), p_column);
-    // desc
+    // change id
     p_renderer = gtk_cell_renderer_text_new();
-    p_column = gtk_tree_view_column_new_with_attributes(_("Description"), p_renderer, "text", COLUMN_CHANGE_DESC, NULL);
+    p_column = gtk_tree_view_column_new_with_attributes(_("Id"), p_renderer, "text", COLUMN_CHANGE_ID,
+                                                                             "weight", COLUMN_CHANGE_WEIGHT,
+                                                                             NULL);
+    gtk_tree_view_column_set_sort_column_id(p_column, COLUMN_CHANGE_ID);
     gtk_tree_view_append_column(GTK_TREE_VIEW(p_treeview_kbd_change), p_column);
     
     // populate model
@@ -622,6 +793,8 @@ static void on_button_kbd_change_layout_clicked(GtkButton *p_button, gpointer *p
     gchar *xkbcfg_filepath = g_strdup_printf("%s/toggle.cfg", XKBCONFDIR);
     if(g_key_file_load_from_file(p_keyfile, xkbcfg_filepath, 0, NULL))
     {
+        char **change_opts = g_strsplit_set(p_xkb->kbd_change_option, ",", 0);
+        int    num_change_opts;
         gchar **keys_changes = g_key_file_get_keys(p_keyfile, "TOGGLE", NULL, NULL);
         guint   change_idx = 0;
         GtkTreeIter  tree_iter;
@@ -630,56 +803,56 @@ static void on_button_kbd_change_layout_clicked(GtkButton *p_button, gpointer *p
         {
             p_change_desc = g_key_file_get_string(p_keyfile, "TOGGLE", keys_changes[change_idx], NULL);
             gtk_list_store_append(p_liststore_kbd_change, &tree_iter);
+            gboolean  included = FALSE;
+            num_change_opts = 0;
+            while(change_opts[num_change_opts] != NULL)
+            {
+                if(strcmp(change_opts[num_change_opts], keys_changes[change_idx]) == 0)
+                {
+                    included = TRUE;
+                    break;
+                }
+                num_change_opts++;
+            }
             gtk_list_store_set(p_liststore_kbd_change, &tree_iter,
-                                COLUMN_CHANGE_NAME, keys_changes[change_idx],
+                                COLUMN_CHANGE_ID, keys_changes[change_idx],
                                 COLUMN_CHANGE_DESC, p_change_desc,
+                                COLUMN_CHANGE_INCL, included,
+                                COLUMN_CHANGE_WEIGHT, included ? PANGO_WEIGHT_ULTRAHEAVY : PANGO_WEIGHT_NORMAL,
                                 -1);
             g_free(p_change_desc);
             change_idx++;
         }
         g_strfreev(keys_changes);
         g_key_file_free(p_keyfile);
+        g_strfreev(change_opts);
     }
     g_free(xkbcfg_filepath);
     
     // callback for double click
-    gboolean  on_treeview_kbd_change_button_press_event(GtkWidget *p_widget,
-                                                        GdkEventButton *p_event,
-                                                        gpointer p_data)
-    {
-        if(p_event->button == 1)
-        {
-            if(p_event->type == GDK_2BUTTON_PRESS)
-            {
-                GtkButton *p_button_ok = (GtkButton *)gtk_dialog_get_widget_for_response(GTK_DIALOG(p_dialog), GTK_RESPONSE_OK);
-                gtk_button_clicked(p_button_ok);
-            }
-        }
-        return FALSE;
-    }
-    g_signal_connect(p_treeview_kbd_change, "button-press-event",
-                     G_CALLBACK(on_treeview_kbd_change_button_press_event), NULL);
-    gtk_widget_set_size_request(p_dialog, 600, 500);
+    //g_signal_connect(p_treeview_kbd_change, "button-press-event",
+                     //G_CALLBACK(on_treeviews_lists_button_press_event),
+                     //gtk_dialog_get_widget_for_response(GTK_DIALOG(p_dialog), GTK_RESPONSE_OK));
+    gtk_widget_set_size_request(p_dialog, 700, 500);
     gtk_widget_show_all(GTK_WIDGET(p_scrolledwindow_kbd_change));
     gint  response = gtk_dialog_run(GTK_DIALOG(p_dialog));
     if(response == GTK_RESPONSE_OK)
     {
-        GtkTreeIter  tree_iter_sel;
-        GtkTreeSelection *p_treeselection_kbd_change = gtk_tree_view_get_selection(GTK_TREE_VIEW(p_treeview_kbd_change));
-        if(gtk_tree_selection_get_selected(p_treeselection_kbd_change,
-                                           (GtkTreeModel **)(&p_liststore_kbd_change),
-                                           &tree_iter_sel))
+        p_xkb->p_gstring_change_opt_partial = g_string_new("");
+        gtk_tree_model_foreach(GTK_TREE_MODEL(p_liststore_kbd_change),
+                               change_opt_tree_model_foreach,
+                               p_xkb);
+        if(!strlen(p_xkb->p_gstring_change_opt_partial->str))
         {
-            gchar *kbd_change_new;
-            gtk_tree_model_get(GTK_TREE_MODEL(p_liststore_kbd_change),
-                               &tree_iter_sel, COLUMN_CHANGE_NAME, &kbd_change_new, -1);
-            g_free(p_xkb->kbd_change_option);
-            p_xkb->kbd_change_option = g_strdup(kbd_change_new);
-            gtk_button_set_label(GTK_BUTTON(p_xkb->p_button_change_layout), p_xkb->kbd_change_option);
-            g_free(kbd_change_new);
-            xkb_setxkbmap(p_xkb);
-            xkb_redraw(p_xkb);
+            g_string_append_c(p_xkb->p_gstring_change_opt_partial, ',');
         }
+        g_free(p_xkb->kbd_change_option);
+        p_xkb->kbd_change_option = g_strdup(p_xkb->p_gstring_change_opt_partial->str);
+        g_string_free(p_xkb->p_gstring_change_opt_partial, TRUE/*free also gstring->str*/);
+        
+        gtk_button_set_label(GTK_BUTTON(p_xkb->p_button_change_layout), p_xkb->kbd_change_option);
+        xkb_setxkbmap(p_xkb);
+        xkb_redraw(p_xkb);
     }
     gtk_widget_destroy(p_dialog);
 }
@@ -765,19 +938,24 @@ static void on_button_add_layout_clicked(GtkButton *p_button, gpointer *p_data)
     gtk_tree_view_set_enable_tree_lines(GTK_TREE_VIEW(p_treeview_add_layout), TRUE);
     gtk_container_add(GTK_CONTAINER(p_scrolledwindow_add_layout), p_treeview_add_layout);
     GtkCellRenderer *p_renderer;
-    GtkTreeViewColumn *p_column;
+    GtkTreeViewColumn *p_column, *p_column_desc;
     // icon
     p_renderer = gtk_cell_renderer_pixbuf_new();
-    p_column = gtk_tree_view_column_new_with_attributes(_("Flag"), p_renderer, "pixbuf", COLUMN_ICON, NULL);
+    p_column = gtk_tree_view_column_new_with_attributes(_("Flag"), p_renderer, "pixbuf", COLUMN_ADD_ICON, NULL);
+    gtk_tree_view_column_set_sort_column_id(p_column, COLUMN_ADD_DESC);
     gtk_tree_view_append_column(GTK_TREE_VIEW(p_treeview_add_layout), p_column);
     // layout
     p_renderer = gtk_cell_renderer_text_new();
-    p_column = gtk_tree_view_column_new_with_attributes(_("Layout"), p_renderer, "text", COLUMN_LAYOUT, NULL);
+    p_column = gtk_tree_view_column_new_with_attributes(_("Layout"), p_renderer, "text", COLUMN_ADD_LAYOUT, NULL);
+    gtk_tree_view_column_set_sort_column_id(p_column, COLUMN_ADD_LAYOUT);
     gtk_tree_view_append_column(GTK_TREE_VIEW(p_treeview_add_layout), p_column);
     // desc
     p_renderer = gtk_cell_renderer_text_new();
-    p_column = gtk_tree_view_column_new_with_attributes(_("Description"), p_renderer, "text", COLUMN_VARIANT, NULL);
-    gtk_tree_view_append_column(GTK_TREE_VIEW(p_treeview_add_layout), p_column);
+    p_column_desc = gtk_tree_view_column_new_with_attributes(_("Description"), p_renderer, "text", COLUMN_ADD_DESC, NULL);
+    gtk_tree_view_column_set_sort_column_id(p_column_desc, COLUMN_ADD_DESC);
+    gtk_tree_view_append_column(GTK_TREE_VIEW(p_treeview_add_layout), p_column_desc);
+    // search column
+    gtk_tree_view_set_search_column(GTK_TREE_VIEW(p_treeview_add_layout), COLUMN_ADD_DESC);
     
     // populate model
     GKeyFile *p_keyfile = g_key_file_new();
@@ -845,23 +1023,13 @@ static void on_button_add_layout_clicked(GtkButton *p_button, gpointer *p_data)
     g_free(xkbcfg_filepath);
     
     // callback for double click
-    gboolean  on_treeview_add_layout_button_press_event(GtkWidget *p_widget,
-                                                        GdkEventButton *p_event,
-                                                        gpointer p_data)
-    {
-        if(p_event->button == 1)
-        {
-            if(p_event->type == GDK_2BUTTON_PRESS)
-            {
-                GtkButton *p_button_ok = (GtkButton *)gtk_dialog_get_widget_for_response(GTK_DIALOG(p_dialog), GTK_RESPONSE_OK);
-                gtk_button_clicked(p_button_ok);
-            }
-        }
-        return FALSE;
-    }
     g_signal_connect(p_treeview_add_layout, "button-press-event",
-                     G_CALLBACK(on_treeview_add_layout_button_press_event), NULL);
-    gtk_widget_set_size_request(p_dialog, 600, 500);
+                     G_CALLBACK(on_treeviews_lists_button_press_event),
+                     gtk_dialog_get_widget_for_response(GTK_DIALOG(p_dialog), GTK_RESPONSE_OK));
+    // sort for description
+    gtk_tree_view_column_clicked(p_column_desc);
+    
+    gtk_widget_set_size_request(p_dialog, 700, 500);
     gtk_widget_show_all(GTK_WIDGET(p_scrolledwindow_add_layout));
     gint  response = gtk_dialog_run(GTK_DIALOG(p_dialog));
     if(response == GTK_RESPONSE_OK)
@@ -917,22 +1085,39 @@ static void on_button_add_layout_clicked(GtkButton *p_button, gpointer *p_data)
     gtk_widget_destroy(p_dialog);
 }
 
-static void xkb_setxkbmap(XkbPlugin *p_xkb)
+void xkb_setxkbmap(XkbPlugin *p_xkb)
 {
+    if(p_xkb->keep_system_layouts) return;
+    
     GString *p_gstring_syscmd = g_string_new("");
     g_string_printf(p_gstring_syscmd,
-                    "setxkbmap -model %s -layout %s -variant %s -option grp:%s",
-                    p_xkb->kbd_model, p_xkb->kbd_layouts, p_xkb->kbd_variants, p_xkb->kbd_change_option);
-    if(system("setxkbmap -option")) {}; // reset options
-    if(system(p_gstring_syscmd->str)) {}; // set new map
+                    "setxkbmap -model %s -layout %s -variant %s -option %s",
+                    p_xkb->kbd_model, p_xkb->kbd_layouts, p_xkb->kbd_variants,
+                    p_xkb->kbd_change_option);
+    if( (p_xkb->kbd_advanced_options != NULL) && strlen(p_xkb->kbd_advanced_options) )
+    {
+        g_string_append(p_gstring_syscmd, " ");
+        g_string_append(p_gstring_syscmd, p_xkb->kbd_advanced_options);
+    }
+    if(!p_xkb->do_not_reset_opt)
+    {
+        if(system("setxkbmap -option")) // reset options
+        {
+            ERR("xkb: system(setxkbmap -option)\n");
+        }
+    }
+    if(system(p_gstring_syscmd->str)) // set new map
+    {
+        ERR("xkb: system(%s)\n", p_gstring_syscmd->str);
+    }
     //g_printf("\n%s\n", p_gstring_syscmd->str);
     g_string_free(p_gstring_syscmd, TRUE/*free also gstring->str*/);
 }
 
-static gboolean layouts_tree_model_foreach(GtkTreeModel *p_model,
-                                           GtkTreePath *p_path,
-                                           GtkTreeIter *p_iter,
-                                           gpointer p_data)
+static gboolean  layouts_tree_model_foreach(GtkTreeModel *p_model,
+                                            GtkTreePath *p_path,
+                                            GtkTreeIter *p_iter,
+                                            gpointer p_data)
 {
     XkbPlugin *p_xkb = (XkbPlugin *)p_data;
     gchar *layout_val;
@@ -949,8 +1134,8 @@ static gboolean layouts_tree_model_foreach(GtkTreeModel *p_model,
     g_string_append(p_xkb->p_gstring_layouts_partial, layout_val);
     g_string_append(p_xkb->p_gstring_variants_partial, variant_val);
     
-    //printf("\npartial layouts = '%s'\n", p_xkb->p_gstring_layouts_partial->str);
-    //printf("partial variants = '%s'\n", p_xkb->p_gstring_variants_partial->str);
+    //g_printf("\npartial layouts = '%s'\n", p_xkb->p_gstring_layouts_partial->str);
+    //g_printf("partial variants = '%s'\n", p_xkb->p_gstring_variants_partial->str);
     
     g_free(layout_val);
     g_free(variant_val);
@@ -1060,24 +1245,29 @@ static void xkb_configure(Plugin * p, GtkWindow * parent)
     panel_apply_icon(GTK_WINDOW(dlg));
 
     // main vbox of the config dialog
-    GtkWidget * p_vbox_main = gtk_vbox_new(FALSE, 0);
-    gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dlg)->vbox), p_vbox_main);
+    GtkWidget * p_hbox_main = gtk_hbox_new(TRUE, 0);
+    GtkWidget * p_vbox_left = gtk_vbox_new(FALSE, 0);
+    GtkWidget * p_vbox_right = gtk_vbox_new(FALSE, 0);
+    gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dlg)->vbox), p_hbox_main);
+    gtk_box_pack_start(GTK_BOX(p_hbox_main), p_vbox_left, FALSE, TRUE, 0);
+    gtk_box_pack_start(GTK_BOX(p_hbox_main), p_vbox_right, FALSE, TRUE, 0);
 
 
     // 'KEYBOARD MODEL' frame
-    GtkWidget * p_frame_kbd_model = gtk_frame_new(NULL);
+    p_xkb->p_frame_kbd_model = gtk_frame_new(NULL);
+    gtk_widget_set_sensitive(p_xkb->p_frame_kbd_model, !p_xkb->keep_system_layouts);
     GtkWidget * p_label_kbd_model = gtk_label_new(NULL);
     snprintf(markup_str, MAX_MARKUP_LEN, "<b>%s</b>", _("Keyboard Model"));
     gtk_label_set_markup(GTK_LABEL(p_label_kbd_model), markup_str);
     gtk_misc_set_padding(GTK_MISC(p_label_kbd_model), 1, 0);
-    gtk_frame_set_label_widget(GTK_FRAME(p_frame_kbd_model), p_label_kbd_model);
-    gtk_frame_set_shadow_type(GTK_FRAME(p_frame_kbd_model), GTK_SHADOW_NONE);
-    gtk_box_pack_start(GTK_BOX(p_vbox_main), p_frame_kbd_model, TRUE, TRUE, 2);
-    gtk_container_set_border_width(GTK_CONTAINER(p_frame_kbd_model), 3);
+    gtk_frame_set_label_widget(GTK_FRAME(p_xkb->p_frame_kbd_model), p_label_kbd_model);
+    gtk_frame_set_shadow_type(GTK_FRAME(p_xkb->p_frame_kbd_model), GTK_SHADOW_NONE);
+    gtk_box_pack_start(GTK_BOX(p_vbox_left), p_xkb->p_frame_kbd_model, TRUE, TRUE, 2);
+    gtk_container_set_border_width(GTK_CONTAINER(p_xkb->p_frame_kbd_model), 3);
 
     // frame alignment
     GtkWidget * p_alignment_kbd_model = gtk_alignment_new(0.5, 0.5, 1, 1);
-    gtk_container_add(GTK_CONTAINER(p_frame_kbd_model), p_alignment_kbd_model);
+    gtk_container_add(GTK_CONTAINER(p_xkb->p_frame_kbd_model), p_alignment_kbd_model);
     gtk_alignment_set_padding(GTK_ALIGNMENT(p_alignment_kbd_model), 4, 4, 10, 10);
     p_xkb->p_button_kbd_model = gtk_button_new_with_label(p_xkb->kbd_model);
     g_signal_connect(p_xkb->p_button_kbd_model, "clicked", G_CALLBACK(on_button_kbd_model_clicked), p_xkb);
@@ -1085,20 +1275,21 @@ static void xkb_configure(Plugin * p, GtkWindow * parent)
 
 
     // 'KEYBOARD LAYOUTS' frame
-    GtkWidget * p_frame_kbd_layouts = gtk_frame_new(NULL);
+    p_xkb->p_frame_kbd_layouts = gtk_frame_new(NULL);
+    gtk_widget_set_sensitive(p_xkb->p_frame_kbd_layouts, !p_xkb->keep_system_layouts);
     GtkWidget * p_label_kbd_layouts = gtk_label_new(NULL);
     snprintf(markup_str, MAX_MARKUP_LEN, "<b>%s</b>", _("Keyboard Layouts"));
     gtk_label_set_markup(GTK_LABEL(p_label_kbd_layouts), markup_str);
     gtk_misc_set_padding(GTK_MISC(p_label_kbd_layouts), 1, 0);
-    gtk_frame_set_label_widget(GTK_FRAME(p_frame_kbd_layouts), p_label_kbd_layouts);
-    gtk_frame_set_shadow_type(GTK_FRAME(p_frame_kbd_layouts), GTK_SHADOW_NONE);
-    gtk_box_pack_start(GTK_BOX(p_vbox_main), p_frame_kbd_layouts, TRUE, TRUE, 2);
-    gtk_container_set_border_width(GTK_CONTAINER(p_frame_kbd_layouts), 3);
-    gtk_widget_set_size_request(GTK_WIDGET(p_frame_kbd_layouts), -1, 180);
+    gtk_frame_set_label_widget(GTK_FRAME(p_xkb->p_frame_kbd_layouts), p_label_kbd_layouts);
+    gtk_frame_set_shadow_type(GTK_FRAME(p_xkb->p_frame_kbd_layouts), GTK_SHADOW_NONE);
+    gtk_box_pack_start(GTK_BOX(p_vbox_left), p_xkb->p_frame_kbd_layouts, TRUE, TRUE, 2);
+    gtk_container_set_border_width(GTK_CONTAINER(p_xkb->p_frame_kbd_layouts), 3);
+    gtk_widget_set_size_request(GTK_WIDGET(p_xkb->p_frame_kbd_layouts), 300, 180);
 
     // frame alignment
     GtkWidget * p_alignment_kbd_layouts = gtk_alignment_new(0.5, 0.5, 1, 1);
-    gtk_container_add(GTK_CONTAINER(p_frame_kbd_layouts), p_alignment_kbd_layouts);
+    gtk_container_add(GTK_CONTAINER(p_xkb->p_frame_kbd_layouts), p_alignment_kbd_layouts);
     gtk_alignment_set_padding(GTK_ALIGNMENT(p_alignment_kbd_layouts), 4, 4, 10, 10);
     GtkWidget * p_hbox_kbd_layouts = gtk_hbox_new(FALSE, 0);
     gtk_container_add(GTK_CONTAINER(p_alignment_kbd_layouts), p_hbox_kbd_layouts);
@@ -1147,25 +1338,81 @@ static void xkb_configure(Plugin * p, GtkWindow * parent)
 
 
     // 'CHANGE LAYOUT OPTION' frame
-    GtkWidget * p_frame_change_layout = gtk_frame_new(NULL);
+    p_xkb->p_frame_change_layout = gtk_frame_new(NULL);
+    gtk_widget_set_sensitive(p_xkb->p_frame_change_layout, !p_xkb->keep_system_layouts);
     GtkWidget * p_label_change_layout = gtk_label_new(NULL);
     snprintf(markup_str, MAX_MARKUP_LEN, "<b>%s</b>", _("Change Layout Option"));
     gtk_label_set_markup(GTK_LABEL(p_label_change_layout), markup_str);
     gtk_misc_set_padding(GTK_MISC(p_label_change_layout), 1, 0);
-    gtk_frame_set_label_widget(GTK_FRAME(p_frame_change_layout), p_label_change_layout);
-    gtk_frame_set_shadow_type(GTK_FRAME(p_frame_change_layout), GTK_SHADOW_NONE);
-    gtk_box_pack_start(GTK_BOX(p_vbox_main), p_frame_change_layout, TRUE, TRUE, 2);
-    gtk_container_set_border_width(GTK_CONTAINER(p_frame_change_layout), 3);
+    gtk_frame_set_label_widget(GTK_FRAME(p_xkb->p_frame_change_layout), p_label_change_layout);
+    gtk_frame_set_shadow_type(GTK_FRAME(p_xkb->p_frame_change_layout), GTK_SHADOW_NONE);
+    gtk_box_pack_start(GTK_BOX(p_vbox_left), p_xkb->p_frame_change_layout, TRUE, TRUE, 2);
+    gtk_container_set_border_width(GTK_CONTAINER(p_xkb->p_frame_change_layout), 3);
 
     // frame alignment
     GtkWidget * p_alignment_change_layout = gtk_alignment_new(0.5, 0.5, 1, 1);
-    gtk_container_add(GTK_CONTAINER(p_frame_change_layout), p_alignment_change_layout);
+    gtk_container_add(GTK_CONTAINER(p_xkb->p_frame_change_layout), p_alignment_change_layout);
     gtk_alignment_set_padding(GTK_ALIGNMENT(p_alignment_change_layout), 4, 4, 10, 10);
     p_xkb->p_button_change_layout = gtk_button_new_with_label(p_xkb->kbd_change_option);
     g_signal_connect(p_xkb->p_button_change_layout, "clicked", G_CALLBACK(on_button_kbd_change_layout_clicked), p_xkb);
     gtk_container_add(GTK_CONTAINER(p_alignment_change_layout), p_xkb->p_button_change_layout);
 
 
+    // 'ADVANCED setxkbmap OPTIONS' frame
+    GtkWidget * p_frame_advanced_opt = gtk_frame_new(NULL);
+    GtkWidget * p_label_advanced_opt = gtk_label_new(NULL);
+    snprintf(markup_str, MAX_MARKUP_LEN, "<b>%s</b>", _("Advanced setxkbmap Options"));
+    gtk_label_set_markup(GTK_LABEL(p_label_advanced_opt), markup_str);
+    gtk_misc_set_padding(GTK_MISC(p_label_advanced_opt), 1, 0);
+    gtk_frame_set_label_widget(GTK_FRAME(p_frame_advanced_opt), p_label_advanced_opt);
+    gtk_frame_set_shadow_type(GTK_FRAME(p_frame_advanced_opt), GTK_SHADOW_NONE);
+    gtk_box_pack_start(GTK_BOX(p_vbox_right), p_frame_advanced_opt, TRUE, TRUE, 2);
+    gtk_container_set_border_width(GTK_CONTAINER(p_frame_advanced_opt), 3);
+
+    // frame alignment
+    GtkWidget * p_alignment_advanced_opt = gtk_alignment_new(0.5, 0.5, 1, 1);
+    gtk_container_add(GTK_CONTAINER(p_frame_advanced_opt), p_alignment_advanced_opt);
+    gtk_alignment_set_padding(GTK_ALIGNMENT(p_alignment_advanced_opt), 4, 4, 10, 10);
+    GtkWidget * p_vbox_advanced_opt = gtk_vbox_new(FALSE, 0);
+    gtk_container_add(GTK_CONTAINER(p_alignment_advanced_opt), p_vbox_advanced_opt);
+    p_xkb->p_entry_advanced_opt = gtk_entry_new();
+    gtk_widget_set_sensitive(p_xkb->p_entry_advanced_opt, !p_xkb->keep_system_layouts);
+    gtk_entry_set_text(GTK_ENTRY(p_xkb->p_entry_advanced_opt), p_xkb->kbd_advanced_options);
+    gtk_entry_set_icon_from_stock(GTK_ENTRY(p_xkb->p_entry_advanced_opt), GTK_ENTRY_ICON_SECONDARY, "gtk-save");
+    g_signal_connect(p_xkb->p_entry_advanced_opt, "icon-press", G_CALLBACK(on_xkb_entry_advanced_opt_icon_press), p_xkb);
+    gtk_box_pack_start(GTK_BOX(p_vbox_advanced_opt), p_xkb->p_entry_advanced_opt, FALSE, TRUE, 0);
+    p_xkb->p_checkbutton_no_reset_opt = gtk_check_button_new_with_mnemonic(_("Do _not reset existing options"));
+    gtk_widget_set_sensitive(p_xkb->p_checkbutton_no_reset_opt, !p_xkb->keep_system_layouts);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p_xkb->p_checkbutton_no_reset_opt), p_xkb->do_not_reset_opt);
+    g_signal_connect(p_xkb->p_checkbutton_no_reset_opt, "toggled", G_CALLBACK(on_xkb_checkbutton_no_reset_opt_toggled), p_xkb);
+    gtk_box_pack_start(GTK_BOX(p_vbox_advanced_opt), p_xkb->p_checkbutton_no_reset_opt, FALSE, TRUE, 0);
+    GtkWidget *p_checkbutton_keep_system_layouts = gtk_check_button_new_with_mnemonic(_("Keep _system layouts"));
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p_checkbutton_keep_system_layouts), p_xkb->keep_system_layouts);
+    g_signal_connect(p_checkbutton_keep_system_layouts, "toggled", G_CALLBACK(on_xkb_checkbutton_keep_system_layouts_toggled), p_xkb);
+    gtk_box_pack_start(GTK_BOX(p_vbox_advanced_opt), p_checkbutton_keep_system_layouts, FALSE, TRUE, 0);
+
+
+    // 'PER WINDOW SETTINGS' frame
+    GtkWidget * p_frame_perapp_layout = gtk_frame_new(NULL);
+    GtkWidget * p_label_perapp_layout = gtk_label_new(NULL);
+    snprintf(markup_str, MAX_MARKUP_LEN, "<b>%s</b>", _("Per Window Settings"));
+    gtk_label_set_markup(GTK_LABEL(p_label_perapp_layout), markup_str);
+    gtk_misc_set_padding(GTK_MISC(p_label_perapp_layout), 1, 0);
+    gtk_frame_set_label_widget(GTK_FRAME(p_frame_perapp_layout), p_label_perapp_layout);
+    gtk_frame_set_shadow_type(GTK_FRAME(p_frame_perapp_layout), GTK_SHADOW_NONE);
+    gtk_box_pack_start(GTK_BOX(p_vbox_right), p_frame_perapp_layout, TRUE, TRUE, 2);
+    gtk_container_set_border_width(GTK_CONTAINER(p_frame_perapp_layout), 3);
+
+    // frame alignment
+    GtkWidget * p_alignment_perapp_layout = gtk_alignment_new(0.5, 0.5, 1, 1);
+    gtk_container_add(GTK_CONTAINER(p_frame_perapp_layout), p_alignment_perapp_layout);
+    gtk_alignment_set_padding(GTK_ALIGNMENT(p_alignment_perapp_layout), 4, 4, 10, 10);
+    GtkWidget *p_checkbutton_per_app = gtk_check_button_new_with_mnemonic(_("_Remember layout for each window"));
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p_checkbutton_per_app), p_xkb->enable_perwin);
+    g_signal_connect(p_checkbutton_per_app, "toggled", G_CALLBACK(on_xkb_checkbutton_per_app_toggled), p_xkb);
+    gtk_container_add(GTK_CONTAINER(p_alignment_perapp_layout), p_checkbutton_per_app);
+
+
     // 'SHOW LAYOUT AS' frame
     GtkWidget * p_frame_display_type = gtk_frame_new(NULL);
     GtkWidget * p_label_show_layout_as = gtk_label_new(NULL);
@@ -1174,7 +1421,7 @@ static void xkb_configure(Plugin * p, GtkWindow * parent)
     gtk_misc_set_padding(GTK_MISC(p_label_show_layout_as), 1, 0);
     gtk_frame_set_label_widget(GTK_FRAME(p_frame_display_type), p_label_show_layout_as);
     gtk_frame_set_shadow_type(GTK_FRAME(p_frame_display_type), GTK_SHADOW_NONE);
-    gtk_box_pack_start(GTK_BOX(p_vbox_main), p_frame_display_type, TRUE, TRUE, 2);
+    gtk_box_pack_start(GTK_BOX(p_vbox_right), p_frame_display_type, TRUE, TRUE, 2);
     gtk_container_set_border_width(GTK_CONTAINER(p_frame_display_type), 3);
 
     // frame alignment
@@ -1229,7 +1476,7 @@ static void xkb_configure(Plugin * p, GtkWindow * parent)
     GtkWidget * p_label_disp_type_text = gtk_label_new(NULL);
     snprintf(markup_str, MAX_MARKUP_LEN, "<span font='%d' font_weight='heavy'>%s</span>", 16, xkb_get_current_symbol_name(p_xkb));
     gtk_label_set_markup(GTK_LABEL(p_label_disp_type_text), markup_str);
-    GtkWidget * p_radiobutton_disp_type_image = gtk_radio_button_new_with_label(NULL, (const gchar *)_("Flag Image"));
+    GtkWidget * p_radiobutton_disp_type_image = gtk_radio_button_new_with_label(NULL, (const gchar *)_("Image"));
     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"));
     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"));
     
@@ -1262,7 +1509,7 @@ static void xkb_configure(Plugin * p, GtkWindow * parent)
     gtk_misc_set_padding(GTK_MISC(p_label_flag_size), 1, 0);
     gtk_frame_set_label_widget(GTK_FRAME(p_frame_flag_size), p_label_flag_size);
     gtk_frame_set_shadow_type(GTK_FRAME(p_frame_flag_size), GTK_SHADOW_NONE);
-    gtk_box_pack_start(GTK_BOX(p_vbox_main), p_frame_flag_size, TRUE, TRUE, 2);
+    gtk_box_pack_start(GTK_BOX(p_vbox_right), p_frame_flag_size, TRUE, TRUE, 2);
     gtk_container_set_border_width(GTK_CONTAINER(p_frame_flag_size), 3);
 
     // frame alignment
@@ -1277,27 +1524,30 @@ static void xkb_configure(Plugin * p, GtkWindow * parent)
     GtkWidget *p_radiobutton_flag_size_3 = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(p_radiobutton_flag_size_1), "3");
     GtkWidget *p_radiobutton_flag_size_4 = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(p_radiobutton_flag_size_1), "4");
     GtkWidget *p_radiobutton_flag_size_5 = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(p_radiobutton_flag_size_1), "5");
+    GtkWidget *p_radiobutton_flag_size_6 = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(p_radiobutton_flag_size_1), "6");
     g_signal_connect(p_radiobutton_flag_size_1, "toggled", G_CALLBACK(on_radiobutton_flag_size_1_toggled), p_xkb);
     g_signal_connect(p_radiobutton_flag_size_2, "toggled", G_CALLBACK(on_radiobutton_flag_size_2_toggled), p_xkb);
     g_signal_connect(p_radiobutton_flag_size_3, "toggled", G_CALLBACK(on_radiobutton_flag_size_3_toggled), p_xkb);
     g_signal_connect(p_radiobutton_flag_size_4, "toggled", G_CALLBACK(on_radiobutton_flag_size_4_toggled), p_xkb);
     g_signal_connect(p_radiobutton_flag_size_5, "toggled", G_CALLBACK(on_radiobutton_flag_size_5_toggled), p_xkb);
+    g_signal_connect(p_radiobutton_flag_size_6, "toggled", G_CALLBACK(on_radiobutton_flag_size_6_toggled), p_xkb);
     gtk_box_pack_start(GTK_BOX(p_hbox_flag_size), p_radiobutton_flag_size_1, TRUE, TRUE, 2);
     gtk_box_pack_start(GTK_BOX(p_hbox_flag_size), p_radiobutton_flag_size_2, TRUE, TRUE, 2);
     gtk_box_pack_start(GTK_BOX(p_hbox_flag_size), p_radiobutton_flag_size_3, TRUE, TRUE, 2);
     gtk_box_pack_start(GTK_BOX(p_hbox_flag_size), p_radiobutton_flag_size_4, TRUE, TRUE, 2);
     gtk_box_pack_start(GTK_BOX(p_hbox_flag_size), p_radiobutton_flag_size_5, TRUE, TRUE, 2);
+    gtk_box_pack_start(GTK_BOX(p_hbox_flag_size), p_radiobutton_flag_size_6, TRUE, TRUE, 2);
     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p_radiobutton_flag_size_1), p_xkb->flag_size == 1);
     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p_radiobutton_flag_size_2), p_xkb->flag_size == 2);
     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p_radiobutton_flag_size_3), p_xkb->flag_size == 3);
     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p_radiobutton_flag_size_4), p_xkb->flag_size == 4);
     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p_radiobutton_flag_size_5), p_xkb->flag_size == 5);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p_radiobutton_flag_size_6), p_xkb->flag_size == 6);
 
     /* Connect signals. */
     g_signal_connect(p_xkb->p_dialog_config, "response", G_CALLBACK(on_dialog_config_response), p_xkb);
 
     /* Display the dialog. */
-    gtk_widget_set_size_request(p_xkb->p_dialog_config, 350, -1);
     gtk_widget_show_all(p_xkb->p_dialog_config);
     gtk_window_present(GTK_WINDOW(p_xkb->p_dialog_config));
     
@@ -1309,10 +1559,14 @@ static void xkb_save_configuration(Plugin * p, FILE * fp)
 {
     XkbPlugin * p_xkb = (XkbPlugin *)p->priv;
     lxpanel_put_int(fp, "DisplayType", p_xkb->display_type);
+    lxpanel_put_int(fp, "PerWinLayout", p_xkb->enable_perwin);
+    lxpanel_put_int(fp, "NoResetOpt", p_xkb->do_not_reset_opt);
+    lxpanel_put_int(fp, "KeepSysLayouts", p_xkb->keep_system_layouts);
     lxpanel_put_str(fp, "Model", p_xkb->kbd_model);
     lxpanel_put_str(fp, "LayoutsList", p_xkb->kbd_layouts);
     lxpanel_put_str(fp, "VariantsList", p_xkb->kbd_variants);
     lxpanel_put_str(fp, "ToggleOpt", p_xkb->kbd_change_option);
+    lxpanel_put_str(fp, "AdvancedOpt", p_xkb->kbd_advanced_options);
     lxpanel_put_int(fp, "FlagSize", p_xkb->flag_size);
 }
 
@@ -1329,16 +1583,15 @@ PluginClass xkb_plugin_class = {
 
     PLUGINCLASS_VERSIONING,
 
-    type : "xkb",
-    name : N_("Keyboard Layout Handler"),
-    version: "2.0",
-    description : N_("Handle keyboard layouts"),
+    .type = "xkb",
+    .name = N_("Keyboard Layout Handler"),
+    .version = "2.0",
+    .description = N_("Handle keyboard layouts"),
 
-    constructor : xkb_constructor,
-    destructor  : xkb_destructor,
-    config : xkb_configure,
-    save : xkb_save_configuration,
-    panel_configuration_changed : xkb_panel_configuration_changed
+    .constructor = xkb_constructor,
+    .destructor  = xkb_destructor,
+    .config = xkb_configure,
+    .save = xkb_save_configuration,
+    .panel_configuration_changed = xkb_panel_configuration_changed
 
 };
-