Hi,

Attached is a various prefs editor which applies against 0.20.
Now a few words about the individual prefs:

[current] - the current pref value is always used, and there are no
dependencies on the previous value AFAICT.

[restart] - requires restart to take effect.

allow_always_save - If changed from false to true and File -> Save was
disabled, it remains disabled after the file is changed (the shortcut
works properly). Easily fixable, but why do we enable Save All if
always_save is true? If we expect each Save All to always save all
files, I'd better be sure to never enable this. [restart], or a
ui_save_buttons_toggle() call when updating the preferences.

brace_match_ltgt - [current]

compiler_tab_autoscroll - [current]

complete_snippets_whilst_editing - [current]

find_selection_type - [current]

gio_unsafe_save_backup - [current]

indent_hard_tab_width - [restart]. And a big, fat warning. Best of
all, kill it.

msgwin_[a-z]\+_visible - Safe to change. [restart], or a call to
msgwin_show_hide_tabs() when updating the preferences.

new_document_after_close - [current]

number_[a-z_]\+_items - Safe to change. [restart].

show_editor_scrollbars - Safe to change, affects the newly opened
files. For the files already open, [restart] or foreach document
sci_set_scrollbar_mode().

show_symbol_list_expanders - TODO

statusbar_template - [current]

use_gtk_word_boundaries - TODO

use_safe_file_saving - [current]. I think utils_write_file() should be
based on write_data_to_disk(), and should display a popup message like
document_save_file(). The second worst thing after losing a document is
to lose a project/config/... file, possibly without even noticing it.

-- 
E-gards: Jimmy
--- ./geany.glade.orig	2010-12-24 15:31:39.000000000 +0200
+++ ./geany.glade	2011-01-06 20:27:40.000000000 +0200
@@ -9991,6 +9991,272 @@
 	      <property name="type">tab</property>
 	    </packing>
 	  </child>
