1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2013 Hiroyuki Yamamoto and the Claws Mail Team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #include "claws-features.h"
23 #endif
24 
25 #include <glib.h>
26 #include <glib/gi18n.h>
27 #include <string.h>
28 #include <gtk/gtk.h>
29 #include <gdk/gdkkeysyms.h>
30 
31 #include "utils.h"
32 #include "prefswindow.h"
33 #include "gtkutils.h"
34 #include "prefs_common.h"
35 #include "gtk/manage_window.h"
36 
37 static void prefs_size_allocate_cb(GtkWidget *widget,
38 							 GtkAllocation *allocation, gpointer *user_data);
39 static GtkTreeStore *prefswindow_create_data_store	(void);
40 static GtkWidget *prefswindow_tree_view_create		(PrefsWindow* prefswindow);
41 static void prefs_filtering_create_tree_view_columns	(GtkWidget *tree_view);
42 static gboolean prefswindow_row_selected		(GtkTreeSelection *selector,
43 							 GtkTreeModel *model,
44 							 GtkTreePath *path,
45 							 gboolean currently_selected,
46 							 gpointer data);
47 
save_all_pages(GSList * prefs_pages)48 static void save_all_pages(GSList *prefs_pages)
49 {
50 	GSList *cur;
51 
52 	for (cur = prefs_pages; cur != NULL; cur = g_slist_next(cur)) {
53 		PrefsPage *page = (PrefsPage *) cur->data;
54 
55 		if (page->page_open) {
56 			page->save_page(page);
57 		}
58 	}
59 }
60 
query_can_close_all_pages(GSList * prefs_pages)61 static gboolean query_can_close_all_pages(GSList *prefs_pages)
62 {
63 	GSList *cur;
64 
65 	for (cur = prefs_pages; cur != NULL; cur = g_slist_next(cur)) {
66 		PrefsPage *page = (PrefsPage *) cur->data;
67 
68 		if (page->can_close)
69 			if (!page->can_close(page))
70 				return FALSE;
71 	}
72 	return TRUE;
73 }
74 
close_all_pages(GSList * prefs_pages)75 static void close_all_pages(GSList *prefs_pages)
76 {
77 	GSList *cur;
78 
79 	for (cur = prefs_pages; cur != NULL; cur = g_slist_next(cur)) {
80 		PrefsPage *page = (PrefsPage *) cur->data;
81 
82 		if (page->page_open) {
83 			page->destroy_widget(page);
84 			page->page_open = FALSE;
85 		}
86 	}
87 }
88 
89 #ifdef GENERIC_UMPC
prefs_show_sections(PrefsWindow * prefswindow)90 static void prefs_show_sections(PrefsWindow *prefswindow)
91 {
92 	gint max;
93 	GtkWidget *paned = prefswindow->paned;
94 
95         g_object_get (G_OBJECT(paned),
96                         "max-position",
97                         &max, NULL);
98 
99 	gtk_widget_show(gtk_paned_get_child1(GTK_PANED(paned)));
100 	gtk_widget_hide(gtk_paned_get_child2(GTK_PANED(paned)));
101 	gtk_paned_set_position(GTK_PANED(paned), max);
102 }
103 
prefs_show_page(PrefsWindow * prefswindow)104 static void prefs_show_page(PrefsWindow *prefswindow)
105 {
106 	gint min;
107 	GtkWidget *paned = prefswindow->paned;
108 
109         g_object_get (G_OBJECT(paned),
110                         "min-position",
111                         &min, NULL);
112 
113 	gtk_widget_hide(gtk_paned_get_child1(GTK_PANED(paned)));
114 	gtk_widget_show(gtk_paned_get_child2(GTK_PANED(paned)));
115 	gtk_paned_set_position(GTK_PANED(paned), min);
116 }
117 #endif
118 
apply_button_clicked(GtkButton * button,gpointer user_data)119 static void apply_button_clicked(GtkButton *button, gpointer user_data)
120 {
121 	PrefsWindow *prefswindow = (PrefsWindow *) user_data;
122 
123 	prefswindow->dialog_response = PREFSWINDOW_RESPONSE_APPLY;
124 
125 	save_all_pages(prefswindow->prefs_pages);
126 #ifdef GENERIC_UMPC
127 	prefs_show_sections(prefswindow);
128 #endif
129 
130 	if (prefswindow->apply_cb)
131 		prefswindow->apply_cb(prefswindow);
132 }
133 
close_prefs_window(PrefsWindow * prefswindow)134 static void close_prefs_window(PrefsWindow *prefswindow)
135 {
136 	debug_print("prefs window closed\n");
137 
138 	close_all_pages(prefswindow->prefs_pages);
139 
140 	if (prefswindow->close_cb)
141 		prefswindow->close_cb(prefswindow);
142 
143 	gtk_widget_destroy(prefswindow->window);
144 	g_slist_free(prefswindow->prefs_pages);
145 	if(prefswindow->func != NULL)
146 		prefswindow->func(prefswindow->data);
147 	g_free(prefswindow);
148 }
149 
ok_button_clicked(GtkButton * button,gpointer user_data)150 static void ok_button_clicked(GtkButton *button, gpointer user_data)
151 {
152 	PrefsWindow *prefswindow = (PrefsWindow *) user_data;
153 
154 	prefswindow->dialog_response = PREFSWINDOW_RESPONSE_OK;
155 
156 	if (query_can_close_all_pages(prefswindow->prefs_pages)) {
157 		save_all_pages(prefswindow->prefs_pages);
158 		close_prefs_window(prefswindow);
159 	}
160 }
161 
cancel_button_clicked(GtkButton * button,gpointer user_data)162 static void cancel_button_clicked(GtkButton *button, gpointer user_data)
163 {
164 	PrefsWindow *prefswindow = (PrefsWindow *) user_data;
165 
166 	close_prefs_window(prefswindow);
167 }
168 
window_closed(GtkWidget * widget,GdkEvent * event,gpointer user_data)169 static gboolean window_closed(GtkWidget *widget, GdkEvent *event, gpointer user_data)
170 {
171 	PrefsWindow *prefswindow = (PrefsWindow *) user_data;
172 
173 #ifdef GENERIC_UMPC
174 	save_all_pages(prefswindow->prefs_pages);
175 #endif
176 	close_prefs_window(prefswindow);
177 
178 	return FALSE;
179 }
180 
prefswindow_key_pressed(GtkWidget * widget,GdkEventKey * event,PrefsWindow * data)181 static gboolean prefswindow_key_pressed(GtkWidget *widget, GdkEventKey *event,
182 				    PrefsWindow *data)
183 {
184 	GtkWidget *focused_child;
185 
186 	if (event) {
187 		switch (event->keyval) {
188 			case GDK_KEY_Escape :
189 				cancel_button_clicked(NULL, data);
190 				break;
191 			case GDK_KEY_Return :
192 			case GDK_KEY_KP_Enter :
193 				focused_child = gtkut_get_focused_child
194 					(GTK_CONTAINER(data->notebook));
195 				/* Press ok, if the focused child is not a text view
196 				 * and text (anything that accepts return) (can pass
197 				 * NULL to any of the GTK_xxx() casts) */
198 				if (!GTK_IS_TEXT_VIEW(focused_child))
199 					ok_button_clicked(NULL, data);
200 				break;
201 			default:
202 				break;
203 		}
204 	}
205 	return FALSE;
206 }
207 
208 typedef struct FindNodeByName {
209 	const gchar *name;
210 	gboolean     found;
211 	GtkTreeIter  node;
212 } FindNodeByName;
213 
find_node_by_name(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,FindNodeByName * data)214 static gboolean find_node_by_name(GtkTreeModel *model, GtkTreePath *path,
215 				  GtkTreeIter *iter, FindNodeByName *data)
216 {
217 	gchar *name;
218 	gboolean result = FALSE;
219 
220 	gtk_tree_model_get(model, iter, PREFS_PAGE_TITLE, &name, -1);
221 	if (name) {
222 		result = strcmp(name, data->name) == 0;
223 		if (result) {
224 			data->found = TRUE;
225 			data->node  = *iter;
226 		}
227 		g_free(name);
228 	}
229 
230 	return result;
231 }
232 
prefswindow_tree_sort_by_weight(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer context)233 static gint prefswindow_tree_sort_by_weight(GtkTreeModel *model,
234 					    GtkTreeIter  *a,
235 					    GtkTreeIter  *b,
236 					    gpointer      context)
237 {
238 	gfloat f1, f2;
239 	gint i1, i2;
240 
241 	/* From observation sorting should keep in account the original
242 	 * order in the prefs_pages list. I.e. if equal weight, prefer
243 	 * the index in the pages list */
244 	gtk_tree_model_get(model, a,
245 			   PREFS_PAGE_INDEX,  &i1,
246 			   PREFS_PAGE_WEIGHT, &f1, -1);
247 	gtk_tree_model_get(model, b,
248 			   PREFS_PAGE_INDEX,  &i2,
249 			   PREFS_PAGE_WEIGHT, &f2, -1);
250 
251 	return f1 < f2 ? -1 : (f1 > f2 ?  1 :
252 	      (i1 < i2 ?  1 : (i1 > i2 ? -1 : 0)));
253 }
254 
prefswindow_build_page(PrefsWindow * prefswindow,PrefsPage * page)255 static void prefswindow_build_page(PrefsWindow *prefswindow, PrefsPage *page)
256 {
257 	GtkWidget *scrolledwin, *tmp;
258 
259 	if (!page->page_open) {
260 		scrolledwin = gtk_scrolled_window_new(NULL, NULL);
261 		gtk_widget_show(scrolledwin);
262 		gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
263 			GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
264 
265 		page->create_widget(page, GTK_WINDOW(prefswindow->window), prefswindow->data);
266 		gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolledwin),
267 					page->widget);
268 
269 		gtk_container_add(GTK_CONTAINER(prefswindow->notebook), scrolledwin);
270 		tmp = gtk_bin_get_child(GTK_BIN(scrolledwin));
271 
272 		gtk_widget_realize(tmp);
273 		gtk_widget_realize(page->widget);
274 
275 		page->widget	= scrolledwin;
276 		page->page_open	= TRUE;
277 	}
278 }
279 
prefswindow_build_all_pages(PrefsWindow * prefswindow,GSList * prefs_pages)280 static GSList *prefswindow_build_all_pages(PrefsWindow *prefswindow, GSList *prefs_pages)
281 {
282 	GSList *cur;
283 
284 	prefs_pages = g_slist_reverse(prefs_pages);
285 	for (cur = prefs_pages; cur != NULL; cur = g_slist_next(cur)) {
286 		PrefsPage *page = (PrefsPage *) cur->data;
287 
288 		prefswindow_build_page(prefswindow, page);
289 	}
290 	return g_slist_reverse(prefs_pages);
291 }
292 
prefswindow_build_tree(GtkWidget * tree_view,GSList * prefs_pages,PrefsWindow * prefswindow,gboolean preload_pages)293 static void prefswindow_build_tree(GtkWidget *tree_view, GSList *prefs_pages,
294 									PrefsWindow *prefswindow,
295 									gboolean preload_pages)
296 {
297 	GtkTreeStore *store = GTK_TREE_STORE(gtk_tree_view_get_model
298 			(GTK_TREE_VIEW(tree_view)));
299 	GSList *cur;
300 	gint index; /* index in pages list */
301 #ifndef GENERIC_UMPC
302 	GtkTreeSelection *selection;
303 	GtkTreeIter iter;
304 #endif
305 
306 	for (cur = prefs_pages, index = 0; cur != NULL; cur = g_slist_next(cur), index++) {
307 		PrefsPage *page = (PrefsPage *)cur->data;
308 		FindNodeByName find_name;
309 		GtkTreeIter node, child;
310 		PrefsTreeNode *prefs_node = NULL;
311 		int i;
312 
313 		/* each page tree component string */
314 		for (i = 0; page->path[i] != NULL; i++) {
315 			find_name.found = FALSE;
316 			find_name.name  = page->path[i];
317 
318 			/* find node to attach to
319 			 * FIXME: we search the entire tree, so this is suboptimal... */
320 			gtk_tree_model_foreach(GTK_TREE_MODEL(store),
321 					       (GtkTreeModelForeachFunc) find_node_by_name,
322 					       &find_name);
323 			if (find_name.found && (i == 0 || page->path[i] != page->path[i-1])) {
324 				node = find_name.node;
325 				gtk_tree_model_get(GTK_TREE_MODEL(store), &node,
326 						   PREFS_PAGE_DATA, &prefs_node,
327 						   -1);
328 			} else {
329 				GAuto *autoptr;
330 
331 				/* create a new top level */
332 				gtk_tree_store_append(store, &child, i == 0 ? NULL : &node);
333 				prefs_node = g_new0(PrefsTreeNode, 1);
334 				autoptr = g_auto_pointer_new(prefs_node);
335 				gtk_tree_store_set(store, &child,
336 						   PREFS_PAGE_TITLE, page->path[i],
337 						   PREFS_PAGE_DATA,  prefs_node,
338 						   PREFS_PAGE_DATA_AUTO_FREE, autoptr,
339 						   PREFS_PAGE_INDEX, index,
340 						   PREFS_PAGE_WEIGHT, 0.0f,
341 						   -1);
342 				g_auto_pointer_free(autoptr);
343 				node = child;
344 			}
345 		}
346 
347 		/* right now we have a node and its prefs_node */
348 		if (!prefs_node)
349 			g_warning("no prefs_node :/");
350 		else
351 			prefs_node->page = page;
352 
353 		/* parents "inherit" the max weight of the children */
354 		do {
355 			gfloat f;
356 
357 			gtk_tree_model_get(GTK_TREE_MODEL(store), &node,
358 					   PREFS_PAGE_WEIGHT, &f,
359 					   -1);
360 			if (page->weight > f) {
361 				f = page->weight;
362 				gtk_tree_store_set(store, &node,
363 						   PREFS_PAGE_WEIGHT, f,
364 						   -1);
365 			}
366 			child = node;
367 		} while (gtk_tree_model_iter_parent(GTK_TREE_MODEL(store),
368 						    &node, &child));
369 	}
370 
371 	gtk_tree_view_expand_all(GTK_TREE_VIEW(tree_view));
372 
373 	/* set sort func & sort */
374 	gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store),
375 					PREFS_PAGE_WEIGHT,
376 					prefswindow_tree_sort_by_weight,
377 					NULL, NULL);
378 	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store),
379 					     PREFS_PAGE_WEIGHT,
380 					     GTK_SORT_DESCENDING);
381 
382 	if (preload_pages)
383 		prefs_pages = prefswindow_build_all_pages(prefswindow, prefs_pages);
384 
385 	/* select first one or its first child if necessary */
386 #ifndef GENERIC_UMPC
387 	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
388 	if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) {
389 		if (gtk_tree_model_iter_has_child(GTK_TREE_MODEL(store), &iter)) {
390 			GtkTreeIter parent = iter;
391 			if (!gtk_tree_model_iter_children(GTK_TREE_MODEL(store), &iter, &parent))
392 				iter = parent;
393 		}
394 		gtk_tree_selection_select_iter(selection, &iter);
395 	}
396 #endif
397 }
398 
prefswindow_open_full(const gchar * title,GSList * prefs_pages,gpointer data,GDestroyNotify func,gint * save_width,gint * save_height,gboolean preload_pages,PrefsOpenCallbackFunc open_cb,PrefsApplyCallbackFunc apply_cb,PrefsCloseCallbackFunc close_cb)399 void prefswindow_open_full(const gchar *title, GSList *prefs_pages,
400 							 gpointer data, GDestroyNotify func,
401 							 gint *save_width, gint *save_height,
402 							 gboolean preload_pages,
403 							 PrefsOpenCallbackFunc open_cb,
404 							 PrefsApplyCallbackFunc apply_cb,
405 							 PrefsCloseCallbackFunc close_cb)
406 {
407 	PrefsWindow *prefswindow;
408 	gint x = gdk_screen_width();
409 	gint y = gdk_screen_height();
410 	static GdkGeometry geometry;
411 	GtkAdjustment *adj;
412 
413 	prefswindow = g_new0(PrefsWindow, 1);
414 
415 	prefswindow->data = data;
416 	prefswindow->func = func;
417 	prefswindow->prefs_pages = g_slist_copy(prefs_pages);
418 	prefswindow->save_width = save_width;
419 	prefswindow->save_height = save_height;
420 	prefswindow->open_cb = open_cb;
421 	prefswindow->apply_cb = apply_cb;
422 	prefswindow->close_cb = close_cb;
423 	prefswindow->dialog_response = PREFSWINDOW_RESPONSE_CANCEL;
424 
425 	prefswindow->window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "prefswindow");
426 	gtk_window_set_title(GTK_WINDOW(prefswindow->window), title);
427 
428 	gtk_window_set_position (GTK_WINDOW(prefswindow->window), GTK_WIN_POS_CENTER);
429 	gtk_window_set_modal (GTK_WINDOW (prefswindow->window), TRUE);
430 	gtk_window_set_resizable (GTK_WINDOW(prefswindow->window), TRUE);
431 	gtk_window_set_type_hint(GTK_WINDOW(prefswindow->window), GDK_WINDOW_TYPE_HINT_DIALOG);
432 	gtk_window_set_transient_for (GTK_WINDOW(prefswindow->window),
433 			GTK_WINDOW(mainwindow_get_mainwindow()->window));
434 	gtk_container_set_border_width(GTK_CONTAINER(prefswindow->window), 4);
435 
436 	prefswindow->vbox = gtk_vbox_new(FALSE, 6);
437 	gtk_widget_show(prefswindow->vbox);
438 
439 	prefswindow->paned = gtk_hpaned_new();
440 	gtk_widget_show(prefswindow->paned);
441 
442 	gtk_container_add(GTK_CONTAINER(prefswindow->window), prefswindow->vbox);
443 
444 	gtk_box_pack_start(GTK_BOX(prefswindow->vbox), prefswindow->paned, TRUE, TRUE, 0);
445 
446 	prefswindow->scrolledwindow1 = gtk_scrolled_window_new(NULL, NULL);
447 	gtk_widget_show(prefswindow->scrolledwindow1);
448 	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(prefswindow->scrolledwindow1),
449 			GTK_SHADOW_IN);
450 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(prefswindow->scrolledwindow1),
451 			GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
452 
453 	gtk_paned_add1(GTK_PANED(prefswindow->paned), prefswindow->scrolledwindow1);
454 
455 	prefswindow->tree_view = prefswindow_tree_view_create(prefswindow);
456 	gtk_widget_show(prefswindow->tree_view);
457 	gtk_container_add(GTK_CONTAINER(prefswindow->scrolledwindow1),
458 			  prefswindow->tree_view);
459 
460 	prefswindow->vbox2 = gtk_vbox_new(FALSE, 2);
461 	gtk_widget_show(prefswindow->vbox2);
462 
463 	gtk_paned_add2(GTK_PANED(prefswindow->paned), prefswindow->vbox2);
464 
465 	prefswindow->table2 = gtk_table_new(1, 2, FALSE);
466 	gtk_widget_show(prefswindow->table2);
467 	gtk_container_add(GTK_CONTAINER(prefswindow->vbox2), prefswindow->table2);
468 
469 	prefswindow->labelframe = gtk_frame_new(NULL);
470 	gtk_widget_show(prefswindow->labelframe);
471 	gtk_frame_set_shadow_type(GTK_FRAME(prefswindow->labelframe), GTK_SHADOW_OUT);
472 	gtk_table_attach(GTK_TABLE(prefswindow->table2), prefswindow->labelframe,
473 			0, 1, 0, 1, GTK_FILL | GTK_EXPAND, GTK_FILL, 1, 1);
474 
475 	prefswindow->pagelabel = gtk_label_new("");
476 	gtk_widget_show(prefswindow->pagelabel);
477 	gtk_label_set_justify(GTK_LABEL(prefswindow->pagelabel), GTK_JUSTIFY_LEFT);
478 	gtk_misc_set_alignment(GTK_MISC(prefswindow->pagelabel), 0, 0.0);
479 	gtk_container_add(GTK_CONTAINER(prefswindow->labelframe), prefswindow->pagelabel);
480 
481 	prefswindow->notebook = gtk_notebook_new();
482 	gtk_widget_show(prefswindow->notebook);
483 	gtk_notebook_set_scrollable(GTK_NOTEBOOK(prefswindow->notebook), TRUE);
484 	gtk_notebook_set_show_tabs(GTK_NOTEBOOK(prefswindow->notebook), FALSE);
485 	gtk_notebook_set_show_border(GTK_NOTEBOOK(prefswindow->notebook), FALSE);
486 
487 	gtk_table_attach(GTK_TABLE(prefswindow->table2), prefswindow->notebook,
488 			0, 1, 1, 2, GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 4);
489 
490 	prefswindow->empty_page = gtk_label_new("");
491 	gtk_widget_show(prefswindow->empty_page);
492 	gtk_container_add(GTK_CONTAINER(prefswindow->notebook), prefswindow->empty_page);
493 
494 	prefswindow_build_tree(prefswindow->tree_view, prefs_pages, prefswindow,
495 							preload_pages);
496 
497 	if (open_cb)
498 		open_cb(prefswindow);
499 
500 	gtk_widget_grab_focus(prefswindow->tree_view);
501 
502 #ifndef GENERIC_UMPC
503 	gtkut_stock_button_set_create(&prefswindow->confirm_area,
504 				      &prefswindow->apply_btn,	GTK_STOCK_APPLY,
505 				      &prefswindow->cancel_btn,	GTK_STOCK_CANCEL,
506 				      &prefswindow->ok_btn,	GTK_STOCK_OK);
507 #else
508 	gtkut_stock_button_set_create(&prefswindow->confirm_area,
509 				      &prefswindow->apply_btn,	GTK_STOCK_APPLY,
510 				      &prefswindow->ok_btn,	GTK_STOCK_CLOSE,
511 				      NULL,			NULL);
512 #endif
513 	gtk_widget_show_all(prefswindow->confirm_area);
514 	gtk_widget_show(prefswindow->vbox);
515 	gtk_widget_show(prefswindow->scrolledwindow1);
516 
517 	gtk_box_pack_start(GTK_BOX(prefswindow->vbox), prefswindow->confirm_area, FALSE, FALSE, 0);
518 
519 #ifndef GENERIC_UMPC
520 	g_signal_connect(G_OBJECT(prefswindow->ok_btn), "clicked",
521 			 G_CALLBACK(ok_button_clicked), prefswindow);
522 	g_signal_connect(G_OBJECT(prefswindow->cancel_btn), "clicked",
523 			 G_CALLBACK(cancel_button_clicked), prefswindow);
524 	g_signal_connect(G_OBJECT(prefswindow->apply_btn), "clicked",
525 			 G_CALLBACK(apply_button_clicked), prefswindow);
526 #else
527 	g_signal_connect(G_OBJECT(prefswindow->ok_btn), "clicked",
528 			 G_CALLBACK(ok_button_clicked), prefswindow);
529 	g_signal_connect(G_OBJECT(prefswindow->apply_btn), "clicked",
530 			 G_CALLBACK(apply_button_clicked), prefswindow);
531 #endif
532 
533 	g_signal_connect(G_OBJECT(prefswindow->window), "delete_event",
534 			 G_CALLBACK(window_closed), prefswindow);
535 	g_signal_connect(G_OBJECT(prefswindow->window), "key_press_event",
536 			   G_CALLBACK(prefswindow_key_pressed), &(prefswindow->window));
537 
538 	/* connect to callback only if we have non-NULL pointers to store size to */
539 	if (prefswindow->save_width && prefswindow->save_height) {
540 		g_signal_connect(G_OBJECT(prefswindow->window), "size_allocate",
541 				 G_CALLBACK(prefs_size_allocate_cb), prefswindow);
542 	}
543 
544 	MANAGE_WINDOW_SIGNALS_CONNECT(prefswindow->window);
545 
546 	if (!geometry.min_height) {
547 
548 		if (x < 800 && y < 600) {
549 			geometry.min_width = 600;
550 			geometry.min_height = 440;
551 		} else {
552 			geometry.min_width = 700;
553 			geometry.min_height = 550;
554 		}
555 	}
556 	gtk_window_set_geometry_hints(GTK_WINDOW(prefswindow->window), NULL, &geometry,
557 				      GDK_HINT_MIN_SIZE);
558 	if (prefswindow->save_width && prefswindow->save_height) {
559 		gtk_widget_set_size_request(prefswindow->window, *(prefswindow->save_width),
560 					    *(prefswindow->save_height));
561 	}
562 
563 #ifdef GENERIC_UMPC
564 	prefs_show_sections(prefswindow);
565 #endif
566 	gtk_widget_show(prefswindow->window);
567 	adj = gtk_scrolled_window_get_vadjustment(
568 			GTK_SCROLLED_WINDOW(prefswindow->scrolledwindow1));
569 	gtk_adjustment_set_value(adj, gtk_adjustment_get_lower(adj));
570 	gtk_adjustment_changed(adj);
571 }
572 
prefswindow_open(const gchar * title,GSList * prefs_pages,gpointer data,gint * save_width,gint * save_height,PrefsOpenCallbackFunc open_cb,PrefsApplyCallbackFunc apply_cb,PrefsCloseCallbackFunc close_cb)573 void prefswindow_open(const gchar *title, GSList *prefs_pages, gpointer data,
574 					 gint *save_width, gint *save_height,
575 					 PrefsOpenCallbackFunc open_cb,
576 					 PrefsApplyCallbackFunc apply_cb,
577 					 PrefsCloseCallbackFunc close_cb)
578 {
579 	prefswindow_open_full(title, prefs_pages, data, NULL, save_width, save_height,
580 						  FALSE, open_cb, apply_cb, close_cb);
581 }
582 
583 /*!
584  *\brief	Save Gtk object size to prefs dataset
585  */
prefs_size_allocate_cb(GtkWidget * widget,GtkAllocation * allocation,gpointer * user_data)586 static void prefs_size_allocate_cb(GtkWidget *widget,
587 					 GtkAllocation *allocation, gpointer *user_data)
588 {
589 	PrefsWindow *prefswindow = (PrefsWindow *) user_data;
590 
591 	cm_return_if_fail(allocation != NULL);
592 
593 	/* don't try to save size to NULL pointers */
594 	if (prefswindow && prefswindow->save_width && prefswindow->save_height) {
595 		*(prefswindow->save_width) = allocation->width;
596 		*(prefswindow->save_height) = allocation->height;
597 	}
598 }
599 
prefswindow_create_data_store(void)600 static GtkTreeStore *prefswindow_create_data_store(void)
601 {
602 	return gtk_tree_store_new(N_PREFS_PAGE_COLUMNS,
603 				  G_TYPE_STRING,
604 				  G_TYPE_POINTER,
605 				  G_TYPE_AUTO_POINTER,
606 				  G_TYPE_FLOAT,
607 				  G_TYPE_INT,
608 				  -1);
609 }
610 
prefswindow_tree_view_create(PrefsWindow * prefswindow)611 static GtkWidget *prefswindow_tree_view_create(PrefsWindow *prefswindow)
612 {
613 	GtkTreeView *tree_view;
614 	GtkTreeSelection *selector;
615 	GtkTreeModel *model;
616 
617 	model = GTK_TREE_MODEL(prefswindow_create_data_store());
618 	tree_view = GTK_TREE_VIEW(gtk_tree_view_new_with_model(model));
619 	g_object_unref(model);
620 	gtk_tree_view_set_rules_hint(tree_view, prefs_common.use_stripes_everywhere);
621 
622 	selector = gtk_tree_view_get_selection(tree_view);
623 	gtk_tree_selection_set_mode(selector, GTK_SELECTION_BROWSE);
624 	gtk_tree_selection_set_select_function(selector, prefswindow_row_selected,
625 					       prefswindow, NULL);
626 
627 	/* create the columns */
628 	prefs_filtering_create_tree_view_columns(GTK_WIDGET(tree_view));
629 
630 	return GTK_WIDGET(tree_view);
631 }
632 
prefs_filtering_create_tree_view_columns(GtkWidget * tree_view)633 static void prefs_filtering_create_tree_view_columns(GtkWidget *tree_view)
634 {
635 	GtkTreeViewColumn *column;
636 	GtkCellRenderer *renderer;
637 
638 	renderer = gtk_cell_renderer_text_new();
639 	column = gtk_tree_view_column_new_with_attributes
640 		(_("Page Index"),
641 		 renderer,
642 		 "text", PREFS_PAGE_TITLE,
643 		 NULL);
644 	gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
645 }
646 
prefswindow_row_selected(GtkTreeSelection * selector,GtkTreeModel * model,GtkTreePath * path,gboolean currently_selected,gpointer data)647 static gboolean prefswindow_row_selected(GtkTreeSelection *selector,
648 					 GtkTreeModel *model,
649 					 GtkTreePath *path,
650 					 gboolean currently_selected,
651 					 gpointer data)
652 {
653 	PrefsTreeNode *prefsnode;
654 	PrefsPage *page;
655 	PrefsWindow *prefswindow = (PrefsWindow *) data;
656 	gfloat lower;
657 	gchar *labeltext;
658 	gint pagenum, i;
659 	GtkTreeIter iter;
660 	GtkAdjustment *adj;
661 
662 #ifndef GENERIC_UMPC
663 	if (currently_selected)
664 		return TRUE;
665 #endif
666 	if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path))
667 		return TRUE;
668 
669 	gtk_tree_model_get(model, &iter, PREFS_PAGE_DATA, &prefsnode, -1);
670 	page = prefsnode->page;
671 
672 	debug_print("%f\n", prefsnode->treeweight);
673 
674 	if (page == NULL) {
675 		gtk_label_set_text(GTK_LABEL(prefswindow->pagelabel), "");
676 		pagenum = gtk_notebook_page_num(GTK_NOTEBOOK(prefswindow->notebook),
677 						prefswindow->empty_page);
678 		gtk_notebook_set_current_page(GTK_NOTEBOOK(prefswindow->notebook),
679 					      pagenum);
680 		return TRUE;
681 	}
682 
683 	prefswindow_build_page(prefswindow, page);
684 
685 	i = 0;
686 	while (page->path[i + 1] != 0)
687 		i++;
688 	labeltext = page->path[i];
689 
690 	gtk_label_set_text(GTK_LABEL(prefswindow->pagelabel), labeltext);
691 
692 	pagenum = gtk_notebook_page_num(GTK_NOTEBOOK(prefswindow->notebook),
693 					page->widget);
694 	gtk_notebook_set_current_page(GTK_NOTEBOOK(prefswindow->notebook),
695 				      pagenum);
696 
697 	adj = gtk_scrolled_window_get_vadjustment(
698 			GTK_SCROLLED_WINDOW(page->widget));
699 	lower = gtk_adjustment_get_lower(adj);
700 	gtk_adjustment_set_value(adj, lower);
701 	gtk_adjustment_changed(adj);
702 	adj = gtk_scrolled_window_get_hadjustment(
703 			GTK_SCROLLED_WINDOW(page->widget));
704 	gtk_adjustment_set_value(adj, lower);
705 	gtk_adjustment_changed(adj);
706 
707 #ifdef GENERIC_UMPC
708 	prefs_show_page(prefswindow);
709 #endif
710 	return TRUE;
711 }
712 
713