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