+
+	  <child>
+	    <widget class="GtkFrame" id="frame24">
+	      <property name="border_width">5</property>
+	      <property name="visible">True</property>
+	      <property name="label_xalign">0</property>
+	      <property name="label_yalign">0.5</property>
+	      <property name="shadow_type">GTK_SHADOW_NONE</property>
+
+	      <child>
+		<widget class="GtkAlignment" id="alignment14">
+		  <property name="visible">True</property>
+		  <property name="xalign">0.5</property>
+		  <property name="yalign">0.5</property>
+		  <property name="xscale">1</property>
+		  <property name="yscale">1</property>
+		  <property name="top_padding">0</property>
+		  <property name="bottom_padding">0</property>
+		  <property name="left_padding">12</property>
+		  <property name="right_padding">0</property>
+
+		  <child>
+		    <widget class="GtkVBox" id="vbox50">
+		      <property name="visible">True</property>
+		      <property name="homogeneous">False</property>
+		      <property name="spacing">5</property>
+
+		      <child>
+			<widget class="GtkVBox" id="vbox51">
+			  <property name="visible">True</property>
+			  <property name="homogeneous">False</property>
+			  <property name="spacing">0</property>
+
+			  <child>
+			    <placeholder/>
+			  </child>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">False</property>
+			  <property name="fill">True</property>
+			</packing>
+		      </child>
+
+		      <child>
+			<widget class="GtkScrolledWindow" id="scrolledwindow9">
+			  <property name="visible">True</property>
+			  <property name="can_focus">True</property>
+			  <property name="hscrollbar_policy">GTK_POLICY_ALWAYS</property>
+			  <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property>
+			  <property name="shadow_type">GTK_SHADOW_IN</property>
+			  <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+			  <child>
+			    <widget class="GtkTreeView" id="various_treeview">
+			      <property name="visible">True</property>
+			      <property name="can_focus">True</property>
+			      <property name="headers_visible">True</property>
+			      <property name="rules_hint">True</property>
+			      <property name="reorderable">False</property>
+			      <property name="enable_search">True</property>
+			      <property name="fixed_height_mode">False</property>
+			      <property name="hover_selection">False</property>
+			      <property name="hover_expand">False</property>
+			    </widget>
+			  </child>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">True</property>
+			  <property name="fill">True</property>
+			</packing>
+		      </child>
+
+		      <child>
+			<widget class="GtkAlignment" id="alignment15">
+			  <property name="visible">True</property>
+			  <property name="xalign">0</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xscale">1</property>
+			  <property name="yscale">1</property>
+			  <property name="top_padding">0</property>
+			  <property name="bottom_padding">5</property>
+			  <property name="left_padding">0</property>
+			  <property name="right_padding">0</property>
+
+			  <child>
+			    <widget class="GtkHBox" id="hbox14">
+			      <property name="visible">True</property>
+			      <property name="homogeneous">False</property>
+			      <property name="spacing">5</property>
+
+			      <child>
+				<widget class="GtkHBox" id="various_hbox">
+				  <property name="visible">True</property>
+				  <property name="homogeneous">False</property>
+				  <property name="spacing">5</property>
+
+				  <child>
+				    <widget class="GtkLabel" id="various_label">
+				      <property name="visible">True</property>
+				      <property name="label" translatable="yes"></property>
+				      <property name="use_underline">False</property>
+				      <property name="use_markup">False</property>
+				      <property name="justify">GTK_JUSTIFY_LEFT</property>
+				      <property name="wrap">False</property>
+				      <property name="selectable">False</property>
+				      <property name="xalign">0.5</property>
+				      <property name="yalign">0.5</property>
+				      <property name="xpad">0</property>
+				      <property name="ypad">0</property>
+				      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+				      <property name="width_chars">-1</property>
+				      <property name="single_line_mode">False</property>
+				      <property name="angle">0</property>
+				    </widget>
+				    <packing>
+				      <property name="padding">0</property>
+				      <property name="expand">False</property>
+				      <property name="fill">False</property>
+				    </packing>
+				  </child>
+
+				  <child>
+				    <placeholder/>
+				  </child>
+				</widget>
+				<packing>
+				  <property name="padding">0</property>
+				  <property name="expand">True</property>
+				  <property name="fill">True</property>
+				</packing>
+			      </child>
+
+			      <child>
+				<widget class="GtkButton" id="various_button">
+				  <property name="visible">True</property>
+				  <property name="can_focus">True</property>
+				  <property name="label" translatable="yes">_Reset</property>
+				  <property name="use_underline">True</property>
+				  <property name="relief">GTK_RELIEF_NORMAL</property>
+				  <property name="focus_on_click">True</property>
+				</widget>
+				<packing>
+				  <property name="padding">0</property>
+				  <property name="expand">False</property>
+				  <property name="fill">False</property>
+				</packing>
+			      </child>
+			    </widget>
+			  </child>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">False</property>
+			  <property name="fill">False</property>
+			</packing>
+		      </child>
+
+		      <child>
+			<widget class="GtkAlignment" id="alignment16">
+			  <property name="visible">True</property>
+			  <property name="xalign">0</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xscale">1</property>
+			  <property name="yscale">1</property>
+			  <property name="top_padding">0</property>
+			  <property name="bottom_padding">5</property>
+			  <property name="left_padding">0</property>
+			  <property name="right_padding">0</property>
+
+			  <child>
+			    <widget class="GtkHBox" id="hbox15">
+			      <property name="visible">True</property>
+			      <property name="homogeneous">False</property>
+			      <property name="spacing">5</property>
+
+			      <child>
+				<widget class="GtkLabel" id="label140">
+				  <property name="visible">True</property>
+				  <property name="label" translatable="yes">&lt;i&gt;You need to restart Geany for these preferences to take effect&lt;/i&gt;.</property>
+				  <property name="use_underline">False</property>
+				  <property name="use_markup">True</property>
+				  <property name="justify">GTK_JUSTIFY_LEFT</property>
+				  <property name="wrap">False</property>
+				  <property name="selectable">False</property>
+				  <property name="xalign">0.5</property>
+				  <property name="yalign">0.5</property>
+				  <property name="xpad">0</property>
+				  <property name="ypad">0</property>
+				  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+				  <property name="width_chars">-1</property>
+				  <property name="single_line_mode">False</property>
+				  <property name="angle">0</property>
+				</widget>
+				<packing>
+				  <property name="padding">0</property>
+				  <property name="expand">False</property>
+				  <property name="fill">False</property>
+				</packing>
+			      </child>
+			    </widget>
+			  </child>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">False</property>
+			  <property name="fill">False</property>
+			</packing>
+		      </child>
+		    </widget>
+		  </child>
+		</widget>
+	      </child>
+
+	      <child>
+		<widget class="GtkLabel" id="label139">
+		  <property name="visible">True</property>
+		  <property name="label" translatable="yes">&lt;b&gt;Various preferences&lt;/b&gt;</property>
+		  <property name="use_underline">False</property>
+		  <property name="use_markup">True</property>
+		  <property name="justify">GTK_JUSTIFY_LEFT</property>
+		  <property name="wrap">False</property>
+		  <property name="selectable">False</property>
+		  <property name="xalign">0.5</property>
+		  <property name="yalign">0.5</property>
+		  <property name="xpad">0</property>
+		  <property name="ypad">0</property>
+		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		  <property name="width_chars">-1</property>
+		  <property name="single_line_mode">False</property>
+		  <property name="angle">0</property>
+		</widget>
+		<packing>
+		  <property name="type">label_item</property>
+		</packing>
+	      </child>
+	    </widget>
+	    <packing>
+	      <property name="tab_expand">False</property>
+	      <property name="tab_fill">True</property>
+	    </packing>
+	  </child>
+
+	  <child>
+	    <widget class="GtkLabel" id="label138">
+	      <property name="visible">True</property>
+	      <property name="label" translatable="yes">Various</property>
+	      <property name="use_underline">False</property>
+	      <property name="use_markup">False</property>
+	      <property name="justify">GTK_JUSTIFY_LEFT</property>
+	      <property name="wrap">False</property>
+	      <property name="selectable">False</property>
+	      <property name="xalign">0.5</property>
+	      <property name="yalign">0.5</property>
+	      <property name="xpad">0</property>
+	      <property name="ypad">0</property>
+	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+	      <property name="width_chars">-1</property>
+	      <property name="single_line_mode">False</property>
+	      <property name="angle">0</property>
+	    </widget>
+	    <packing>
+	      <property name="type">tab</property>
+	    </packing>
+	  </child>
 	</widget>
 	<packing>
 	  <property name="padding">6</property>
--- ./src/build.c.orig	2010-12-09 17:34:28.000000000 +0200
+++ ./src/build.c	2011-01-06 20:27:40.000000000 +0200
@@ -70,6 +70,8 @@
 
 GeanyBuildInfo build_info = {GEANY_GBG_FT, 0, 0, NULL, GEANY_FILETYPES_NONE, NULL, 0};
 
+GeanyBuildMenuPrefs build_menu_prefs;
+
 static gchar *current_dir_entered = NULL;
 
 typedef struct RunInfo
--- ./src/build.h.orig	2010-12-08 19:13:10.000000000 +0200
+++ ./src/build.h	2011-01-06 20:27:40.000000000 +0200
@@ -158,6 +158,15 @@
 /* opaque pointers returned from build functions and passed back to them */
 typedef struct BuildTableFields *BuildTableData;
 
+typedef struct GeanyBuildMenuPrefs
+{
+	int number_ft_menu_items;
+	int number_non_ft_menu_items;
+	int number_exec_menu_items;
+} GeanyBuildMenuPrefs;
+
+extern GeanyBuildMenuPrefs build_menu_prefs;
+
 void build_init(void);
 
 void build_finalize(void);
--- ./src/interface.c.orig	2010-12-24 15:31:39.000000000 +0200
+++ ./src/interface.c	2011-01-06 20:27:40.000000000 +0200
@@ -2891,6 +2891,22 @@
   GtkWidget *radio_print_gtk;
   GtkWidget *label243;
   GtkWidget *label201;
+  GtkWidget *frame24;
+  GtkWidget *alignment14;
+  GtkWidget *vbox50;
+  GtkWidget *vbox51;
+  GtkWidget *scrolledwindow9;
+  GtkWidget *various_treeview;
+  GtkWidget *alignment15;
+  GtkWidget *hbox14;
+  GtkWidget *various_hbox;
+  GtkWidget *various_label;
+  GtkWidget *various_button;
+  GtkWidget *alignment16;
+  GtkWidget *hbox15;
+  GtkWidget *label140;
+  GtkWidget *label139;
+  GtkWidget *label138;
   GtkWidget *dialog_action_area3;
   GtkWidget *button3;
   GtkWidget *button4;
@@ -4981,6 +4997,79 @@
   gtk_widget_show (label201);
   gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook2), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook2), 8), label201);
 
+  frame24 = gtk_frame_new (NULL);
+  gtk_widget_show (frame24);
+  gtk_container_add (GTK_CONTAINER (notebook2), frame24);
+  gtk_container_set_border_width (GTK_CONTAINER (frame24), 5);
+  gtk_frame_set_shadow_type (GTK_FRAME (frame24), GTK_SHADOW_NONE);
+
+  alignment14 = gtk_alignment_new (0.5, 0.5, 1, 1);
+  gtk_widget_show (alignment14);
+  gtk_container_add (GTK_CONTAINER (frame24), alignment14);
+  gtk_alignment_set_padding (GTK_ALIGNMENT (alignment14), 0, 0, 12, 0);
+
+  vbox50 = gtk_vbox_new (FALSE, 5);
+  gtk_widget_show (vbox50);
+  gtk_container_add (GTK_CONTAINER (alignment14), vbox50);
+
+  vbox51 = gtk_vbox_new (FALSE, 0);
+  gtk_widget_show (vbox51);
+  gtk_box_pack_start (GTK_BOX (vbox50), vbox51, FALSE, TRUE, 0);
+
+  scrolledwindow9 = gtk_scrolled_window_new (NULL, NULL);
+  gtk_widget_show (scrolledwindow9);
+  gtk_box_pack_start (GTK_BOX (vbox50), scrolledwindow9, TRUE, TRUE, 0);
+  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow9), GTK_SHADOW_IN);
+
+  various_treeview = gtk_tree_view_new ();
+  gtk_widget_show (various_treeview);
+  gtk_container_add (GTK_CONTAINER (scrolledwindow9), various_treeview);
+  gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (various_treeview), TRUE);
+
+  alignment15 = gtk_alignment_new (0, 0.5, 1, 1);
+  gtk_widget_show (alignment15);
+  gtk_box_pack_start (GTK_BOX (vbox50), alignment15, FALSE, FALSE, 0);
+  gtk_alignment_set_padding (GTK_ALIGNMENT (alignment15), 0, 5, 0, 0);
+
+  hbox14 = gtk_hbox_new (FALSE, 5);
+  gtk_widget_show (hbox14);
+  gtk_container_add (GTK_CONTAINER (alignment15), hbox14);
+
+  various_hbox = gtk_hbox_new (FALSE, 5);
+  gtk_widget_show (various_hbox);
+  gtk_box_pack_start (GTK_BOX (hbox14), various_hbox, TRUE, TRUE, 0);
+
+  various_label = gtk_label_new ("");
+  gtk_widget_show (various_label);
+  gtk_box_pack_start (GTK_BOX (various_hbox), various_label, FALSE, FALSE, 0);
+
+  various_button = gtk_button_new_with_mnemonic (_("_Reset"));
+  gtk_widget_show (various_button);
+  gtk_box_pack_start (GTK_BOX (hbox14), various_button, FALSE, FALSE, 0);
+
+  alignment16 = gtk_alignment_new (0, 0.5, 1, 1);
+  gtk_widget_show (alignment16);
+  gtk_box_pack_start (GTK_BOX (vbox50), alignment16, FALSE, FALSE, 0);
+  gtk_alignment_set_padding (GTK_ALIGNMENT (alignment16), 0, 5, 0, 0);
+
+  hbox15 = gtk_hbox_new (FALSE, 5);
+  gtk_widget_show (hbox15);
+  gtk_container_add (GTK_CONTAINER (alignment16), hbox15);
+
+  label140 = gtk_label_new (_("<i>You need to restart Geany for these preferences to take effect</i>."));
+  gtk_widget_show (label140);
+  gtk_box_pack_start (GTK_BOX (hbox15), label140, FALSE, FALSE, 0);
+  gtk_label_set_use_markup (GTK_LABEL (label140), TRUE);
+
+  label139 = gtk_label_new (_("<b>Various preferences</b>"));
+  gtk_widget_show (label139);
+  gtk_frame_set_label_widget (GTK_FRAME (frame24), label139);
+  gtk_label_set_use_markup (GTK_LABEL (label139), TRUE);
+
+  label138 = gtk_label_new (_("Various"));
+  gtk_widget_show (label138);
+  gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook2), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook2), 9), label138);
+
   dialog_action_area3 = GTK_DIALOG (prefs_dialog)->action_area;
   gtk_widget_show (dialog_action_area3);
   gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area3), GTK_BUTTONBOX_END);
@@ -5391,6 +5480,22 @@
   GLADE_HOOKUP_OBJECT (prefs_dialog, radio_print_gtk, "radio_print_gtk");
   GLADE_HOOKUP_OBJECT (prefs_dialog, label243, "label243");
   GLADE_HOOKUP_OBJECT (prefs_dialog, label201, "label201");
+  GLADE_HOOKUP_OBJECT (prefs_dialog, frame24, "frame24");
+  GLADE_HOOKUP_OBJECT (prefs_dialog, alignment14, "alignment14");
+  GLADE_HOOKUP_OBJECT (prefs_dialog, vbox50, "vbox50");
+  GLADE_HOOKUP_OBJECT (prefs_dialog, vbox51, "vbox51");
+  GLADE_HOOKUP_OBJECT (prefs_dialog, scrolledwindow9, "scrolledwindow9");
+  GLADE_HOOKUP_OBJECT (prefs_dialog, various_treeview, "various_treeview");
+  GLADE_HOOKUP_OBJECT (prefs_dialog, alignment15, "alignment15");
+  GLADE_HOOKUP_OBJECT (prefs_dialog, hbox14, "hbox14");
+  GLADE_HOOKUP_OBJECT (prefs_dialog, various_hbox, "various_hbox");
+  GLADE_HOOKUP_OBJECT (prefs_dialog, various_label, "various_label");
+  GLADE_HOOKUP_OBJECT (prefs_dialog, various_button, "various_button");
+  GLADE_HOOKUP_OBJECT (prefs_dialog, alignment16, "alignment16");
+  GLADE_HOOKUP_OBJECT (prefs_dialog, hbox15, "hbox15");
+  GLADE_HOOKUP_OBJECT (prefs_dialog, label140, "label140");
+  GLADE_HOOKUP_OBJECT (prefs_dialog, label139, "label139");
+  GLADE_HOOKUP_OBJECT (prefs_dialog, label138, "label138");
   GLADE_HOOKUP_OBJECT_NO_REF (prefs_dialog, dialog_action_area3, "dialog_action_area3");
   GLADE_HOOKUP_OBJECT (prefs_dialog, button3, "button3");
   GLADE_HOOKUP_OBJECT (prefs_dialog, button4, "button4");
--- ./src/keyfile.c.orig	2010-12-07 15:16:57.000000000 +0200
+++ ./src/keyfile.c	2011-01-06 20:27:40.000000000 +0200
@@ -174,10 +174,10 @@
 	stash_group_add_spin_button_integer(group, &file_prefs.disk_check_timeout,
 		"disk_check_timeout", GEANY_DISK_CHECK_TIMEOUT, "spin_disk_check");
 
-	/* hidden prefs (don't overwrite them so users can edit them manually) */
+	/* various geany prefs */
 	group = stash_group_new(PACKAGE);
-	configuration_add_pref_group(group, FALSE);
-	stash_group_set_write_once(group, TRUE);
+	configuration_add_pref_group(group, TRUE);
+	stash_group_set_various(group, TRUE);
 
 	stash_group_add_boolean(group, &editor_prefs.show_scrollbars,
 		"show_editor_scrollbars", TRUE);
@@ -197,7 +197,19 @@
 	stash_group_add_integer(group, (gint*)&search_prefs.find_selection_type,
 		"find_selection_type", GEANY_FIND_SEL_CURRENT_WORD);
 
-	/* Note: Interface-related hidden prefs are in ui_init_prefs() */
+	/* Note: Interface-related variuos prefs are in ui_init_prefs() */
+
+	/* variuos build-menu prefs */
+	group = stash_group_new("build-menu");
+	configuration_add_pref_group(group, TRUE);
+	stash_group_set_various(group, TRUE);
+
+	stash_group_add_integer(group, &build_menu_prefs.number_ft_menu_items,
+		"number_ft_menu_items", 0);
+	stash_group_add_integer(group, &build_menu_prefs.number_non_ft_menu_items,
+		"number_non_ft_menu_items", 0);
+	stash_group_add_integer(group, &build_menu_prefs.number_exec_menu_items,
+		"number_exec_menu_items", 0);
 }
 
 
@@ -363,10 +375,6 @@
 	g_key_file_set_boolean(config, PACKAGE, "tab_order_beside", file_prefs.tab_order_beside);
 	g_key_file_set_integer(config, PACKAGE, "tab_pos_editor", interface_prefs.tab_pos_editor);
 	g_key_file_set_integer(config, PACKAGE, "tab_pos_msgwin", interface_prefs.tab_pos_msgwin);
-	g_key_file_set_boolean(config, PACKAGE, "msgwin_status_visible", interface_prefs.msgwin_status_visible);
-	g_key_file_set_boolean(config, PACKAGE, "msgwin_compiler_visible", interface_prefs.msgwin_compiler_visible);
-	g_key_file_set_boolean(config, PACKAGE, "msgwin_messages_visible", interface_prefs.msgwin_messages_visible);
-	g_key_file_set_boolean(config, PACKAGE, "msgwin_scribble_visible", interface_prefs.msgwin_scribble_visible);
 	g_key_file_set_boolean(config, PACKAGE, "use_native_windows_dialogs", interface_prefs.use_native_windows_dialogs);
 
 	/* display */
@@ -658,10 +666,6 @@
 	interface_prefs.editor_font = utils_get_setting_string(config, PACKAGE, "editor_font", GEANY_DEFAULT_FONT_EDITOR);
 	interface_prefs.tagbar_font = utils_get_setting_string(config, PACKAGE, "tagbar_font", GEANY_DEFAULT_FONT_SYMBOL_LIST);
 	interface_prefs.msgwin_font = utils_get_setting_string(config, PACKAGE, "msgwin_font", GEANY_DEFAULT_FONT_MSG_WINDOW);
-	interface_prefs.msgwin_status_visible = utils_get_setting_boolean(config, PACKAGE, "msgwin_status_visible", TRUE);
-	interface_prefs.msgwin_compiler_visible = utils_get_setting_boolean(config, PACKAGE, "msgwin_compiler_visible", TRUE);
-	interface_prefs.msgwin_messages_visible = utils_get_setting_boolean(config, PACKAGE, "msgwin_messages_visible", TRUE);
-	interface_prefs.msgwin_scribble_visible = utils_get_setting_boolean(config, PACKAGE, "msgwin_scribble_visible", TRUE);
 	interface_prefs.use_native_windows_dialogs = utils_get_setting_boolean(config, PACKAGE, "use_native_windows_dialogs", FALSE);
 
 	/* display, editor */
@@ -810,9 +814,9 @@
 	tool_prefs.context_action_cmd = utils_get_setting_string(config, PACKAGE, "context_action_cmd", "");
 
 	/* build menu */
-	build_set_group_count(GEANY_GBG_FT, utils_get_setting_integer(config, "build-menu", "number_ft_menu_items", 0));
-	build_set_group_count(GEANY_GBG_NON_FT, utils_get_setting_integer(config, "build-menu", "number_non_ft_menu_items", 0));
-	build_set_group_count(GEANY_GBG_EXEC, utils_get_setting_integer(config, "build-menu", "number_exec_menu_items", 0));
+	build_set_group_count(GEANY_GBG_FT, build_menu_prefs.number_ft_menu_items);
+	build_set_group_count(GEANY_GBG_NON_FT, build_menu_prefs.number_non_ft_menu_items);
+	build_set_group_count(GEANY_GBG_EXEC, build_menu_prefs.number_exec_menu_items);
 	build_load_menu(config, GEANY_BCS_PREF, NULL);
 
 	/* printing */
--- ./src/prefs.c.orig	2010-11-23 19:36:29.000000000 +0200
+++ ./src/prefs.c	2011-01-06 20:27:40.000000000 +0200
@@ -1700,6 +1700,15 @@
 				ui_entry_add_clear_icon(GTK_ENTRY(ui_lookup_widget(ui_widgets.prefs_dialog, *name)));
 		}
 
+		/* page Various */
+		{
+			GtkTreeView *tree = GTK_TREE_VIEW(ui_lookup_widget(ui_widgets.prefs_dialog, "various_treeview"));
+			GtkLabel *label = GTK_LABEL(ui_lookup_widget(ui_widgets.prefs_dialog, "various_label"));
+			GtkBox *container = GTK_BOX(ui_lookup_widget(ui_widgets.prefs_dialog, "various_hbox"));
+			GtkButton *reset = GTK_BUTTON(ui_lookup_widget(ui_widgets.prefs_dialog, "various_button"));
+			stash_setup_editor(pref_groups, TRUE, ui_widgets.prefs_dialog, tree, label, container, reset);
+		}
+
 #ifdef HAVE_VTE
 		vte_append_preferences_tab();
 #endif
--- ./src/stash.c.orig	2010-10-28 14:45:14.000000000 +0300
+++ ./src/stash.c	2011-01-06 20:27:40.000000000 +0200
@@ -84,7 +84,9 @@
 
 
 #include "geany.h"		/* necessary for utils.h, otherwise use gtk/gtk.h */
-#include "utils.h"		/* only for foreach_*, utils_get_setting_*(). Stash should not depend on Geany. */
+#include "support.h"		/* only for _("text") */
+#include "utils.h"		/* only for foreach_*, utils_get_setting_*() and
+				 * ui_widget_set_tooltip_text(). Stash should not depend on Geany. */
 
 #include "stash.h"
 
@@ -106,7 +108,7 @@
 {
 	const gchar *name;			/* group name to use in the keyfile */
 	GArray *entries;			/* array of StashPref */
-	gboolean write_once;		/* only write settings if they don't already exist */
+	gboolean various;		/* mark group for display/edit in stash treeview */
 	gboolean use_defaults;		/* use default values if there's no keyfile entry */
 };
 
@@ -224,21 +226,11 @@
 
 	foreach_array(StashPref, entry, group->entries)
 	{
-		gpointer tmp = entry->setting;
-
 		/* don't override settings with default values */
 		if (!group->use_defaults && action == SETTING_READ &&
 			!g_key_file_has_key(keyfile, group->name, entry->key_name, NULL))
 			continue;
 
-		/* don't overwrite write_once prefs */
-		if (group->write_once && action == SETTING_WRITE)
-		{
-			if (g_key_file_has_key(keyfile, group->name, entry->key_name, NULL))
-				continue;
-			/* We temporarily use the default value for writing */
-			entry->setting = &entry->default_value;
-		}
 		switch (entry->setting_type)
 		{
 			case G_TYPE_BOOLEAN:
@@ -255,8 +247,6 @@
 					g_warning("Unhandled type for %s::%s in %s()!", group->name, entry->key_name,
 						G_STRFUNC);
 		}
-		if (group->write_once && action == SETTING_WRITE)
-			entry->setting = tmp;
 	}
 }
 
@@ -372,9 +362,9 @@
 /* Useful so the user can edit the keyfile manually while the program is running,
  * and the setting won't be overridden.
  * @c FALSE by default. */
-void stash_group_set_write_once(StashGroup *group, gboolean write_once)
+void stash_group_set_various(StashGroup *group, gboolean various)
 {
-	group->write_once = write_once;
+	group->various = various;
 }
 
 
@@ -903,3 +893,363 @@
 }
 
 
+enum
+{
+	STASH_TREE_NAME,
+	STASH_TREE_VALUE,
+	STASH_TREE_PREF,
+	STASH_TREE_COUNT
+};
+
+
+static void stash_tree_update_value(const gchar *value, gpointer user_data)
+{
+	GtkTreeIter iter;
+	GtkTreeModel *model;
+
+	if (gtk_tree_selection_get_selected(GTK_TREE_SELECTION(user_data), &model, &iter))
+		gtk_list_store_set(GTK_LIST_STORE(model), &iter, STASH_TREE_VALUE, value, -1);
+}
+
+
+static void stash_check_button_toggled_cb(GtkToggleButton *button, gpointer user_data)
+{
+	stash_tree_update_value(gtk_toggle_button_get_active(button) ? "true" : "false", user_data);
+}
+
+
+static void stash_int_entry_changed_cb(GtkEditable *editable, gpointer user_data)
+{
+	const gchar *value = gtk_entry_get_text(GTK_ENTRY(editable));
+	stash_tree_update_value(*value ? value : "0", user_data);
+}
+
+
+static void stash_string_entry_changed_cb(GtkEditable *editable, gpointer user_data)
+{
+	stash_tree_update_value(gtk_entry_get_text(GTK_ENTRY(editable)), user_data);
+}
+
+
+static gchar *stash_tree_pref_to_string(StashPref *entry, gboolean current)
+{
+	gpointer *setting = current ? entry->setting : &entry->default_value;
+	gchar *value;
+
+	switch (entry->setting_type)
+	{
+		case G_TYPE_BOOLEAN:
+			value = g_strdup(*(gboolean *) setting ? "true" : "false"); break;
+		case G_TYPE_INT:
+			value = g_strdup_printf("%d", *(gint *) setting); break;
+		case G_TYPE_STRING:
+			value = g_strdup(*(gchararray *) setting); break;
+		default:
+			g_warning("Unhandled type for %s in %s()!", entry->key_name, G_STRFUNC);
+			value = NULL;
+	}
+
+	return value;
+}
+
+
+typedef struct
+{
+	GtkWidget *owner;
+	GtkTreeView *tree; /* currently not used */
+	GtkTreeSelection *selection;
+	GtkLabel *label;
+	GtkBox *container;
+	GtkButton *reset;
+	StashPref *entry;
+} StashEditorData;
+
+
+static void stash_tree_selection_changed_cb(GtkTreeSelection *selection, gpointer user_data)
+{
+	StashEditorData *sed = (StashEditorData *) user_data;
+	GtkTreeIter iter;
+	GtkTreeModel *model;
+	StashPref *new_entry = NULL;
+
+	if (gtk_tree_selection_get_selected(sed->selection, &model, &iter))
+		gtk_tree_model_get(model, &iter, STASH_TREE_PREF, &new_entry, -1);
+	else
+		new_entry = NULL;
+
+	if (new_entry != sed->entry)
+	{
+		if (sed->label)
+		{
+			if (new_entry)
+			{
+				gchar *name;
+				gchar *label;
+
+				gtk_tree_model_get(model, &iter, STASH_TREE_NAME, &name, -1);
+				label = g_strdup_printf("%s:", name);
+				gtk_label_set_text(sed->label, label);
+				g_free(label);
+				g_free(name);
+			}
+			else
+				gtk_label_set_text(sed->label, "");
+		}
+
+		if (sed->container)
+		{
+			GtkWidget *new_widget;
+
+			if (sed->entry)
+			{
+				GtkWidget *old_widget = get_widget(sed->owner, sed->entry->widget_id);
+
+				if (old_widget)
+					gtk_widget_hide(old_widget);
+			}
+
+			if (new_entry)
+			{
+				new_widget = get_widget(sed->owner, new_entry->widget_id);
+				if (new_widget)
+					gtk_widget_show(new_widget);
+			}
+			else
+				new_widget = NULL;
+
+			if (sed->reset)
+			{
+				if (new_widget)
+				{
+					gchar *value = stash_tree_pref_to_string(new_entry, FALSE);
+					gchar *tooltip = g_strdup_printf("Default = %s", value);
+
+					if (!sed->entry)
+						gtk_widget_set_sensitive(GTK_WIDGET(sed->reset), TRUE);
+					ui_widget_set_tooltip_text(sed->reset, tooltip);
+					g_free(tooltip);
+					g_free(value);
+				}
+				else
+					gtk_widget_set_sensitive(GTK_WIDGET(sed->reset), FALSE);
+			}
+		}
+
+		sed->entry = new_entry;
+	}
+}
+
+
+/* only PREF_DISPLAY is used, update is automatic */
+static void handle_editor_widget(GtkWidget *widget, StashPref *entry, PrefAction action)
+{
+	switch (entry->setting_type)
+	{
+		case G_TYPE_BOOLEAN:
+			handle_toggle_button(widget, entry->setting, action);
+			break;
+		case G_TYPE_INT:
+			handle_spin_button(widget, entry, action);
+			break;
+		case G_TYPE_STRING:
+			handle_entry(widget, entry, action);
+			break;
+		default:
+			g_warning("Unhandled type for %s in %s()!", entry->key_name, G_STRFUNC);
+	}
+}
+
+
+static void stash_reset_button_clicked_cb(GtkButton *button, gpointer user_data)
+{
+	StashEditorData *sed = (StashEditorData *) user_data;
+	GtkTreeIter iter;
+	GtkTreeModel *model;
+
+	if (gtk_tree_selection_get_selected(sed->selection, &model, &iter))
+	{
+		StashPref *entry;
+		GtkWidget *widget;
+
+		gtk_tree_model_get(model, &iter, STASH_TREE_PREF, &entry, -1);
+		widget = get_widget(sed->owner, entry->widget_id);
+		if (widget)
+		{
+			gpointer tmp = entry->setting;
+
+			entry->setting = &entry->default_value;
+			handle_editor_widget(widget, entry, PREF_DISPLAY);
+			entry->setting = tmp;
+		}
+	}
+}
+
+
+static gboolean stash_tree_free_widget_id(GtkTreeModel *model, GtkTreePath *path,
+		GtkTreeIter *iter, gpointer user_data)
+{
+	StashPref *entry;
+
+	gtk_tree_model_get(model, iter, STASH_TREE_PREF, &entry, -1);
+	g_free(entry->widget_id);
+	entry->widget_id = NULL;
+
+	return FALSE;
+}
+
+
+static void stash_tree_destroy_cb(GtkWidget *widget, gpointer user_data)
+{
+	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
+	gtk_tree_model_foreach(model, stash_tree_free_widget_id, NULL);
+}
+
+
+#define GLADE_HOOKUP_OBJECT(component,widget,name) \
+  g_object_set_data_full (G_OBJECT (component), name, \
+    gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref)
+
+
+/** Setups a simple editor for stash preferences based on the widget arguments.
+ * @param group_array Array of groups which's settings will be edited.
+ * @param various_only If TRUE, only groups with the various flag set will be edited.
+ * @param owner GtkWidget that owns the editor widgets.
+ * @param tree GtkTreeView in which to display the preferences.
+ * Must not contain any other items.
+ * @param label GtkLabel in which the the name of the current item will be displayed.
+ * May be NULL.
+ * @param container GtkBox that will contain a widget for editing of the current item.
+ * If NULL, the preferences will be displayed only, not edited.
+ * @param reset GtkButton that, when pressed, will reset the current item to it's default value.
+ * May be NULL. Requires non-NULL @param container to work. */
+void stash_setup_editor(GPtrArray *group_array, gboolean various_only,
+		GtkWidget *owner, GtkTreeView *tree, GtkLabel *label,
+		GtkBox *container, GtkButton *reset)
+{
+	StashGroup *group;
+	guint i;
+	GtkListStore *store;
+	GtkCellRenderer *renderer;
+	GtkTreeViewColumn *column;
+	GtkTreeSelection *selection = gtk_tree_view_get_selection(tree);
+
+	store = gtk_list_store_new(STASH_TREE_COUNT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
+	foreach_ptr_array(group, i, group_array)
+	{
+		StashPref *entry;
+
+		if (various_only && !group->various)
+			continue;
+
+		foreach_array(StashPref, entry, group->entries)
+		{
+			GtkTreeIter iter;
+			gchar *value = stash_tree_pref_to_string(entry, TRUE);
+			GtkWidget *widget;
+			gboolean sizable;
+			const gchar *signame;
+			GCallback sigfunc;
+
+			if (!value)
+				continue; /* entry not supported */
+
+			gtk_list_store_append(store, &iter);
+			gtk_list_store_set(store, &iter, STASH_TREE_NAME, entry->key_name,
+				STASH_TREE_VALUE, value, STASH_TREE_PREF, (gpointer) entry, -1);
+			g_free(value);
+
+			if (!container)
+				continue; /* display only, not edit */
+
+			switch (entry->setting_type)
+			{
+				case G_TYPE_BOOLEAN:
+				{
+					entry->widget_type = GTK_TYPE_TOGGLE_BUTTON;
+					widget = gtk_check_button_new();
+					sizable = FALSE;
+					signame = "toggled";
+					sigfunc = G_CALLBACK(stash_check_button_toggled_cb);
+					break;
+				}
+				case G_TYPE_INT:
+				{
+					entry->widget_type = GTK_TYPE_SPIN_BUTTON;
+					widget = gtk_spin_button_new_with_range(INT_MIN, INT_MAX, 1);
+					gtk_entry_set_max_length(GTK_ENTRY(widget), 20);
+					sizable = FALSE;
+					signame = "changed";
+					sigfunc = G_CALLBACK(stash_int_entry_changed_cb);
+					break;
+				}
+				case G_TYPE_STRING:
+				{
+					entry->widget_type = GTK_TYPE_ENTRY;
+					widget = gtk_entry_new();
+					gtk_entry_set_max_length(GTK_ENTRY(widget), 255);
+					sizable = TRUE;
+					signame = "changed";
+					sigfunc = G_CALLBACK(stash_string_entry_changed_cb);
+					break;
+				}
+				default:
+					g_warning("Unhandled type for %s::%s in %s()!", group->name,
+						entry->key_name, G_STRFUNC);
+					widget = NULL;
+			}
+
+			/* widget_id is mandatory for entries added to the store */
+			entry->widget_id = g_strdup_printf("%s::%s", group->name, entry->key_name);
+			if (widget)
+			{
+				handle_editor_widget(widget, entry, PREF_DISPLAY);
+				g_signal_connect(widget, signame, sigfunc, selection);
+				gtk_box_pack_start(container, widget, sizable, sizable, 0);
+				GLADE_HOOKUP_OBJECT(owner, widget, entry->widget_id);
+			}
+		}
+	}
+	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), STASH_TREE_NAME,
+		GTK_SORT_ASCENDING);
+	gtk_tree_view_set_model(tree, GTK_TREE_MODEL(store));
+	g_object_unref(G_OBJECT(store));
+	g_signal_connect(tree, "destroy", G_CALLBACK(stash_tree_destroy_cb), NULL);
+
+	renderer = gtk_cell_renderer_text_new();
+	column = gtk_tree_view_column_new_with_attributes(_("Name"), renderer, "text",
+		STASH_TREE_NAME, NULL);
+	gtk_tree_view_column_set_sort_column_id(column, STASH_TREE_NAME);
+	gtk_tree_view_column_set_sort_indicator(column, TRUE);
+	gtk_tree_view_append_column(tree, column);
+
+	renderer = gtk_cell_renderer_text_new();
+	column = gtk_tree_view_column_new_with_attributes(_("Value"), renderer, "text",
+		STASH_TREE_VALUE, NULL);
+	gtk_tree_view_append_column(tree, column);
+
+	{
+		/* sed should only be visible to the callbacks */
+		static StashEditorData sed;
+
+		sed.owner = owner;
+		sed.tree = tree;
+		sed.selection = selection;
+		sed.label = label;
+		sed.container = container;
+		sed.reset = reset;
+		sed.entry = NULL;
+
+		gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
+		g_signal_connect(G_OBJECT(selection), "changed",
+			G_CALLBACK(stash_tree_selection_changed_cb), &sed);
+
+		if (reset)
+		{
+			gtk_widget_set_sensitive(GTK_WIDGET(reset), FALSE);
+			g_signal_connect(G_OBJECT(reset), "clicked",
+				G_CALLBACK(stash_reset_button_clicked_cb), &sed);
+		}
+	}
+}
+
+
--- ./src/stash.h.orig	2010-03-31 19:21:28.000000000 +0300
+++ ./src/stash.h	2011-01-06 20:27:40.000000000 +0200
@@ -92,4 +92,8 @@
 
 void stash_group_update(StashGroup *group, GtkWidget *owner);
 
+void stash_setup_editor(GPtrArray *group_array, gboolean various_only,
+		GtkWidget *owner, GtkTreeView *tree, GtkLabel *label,
+		GtkBox *container, GtkButton *reset);
+
 #endif
--- ./src/ui_utils.c.orig	2010-11-08 15:13:33.000000000 +0200
+++ ./src/ui_utils.c	2011-01-06 20:27:40.000000000 +0200
@@ -170,11 +170,7 @@
 	const gchar *expos;	/* % expansion position */
 	const gchar sp[] = "      ";
 
-	fmt = NZV(statusbar_template) ? statusbar_template :
-		/* Status bar statistics: col = column, sel = selection. */
-		_("line: %l / %L\t col: %c\t sel: %s\t %w      %t      %m"
-		"mode: %M      encoding: %e      filetype: %f      scope: %S");
-
+	fmt = statusbar_template;
 	g_string_assign(stats_str, "");
 	while ((expos = strchr(fmt, '%')) != NULL)
 	{
@@ -2030,9 +2026,9 @@
 {
 	StashGroup *group = stash_group_new(PACKAGE);
 
-	/* hidden prefs (don't overwrite them so users can edit them manually) */
-	configuration_add_pref_group(group, FALSE);
-	stash_group_set_write_once(group, TRUE);
+	/* various prefs */
+	configuration_add_pref_group(group, TRUE);
+	stash_group_set_various(group, TRUE);
 
 	stash_group_add_boolean(group, &interface_prefs.show_symbol_list_expanders,
 		"show_symbol_list_expanders", TRUE);
@@ -2041,9 +2037,19 @@
 	stash_group_add_boolean(group, &ui_prefs.allow_always_save,
 		"allow_always_save", FALSE);
 	stash_group_add_string(group, &statusbar_template,
-		"statusbar_template", "");
+		"statusbar_template", /* Status bar statistics: col = column, sel = selection. */
+		_("line: %l / %L\t col: %c\t sel: %s\t %w      %t      %m"
+		"mode: %M      encoding: %e      filetype: %f      scope: %S"));
 	stash_group_add_boolean(group, &ui_prefs.new_document_after_close,
 		"new_document_after_close", FALSE);
+	stash_group_add_boolean(group, &interface_prefs.msgwin_status_visible,
+		"msgwin_status_visible", TRUE);
+	stash_group_add_boolean(group, &interface_prefs.msgwin_compiler_visible,
+		"msgwin_compiler_visible", TRUE);
+	stash_group_add_boolean(group, &interface_prefs.msgwin_messages_visible,
+		"msgwin_messages_visible", TRUE);
+	stash_group_add_boolean(group, &interface_prefs.msgwin_scribble_visible,
+		"msgwin_scribble_visible", TRUE);
 }
 
 
_______________________________________________
Geany mailing list
[email protected]
http://lists.uvena.de/cgi-bin/mailman/listinfo/geany

Reply via email to